Fix a couple bugs in the settings_page_header wrt breadcrumbs.
[chromium-blink-merge.git] / content / renderer / history_controller.cc
blob5f53009158b24e4d5a4e14ca3b8a41525c8cae7d
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /*
6 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
9 * (http://www.torchmobile.com/)
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
21 * its contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
25 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
28 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include "content/renderer/history_controller.h"
38 #include "content/common/navigation_params.h"
39 #include "content/renderer/render_frame_impl.h"
40 #include "content/renderer/render_view_impl.h"
41 #include "third_party/WebKit/public/web/WebLocalFrame.h"
43 using blink::WebFrame;
44 using blink::WebHistoryCommitType;
45 using blink::WebHistoryItem;
46 using blink::WebURLRequest;
48 namespace content {
50 HistoryController::HistoryController(RenderViewImpl* render_view)
51 : render_view_(render_view) {
54 HistoryController::~HistoryController() {
57 void HistoryController::GoToEntry(
58 scoped_ptr<HistoryEntry> target_entry,
59 scoped_ptr<NavigationParams> navigation_params,
60 WebURLRequest::CachePolicy cache_policy) {
61 HistoryFrameLoadVector same_document_loads;
62 HistoryFrameLoadVector different_document_loads;
64 provisional_entry_ = target_entry.Pass();
65 navigation_params_ = navigation_params.Pass();
67 WebFrame* main_frame = render_view_->GetMainRenderFrame()->GetWebFrame();
68 if (current_entry_) {
69 RecursiveGoToEntry(
70 main_frame, same_document_loads, different_document_loads);
73 if (same_document_loads.empty() && different_document_loads.empty()) {
74 // If we don't have any frames to navigate at this point, either
75 // (1) there is no previous history entry to compare against, or
76 // (2) we were unable to match any frames by name. In the first case,
77 // doing a different document navigation to the root item is the only valid
78 // thing to do. In the second case, we should have been able to find a
79 // frame to navigate based on names if this were a same document
80 // navigation, so we can safely assume this is the different document case.
81 different_document_loads.push_back(
82 std::make_pair(main_frame, provisional_entry_->root()));
85 for (const auto& item : same_document_loads) {
86 WebFrame* frame = item.first;
87 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
88 if (!render_frame)
89 continue;
90 render_frame->SetPendingNavigationParams(make_scoped_ptr(
91 new NavigationParams(*navigation_params_.get())));
92 frame->loadHistoryItem(item.second,
93 blink::WebHistorySameDocumentLoad,
94 cache_policy);
96 for (const auto& item : different_document_loads) {
97 WebFrame* frame = item.first;
98 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
99 if (!render_frame)
100 continue;
101 render_frame->SetPendingNavigationParams(make_scoped_ptr(
102 new NavigationParams(*navigation_params_.get())));
103 frame->loadHistoryItem(item.second,
104 blink::WebHistoryDifferentDocumentLoad,
105 cache_policy);
109 void HistoryController::RecursiveGoToEntry(
110 WebFrame* frame,
111 HistoryFrameLoadVector& same_document_loads,
112 HistoryFrameLoadVector& different_document_loads) {
113 DCHECK(provisional_entry_);
114 DCHECK(current_entry_);
115 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
116 const WebHistoryItem& new_item =
117 provisional_entry_->GetItemForFrame(render_frame);
118 const WebHistoryItem& old_item =
119 current_entry_->GetItemForFrame(render_frame);
120 if (new_item.isNull())
121 return;
123 if (old_item.isNull() ||
124 new_item.itemSequenceNumber() != old_item.itemSequenceNumber()) {
125 if (!old_item.isNull() &&
126 new_item.documentSequenceNumber() == old_item.documentSequenceNumber())
127 same_document_loads.push_back(std::make_pair(frame, new_item));
128 else
129 different_document_loads.push_back(std::make_pair(frame, new_item));
130 return;
133 for (WebFrame* child = frame->firstChild(); child;
134 child = child->nextSibling()) {
135 RecursiveGoToEntry(child, same_document_loads, different_document_loads);
139 void HistoryController::UpdateForInitialLoadInChildFrame(
140 RenderFrameImpl* frame,
141 const WebHistoryItem& item) {
142 DCHECK_NE(frame->GetWebFrame()->top(), frame->GetWebFrame());
143 if (!current_entry_)
144 return;
145 if (HistoryEntry::HistoryNode* existing_node =
146 current_entry_->GetHistoryNodeForFrame(frame)) {
147 existing_node->set_item(item);
148 return;
150 RenderFrameImpl* parent =
151 RenderFrameImpl::FromWebFrame(frame->GetWebFrame()->parent());
152 if (!parent)
153 return;
154 if (HistoryEntry::HistoryNode* parent_history_node =
155 current_entry_->GetHistoryNodeForFrame(parent)) {
156 parent_history_node->AddChild(item);
160 void HistoryController::UpdateForCommit(RenderFrameImpl* frame,
161 const WebHistoryItem& item,
162 WebHistoryCommitType commit_type,
163 bool navigation_within_page) {
164 switch (commit_type) {
165 case blink::WebBackForwardCommit:
166 if (!provisional_entry_)
167 return;
168 current_entry_.reset(provisional_entry_.release());
169 break;
170 case blink::WebStandardCommit:
171 CreateNewBackForwardItem(frame, item, navigation_within_page);
172 break;
173 case blink::WebInitialCommitInChildFrame:
174 UpdateForInitialLoadInChildFrame(frame, item);
175 break;
176 case blink::WebHistoryInertCommit:
177 // Even for inert commits (e.g., location.replace, client redirects), make
178 // sure the current entry gets updated, if there is one.
179 if (current_entry_) {
180 if (HistoryEntry::HistoryNode* node =
181 current_entry_->GetHistoryNodeForFrame(frame)) {
182 node->set_item(item);
185 break;
186 default:
187 NOTREACHED() << "Invalid commit type: " << commit_type;
191 HistoryEntry* HistoryController::GetCurrentEntry() {
192 return current_entry_.get();
195 WebHistoryItem HistoryController::GetItemForNewChildFrame(
196 RenderFrameImpl* frame) const {
197 if (navigation_params_.get()) {
198 frame->SetPendingNavigationParams(make_scoped_ptr(
199 new NavigationParams(*navigation_params_.get())));
202 if (!current_entry_)
203 return WebHistoryItem();
204 return current_entry_->GetItemForFrame(frame);
207 void HistoryController::RemoveChildrenForRedirect(RenderFrameImpl* frame) {
208 if (!provisional_entry_)
209 return;
210 if (HistoryEntry::HistoryNode* node =
211 provisional_entry_->GetHistoryNodeForFrame(frame))
212 node->RemoveChildren();
215 void HistoryController::CreateNewBackForwardItem(
216 RenderFrameImpl* target_frame,
217 const WebHistoryItem& new_item,
218 bool clone_children_of_target) {
219 if (!current_entry_) {
220 current_entry_.reset(new HistoryEntry(new_item));
221 } else {
222 current_entry_.reset(current_entry_->CloneAndReplace(
223 new_item, clone_children_of_target, target_frame, render_view_));
227 } // namespace content