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

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

Issue 23731010: Move text_elider to gfx. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update3 Created 7 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « ui/gfx/text_elider.h ('k') | ui/gfx/text_elider_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 (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 // This file implements utility functions for eliding and formatting UI text. 5 // This file implements utility functions for eliding and formatting UI text.
6 // 6 //
7 // Note that several of the functions declared in text_elider.h are implemented 7 // Note that several of the functions declared in text_elider.h are implemented
8 // in this file using helper classes in an unnamed namespace. 8 // in this file using helper classes in an unnamed namespace.
9 9
10 #include "ui/base/text/text_elider.h" 10 #include "ui/gfx/text_elider.h"
11 11
12 #include <string> 12 #include <string>
13 #include <vector> 13 #include <vector>
14 14
15 #include "base/files/file_path.h" 15 #include "base/files/file_path.h"
16 #include "base/i18n/break_iterator.h" 16 #include "base/i18n/break_iterator.h"
17 #include "base/i18n/char_iterator.h" 17 #include "base/i18n/char_iterator.h"
18 #include "base/i18n/rtl.h" 18 #include "base/i18n/rtl.h"
19 #include "base/memory/scoped_ptr.h" 19 #include "base/memory/scoped_ptr.h"
20 #include "base/strings/string_split.h" 20 #include "base/strings/string_split.h"
21 #include "base/strings/string_util.h" 21 #include "base/strings/string_util.h"
22 #include "base/strings/sys_string_conversions.h" 22 #include "base/strings/sys_string_conversions.h"
23 #include "base/strings/utf_string_conversions.h" 23 #include "base/strings/utf_string_conversions.h"
24 #include "net/base/escape.h" 24 #include "net/base/escape.h"
25 #include "net/base/net_util.h" 25 #include "net/base/net_util.h"
26 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 26 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
27 #include "third_party/icu/source/common/unicode/rbbi.h" 27 #include "third_party/icu/source/common/unicode/rbbi.h"
28 #include "third_party/icu/source/common/unicode/uloc.h" 28 #include "third_party/icu/source/common/unicode/uloc.h"
29 #include "ui/gfx/font_list.h" 29 #include "ui/gfx/font_list.h"
30 #include "ui/gfx/text_utils.h" 30 #include "ui/gfx/text_utils.h"
31 #include "url/gurl.h" 31 #include "url/gurl.h"
32 32
33 namespace ui { 33 namespace gfx {
34 34
35 // U+2026 in utf8 35 // U+2026 in utf8
36 const char kEllipsis[] = "\xE2\x80\xA6"; 36 const char kEllipsis[] = "\xE2\x80\xA6";
37 const char16 kEllipsisUTF16[] = { 0x2026, 0 }; 37 const char16 kEllipsisUTF16[] = { 0x2026, 0 };
38 const char16 kForwardSlash = '/'; 38 const char16 kForwardSlash = '/';
39 39
40 namespace { 40 namespace {
41 41
42 // Helper class to split + elide text, while respecting UTF16 surrogate pairs. 42 // Helper class to split + elide text, while respecting UTF16 surrogate pairs.
43 class StringSlicer { 43 class StringSlicer {
(...skipping 591 matching lines...) Expand 10 before | Expand all | Expand 10 after
635 int lstr_len = rstr_len + ((max_len - 3) % 2); 635 int lstr_len = rstr_len + ((max_len - 3) % 2);
636 output->assign(input.substr(0, lstr_len) + ASCIIToUTF16("...") + 636 output->assign(input.substr(0, lstr_len) + ASCIIToUTF16("...") +
637 input.substr(input.length() - rstr_len)); 637 input.substr(input.length() - rstr_len));
638 break; 638 break;
639 } 639 }
640 } 640 }
641 641
642 return true; 642 return true;
643 } 643 }
644 644
645 } // namespace ui
646
647 namespace { 645 namespace {
648 646
649 // Internal class used to track progress of a rectangular string elide 647 // Internal class used to track progress of a rectangular string elide
650 // operation. Exists so the top-level ElideRectangleString() function 648 // operation. Exists so the top-level ElideRectangleString() function
651 // can be broken into smaller methods sharing this state. 649 // can be broken into smaller methods sharing this state.
652 class RectangleString { 650 class RectangleString {
653 public: 651 public:
654 RectangleString(size_t max_rows, size_t max_cols, 652 RectangleString(size_t max_rows, size_t max_cols,
655 bool strict, string16 *output) 653 bool strict, string16 *output)
656 : max_rows_(max_rows), 654 : max_rows_(max_rows),
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
807 } 805 }
808 806
809 // Internal class used to track progress of a rectangular text elide 807 // Internal class used to track progress of a rectangular text elide
810 // operation. Exists so the top-level ElideRectangleText() function 808 // operation. Exists so the top-level ElideRectangleText() function
811 // can be broken into smaller methods sharing this state. 809 // can be broken into smaller methods sharing this state.
812 class RectangleText { 810 class RectangleText {
813 public: 811 public:
814 RectangleText(const gfx::FontList& font_list, 812 RectangleText(const gfx::FontList& font_list,
815 int available_pixel_width, 813 int available_pixel_width,
816 int available_pixel_height, 814 int available_pixel_height,
817 ui::WordWrapBehavior wrap_behavior, 815 WordWrapBehavior wrap_behavior,
818 std::vector<string16>* lines) 816 std::vector<string16>* lines)
819 : font_list_(font_list), 817 : font_list_(font_list),
820 line_height_(font_list.GetHeight()), 818 line_height_(font_list.GetHeight()),
821 available_pixel_width_(available_pixel_width), 819 available_pixel_width_(available_pixel_width),
822 available_pixel_height_(available_pixel_height), 820 available_pixel_height_(available_pixel_height),
823 wrap_behavior_(wrap_behavior), 821 wrap_behavior_(wrap_behavior),
824 current_width_(0), 822 current_width_(0),
825 current_height_(0), 823 current_height_(0),
826 last_line_ended_in_lf_(false), 824 last_line_ended_in_lf_(false),
827 lines_(lines), 825 lines_(lines),
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
875 // The height of each line of text. 873 // The height of each line of text.
876 const int line_height_; 874 const int line_height_;
877 875
878 // The number of pixels of available width in the rectangle. 876 // The number of pixels of available width in the rectangle.
879 const int available_pixel_width_; 877 const int available_pixel_width_;
880 878
881 // The number of pixels of available height in the rectangle. 879 // The number of pixels of available height in the rectangle.
882 const int available_pixel_height_; 880 const int available_pixel_height_;
883 881
884 // The wrap behavior for words that are too long to fit on a single line. 882 // The wrap behavior for words that are too long to fit on a single line.
885 const ui::WordWrapBehavior wrap_behavior_; 883 const WordWrapBehavior wrap_behavior_;
886 884
887 // The current running width. 885 // The current running width.
888 int current_width_; 886 int current_width_;
889 887
890 // The current running height. 888 // The current running height.
891 int current_height_; 889 int current_height_;
892 890
893 // The current line of text. 891 // The current line of text.
894 string16 current_line_; 892 string16 current_line_;
895 893
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
931 int RectangleText::Finalize() { 929 int RectangleText::Finalize() {
932 // Remove trailing whitespace from the last line or remove the last line 930 // Remove trailing whitespace from the last line or remove the last line
933 // completely, if it's just whitespace. 931 // completely, if it's just whitespace.
934 if (!insufficient_height_ && !lines_->empty()) { 932 if (!insufficient_height_ && !lines_->empty()) {
935 TrimWhitespace(lines_->back(), TRIM_TRAILING, &lines_->back()); 933 TrimWhitespace(lines_->back(), TRIM_TRAILING, &lines_->back());
936 if (lines_->back().empty() && !last_line_ended_in_lf_) 934 if (lines_->back().empty() && !last_line_ended_in_lf_)
937 lines_->pop_back(); 935 lines_->pop_back();
938 } 936 }
939 if (last_line_ended_in_lf_) 937 if (last_line_ended_in_lf_)
940 lines_->push_back(string16()); 938 lines_->push_back(string16());
941 return (insufficient_width_ ? ui::INSUFFICIENT_SPACE_HORIZONTAL : 0) | 939 return (insufficient_width_ ? INSUFFICIENT_SPACE_HORIZONTAL : 0) |
942 (insufficient_height_ ? ui::INSUFFICIENT_SPACE_VERTICAL : 0); 940 (insufficient_height_ ? INSUFFICIENT_SPACE_VERTICAL : 0);
943 } 941 }
944 942
945 void RectangleText::AddLine(const string16& line) { 943 void RectangleText::AddLine(const string16& line) {
946 const int line_width = gfx::GetStringWidth(line, font_list_); 944 const int line_width = gfx::GetStringWidth(line, font_list_);
947 if (line_width <= available_pixel_width_) { 945 if (line_width <= available_pixel_width_) {
948 AddToCurrentLineWithWidth(line, line_width); 946 AddToCurrentLineWithWidth(line, line_width);
949 } else { 947 } else {
950 // Iterate over positions that are valid to break the line at. In general, 948 // Iterate over positions that are valid to break the line at. In general,
951 // these are word boundaries but after any punctuation following the word. 949 // these are word boundaries but after any punctuation following the word.
952 base::i18n::BreakIterator words(line, 950 base::i18n::BreakIterator words(line,
(...skipping 24 matching lines...) Expand all
977 NewLine(); 975 NewLine();
978 } 976 }
979 977
980 int RectangleText::WrapWord(const string16& word) { 978 int RectangleText::WrapWord(const string16& word) {
981 // Word is so wide that it must be fragmented. 979 // Word is so wide that it must be fragmented.
982 string16 text = word; 980 string16 text = word;
983 int lines_added = 0; 981 int lines_added = 0;
984 bool first_fragment = true; 982 bool first_fragment = true;
985 while (!insufficient_height_ && !text.empty()) { 983 while (!insufficient_height_ && !text.empty()) {
986 string16 fragment = 984 string16 fragment =
987 ui::ElideText(text, font_list_, available_pixel_width_, 985 ElideText(text, font_list_, available_pixel_width_,
988 ui::TRUNCATE_AT_END); 986 TRUNCATE_AT_END);
989 // At least one character has to be added at every line, even if the 987 // At least one character has to be added at every line, even if the
990 // available space is too small. 988 // available space is too small.
991 if(fragment.empty()) 989 if(fragment.empty())
992 fragment = text.substr(0, 1); 990 fragment = text.substr(0, 1);
993 if (!first_fragment && NewLine()) 991 if (!first_fragment && NewLine())
994 lines_added++; 992 lines_added++;
995 AddToCurrentLine(fragment); 993 AddToCurrentLine(fragment);
996 text = text.substr(fragment.length()); 994 text = text.substr(fragment.length());
997 first_fragment = false; 995 first_fragment = false;
998 } 996 }
999 return lines_added; 997 return lines_added;
1000 } 998 }
1001 999
1002 int RectangleText::AddWordOverflow(const string16& word) { 1000 int RectangleText::AddWordOverflow(const string16& word) {
1003 int lines_added = 0; 1001 int lines_added = 0;
1004 1002
1005 // Unless this is the very first word, put it on a new line. 1003 // Unless this is the very first word, put it on a new line.
1006 if (!current_line_.empty()) { 1004 if (!current_line_.empty()) {
1007 if (!NewLine()) 1005 if (!NewLine())
1008 return 0; 1006 return 0;
1009 lines_added++; 1007 lines_added++;
1010 } 1008 }
1011 1009
1012 if (wrap_behavior_ == ui::IGNORE_LONG_WORDS) { 1010 if (wrap_behavior_ == IGNORE_LONG_WORDS) {
1013 current_line_ = word; 1011 current_line_ = word;
1014 current_width_ = available_pixel_width_; 1012 current_width_ = available_pixel_width_;
1015 } else if (wrap_behavior_ == ui::WRAP_LONG_WORDS) { 1013 } else if (wrap_behavior_ == WRAP_LONG_WORDS) {
1016 lines_added += WrapWord(word); 1014 lines_added += WrapWord(word);
1017 } else { 1015 } else {
1018 const ui::ElideBehavior elide_behavior = 1016 const ElideBehavior elide_behavior =
1019 (wrap_behavior_ == ui::ELIDE_LONG_WORDS ? ui::ELIDE_AT_END : 1017 (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_AT_END : TRUNCATE_AT_END);
1020 ui::TRUNCATE_AT_END);
1021 const string16 elided_word = 1018 const string16 elided_word =
1022 ui::ElideText(word, font_list_, available_pixel_width_, elide_behavior); 1019 ElideText(word, font_list_, available_pixel_width_, elide_behavior);
1023 AddToCurrentLine(elided_word); 1020 AddToCurrentLine(elided_word);
1024 insufficient_width_ = true; 1021 insufficient_width_ = true;
1025 } 1022 }
1026 1023
1027 return lines_added; 1024 return lines_added;
1028 } 1025 }
1029 1026
1030 int RectangleText::AddWord(const string16& word) { 1027 int RectangleText::AddWord(const string16& word) {
1031 int lines_added = 0; 1028 int lines_added = 0;
1032 string16 trimmed; 1029 string16 trimmed;
1033 TrimWhitespace(word, TRIM_TRAILING, &trimmed); 1030 TrimWhitespace(word, TRIM_TRAILING, &trimmed);
1034 const int trimmed_width = gfx::GetStringWidth(trimmed, font_list_); 1031 const int trimmed_width = gfx::GetStringWidth(trimmed, font_list_);
1035 if (trimmed_width <= available_pixel_width_) { 1032 if (trimmed_width <= available_pixel_width_) {
1036 // Word can be made to fit, no need to fragment it. 1033 // Word can be made to fit, no need to fragment it.
1037 if ((current_width_ + trimmed_width > available_pixel_width_) && NewLine()) 1034 if ((current_width_ + trimmed_width > available_pixel_width_) && NewLine())
1038 lines_added++; 1035 lines_added++;
1039 // Append the non-trimmed word, in case more words are added after. 1036 // Append the non-trimmed word, in case more words are added after.
1040 AddToCurrentLine(word); 1037 AddToCurrentLine(word);
1041 } else { 1038 } else {
1042 lines_added = AddWordOverflow(wrap_behavior_ == ui::IGNORE_LONG_WORDS ? 1039 lines_added = AddWordOverflow(wrap_behavior_ == IGNORE_LONG_WORDS ?
1043 trimmed : word); 1040 trimmed : word);
1044 } 1041 }
1045 return lines_added; 1042 return lines_added;
1046 } 1043 }
1047 1044
1048 void RectangleText::AddToCurrentLine(const string16& text) { 1045 void RectangleText::AddToCurrentLine(const string16& text) {
1049 AddToCurrentLineWithWidth(text, gfx::GetStringWidth(text, font_list_)); 1046 AddToCurrentLineWithWidth(text, gfx::GetStringWidth(text, font_list_));
1050 } 1047 }
1051 1048
1052 void RectangleText::AddToCurrentLineWithWidth(const string16& text, 1049 void RectangleText::AddToCurrentLineWithWidth(const string16& text,
(...skipping 15 matching lines...) Expand all
1068 } else { 1065 } else {
1069 insufficient_height_ = true; 1066 insufficient_height_ = true;
1070 } 1067 }
1071 current_height_ += line_height_; 1068 current_height_ += line_height_;
1072 current_width_ = 0; 1069 current_width_ = 0;
1073 return line_added; 1070 return line_added;
1074 } 1071 }
1075 1072
1076 } // namespace 1073 } // namespace
1077 1074
1078 namespace ui {
1079
1080 bool ElideRectangleString(const string16& input, size_t max_rows, 1075 bool ElideRectangleString(const string16& input, size_t max_rows,
1081 size_t max_cols, bool strict, string16* output) { 1076 size_t max_cols, bool strict, string16* output) {
1082 RectangleString rect(max_rows, max_cols, strict, output); 1077 RectangleString rect(max_rows, max_cols, strict, output);
1083 rect.Init(); 1078 rect.Init();
1084 rect.AddString(input); 1079 rect.AddString(input);
1085 return rect.Finalize(); 1080 return rect.Finalize();
1086 } 1081 }
1087 1082
1088 int ElideRectangleText(const string16& input, 1083 int ElideRectangleText(const string16& input,
1089 const gfx::FontList& font_list, 1084 const gfx::FontList& font_list,
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1167 // Found a valid break point. 1162 // Found a valid break point.
1168 index = char_iterator.getIndex(); 1163 index = char_iterator.getIndex();
1169 } else { 1164 } else {
1170 // String has leading whitespace, return the elide string. 1165 // String has leading whitespace, return the elide string.
1171 return kElideString; 1166 return kElideString;
1172 } 1167 }
1173 } 1168 }
1174 return string.substr(0, index) + kElideString; 1169 return string.substr(0, index) + kElideString;
1175 } 1170 }
1176 1171
1177 } // namespace ui 1172 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/text_elider.h ('k') | ui/gfx/text_elider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698