OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 #include <vector> | 5 #include <vector> |
6 | 6 |
7 #include "ui/base/text/text_elider.h" | 7 #include "ui/base/text/text_elider.h" |
8 | 8 |
9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
10 #include "base/i18n/break_iterator.h" | 10 #include "base/i18n/break_iterator.h" |
11 #include "base/i18n/char_iterator.h" | 11 #include "base/i18n/char_iterator.h" |
12 #include "base/i18n/rtl.h" | 12 #include "base/i18n/rtl.h" |
| 13 #include "base/scoped_ptr.h" |
13 #include "base/string_split.h" | 14 #include "base/string_split.h" |
14 #include "base/string_util.h" | 15 #include "base/string_util.h" |
15 #include "base/sys_string_conversions.h" | 16 #include "base/sys_string_conversions.h" |
16 #include "base/utf_string_conversions.h" | 17 #include "base/utf_string_conversions.h" |
17 #include "googleurl/src/gurl.h" | 18 #include "googleurl/src/gurl.h" |
18 #include "net/base/escape.h" | 19 #include "net/base/escape.h" |
19 #include "net/base/net_util.h" | 20 #include "net/base/net_util.h" |
20 #include "net/base/registry_controlled_domain.h" | 21 #include "net/base/registry_controlled_domain.h" |
21 #include "ui/gfx/font.h" | 22 #include "ui/gfx/font.h" |
| 23 #include "unicode/rbbi.h" |
| 24 #include "unicode/uloc.h" |
22 | 25 |
23 namespace ui { | 26 namespace ui { |
24 | 27 |
25 // U+2026 in utf8 | 28 // U+2026 in utf8 |
26 const char kEllipsis[] = "\xE2\x80\xA6"; | 29 const char kEllipsis[] = "\xE2\x80\xA6"; |
27 const char16 kForwardSlash = '/'; | 30 const char16 kForwardSlash = '/'; |
28 | 31 |
29 namespace { | 32 namespace { |
30 | 33 |
31 // Cuts |text| to be |length| characters long. If |cut_in_middle| is true, the | 34 // Cuts |text| to be |length| characters long. If |cut_in_middle| is true, the |
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
666 namespace ui { | 669 namespace ui { |
667 | 670 |
668 bool ElideRectangleString(const string16& input, size_t max_rows, | 671 bool ElideRectangleString(const string16& input, size_t max_rows, |
669 size_t max_cols, bool strict, string16* output) { | 672 size_t max_cols, bool strict, string16* output) { |
670 RectangleString rect(max_rows, max_cols, strict, output); | 673 RectangleString rect(max_rows, max_cols, strict, output); |
671 rect.Init(); | 674 rect.Init(); |
672 rect.AddString(input); | 675 rect.AddString(input); |
673 return rect.Finalize(); | 676 return rect.Finalize(); |
674 } | 677 } |
675 | 678 |
| 679 string16 TruncateString(const string16& string, size_t length) { |
| 680 if (string.size() <= length) |
| 681 // String fits, return it. |
| 682 return string; |
| 683 |
| 684 if (length == 0) { |
| 685 // No room for the elide string, return an empty string. |
| 686 return string16(); |
| 687 } |
| 688 size_t max = length - 1; |
| 689 |
| 690 // Added to the end of strings that are too big. |
| 691 static const char16 kElideString[] = { 0x2026, 0 }; |
| 692 |
| 693 if (max == 0) { |
| 694 // Just enough room for the elide string. |
| 695 return kElideString; |
| 696 } |
| 697 |
| 698 // Use a line iterator to find the first boundary. |
| 699 UErrorCode status = U_ZERO_ERROR; |
| 700 scoped_ptr<icu::RuleBasedBreakIterator> bi( |
| 701 static_cast<icu::RuleBasedBreakIterator*>( |
| 702 icu::RuleBasedBreakIterator::createLineInstance( |
| 703 icu::Locale::getDefault(), status))); |
| 704 if (U_FAILURE(status)) |
| 705 return string.substr(0, max) + kElideString; |
| 706 bi->setText(string.c_str()); |
| 707 int32_t index = bi->preceding(static_cast<int32_t>(max)); |
| 708 if (index == icu::BreakIterator::DONE) { |
| 709 index = static_cast<int32_t>(max); |
| 710 } else { |
| 711 // Found a valid break (may be the beginning of the string). Now use |
| 712 // a character iterator to find the previous non-whitespace character. |
| 713 icu::StringCharacterIterator char_iterator(string.c_str()); |
| 714 if (index == 0) { |
| 715 // No valid line breaks. Start at the end again. This ensures we break |
| 716 // on a valid character boundary. |
| 717 index = static_cast<int32_t>(max); |
| 718 } |
| 719 char_iterator.setIndex(index); |
| 720 while (char_iterator.hasPrevious()) { |
| 721 char_iterator.previous(); |
| 722 if (!(u_isspace(char_iterator.current()) || |
| 723 u_charType(char_iterator.current()) == U_CONTROL_CHAR || |
| 724 u_charType(char_iterator.current()) == U_NON_SPACING_MARK)) { |
| 725 // Not a whitespace character. Advance the iterator so that we |
| 726 // include the current character in the truncated string. |
| 727 char_iterator.next(); |
| 728 break; |
| 729 } |
| 730 } |
| 731 if (char_iterator.hasPrevious()) { |
| 732 // Found a valid break point. |
| 733 index = char_iterator.getIndex(); |
| 734 } else { |
| 735 // String has leading whitespace, return the elide string. |
| 736 return kElideString; |
| 737 } |
| 738 } |
| 739 return string.substr(0, index) + kElideString; |
| 740 } |
| 741 |
676 } // namespace ui | 742 } // namespace ui |
OLD | NEW |