Index: ui/gfx/text_elider.cc |
diff --git a/ui/gfx/text_elider.cc b/ui/gfx/text_elider.cc |
index 8c07bdecd5f581d2e88b3bf20f1947bd94fe1c6b..c8a823d31c89dad9755d2ba5823ee0341cb27b4b 100644 |
--- a/ui/gfx/text_elider.cc |
+++ b/ui/gfx/text_elider.cc |
@@ -24,6 +24,7 @@ |
#include "third_party/icu/source/common/unicode/rbbi.h" |
#include "third_party/icu/source/common/unicode/uloc.h" |
#include "ui/gfx/font_list.h" |
+#include "ui/gfx/render_text.h" |
#include "ui/gfx/text_utils.h" |
using base::ASCIIToUTF16; |
@@ -32,76 +33,6 @@ using base::WideToUTF16; |
namespace gfx { |
-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) { |
- if (GetStringWidthF(email, font_list) <= available_pixel_width) |
- return email; |
- |
- // Split the email into its local-part (username) and domain-part. The email |
- // spec technically allows for @ symbols in the local-part (username) of the |
- // email under some special requirements. It is guaranteed that there is no @ |
- // symbol in the domain part of the email however so splitting at the last @ |
- // symbol is safe. |
- const size_t split_index = email.find_last_of('@'); |
- DCHECK_NE(split_index, base::string16::npos); |
- base::string16 username = email.substr(0, split_index); |
- base::string16 domain = email.substr(split_index + 1); |
- DCHECK(!username.empty()); |
- DCHECK(!domain.empty()); |
- |
- // Subtract the @ symbol from the available width as it is mandatory. |
- const base::string16 kAtSignUTF16 = ASCIIToUTF16("@"); |
- available_pixel_width -= GetStringWidthF(kAtSignUTF16, font_list); |
- |
- // Check whether eliding the domain is necessary: if eliding the username |
- // is sufficient, the domain will not be elided. |
- const float full_username_width = GetStringWidthF(username, font_list); |
- const float available_domain_width = |
- available_pixel_width - |
- std::min(full_username_width, |
- GetStringWidthF(username.substr(0, 1) + kEllipsisUTF16, |
- font_list)); |
- if (GetStringWidthF(domain, font_list) > available_domain_width) { |
- // Elide the domain so that it only takes half of the available width. |
- // Should the username not need all the width available in its half, the |
- // domain will occupy the leftover width. |
- // If |desired_domain_width| is greater than |available_domain_width|: the |
- // minimal username elision allowed by the specifications will not fit; thus |
- // |desired_domain_width| must be <= |available_domain_width| at all cost. |
- const float desired_domain_width = |
- 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_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) |
- return base::string16(kEllipsisUTF16); |
- } |
- |
- // Fit the username in the remaining width (at this point the elided username |
- // 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_TAIL); |
- return username + kAtSignUTF16 + domain; |
-} |
- |
-} // namespace |
- |
// U+2026 in utf8 |
const char kEllipsis[] = "\xE2\x80\xA6"; |
const base::char16 kEllipsisUTF16[] = { 0x2026, 0 }; |
@@ -206,64 +137,10 @@ base::string16 ElideText(const base::string16& text, |
float available_pixel_width, |
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 = (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); |
- |
- // Pango will return 0 width for absurdly long strings. Cut the string in |
- // half and try again. |
- // This is caused by an int overflow in Pango (specifically, in |
- // pango_glyph_string_extents_range). It's actually more subtle than just |
- // returning 0, since on super absurdly long strings, the int can wrap and |
- // 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) { |
- const base::string16 cut = |
- slicer.CutString(text.length() / 2, insert_ellipsis); |
- return ElideText(cut, font_list, available_pixel_width, behavior); |
- } |
- |
- if (current_text_pixel_width <= available_pixel_width) |
- return text; |
- |
- if (insert_ellipsis && |
- GetStringWidthF(ellipsis, font_list) > available_pixel_width) |
- return base::string16(); |
- |
- // Use binary search to compute the elided text. |
- size_t lo = 0; |
- size_t hi = text.length() - 1; |
- size_t guess; |
- for (guess = (lo + hi) / 2; lo <= hi; guess = (lo + hi) / 2) { |
- // We check the width of the whole desired string at once to ensure we |
- // handle kerning/ligatures/etc. correctly. |
- // TODO(skanuj) : Handle directionality of ellipsis based on adjacent |
- // characters. See crbug.com/327963. |
- const base::string16 cut = slicer.CutString(guess, insert_ellipsis); |
- const float guess_width = GetStringWidthF(cut, font_list); |
- if (guess_width == available_pixel_width) |
- break; |
- if (guess_width > available_pixel_width) { |
- hi = guess - 1; |
- // Move back if we are on loop terminating condition, and guess is wider |
- // than available. |
- if (hi < lo) |
- lo = hi; |
- } else { |
- lo = guess + 1; |
- } |
- } |
- |
- return slicer.CutString(guess, insert_ellipsis); |
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
+ render_text->SetCursorEnabled(false); |
+ render_text->SetFontList(font_list); |
+ return render_text->Elide(text, available_pixel_width, behavior); |
} |
bool ElideString(const base::string16& input, |