OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "app/gfx/font.h" | 5 #include "app/gfx/font.h" |
6 #include "app/gfx/text_elider.h" | 6 #include "app/gfx/text_elider.h" |
7 #include "base/file_path.h" | 7 #include "base/file_path.h" |
8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
9 #include "base/sys_string_conversions.h" | 9 #include "base/sys_string_conversions.h" |
10 #include "googleurl/src/gurl.h" | 10 #include "googleurl/src/gurl.h" |
11 #include "net/base/escape.h" | 11 #include "net/base/escape.h" |
12 #include "net/base/net_util.h" | 12 #include "net/base/net_util.h" |
13 #include "net/base/registry_controlled_domain.h" | 13 #include "net/base/registry_controlled_domain.h" |
14 | 14 |
15 const wchar_t kEllipsis[] = L"\x2026"; | 15 const wchar_t kEllipsis[] = L"\x2026"; |
16 | 16 |
17 namespace gfx { | 17 namespace gfx { |
18 | 18 |
19 // Appends the given part of the original URL to the output string formatted for | |
20 // the user. The given parsed structure will be updated. The host name formatter | |
21 // also takes the same accept languages component as ElideURL. |new_parsed| may | |
22 // be null. | |
23 static void AppendFormattedHost(const GURL& url, | |
24 const std::wstring& languages, | |
25 std::wstring* output, | |
26 url_parse::Parsed* new_parsed); | |
27 | |
28 // Calls the unescaper for the substring |in_component| inside of the URL | |
29 // |spec|. The decoded string will be appended to |output| and the resulting | |
30 // range will be filled into |out_component|. | |
31 static void AppendFormattedComponent(const std::string& spec, | |
32 const url_parse::Component& in_component, | |
33 std::wstring* output, | |
34 url_parse::Component* out_component); | |
35 | |
36 // This function takes a GURL object and elides it. It returns a string | 19 // This function takes a GURL object and elides it. It returns a string |
37 // which composed of parts from subdomain, domain, path, filename and query. | 20 // which composed of parts from subdomain, domain, path, filename and query. |
38 // A "..." is added automatically at the end if the elided string is bigger | 21 // A "..." is added automatically at the end if the elided string is bigger |
39 // than the available pixel width. For available pixel width = 0, a formatted, | 22 // than the available pixel width. For available pixel width = 0, a formatted, |
40 // but un-elided, string is returned. | 23 // but un-elided, string is returned. |
41 // | 24 // |
42 // TODO(pkasting): http://b/119635 This whole function gets | 25 // TODO(pkasting): http://b/119635 This whole function gets |
43 // kerning/ligatures/etc. issues potentially wrong by assuming that the width of | 26 // kerning/ligatures/etc. issues potentially wrong by assuming that the width of |
44 // a rendered string is always the sum of the widths of its substrings. Also I | 27 // a rendered string is always the sum of the widths of its substrings. Also I |
45 // suspect it could be made simpler. | 28 // suspect it could be made simpler. |
46 std::wstring ElideUrl(const GURL& url, | 29 std::wstring ElideUrl(const GURL& url, |
47 const gfx::Font& font, | 30 const gfx::Font& font, |
48 int available_pixel_width, | 31 int available_pixel_width, |
49 const std::wstring& languages) { | 32 const std::wstring& languages) { |
50 // Get a formatted string and corresponding parsing of the url. | 33 // Get a formatted string and corresponding parsing of the url. |
51 url_parse::Parsed parsed; | 34 url_parse::Parsed parsed; |
52 std::wstring url_string = GetCleanStringFromUrl(url, languages, &parsed, | 35 std::wstring url_string = |
53 NULL); | 36 net::FormatUrl(url, languages, true, true, &parsed, NULL); |
54 if (available_pixel_width <= 0) | 37 if (available_pixel_width <= 0) |
55 return url_string; | 38 return url_string; |
56 | 39 |
57 // If non-standard or not file type, return plain eliding. | 40 // If non-standard or not file type, return plain eliding. |
58 if (!(url.SchemeIsFile() || url.IsStandard())) | 41 if (!(url.SchemeIsFile() || url.IsStandard())) |
59 return ElideText(url_string, font, available_pixel_width); | 42 return ElideText(url_string, font, available_pixel_width); |
60 | 43 |
61 // Now start eliding url_string to fit within available pixel width. | 44 // Now start eliding url_string to fit within available pixel width. |
62 // Fist pass - check to see whether entire url_string fits. | 45 // Fist pass - check to see whether entire url_string fits. |
63 int pixel_width_url_string = font.GetStringWidth(url_string); | 46 int pixel_width_url_string = font.GetStringWidth(url_string); |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 if (lo == guess) | 314 if (lo == guess) |
332 break; | 315 break; |
333 lo = guess; | 316 lo = guess; |
334 } | 317 } |
335 guess = (lo + hi) / 2; | 318 guess = (lo + hi) / 2; |
336 } | 319 } |
337 | 320 |
338 return text.substr(0, lo) + kEllipsis; | 321 return text.substr(0, lo) + kEllipsis; |
339 } | 322 } |
340 | 323 |
341 void AppendFormattedHost(const GURL& url, | |
342 const std::wstring& languages, | |
343 std::wstring* output, | |
344 url_parse::Parsed* new_parsed) { | |
345 const url_parse::Component& host = | |
346 url.parsed_for_possibly_invalid_spec().host; | |
347 | |
348 if (host.is_nonempty()) { | |
349 // Handle possible IDN in the host name. | |
350 if (new_parsed) | |
351 new_parsed->host.begin = static_cast<int>(output->length()); | |
352 | |
353 const std::string& spec = url.possibly_invalid_spec(); | |
354 DCHECK(host.begin >= 0 && | |
355 ((spec.length() == 0 && host.begin == 0) || | |
356 host.begin < static_cast<int>(spec.length()))); | |
357 net::IDNToUnicode(&spec[host.begin], host.len, languages, output); | |
358 | |
359 if (new_parsed) { | |
360 new_parsed->host.len = | |
361 static_cast<int>(output->length()) - new_parsed->host.begin; | |
362 } | |
363 } else if (new_parsed) { | |
364 new_parsed->host.reset(); | |
365 } | |
366 } | |
367 | |
368 void AppendFormattedComponent(const std::string& spec, | |
369 const url_parse::Component& in_component, | |
370 std::wstring* output, | |
371 url_parse::Component* out_component) { | |
372 if (in_component.is_nonempty()) { | |
373 out_component->begin = static_cast<int>(output->length()); | |
374 | |
375 output->append(UnescapeAndDecodeUTF8URLComponent( | |
376 spec.substr(in_component.begin, in_component.len), | |
377 UnescapeRule::NORMAL)); | |
378 | |
379 out_component->len = | |
380 static_cast<int>(output->length()) - out_component->begin; | |
381 } else { | |
382 out_component->reset(); | |
383 } | |
384 } | |
385 | |
386 std::wstring GetCleanStringFromUrl(const GURL& url, | |
387 const std::wstring& languages, | |
388 url_parse::Parsed* new_parsed, | |
389 size_t* prefix_end) { | |
390 url_parse::Parsed parsed_temp; | |
391 if (!new_parsed) | |
392 new_parsed = &parsed_temp; | |
393 | |
394 std::wstring url_string; | |
395 | |
396 // Check for empty URLs or 0 available text width. | |
397 if (url.is_empty()) { | |
398 if (prefix_end) | |
399 *prefix_end = 0; | |
400 return url_string; | |
401 } | |
402 | |
403 // We handle both valid and invalid URLs (this will give us the spec | |
404 // regardless of validity). | |
405 const std::string& spec = url.possibly_invalid_spec(); | |
406 const url_parse::Parsed& parsed = url.parsed_for_possibly_invalid_spec(); | |
407 | |
408 // Construct a new URL with the username and password fields removed. We | |
409 // don't want to display those to the user since they can be used for | |
410 // attacks, e.g. "http://google.com:search@evil.ru/" | |
411 // | |
412 // Copy everything before the host name we want (the scheme and the | |
413 // separators), minus the username start we computed above. These are ASCII. | |
414 int pre_end = parsed.CountCharactersBefore( | |
415 url_parse::Parsed::USERNAME, true); | |
416 for (int i = 0; i < pre_end; ++i) | |
417 url_string.push_back(spec[i]); | |
418 if (prefix_end) | |
419 *prefix_end = static_cast<size_t>(pre_end); | |
420 new_parsed->scheme = parsed.scheme; | |
421 new_parsed->username.reset(); | |
422 new_parsed->password.reset(); | |
423 | |
424 AppendFormattedHost(url, languages, &url_string, new_parsed); | |
425 | |
426 // Port. | |
427 if (parsed.port.is_nonempty()) { | |
428 url_string.push_back(':'); | |
429 for (int i = parsed.port.begin; i < parsed.port.end(); ++i) | |
430 url_string.push_back(spec[i]); | |
431 } | |
432 | |
433 // Path and query both get the same general unescape & convert treatment. | |
434 AppendFormattedComponent(spec, parsed.path, &url_string, &new_parsed->path); | |
435 if (parsed.query.is_valid()) | |
436 url_string.push_back('?'); | |
437 AppendFormattedComponent(spec, parsed.query, &url_string, &new_parsed->query); | |
438 | |
439 // Reference is stored in valid, unescaped UTF-8, so we can just convert. | |
440 if (parsed.ref.is_valid()) { | |
441 url_string.push_back('#'); | |
442 if (parsed.ref.len > 0) | |
443 url_string.append(UTF8ToWide(std::string(&spec[parsed.ref.begin], | |
444 parsed.ref.len))); | |
445 } | |
446 | |
447 return url_string; | |
448 } | |
449 | |
450 SortedDisplayURL::SortedDisplayURL(const GURL& url, | 324 SortedDisplayURL::SortedDisplayURL(const GURL& url, |
451 const std::wstring& languages) { | 325 const std::wstring& languages) { |
452 std::wstring host; | 326 std::wstring host; |
453 AppendFormattedHost(url, languages, &host, NULL); | 327 net::AppendFormattedHost(url, languages, &host, NULL); |
454 sort_host_ = WideToUTF16Hack(host); | 328 sort_host_ = WideToUTF16Hack(host); |
455 string16 host_minus_www = WideToUTF16Hack(net::StripWWW(host)); | 329 string16 host_minus_www = WideToUTF16Hack(net::StripWWW(host)); |
456 url_parse::Parsed parsed; | 330 url_parse::Parsed parsed; |
457 display_url_ = WideToUTF16Hack(GetCleanStringFromUrl(url, languages, | 331 display_url_ = WideToUTF16Hack(net::FormatUrl(url, languages, |
458 &parsed, &prefix_end_)); | 332 true, true, &parsed, &prefix_end_)); |
459 if (sort_host_.length() > host_minus_www.length()) { | 333 if (sort_host_.length() > host_minus_www.length()) { |
460 prefix_end_ += sort_host_.length() - host_minus_www.length(); | 334 prefix_end_ += sort_host_.length() - host_minus_www.length(); |
461 sort_host_.swap(host_minus_www); | 335 sort_host_.swap(host_minus_www); |
462 } | 336 } |
463 } | 337 } |
464 | 338 |
465 int SortedDisplayURL::Compare(const SortedDisplayURL& other, | 339 int SortedDisplayURL::Compare(const SortedDisplayURL& other, |
466 Collator* collator) const { | 340 Collator* collator) const { |
467 // Compare on hosts first. The host won't contain 'www.'. | 341 // Compare on hosts first. The host won't contain 'www.'. |
468 UErrorCode compare_status = U_ZERO_ERROR; | 342 UErrorCode compare_status = U_ZERO_ERROR; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 string16 SortedDisplayURL::AfterHost() const { | 380 string16 SortedDisplayURL::AfterHost() const { |
507 size_t slash_index = display_url_.find(sort_host_, prefix_end_); | 381 size_t slash_index = display_url_.find(sort_host_, prefix_end_); |
508 if (slash_index == string16::npos) { | 382 if (slash_index == string16::npos) { |
509 NOTREACHED(); | 383 NOTREACHED(); |
510 return string16(); | 384 return string16(); |
511 } | 385 } |
512 return display_url_.substr(slash_index + sort_host_.length()); | 386 return display_url_.substr(slash_index + sort_host_.length()); |
513 } | 387 } |
514 | 388 |
515 } // namespace gfx. | 389 } // namespace gfx. |
OLD | NEW |