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/WebFrame.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 HistoryNode
* child_history_node
=
90 entry_
->GetHistoryNodeForFrame(child_render_frame
);
91 if (!child_history_node
)
93 HistoryNode
* new_child_node
=
94 child_history_node
->CloneAndReplace(new_entry
,
96 clone_children_of_target
,
99 new_history_node
->children_
->push_back(new_child_node
);
102 return new_history_node
;
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;
109 entry_
->frames_to_items_
[item
.frameSequenceNumber()] = this;
113 HistoryEntry::HistoryNode::HistoryNode(HistoryEntry
* entry
,
114 const WebHistoryItem
& item
,
116 : entry_(entry
), item_(item
) {
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;
130 entry_
->unique_names_to_items_
[item_
.target().utf8()] = this;
131 children_
.reset(new ScopedVector
<HistoryNode
>);
134 HistoryEntry::HistoryNode::~HistoryNode() {
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();
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();
153 if (it
->second
== children().at(i
))
154 frames_to_remove
.push_back(GetFrameMap()[it
->first
]);
156 for (HistoryEntry::UniqueNamesToItems::iterator it
=
157 entry_
->unique_names_to_items_
.begin();
158 it
!= unique_names_end
;
160 if (it
->second
== children().at(i
))
161 unique_names_to_remove
.push_back(it
->first
);
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
>);
171 HistoryEntry::HistoryEntry() {
172 root_
.reset(new HistoryNode(this, WebHistoryItem(), kInvalidFrameRoutingID
));
175 HistoryEntry::~HistoryEntry() {
178 HistoryEntry::HistoryEntry(const WebHistoryItem
& root
, int64_t frame_id
) {
179 root_
.reset(new HistoryNode(this, root
, frame_id
));
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
,
190 clone_children_of_target
,
192 render_view
->main_render_frame()));
196 HistoryEntry::HistoryNode
* HistoryEntry::GetHistoryNodeForFrame(
197 RenderFrameImpl
* frame
) {
198 if (HistoryNode
* history_node
=
199 frames_to_items_
[GetFrameMap()[frame
->GetRoutingID()]])
201 return unique_names_to_items_
[frame
->GetWebFrame()->uniqueName().utf8()];
204 WebHistoryItem
HistoryEntry::GetItemForFrame(RenderFrameImpl
* frame
) {
205 if (HistoryNode
* history_node
= GetHistoryNodeForFrame(frame
))
206 return history_node
->item();
207 return WebHistoryItem();
210 } // namespace content