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 "chrome/browser/tab_contents/navigation_controller.h" | 5 #include "chrome/browser/tab_contents/navigation_controller.h" |
6 | 6 |
7 #include "app/resource_bundle.h" | 7 #include "app/resource_bundle.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 bool AreURLsInPageNavigation(const GURL& existing_url, const GURL& new_url) { | 83 bool AreURLsInPageNavigation(const GURL& existing_url, const GURL& new_url) { |
84 if (existing_url == new_url || !new_url.has_ref()) | 84 if (existing_url == new_url || !new_url.has_ref()) |
85 return false; | 85 return false; |
86 | 86 |
87 url_canon::Replacements<char> replacements; | 87 url_canon::Replacements<char> replacements; |
88 replacements.ClearRef(); | 88 replacements.ClearRef(); |
89 return existing_url.ReplaceComponents(replacements) == | 89 return existing_url.ReplaceComponents(replacements) == |
90 new_url.ReplaceComponents(replacements); | 90 new_url.ReplaceComponents(replacements); |
91 } | 91 } |
92 | 92 |
| 93 // Navigation within this limit since the last document load is considered to |
| 94 // be automatic (i.e., machine-initiated) rather than user-initiated unless |
| 95 // a user gesture has been observed. |
| 96 const base::TimeDelta kMaxAutoNavigationTimeDelta = |
| 97 base::TimeDelta::FromSeconds(5); |
| 98 |
93 } // namespace | 99 } // namespace |
94 | 100 |
95 // NavigationController --------------------------------------------------- | 101 // NavigationController --------------------------------------------------- |
96 | 102 |
97 // static | 103 // static |
98 size_t NavigationController::max_entry_count_ = 50; | 104 size_t NavigationController::max_entry_count_ = 50; |
99 | 105 |
100 // static | 106 // static |
101 bool NavigationController::check_for_repost_ = true; | 107 bool NavigationController::check_for_repost_ = true; |
102 | 108 |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 | 423 |
418 const SkBitmap& NavigationController::GetLazyFavIcon() const { | 424 const SkBitmap& NavigationController::GetLazyFavIcon() const { |
419 if (pending_entry_) { | 425 if (pending_entry_) { |
420 return pending_entry_->favicon().bitmap(); | 426 return pending_entry_->favicon().bitmap(); |
421 } else { | 427 } else { |
422 ResourceBundle &rb = ResourceBundle::GetSharedInstance(); | 428 ResourceBundle &rb = ResourceBundle::GetSharedInstance(); |
423 return *rb.GetBitmapNamed(IDR_DEFAULT_FAVICON); | 429 return *rb.GetBitmapNamed(IDR_DEFAULT_FAVICON); |
424 } | 430 } |
425 } | 431 } |
426 | 432 |
| 433 void NavigationController::DocumentLoadedInFrame() { |
| 434 last_document_loaded_ = base::TimeTicks::Now(); |
| 435 } |
| 436 |
| 437 void NavigationController::OnUserGesture() { |
| 438 user_gesture_observed_ = true; |
| 439 } |
| 440 |
427 bool NavigationController::RendererDidNavigate( | 441 bool NavigationController::RendererDidNavigate( |
428 const ViewHostMsg_FrameNavigate_Params& params, | 442 const ViewHostMsg_FrameNavigate_Params& params, |
429 LoadCommittedDetails* details) { | 443 LoadCommittedDetails* details) { |
430 // Save the previous state before we clobber it. | 444 // Save the previous state before we clobber it. |
431 if (GetLastCommittedEntry()) { | 445 if (GetLastCommittedEntry()) { |
432 details->previous_url = GetLastCommittedEntry()->url(); | 446 details->previous_url = GetLastCommittedEntry()->url(); |
433 details->previous_entry_index = last_committed_entry_index(); | 447 details->previous_entry_index = last_committed_entry_index(); |
434 } else { | 448 } else { |
435 details->previous_url = GURL(); | 449 details->previous_url = GURL(); |
436 details->previous_entry_index = -1; | 450 details->previous_entry_index = -1; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 | 512 |
499 // Now prep the rest of the details for the notification and broadcast. | 513 // Now prep the rest of the details for the notification and broadcast. |
500 details->entry = GetActiveEntry(); | 514 details->entry = GetActiveEntry(); |
501 details->is_in_page = IsURLInPageNavigation(params.url); | 515 details->is_in_page = IsURLInPageNavigation(params.url); |
502 details->is_main_frame = PageTransition::IsMainFrame(params.transition); | 516 details->is_main_frame = PageTransition::IsMainFrame(params.transition); |
503 details->serialized_security_info = params.security_info; | 517 details->serialized_security_info = params.security_info; |
504 details->is_content_filtered = params.is_content_filtered; | 518 details->is_content_filtered = params.is_content_filtered; |
505 details->http_status_code = params.http_status_code; | 519 details->http_status_code = params.http_status_code; |
506 NotifyNavigationEntryCommitted(details); | 520 NotifyNavigationEntryCommitted(details); |
507 | 521 |
| 522 user_gesture_observed_ = false; |
| 523 |
508 return true; | 524 return true; |
509 } | 525 } |
510 | 526 |
511 NavigationType::Type NavigationController::ClassifyNavigation( | 527 NavigationType::Type NavigationController::ClassifyNavigation( |
512 const ViewHostMsg_FrameNavigate_Params& params) const { | 528 const ViewHostMsg_FrameNavigate_Params& params) const { |
513 // If a page makes a popup navigated to about blank, and then writes stuff | 529 // If a page makes a popup navigated to about blank, and then writes stuff |
514 // like a subframe navigated to a real site, we'll get a notification with an | 530 // like a subframe navigated to a real site, we'll get a notification with an |
515 // invalid page ID. There's nothing we can do with these, so just ignore them. | 531 // invalid page ID. There's nothing we can do with these, so just ignore them. |
516 if (params.page_id == -1) { | 532 if (params.page_id == -1) { |
517 DCHECK(!GetActiveEntry()) << "Got an invalid page ID but we seem to be " | 533 DCHECK(!GetActiveEntry()) << "Got an invalid page ID but we seem to be " |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
578 // navigations that don't actually navigate, but it can happen when there is | 594 // navigations that don't actually navigate, but it can happen when there is |
579 // an encoding override (it always sends a navigation request). | 595 // an encoding override (it always sends a navigation request). |
580 if (AreURLsInPageNavigation(existing_entry->url(), params.url)) | 596 if (AreURLsInPageNavigation(existing_entry->url(), params.url)) |
581 return NavigationType::IN_PAGE; | 597 return NavigationType::IN_PAGE; |
582 | 598 |
583 // Since we weeded out "new" navigations above, we know this is an existing | 599 // Since we weeded out "new" navigations above, we know this is an existing |
584 // (back/forward) navigation. | 600 // (back/forward) navigation. |
585 return NavigationType::EXISTING_PAGE; | 601 return NavigationType::EXISTING_PAGE; |
586 } | 602 } |
587 | 603 |
| 604 bool NavigationController::IsRedirect( |
| 605 const ViewHostMsg_FrameNavigate_Params& params) { |
| 606 // For main frame transition, we judge by params.transition. |
| 607 // Otherwise, by params.redirects. |
| 608 if (PageTransition::IsMainFrame(params.transition)) { |
| 609 return PageTransition::IsRedirect(params.transition); |
| 610 } |
| 611 return params.redirects.size() > 1; |
| 612 } |
| 613 |
| 614 bool NavigationController::IsLikelyAutoNavigation(base::TimeTicks now) { |
| 615 return !user_gesture_observed_ && |
| 616 (now - last_document_loaded_) < kMaxAutoNavigationTimeDelta; |
| 617 } |
| 618 |
588 void NavigationController::RendererDidNavigateToNewPage( | 619 void NavigationController::RendererDidNavigateToNewPage( |
589 const ViewHostMsg_FrameNavigate_Params& params) { | 620 const ViewHostMsg_FrameNavigate_Params& params) { |
590 NavigationEntry* new_entry; | 621 NavigationEntry* new_entry; |
591 if (pending_entry_) { | 622 if (pending_entry_) { |
592 // TODO(brettw) this assumes that the pending entry is appropriate for the | 623 // TODO(brettw) this assumes that the pending entry is appropriate for the |
593 // new page that was just loaded. I don't think this is necessarily the | 624 // new page that was just loaded. I don't think this is necessarily the |
594 // case! We should have some more tracking to know for sure. This goes along | 625 // case! We should have some more tracking to know for sure. This goes along |
595 // with a similar TODO at the top of RendererDidNavigate where we blindly | 626 // with a similar TODO at the top of RendererDidNavigate where we blindly |
596 // set the site instance on the pending entry. | 627 // set the site instance on the pending entry. |
597 new_entry = new NavigationEntry(*pending_entry_); | 628 new_entry = new NavigationEntry(*pending_entry_); |
598 | 629 |
599 // Don't use the page type from the pending entry. Some interstitial page | 630 // Don't use the page type from the pending entry. Some interstitial page |
600 // may have set the type to interstitial. Once we commit, however, the page | 631 // may have set the type to interstitial. Once we commit, however, the page |
601 // type must always be normal. | 632 // type must always be normal. |
602 new_entry->set_page_type(NavigationEntry::NORMAL_PAGE); | 633 new_entry->set_page_type(NavigationEntry::NORMAL_PAGE); |
603 } else { | 634 } else { |
604 new_entry = new NavigationEntry; | 635 new_entry = new NavigationEntry; |
605 } | 636 } |
606 | 637 |
607 new_entry->set_url(params.url); | 638 new_entry->set_url(params.url); |
608 new_entry->set_referrer(params.referrer); | 639 new_entry->set_referrer(params.referrer); |
609 new_entry->set_page_id(params.page_id); | 640 new_entry->set_page_id(params.page_id); |
610 new_entry->set_transition_type(params.transition); | 641 new_entry->set_transition_type(params.transition); |
611 new_entry->set_site_instance(tab_contents_->GetSiteInstance()); | 642 new_entry->set_site_instance(tab_contents_->GetSiteInstance()); |
612 new_entry->set_has_post_data(params.is_post); | 643 new_entry->set_has_post_data(params.is_post); |
613 | 644 |
614 // If the current entry is a redirection source, it needs to be replaced with | 645 // If the current entry is a redirection source and the redirection has |
615 // the new entry to avoid unwanted redirections in navigating backward / | 646 // occurred within kMaxAutoNavigationTimeDelta since the last document load, |
616 // forward. Otherwise, just insert the new entry. | 647 // this is likely to be machine-initiated redirect and the entry needs to be |
| 648 // replaced with the new entry to avoid unwanted redirections in navigating |
| 649 // backward/forward. |
| 650 // Otherwise, just insert the new entry. |
617 InsertOrReplaceEntry(new_entry, | 651 InsertOrReplaceEntry(new_entry, |
618 PageTransition::IsRedirect(new_entry->transition_type())); | 652 IsRedirect(params) && IsLikelyAutoNavigation(base::TimeTicks::Now())); |
619 } | 653 } |
620 | 654 |
621 void NavigationController::RendererDidNavigateToExistingPage( | 655 void NavigationController::RendererDidNavigateToExistingPage( |
622 const ViewHostMsg_FrameNavigate_Params& params) { | 656 const ViewHostMsg_FrameNavigate_Params& params) { |
623 // We should only get here for main frame navigations. | 657 // We should only get here for main frame navigations. |
624 DCHECK(PageTransition::IsMainFrame(params.transition)); | 658 DCHECK(PageTransition::IsMainFrame(params.transition)); |
625 | 659 |
626 // This is a back/forward navigation. The existing page for the ID is | 660 // This is a back/forward navigation. The existing page for the ID is |
627 // guaranteed to exist by ClassifyNavigation, and we just need to update it | 661 // guaranteed to exist by ClassifyNavigation, and we just need to update it |
628 // with new information from the renderer. | 662 // with new information from the renderer. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 NavigationEntry* existing_entry = GetEntryWithPageID( | 714 NavigationEntry* existing_entry = GetEntryWithPageID( |
681 tab_contents_->GetSiteInstance(), | 715 tab_contents_->GetSiteInstance(), |
682 params.page_id); | 716 params.page_id); |
683 | 717 |
684 // Reference fragment navigation. We're guaranteed to have the last_committed | 718 // Reference fragment navigation. We're guaranteed to have the last_committed |
685 // entry and it will be the same page as the new navigation (minus the | 719 // entry and it will be the same page as the new navigation (minus the |
686 // reference fragments, of course). | 720 // reference fragments, of course). |
687 NavigationEntry* new_entry = new NavigationEntry(*existing_entry); | 721 NavigationEntry* new_entry = new NavigationEntry(*existing_entry); |
688 new_entry->set_page_id(params.page_id); | 722 new_entry->set_page_id(params.page_id); |
689 new_entry->set_url(params.url); | 723 new_entry->set_url(params.url); |
690 InsertOrReplaceEntry(new_entry, false); | 724 InsertOrReplaceEntry(new_entry, |
| 725 IsRedirect(params) && IsLikelyAutoNavigation(base::TimeTicks::Now())); |
691 } | 726 } |
692 | 727 |
693 void NavigationController::RendererDidNavigateNewSubframe( | 728 void NavigationController::RendererDidNavigateNewSubframe( |
694 const ViewHostMsg_FrameNavigate_Params& params) { | 729 const ViewHostMsg_FrameNavigate_Params& params) { |
| 730 if (PageTransition::StripQualifier(params.transition) == |
| 731 PageTransition::AUTO_SUBFRAME) { |
| 732 // This is not user-initiated. Ignore. |
| 733 return; |
| 734 } |
| 735 if (IsRedirect(params)) { |
| 736 // This is redirect. Ignore. |
| 737 return; |
| 738 } |
| 739 |
695 // Manual subframe navigations just get the current entry cloned so the user | 740 // Manual subframe navigations just get the current entry cloned so the user |
696 // can go back or forward to it. The actual subframe information will be | 741 // can go back or forward to it. The actual subframe information will be |
697 // stored in the page state for each of those entries. This happens out of | 742 // stored in the page state for each of those entries. This happens out of |
698 // band with the actual navigations. | 743 // band with the actual navigations. |
699 DCHECK(GetLastCommittedEntry()) << "ClassifyNavigation should guarantee " | 744 DCHECK(GetLastCommittedEntry()) << "ClassifyNavigation should guarantee " |
700 << "that a last committed entry exists."; | 745 << "that a last committed entry exists."; |
701 NavigationEntry* new_entry = new NavigationEntry(*GetLastCommittedEntry()); | 746 NavigationEntry* new_entry = new NavigationEntry(*GetLastCommittedEntry()); |
702 new_entry->set_page_id(params.page_id); | 747 new_entry->set_page_id(params.page_id); |
703 InsertOrReplaceEntry(new_entry, false); | 748 InsertOrReplaceEntry(new_entry, false); |
704 } | 749 } |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
974 return i; | 1019 return i; |
975 } | 1020 } |
976 return -1; | 1021 return -1; |
977 } | 1022 } |
978 | 1023 |
979 NavigationEntry* NavigationController::GetTransientEntry() const { | 1024 NavigationEntry* NavigationController::GetTransientEntry() const { |
980 if (transient_entry_index_ == -1) | 1025 if (transient_entry_index_ == -1) |
981 return NULL; | 1026 return NULL; |
982 return entries_[transient_entry_index_].get(); | 1027 return entries_[transient_entry_index_].get(); |
983 } | 1028 } |
OLD | NEW |