OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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 #include "chrome/browser/prerender/prerender_link_manager.h" | |
6 | |
7 #include <limits> | |
8 #include <queue> | |
9 #include <utility> | |
10 | |
11 #include "chrome/browser/prerender/prerender_contents.h" | |
12 #include "chrome/browser/prerender/prerender_manager.h" | |
13 #include "chrome/browser/prerender/prerender_manager_factory.h" | |
14 #include "chrome/browser/profiles/profile.h" | |
15 #include "content/public/common/referrer.h" | |
16 #include "googleurl/src/gurl.h" | |
17 #include "googleurl/src/url_canon.h" | |
18 #include "ui/gfx/size.h" | |
19 | |
20 namespace { | |
21 | |
22 template<typename MapForwards, typename MapBackwards> | |
23 bool MapsAreInverseOfEachOther(const MapForwards& map_forwards, | |
24 const MapBackwards& map_backwards) { | |
25 if (map_forwards.size() != map_backwards.size()) | |
26 return false; | |
27 for (typename MapForwards::const_iterator i = map_forwards.begin(), | |
28 e = map_forwards.end(); | |
29 i != e; ++i) { | |
dominich
2012/04/26 22:50:58
why do you need to declare e in the first part? ie
gavinp
2012/04/27 20:31:32
Pure superstition. The standard guarantees that t
| |
30 // Best to use std::count here both times, as | |
31 // AssociativeContainer::count returns size_t, vs. std::count | |
32 // returning iterator_traits<InputIterator>::difference_type | |
33 typedef typename std::iterator_traits< | |
34 typename MapForwards::iterator>::difference_type diff_type; | |
35 diff_type forwards_count = | |
36 std::count(map_forwards.begin(), map_forwards.end(), | |
37 typename MapForwards::value_type(i->first, i->second)); | |
38 diff_type backwards_count = | |
39 std::count(map_backwards.begin(), map_backwards.end(), | |
40 typename MapBackwards::value_type(i->second, i->first)); | |
41 if (forwards_count != backwards_count) { | |
dominich
2012/04/26 22:50:58
nit: {} not necessary here
gavinp
2012/04/27 20:31:32
Done.
| |
42 return false; | |
43 } | |
44 } | |
45 return true; | |
46 } | |
47 | |
48 } | |
49 | |
50 namespace prerender { | |
51 | |
52 PrerenderLinkManager::PrerenderLinkManager( | |
dominich
2012/04/26 22:50:58
nit: unnecessary to wrap this line
gavinp
2012/04/27 20:31:32
Done.
| |
53 PrerenderManager* manager) | |
54 : manager_(manager) { | |
55 } | |
56 | |
57 PrerenderLinkManager::~PrerenderLinkManager() { | |
58 } | |
59 | |
60 bool PrerenderLinkManager::OnAddPrerender(int child_id, | |
61 int prerender_id, | |
62 const GURL& orig_url, | |
63 const content::Referrer& referrer, | |
64 const gfx::Size& ALLOW_UNUSED size, | |
65 int render_view_route_id) { | |
66 DVLOG(2) << "OnAddPrerender, child_id = " << child_id | |
67 << ", prerender_id = " << prerender_id | |
68 << ", url = " << orig_url.spec(); | |
69 DVLOG(3) << "... render_view_route_id = " << render_view_route_id | |
70 << ", referrer url = " << referrer.url.spec(); | |
71 DCHECK(MapsAreInverseOfEachOther(ids_to_url_map_, urls_to_id_map_)); | |
72 // TODO(gavinp): Add tests to insure fragments work, then remove this fragment | |
73 // clearing code. | |
74 url_canon::Replacements<char> replacements; | |
75 replacements.ClearRef(); | |
76 const GURL url = orig_url.ReplaceComponents(replacements); | |
77 | |
78 // TODO(gavinp,dominich): After the Prerender API can send events back to | |
dominich
2012/04/26 22:50:58
From this code, I don't see why the urls_to_id_map
gavinp
2012/04/27 20:31:32
Two links prerender the same page from the same or
dominich
2012/04/27 21:52:01
So they'd have the same child_id but different pre
gavinp
2012/04/27 23:31:45
Yes. However, notice that OnCancelPrerender has d
| |
79 // their client links, revisit having both maps and all the trouble that | |
80 // causes. | |
81 const bool did_successfully_add = manager_->AddPrerenderFromLinkRelPrerender( | |
82 child_id, render_view_route_id, url, referrer); | |
83 const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); | |
84 DCHECK(ids_to_url_map_.find(child_and_prerender_id) == ids_to_url_map_.end()); | |
85 ids_to_url_map_.insert(std::make_pair(child_and_prerender_id, url)); | |
dominich
2012/04/26 22:50:58
Why insert these if |did_successfully_add| is fals
gavinp
2012/04/27 20:31:32
Done. What I liked about the original approach wa
| |
86 urls_to_id_map_.insert(std::make_pair(url, child_and_prerender_id)); | |
87 DCHECK(MapsAreInverseOfEachOther(ids_to_url_map_, urls_to_id_map_)); | |
88 return did_successfully_add; | |
89 } | |
90 | |
91 void PrerenderLinkManager::OnCancelPrerender(int prerender_id, | |
92 int child_id) { | |
93 DVLOG(2) << "OnCancelPrerender, child_id = " << child_id | |
94 << ", prerender_id = " << prerender_id; | |
95 const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); | |
96 IdPairToUrlMap::iterator id_url_iter = | |
97 ids_to_url_map_.find(child_and_prerender_id); | |
98 if (id_url_iter == ids_to_url_map_.end()) { | |
99 NOTREACHED() << "Canceling a prerender that doesn't exist."; | |
100 return; | |
101 } | |
102 const GURL url = id_url_iter->second; | |
103 RemovePrerender(id_url_iter); | |
104 | |
105 if (urls_to_id_map_.find(url) != urls_to_id_map_.end()) | |
106 return; | |
107 | |
108 // TODO(gavinp): Track down the correct prerender and stop it, rather than | |
109 // this nuclear option, which assumes that only one prerender at a time | |
110 // runs. | |
111 if (PrerenderContents* contents = manager_->GetEntry(url)) | |
112 contents->Destroy(FINAL_STATUS_CANCELLED); | |
113 } | |
114 | |
115 void PrerenderLinkManager::OnAbandonPrerender(int prerender_id, int child_id) { | |
116 DVLOG(2) << "OnAbandonPrerender, child_id = " << child_id | |
117 << ", prerender_id = " << prerender_id; | |
118 // TODO(gavinp,cbentzel): Implement reasonable behaviour for | |
119 // navigation away from launcher. | |
120 const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); | |
121 IdPairToUrlMap::iterator id_url_iter = | |
122 ids_to_url_map_.find(child_and_prerender_id); | |
123 if (id_url_iter == ids_to_url_map_.end()) { | |
124 // FIXME(gavinp): Currently, canceled prerenders also get abandoned later. | |
125 // When the WebKit fix to stop this lands, add a NOTREACHED() here. | |
126 return; | |
127 } | |
128 RemovePrerender(id_url_iter); | |
129 } | |
130 | |
131 void PrerenderLinkManager::OnChannelClosing(int child_id) { | |
132 DVLOG(2) << "OnChannelClosing, child id = " << child_id; | |
133 const ChildAndPrerenderIdPair child_and_minimum_prerender_id( | |
134 child_id, std::numeric_limits<int>::min()); | |
135 const ChildAndPrerenderIdPair child_and_maximum_prerender_id( | |
136 child_id, std::numeric_limits<int>::max()); | |
137 std::queue<int> prerender_ids_to_abandon; | |
138 for (IdPairToUrlMap::iterator | |
139 i = ids_to_url_map_.lower_bound(child_and_minimum_prerender_id), | |
140 e = ids_to_url_map_.upper_bound(child_and_maximum_prerender_id); | |
141 i != e; ++i) { | |
142 prerender_ids_to_abandon.push(i->first.second); | |
143 } | |
144 while (!prerender_ids_to_abandon.empty()) { | |
145 DVLOG(4) << "---> abandon prerender_id = " | |
146 << prerender_ids_to_abandon.front(); | |
147 OnAbandonPrerender(prerender_ids_to_abandon.front(), child_id); | |
148 prerender_ids_to_abandon.pop(); | |
149 } | |
150 } | |
151 | |
152 void PrerenderLinkManager::RemovePrerender( | |
153 const IdPairToUrlMap::iterator& id_url_iter) { | |
154 DCHECK(MapsAreInverseOfEachOther(ids_to_url_map_, urls_to_id_map_)); | |
155 const GURL url = id_url_iter->second; | |
156 const ChildAndPrerenderIdPair child_and_prerender_id = id_url_iter->first; | |
157 ids_to_url_map_.erase(id_url_iter); | |
158 | |
159 for (UrlToIdPairMap::iterator i = urls_to_id_map_.lower_bound(url), | |
160 e = urls_to_id_map_.upper_bound(url); | |
gavinp
2012/04/27 20:31:32
I'm leaving this one here, multimap::upper_bound()
| |
161 i != e; ++i) { | |
162 if (i->second == child_and_prerender_id) { | |
163 urls_to_id_map_.erase(i); | |
164 DCHECK(MapsAreInverseOfEachOther(ids_to_url_map_, urls_to_id_map_)); | |
165 return; | |
166 } | |
167 } | |
168 NOTREACHED(); | |
169 } | |
170 | |
171 bool PrerenderLinkManager::IsEmpty() const { | |
172 return ids_to_url_map_.empty(); | |
173 } | |
174 | |
175 } // namespace prerender | |
176 | |
OLD | NEW |