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