[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 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_entry.h" |
| 37 | |
[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 38 | #include "content/renderer/render_frame_impl.h" |
| 39 | #include "content/renderer/render_view_impl.h" |
mlamouri | 862a2ed | 2014-09-10 15:14:54 | [diff] [blame^] | 40 | #include "third_party/WebKit/public/web/WebLocalFrame.h" |
[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 41 | |
| 42 | using blink::WebFrame; |
| 43 | using blink::WebHistoryItem; |
| 44 | |
| 45 | namespace content { |
| 46 | |
[email protected] | 4e86dbc2 | 2014-07-28 20:44:00 | [diff] [blame] | 47 | // Frame routing ids are not safe to serialize, so instead create a mapping |
| 48 | // from routing ids to frame sequence numbers. The sequence numbers can be |
| 49 | // benignly serialized with limited risk of collision in a different process. |
| 50 | // FrameMap is a singleton per-process. |
| 51 | typedef base::hash_map<uint64_t, uint64_t> FrameMap; |
| 52 | static FrameMap& GetFrameMap() { |
| 53 | CR_DEFINE_STATIC_LOCAL(FrameMap, routing_ids_to_internal_frame_ids, ()); |
| 54 | return routing_ids_to_internal_frame_ids; |
| 55 | } |
| 56 | |
[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 57 | HistoryEntry::HistoryNode* HistoryEntry::HistoryNode::AddChild( |
| 58 | const WebHistoryItem& item, |
| 59 | int64_t frame_id) { |
| 60 | children_->push_back(new HistoryNode(entry_, item, frame_id)); |
| 61 | return children_->back(); |
| 62 | } |
| 63 | |
[email protected] | 9cd14ef | 2014-04-30 18:26:03 | [diff] [blame] | 64 | HistoryEntry::HistoryNode* HistoryEntry::HistoryNode::AddChild() { |
| 65 | return AddChild(WebHistoryItem(), kInvalidFrameRoutingID); |
| 66 | } |
| 67 | |
[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 68 | HistoryEntry::HistoryNode* HistoryEntry::HistoryNode::CloneAndReplace( |
| 69 | HistoryEntry* new_entry, |
| 70 | const WebHistoryItem& new_item, |
| 71 | bool clone_children_of_target, |
| 72 | RenderFrameImpl* target_frame, |
| 73 | RenderFrameImpl* current_frame) { |
| 74 | bool is_target_frame = target_frame == current_frame; |
| 75 | const WebHistoryItem& item_for_create = is_target_frame ? new_item : item_; |
| 76 | HistoryNode* new_history_node = new HistoryNode( |
| 77 | new_entry, item_for_create, current_frame->GetRoutingID()); |
| 78 | |
| 79 | if (is_target_frame && clone_children_of_target && !item_.isNull()) { |
| 80 | new_history_node->item().setDocumentSequenceNumber( |
| 81 | item_.documentSequenceNumber()); |
| 82 | } |
| 83 | |
| 84 | if (clone_children_of_target || !is_target_frame) { |
| 85 | for (WebFrame* child = current_frame->GetWebFrame()->firstChild(); child; |
| 86 | child = child->nextSibling()) { |
| 87 | RenderFrameImpl* child_render_frame = |
| 88 | RenderFrameImpl::FromWebFrame(child); |
| 89 | HistoryNode* child_history_node = |
| 90 | entry_->GetHistoryNodeForFrame(child_render_frame); |
| 91 | if (!child_history_node) |
| 92 | continue; |
| 93 | HistoryNode* new_child_node = |
| 94 | child_history_node->CloneAndReplace(new_entry, |
| 95 | new_item, |
| 96 | clone_children_of_target, |
| 97 | target_frame, |
| 98 | child_render_frame); |
| 99 | new_history_node->children_->push_back(new_child_node); |
| 100 | } |
| 101 | } |
| 102 | return new_history_node; |
| 103 | } |
| 104 | |
[email protected] | 9cd14ef | 2014-04-30 18:26:03 | [diff] [blame] | 105 | void HistoryEntry::HistoryNode::set_item(const WebHistoryItem& item) { |
| 106 | // The previous HistoryItem might not have had a target set, or it might be |
| 107 | // different than the current one. |
| 108 | entry_->unique_names_to_items_[item.target().utf8()] = this; |
[email protected] | 4e86dbc2 | 2014-07-28 20:44:00 | [diff] [blame] | 109 | entry_->frames_to_items_[item.frameSequenceNumber()] = this; |
[email protected] | 9cd14ef | 2014-04-30 18:26:03 | [diff] [blame] | 110 | item_ = item; |
| 111 | } |
| 112 | |
[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 113 | HistoryEntry::HistoryNode::HistoryNode(HistoryEntry* entry, |
| 114 | const WebHistoryItem& item, |
| 115 | int64_t frame_id) |
| 116 | : entry_(entry), item_(item) { |
[email protected] | 4e86dbc2 | 2014-07-28 20:44:00 | [diff] [blame] | 117 | if (frame_id != kInvalidFrameRoutingID) { |
| 118 | // Each history item is given a frame sequence number on creation. |
| 119 | // If we've already mapped this frame id to a sequence number, standardize |
| 120 | // this item to that sequence number. Otherwise, map the frame id to this |
| 121 | // item's existing sequence number. |
| 122 | if (GetFrameMap()[frame_id] == 0) |
| 123 | GetFrameMap()[frame_id] = item_.frameSequenceNumber(); |
| 124 | else if (!item_.isNull()) |
| 125 | item_.setFrameSequenceNumber(GetFrameMap()[frame_id]); |
| 126 | entry_->frames_to_items_[GetFrameMap()[frame_id]] = this; |
| 127 | } |
| 128 | |
| 129 | if (!item_.isNull()) |
| 130 | entry_->unique_names_to_items_[item_.target().utf8()] = this; |
[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 131 | children_.reset(new ScopedVector<HistoryNode>); |
| 132 | } |
| 133 | |
| 134 | HistoryEntry::HistoryNode::~HistoryNode() { |
| 135 | } |
| 136 | |
| 137 | void HistoryEntry::HistoryNode::RemoveChildren() { |
| 138 | // TODO(japhet): This is inefficient. Figure out a cleaner way to ensure |
| 139 | // this HistoryNode isn't cached anywhere. |
| 140 | std::vector<uint64_t> frames_to_remove; |
| 141 | std::vector<std::string> unique_names_to_remove; |
| 142 | for (size_t i = 0; i < children().size(); i++) { |
| 143 | children().at(i)->RemoveChildren(); |
| 144 | |
| 145 | HistoryEntry::FramesToItems::iterator frames_end = |
| 146 | entry_->frames_to_items_.end(); |
| 147 | HistoryEntry::UniqueNamesToItems::iterator unique_names_end = |
| 148 | entry_->unique_names_to_items_.end(); |
| 149 | for (HistoryEntry::FramesToItems::iterator it = |
| 150 | entry_->frames_to_items_.begin(); |
| 151 | it != frames_end; |
| 152 | ++it) { |
| 153 | if (it->second == children().at(i)) |
[email protected] | 4e86dbc2 | 2014-07-28 20:44:00 | [diff] [blame] | 154 | frames_to_remove.push_back(GetFrameMap()[it->first]); |
[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 155 | } |
| 156 | for (HistoryEntry::UniqueNamesToItems::iterator it = |
| 157 | entry_->unique_names_to_items_.begin(); |
| 158 | it != unique_names_end; |
| 159 | ++it) { |
| 160 | if (it->second == children().at(i)) |
| 161 | unique_names_to_remove.push_back(it->first); |
| 162 | } |
| 163 | } |
| 164 | for (unsigned i = 0; i < frames_to_remove.size(); i++) |
| 165 | entry_->frames_to_items_.erase(frames_to_remove[i]); |
| 166 | for (unsigned i = 0; i < unique_names_to_remove.size(); i++) |
| 167 | entry_->unique_names_to_items_.erase(unique_names_to_remove[i]); |
| 168 | children_.reset(new ScopedVector<HistoryNode>); |
| 169 | } |
| 170 | |
| 171 | HistoryEntry::HistoryEntry() { |
[email protected] | 9cd14ef | 2014-04-30 18:26:03 | [diff] [blame] | 172 | root_.reset(new HistoryNode(this, WebHistoryItem(), kInvalidFrameRoutingID)); |
[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 173 | } |
| 174 | |
| 175 | HistoryEntry::~HistoryEntry() { |
| 176 | } |
| 177 | |
| 178 | HistoryEntry::HistoryEntry(const WebHistoryItem& root, int64_t frame_id) { |
| 179 | root_.reset(new HistoryNode(this, root, frame_id)); |
| 180 | } |
| 181 | |
| 182 | HistoryEntry* HistoryEntry::CloneAndReplace(const WebHistoryItem& new_item, |
| 183 | bool clone_children_of_target, |
| 184 | RenderFrameImpl* target_frame, |
| 185 | RenderViewImpl* render_view) { |
| 186 | HistoryEntry* new_entry = new HistoryEntry(); |
| 187 | new_entry->root_.reset( |
| 188 | root_->CloneAndReplace(new_entry, |
| 189 | new_item, |
| 190 | clone_children_of_target, |
| 191 | target_frame, |
| 192 | render_view->main_render_frame())); |
| 193 | return new_entry; |
| 194 | } |
| 195 | |
| 196 | HistoryEntry::HistoryNode* HistoryEntry::GetHistoryNodeForFrame( |
| 197 | RenderFrameImpl* frame) { |
[email protected] | 4e86dbc2 | 2014-07-28 20:44:00 | [diff] [blame] | 198 | if (HistoryNode* history_node = |
| 199 | frames_to_items_[GetFrameMap()[frame->GetRoutingID()]]) |
[email protected] | 021b67d | 2014-04-22 00:57:27 | [diff] [blame] | 200 | return history_node; |
| 201 | return unique_names_to_items_[frame->GetWebFrame()->uniqueName().utf8()]; |
| 202 | } |
| 203 | |
| 204 | WebHistoryItem HistoryEntry::GetItemForFrame(RenderFrameImpl* frame) { |
| 205 | if (HistoryNode* history_node = GetHistoryNodeForFrame(frame)) |
| 206 | return history_node->item(); |
| 207 | return WebHistoryItem(); |
| 208 | } |
| 209 | |
| 210 | } // namespace content |