Index: ui/gfx/text_elider.cc |
diff --git a/ui/gfx/text_elider.cc b/ui/gfx/text_elider.cc |
index 7a7524acf22ba1ca6b3ce064ed9a68bac8f6521c..8c07bdecd5f581d2e88b3bf20f1947bd94fe1c6b 100644 |
--- a/ui/gfx/text_elider.cc |
+++ b/ui/gfx/text_elider.cc |
@@ -32,57 +32,18 @@ using base::WideToUTF16; |
namespace gfx { |
-// U+2026 in utf8 |
-const char kEllipsis[] = "\xE2\x80\xA6"; |
-const base::char16 kEllipsisUTF16[] = { 0x2026, 0 }; |
-const base::char16 kForwardSlash = '/'; |
- |
-StringSlicer::StringSlicer(const base::string16& text, |
- const base::string16& ellipsis, |
- bool elide_in_middle, |
- bool elide_at_beginning) |
- : text_(text), |
- ellipsis_(ellipsis), |
- elide_in_middle_(elide_in_middle), |
- elide_at_beginning_(elide_at_beginning) { |
-} |
- |
-base::string16 StringSlicer::CutString(size_t length, bool insert_ellipsis) { |
- const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_ |
- : base::string16(); |
- |
- if (elide_at_beginning_) |
- return ellipsis_text + |
- text_.substr(FindValidBoundaryBefore(text_.length() - length)); |
- |
- if (!elide_in_middle_) |
- return text_.substr(0, FindValidBoundaryBefore(length)) + ellipsis_text; |
- |
- // We put the extra character, if any, before the cut. |
- const size_t half_length = length / 2; |
- const size_t prefix_length = FindValidBoundaryBefore(length - half_length); |
- const size_t suffix_start_guess = text_.length() - half_length; |
- const size_t suffix_start = FindValidBoundaryAfter(suffix_start_guess); |
- const size_t suffix_length = |
- half_length - (suffix_start_guess - suffix_start); |
- return text_.substr(0, prefix_length) + ellipsis_text + |
- text_.substr(suffix_start, suffix_length); |
-} |
- |
-size_t StringSlicer::FindValidBoundaryBefore(size_t index) const { |
- DCHECK_LE(index, text_.length()); |
- if (index != text_.length()) |
- U16_SET_CP_START(text_.data(), 0, index); |
- return index; |
-} |
- |
-size_t StringSlicer::FindValidBoundaryAfter(size_t index) const { |
- DCHECK_LE(index, text_.length()); |
- if (index != text_.length()) |
- U16_SET_CP_LIMIT(text_.data(), 0, index, text_.length()); |
- return index; |
-} |
+namespace { |
+// Elides a well-formed email address (e.g. username@domain.com) to fit into |
+// |available_pixel_width| using the specified |font_list|. |
+// This function guarantees that the string returned will contain at least one |
+// character, other than the ellipses, on either side of the '@'. If it is |
+// impossible to achieve these requirements: only an ellipsis will be returned. |
+// If possible: this elides only the username portion of the |email|. Otherwise, |
+// the domain is elided in the middle so that it splits the available width |
+// equally with the elided username (should the username be short enough that it |
+// doesn't need half the available width: the elided domain will occupy that |
+// extra width). |
base::string16 ElideEmail(const base::string16& email, |
const FontList& font_list, |
float available_pixel_width) { |
@@ -124,8 +85,7 @@ base::string16 ElideEmail(const base::string16& email, |
std::min(available_domain_width, |
std::max(available_pixel_width - full_username_width, |
available_pixel_width / 2)); |
- domain = ElideText(domain, font_list, desired_domain_width, |
- ELIDE_IN_MIDDLE); |
+ domain = ElideText(domain, font_list, desired_domain_width, ELIDE_MIDDLE); |
// Failing to elide the domain such that at least one character remains |
// (other than the ellipsis itself) remains: return a single ellipsis. |
if (domain.length() <= 1U) |
@@ -136,12 +96,63 @@ base::string16 ElideEmail(const base::string16& email, |
// is guaranteed to fit with at least one character remaining given all the |
// precautions taken earlier). |
available_pixel_width -= GetStringWidthF(domain, font_list); |
- username = ElideText(username, font_list, available_pixel_width, |
- ELIDE_AT_END); |
- |
+ username = ElideText(username, font_list, available_pixel_width, ELIDE_TAIL); |
return username + kAtSignUTF16 + domain; |
} |
+} // namespace |
+ |
+// U+2026 in utf8 |
+const char kEllipsis[] = "\xE2\x80\xA6"; |
+const base::char16 kEllipsisUTF16[] = { 0x2026, 0 }; |
+const base::char16 kForwardSlash = '/'; |
+ |
+StringSlicer::StringSlicer(const base::string16& text, |
+ const base::string16& ellipsis, |
+ bool elide_in_middle, |
+ bool elide_at_beginning) |
+ : text_(text), |
+ ellipsis_(ellipsis), |
+ elide_in_middle_(elide_in_middle), |
+ elide_at_beginning_(elide_at_beginning) { |
+} |
+ |
+base::string16 StringSlicer::CutString(size_t length, bool insert_ellipsis) { |
+ const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_ |
+ : base::string16(); |
+ |
+ if (elide_at_beginning_) |
+ return ellipsis_text + |
+ text_.substr(FindValidBoundaryBefore(text_.length() - length)); |
+ |
+ if (!elide_in_middle_) |
+ return text_.substr(0, FindValidBoundaryBefore(length)) + ellipsis_text; |
+ |
+ // We put the extra character, if any, before the cut. |
+ const size_t half_length = length / 2; |
+ const size_t prefix_length = FindValidBoundaryBefore(length - half_length); |
+ const size_t suffix_start_guess = text_.length() - half_length; |
+ const size_t suffix_start = FindValidBoundaryAfter(suffix_start_guess); |
+ const size_t suffix_length = |
+ half_length - (suffix_start_guess - suffix_start); |
+ return text_.substr(0, prefix_length) + ellipsis_text + |
+ text_.substr(suffix_start, suffix_length); |
+} |
+ |
+size_t StringSlicer::FindValidBoundaryBefore(size_t index) const { |
+ DCHECK_LE(index, text_.length()); |
+ if (index != text_.length()) |
+ U16_SET_CP_START(text_.data(), 0, index); |
+ return index; |
+} |
+ |
+size_t StringSlicer::FindValidBoundaryAfter(size_t index) const { |
+ DCHECK_LE(index, text_.length()); |
+ if (index != text_.length()) |
+ U16_SET_CP_LIMIT(text_.data(), 0, index, text_.length()); |
+ return index; |
+} |
+ |
base::string16 ElideFilename(const base::FilePath& filename, |
const FontList& font_list, |
float available_pixel_width) { |
@@ -163,8 +174,8 @@ base::string16 ElideFilename(const base::FilePath& filename, |
return base::i18n::GetDisplayStringInLTRDirectionality(filename_utf16); |
if (rootname.empty() || extension.empty()) { |
- const base::string16 elided_name = ElideText(filename_utf16, font_list, |
- available_pixel_width, ELIDE_AT_END); |
+ const base::string16 elided_name = |
+ ElideText(filename_utf16, font_list, available_pixel_width, ELIDE_TAIL); |
return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); |
} |
@@ -179,14 +190,13 @@ base::string16 ElideFilename(const base::FilePath& filename, |
if (ext_width >= available_pixel_width) { |
const base::string16 elided_name = ElideText( |
- rootname + extension, font_list, available_pixel_width, |
- ELIDE_IN_MIDDLE); |
+ rootname + extension, font_list, available_pixel_width, ELIDE_MIDDLE); |
return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); |
} |
float available_root_width = available_pixel_width - ext_width; |
base::string16 elided_name = |
- ElideText(rootname, font_list, available_root_width, ELIDE_AT_END); |
+ ElideText(rootname, font_list, available_root_width, ELIDE_TAIL); |
elided_name += extension; |
return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); |
} |
@@ -194,15 +204,17 @@ base::string16 ElideFilename(const base::FilePath& filename, |
base::string16 ElideText(const base::string16& text, |
const FontList& font_list, |
float available_pixel_width, |
- ElideBehavior elide_behavior) { |
- if (text.empty()) |
+ ElideBehavior behavior) { |
+ DCHECK_NE(behavior, FADE_TAIL); |
+ if (text.empty() || behavior == FADE_TAIL) |
return text; |
+ if (behavior == ELIDE_EMAIL) |
+ return ElideEmail(text, font_list, available_pixel_width); |
const float current_text_pixel_width = GetStringWidthF(text, font_list); |
- const bool elide_in_middle = (elide_behavior == ELIDE_IN_MIDDLE); |
- const bool elide_at_beginning = (elide_behavior == ELIDE_AT_BEGINNING); |
- const bool insert_ellipsis = (elide_behavior != TRUNCATE_AT_END); |
- |
+ const bool elide_in_middle = (behavior == ELIDE_MIDDLE); |
+ const bool elide_at_beginning = (behavior == ELIDE_HEAD); |
+ const bool insert_ellipsis = (behavior != TRUNCATE); |
const base::string16 ellipsis = base::string16(kEllipsisUTF16); |
StringSlicer slicer(text, ellipsis, elide_in_middle, elide_at_beginning); |
@@ -214,10 +226,10 @@ base::string16 ElideText(const base::string16& text, |
// return positive numbers again. Detecting that is probably not worth it |
// (eliding way too much from a ridiculous string is probably still |
// ridiculous), but we should check other widths for bogus values as well. |
- if (current_text_pixel_width <= 0 && !text.empty()) { |
+ if (current_text_pixel_width <= 0) { |
const base::string16 cut = |
slicer.CutString(text.length() / 2, insert_ellipsis); |
- return ElideText(cut, font_list, available_pixel_width, elide_behavior); |
+ return ElideText(cut, font_list, available_pixel_width, behavior); |
} |
if (current_text_pixel_width <= available_pixel_width) |
@@ -254,7 +266,8 @@ base::string16 ElideText(const base::string16& text, |
return slicer.CutString(guess, insert_ellipsis); |
} |
-bool ElideString(const base::string16& input, int max_len, |
+bool ElideString(const base::string16& input, |
+ int max_len, |
base::string16* output) { |
DCHECK_GE(max_len, 0); |
if (static_cast<int>(input.length()) <= max_len) { |
@@ -633,11 +646,10 @@ int RectangleText::WrapWord(const base::string16& word) { |
bool first_fragment = true; |
while (!insufficient_height_ && !text.empty()) { |
base::string16 fragment = |
- ElideText(text, font_list_, available_pixel_width_, |
- TRUNCATE_AT_END); |
+ ElideText(text, font_list_, available_pixel_width_, TRUNCATE); |
// At least one character has to be added at every line, even if the |
// available space is too small. |
- if(fragment.empty()) |
+ if (fragment.empty()) |
fragment = text.substr(0, 1); |
if (!first_fragment && NewLine()) |
lines_added++; |
@@ -665,7 +677,7 @@ int RectangleText::AddWordOverflow(const base::string16& word) { |
lines_added += WrapWord(word); |
} else { |
const ElideBehavior elide_behavior = |
- (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_AT_END : TRUNCATE_AT_END); |
+ (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_TAIL : TRUNCATE); |
const base::string16 elided_word = |
ElideText(word, font_list_, available_pixel_width_, elide_behavior); |
AddToCurrentLine(elided_word); |