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