| 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" |
| 11 | 11 |
| 12 #include <stdint.h> | 12 #include <stdint.h> |
| 13 | 13 |
| 14 #include <string> | 14 #include <string> |
| 15 #include <vector> | 15 #include <vector> |
| 16 | 16 |
| 17 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
| 18 #include "base/i18n/break_iterator.h" | 18 #include "base/i18n/break_iterator.h" |
| 19 #include "base/i18n/char_iterator.h" | 19 #include "base/i18n/char_iterator.h" |
| 20 #include "base/i18n/rtl.h" | 20 #include "base/i18n/rtl.h" |
| 21 #include "base/memory/scoped_ptr.h" | 21 #include "base/memory/scoped_ptr.h" |
| 22 #include "base/numerics/safe_conversions.h" | |
| 23 #include "base/strings/string_split.h" | 22 #include "base/strings/string_split.h" |
| 24 #include "base/strings/string_util.h" | 23 #include "base/strings/string_util.h" |
| 25 #include "base/strings/sys_string_conversions.h" | 24 #include "base/strings/sys_string_conversions.h" |
| 26 #include "base/strings/utf_string_conversions.h" | 25 #include "base/strings/utf_string_conversions.h" |
| 27 #include "third_party/icu/source/common/unicode/rbbi.h" | 26 #include "third_party/icu/source/common/unicode/rbbi.h" |
| 28 #include "third_party/icu/source/common/unicode/uchar.h" | |
| 29 #include "third_party/icu/source/common/unicode/uloc.h" | 27 #include "third_party/icu/source/common/unicode/uloc.h" |
| 30 #include "third_party/icu/source/common/unicode/umachine.h" | 28 #include "third_party/icu/source/common/unicode/umachine.h" |
| 31 #include "third_party/icu/source/common/unicode/utf16.h" | |
| 32 #include "ui/gfx/font_list.h" | 29 #include "ui/gfx/font_list.h" |
| 33 #include "ui/gfx/geometry/rect_conversions.h" | 30 #include "ui/gfx/geometry/rect_conversions.h" |
| 34 #include "ui/gfx/render_text.h" | 31 #include "ui/gfx/render_text.h" |
| 35 #include "ui/gfx/text_utils.h" | 32 #include "ui/gfx/text_utils.h" |
| 36 | 33 |
| 37 using base::ASCIIToUTF16; | 34 using base::ASCIIToUTF16; |
| 38 using base::UTF8ToUTF16; | 35 using base::UTF8ToUTF16; |
| 39 using base::WideToUTF16; | 36 using base::WideToUTF16; |
| 40 | 37 |
| 41 namespace gfx { | 38 namespace gfx { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 | 94 |
| 98 // Fit the username in the remaining width (at this point the elided username | 95 // Fit the username in the remaining width (at this point the elided username |
| 99 // is guaranteed to fit with at least one character remaining given all the | 96 // is guaranteed to fit with at least one character remaining given all the |
| 100 // precautions taken earlier). | 97 // precautions taken earlier). |
| 101 available_pixel_width -= GetStringWidthF(domain, font_list); | 98 available_pixel_width -= GetStringWidthF(domain, font_list); |
| 102 username = ElideText(username, font_list, available_pixel_width, ELIDE_TAIL); | 99 username = ElideText(username, font_list, available_pixel_width, ELIDE_TAIL); |
| 103 return username + kAtSignUTF16 + domain; | 100 return username + kAtSignUTF16 + domain; |
| 104 } | 101 } |
| 105 #endif | 102 #endif |
| 106 | 103 |
| 107 // Returns true if the code point |c| is a combining mark character in Unicode. | |
| 108 bool CharIsMark(UChar32 c) { | |
| 109 int8_t char_type = u_charType(c); | |
| 110 return char_type == U_NON_SPACING_MARK || char_type == U_ENCLOSING_MARK || | |
| 111 char_type == U_COMBINING_SPACING_MARK; | |
| 112 } | |
| 113 | |
| 114 // Gets the code point of |str| at the given code unit position |index|. If | |
| 115 // |index| is a surrogate code unit, returns the whole code point (unless the | |
| 116 // code unit is unpaired, in which case it just returns the surrogate value). | |
| 117 UChar32 GetCodePointAt(const base::string16& str, size_t index) { | |
| 118 UChar32 c; | |
| 119 U16_GET(str.data(), 0, index, str.size(), c); | |
| 120 return c; | |
| 121 } | |
| 122 | |
| 123 } // namespace | 104 } // namespace |
| 124 | 105 |
| 125 // U+2026 in utf8 | 106 // U+2026 in utf8 |
| 126 const char kEllipsis[] = "\xE2\x80\xA6"; | 107 const char kEllipsis[] = "\xE2\x80\xA6"; |
| 127 const base::char16 kEllipsisUTF16[] = { 0x2026, 0 }; | 108 const base::char16 kEllipsisUTF16[] = { 0x2026, 0 }; |
| 128 const base::char16 kForwardSlash = '/'; | 109 const base::char16 kForwardSlash = '/'; |
| 129 | 110 |
| 130 StringSlicer::StringSlicer(const base::string16& text, | 111 StringSlicer::StringSlicer(const base::string16& text, |
| 131 const base::string16& ellipsis, | 112 const base::string16& ellipsis, |
| 132 bool elide_in_middle, | 113 bool elide_in_middle, |
| 133 bool elide_at_beginning) | 114 bool elide_at_beginning) |
| 134 : text_(text), | 115 : text_(text), |
| 135 ellipsis_(ellipsis), | 116 ellipsis_(ellipsis), |
| 136 elide_in_middle_(elide_in_middle), | 117 elide_in_middle_(elide_in_middle), |
| 137 elide_at_beginning_(elide_at_beginning) { | 118 elide_at_beginning_(elide_at_beginning) { |
| 138 } | 119 } |
| 139 | 120 |
| 140 base::string16 StringSlicer::CutString(size_t length, | 121 base::string16 StringSlicer::CutString(size_t length, |
| 141 bool insert_ellipsis) const { | 122 bool insert_ellipsis) const { |
| 142 const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_ | 123 const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_ |
| 143 : base::string16(); | 124 : base::string16(); |
| 144 | 125 |
| 145 if (elide_at_beginning_) | 126 if (elide_at_beginning_) |
| 146 return ellipsis_text + | 127 return ellipsis_text + |
| 147 text_.substr(FindValidBoundaryBefore(text_.length() - length)); | 128 text_.substr( |
| 129 FindValidBoundaryBefore(text_, text_.length() - length)); |
| 148 | 130 |
| 149 if (!elide_in_middle_) | 131 if (!elide_in_middle_) |
| 150 return text_.substr(0, FindValidBoundaryBefore(length)) + ellipsis_text; | 132 return text_.substr(0, FindValidBoundaryBefore(text_, length)) + |
| 133 ellipsis_text; |
| 151 | 134 |
| 152 // We put the extra character, if any, before the cut. | 135 // We put the extra character, if any, before the cut. |
| 153 const size_t half_length = length / 2; | 136 const size_t half_length = length / 2; |
| 154 const size_t prefix_length = FindValidBoundaryBefore(length - half_length); | 137 const size_t prefix_length = |
| 138 FindValidBoundaryBefore(text_, length - half_length); |
| 155 const size_t suffix_start = | 139 const size_t suffix_start = |
| 156 FindValidBoundaryAfter(text_.length() - half_length); | 140 FindValidBoundaryAfter(text_, text_.length() - half_length); |
| 157 return text_.substr(0, prefix_length) + ellipsis_text + | 141 return text_.substr(0, prefix_length) + ellipsis_text + |
| 158 text_.substr(suffix_start); | 142 text_.substr(suffix_start); |
| 159 } | 143 } |
| 160 | 144 |
| 161 size_t StringSlicer::FindValidBoundaryBefore(size_t index) const { | |
| 162 size_t length = text_.length(); | |
| 163 DCHECK_LE(index, length); | |
| 164 if (index == length) | |
| 165 return index; | |
| 166 | |
| 167 // If |index| straddles a combining character sequence, go back until we find | |
| 168 // a base character. | |
| 169 while (index > 0 && CharIsMark(GetCodePointAt(text_, index))) | |
| 170 --index; | |
| 171 | |
| 172 // If |index| straddles a UTF-16 surrogate pair, go back. | |
| 173 U16_SET_CP_START(text_.data(), 0, index); | |
| 174 return index; | |
| 175 } | |
| 176 | |
| 177 size_t StringSlicer::FindValidBoundaryAfter(size_t index) const { | |
| 178 DCHECK_LE(index, text_.length()); | |
| 179 if (index == text_.length()) | |
| 180 return index; | |
| 181 | |
| 182 int32_t text_index = base::checked_cast<int32_t>(index); | |
| 183 int32_t text_length = base::checked_cast<int32_t>(text_.length()); | |
| 184 | |
| 185 // If |index| straddles a combining character sequence, go forward until we | |
| 186 // find a base character. | |
| 187 while (text_index < text_length && | |
| 188 CharIsMark(GetCodePointAt(text_, text_index))) { | |
| 189 ++text_index; | |
| 190 } | |
| 191 | |
| 192 // If |index| straddles a UTF-16 surrogate pair, go forward. | |
| 193 U16_SET_CP_LIMIT(text_.data(), 0, text_index, text_length); | |
| 194 return static_cast<size_t>(text_index); | |
| 195 } | |
| 196 | |
| 197 base::string16 ElideFilename(const base::FilePath& filename, | 145 base::string16 ElideFilename(const base::FilePath& filename, |
| 198 const FontList& font_list, | 146 const FontList& font_list, |
| 199 float available_pixel_width) { | 147 float available_pixel_width) { |
| 200 #if defined(OS_WIN) | 148 #if defined(OS_WIN) |
| 201 base::string16 filename_utf16 = filename.value(); | 149 base::string16 filename_utf16 = filename.value(); |
| 202 base::string16 extension = filename.Extension(); | 150 base::string16 extension = filename.Extension(); |
| 203 base::string16 rootname = filename.BaseName().RemoveExtension().value(); | 151 base::string16 rootname = filename.BaseName().RemoveExtension().value(); |
| 204 #elif defined(OS_POSIX) | 152 #elif defined(OS_POSIX) |
| 205 base::string16 filename_utf16 = WideToUTF16(base::SysNativeMBToWide( | 153 base::string16 filename_utf16 = WideToUTF16(base::SysNativeMBToWide( |
| 206 filename.value())); | 154 filename.value())); |
| (...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 861 index = char_iterator.getIndex(); | 809 index = char_iterator.getIndex(); |
| 862 } else { | 810 } else { |
| 863 // String has leading whitespace, return the elide string. | 811 // String has leading whitespace, return the elide string. |
| 864 return kElideString; | 812 return kElideString; |
| 865 } | 813 } |
| 866 | 814 |
| 867 return string.substr(0, index) + kElideString; | 815 return string.substr(0, index) + kElideString; |
| 868 } | 816 } |
| 869 | 817 |
| 870 } // namespace gfx | 818 } // namespace gfx |
| OLD | NEW |