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 3 // found in the LICENSE file. 4 // 5 // This file defines utility functions for eliding and formatting UI text. 6 7 #ifndef UI_GFX_TEXT_ELIDER_H_ 8 #define UI_GFX_TEXT_ELIDER_H_ 9 10 #include <string> 11 #include <vector> 12 13 #include "base/basictypes.h" 14 #include "base/strings/string16.h" 15 #include "third_party/icu/source/common/unicode/uchar.h" 16 #include "third_party/icu/source/i18n/unicode/coll.h" 17 #include "ui/gfx/gfx_export.h" 18 19 class GURL; 20 21 namespace base { 22 class FilePath; 23 } 24 25 namespace gfx { 26 class Font; 27 class FontList; 28 29 GFX_EXPORT extern const char kEllipsis[]; 30 GFX_EXPORT extern const base::char16 kEllipsisUTF16[]; 31 32 // Elides a well-formed email address (e.g. username (at) domain.com) to fit into 33 // |available_pixel_width| using the specified |font_list|. 34 // This function guarantees that the string returned will contain at least one 35 // character, other than the ellipses, on either side of the '@'. If it is 36 // impossible to achieve these requirements: only an ellipsis will be returned. 37 // If possible: this elides only the username portion of the |email|. Otherwise, 38 // the domain is elided in the middle so that it splits the available width 39 // equally with the elided username (should the username be short enough that it 40 // doesn't need half the available width: the elided domain will occupy that 41 // extra width). 42 GFX_EXPORT base::string16 ElideEmail(const base::string16& email, 43 const gfx::FontList& font_list, 44 float available_pixel_width); 45 46 // This function takes a GURL object and elides it. It returns a string 47 // which composed of parts from subdomain, domain, path, filename and query. 48 // A "..." is added automatically at the end if the elided string is bigger 49 // than the |available_pixel_width|. For |available_pixel_width| == 0, a 50 // formatted, but un-elided, string is returned. |languages| is a comma 51 // separated list of ISO 639 language codes and is used to determine what 52 // characters are understood by a user. It should come from 53 // |prefs::kAcceptLanguages|. 54 // 55 // Note: in RTL locales, if the URL returned by this function is going to be 56 // displayed in the UI, then it is likely that the string needs to be marked 57 // as an LTR string (using base::i18n::WrapStringWithLTRFormatting()) so that it 58 // is displayed properly in an RTL context. Please refer to 59 // http://crbug.com/6487 for more information. 60 GFX_EXPORT base::string16 ElideUrl(const GURL& url, 61 const gfx::FontList& font_list, 62 float available_pixel_width, 63 const std::string& languages); 64 65 enum ElideBehavior { 66 // Add ellipsis at the end of the string. 67 ELIDE_AT_END, 68 // Add ellipsis in the middle of the string. 69 ELIDE_IN_MIDDLE, 70 // Truncate the end of the string. 71 TRUNCATE_AT_END 72 }; 73 74 // Elides |text| to fit in |available_pixel_width| according to the specified 75 // |elide_behavior|. 76 GFX_EXPORT base::string16 ElideText(const base::string16& text, 77 const gfx::FontList& font_list, 78 float available_pixel_width, 79 ElideBehavior elide_behavior); 80 // Obsolete version. Use the above version which takes gfx::FontList. 81 GFX_EXPORT base::string16 ElideText(const base::string16& text, 82 const gfx::Font& font, 83 float available_pixel_width, 84 ElideBehavior elide_behavior); 85 86 // Elide a filename to fit a given pixel width, with an emphasis on not hiding 87 // the extension unless we have to. If filename contains a path, the path will 88 // be removed if filename doesn't fit into available_pixel_width. The elided 89 // filename is forced to have LTR directionality, which means that in RTL UI 90 // the elided filename is wrapped with LRE (Left-To-Right Embedding) mark and 91 // PDF (Pop Directional Formatting) mark. 92 GFX_EXPORT base::string16 ElideFilename(const base::FilePath& filename, 93 const gfx::FontList& font_list, 94 float available_pixel_width); 95 96 // SortedDisplayURL maintains a string from a URL suitable for display to the 97 // use. SortedDisplayURL also provides a function used for comparing two 98 // SortedDisplayURLs for use in visually ordering the SortedDisplayURLs. 99 // 100 // SortedDisplayURL is relatively cheap and supports value semantics. 101 class GFX_EXPORT SortedDisplayURL { 102 public: 103 SortedDisplayURL(const GURL& url, const std::string& languages); 104 SortedDisplayURL(); 105 ~SortedDisplayURL(); 106 107 // Compares this SortedDisplayURL to |url| using |collator|. Returns a value 108 // < 0, = 1 or > 0 as to whether this url is less then, equal to or greater 109 // than the supplied url. 110 int Compare(const SortedDisplayURL& other, icu::Collator* collator) const; 111 112 // Returns the display string for the URL. 113 const base::string16& display_url() const { return display_url_; } 114 115 private: 116 // Returns everything after the host. This is used by Compare if the hosts 117 // match. 118 base::string16 AfterHost() const; 119 120 // Host name minus 'www.'. Used by Compare. 121 base::string16 sort_host_; 122 123 // End of the prefix (spec and separator) in display_url_. 124 size_t prefix_end_; 125 126 base::string16 display_url_; 127 128 DISALLOW_COPY_AND_ASSIGN(SortedDisplayURL); 129 }; 130 131 // Functions to elide strings when the font information is unknown. As 132 // opposed to the above functions, the ElideString() and 133 // ElideRectangleString() functions operate in terms of character units, 134 // not pixels. 135 136 // If the size of |input| is more than |max_len|, this function returns 137 // true and |input| is shortened into |output| by removing chars in the 138 // middle (they are replaced with up to 3 dots, as size permits). 139 // Ex: ElideString(ASCIIToUTF16("Hello"), 10, &str) puts Hello in str and 140 // returns false. ElideString(ASCIIToUTF16("Hello my name is Tom"), 10, &str) 141 // puts "Hell...Tom" in str and returns true. 142 // TODO(tsepez): Doesn't handle UTF-16 surrogate pairs properly. 143 // TODO(tsepez): Doesn't handle bidi properly. 144 GFX_EXPORT bool ElideString(const base::string16& input, int max_len, 145 base::string16* output); 146 147 // Reformat |input| into |output| so that it fits into a |max_rows| by 148 // |max_cols| rectangle of characters. Input newlines are respected, but 149 // lines that are too long are broken into pieces. If |strict| is true, 150 // we break first at naturally occuring whitespace boundaries, otherwise 151 // we assume some other mechanism will do this in approximately the same 152 // spot after the fact. If the word itself is too long, we always break 153 // intra-word (respecting UTF-16 surrogate pairs) as necssary. Truncation 154 // (indicated by an added 3 dots) occurs if the result is still too long. 155 // Returns true if the input had to be truncated (and not just reformatted). 156 GFX_EXPORT bool ElideRectangleString(const base::string16& input, 157 size_t max_rows, 158 size_t max_cols, 159 bool strict, 160 base::string16* output); 161 162 // Specifies the word wrapping behavior of |ElideRectangleText()| when a word 163 // would exceed the available width. 164 enum WordWrapBehavior { 165 // Words that are too wide will be put on a new line, but will not be 166 // truncated or elided. 167 IGNORE_LONG_WORDS, 168 169 // Words that are too wide will be put on a new line and will be truncated to 170 // the available width. 171 TRUNCATE_LONG_WORDS, 172 173 // Words that are too wide will be put on a new line and will be elided to the 174 // available width. 175 ELIDE_LONG_WORDS, 176 177 // Words that are too wide will be put on a new line and will be wrapped over 178 // multiple lines. 179 WRAP_LONG_WORDS, 180 }; 181 182 // Indicates whether the |available_pixel_width| by |available_pixel_height| 183 // rectangle passed to |ElideRectangleText()| had insufficient space to 184 // accommodate the given |text|, leading to elision or truncation. 185 enum ReformattingResultFlags { 186 INSUFFICIENT_SPACE_HORIZONTAL = 1 << 0, 187 INSUFFICIENT_SPACE_VERTICAL = 1 << 1, 188 }; 189 190 // Reformats |text| into output vector |lines| so that the resulting text fits 191 // into an |available_pixel_width| by |available_pixel_height| rectangle with 192 // the specified |font_list|. Input newlines are respected, but lines that are 193 // too long are broken into pieces. For words that are too wide to fit on a 194 // single line, the wrapping behavior can be specified with the |wrap_behavior| 195 // param. Returns a combination of |ReformattingResultFlags| that indicate 196 // whether the given rectangle had insufficient space to accommodate |tex|, 197 // leading to elision or truncation (and not just reformatting). 198 GFX_EXPORT int ElideRectangleText(const base::string16& text, 199 const gfx::FontList& font_list, 200 float available_pixel_width, 201 int available_pixel_height, 202 WordWrapBehavior wrap_behavior, 203 std::vector<base::string16>* lines); 204 205 // Truncates the string to length characters. This breaks the string at 206 // the first word break before length, adding the horizontal ellipsis 207 // character (unicode character 0x2026) to render ... 208 // The supplied string is returned if the string has length characters or 209 // less. 210 GFX_EXPORT base::string16 TruncateString(const base::string16& string, 211 size_t length); 212 213 } // namespace gfx 214 215 #endif // UI_GFX_TEXT_ELIDER_H_ 216