Add ICU message format support
[chromium-blink-merge.git] / content / renderer / history_controller.cc
blob225f71748afa19537689e5e294e28b70faec1c78
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/WebFrameLoadType.h"
42 #include "third_party/WebKit/public/web/WebLocalFrame.h"
44 using blink::WebFrame;
45 using blink::WebHistoryCommitType;
46 using blink::WebHistoryItem;
47 using blink::WebURLRequest;
49 namespace content {
51 HistoryController::HistoryController(RenderViewImpl* render_view)
52 : render_view_(render_view) {
55 HistoryController::~HistoryController() {
58 void HistoryController::GoToEntry(
59 blink::WebLocalFrame* main_frame,
60 scoped_ptr<HistoryEntry> target_entry,
61 scoped_ptr<NavigationParams> navigation_params,
62 WebURLRequest::CachePolicy cache_policy) {
63 DCHECK(!main_frame->parent());
64 HistoryFrameLoadVector same_document_loads;
65 HistoryFrameLoadVector different_document_loads;
67 set_provisional_entry(target_entry.Pass());
68 navigation_params_ = navigation_params.Pass();
70 if (current_entry_) {
71 RecursiveGoToEntry(
72 main_frame, same_document_loads, different_document_loads);
75 if (same_document_loads.empty() && different_document_loads.empty()) {
76 // If we don't have any frames to navigate at this point, either
77 // (1) there is no previous history entry to compare against, or
78 // (2) we were unable to match any frames by name. In the first case,
79 // doing a different document navigation to the root item is the only valid
80 // thing to do. In the second case, we should have been able to find a
81 // frame to navigate based on names if this were a same document
82 // navigation, so we can safely assume this is the different document case.
83 different_document_loads.push_back(
84 std::make_pair(main_frame, provisional_entry_->root()));
87 for (const auto& item : same_document_loads) {
88 WebFrame* frame = item.first;
89 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
90 if (!render_frame)
91 continue;
92 render_frame->SetPendingNavigationParams(make_scoped_ptr(
93 new NavigationParams(*navigation_params_.get())));
94 WebURLRequest request = frame->toWebLocalFrame()->requestFromHistoryItem(
95 item.second, cache_policy);
96 frame->toWebLocalFrame()->load(
97 request, blink::WebFrameLoadType::BackForward, item.second,
98 blink::WebHistorySameDocumentLoad);
100 for (const auto& item : different_document_loads) {
101 WebFrame* frame = item.first;
102 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
103 if (!render_frame)
104 continue;
105 render_frame->SetPendingNavigationParams(make_scoped_ptr(
106 new NavigationParams(*navigation_params_.get())));
107 WebURLRequest request = frame->toWebLocalFrame()->requestFromHistoryItem(
108 item.second, cache_policy);
109 frame->toWebLocalFrame()->load(
110 request, blink::WebFrameLoadType::BackForward, item.second,
111 blink::WebHistoryDifferentDocumentLoad);
115 void HistoryController::RecursiveGoToEntry(
116 WebFrame* frame,
117 HistoryFrameLoadVector& same_document_loads,
118 HistoryFrameLoadVector& different_document_loads) {
119 DCHECK(provisional_entry_);
120 DCHECK(current_entry_);
121 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
122 const WebHistoryItem& new_item =
123 provisional_entry_->GetItemForFrame(render_frame);
124 const WebHistoryItem& old_item =
125 current_entry_->GetItemForFrame(render_frame);
126 if (new_item.isNull())
127 return;
129 if (old_item.isNull() ||
130 new_item.itemSequenceNumber() != old_item.itemSequenceNumber()) {
131 if (!old_item.isNull() &&
132 new_item.documentSequenceNumber() == old_item.documentSequenceNumber())
133 same_document_loads.push_back(std::make_pair(frame, new_item));
134 else
135 different_document_loads.push_back(std::make_pair(frame, new_item));
136 return;
139 for (WebFrame* child = frame->firstChild(); child;
140 child = child->nextSibling()) {
141 RecursiveGoToEntry(child, same_document_loads, different_document_loads);
145 void HistoryController::UpdateForInitialLoadInChildFrame(
146 RenderFrameImpl* frame,
147 const WebHistoryItem& item) {
148 DCHECK_NE(frame->GetWebFrame()->top(), frame->GetWebFrame());
149 if (!current_entry_)
150 return;
151 if (HistoryEntry::HistoryNode* existing_node =
152 current_entry_->GetHistoryNodeForFrame(frame)) {
153 existing_node->set_item(item);
154 return;
156 RenderFrameImpl* parent =
157 RenderFrameImpl::FromWebFrame(frame->GetWebFrame()->parent());
158 if (!parent)
159 return;
160 if (HistoryEntry::HistoryNode* parent_history_node =
161 current_entry_->GetHistoryNodeForFrame(parent)) {
162 parent_history_node->AddChild(item);
166 void HistoryController::UpdateForCommit(RenderFrameImpl* frame,
167 const WebHistoryItem& item,
168 WebHistoryCommitType commit_type,
169 bool navigation_within_page) {
170 switch (commit_type) {
171 case blink::WebBackForwardCommit:
172 if (!provisional_entry_)
173 return;
174 current_entry_.reset(provisional_entry_.release());
175 if (HistoryEntry::HistoryNode* node =
176 current_entry_->GetHistoryNodeForFrame(frame)) {
177 node->set_item(item);
179 break;
180 case blink::WebStandardCommit:
181 CreateNewBackForwardItem(frame, item, navigation_within_page);
182 break;
183 case blink::WebInitialCommitInChildFrame:
184 UpdateForInitialLoadInChildFrame(frame, item);
185 break;
186 case blink::WebHistoryInertCommit:
187 // Even for inert commits (e.g., location.replace, client redirects), make
188 // sure the current entry gets updated, if there is one.
189 if (current_entry_) {
190 if (HistoryEntry::HistoryNode* node =
191 current_entry_->GetHistoryNodeForFrame(frame)) {
192 // Inert commits that reset the page without changing the item (e.g.,
193 // reloads, location.replace) shouldn't keep the old subtree.
194 if (!navigation_within_page)
195 node->RemoveChildren();
196 node->set_item(item);
199 break;
200 default:
201 NOTREACHED() << "Invalid commit type: " << commit_type;
205 HistoryEntry* HistoryController::GetCurrentEntry() {
206 return current_entry_.get();
209 WebHistoryItem HistoryController::GetItemForNewChildFrame(
210 RenderFrameImpl* frame) const {
211 if (navigation_params_.get()) {
212 frame->SetPendingNavigationParams(make_scoped_ptr(
213 new NavigationParams(*navigation_params_.get())));
216 if (!current_entry_)
217 return WebHistoryItem();
218 return current_entry_->GetItemForFrame(frame);
221 void HistoryController::RemoveChildrenForRedirect(RenderFrameImpl* frame) {
222 if (!provisional_entry_)
223 return;
224 if (HistoryEntry::HistoryNode* node =
225 provisional_entry_->GetHistoryNodeForFrame(frame))
226 node->RemoveChildren();
229 void HistoryController::CreateNewBackForwardItem(
230 RenderFrameImpl* target_frame,
231 const WebHistoryItem& new_item,
232 bool clone_children_of_target) {
233 if (!current_entry_) {
234 current_entry_.reset(new HistoryEntry(new_item));
235 } else {
236 current_entry_.reset(current_entry_->CloneAndReplace(
237 new_item, clone_children_of_target, target_frame, render_view_));
241 } // namespace content