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 19class GURL; 20 21namespace base { 22class FilePath; 23} 24 25namespace gfx { 26class Font; 27class FontList; 28 29GFX_EXPORT extern const char kEllipsis[]; 30GFX_EXPORT extern const base::char16 kEllipsisUTF16[]; 31 32// Elides a well-formed email address (e.g. username@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). 42GFX_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. 60GFX_EXPORT base::string16 ElideUrl(const GURL& url, 61 const gfx::FontList& font_list, 62 float available_pixel_width, 63 const std::string& languages); 64 65enum 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|. 76GFX_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. 81GFX_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. 92GFX_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. 101class 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. 144GFX_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). 156GFX_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. 164enum 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. 185enum 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). 198GFX_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. 210GFX_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