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/navigation_controller.h" | 5 #include "chrome/browser/navigation_controller.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.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" |
11 #include "chrome/common/navigation_types.h" | 11 #include "chrome/common/navigation_types.h" |
12 #include "chrome/common/resource_bundle.h" | 12 #include "chrome/common/resource_bundle.h" |
13 #include "chrome/common/scoped_vector.h" | 13 #include "chrome/common/scoped_vector.h" |
14 #include "chrome/browser/browser_process.h" | 14 #include "chrome/browser/browser_process.h" |
15 #include "chrome/browser/dom_ui/dom_ui_host.h" | 15 #include "chrome/browser/dom_ui/dom_ui_host.h" |
16 #include "chrome/browser/navigation_entry.h" | 16 #include "chrome/browser/navigation_entry.h" |
17 #include "chrome/browser/profile.h" | 17 #include "chrome/browser/profile.h" |
18 #include "chrome/browser/repost_form_warning_dialog.h" | 18 #include "chrome/browser/repost_form_warning_dialog.h" |
19 #include "chrome/browser/site_instance.h" | 19 #include "chrome/browser/site_instance.h" |
20 #include "chrome/browser/tab_contents.h" | 20 #include "chrome/browser/tab_contents.h" |
21 #include "chrome/browser/tab_contents_delegate.h" | 21 #include "chrome/browser/tab_contents_delegate.h" |
22 #include "chrome/common/chrome_switches.h" | 22 #include "chrome/common/chrome_switches.h" |
23 #include "net/base/net_util.h" | 23 #include "net/base/net_util.h" |
24 #include "webkit/glue/webkit_glue.h" | 24 #include "webkit/glue/webkit_glue.h" |
25 | 25 |
26 namespace { | |
27 | |
28 // Invoked when entries have been pruned, or removed. For example, if the | |
29 // current entries are [google, digg, yahoo], with the current entry google, | |
30 // and the user types in cnet, then digg and yahoo are pruned. | |
31 void NotifyPrunedEntries(NavigationController* nav_controller) { | |
32 NotificationService::current()->Notify( | |
33 NOTIFY_NAV_LIST_PRUNED, | |
34 Source<NavigationController>(nav_controller), | |
35 NotificationService::NoDetails()); | |
36 } | |
37 | |
38 // Ensure the given NavigationEntry has a valid state, so that WebKit does not | |
39 // get confused if we navigate back to it. | |
40 // | |
41 // An empty state is treated as a new navigation by WebKit, which would mean | |
42 // losing the navigation entries and generating a new navigation entry after | |
43 // this one. We don't want that. To avoid this we create a valid state which | |
44 // WebKit will not treat as a new navigation. | |
45 void SetContentStateIfEmpty(NavigationEntry* entry) { | |
46 if (entry->content_state().empty() && | |
47 (entry->tab_type() == TAB_CONTENTS_WEB || | |
48 entry->tab_type() == TAB_CONTENTS_NEW_TAB_UI || | |
49 entry->tab_type() == TAB_CONTENTS_ABOUT_UI || | |
50 entry->tab_type() == TAB_CONTENTS_HTML_DIALOG)) { | |
51 entry->set_content_state( | |
52 webkit_glue::CreateHistoryStateForURL(entry->url())); | |
53 } | |
54 } | |
55 | |
56 // Configure all the NavigationEntries in entries for restore. This resets | |
57 // the transition type to reload and makes sure the content state isn't empty. | |
58 void ConfigureEntriesForRestore( | |
59 std::vector<linked_ptr<NavigationEntry> >* entries) { | |
60 for (size_t i = 0; i < entries->size(); ++i) { | |
61 // Use a transition type of reload so that we don't incorrectly increase | |
62 // the typed count. | |
63 (*entries)[i]->set_transition_type(PageTransition::RELOAD); | |
64 (*entries)[i]->set_restored(true); | |
65 // NOTE(darin): This code is only needed for backwards compat. | |
66 SetContentStateIfEmpty((*entries)[i].get()); | |
67 } | |
68 } | |
69 | |
70 // See NavigationController::IsURLInPageNavigation for how this works and why. | |
71 bool AreURLsInPageNavigation(const GURL& existing_url, const GURL& new_url) { | |
72 if (existing_url == new_url || !new_url.has_ref()) | |
73 return false; | |
74 | |
75 url_canon::Replacements<char> replacements; | |
76 replacements.ClearRef(); | |
77 return existing_url.ReplaceComponents(replacements) == | |
78 new_url.ReplaceComponents(replacements); | |
79 } | |
80 | |
81 } // namespace | |
82 | |
26 // TabContentsCollector --------------------------------------------------- | 83 // TabContentsCollector --------------------------------------------------- |
27 | 84 |
28 // We never destroy a TabContents synchronously because there are some | 85 // We never destroy a TabContents synchronously because there are some |
29 // complex code path that cause the current TabContents to be in the call | 86 // complex code path that cause the current TabContents to be in the call |
30 // stack. So instead, we use a TabContentsCollector which either destroys | 87 // stack. So instead, we use a TabContentsCollector which either destroys |
31 // the TabContents or does nothing if it has been cancelled. | 88 // the TabContents or does nothing if it has been cancelled. |
32 class TabContentsCollector : public Task { | 89 class TabContentsCollector : public Task { |
33 public: | 90 public: |
34 TabContentsCollector(NavigationController* target, | 91 TabContentsCollector(NavigationController* target, |
35 TabContentsType target_type) | 92 TabContentsType target_type) |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
94 // increase the typed count. | 151 // increase the typed count. |
95 PageTransition::RELOAD); | 152 PageTransition::RELOAD); |
96 entry->set_display_url(navigation.url); | 153 entry->set_display_url(navigation.url); |
97 entry->set_content_state(navigation.state); | 154 entry->set_content_state(navigation.state); |
98 entry->set_has_post_data( | 155 entry->set_has_post_data( |
99 navigation.type_mask & TabNavigation::HAS_POST_DATA); | 156 navigation.type_mask & TabNavigation::HAS_POST_DATA); |
100 entries->push_back(linked_ptr<NavigationEntry>(entry)); | 157 entries->push_back(linked_ptr<NavigationEntry>(entry)); |
101 } | 158 } |
102 } | 159 } |
103 | 160 |
104 // Configure all the NavigationEntries in entries for restore. This resets | |
105 // the transition type to reload and makes sure the content state isn't empty. | |
106 static void ConfigureEntriesForRestore( | |
107 std::vector<linked_ptr<NavigationEntry> >* entries) { | |
108 for (size_t i = 0, count = entries->size(); i < count; ++i) { | |
109 // Use a transition type of reload so that we don't incorrectly increase | |
110 // the typed count. | |
111 (*entries)[i]->set_transition_type(PageTransition::RELOAD); | |
112 (*entries)[i]->set_restored(true); | |
113 // NOTE(darin): This code is only needed for backwards compat. | |
114 NavigationController::SetContentStateIfEmpty((*entries)[i].get()); | |
115 } | |
116 } | |
117 | |
118 NavigationController::NavigationController(TabContents* contents, | 161 NavigationController::NavigationController(TabContents* contents, |
119 Profile* profile) | 162 Profile* profile) |
120 : profile_(profile), | 163 : profile_(profile), |
121 pending_entry_(NULL), | 164 pending_entry_(NULL), |
122 last_committed_entry_index_(-1), | 165 last_committed_entry_index_(-1), |
123 pending_entry_index_(-1), | 166 pending_entry_index_(-1), |
124 max_entry_count_(kMaxEntryCount), | 167 max_entry_count_(kMaxEntryCount), |
125 active_contents_(contents), | 168 active_contents_(contents), |
126 alternate_nav_url_fetcher_entry_unique_id_(0), | 169 alternate_nav_url_fetcher_entry_unique_id_(0), |
127 max_restored_page_id_(-1), | 170 max_restored_page_id_(-1), |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
175 NotificationService::NoDetails()); | 218 NotificationService::NoDetails()); |
176 } | 219 } |
177 | 220 |
178 TabContents* NavigationController::GetTabContents(TabContentsType t) { | 221 TabContents* NavigationController::GetTabContents(TabContentsType t) { |
179 // Make sure the TabContents is no longer scheduled for collection. | 222 // Make sure the TabContents is no longer scheduled for collection. |
180 CancelTabContentsCollection(t); | 223 CancelTabContentsCollection(t); |
181 return tab_contents_map_[t]; | 224 return tab_contents_map_[t]; |
182 } | 225 } |
183 | 226 |
184 void NavigationController::Reload() { | 227 void NavigationController::Reload() { |
185 // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? | |
186 DiscardPendingEntryInternal(); | 228 DiscardPendingEntryInternal(); |
187 int current_index = GetCurrentEntryIndex(); | 229 int current_index = GetCurrentEntryIndex(); |
188 if (check_for_repost_ && current_index != -1 && | 230 if (check_for_repost_ && current_index != -1 && |
189 GetEntryAtIndex(current_index)->has_post_data() && | 231 GetEntryAtIndex(current_index)->has_post_data() && |
190 active_contents_->AsWebContents() && | 232 active_contents_->AsWebContents() && |
191 !active_contents_->AsWebContents()->showing_repost_interstitial()) { | 233 !active_contents_->AsWebContents()->showing_repost_interstitial()) { |
192 // The user is asking to reload a page with POST data and we're not showing | 234 // The user is asking to reload a page with POST data and we're not showing |
193 // the POST interstitial. Prompt to make sure they really want to do this. | 235 // the POST interstitial. Prompt to make sure they really want to do this. |
194 // If they do, RepostFormWarningDialog calls us back with | 236 // If they do, RepostFormWarningDialog calls us back with |
195 // ReloadDontCheckForRepost. | 237 // ReloadDontCheckForRepost. |
196 active_contents_->Activate(); | 238 active_contents_->Activate(); |
197 RepostFormWarningDialog::RunRepostFormWarningDialog(this); | 239 RepostFormWarningDialog::RunRepostFormWarningDialog(this); |
198 } else { | 240 } else { |
199 // Base the navigation on where we are now... | 241 // Base the navigation on where we are now... |
200 int current_index = GetCurrentEntryIndex(); | 242 int current_index = GetCurrentEntryIndex(); |
201 | 243 |
202 // If we are no where, then we can't reload. TODO(darin): We should add a | 244 // If we are no where, then we can't reload. TODO(darin): We should add a |
203 // CanReload method. | 245 // CanReload method. |
204 if (current_index == -1) | 246 if (current_index == -1) |
205 return; | 247 return; |
206 | 248 |
207 // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? | |
208 DiscardPendingEntryInternal(); | 249 DiscardPendingEntryInternal(); |
209 | 250 |
210 pending_entry_index_ = current_index; | 251 pending_entry_index_ = current_index; |
211 entries_[pending_entry_index_]->set_transition_type(PageTransition::RELOAD); | 252 entries_[pending_entry_index_]->set_transition_type(PageTransition::RELOAD); |
212 NavigateToPendingEntry(true); | 253 NavigateToPendingEntry(true); |
213 } | 254 } |
214 } | 255 } |
215 | 256 |
216 NavigationEntry* NavigationController::GetEntryWithPageID( | 257 NavigationEntry* NavigationController::GetEntryWithPageID( |
217 TabContentsType type, SiteInstance* instance, int32 page_id) const { | 258 TabContentsType type, SiteInstance* instance, int32 page_id) const { |
218 int index = GetEntryIndexWithPageID(type, instance, page_id); | 259 int index = GetEntryIndexWithPageID(type, instance, page_id); |
219 return (index != -1) ? entries_[index].get() : NULL; | 260 return (index != -1) ? entries_[index].get() : NULL; |
220 } | 261 } |
221 | 262 |
222 void NavigationController::LoadEntry(NavigationEntry* entry) { | 263 void NavigationController::LoadEntry(NavigationEntry* entry) { |
223 // When navigating to a new page, we don't know for sure if we will actually | 264 // When navigating to a new page, we don't know for sure if we will actually |
224 // end up leaving the current page. The new page load could for example | 265 // end up leaving the current page. The new page load could for example |
225 // result in a download or a 'no content' response (e.g., a mailto: URL). | 266 // result in a download or a 'no content' response (e.g., a mailto: URL). |
226 | |
227 // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? | |
228 DiscardPendingEntryInternal(); | 267 DiscardPendingEntryInternal(); |
229 pending_entry_ = entry; | 268 pending_entry_ = entry; |
230 NotificationService::current()->Notify( | 269 NotificationService::current()->Notify( |
231 NOTIFY_NAV_ENTRY_PENDING, | 270 NOTIFY_NAV_ENTRY_PENDING, |
232 Source<NavigationController>(this), | 271 Source<NavigationController>(this), |
233 NotificationService::NoDetails()); | 272 NotificationService::NoDetails()); |
234 NavigateToPendingEntry(false); | 273 NavigateToPendingEntry(false); |
235 } | 274 } |
236 | 275 |
237 /* static */ | |
238 void NavigationController::SetContentStateIfEmpty( | |
239 NavigationEntry* entry) { | |
240 if (entry->content_state().empty() && | |
241 (entry->tab_type() == TAB_CONTENTS_WEB || | |
242 entry->tab_type() == TAB_CONTENTS_NEW_TAB_UI || | |
243 entry->tab_type() == TAB_CONTENTS_ABOUT_UI || | |
244 entry->tab_type() == TAB_CONTENTS_HTML_DIALOG)) { | |
245 // The state is empty and the url will be rendered by WebKit. An empty | |
246 // state is treated as a new navigation by WebKit, which would mean | |
247 // losing the navigation entries and generating a new navigation | |
248 // entry after this one. We don't want that. To avoid this we create | |
249 // a valid state which WebKit will not treat as a new navigation. | |
250 entry->set_content_state( | |
251 webkit_glue::CreateHistoryStateForURL(entry->url())); | |
252 } | |
253 } | |
254 | |
255 NavigationEntry* NavigationController::GetActiveEntry() const { | 276 NavigationEntry* NavigationController::GetActiveEntry() const { |
256 NavigationEntry* entry = pending_entry_; | 277 NavigationEntry* entry = pending_entry_; |
257 if (!entry) | 278 if (!entry) |
258 entry = GetLastCommittedEntry(); | 279 entry = GetLastCommittedEntry(); |
259 return entry; | 280 return entry; |
260 } | 281 } |
261 | 282 |
262 int NavigationController::GetCurrentEntryIndex() const { | 283 int NavigationController::GetCurrentEntryIndex() const { |
263 if (pending_entry_index_ != -1) | 284 if (pending_entry_index_ != -1) |
264 return pending_entry_index_; | 285 return pending_entry_index_; |
265 return last_committed_entry_index_; | 286 return last_committed_entry_index_; |
266 } | 287 } |
267 | 288 |
268 NavigationEntry* NavigationController::GetLastCommittedEntry() const { | 289 NavigationEntry* NavigationController::GetLastCommittedEntry() const { |
269 if (last_committed_entry_index_ == -1) | 290 if (last_committed_entry_index_ == -1) |
270 return NULL; | 291 return NULL; |
271 return entries_[last_committed_entry_index_].get(); | 292 return entries_[last_committed_entry_index_].get(); |
272 } | 293 } |
273 | 294 |
274 NavigationEntry* NavigationController::GetEntryAtOffset(int offset) const { | 295 NavigationEntry* NavigationController::GetEntryAtOffset(int offset) const { |
275 int index = last_committed_entry_index_ + offset; | 296 int index = last_committed_entry_index_ + offset; |
276 if (index < 0 || index >= GetEntryCount()) | 297 if (index < 0 || index >= GetEntryCount()) |
277 return NULL; | 298 return NULL; |
278 | 299 |
279 return entries_[index].get(); | 300 return entries_[index].get(); |
280 } | 301 } |
281 | 302 |
282 bool NavigationController::CanStop() const { | |
283 // TODO(darin): do we have something pending that we can stop? | |
284 return false; | |
285 } | |
286 | |
287 bool NavigationController::CanGoBack() const { | 303 bool NavigationController::CanGoBack() const { |
288 return entries_.size() > 1 && GetCurrentEntryIndex() > 0; | 304 return entries_.size() > 1 && GetCurrentEntryIndex() > 0; |
289 } | 305 } |
290 | 306 |
291 bool NavigationController::CanGoForward() const { | 307 bool NavigationController::CanGoForward() const { |
292 int index = GetCurrentEntryIndex(); | 308 int index = GetCurrentEntryIndex(); |
293 return index >= 0 && index < (static_cast<int>(entries_.size()) - 1); | 309 return index >= 0 && index < (static_cast<int>(entries_.size()) - 1); |
294 } | 310 } |
295 | 311 |
296 void NavigationController::GoBack() { | 312 void NavigationController::GoBack() { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
336 } | 352 } |
337 | 353 |
338 void NavigationController::GoToOffset(int offset) { | 354 void NavigationController::GoToOffset(int offset) { |
339 int index = last_committed_entry_index_ + offset; | 355 int index = last_committed_entry_index_ + offset; |
340 if (index < 0 || index >= GetEntryCount()) | 356 if (index < 0 || index >= GetEntryCount()) |
341 return; | 357 return; |
342 | 358 |
343 GoToIndex(index); | 359 GoToIndex(index); |
344 } | 360 } |
345 | 361 |
346 void NavigationController::Stop() { | |
347 DCHECK(CanStop()); | |
348 | |
349 // TODO(darin): we probably want to just call Stop on the active tab | |
350 // contents, but should we also call DiscardPendingEntry? | |
351 NOTREACHED() << "implement me"; | |
352 } | |
353 | |
354 void NavigationController::ReloadDontCheckForRepost() { | 362 void NavigationController::ReloadDontCheckForRepost() { |
355 Reload(); | 363 Reload(); |
356 } | 364 } |
357 | 365 |
358 void NavigationController::Destroy() { | 366 void NavigationController::Destroy() { |
359 // Close all tab contents owned by this controller. We make a list on the | 367 // Close all tab contents owned by this controller. We make a list on the |
360 // stack because they are removed from the map as they are Destroyed | 368 // stack because they are removed from the map as they are Destroyed |
361 // (invalidating the iterators), which may or may not occur synchronously. | 369 // (invalidating the iterators), which may or may not occur synchronously. |
362 // We also keep track of any NULL entries in the map so that we can clean | 370 // We also keep track of any NULL entries in the map so that we can clean |
363 // them out. | 371 // them out. |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
452 | 460 |
453 void NavigationController::LoadURLLazily(const GURL& url, | 461 void NavigationController::LoadURLLazily(const GURL& url, |
454 PageTransition::Type type, | 462 PageTransition::Type type, |
455 const std::wstring& title, | 463 const std::wstring& title, |
456 SkBitmap* icon) { | 464 SkBitmap* icon) { |
457 NavigationEntry* entry = CreateNavigationEntry(url, type); | 465 NavigationEntry* entry = CreateNavigationEntry(url, type); |
458 entry->set_title(title); | 466 entry->set_title(title); |
459 if (icon) | 467 if (icon) |
460 entry->favicon().set_bitmap(*icon); | 468 entry->favicon().set_bitmap(*icon); |
461 | 469 |
462 // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? | |
463 DiscardPendingEntryInternal(); | 470 DiscardPendingEntryInternal(); |
464 pending_entry_ = entry; | 471 pending_entry_ = entry; |
465 load_pending_entry_when_active_ = true; | 472 load_pending_entry_when_active_ = true; |
466 } | 473 } |
467 | 474 |
468 bool NavigationController::LoadingURLLazily() { | 475 bool NavigationController::LoadingURLLazily() { |
469 return load_pending_entry_when_active_; | 476 return load_pending_entry_when_active_; |
470 } | 477 } |
471 | 478 |
472 const std::wstring& NavigationController::GetLazyTitle() const { | 479 const std::wstring& NavigationController::GetLazyTitle() const { |
(...skipping 13 matching lines...) Expand all Loading... | |
486 } | 493 } |
487 | 494 |
488 void NavigationController::SetAlternateNavURLFetcher( | 495 void NavigationController::SetAlternateNavURLFetcher( |
489 AlternateNavURLFetcher* alternate_nav_url_fetcher) { | 496 AlternateNavURLFetcher* alternate_nav_url_fetcher) { |
490 DCHECK(!alternate_nav_url_fetcher_.get()); | 497 DCHECK(!alternate_nav_url_fetcher_.get()); |
491 DCHECK(pending_entry_); | 498 DCHECK(pending_entry_); |
492 alternate_nav_url_fetcher_.reset(alternate_nav_url_fetcher); | 499 alternate_nav_url_fetcher_.reset(alternate_nav_url_fetcher); |
493 alternate_nav_url_fetcher_entry_unique_id_ = pending_entry_->unique_id(); | 500 alternate_nav_url_fetcher_entry_unique_id_ = pending_entry_->unique_id(); |
494 } | 501 } |
495 | 502 |
496 void NavigationController::DidNavigateToEntry(NavigationEntry* entry, | 503 bool NavigationController::RendererDidNavigate( |
497 LoadCommittedDetails* details) { | 504 const ViewHostMsg_FrameNavigate_Params& params, |
498 DCHECK(active_contents_); | 505 bool is_interstitial, |
499 DCHECK(entry->tab_type() == active_contents_->type()); | 506 LoadCommittedDetails* details) { |
500 | 507 // Save the previous URL before we clobber it. |
501 SetContentStateIfEmpty(entry); | |
502 | |
503 entry->set_restored(false); | |
504 | |
505 // Update the details to list the last URL. Later, we'll update the current | |
506 // entry (after it's committed) and the details will be complete. | |
507 if (GetLastCommittedEntry()) | 508 if (GetLastCommittedEntry()) |
508 details->previous_url = GetLastCommittedEntry()->url(); | 509 details->previous_url = GetLastCommittedEntry()->url(); |
509 | 510 |
510 // If the entry is that of a page with PageID larger than any this Tab has | 511 // Assign the current site instance to any pending entry, so we can find it |
511 // seen before, then consider it a new navigation. Note that if the entry | 512 // later by calling GetEntryIndexWithPageID. We only care about this if the |
512 // has a SiteInstance, it should be the same as the SiteInstance of the | 513 // pending entry is an existing navigation and not a new one (or else we |
513 // active WebContents, because we have just navigated to it. | 514 // wouldn't care about finding it with GetEntryIndexWithPageID). |
514 DCHECK(entry->page_id() >= 0) << "Page ID must be set before calling us."; | 515 // |
515 if (entry->page_id() > GetMaxPageID()) { | 516 // TODO(brettw) this seems slightly bogus as we don't really know if the |
516 InsertEntry(entry); | 517 // pending entry is what this navigation is for. There is a similar TODO |
517 NotifyNavigationEntryCommitted(details); | 518 // w.r.t. the pending entry in RendererDidNavigateToNewPage. |
518 // It is now a safe time to schedule collection for any tab contents of a | 519 if (pending_entry_index_ >= 0) |
519 // different type, because a navigation is necessary to get back to them. | 520 pending_entry_->set_site_instance(active_contents_->GetSiteInstance()); |
520 ScheduleTabContentsCollectionForInactiveTabs(); | 521 |
521 return; | 522 // Do navigation-type specific actions. These will make and commit an entry. |
522 } | 523 switch (ClassifyNavigation(params)) { |
523 | 524 case NAV_NEW_PAGE: |
524 // Otherwise, we just need to update an existing entry with matching PageID. | 525 RendererDidNavigateToNewPage(params); |
525 // If the existing entry corresponds to the entry which is pending, then we | 526 break; |
526 // must update the current entry index accordingly. When navigating to the | 527 case NAV_EXISTING_PAGE: |
527 // same URL, a new PageID is not created. | 528 RendererDidNavigateToExistingPage(params); |
528 | 529 break; |
529 int existing_entry_index = GetEntryIndexWithPageID(entry->tab_type(), | 530 case NAV_SAME_PAGE: |
530 entry->site_instance(), | 531 RendererDidNavigateToSamePage(params); |
531 entry->page_id()); | 532 break; |
532 NavigationEntry* existing_entry = (existing_entry_index != -1) ? | 533 case NAV_IN_PAGE: |
533 entries_[existing_entry_index].get() : NULL; | 534 RendererDidNavigateInPage(params); |
534 if (!existing_entry) { | 535 break; |
535 // No existing entry, then simply ignore this navigation! | 536 case NAV_NEW_SUBFRAME: |
536 DLOG(WARNING) << "ignoring navigation for page: " << entry->page_id(); | 537 RendererDidNavigateNewSubframe(params); |
537 } else if ((existing_entry != pending_entry_) && pending_entry_ && | 538 break; |
538 (pending_entry_->page_id() == -1) && | 539 case NAV_AUTO_SUBFRAME: |
539 (pending_entry_->url() == existing_entry->url())) { | 540 if (!RendererDidNavigateAutoSubframe(params)) |
540 // In this case, we have a pending entry for a URL but WebCore didn't do a | 541 return false; |
541 // new navigation. This happens when you press enter in the URL bar to | 542 break; |
542 // reload. We will create a pending entry, but WebCore will convert it to | 543 case NAV_IGNORE: |
543 // a reload since it's the same page and not create a new entry for it | 544 // There is nothing we can do with this navigation, so we just return to |
544 // (the user doesn't want to have a new back/forward entry when they do | 545 // the caller that nothing has happened. |
545 // this). In this case, we want to just ignore the pending entry and go back | 546 return false; |
546 // to where we were. | 547 default: |
547 existing_entry->set_unique_id(pending_entry_->unique_id()); | 548 NOTREACHED(); |
548 DiscardPendingEntry(); | 549 } |
549 } else { | 550 |
550 DCHECK(existing_entry != entry); | 551 // All committed entries should have nonempty content state so WebKit doesn't |
551 // The given entry might provide a new URL... e.g., navigating back to a | 552 // get confused when we go back to them (see the function for details). |
552 // page in session history could have resulted in a new client redirect. | 553 SetContentStateIfEmpty(GetActiveEntry()); |
553 // The given entry might also provide a new title (typically an empty title | 554 |
554 // to overwrite the existing title). | 555 // WebKit doesn't set the "auto" transition on meta refreshes properly (bug |
555 existing_entry->set_url(entry->url()); | 556 // 1051891) so we manually set it for redirects which we normally treat as |
556 existing_entry->set_title(entry->title()); | 557 // "non-user-gestures" where we want to update stuff after navigations. |
557 existing_entry->favicon() = entry->favicon(); | 558 // |
558 existing_entry->set_content_state(entry->content_state()); | 559 // Note that the redirect check also checks for a pending entry to |
559 | 560 // differentiate real redirects from browser initiated navigations to a |
560 // TODO(brettw) why only copy the security style and no other SSL stuff? | 561 // redirected entry. This happens when you hit back to go to a page that was |
561 existing_entry->ssl().set_security_style(entry->ssl().security_style()); | 562 // the destination of a redirect, we don't want to treat it as a redirect |
562 | 563 // even though that's what its transition will be. See bug 1117048. |
563 const int prev_entry_index = last_committed_entry_index_; | 564 // |
564 if (existing_entry == pending_entry_) { | 565 // TODO(brettw) write a test for this complicated logic. |
565 DCHECK(pending_entry_index_ != -1); | 566 details->is_auto = (PageTransition::IsRedirect(params.transition) && |
566 last_committed_entry_index_ = pending_entry_index_; | 567 !GetPendingEntry()) || |
567 // TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()? | 568 params.gesture == NavigationGestureAuto; |
568 DiscardPendingEntryInternal(); | 569 |
569 } else { | 570 // Now prep the rest of the details for the notification and broadcast. |
570 // NOTE: Do not update the unique ID here, as we don't want infobars etc. | 571 details->entry = GetActiveEntry(); |
571 // to dismiss. | 572 details->is_in_page = IsURLInPageNavigation(params.url); |
572 | 573 details->is_main_frame = PageTransition::IsMainFrame(params.transition); |
573 // The navigation could have been issued by the renderer, so be sure that | |
574 // we update our current index. | |
575 last_committed_entry_index_ = existing_entry_index; | |
576 } | |
577 IndexOfActiveEntryChanged(prev_entry_index); | |
578 } | |
579 | |
580 delete entry; | |
581 NotifyNavigationEntryCommitted(details); | 574 NotifyNavigationEntryCommitted(details); |
582 | 575 |
583 if (alternate_nav_url_fetcher_.get()) { | 576 // Because this call may synchronously show an infobar, we do it last, to |
584 // Because this call may synchronously show an infobar, we do it last, to | 577 // make sure all other state is stable and the infobar won't get blown away |
585 // make sure all other state is stable and the infobar won't get blown away | 578 // by some transition. |
586 // by some transition. | 579 // |
580 // TODO(brettw) bug 1324500: This logic should be moved out of here, it should | |
581 // listen for the notification instead. | |
582 if (alternate_nav_url_fetcher_.get()) | |
587 alternate_nav_url_fetcher_->OnNavigatedToEntry(); | 583 alternate_nav_url_fetcher_->OnNavigatedToEntry(); |
588 } | 584 |
585 // Broadcast the NOTIFY_FRAME_PROVISIONAL_LOAD_COMMITTED notification for use | |
586 // by the SSL manager. | |
587 // | |
588 // TODO(brettw) bug 1352803: this information should be combined with | |
589 // NOTIFY_NAV_ENTRY_COMMITTED so this one can be deleted. | |
590 ProvisionalLoadDetails provisional_details(details->is_main_frame, | |
591 is_interstitial, | |
592 details->is_in_page, | |
593 params.url, | |
594 params.security_info); | |
595 NotificationService::current()-> | |
596 Notify(NOTIFY_FRAME_PROVISIONAL_LOAD_COMMITTED, | |
597 Source<NavigationController>(this), | |
598 Details<ProvisionalLoadDetails>(&provisional_details)); | |
589 | 599 |
590 // It is now a safe time to schedule collection for any tab contents of a | 600 // It is now a safe time to schedule collection for any tab contents of a |
591 // different type, because a navigation is necessary to get back to them. | 601 // different type, because a navigation is necessary to get back to them. |
592 ScheduleTabContentsCollectionForInactiveTabs(); | 602 ScheduleTabContentsCollectionForInactiveTabs(); |
593 } | 603 return true; |
594 | 604 } |
605 | |
606 NavigationController::NavClass NavigationController::ClassifyNavigation( | |
607 const ViewHostMsg_FrameNavigate_Params& params) const { | |
608 // If a page makes a popup navigated to about blank, and then writes stuff | |
609 // like a subframe navigated to a real site, we'll get a notification with an | |
610 // invalid page ID. There's nothing we can do with these, so just ignore them. | |
611 if (params.page_id == -1) { | |
612 DCHECK(!GetActiveEntry()) << "Got an invalid page ID but we seem to be " | |
613 " navigated to a valid page. This should be impossible."; | |
614 return NAV_IGNORE; | |
615 } | |
616 | |
617 if (params.page_id > active_contents_->GetMaxPageID()) { | |
618 // Greater page IDs than we've ever seen before are new pages. We may or may | |
619 // not have a pending entry for the page, and this may or may not be the | |
620 // main frame. | |
621 if (PageTransition::IsMainFrame(params.transition)) | |
622 return NAV_NEW_PAGE; | |
623 return NAV_NEW_SUBFRAME; | |
624 } | |
625 | |
626 // Now we know that the notification is for an existing page. Find that entry. | |
627 int existing_entry_index = GetEntryIndexWithPageID( | |
628 active_contents_->type(), | |
629 active_contents_->GetSiteInstance(), | |
630 params.page_id); | |
631 if (existing_entry_index == -1) | |
jcampan
2008/09/10 22:38:12
What case would that be? Should we DCHECK?
| |
632 return NAV_IGNORE; | |
633 NavigationEntry* existing_entry = entries_[existing_entry_index].get(); | |
634 | |
635 if (pending_entry_ && | |
636 pending_entry_->url() == params.url && | |
637 existing_entry != pending_entry_ && | |
638 pending_entry_->page_id() == -1 && | |
639 pending_entry_->url() == existing_entry->url()) { | |
640 // In this case, we have a pending entry for a URL but WebCore didn't do a | |
641 // new navigation. This happens when you press enter in the URL bar to | |
642 // reload. We will create a pending entry, but WebKit will convert it to | |
643 // a reload since it's the same page and not create a new entry for it | |
644 // (the user doesn't want to have a new back/forward entry when they do | |
645 // this). In this case, we want to just ignore the pending entry and go | |
646 // back to where we were (the "existing entry"). | |
647 return NAV_SAME_PAGE; | |
648 } | |
649 | |
650 if (AreURLsInPageNavigation(existing_entry->url(), params.url)) | |
651 return NAV_IN_PAGE; | |
652 | |
653 if (!PageTransition::IsMainFrame(params.transition)) | |
654 return NAV_AUTO_SUBFRAME; // All manual subframes would get new IDs and | |
655 // were handled above. | |
656 // Since we weeded out "new" navigations above, we know this is an existing | |
657 // navigation. | |
658 return NAV_EXISTING_PAGE; | |
659 } | |
660 | |
661 void NavigationController::RendererDidNavigateToNewPage( | |
662 const ViewHostMsg_FrameNavigate_Params& params) { | |
663 NavigationEntry* new_entry; | |
664 if (pending_entry_) { | |
665 // TODO(brettw) this assumes that the pending entry is appropriate for the | |
666 // new page that was just loaded. I don't think this is necessarily the | |
667 // case! We should have some more tracking to know for sure. This goes along | |
668 // with a similar TODO at the top of RendererDidNavigate where we blindly | |
669 // set the site instance on the pending entry. | |
670 new_entry = new NavigationEntry(*pending_entry_); | |
671 | |
672 // Don't use the page type from the pending entry. Some interstitial page | |
673 // may have set the type to interstitial. Once we commit, however, the page | |
674 // type must always be normal. | |
675 new_entry->set_page_type(NavigationEntry::NORMAL_PAGE); | |
676 } else { | |
677 new_entry = new NavigationEntry(active_contents_->type()); | |
678 } | |
679 | |
680 new_entry->set_url(params.url); | |
681 new_entry->set_page_id(params.page_id); | |
682 new_entry->set_transition_type(params.transition); | |
683 new_entry->set_site_instance(active_contents_->GetSiteInstance()); | |
684 new_entry->set_has_post_data(params.is_post); | |
685 | |
686 InsertEntry(new_entry); | |
687 } | |
688 | |
689 void NavigationController::RendererDidNavigateToExistingPage( | |
690 const ViewHostMsg_FrameNavigate_Params& params) { | |
691 // We should only get here for main frame navigations. | |
692 DCHECK(PageTransition::IsMainFrame(params.transition)); | |
693 | |
694 // This is a back/forward navigation. The existing page for the ID is | |
695 // guaranteed to exist, and we just need to update it with new information | |
696 // from the renderer. | |
697 int entry_index = GetEntryIndexWithPageID( | |
698 active_contents_->type(), | |
699 active_contents_->GetSiteInstance(), | |
700 params.page_id); | |
701 DCHECK(entry_index >= 0 && | |
702 entry_index < static_cast<int>(entries_.size())); | |
703 NavigationEntry* entry = entries_[entry_index].get(); | |
704 | |
705 // The URL (and hence the site instance) may have changed due to redirects. | |
706 entry->set_url(params.url); | |
707 entry->set_site_instance(active_contents_->GetSiteInstance()); | |
Charlie Reis
2008/09/10 22:58:19
Hmm, I missed this one before. Did this correspon
brettw
2008/09/11 02:46:36
This gets hit during session restore. I clarified
Charlie Reis
2008/09/11 03:59:28
OK
| |
708 | |
709 // The entry we found in the list might be pending if the user hit | |
710 // back/forward/reload. This load should commit it (since it's already in the | |
711 // list, we can just discard the pending pointer). | |
712 // | |
713 // Note that we need to use the "internal" version since we don't want to | |
714 // actually change any other state, just kill the pointer. | |
715 if (entry == pending_entry_) | |
716 DiscardPendingEntryInternal(); | |
717 | |
718 int old_committed_entry_index = last_committed_entry_index_; | |
719 last_committed_entry_index_ = entry_index; | |
720 IndexOfActiveEntryChanged(old_committed_entry_index); | |
721 } | |
722 | |
723 void NavigationController::RendererDidNavigateToSamePage( | |
724 const ViewHostMsg_FrameNavigate_Params& params) { | |
725 // This mode implies we have a pending entry that's the same as an existing | |
726 // entry for this page ID. All we need to do is update the existing entry. | |
727 NavigationEntry* existing_entry = GetEntryWithPageID( | |
728 active_contents_->type(), | |
729 active_contents_->GetSiteInstance(), | |
730 params.page_id); | |
731 | |
732 // We assign the entry's unique ID to be that of the new one. Since this is | |
733 // always the result of a user action, we want to dismiss infobars, etc. like | |
734 // a regular user-initiated navigation. | |
735 existing_entry->set_unique_id(pending_entry_->unique_id()); | |
736 | |
737 DiscardPendingEntry(); | |
738 } | |
739 | |
740 void NavigationController::RendererDidNavigateInPage( | |
741 const ViewHostMsg_FrameNavigate_Params& params) { | |
742 DCHECK(PageTransition::IsMainFrame(params.transition)) << | |
743 "WebKit should only tell us about in-page navs for the main frame."; | |
744 // We're guaranteed to have an entry for this one. | |
745 NavigationEntry* existing_entry = GetEntryWithPageID( | |
746 active_contents_->type(), | |
747 active_contents_->GetSiteInstance(), | |
748 params.page_id); | |
749 | |
750 // Reference fragment navigation. We're guaranteed to have the last_committed | |
751 // entry and it will be the same page as the new navigation (minus the | |
752 // reference fragments, of course). | |
753 NavigationEntry* new_entry = new NavigationEntry(*existing_entry); | |
754 new_entry->set_page_id(params.page_id); | |
755 new_entry->set_url(params.url); | |
756 InsertEntry(new_entry); | |
757 } | |
758 | |
759 void NavigationController::RendererDidNavigateNewSubframe( | |
760 const ViewHostMsg_FrameNavigate_Params& params) { | |
761 // Manual subframe navigations just get the current entry cloned so the user | |
762 // can go back or forward to it. The actual subframe information will be | |
763 // stored in the page state for each of those entries. This happens out of | |
764 // band with the actual navigations. | |
765 DCHECK(GetLastCommittedEntry()); | |
766 NavigationEntry* new_entry = new NavigationEntry(*GetLastCommittedEntry()); | |
767 new_entry->set_page_id(params.page_id); | |
768 InsertEntry(new_entry); | |
769 } | |
770 | |
771 bool NavigationController::RendererDidNavigateAutoSubframe( | |
772 const ViewHostMsg_FrameNavigate_Params& params) { | |
773 // We're guaranteed to have a previously committed entry, and we now need to | |
774 // handle navigation inside of a subframe in it without creating a new entry. | |
775 DCHECK(GetLastCommittedEntry()); | |
776 | |
777 // Handle the case where we're navigating back/forward to a previous subframe | |
778 // navigation entry. This is case "2." in NAV_AUTO_SUBFRAME comment in the | |
779 // header file. In case "1." this will be a NOP. | |
780 int entry_index = GetEntryIndexWithPageID( | |
781 active_contents_->type(), | |
782 active_contents_->GetSiteInstance(), | |
783 params.page_id); | |
784 if (entry_index < 0 || | |
785 entry_index >= static_cast<int>(entries_.size())) { | |
786 NOTREACHED(); | |
787 return false; | |
788 } | |
789 | |
790 // Update the current navigation entry in case we're going back/forward. | |
791 if (entry_index != last_committed_entry_index_) { | |
792 int old_committed_entry_index = last_committed_entry_index_; | |
793 last_committed_entry_index_ = entry_index; | |
794 IndexOfActiveEntryChanged(old_committed_entry_index); | |
795 return true; | |
796 } | |
797 return false; | |
798 } | |
799 | |
800 void NavigationController::CommitPendingEntry() { | |
801 if (!GetPendingEntry()) | |
802 return; // Nothing to do. | |
803 | |
804 // Need to save the previous URL for the notification. | |
805 LoadCommittedDetails details; | |
806 if (GetLastCommittedEntry()) | |
807 details.previous_url = GetLastCommittedEntry()->url(); | |
808 | |
809 if (pending_entry_index_ >= 0) { | |
810 // This is a previous navigation (back/forward) that we're just now | |
811 // committing. Just mark it as committed. | |
812 int new_entry_index = pending_entry_index_; | |
813 DiscardPendingEntryInternal(); | |
814 | |
815 // Mark that entry as committed. | |
816 int old_committed_entry_index = last_committed_entry_index_; | |
817 last_committed_entry_index_ = new_entry_index; | |
818 IndexOfActiveEntryChanged(old_committed_entry_index); | |
819 } else { | |
820 // This is a new navigation. It's easiest to just copy the entry and insert | |
821 // it new again, since InsertEntry expects to take ownership and also | |
822 // discard the pending entry. We also need to synthesize a page ID. We can | |
823 // only do this because this function will only be called by our custom | |
824 // TabContents types. For WebContents, the IDs are generated by the | |
825 // renderer, so we can't do this. | |
826 pending_entry_->set_page_id(active_contents_->GetMaxPageID() + 1); | |
827 active_contents_->UpdateMaxPageID(pending_entry_->page_id()); | |
828 InsertEntry(new NavigationEntry(*pending_entry_)); | |
829 } | |
830 | |
831 // Broadcast the notification of the navigation. | |
832 details.entry = GetActiveEntry(); | |
833 details.is_auto = false; | |
834 details.is_in_page = AreURLsInPageNavigation(details.previous_url, | |
835 details.entry->url()); | |
836 details.is_main_frame = true; | |
837 NotifyNavigationEntryCommitted(&details); | |
838 } | |
595 | 839 |
596 int NavigationController::GetIndexOfEntry( | 840 int NavigationController::GetIndexOfEntry( |
597 const NavigationEntry* entry) const { | 841 const NavigationEntry* entry) const { |
598 const NavigationEntries::const_iterator i(std::find( | 842 const NavigationEntries::const_iterator i(std::find( |
599 entries_.begin(), | 843 entries_.begin(), |
600 entries_.end(), | 844 entries_.end(), |
601 entry)); | 845 entry)); |
602 return (i == entries_.end()) ? -1 : static_cast<int>(i - entries_.begin()); | 846 return (i == entries_.end()) ? -1 : static_cast<int>(i - entries_.begin()); |
603 } | 847 } |
604 | 848 |
605 void NavigationController::RemoveLastEntry() { | 849 void NavigationController::RemoveLastEntryForInterstitial() { |
606 int current_size = static_cast<int>(entries_.size()); | 850 int current_size = static_cast<int>(entries_.size()); |
607 | 851 |
608 if (current_size > 0) { | 852 if (current_size > 0) { |
609 if (pending_entry_ == entries_[current_size - 1] || | 853 if (pending_entry_ == entries_[current_size - 1] || |
610 pending_entry_index_ == current_size - 1) | 854 pending_entry_index_ == current_size - 1) |
611 DiscardPendingEntryInternal(); | 855 DiscardPendingEntryInternal(); |
612 | 856 |
613 entries_.pop_back(); | 857 entries_.pop_back(); |
614 | 858 |
615 if (last_committed_entry_index_ >= current_size - 1) | 859 if (last_committed_entry_index_ >= current_size - 1) { |
616 last_committed_entry_index_ = current_size - 2; | 860 last_committed_entry_index_ = current_size - 2; |
617 | 861 |
618 NotifyPrunedEntries(); | 862 // Broadcast the notification of the navigation. This is kind of a hack, |
863 // since the navigation wasn't actually committed. But this function is | |
864 // used for interstital pages, and the UI needs to get updated when the | |
865 // interstitial page | |
866 LoadCommittedDetails details; | |
867 details.entry = GetActiveEntry(); | |
868 details.is_auto = false; | |
869 details.is_in_page = false; | |
870 details.is_main_frame = true; | |
871 NotifyNavigationEntryCommitted(&details); | |
872 } | |
873 | |
874 NotifyPrunedEntries(this); | |
619 } | 875 } |
620 } | 876 } |
621 | 877 |
878 void NavigationController::AddDummyEntryForInterstitial( | |
879 const NavigationEntry& clone_me) { | |
880 // We need to send a commit notification for this transition. | |
881 LoadCommittedDetails details; | |
882 if (GetLastCommittedEntry()) | |
883 details.previous_url = GetLastCommittedEntry()->url(); | |
884 | |
885 NavigationEntry* new_entry = new NavigationEntry(clone_me); | |
886 InsertEntry(new_entry); | |
887 // Watch out, don't use clone_me after this. The caller may have passed in a | |
888 // reference to our pending entry, which means it would have been destroyed. | |
889 | |
890 details.is_auto = false; | |
891 details.entry = GetActiveEntry(); | |
892 details.is_in_page = false; | |
893 details.is_main_frame = true; | |
894 NotifyNavigationEntryCommitted(&details); | |
895 } | |
896 | |
897 bool NavigationController::IsURLInPageNavigation(const GURL& url) const { | |
898 NavigationEntry* last_committed = GetLastCommittedEntry(); | |
899 if (!last_committed) | |
900 return false; | |
901 return AreURLsInPageNavigation(last_committed->url(), url); | |
902 } | |
903 | |
622 void NavigationController::DiscardPendingEntry() { | 904 void NavigationController::DiscardPendingEntry() { |
623 DiscardPendingEntryInternal(); | 905 DiscardPendingEntryInternal(); |
624 | 906 |
625 // Synchronize the active_contents_ to the last committed entry. | 907 // Synchronize the active_contents_ to the last committed entry. |
626 NavigationEntry* last_entry = GetLastCommittedEntry(); | 908 NavigationEntry* last_entry = GetLastCommittedEntry(); |
627 if (last_entry && last_entry->tab_type() != active_contents_->type()) { | 909 if (last_entry && last_entry->tab_type() != active_contents_->type()) { |
628 TabContents* from_contents = active_contents_; | 910 TabContents* from_contents = active_contents_; |
629 from_contents->SetActive(false); | 911 from_contents->SetActive(false); |
630 | 912 |
631 // Switch back to the previous tab contents. | 913 // Switch back to the previous tab contents. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
668 | 950 |
669 // Prune any entries which are in front of the current entry. | 951 // Prune any entries which are in front of the current entry. |
670 if (current_size > 0) { | 952 if (current_size > 0) { |
671 bool pruned = false; | 953 bool pruned = false; |
672 while (last_committed_entry_index_ < (current_size - 1)) { | 954 while (last_committed_entry_index_ < (current_size - 1)) { |
673 pruned = true; | 955 pruned = true; |
674 entries_.pop_back(); | 956 entries_.pop_back(); |
675 current_size--; | 957 current_size--; |
676 } | 958 } |
677 if (pruned) // Only notify if we did prune something. | 959 if (pruned) // Only notify if we did prune something. |
678 NotifyPrunedEntries(); | 960 NotifyPrunedEntries(this); |
679 } | 961 } |
680 | 962 |
681 if (entries_.size() >= max_entry_count_) | 963 if (entries_.size() >= max_entry_count_) |
682 RemoveEntryAtIndex(0); | 964 RemoveEntryAtIndex(0); |
683 | 965 |
684 entries_.push_back(linked_ptr<NavigationEntry>(entry)); | 966 entries_.push_back(linked_ptr<NavigationEntry>(entry)); |
685 last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1; | 967 last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1; |
968 | |
969 // This is a new page ID, so we need everybody to know about it. | |
970 active_contents_->UpdateMaxPageID(entry->page_id()); | |
686 | 971 |
972 // TODO(brettw) this seems bogus. The tab contents can listen for the | |
973 // notification or use the details that we pass back to it. | |
687 active_contents_->NotifyDidNavigate(NAVIGATION_NEW, 0); | 974 active_contents_->NotifyDidNavigate(NAVIGATION_NEW, 0); |
688 } | 975 } |
689 | 976 |
690 void NavigationController::SetWindowID(const SessionID& id) { | 977 void NavigationController::SetWindowID(const SessionID& id) { |
691 window_id_ = id; | 978 window_id_ = id; |
692 NotificationService::current()->Notify(NOTIFY_TAB_PARENTED, | 979 NotificationService::current()->Notify(NOTIFY_TAB_PARENTED, |
693 Source<NavigationController>(this), | 980 Source<NavigationController>(this), |
694 NotificationService::NoDetails()); | 981 NotificationService::NoDetails()); |
695 } | 982 } |
696 | 983 |
(...skipping 19 matching lines...) Expand all Loading... | |
716 GetTabContentsCreateIfNecessary(parent, *pending_entry_); | 1003 GetTabContentsCreateIfNecessary(parent, *pending_entry_); |
717 | 1004 |
718 contents->SetActive(true); | 1005 contents->SetActive(true); |
719 active_contents_ = contents; | 1006 active_contents_ = contents; |
720 | 1007 |
721 if (from_contents && from_contents != contents) { | 1008 if (from_contents && from_contents != contents) { |
722 if (from_contents->delegate()) | 1009 if (from_contents->delegate()) |
723 from_contents->delegate()->ReplaceContents(from_contents, contents); | 1010 from_contents->delegate()->ReplaceContents(from_contents, contents); |
724 } | 1011 } |
725 | 1012 |
726 if (!contents->Navigate(*pending_entry_, reload)) | 1013 NavigationEntry temp_entry(*pending_entry_); |
1014 if (!contents->NavigateToPendingEntry(reload)) | |
727 DiscardPendingEntry(); | 1015 DiscardPendingEntry(); |
728 } | 1016 } |
729 | 1017 |
730 void NavigationController::NotifyNavigationEntryCommitted( | 1018 void NavigationController::NotifyNavigationEntryCommitted( |
731 LoadCommittedDetails* details) { | 1019 LoadCommittedDetails* details) { |
732 // Reset the Alternate Nav URL Fetcher if we're loading some page it doesn't | 1020 // Reset the Alternate Nav URL Fetcher if we're loading some page it doesn't |
733 // care about. We must do this before calling Notify() below as that may | 1021 // care about. We must do this before calling Notify() below as that may |
734 // result in the creation of a new fetcher. | 1022 // result in the creation of a new fetcher. |
735 // | 1023 // |
736 // TODO(brettw) bug 1324500: this logic should be moved out of the controller! | 1024 // TODO(brettw) bug 1324500: this logic should be moved out of the controller! |
(...skipping 11 matching lines...) Expand all Loading... | |
748 active_contents_->NotifyNavigationStateChanged( | 1036 active_contents_->NotifyNavigationStateChanged( |
749 TabContents::INVALIDATE_EVERYTHING); | 1037 TabContents::INVALIDATE_EVERYTHING); |
750 | 1038 |
751 details->entry = GetActiveEntry(); | 1039 details->entry = GetActiveEntry(); |
752 NotificationService::current()->Notify( | 1040 NotificationService::current()->Notify( |
753 NOTIFY_NAV_ENTRY_COMMITTED, | 1041 NOTIFY_NAV_ENTRY_COMMITTED, |
754 Source<NavigationController>(this), | 1042 Source<NavigationController>(this), |
755 Details<LoadCommittedDetails>(details)); | 1043 Details<LoadCommittedDetails>(details)); |
756 } | 1044 } |
757 | 1045 |
758 void NavigationController::NotifyPrunedEntries() { | 1046 void NavigationController::IndexOfActiveEntryChanged(int prev_committed_index) { |
759 NotificationService::current()->Notify(NOTIFY_NAV_LIST_PRUNED, | |
760 Source<NavigationController>(this), | |
761 NotificationService::NoDetails()); | |
762 } | |
763 | |
764 void NavigationController::IndexOfActiveEntryChanged( | |
765 int prev_committed_index) { | |
766 NavigationType nav_type = NAVIGATION_BACK_FORWARD; | 1047 NavigationType nav_type = NAVIGATION_BACK_FORWARD; |
767 int relative_navigation_offset = | 1048 int relative_navigation_offset = |
768 GetLastCommittedEntryIndex() - prev_committed_index; | 1049 GetLastCommittedEntryIndex() - prev_committed_index; |
769 if (relative_navigation_offset == 0) { | 1050 if (relative_navigation_offset == 0) |
770 nav_type = NAVIGATION_REPLACE; | 1051 nav_type = NAVIGATION_REPLACE; |
771 } | 1052 |
1053 // TODO(brettw) I don't think this call should be necessary. There is already | |
1054 // a notification of this event that could be used, or maybe all the tab | |
1055 // contents' know when we navigate (WebContents does). | |
772 active_contents_->NotifyDidNavigate(nav_type, relative_navigation_offset); | 1056 active_contents_->NotifyDidNavigate(nav_type, relative_navigation_offset); |
773 } | 1057 } |
774 | 1058 |
775 TabContents* NavigationController::GetTabContentsCreateIfNecessary( | 1059 TabContents* NavigationController::GetTabContentsCreateIfNecessary( |
776 HWND parent, | 1060 HWND parent, |
777 const NavigationEntry& entry) { | 1061 const NavigationEntry& entry) { |
778 TabContents* contents = GetTabContents(entry.tab_type()); | 1062 TabContents* contents = GetTabContents(entry.tab_type()); |
779 if (!contents) { | 1063 if (!contents) { |
780 contents = TabContents::CreateWithType(entry.tab_type(), parent, profile_, | 1064 contents = TabContents::CreateWithType(entry.tab_type(), parent, profile_, |
781 entry.site_instance()); | 1065 entry.site_instance()); |
(...skipping 30 matching lines...) Expand all Loading... | |
812 NOTREACHED() << "Should not happen. Multiple contents for one type"; | 1096 NOTREACHED() << "Should not happen. Multiple contents for one type"; |
813 } else { | 1097 } else { |
814 tab_contents_map_[t] = some_contents; | 1098 tab_contents_map_[t] = some_contents; |
815 some_contents->set_controller(this); | 1099 some_contents->set_controller(this); |
816 } | 1100 } |
817 } | 1101 } |
818 if (some_contents->AsDOMUIHost()) | 1102 if (some_contents->AsDOMUIHost()) |
819 some_contents->AsDOMUIHost()->AttachMessageHandlers(); | 1103 some_contents->AsDOMUIHost()->AttachMessageHandlers(); |
820 } | 1104 } |
821 | 1105 |
822 void NavigationController::NotifyEntryChangedByPageID( | |
823 TabContentsType type, | |
824 SiteInstance *instance, | |
825 int32 page_id) { | |
826 int index = GetEntryIndexWithPageID(type, instance, page_id); | |
827 if (index != -1) | |
828 NotifyEntryChanged(entries_[index].get(), index); | |
829 } | |
830 | |
831 // static | 1106 // static |
832 void NavigationController::DisablePromptOnRepost() { | 1107 void NavigationController::DisablePromptOnRepost() { |
833 check_for_repost_ = false; | 1108 check_for_repost_ = false; |
834 } | 1109 } |
835 | 1110 |
836 void NavigationController::SetActive(bool is_active) { | 1111 void NavigationController::SetActive(bool is_active) { |
837 if (is_active) { | 1112 if (is_active) { |
838 if (needs_reload_) { | 1113 if (needs_reload_) { |
839 LoadIfNecessary(); | 1114 LoadIfNecessary(); |
840 } else if (load_pending_entry_when_active_) { | 1115 } else if (load_pending_entry_when_active_) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
881 if (!entries_.empty()) | 1156 if (!entries_.empty()) |
882 last_committed_entry_index_--; | 1157 last_committed_entry_index_--; |
883 else | 1158 else |
884 last_committed_entry_index_ = -1; | 1159 last_committed_entry_index_ = -1; |
885 } | 1160 } |
886 | 1161 |
887 // TODO(brettw) bug 1324021: we probably need some notification here so the | 1162 // TODO(brettw) bug 1324021: we probably need some notification here so the |
888 // session service can stay in sync. | 1163 // session service can stay in sync. |
889 } | 1164 } |
890 | 1165 |
891 int NavigationController::GetMaxPageID() const { | |
892 return active_contents_->GetMaxPageID(); | |
893 } | |
894 | |
895 NavigationController* NavigationController::Clone(HWND parent_hwnd) { | 1166 NavigationController* NavigationController::Clone(HWND parent_hwnd) { |
896 NavigationController* nc = new NavigationController(NULL, profile_); | 1167 NavigationController* nc = new NavigationController(NULL, profile_); |
897 | 1168 |
898 if (GetEntryCount() == 0) | 1169 if (GetEntryCount() == 0) |
899 return nc; | 1170 return nc; |
900 | 1171 |
901 nc->needs_reload_ = true; | 1172 nc->needs_reload_ = true; |
902 | 1173 |
903 nc->entries_.reserve(entries_.size()); | 1174 nc->entries_.reserve(entries_.size()); |
904 for (int i = 0, c = GetEntryCount(); i < c; ++i) { | 1175 for (int i = 0, c = GetEntryCount(); i < c; ++i) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
967 | 1238 |
968 void NavigationController::DiscardPendingEntryInternal() { | 1239 void NavigationController::DiscardPendingEntryInternal() { |
969 if (pending_entry_index_ == -1) | 1240 if (pending_entry_index_ == -1) |
970 delete pending_entry_; | 1241 delete pending_entry_; |
971 pending_entry_ = NULL; | 1242 pending_entry_ = NULL; |
972 pending_entry_index_ = -1; | 1243 pending_entry_index_ = -1; |
973 } | 1244 } |
974 | 1245 |
975 int NavigationController::GetEntryIndexWithPageID( | 1246 int NavigationController::GetEntryIndexWithPageID( |
976 TabContentsType type, SiteInstance* instance, int32 page_id) const { | 1247 TabContentsType type, SiteInstance* instance, int32 page_id) const { |
977 // The instance should only be specified for contents displaying web pages. | |
978 // TODO(evanm): checking against NEW_TAB_UI and HTML_DLG here is lame. | |
979 // It'd be nice for DomUIHost to just use SiteInstances for keeping content | |
980 // separated properly. | |
981 if (type != TAB_CONTENTS_WEB && | |
982 type != TAB_CONTENTS_NEW_TAB_UI && | |
983 type != TAB_CONTENTS_ABOUT_UI && | |
984 type != TAB_CONTENTS_HTML_DIALOG && | |
985 type != TAB_CONTENTS_VIEW_SOURCE && | |
986 type != TAB_CONTENTS_DEBUGGER) | |
987 DCHECK(instance == NULL); | |
988 | |
989 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { | 1248 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { |
990 if ((entries_[i]->tab_type() == type) && | 1249 if ((entries_[i]->tab_type() == type) && |
991 (entries_[i]->site_instance() == instance) && | 1250 (entries_[i]->site_instance() == instance) && |
992 (entries_[i]->page_id() == page_id)) | 1251 (entries_[i]->page_id() == page_id)) |
993 return i; | 1252 return i; |
994 } | 1253 } |
995 return -1; | 1254 return -1; |
996 } | 1255 } |
OLD | NEW |