Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: ui/gfx/text_elider.cc

Issue 1340423006: Improve text elision in TruncateString(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | ui/gfx/text_elider_unittest.cc » ('j') | ui/gfx/text_elider_unittest.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 // String fits, return it.
msw 2015/09/17 18:42:44 unrelated nit: please move the comment above the i
Peter Kasting 2015/09/19 02:43:25 Fixed by exchanging these for some EOL comments (w
759 return string; 760 return string;
760 761
761 if (length == 0) 762 if (length == 0)
762 // No room for the elide string, return an empty string. 763 // No room for the elide string, return an empty string.
763 return base::string16(); 764 return base::string16();
764 765
765 size_t max = length - 1;
766
767 // Added to the end of strings that are too big. 766 // Added to the end of strings that are too big.
768 static const base::char16 kElideString[] = { 0x2026, 0 }; 767 static const base::char16 kElideString[] = { 0x2026, 0 };
769 768
770 if (max == 0) 769 if (length == 1)
771 // Just enough room for the elide string. 770 // Just enough room for the elide string.
772 return kElideString; 771 return kElideString;
773 772
774 int32_t index = static_cast<int32_t>(max); 773 int32_t index = static_cast<int32_t>(length) - (word_break ? 0 : 1);
msw 2015/09/17 18:42:44 I'd be a lot more comfortable with this code using
Peter Kasting 2015/09/17 19:39:03 I tried a couple times yesterday to rewrite the ch
msw 2015/09/17 20:45:10 That seems fine, except lines 804 and 814 seem to
Peter Kasting 2015/09/17 20:58:05 804 is definitely a regression I need to fix. I m
msw 2015/09/17 21:06:26 OK, sgtm
Peter Kasting 2015/09/19 02:43:25 Fixed line 804 by restoring the next() call.
775 if (break_type == WORD_BREAK) { 774 if (word_break) {
776 // Use a line iterator to find the first boundary. 775 // Use a word iterator to find the first boundary.
777 UErrorCode status = U_ZERO_ERROR; 776 UErrorCode status = U_ZERO_ERROR;
778 scoped_ptr<icu::BreakIterator> bi( 777 scoped_ptr<icu::BreakIterator> bi(
779 icu::RuleBasedBreakIterator::createLineInstance( 778 icu::RuleBasedBreakIterator::createWordInstance(
780 icu::Locale::getDefault(), status)); 779 icu::Locale::getDefault(), status));
781 if (U_FAILURE(status)) 780 if (U_FAILURE(status))
782 return string.substr(0, max) + kElideString; 781 return string.substr(0, length - 1) + kElideString;
msw 2015/09/17 18:42:44 It's unrelated (okay for follow-up), but I think t
Peter Kasting 2015/09/19 02:43:25 Yep, will address in the followup.
783 bi->setText(string.c_str()); 782 bi->setText(string.c_str());
784 index = bi->preceding(index); 783 index = bi->preceding(index);
msw 2015/09/17 18:42:44 nit: consider using |index = bi->preceding(length)
Peter Kasting 2015/09/19 02:43:25 Done.
785 if (index == icu::BreakIterator::DONE || index == 0) { 784 if (index == icu::BreakIterator::DONE || index == 0) {
786 // We either found no valid line break at all, or one right at the 785 // 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 786 // beginning of the string. Go back to the end; we'll have to break in the
788 // middle of a word. 787 // middle of a word.
789 index = static_cast<int32_t>(max); 788 index = static_cast<int32_t>(length - 1);
790 } 789 }
791 } 790 }
792 791
793 // Use a character iterator to find the previous non-whitespace character. 792 // By this point, |index| should point at the character that's a candidate for
793 // replacing with an ellipsis. Use a character iterator to check previous
794 // characters and stop as soon as we find a previous non-whitespace character.
794 icu::StringCharacterIterator char_iterator(string.c_str()); 795 icu::StringCharacterIterator char_iterator(string.c_str());
795 char_iterator.setIndex(index); 796 char_iterator.setIndex(index);
796 while (char_iterator.hasPrevious()) { 797 while (char_iterator.hasPrevious()) {
797 char_iterator.previous(); 798 char_iterator.previous();
798 if (!(u_isspace(char_iterator.current()) || 799 if (!(u_isspace(char_iterator.current()) ||
799 u_charType(char_iterator.current()) == U_CONTROL_CHAR || 800 u_charType(char_iterator.current()) == U_CONTROL_CHAR ||
800 u_charType(char_iterator.current()) == U_NON_SPACING_MARK)) { 801 u_charType(char_iterator.current()) == U_NON_SPACING_MARK)) {
801 // Not a whitespace character. Advance the iterator so that we 802 // Not a whitespace character. Truncate to everything up to and including
802 // include the current character in the truncated string. 803 // this character, plus the ellipsis.
msw 2015/09/17 18:42:44 nit: s/plus/and append/
Peter Kasting 2015/09/19 02:43:25 Done.
803 char_iterator.next(); 804 return string.substr(0, char_iterator.getIndex() + 1) + kElideString;
804 break;
805 } 805 }
806 } 806 }
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 807
815 return string.substr(0, index) + kElideString; 808 // Couldn't find a previous non-whitespace character. If we were originally
809 // word-breaking, and index != length - 1, then the string is |index|
810 // whitespace characters followed by a word we're trying to break in the midst
811 // of, and we can fit at least one character of the word in the elided string.
812 // Do that rather than just returning an ellipsis.
813 if (word_break && (index != static_cast<int32_t>(length - 1)))
814 return string.substr(0, length - 1) + kElideString;
msw 2015/09/17 18:42:44 This should use a char iterator to avoid chopping
815
816 // Trying to break after only whitespace, elide all of it.
817 return kElideString;
816 } 818 }
817 819
818 } // namespace gfx 820 } // namespace gfx
OLDNEW
« no previous file with comments | « no previous file | ui/gfx/text_elider_unittest.cc » ('j') | ui/gfx/text_elider_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698