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

Side by Side Diff: ui/base/text/text_elider.cc

Issue 7348010: Added Header and Footer support using Skia (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Custom length strings being printed Created 9 years, 5 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 | Annotate | Revision Log
« ui/base/text/text_elider.h ('K') | « ui/base/text/text_elider.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 for (size_t j = 0; j < num_components; ++j) 65 for (size_t j = 0; j < num_components; ++j)
66 path += path_elements[j] + kForwardSlash; 66 path += path_elements[j] + kForwardSlash;
67 67
68 // Add |filename|, ellipsis if necessary. 68 // Add |filename|, ellipsis if necessary.
69 if (num_components != (path_elements.size() - 1)) 69 if (num_components != (path_elements.size() - 1))
70 path += kEllipsisAndSlash; 70 path += kEllipsisAndSlash;
71 path += filename; 71 path += filename;
72 72
73 return path; 73 return path;
74 } 74 }
75 75
vandebo (ex-Chrome) 2011/07/19 21:31:20 I think this is the wrong way to go about things.
Aayush Kumar 2011/07/21 21:58:53 Restored changes :) I now have mapping between th
76 // Measures the width of the |text| string passed depending on the |object_type|
77 // passed.
78 // If the object is a Skia_Paint object, then the width of the text is returned
79 // in points.
80 // If the object is a gfx::Font object, then the width of the text is returned
81 // in pixels.
82 SkScalar measureStringWidth(const string16& text,
dpapad 2011/07/19 20:34:01 Nit: Function names should start with capital lett
Aayush Kumar 2011/07/21 21:58:53 Done.
83 void* font_or_paint,
84 ObjectType object_type) {
85 // TODO(aayushkumar): Make sure that |font_or_paint| is actually of type
86 // |object_type| otherwise we will segfault!
87 if (object_type == Skia_Paint) {
88 return ((SkPaint *)font_or_paint)->measureText(text.c_str(),
89 text.length()*sizeof(char16));
90 } else {
91 return ((gfx::Font *)font_or_paint)->GetStringWidth(text);
92 }
93 }
94
95 // Overloaded function.
96 // This function adds an ellipsis at the end of the text if the text
97 // does not fit the given pixel width.
98 // The |font_or_paint| argument is a pointer to either a Font or Paint object
99 // and that is specified in the |object_type| parameter.
100 // Depending on what type of object is passed, the appropriate function is
101 // called to measure the width of the text.
102 string16 ElideText(const string16& text,
103 void* font_or_paint,
104 SkScalar available_width,
105 bool elide_in_middle,
106 ObjectType object_type) {
107
108 if (text.empty())
109 return text;
110
111 int current_text_pixel_width = measureStringWidth(text, font_or_paint,
112 object_type);
113
114 // Pango will return 0 width for absurdly long strings. Cut the string in
115 // half and try again.
116 // This is caused by an int overflow in Pango (specifically, in
117 // pango_glyph_string_extents_range). It's actually more subtle than just
118 // returning 0, since on super absurdly long strings, the int can wrap and
119 // return positive numbers again. Detecting that is probably not worth it
120 // (eliding way too much from a ridiculous string is probably still
121 // ridiculous), but we should check other widths for bogus values as well.
122 if (current_text_pixel_width <= 0 && !text.empty()) {
123 return ElideText(CutString(text, text.length() / 2, elide_in_middle, false),
124 font_or_paint, available_width, false, object_type);
125 }
126
127 if (current_text_pixel_width <= available_width)
128 return text;
129
130 if (measureStringWidth(UTF8ToUTF16(kEllipsis), font_or_paint, object_type) >
131 available_width)
132 return string16();
133
134 // Use binary search to compute the elided text.
135 size_t lo = 0;
136 size_t hi = text.length() - 1;
137 for (size_t guess = (lo + hi) / 2; guess != lo; guess = (lo + hi) / 2) {
138 // We check the length of the whole desired string at once to ensure we
139 // handle kerning/ligatures/etc. correctly.
140 int guess_length = measureStringWidth(//font.GetStringWidth(
141 CutString(text, guess, elide_in_middle, true), font_or_paint,
142 object_type);
143 // Check again that we didn't hit a Pango width overflow. If so, cut the
144 // current string in half and start over.
145 if (guess_length <= 0) {
146 return ElideText(CutString(text, guess / 2, elide_in_middle, false),
147 font_or_paint, available_width, elide_in_middle,
148 object_type);
149 }
150 if (guess_length > available_width)
151 hi = guess;
152 else
153 lo = guess;
154 }
155
156 return CutString(text, lo, elide_in_middle, true);
157 }
158
76 // Takes a prefix (Domain, or Domain+subdomain) and a collection of path 159 // Takes a prefix (Domain, or Domain+subdomain) and a collection of path
77 // components and elides if possible. Returns a string containing the longest 160 // components and elides if possible. Returns a string containing the longest
78 // possible elided path, or an empty string if elision is not possible. 161 // possible elided path, or an empty string if elision is not possible.
79 string16 ElideComponentizedPath(const string16& url_path_prefix, 162 string16 ElideComponentizedPath(const string16& url_path_prefix,
80 const std::vector<string16>& url_path_elements, 163 const std::vector<string16>& url_path_elements,
81 const string16& url_filename, 164 const string16& url_filename,
82 const string16& url_query, 165 const string16& url_query,
83 const gfx::Font& font, 166 void* font_or_paint,
84 int available_pixel_width) { 167 int available_width,
168 ObjectType object_type) {
85 size_t url_path_number_of_elements = url_path_elements.size(); 169 size_t url_path_number_of_elements = url_path_elements.size();
86 170
87 static const string16 kEllipsisAndSlash = UTF8ToUTF16(kEllipsis) + 171 static const string16 kEllipsisAndSlash = UTF8ToUTF16(kEllipsis) +
88 kForwardSlash; 172 kForwardSlash;
89 173
90 for (size_t i = url_path_number_of_elements - 1; i > 0; --i) { 174 for (size_t i = url_path_number_of_elements - 1; i > 0; --i) {
91 string16 elided_path = BuildPathFromComponents(url_path_prefix, 175 string16 elided_path = BuildPathFromComponents(url_path_prefix,
92 url_path_elements, url_filename, i); 176 url_path_elements, url_filename, i);
93 if (available_pixel_width >= font.GetStringWidth(elided_path)) 177 if (available_width >= measureStringWidth(elided_path, font_or_paint,
178 object_type)) {
94 return ElideText(elided_path + url_query, 179 return ElideText(elided_path + url_query,
95 font, available_pixel_width, false); 180 font_or_paint, available_width, false, object_type);
181 }
96 } 182 }
97 183
98 return string16(); 184 return string16();
99 } 185 }
100 186
101 } // namespace 187 // Overloaded Function.
102
103 // This function takes a GURL object and elides it. It returns a string 188 // This function takes a GURL object and elides it. It returns a string
104 // which composed of parts from subdomain, domain, path, filename and query. 189 // which composed of parts from subdomain, domain, path, filename and query.
105 // A "..." is added automatically at the end if the elided string is bigger 190 // A "..." is added automatically at the end if the elided string is bigger
106 // than the available pixel width. For available pixel width = 0, a formatted, 191 // than the available pixel width. For available pixel width = 0, a formatted,
107 // but un-elided, string is returned. 192 // but un-elided, string is returned.
108 // 193 //
109 // TODO(pkasting): http://crbug.com/77883 This whole function gets 194 // TODO(pkasting): http://crbug.com/77883 This whole function gets
110 // kerning/ligatures/etc. issues potentially wrong by assuming that the width of 195 // kerning/ligatures/etc. issues potentially wrong by assuming that the width of
111 // a rendered string is always the sum of the widths of its substrings. Also I 196 // a rendered string is always the sum of the widths of its substrings. Also I
112 // suspect it could be made simpler. 197 // suspect it could be made simpler.
198 // The |font_or_paint| argument is a pointer to either a Font or Paint object
199 // and that is specified in the |object_type| parameter.
200 // Depending on what type of object is passed, the appropriate function is
201 // called to measure the width of the text.
113 string16 ElideUrl(const GURL& url, 202 string16 ElideUrl(const GURL& url,
114 const gfx::Font& font, 203 void* font_or_paint,
115 int available_pixel_width, 204 int available_width,
116 const std::string& languages) { 205 const std::string& languages,
206 ObjectType object_type) {
117 // Get a formatted string and corresponding parsing of the url. 207 // Get a formatted string and corresponding parsing of the url.
118 url_parse::Parsed parsed; 208 url_parse::Parsed parsed;
119 string16 url_string = net::FormatUrl(url, languages, net::kFormatUrlOmitAll, 209 string16 url_string = net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
120 UnescapeRule::SPACES, &parsed, NULL, NULL); 210 UnescapeRule::SPACES, &parsed, NULL, NULL);
121 if (available_pixel_width <= 0) 211 if (available_width <= 0)
122 return url_string; 212 return url_string;
123 213
124 // If non-standard or not file type, return plain eliding. 214 // If non-standard or not file type, return plain eliding.
125 if (!(url.SchemeIsFile() || url.IsStandard())) 215 if (!(url.SchemeIsFile() || url.IsStandard()))
126 return ElideText(url_string, font, available_pixel_width, false); 216 return ElideText(url_string, font_or_paint, available_width, false,
217 object_type);
127 218
128 // Now start eliding url_string to fit within available pixel width. 219 // Now start eliding url_string to fit within available pixel width.
129 // Fist pass - check to see whether entire url_string fits. 220 // Fist pass - check to see whether entire url_string fits.
130 int pixel_width_url_string = font.GetStringWidth(url_string); 221 int pixel_width_url_string = measureStringWidth(url_string, font_or_paint,
131 if (available_pixel_width >= pixel_width_url_string) 222 object_type);
223 if (available_width >= pixel_width_url_string)
132 return url_string; 224 return url_string;
133 225
134 // Get the path substring, including query and reference. 226 // Get the path substring, including query and reference.
135 size_t path_start_index = parsed.path.begin; 227 size_t path_start_index = parsed.path.begin;
136 size_t path_len = parsed.path.len; 228 size_t path_len = parsed.path.len;
137 string16 url_path_query_etc = url_string.substr(path_start_index); 229 string16 url_path_query_etc = url_string.substr(path_start_index);
138 string16 url_path = url_string.substr(path_start_index, path_len); 230 string16 url_path = url_string.substr(path_start_index, path_len);
139 231
140 // Return general elided text if url minus the query fits. 232 // Return general elided text if url minus the query fits.
141 string16 url_minus_query = url_string.substr(0, path_start_index + path_len); 233 string16 url_minus_query = url_string.substr(0, path_start_index + path_len);
142 if (available_pixel_width >= font.GetStringWidth(url_minus_query)) 234 if (available_width >= measureStringWidth(url_minus_query, font_or_paint,
143 return ElideText(url_string, font, available_pixel_width, false); 235 object_type)) {
236 return ElideText(url_string, font_or_paint, available_width, false,
237 object_type);
238 }
144 239
145 // Get Host. 240 // Get Host.
146 string16 url_host = UTF8ToUTF16(url.host()); 241 string16 url_host = UTF8ToUTF16(url.host());
147 242
148 // Get domain and registry information from the URL. 243 // Get domain and registry information from the URL.
149 string16 url_domain = UTF8ToUTF16( 244 string16 url_domain = UTF8ToUTF16(
150 net::RegistryControlledDomainService::GetDomainAndRegistry(url)); 245 net::RegistryControlledDomainService::GetDomainAndRegistry(url));
151 if (url_domain.empty()) 246 if (url_domain.empty())
152 url_domain = url_host; 247 url_domain = url_host;
153 248
(...skipping 26 matching lines...) Expand all
180 url_domain.clear(); 275 url_domain.clear();
181 url_subdomain.clear(); 276 url_subdomain.clear();
182 277
183 static const string16 kColon = UTF8ToUTF16(":"); 278 static const string16 kColon = UTF8ToUTF16(":");
184 url_host = url_domain = file_path_split.at(0).substr(1) + kColon; 279 url_host = url_domain = file_path_split.at(0).substr(1) + kColon;
185 url_path_query_etc = url_path = file_path_split.at(1); 280 url_path_query_etc = url_path = file_path_split.at(1);
186 } 281 }
187 } 282 }
188 283
189 // Second Pass - remove scheme - the rest fits. 284 // Second Pass - remove scheme - the rest fits.
190 int pixel_width_url_host = font.GetStringWidth(url_host); 285 int pixel_width_url_host = measureStringWidth(url_host, font_or_paint,
191 int pixel_width_url_path = font.GetStringWidth(url_path_query_etc); 286 object_type);
192 if (available_pixel_width >= 287 int pixel_width_url_path = measureStringWidth(url_path_query_etc,
288 font_or_paint, object_type);
289 if (available_width >=
193 pixel_width_url_host + pixel_width_url_path) 290 pixel_width_url_host + pixel_width_url_path)
dpapad 2011/07/19 20:34:01 Use braces when an if statement spans multiple lin
Aayush Kumar 2011/07/21 21:58:53 Done.
194 return url_host + url_path_query_etc; 291 return url_host + url_path_query_etc;
195 292
196 // Third Pass: Subdomain, domain and entire path fits. 293 // Third Pass: Subdomain, domain and entire path fits.
197 int pixel_width_url_domain = font.GetStringWidth(url_domain); 294 int pixel_width_url_domain = measureStringWidth(url_domain, font_or_paint,
198 int pixel_width_url_subdomain = font.GetStringWidth(url_subdomain); 295 object_type);
199 if (available_pixel_width >= 296 int pixel_width_url_subdomain = measureStringWidth(url_subdomain,
297 font_or_paint,
298 object_type);
299 if (available_width >=
200 pixel_width_url_subdomain + pixel_width_url_domain + 300 pixel_width_url_subdomain + pixel_width_url_domain +
201 pixel_width_url_path) 301 pixel_width_url_path)
202 return url_subdomain + url_domain + url_path_query_etc; 302 return url_subdomain + url_domain + url_path_query_etc;
203 303
204 // Query element. 304 // Query element.
205 string16 url_query; 305 string16 url_query;
206 const int kPixelWidthDotsTrailer = 306 const int kPixelWidthDotsTrailer =
207 font.GetStringWidth(UTF8ToUTF16(kEllipsis)); 307 measureStringWidth(UTF8ToUTF16(kEllipsis), font_or_paint, object_type);
208 if (parsed.query.is_nonempty()) { 308 if (parsed.query.is_nonempty()) {
209 url_query = UTF8ToUTF16("?") + url_string.substr(parsed.query.begin); 309 url_query = UTF8ToUTF16("?") + url_string.substr(parsed.query.begin);
210 if (available_pixel_width >= (pixel_width_url_subdomain + 310 if (available_width >= (pixel_width_url_subdomain +
211 pixel_width_url_domain + pixel_width_url_path - 311 pixel_width_url_domain + pixel_width_url_path -
212 font.GetStringWidth(url_query))) { 312 measureStringWidth(url_query, font_or_paint, object_type))) {
213 return ElideText(url_subdomain + url_domain + url_path_query_etc, 313 return ElideText(url_subdomain + url_domain + url_path_query_etc,
214 font, available_pixel_width, false); 314 font_or_paint, available_width, false, object_type);
215 } 315 }
216 } 316 }
217 317
218 // Parse url_path using '/'. 318 // Parse url_path using '/'.
219 std::vector<string16> url_path_elements; 319 std::vector<string16> url_path_elements;
220 base::SplitString(url_path, kForwardSlash, &url_path_elements); 320 base::SplitString(url_path, kForwardSlash, &url_path_elements);
221 321
222 // Get filename - note that for a path ending with / 322 // Get filename - note that for a path ending with /
223 // such as www.google.com/intl/ads/, the file name is ads/. 323 // such as www.google.com/intl/ads/, the file name is ads/.
224 size_t url_path_number_of_elements = url_path_elements.size(); 324 size_t url_path_number_of_elements = url_path_elements.size();
225 DCHECK(url_path_number_of_elements != 0); 325 DCHECK(url_path_number_of_elements != 0);
226 string16 url_filename; 326 string16 url_filename;
227 if ((url_path_elements.at(url_path_number_of_elements - 1)).length() > 0) { 327 if ((url_path_elements.at(url_path_number_of_elements - 1)).length() > 0) {
228 url_filename = *(url_path_elements.end() - 1); 328 url_filename = *(url_path_elements.end() - 1);
229 } else if (url_path_number_of_elements > 1) { // Path ends with a '/'. 329 } else if (url_path_number_of_elements > 1) { // Path ends with a '/'.
230 url_filename = url_path_elements.at(url_path_number_of_elements - 2) + 330 url_filename = url_path_elements.at(url_path_number_of_elements - 2) +
231 kForwardSlash; 331 kForwardSlash;
232 url_path_number_of_elements--; 332 url_path_number_of_elements--;
233 } 333 }
234 DCHECK(url_path_number_of_elements != 0); 334 DCHECK(url_path_number_of_elements != 0);
235 335
236 const size_t kMaxNumberOfUrlPathElementsAllowed = 1024; 336 const size_t kMaxNumberOfUrlPathElementsAllowed = 1024;
237 if (url_path_number_of_elements <= 1 || 337 if (url_path_number_of_elements <= 1 ||
238 url_path_number_of_elements > kMaxNumberOfUrlPathElementsAllowed) { 338 url_path_number_of_elements > kMaxNumberOfUrlPathElementsAllowed) {
239 // No path to elide, or too long of a path (could overflow in loop below) 339 // No path to elide, or too long of a path (could overflow in loop below)
240 // Just elide this as a text string. 340 // Just elide this as a text string.
241 return ElideText(url_subdomain + url_domain + url_path_query_etc, font, 341 return ElideText(url_subdomain + url_domain + url_path_query_etc,
242 available_pixel_width, false); 342 font_or_paint, available_width, false, object_type);
243 } 343 }
244 344
245 // Start eliding the path and replacing elements by ".../". 345 // Start eliding the path and replacing elements by ".../".
246 const string16 kEllipsisAndSlash = UTF8ToUTF16(kEllipsis) + kForwardSlash; 346 const string16 kEllipsisAndSlash = UTF8ToUTF16(kEllipsis) + kForwardSlash;
247 int pixel_width_ellipsis_slash = font.GetStringWidth(kEllipsisAndSlash); 347 int pixel_width_ellipsis_slash = measureStringWidth(kEllipsisAndSlash,
348 font_or_paint,
349 object_type);
248 350
249 // Check with both subdomain and domain. 351 // Check with both subdomain and domain.
250 string16 elided_path = ElideComponentizedPath(url_subdomain + url_domain, 352 string16 elided_path = ElideComponentizedPath(url_subdomain + url_domain,
251 url_path_elements, url_filename, url_query, font, available_pixel_width); 353 url_path_elements, url_filename, url_query, font_or_paint,
354 available_width, object_type);
252 if (!elided_path.empty()) 355 if (!elided_path.empty())
253 return elided_path; 356 return elided_path;
254 357
255 // Check with only domain. 358 // Check with only domain.
256 // If a subdomain is present, add an ellipsis before domain. 359 // If a subdomain is present, add an ellipsis before domain.
257 // This is added only if the subdomain pixel width is larger than 360 // This is added only if the subdomain pixel width is larger than
258 // the pixel width of kEllipsis. Otherwise, subdomain remains, 361 // the pixel width of kEllipsis. Otherwise, subdomain remains,
259 // which means that this case has been resolved earlier. 362 // which means that this case has been resolved earlier.
260 string16 url_elided_domain = url_subdomain + url_domain; 363 string16 url_elided_domain = url_subdomain + url_domain;
261 int pixel_width_url_elided_domain = pixel_width_url_domain; 364 int pixel_width_url_elided_domain = pixel_width_url_domain;
262 if (pixel_width_url_subdomain > kPixelWidthDotsTrailer) { 365 if (pixel_width_url_subdomain > kPixelWidthDotsTrailer) {
263 if (!url_subdomain.empty()) { 366 if (!url_subdomain.empty()) {
264 url_elided_domain = kEllipsisAndSlash[0] + url_domain; 367 url_elided_domain = kEllipsisAndSlash[0] + url_domain;
265 pixel_width_url_elided_domain += kPixelWidthDotsTrailer; 368 pixel_width_url_elided_domain += kPixelWidthDotsTrailer;
266 } else { 369 } else {
267 url_elided_domain = url_domain; 370 url_elided_domain = url_domain;
268 } 371 }
269 372
270 elided_path = ElideComponentizedPath(url_elided_domain, url_path_elements, 373 elided_path = ElideComponentizedPath(url_elided_domain, url_path_elements,
271 url_filename, url_query, font, available_pixel_width); 374 url_filename, url_query, font_or_paint, available_width, object_type);
272 375
273 if (!elided_path.empty()) 376 if (!elided_path.empty())
274 return elided_path; 377 return elided_path;
275 } 378 }
276 379
277 // Return elided domain/.../filename anyway. 380 // Return elided domain/.../filename anyway.
278 string16 final_elided_url_string(url_elided_domain); 381 string16 final_elided_url_string(url_elided_domain);
279 int url_elided_domain_width = font.GetStringWidth(url_elided_domain); 382 int url_elided_domain_width = measureStringWidth(url_elided_domain,
383 font_or_paint, object_type);
280 384
281 // A hack to prevent trailing ".../...". 385 // A hack to prevent trailing ".../...".
282 if ((available_pixel_width - url_elided_domain_width) > 386 if ((available_width - url_elided_domain_width) >
283 pixel_width_ellipsis_slash + kPixelWidthDotsTrailer + 387 pixel_width_ellipsis_slash + kPixelWidthDotsTrailer +
284 font.GetStringWidth(ASCIIToUTF16("UV"))) { 388 measureStringWidth(ASCIIToUTF16("UV"), font_or_paint, object_type)) {
285 final_elided_url_string += BuildPathFromComponents(string16(), 389 final_elided_url_string += BuildPathFromComponents(string16(),
286 url_path_elements, url_filename, 1); 390 url_path_elements, url_filename, 1);
287 } else { 391 } else {
288 final_elided_url_string += url_path; 392 final_elided_url_string += url_path;
289 } 393 }
290 394
291 return ElideText(final_elided_url_string, font, available_pixel_width, false); 395 return ElideText(final_elided_url_string, font_or_paint, available_width,
396 false, object_type);
397 }
398
399 } // namespace
400
401 // Overloaded Function.
402 // Takes a Font object to measure the string width.
403 string16 ElideUrl(const GURL& url,
404 const gfx::Font& font,
405 int available_pixel_width,
406 const std::string& languages) {
407 return ElideUrl(url, (void* )&font, available_pixel_width, languages,
408 GFX_Font);
409 }
410
411 // Overloaded Function.
412 // Takes a SkPaint object to measure the string width.
413 string16 ElideUrl(const GURL& url,
414 const SkPaint paint,
415 SkScalar available_point_width,
416 const std::string& languages) {
417 return ElideUrl(url, (void* )&paint, available_point_width, languages,
418 Skia_Paint);
292 } 419 }
293 420
294 string16 ElideFilename(const FilePath& filename, 421 string16 ElideFilename(const FilePath& filename,
295 const gfx::Font& font, 422 const gfx::Font& font,
296 int available_pixel_width) { 423 int available_width) {
297 #if defined(OS_WIN) 424 #if defined(OS_WIN)
298 string16 filename_utf16 = filename.value(); 425 string16 filename_utf16 = filename.value();
299 string16 extension = filename.Extension(); 426 string16 extension = filename.Extension();
300 string16 rootname = filename.BaseName().RemoveExtension().value(); 427 string16 rootname = filename.BaseName().RemoveExtension().value();
301 #elif defined(OS_POSIX) 428 #elif defined(OS_POSIX)
302 string16 filename_utf16 = WideToUTF16(base::SysNativeMBToWide( 429 string16 filename_utf16 = WideToUTF16(base::SysNativeMBToWide(
303 filename.value())); 430 filename.value()));
304 string16 extension = WideToUTF16(base::SysNativeMBToWide( 431 string16 extension = WideToUTF16(base::SysNativeMBToWide(
305 filename.Extension())); 432 filename.Extension()));
306 string16 rootname = WideToUTF16(base::SysNativeMBToWide( 433 string16 rootname = WideToUTF16(base::SysNativeMBToWide(
307 filename.BaseName().RemoveExtension().value())); 434 filename.BaseName().RemoveExtension().value()));
308 #endif 435 #endif
309 436
310 int full_width = font.GetStringWidth(filename_utf16); 437 int full_width = font.GetStringWidth(filename_utf16);
311 if (full_width <= available_pixel_width) 438 if (full_width <= available_width)
312 return base::i18n::GetDisplayStringInLTRDirectionality(filename_utf16); 439 return base::i18n::GetDisplayStringInLTRDirectionality(filename_utf16);
313 440
314 if (rootname.empty() || extension.empty()) { 441 if (rootname.empty() || extension.empty()) {
315 string16 elided_name = ElideText(filename_utf16, font, 442 string16 elided_name = ElideText(filename_utf16, font,
316 available_pixel_width, false); 443 available_width, false);
317 return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); 444 return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
318 } 445 }
319 446
320 int ext_width = font.GetStringWidth(extension); 447 int ext_width = font.GetStringWidth(extension);
321 int root_width = font.GetStringWidth(rootname); 448 int root_width = font.GetStringWidth(rootname);
322 449
323 // We may have trimmed the path. 450 // We may have trimmed the path.
324 if (root_width + ext_width <= available_pixel_width) { 451 if (root_width + ext_width <= available_width) {
325 string16 elided_name = rootname + extension; 452 string16 elided_name = rootname + extension;
326 return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); 453 return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
327 } 454 }
328 455
329 if (ext_width >= available_pixel_width) { 456 if (ext_width >= available_width) {
330 string16 elided_name = ElideText(rootname + extension, font, 457 string16 elided_name = ElideText(rootname + extension, font,
331 available_pixel_width, true); 458 available_width, true);
332 return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); 459 return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
333 } 460 }
334 461
335 int available_root_width = available_pixel_width - ext_width; 462 int available_root_width = available_width - ext_width;
336 string16 elided_name = 463 string16 elided_name =
337 ElideText(rootname, font, available_root_width, false); 464 ElideText(rootname, font, available_root_width, false);
338 elided_name += extension; 465 elided_name += extension;
339 return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); 466 return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
340 } 467 }
341 468
342 // This function adds an ellipsis at the end of the text if the text 469 // Overloaded function.
343 // does not fit the given pixel width. 470 // Uses Font object to determine text width.
344 string16 ElideText(const string16& text, 471 string16 ElideText(const string16& text,
345 const gfx::Font& font, 472 const gfx::Font& font,
346 int available_pixel_width, 473 int available_pixel_width,
347 bool elide_in_middle) { 474 bool elide_in_middle) {
348 if (text.empty()) 475 return ElideText(text, (void* )&font, (SkScalar)available_pixel_width,
dpapad 2011/07/19 20:34:01 Nit: No need for space in "(void* )", here and els
Aayush Kumar 2011/07/21 21:58:53 Done.
349 return text; 476 elide_in_middle, GFX_Font);
477 }
350 478
351 int current_text_pixel_width = font.GetStringWidth(text); 479 // Overloaded function.
352 480 // Uses SkPaint object to determine text width.
353 // Pango will return 0 width for absurdly long strings. Cut the string in 481 string16 ElideText(const string16& text,
354 // half and try again. 482 const SkPaint paint,
355 // This is caused by an int overflow in Pango (specifically, in 483 SkScalar available_point_width,
356 // pango_glyph_string_extents_range). It's actually more subtle than just 484 bool elide_in_middle) {
357 // returning 0, since on super absurdly long strings, the int can wrap and 485 return ElideText(text, (void* )&paint, available_point_width, elide_in_middle,
358 // return positive numbers again. Detecting that is probably not worth it 486 Skia_Paint);
359 // (eliding way too much from a ridiculous string is probably still
360 // ridiculous), but we should check other widths for bogus values as well.
361 if (current_text_pixel_width <= 0 && !text.empty()) {
362 return ElideText(CutString(text, text.length() / 2, elide_in_middle, false),
363 font, available_pixel_width, false);
364 }
365
366 if (current_text_pixel_width <= available_pixel_width)
367 return text;
368
369 if (font.GetStringWidth(UTF8ToUTF16(kEllipsis)) > available_pixel_width)
370 return string16();
371
372 // Use binary search to compute the elided text.
373 size_t lo = 0;
374 size_t hi = text.length() - 1;
375 for (size_t guess = (lo + hi) / 2; guess != lo; guess = (lo + hi) / 2) {
376 // We check the length of the whole desired string at once to ensure we
377 // handle kerning/ligatures/etc. correctly.
378 int guess_length = font.GetStringWidth(
379 CutString(text, guess, elide_in_middle, true));
380 // Check again that we didn't hit a Pango width overflow. If so, cut the
381 // current string in half and start over.
382 if (guess_length <= 0) {
383 return ElideText(CutString(text, guess / 2, elide_in_middle, false),
384 font, available_pixel_width, elide_in_middle);
385 }
386 if (guess_length > available_pixel_width)
387 hi = guess;
388 else
389 lo = guess;
390 }
391
392 return CutString(text, lo, elide_in_middle, true);
393 } 487 }
394 488
395 SortedDisplayURL::SortedDisplayURL(const GURL& url, 489 SortedDisplayURL::SortedDisplayURL(const GURL& url,
396 const std::string& languages) { 490 const std::string& languages) {
397 net::AppendFormattedHost(url, languages, &sort_host_); 491 net::AppendFormattedHost(url, languages, &sort_host_);
398 string16 host_minus_www = net::StripWWW(sort_host_); 492 string16 host_minus_www = net::StripWWW(sort_host_);
399 url_parse::Parsed parsed; 493 url_parse::Parsed parsed;
400 display_url_ = net::FormatUrl(url, languages, 494 display_url_ = net::FormatUrl(url, languages,
401 net::kFormatUrlOmitAll, UnescapeRule::SPACES, &parsed, &prefix_end_, 495 net::kFormatUrlOmitAll, UnescapeRule::SPACES, &parsed, &prefix_end_,
402 NULL); 496 NULL);
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 761
668 bool ElideRectangleString(const string16& input, size_t max_rows, 762 bool ElideRectangleString(const string16& input, size_t max_rows,
669 size_t max_cols, bool strict, string16* output) { 763 size_t max_cols, bool strict, string16* output) {
670 RectangleString rect(max_rows, max_cols, strict, output); 764 RectangleString rect(max_rows, max_cols, strict, output);
671 rect.Init(); 765 rect.Init();
672 rect.AddString(input); 766 rect.AddString(input);
673 return rect.Finalize(); 767 return rect.Finalize();
674 } 768 }
675 769
676 } // namespace ui 770 } // namespace ui
OLDNEW
« ui/base/text/text_elider.h ('K') | « ui/base/text/text_elider.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698