 Chromium Code Reviews
 Chromium Code Reviews Issue 1070223004:
  Stop combining text runs which are connected by 'COMMON' blocks.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 1070223004:
  Stop combining text runs which are connected by 'COMMON' blocks.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| 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" | 22 #include "base/numerics/safe_conversions.h" | 
| 23 #include "base/strings/string_split.h" | 23 #include "base/strings/string_split.h" | 
| 24 #include "base/strings/string_util.h" | 24 #include "base/strings/string_util.h" | 
| 25 #include "base/strings/sys_string_conversions.h" | 25 #include "base/strings/sys_string_conversions.h" | 
| 26 #include "base/strings/utf_string_conversions.h" | 26 #include "base/strings/utf_string_conversions.h" | 
| 27 #include "third_party/icu/source/common/unicode/rbbi.h" | 27 #include "third_party/icu/source/common/unicode/rbbi.h" | 
| 28 #include "third_party/icu/source/common/unicode/uchar.h" | 28 #include "third_party/icu/source/common/unicode/uchar.h" | 
| 
msw
2015/06/03 00:32:03
nit: can we remove some includes, like this one, n
 
xdai1
2015/06/06 00:05:19
Done.
 | |
| 29 #include "third_party/icu/source/common/unicode/uloc.h" | 29 #include "third_party/icu/source/common/unicode/uloc.h" | 
| 30 #include "third_party/icu/source/common/unicode/umachine.h" | 30 #include "third_party/icu/source/common/unicode/umachine.h" | 
| 31 #include "third_party/icu/source/common/unicode/utf16.h" | 31 #include "third_party/icu/source/common/unicode/utf16.h" | 
| 
msw
2015/06/03 00:32:03
ditto
 
xdai1
2015/06/06 00:05:19
Done.
 | |
| 32 #include "ui/gfx/font_list.h" | 32 #include "ui/gfx/font_list.h" | 
| 33 #include "ui/gfx/geometry/rect_conversions.h" | 33 #include "ui/gfx/geometry/rect_conversions.h" | 
| 34 #include "ui/gfx/render_text.h" | 34 #include "ui/gfx/render_text.h" | 
| 35 #include "ui/gfx/text_utils.h" | 35 #include "ui/gfx/text_utils.h" | 
| 36 | 36 | 
| 37 using base::ASCIIToUTF16; | 37 using base::ASCIIToUTF16; | 
| 38 using base::UTF8ToUTF16; | 38 using base::UTF8ToUTF16; | 
| 39 using base::WideToUTF16; | 39 using base::WideToUTF16; | 
| 40 | 40 | 
| 41 namespace gfx { | 41 namespace gfx { | 
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 | 97 | 
| 98 // Fit the username in the remaining width (at this point the elided username | 98 // 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 | 99 // is guaranteed to fit with at least one character remaining given all the | 
| 100 // precautions taken earlier). | 100 // precautions taken earlier). | 
| 101 available_pixel_width -= GetStringWidthF(domain, font_list); | 101 available_pixel_width -= GetStringWidthF(domain, font_list); | 
| 102 username = ElideText(username, font_list, available_pixel_width, ELIDE_TAIL); | 102 username = ElideText(username, font_list, available_pixel_width, ELIDE_TAIL); | 
| 103 return username + kAtSignUTF16 + domain; | 103 return username + kAtSignUTF16 + domain; | 
| 104 } | 104 } | 
| 105 #endif | 105 #endif | 
| 106 | 106 | 
| 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 | 107 } // namespace | 
| 124 | 108 | 
| 125 // U+2026 in utf8 | 109 // U+2026 in utf8 | 
| 126 const char kEllipsis[] = "\xE2\x80\xA6"; | 110 const char kEllipsis[] = "\xE2\x80\xA6"; | 
| 127 const base::char16 kEllipsisUTF16[] = { 0x2026, 0 }; | 111 const base::char16 kEllipsisUTF16[] = { 0x2026, 0 }; | 
| 128 const base::char16 kForwardSlash = '/'; | 112 const base::char16 kForwardSlash = '/'; | 
| 129 | 113 | 
| 130 StringSlicer::StringSlicer(const base::string16& text, | 114 StringSlicer::StringSlicer(const base::string16& text, | 
| 131 const base::string16& ellipsis, | 115 const base::string16& ellipsis, | 
| 132 bool elide_in_middle, | 116 bool elide_in_middle, | 
| 133 bool elide_at_beginning) | 117 bool elide_at_beginning) | 
| 134 : text_(text), | 118 : text_(text), | 
| 135 ellipsis_(ellipsis), | 119 ellipsis_(ellipsis), | 
| 136 elide_in_middle_(elide_in_middle), | 120 elide_in_middle_(elide_in_middle), | 
| 137 elide_at_beginning_(elide_at_beginning) { | 121 elide_at_beginning_(elide_at_beginning) { | 
| 138 } | 122 } | 
| 139 | 123 | 
| 140 base::string16 StringSlicer::CutString(size_t length, | 124 base::string16 StringSlicer::CutString(size_t length, | 
| 141 bool insert_ellipsis) const { | 125 bool insert_ellipsis) const { | 
| 142 const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_ | 126 const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_ | 
| 143 : base::string16(); | 127 : base::string16(); | 
| 144 | 128 | 
| 145 if (elide_at_beginning_) | 129 if (elide_at_beginning_) | 
| 146 return ellipsis_text + | 130 return ellipsis_text + | 
| 147 text_.substr(FindValidBoundaryBefore(text_.length() - length)); | 131 text_.substr( | 
| 132 FindValidBoundaryBefore(text_, text_.length() - length)); | |
| 148 | 133 | 
| 149 if (!elide_in_middle_) | 134 if (!elide_in_middle_) | 
| 150 return text_.substr(0, FindValidBoundaryBefore(length)) + ellipsis_text; | 135 return text_.substr(0, FindValidBoundaryBefore(text_, length)) + | 
| 136 ellipsis_text; | |
| 151 | 137 | 
| 152 // We put the extra character, if any, before the cut. | 138 // We put the extra character, if any, before the cut. | 
| 153 const size_t half_length = length / 2; | 139 const size_t half_length = length / 2; | 
| 154 const size_t prefix_length = FindValidBoundaryBefore(length - half_length); | 140 const size_t prefix_length = | 
| 141 FindValidBoundaryBefore(text_, length - half_length); | |
| 155 const size_t suffix_start = | 142 const size_t suffix_start = | 
| 156 FindValidBoundaryAfter(text_.length() - half_length); | 143 FindValidBoundaryAfter(text_, text_.length() - half_length); | 
| 157 return text_.substr(0, prefix_length) + ellipsis_text + | 144 return text_.substr(0, prefix_length) + ellipsis_text + | 
| 158 text_.substr(suffix_start); | 145 text_.substr(suffix_start); | 
| 159 } | 146 } | 
| 160 | 147 | 
| 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, | 148 base::string16 ElideFilename(const base::FilePath& filename, | 
| 198 const FontList& font_list, | 149 const FontList& font_list, | 
| 199 float available_pixel_width) { | 150 float available_pixel_width) { | 
| 200 #if defined(OS_WIN) | 151 #if defined(OS_WIN) | 
| 201 base::string16 filename_utf16 = filename.value(); | 152 base::string16 filename_utf16 = filename.value(); | 
| 202 base::string16 extension = filename.Extension(); | 153 base::string16 extension = filename.Extension(); | 
| 203 base::string16 rootname = filename.BaseName().RemoveExtension().value(); | 154 base::string16 rootname = filename.BaseName().RemoveExtension().value(); | 
| 204 #elif defined(OS_POSIX) | 155 #elif defined(OS_POSIX) | 
| 205 base::string16 filename_utf16 = WideToUTF16(base::SysNativeMBToWide( | 156 base::string16 filename_utf16 = WideToUTF16(base::SysNativeMBToWide( | 
| 206 filename.value())); | 157 filename.value())); | 
| (...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 861 index = char_iterator.getIndex(); | 812 index = char_iterator.getIndex(); | 
| 862 } else { | 813 } else { | 
| 863 // String has leading whitespace, return the elide string. | 814 // String has leading whitespace, return the elide string. | 
| 864 return kElideString; | 815 return kElideString; | 
| 865 } | 816 } | 
| 866 | 817 | 
| 867 return string.substr(0, index) + kElideString; | 818 return string.substr(0, index) + kElideString; | 
| 868 } | 819 } | 
| 869 | 820 | 
| 870 } // namespace gfx | 821 } // namespace gfx | 
| OLD | NEW |