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. 4 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/) 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 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. 23 * 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. 34 */ 35 36 #include "content/renderer/history_controller.h" 37 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" 41 42 using blink::WebFrame; 43 using blink::WebHistoryCommitType; 44 using blink::WebHistoryItem; 45 using blink::WebURLRequest; 46 47 namespace content { 48 49 HistoryController::HistoryController(RenderViewImpl* render_view) 50 : render_view_(render_view) { 51 } 52 53 HistoryController::~HistoryController() { 54 } 55 56 void HistoryController::GoToEntry(scoped_ptr<HistoryEntry> target_entry, 57 WebURLRequest::CachePolicy cache_policy) { 58 HistoryFrameLoadVector same_document_loads; 59 HistoryFrameLoadVector different_document_loads; 60 61 provisional_entry_ = target_entry.Pass(); 62 63 WebFrame* main_frame = render_view_->main_render_frame()->GetWebFrame(); 64 if (current_entry_) { 65 RecursiveGoToEntry( 66 main_frame, same_document_loads, different_document_loads); 67 } 68 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 } 80 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)) 84 continue; 85 frame->loadHistoryItem(same_document_loads[i].second, 86 blink::WebHistorySameDocumentLoad, 87 cache_policy); 88 } 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)) 92 continue; 93 frame->loadHistoryItem(different_document_loads[i].second, 94 blink::WebHistoryDifferentDocumentLoad, 95 cache_policy); 96 } 97 } 98 99 void HistoryController::RecursiveGoToEntry( 100 WebFrame* frame, 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()) 111 return; 112 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)); 118 else 119 different_document_loads.push_back(std::make_pair(frame, new_item)); 120 return; 121 } 122 123 for (WebFrame* child = frame->firstChild(); child; 124 child = child->nextSibling()) { 125 RecursiveGoToEntry(child, same_document_loads, different_document_loads); 126 } 127 } 128 129 void HistoryController::UpdateForInitialLoadInChildFrame( 130 RenderFrameImpl* frame, 131 const WebHistoryItem& item) { 132 DCHECK_NE(frame->GetWebFrame()->top(), frame->GetWebFrame()); 133 if (!current_entry_) 134 return; 135 if (HistoryEntry::HistoryNode* existing_node = 136 current_entry_->GetHistoryNodeForFrame(frame)) { 137 existing_node->set_item(item); 138 return; 139 } 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()); 145 } 146 } 147 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_) 154 return; 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); 160 } 161 } 162 163 HistoryEntry* HistoryController::GetCurrentEntry() { 164 return current_entry_.get(); 165 } 166 167 WebHistoryItem HistoryController::GetItemForNewChildFrame( 168 RenderFrameImpl* frame) const { 169 if (!current_entry_) 170 return WebHistoryItem(); 171 return current_entry_->GetItemForFrame(frame); 172 } 173 174 void HistoryController::RemoveChildrenForRedirect(RenderFrameImpl* frame) { 175 if (!provisional_entry_) 176 return; 177 if (HistoryEntry::HistoryNode* node = 178 provisional_entry_->GetHistoryNodeForFrame(frame)) 179 node->RemoveChildren(); 180 } 181 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())); 189 } else { 190 current_entry_.reset(current_entry_->CloneAndReplace( 191 new_item, clone_children_of_target, target_frame, render_view_)); 192 } 193 } 194 195 } // namespace content 196