blob: 1142839ae1bba4222def444eb26f883ad8cfd9a1 [file] [log] [blame]
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "webkit/tools/test_shell/test_navigation_controller.h"
#include "base/logging.h"
#include "webkit/tools/test_shell/test_shell.h"
// ----------------------------------------------------------------------------
// TestNavigationEntry
TestNavigationEntry::TestNavigationEntry()
: page_id_(-1) {
}
TestNavigationEntry::TestNavigationEntry(int page_id,
const GURL& url,
const std::wstring& title,
const std::wstring& target_frame)
: page_id_(page_id),
url_(url),
title_(title),
target_frame_(target_frame) {
}
TestNavigationEntry::~TestNavigationEntry() {
}
void TestNavigationEntry::SetContentState(const std::string& state) {
state_ = state;
}
// ----------------------------------------------------------------------------
// TestNavigationController
TestNavigationController::TestNavigationController(TestShell* shell)
: pending_entry_(NULL),
last_committed_entry_index_(-1),
pending_entry_index_(-1),
shell_(shell),
max_page_id_(-1) {
}
TestNavigationController::~TestNavigationController() {
DiscardPendingEntry();
}
void TestNavigationController::Reset() {
entries_.clear();
DiscardPendingEntry();
last_committed_entry_index_ = -1;
}
void TestNavigationController::Reload() {
// Base the navigation on where we are now...
int current_index = GetCurrentEntryIndex();
// If we are no where, then we can't reload. TODO(darin): We should add a
// CanReload method.
if (current_index == -1)
return;
DiscardPendingEntry();
pending_entry_index_ = current_index;
NavigateToPendingEntry(true);
}
void TestNavigationController::GoToOffset(int offset) {
int index = last_committed_entry_index_ + offset;
if (index < 0 || index >= GetEntryCount())
return;
GoToIndex(index);
}
void TestNavigationController::GoToIndex(int index) {
DCHECK(index >= 0);
DCHECK(index < static_cast<int>(entries_.size()));
DiscardPendingEntry();
pending_entry_index_ = index;
NavigateToPendingEntry(false);
}
void TestNavigationController::LoadEntry(TestNavigationEntry* entry) {
// When navigating to a new page, we don't know for sure if we will actually
// end up leaving the current page. The new page load could for example
// result in a download or a 'no content' response (e.g., a mailto: URL).
DiscardPendingEntry();
pending_entry_ = entry;
NavigateToPendingEntry(false);
}
TestNavigationEntry* TestNavigationController::GetLastCommittedEntry() const {
if (last_committed_entry_index_ == -1)
return NULL;
return entries_[last_committed_entry_index_].get();
}
TestNavigationEntry* TestNavigationController::GetActiveEntry() const {
TestNavigationEntry* entry = pending_entry_;
if (!entry)
entry = GetLastCommittedEntry();
return entry;
}
int TestNavigationController::GetCurrentEntryIndex() const {
if (pending_entry_index_ != -1)
return pending_entry_index_;
return last_committed_entry_index_;
}
TestNavigationEntry* TestNavigationController::GetEntryAtIndex(
int index) const {
if (index < 0 || index >= GetEntryCount())
return NULL;
return entries_[index].get();
}
TestNavigationEntry* TestNavigationController::GetEntryWithPageID(
int32 page_id) const {
int index = GetEntryIndexWithPageID(page_id);
return (index != -1) ? entries_[index].get() : NULL;
}
void TestNavigationController::DidNavigateToEntry(TestNavigationEntry* entry) {
// If the entry is that of a page with PageID larger than any this Tab has
// seen before, then consider it a new navigation.
if (entry->GetPageID() > GetMaxPageID()) {
InsertEntry(entry);
return;
}
// Otherwise, we just need to update an existing entry with matching PageID.
// If the existing entry corresponds to the entry which is pending, then we
// must update the current entry index accordingly. When navigating to the
// same URL, a new PageID is not created.
int existing_entry_index = GetEntryIndexWithPageID(entry->GetPageID());
TestNavigationEntry* existing_entry = (existing_entry_index != -1) ?
entries_[existing_entry_index].get() : NULL;
if (!existing_entry) {
// No existing entry, then simply ignore this navigation!
DLOG(WARNING) << "ignoring navigation for page: " << entry->GetPageID();
} else if (existing_entry == pending_entry_) {
// The given entry might provide a new URL... e.g., navigating back to a
// page in session history could have resulted in a new client redirect.
existing_entry->SetURL(entry->GetURL());
existing_entry->SetContentState(entry->GetContentState());
last_committed_entry_index_ = pending_entry_index_;
pending_entry_index_ = -1;
pending_entry_ = NULL;
} else if (pending_entry_ && pending_entry_->GetPageID() == -1 &&
pending_entry_->GetURL() == existing_entry->GetURL()) {
// Not a new navigation
DiscardPendingEntry();
} else {
// The given entry might provide a new URL... e.g., navigating to a page
// might result in a client redirect, which should override the URL of the
// existing entry.
existing_entry->SetURL(entry->GetURL());
existing_entry->SetContentState(entry->GetContentState());
// The navigation could have been issued by the renderer, so be sure that
// we update our current index.
last_committed_entry_index_ = existing_entry_index;
}
delete entry;
UpdateMaxPageID();
}
void TestNavigationController::DiscardPendingEntry() {
if (pending_entry_index_ == -1)
delete pending_entry_;
pending_entry_ = NULL;
pending_entry_index_ = -1;
}
void TestNavigationController::InsertEntry(TestNavigationEntry* entry) {
DiscardPendingEntry();
// Prune any entry which are in front of the current entry
int current_size = static_cast<int>(entries_.size());
if (current_size > 0) {
while (last_committed_entry_index_ < (current_size - 1)) {
entries_.pop_back();
current_size--;
}
}
entries_.push_back(linked_ptr<TestNavigationEntry>(entry));
last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1;
UpdateMaxPageID();
}
int TestNavigationController::GetEntryIndexWithPageID(int32 page_id) const {
for (int i = static_cast<int>(entries_.size())-1; i >= 0; --i) {
if (entries_[i]->GetPageID() == page_id)
return i;
}
return -1;
}
void TestNavigationController::NavigateToPendingEntry(bool reload) {
// For session history navigations only the pending_entry_index_ is set.
if (!pending_entry_) {
DCHECK(pending_entry_index_ != -1);
pending_entry_ = entries_[pending_entry_index_].get();
}
if (shell_->Navigate(*pending_entry_, reload)) {
// Note: this is redundant if navigation completed synchronously because
// DidNavigateToEntry call this as well.
UpdateMaxPageID();
} else {
DiscardPendingEntry();
}
}
void TestNavigationController::UpdateMaxPageID() {
TestNavigationEntry* entry = GetActiveEntry();
if (entry)
max_page_id_ = std::max(max_page_id_, entry->GetPageID());
}