OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This file implements utility functions for eliding and formatting UI text. | 5 // This file implements utility functions for eliding and formatting UI text. |
6 // | 6 // |
7 // Note that several of the functions declared in text_elider.h are implemented | 7 // Note that several of the functions declared in text_elider.h are implemented |
8 // in this file using helper classes in an unnamed namespace. | 8 // in this file using helper classes in an unnamed namespace. |
9 | 9 |
10 #include "ui/gfx/text_elider.h" | 10 #include "ui/gfx/text_elider.h" |
(...skipping 734 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
745 wrap_behavior, | 745 wrap_behavior, |
746 lines); | 746 lines); |
747 rect.Init(); | 747 rect.Init(); |
748 rect.AddString(input); | 748 rect.AddString(input); |
749 return rect.Finalize(); | 749 return rect.Finalize(); |
750 } | 750 } |
751 | 751 |
752 base::string16 TruncateString(const base::string16& string, | 752 base::string16 TruncateString(const base::string16& string, |
753 size_t length, | 753 size_t length, |
754 BreakType break_type) { | 754 BreakType break_type) { |
755 DCHECK(break_type == CHARACTER_BREAK || break_type == WORD_BREAK); | 755 const bool word_break = break_type == WORD_BREAK; |
756 DCHECK(word_break || (break_type == CHARACTER_BREAK)); | |
756 | 757 |
757 if (string.size() <= length) | 758 if (string.size() <= length) |
758 // String fits, return it. | 759 return string; // No need to elide. |
759 return string; | |
760 | 760 |
761 if (length == 0) | 761 if (length == 0) |
762 // No room for the elide string, return an empty string. | 762 return base::string16(); // No room for anything, even an ellipsis. |
763 return base::string16(); | |
764 | |
765 size_t max = length - 1; | |
766 | 763 |
767 // Added to the end of strings that are too big. | 764 // Added to the end of strings that are too big. |
768 static const base::char16 kElideString[] = { 0x2026, 0 }; | 765 static const base::char16 kElideString[] = { 0x2026, 0 }; |
769 | 766 |
770 if (max == 0) | 767 if (length == 1) |
771 // Just enough room for the elide string. | 768 return kElideString; // Only room for an ellipsis. |
772 return kElideString; | |
773 | 769 |
774 int32_t index = static_cast<int32_t>(max); | 770 int32_t index = static_cast<int32_t>(length - 1); |
775 if (break_type == WORD_BREAK) { | 771 if (word_break) { |
776 // Use a line iterator to find the first boundary. | 772 // Use a word iterator to find the first boundary. |
777 UErrorCode status = U_ZERO_ERROR; | 773 UErrorCode status = U_ZERO_ERROR; |
778 scoped_ptr<icu::BreakIterator> bi( | 774 scoped_ptr<icu::BreakIterator> bi( |
779 icu::RuleBasedBreakIterator::createLineInstance( | 775 icu::RuleBasedBreakIterator::createWordInstance( |
780 icu::Locale::getDefault(), status)); | 776 icu::Locale::getDefault(), status)); |
781 if (U_FAILURE(status)) | 777 if (U_FAILURE(status)) |
782 return string.substr(0, max) + kElideString; | 778 return string.substr(0, length - 1) + kElideString; |
783 bi->setText(string.c_str()); | 779 bi->setText(string.c_str()); |
784 index = bi->preceding(index); | 780 index = bi->preceding(static_cast<int32_t>(length)); |
785 if (index == icu::BreakIterator::DONE || index == 0) { | 781 if (index == icu::BreakIterator::DONE || index == 0) { |
786 // We either found no valid line break at all, or one right at the | 782 // We either found no valid word break at all, or one right at the |
787 // beginning of the string. Go back to the end; we'll have to break in the | 783 // beginning of the string. Go back to the end; we'll have to break in the |
788 // middle of a word. | 784 // middle of a word. |
789 index = static_cast<int32_t>(max); | 785 index = static_cast<int32_t>(length - 1); |
790 } | 786 } |
791 } | 787 } |
792 | 788 |
793 // Use a character iterator to find the previous non-whitespace character. | 789 // By this point, |index| should point at the character that's a candidate for |
790 // replacing with an ellipsis. Use a character iterator to check previous | |
791 // characters and stop as soon as we find a previous non-whitespace character. | |
794 icu::StringCharacterIterator char_iterator(string.c_str()); | 792 icu::StringCharacterIterator char_iterator(string.c_str()); |
795 char_iterator.setIndex(index); | 793 char_iterator.setIndex(index); |
796 while (char_iterator.hasPrevious()) { | 794 while (char_iterator.hasPrevious()) { |
797 char_iterator.previous(); | 795 char_iterator.previous(); |
798 if (!(u_isspace(char_iterator.current()) || | 796 if (!(u_isspace(char_iterator.current()) || |
799 u_charType(char_iterator.current()) == U_CONTROL_CHAR || | 797 u_charType(char_iterator.current()) == U_CONTROL_CHAR || |
800 u_charType(char_iterator.current()) == U_NON_SPACING_MARK)) { | 798 u_charType(char_iterator.current()) == U_NON_SPACING_MARK)) { |
801 // Not a whitespace character. Advance the iterator so that we | 799 // Not a whitespace character. Truncate to everything up to and including |
802 // include the current character in the truncated string. | 800 // this character, and append an ellipsis. |
803 char_iterator.next(); | 801 char_iterator.next(); |
804 break; | 802 return string.substr(0, char_iterator.getIndex()) + kElideString; |
805 } | 803 } |
806 } | 804 } |
807 if (char_iterator.hasPrevious()) { | |
808 // Found a valid break point. | |
809 index = char_iterator.getIndex(); | |
810 } else { | |
811 // String has leading whitespace, return the elide string. | |
812 return kElideString; | |
813 } | |
814 | 805 |
815 return string.substr(0, index) + kElideString; | 806 // Couldn't find a previous non-whitespace character. If we were originally |
807 // word-breaking, and index != length - 1, then the string is |index| | |
808 // whitespace characters followed by a word we're trying to break in the midst | |
809 // of, and we can fit at least one character of the word in the elided string. | |
810 // Do that rather than just returning an ellipsis. | |
811 if (word_break && (index != static_cast<int32_t>(length - 1))) | |
812 return string.substr(0, length - 1) + kElideString; | |
msw
2015/09/21 18:28:10
This is the one new place that might break multi-c
| |
813 | |
814 // Trying to break after only whitespace, elide all of it. | |
815 return kElideString; | |
816 } | 816 } |
817 | 817 |
818 } // namespace gfx | 818 } // namespace gfx |
OLD | NEW |