// Copyright 2014 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. /* * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. * (http://www.torchmobile.com/) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "content/renderer/history_controller.h" #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_view_impl.h" #include "third_party/WebKit/public/web/WebFrame.h" using blink::WebFrame; using blink::WebHistoryCommitType; using blink::WebHistoryItem; using blink::WebURLRequest; namespace content { HistoryController::HistoryController(RenderViewImpl* render_view) : render_view_(render_view) { } HistoryController::~HistoryController() { } void HistoryController::GoToEntry(scoped_ptr target_entry, WebURLRequest::CachePolicy cache_policy) { HistoryFrameLoadVector same_document_loads; HistoryFrameLoadVector different_document_loads; provisional_entry_ = target_entry.Pass(); WebFrame* main_frame = render_view_->main_render_frame()->GetWebFrame(); if (current_entry_) { RecursiveGoToEntry( main_frame, same_document_loads, different_document_loads); } if (same_document_loads.empty() && different_document_loads.empty()) { // If we don't have any frames to navigate at this point, either // (1) there is no previous history entry to compare against, or // (2) we were unable to match any frames by name. In the first case, // doing a different document navigation to the root item is the only valid // thing to do. In the second case, we should have been able to find a // frame to navigate based on names if this were a same document // navigation, so we can safely assume this is the different document case. different_document_loads.push_back( std::make_pair(main_frame, provisional_entry_->root())); } for (size_t i = 0; i < same_document_loads.size(); ++i) { WebFrame* frame = same_document_loads[i].first; if (!RenderFrameImpl::FromWebFrame(frame)) continue; frame->loadHistoryItem(same_document_loads[i].second, blink::WebHistorySameDocumentLoad, cache_policy); } for (size_t i = 0; i < different_document_loads.size(); ++i) { WebFrame* frame = different_document_loads[i].first; if (!RenderFrameImpl::FromWebFrame(frame)) continue; frame->loadHistoryItem(different_document_loads[i].second, blink::WebHistoryDifferentDocumentLoad, cache_policy); } } void HistoryController::RecursiveGoToEntry( WebFrame* frame, HistoryFrameLoadVector& same_document_loads, HistoryFrameLoadVector& different_document_loads) { DCHECK(provisional_entry_); DCHECK(current_entry_); RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame); const WebHistoryItem& new_item = provisional_entry_->GetItemForFrame(render_frame); const WebHistoryItem& old_item = current_entry_->GetItemForFrame(render_frame); if (new_item.isNull()) return; if (old_item.isNull() || new_item.itemSequenceNumber() != old_item.itemSequenceNumber()) { if (!old_item.isNull() && new_item.documentSequenceNumber() == old_item.documentSequenceNumber()) same_document_loads.push_back(std::make_pair(frame, new_item)); else different_document_loads.push_back(std::make_pair(frame, new_item)); return; } for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling()) { RecursiveGoToEntry(child, same_document_loads, different_document_loads); } } void HistoryController::UpdateForInitialLoadInChildFrame( RenderFrameImpl* frame, const WebHistoryItem& item) { DCHECK_NE(frame->GetWebFrame()->top(), frame->GetWebFrame()); if (!current_entry_) return; if (HistoryEntry::HistoryNode* existing_node = current_entry_->GetHistoryNodeForFrame(frame)) { existing_node->set_item(item); return; } RenderFrameImpl* parent = RenderFrameImpl::FromWebFrame(frame->GetWebFrame()->parent()); if (HistoryEntry::HistoryNode* parent_history_node = current_entry_->GetHistoryNodeForFrame(parent)) { parent_history_node->AddChild(item, frame->GetRoutingID()); } } void HistoryController::UpdateForCommit(RenderFrameImpl* frame, const WebHistoryItem& item, WebHistoryCommitType commit_type, bool navigation_within_page) { if (commit_type == blink::WebBackForwardCommit) { if (!provisional_entry_) return; current_entry_.reset(provisional_entry_.release()); } else if (commit_type == blink::WebStandardCommit) { CreateNewBackForwardItem(frame, item, navigation_within_page); } else if (commit_type == blink::WebInitialCommitInChildFrame) { UpdateForInitialLoadInChildFrame(frame, item); } } HistoryEntry* HistoryController::GetCurrentEntry() { return current_entry_.get(); } WebHistoryItem HistoryController::GetItemForNewChildFrame( RenderFrameImpl* frame) const { if (!current_entry_) return WebHistoryItem(); return current_entry_->GetItemForFrame(frame); } void HistoryController::RemoveChildrenForRedirect(RenderFrameImpl* frame) { if (!provisional_entry_) return; if (HistoryEntry::HistoryNode* node = provisional_entry_->GetHistoryNodeForFrame(frame)) node->RemoveChildren(); } void HistoryController::CreateNewBackForwardItem( RenderFrameImpl* target_frame, const WebHistoryItem& new_item, bool clone_children_of_target) { if (!current_entry_) { current_entry_.reset( new HistoryEntry(new_item, target_frame->GetRoutingID())); } else { current_entry_.reset(current_entry_->CloneAndReplace( new_item, clone_children_of_target, target_frame, render_view_)); } } } // namespace content