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/WebLocalFrame.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_
->GetMainRenderFrame()->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()));
81 for (size_t i
= 0; i
< same_document_loads
.size(); ++i
) {
82 WebFrame
* frame
= same_document_loads
[i
].first
;
83 if (!RenderFrameImpl::FromWebFrame(frame
))
85 frame
->loadHistoryItem(same_document_loads
[i
].second
,
86 blink::WebHistorySameDocumentLoad
,
89 for (size_t i
= 0; i
< different_document_loads
.size(); ++i
) {
90 WebFrame
* frame
= different_document_loads
[i
].first
;
91 if (!RenderFrameImpl::FromWebFrame(frame
))
93 frame
->loadHistoryItem(different_document_loads
[i
].second
,
94 blink::WebHistoryDifferentDocumentLoad
,
99 void HistoryController::RecursiveGoToEntry(
101 HistoryFrameLoadVector
& same_document_loads
,
102 HistoryFrameLoadVector
& different_document_loads
) {
103 DCHECK(provisional_entry_
);
104 DCHECK(current_entry_
);
105 RenderFrameImpl
* render_frame
= RenderFrameImpl::FromWebFrame(frame
);
106 const WebHistoryItem
& new_item
=
107 provisional_entry_
->GetItemForFrame(render_frame
);
108 const WebHistoryItem
& old_item
=
109 current_entry_
->GetItemForFrame(render_frame
);
110 if (new_item
.isNull())
113 if (old_item
.isNull() ||
114 new_item
.itemSequenceNumber() != old_item
.itemSequenceNumber()) {
115 if (!old_item
.isNull() &&
116 new_item
.documentSequenceNumber() == old_item
.documentSequenceNumber())
117 same_document_loads
.push_back(std::make_pair(frame
, new_item
));
119 different_document_loads
.push_back(std::make_pair(frame
, new_item
));
123 for (WebFrame
* child
= frame
->firstChild(); child
;
124 child
= child
->nextSibling()) {
125 RecursiveGoToEntry(child
, same_document_loads
, different_document_loads
);
129 void HistoryController::UpdateForInitialLoadInChildFrame(
130 RenderFrameImpl
* frame
,
131 const WebHistoryItem
& item
) {
132 DCHECK_NE(frame
->GetWebFrame()->top(), frame
->GetWebFrame());
135 if (HistoryEntry::HistoryNode
* existing_node
=
136 current_entry_
->GetHistoryNodeForFrame(frame
)) {
137 existing_node
->set_item(item
);
140 RenderFrameImpl
* parent
=
141 RenderFrameImpl::FromWebFrame(frame
->GetWebFrame()->parent());
142 if (HistoryEntry::HistoryNode
* parent_history_node
=
143 current_entry_
->GetHistoryNodeForFrame(parent
)) {
144 parent_history_node
->AddChild(item
, frame
->GetRoutingID());
148 void HistoryController::UpdateForCommit(RenderFrameImpl
* frame
,
149 const WebHistoryItem
& item
,
150 WebHistoryCommitType commit_type
,
151 bool navigation_within_page
) {
152 if (commit_type
== blink::WebBackForwardCommit
) {
153 if (!provisional_entry_
)
155 current_entry_
.reset(provisional_entry_
.release());
156 } else if (commit_type
== blink::WebStandardCommit
) {
157 CreateNewBackForwardItem(frame
, item
, navigation_within_page
);
158 } else if (commit_type
== blink::WebInitialCommitInChildFrame
) {
159 UpdateForInitialLoadInChildFrame(frame
, item
);
163 HistoryEntry
* HistoryController::GetCurrentEntry() {
164 return current_entry_
.get();
167 WebHistoryItem
HistoryController::GetItemForNewChildFrame(
168 RenderFrameImpl
* frame
) const {
170 return WebHistoryItem();
171 return current_entry_
->GetItemForFrame(frame
);
174 void HistoryController::RemoveChildrenForRedirect(RenderFrameImpl
* frame
) {
175 if (!provisional_entry_
)
177 if (HistoryEntry::HistoryNode
* node
=
178 provisional_entry_
->GetHistoryNodeForFrame(frame
))
179 node
->RemoveChildren();
182 void HistoryController::CreateNewBackForwardItem(
183 RenderFrameImpl
* target_frame
,
184 const WebHistoryItem
& new_item
,
185 bool clone_children_of_target
) {
186 if (!current_entry_
) {
187 current_entry_
.reset(
188 new HistoryEntry(new_item
, target_frame
->GetRoutingID()));
190 current_entry_
.reset(current_entry_
->CloneAndReplace(
191 new_item
, clone_children_of_target
, target_frame
, render_view_
));
195 } // namespace content