| 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);
|
|
|