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