Index: ui/gfx/text_elider.cc |
diff --git a/ui/gfx/text_elider.cc b/ui/gfx/text_elider.cc |
index 5b9469614f22f8080a5dee020af64a4058264669..c58a96d9748b4c357e29a07ef01a97cd6f1a3ac9 100644 |
--- a/ui/gfx/text_elider.cc |
+++ b/ui/gfx/text_elider.cc |
@@ -39,68 +39,6 @@ const base::char16 kForwardSlash = '/'; |
namespace { |
-// Helper class to split + elide text, while respecting UTF16 surrogate pairs. |
-class StringSlicer { |
- public: |
- StringSlicer(const base::string16& text, |
- const base::string16& ellipsis, |
- bool elide_in_middle) |
- : text_(text), |
- ellipsis_(ellipsis), |
- elide_in_middle_(elide_in_middle) { |
- } |
- |
- // Cuts |text_| to be |length| characters long. If |elide_in_middle_| is true, |
- // the middle of the string is removed to leave equal-length pieces from the |
- // beginning and end of the string; otherwise, the end of the string is |
- // removed and only the beginning remains. If |insert_ellipsis| is true, |
- // then an ellipsis character will be inserted at the cut point. |
- base::string16 CutString(size_t length, bool insert_ellipsis) { |
- const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_ |
- : base::string16(); |
- |
- 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); |
- } |
- |
- private: |
- // Returns a valid cut boundary at or before |index|. |
- size_t FindValidBoundaryBefore(size_t index) const { |
- DCHECK_LE(index, text_.length()); |
- if (index != text_.length()) |
- U16_SET_CP_START(text_.data(), 0, index); |
- return index; |
- } |
- |
- // Returns a valid cut boundary at or after |index|. |
- size_t 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; |
- } |
- |
- // The text to be sliced. |
- const base::string16& text_; |
- |
- // Ellipsis string to use. |
- const base::string16& ellipsis_; |
- |
- // If true, the middle of the string will be elided. |
- bool elide_in_middle_; |
- |
- DISALLOW_COPY_AND_ASSIGN(StringSlicer); |
-}; |
// Build a path from the first |num_components| elements in |path_elements|. |
// Prepends |path_prefix|, appends |filename|, inserts ellipsis if appropriate. |
@@ -150,6 +88,46 @@ base::string16 ElideComponentizedPath( |
} // namespace |
+StringSlicer::StringSlicer(const base::string16& text, |
+ const base::string16& ellipsis, |
+ bool elide_in_middle) |
+ : text_(text), |
+ ellipsis_(ellipsis), |
+ elide_in_middle_(elide_in_middle) { |
+} |
+ |
+base::string16 StringSlicer::CutString(size_t length, bool insert_ellipsis) { |
+ const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_ |
+ : base::string16(); |
+ |
+ 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 ElideEmail(const base::string16& email, |
const FontList& font_list, |
float available_pixel_width) { |
@@ -477,7 +455,8 @@ base::string16 ElideText(const base::string16& text, |
// (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()) { |
- const base::string16 cut = slicer.CutString(text.length() / 2, false); |
+ const base::string16 cut = |
+ slicer.CutString(text.length() / 2, insert_ellipsis); |
return ElideText(cut, font_list, available_pixel_width, elide_behavior); |
} |
@@ -493,20 +472,23 @@ base::string16 ElideText(const base::string16& text, |
size_t hi = text.length() - 1; |
size_t guess; |
for (guess = (lo + hi) / 2; lo <= hi; guess = (lo + hi) / 2) { |
- // We check the length of the whole desired string at once to ensure we |
+ // 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_length = GetStringWidthF(cut, font_list); |
- // Check again that we didn't hit a Pango width overflow. If so, cut the |
- // current string in half and start over. |
- if (guess_length <= 0) { |
- return ElideText(slicer.CutString(guess / 2, false), |
- font_list, available_pixel_width, elide_behavior); |
- } |
- if (guess_length > available_pixel_width) |
+ const float guess_width = GetStringWidthF(cut, font_list); |
+ if (guess_width == available_pixel_width) |
+ break; |
+ if (guess_width > available_pixel_width) { |
hi = guess - 1; |
- else |
+ // 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); |