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.
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
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/renderer/render_frame_impl.h"
39 #include "content/renderer/render_view_impl.h"
40 #include "third_party/WebKit/public/web/WebFrame.h"
42 using blink::WebFrame
;
43 using blink::WebHistoryCommitType
;
44 using blink::WebHistoryItem
;
45 using blink::WebURLRequest
;
49 HistoryController::HistoryController(RenderViewImpl
* render_view
)
50 : render_view_(render_view
) {
53 HistoryController::~HistoryController() {
56 void HistoryController::GoToEntry(scoped_ptr
<HistoryEntry
> target_entry
,
57 WebURLRequest::CachePolicy cache_policy
) {
58 HistoryFrameLoadVector same_document_loads
;
59 HistoryFrameLoadVector different_document_loads
;
61 provisional_entry_
= target_entry
.Pass();
63 WebFrame
* main_frame
= render_view_
->main_render_frame()->GetWebFrame();
66 main_frame
, same_document_loads
, different_document_loads
);
69 if (same_document_loads
.empty() && different_document_loads
.empty()) {
70 // If we don't have any frames to navigate at this point, either
71 // (1) there is no previous history entry to compare against, or
72 // (2) we were unable to match any frames by name. In the first case,
73 // doing a different document navigation to the root item is the only valid
74 // thing to do. In the second case, we should have been able to find a
75 // frame to navigate based on names if this were a same document
76 // navigation, so we can safely assume this is the different document case.
77 different_document_loads
.push_back(
78 std::make_pair(main_frame
, provisional_entry_
->root()));
79 } else if (different_document_loads
.empty()) {
80 // If we have only same document navigations to perform, immediately
81 // declare the load "committed" by updating the current entry.
82 // TODO(japhet): This is a historical quirk, because same-document
83 // history navigations call UpdateForCommit() with commit type
84 // HistoryInertCommit. If that is fixed, we can remove this block.
85 previous_entry_
.reset(current_entry_
.release());
86 current_entry_
.reset(provisional_entry_
.release());
89 for (size_t i
= 0; i
< same_document_loads
.size(); ++i
) {
90 WebFrame
* frame
= same_document_loads
[i
].first
;
91 if (!RenderFrameImpl::FromWebFrame(frame
))
93 frame
->loadHistoryItem(same_document_loads
[i
].second
,
94 blink::WebHistorySameDocumentLoad
,
97 for (size_t i
= 0; i
< different_document_loads
.size(); ++i
) {
98 WebFrame
* frame
= different_document_loads
[i
].first
;
99 if (!RenderFrameImpl::FromWebFrame(frame
))
101 frame
->loadHistoryItem(different_document_loads
[i
].second
,
102 blink::WebHistoryDifferentDocumentLoad
,
107 void HistoryController::RecursiveGoToEntry(
109 HistoryFrameLoadVector
& same_document_loads
,
110 HistoryFrameLoadVector
& different_document_loads
) {
111 DCHECK(provisional_entry_
);
112 DCHECK(current_entry_
);
113 RenderFrameImpl
* render_frame
= RenderFrameImpl::FromWebFrame(frame
);
114 const WebHistoryItem
& new_item
=
115 provisional_entry_
->GetItemForFrame(render_frame
);
116 const WebHistoryItem
& old_item
=
117 current_entry_
->GetItemForFrame(render_frame
);
118 if (new_item
.isNull())
121 if (old_item
.isNull() ||
122 new_item
.itemSequenceNumber() != old_item
.itemSequenceNumber()) {
123 if (!old_item
.isNull() &&
124 new_item
.documentSequenceNumber() == old_item
.documentSequenceNumber())
125 same_document_loads
.push_back(std::make_pair(frame
, new_item
));
127 different_document_loads
.push_back(std::make_pair(frame
, new_item
));
131 for (WebFrame
* child
= frame
->firstChild(); child
;
132 child
= child
->nextSibling()) {
133 RecursiveGoToEntry(child
, same_document_loads
, different_document_loads
);
137 void HistoryController::UpdateForInitialLoadInChildFrame(
138 RenderFrameImpl
* frame
,
139 const WebHistoryItem
& item
) {
140 DCHECK_NE(frame
->GetWebFrame()->top(), frame
->GetWebFrame());
143 if (HistoryEntry::HistoryNode
* existing_node
=
144 current_entry_
->GetHistoryNodeForFrame(frame
)) {
145 existing_node
->set_item(item
);
148 RenderFrameImpl
* parent
=
149 RenderFrameImpl::FromWebFrame(frame
->GetWebFrame()->parent());
150 if (HistoryEntry::HistoryNode
* parent_history_node
=
151 current_entry_
->GetHistoryNodeForFrame(parent
)) {
152 parent_history_node
->AddChild(item
, frame
->GetRoutingID());
156 void HistoryController::UpdateForCommit(RenderFrameImpl
* frame
,
157 const WebHistoryItem
& item
,
158 WebHistoryCommitType commit_type
,
159 bool navigation_within_page
) {
160 if (commit_type
== blink::WebBackForwardCommit
) {
161 if (!provisional_entry_
)
163 previous_entry_
.reset(current_entry_
.release());
164 current_entry_
.reset(provisional_entry_
.release());
165 } else if (commit_type
== blink::WebStandardCommit
) {
166 CreateNewBackForwardItem(frame
, item
, navigation_within_page
);
167 } else if (commit_type
== blink::WebInitialCommitInChildFrame
) {
168 UpdateForInitialLoadInChildFrame(frame
, item
);
172 HistoryEntry
* HistoryController::GetCurrentEntry() {
173 return current_entry_
.get();
176 HistoryEntry
* HistoryController::GetPreviousEntry() {
177 return previous_entry_
.get();
180 WebHistoryItem
HistoryController::GetItemForNewChildFrame(
181 RenderFrameImpl
* frame
) const {
183 return WebHistoryItem();
184 return current_entry_
->GetItemForFrame(frame
);
187 void HistoryController::RemoveChildrenForRedirect(RenderFrameImpl
* frame
) {
188 if (!provisional_entry_
)
190 if (HistoryEntry::HistoryNode
* node
=
191 provisional_entry_
->GetHistoryNodeForFrame(frame
))
192 node
->RemoveChildren();
195 void HistoryController::CreateNewBackForwardItem(
196 RenderFrameImpl
* target_frame
,
197 const WebHistoryItem
& new_item
,
198 bool clone_children_of_target
) {
199 if (!current_entry_
) {
200 current_entry_
.reset(
201 new HistoryEntry(new_item
, target_frame
->GetRoutingID()));
203 previous_entry_
.reset(current_entry_
.release());
204 current_entry_
.reset(previous_entry_
->CloneAndReplace(
205 new_item
, clone_children_of_target
, target_frame
, render_view_
));
209 } // namespace content