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_entry.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::WebHistoryItem
;
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
;
57 HistoryEntry::HistoryNode
* HistoryEntry::HistoryNode::AddChild(
58 const WebHistoryItem
& item
,
60 children_
->push_back(new HistoryNode(entry_
, item
, frame_id
));
61 return children_
->back();
64 HistoryEntry::HistoryNode
* HistoryEntry::HistoryNode::AddChild() {
65 return AddChild(WebHistoryItem(), kInvalidFrameRoutingID
);
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());
79 if (is_target_frame
&& clone_children_of_target
&& !item_
.isNull()) {
80 new_history_node
->item().setDocumentSequenceNumber(
81 item_
.documentSequenceNumber());
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 // TODO(creis): A child frame may be a RenderFrameProxy. We should still
90 // process its children, but that will be possible when we move this code
91 // to the browser process in https://crbug.com/236848.
92 if (!child_render_frame
)
94 HistoryNode
* child_history_node
=
95 entry_
->GetHistoryNodeForFrame(child_render_frame
);
96 if (!child_history_node
)
98 HistoryNode
* new_child_node
=
99 child_history_node
->CloneAndReplace(new_entry
,
101 clone_children_of_target
,
104 new_history_node
->children_
->push_back(new_child_node
);
107 return new_history_node
;
110 void HistoryEntry::HistoryNode::set_item(const WebHistoryItem
& item
) {
111 // The previous HistoryItem might not have had a target set, or it might be
112 // different than the current one.
113 entry_
->unique_names_to_items_
[item
.target().utf8()] = this;
114 entry_
->frames_to_items_
[item
.frameSequenceNumber()] = this;
118 HistoryEntry::HistoryNode::HistoryNode(HistoryEntry
* entry
,
119 const WebHistoryItem
& item
,
121 : entry_(entry
), item_(item
) {
122 if (frame_id
!= kInvalidFrameRoutingID
) {
123 // Each history item is given a frame sequence number on creation.
124 // If we've already mapped this frame id to a sequence number, standardize
125 // this item to that sequence number. Otherwise, map the frame id to this
126 // item's existing sequence number.
127 if (GetFrameMap()[frame_id
] == 0)
128 GetFrameMap()[frame_id
] = item_
.frameSequenceNumber();
129 else if (!item_
.isNull())
130 item_
.setFrameSequenceNumber(GetFrameMap()[frame_id
]);
131 entry_
->frames_to_items_
[GetFrameMap()[frame_id
]] = this;
135 entry_
->unique_names_to_items_
[item_
.target().utf8()] = this;
136 children_
.reset(new ScopedVector
<HistoryNode
>);
139 HistoryEntry::HistoryNode::~HistoryNode() {
142 void HistoryEntry::HistoryNode::RemoveChildren() {
143 // TODO(japhet): This is inefficient. Figure out a cleaner way to ensure
144 // this HistoryNode isn't cached anywhere.
145 std::vector
<uint64_t> frames_to_remove
;
146 std::vector
<std::string
> unique_names_to_remove
;
147 for (size_t i
= 0; i
< children().size(); i
++) {
148 children().at(i
)->RemoveChildren();
150 HistoryEntry::FramesToItems::iterator frames_end
=
151 entry_
->frames_to_items_
.end();
152 HistoryEntry::UniqueNamesToItems::iterator unique_names_end
=
153 entry_
->unique_names_to_items_
.end();
154 for (HistoryEntry::FramesToItems::iterator it
=
155 entry_
->frames_to_items_
.begin();
158 if (it
->second
== children().at(i
))
159 frames_to_remove
.push_back(GetFrameMap()[it
->first
]);
161 for (HistoryEntry::UniqueNamesToItems::iterator it
=
162 entry_
->unique_names_to_items_
.begin();
163 it
!= unique_names_end
;
165 if (it
->second
== children().at(i
))
166 unique_names_to_remove
.push_back(it
->first
);
169 for (unsigned i
= 0; i
< frames_to_remove
.size(); i
++)
170 entry_
->frames_to_items_
.erase(frames_to_remove
[i
]);
171 for (unsigned i
= 0; i
< unique_names_to_remove
.size(); i
++)
172 entry_
->unique_names_to_items_
.erase(unique_names_to_remove
[i
]);
173 children_
.reset(new ScopedVector
<HistoryNode
>);
176 HistoryEntry::HistoryEntry() {
177 root_
.reset(new HistoryNode(this, WebHistoryItem(), kInvalidFrameRoutingID
));
180 HistoryEntry::~HistoryEntry() {
183 HistoryEntry::HistoryEntry(const WebHistoryItem
& root
, int64_t frame_id
) {
184 root_
.reset(new HistoryNode(this, root
, frame_id
));
187 HistoryEntry
* HistoryEntry::CloneAndReplace(const WebHistoryItem
& new_item
,
188 bool clone_children_of_target
,
189 RenderFrameImpl
* target_frame
,
190 RenderViewImpl
* render_view
) {
191 HistoryEntry
* new_entry
= new HistoryEntry();
192 new_entry
->root_
.reset(
193 root_
->CloneAndReplace(new_entry
,
195 clone_children_of_target
,
197 render_view
->GetMainRenderFrame()));
201 HistoryEntry::HistoryNode
* HistoryEntry::GetHistoryNodeForFrame(
202 RenderFrameImpl
* frame
) {
203 if (HistoryNode
* history_node
=
204 frames_to_items_
[GetFrameMap()[frame
->GetRoutingID()]])
206 return unique_names_to_items_
[frame
->GetWebFrame()->uniqueName().utf8()];
209 WebHistoryItem
HistoryEntry::GetItemForFrame(RenderFrameImpl
* frame
) {
210 if (HistoryNode
* history_node
= GetHistoryNodeForFrame(frame
))
211 return history_node
->item();
212 return WebHistoryItem();
215 } // namespace content