 Chromium Code Reviews
 Chromium Code Reviews Issue 9875026:
  **NOTFORLANDING**  New link rel=prerender API  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 9875026:
  **NOTFORLANDING**  New link rel=prerender API  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| Index: chrome/browser/prerender/prerender_link_manager.cc | 
| diff --git a/chrome/browser/prerender/prerender_link_manager.cc b/chrome/browser/prerender/prerender_link_manager.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..1419d1c9d6f257bbc7531e866106fce39bfe37d7 | 
| --- /dev/null | 
| +++ b/chrome/browser/prerender/prerender_link_manager.cc | 
| @@ -0,0 +1,163 @@ | 
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "chrome/browser/prerender/prerender_link_manager.h" | 
| + | 
| +#include <limits> | 
| +#include <queue> | 
| +#include <utility> | 
| + | 
| +#include "chrome/browser/profiles/profile.h" | 
| +#include "chrome/browser/prerender/prerender_contents.h" | 
| +#include "chrome/browser/prerender/prerender_manager.h" | 
| +#include "chrome/browser/prerender/prerender_manager_factory.h" | 
| +#include "content/public/common/referrer.h" | 
| +#include "googleurl/src/gurl.h" | 
| +#include "googleurl/src/url_canon.h" | 
| +#include "ui/gfx/size.h" | 
| + | 
| +namespace { | 
| + | 
| +template<typename MapForwards, typename MapBackwards> | 
| +bool CheckMapsAreInverseOfEachOther(const MapForwards& map_forwards, | 
| 
mmenke
2012/04/24 15:26:15
nit:  Suggest you rename this "MapsAreInverseOfEac
 
cbentzel
2012/04/24 15:42:59
Nit: Perhaps AreMapsInverseOfEachOther? No actual
 
gavinp
2012/04/26 23:55:39
Done.
 | 
| + const MapBackwards& map_backwards) { | 
| + if (map_forwards.size() != map_backwards.size()) | 
| + return false; | 
| + for (typename MapForwards::const_iterator i = map_forwards.begin(), | 
| 
cbentzel
2012/04/24 15:42:59
This doesn't quite test inversion. For example, if
 
gavinp
2012/04/26 23:55:39
Done.
 | 
| + e = map_forwards.end(); | 
| + i != e; ++i) { | 
| + if (map_backwards.find(i->second) == map_backwards.end()) | 
| + return false; | 
| + } | 
| + for (typename MapBackwards::const_iterator i = map_backwards.begin(), | 
| + e = map_backwards.end(); | 
| 
mmenke
2012/04/24 15:26:15
Is this necessary?  Given that the maps have the s
 
gavinp
2012/04/26 23:55:39
No it's not, especially now that I fixed the terri
 | 
| + i != e; ++i) { | 
| + if (map_forwards.find(i->second) == map_forwards.end()) | 
| + return false; | 
| + } | 
| + return true; | 
| +} | 
| + | 
| +} | 
| + | 
| +namespace prerender { | 
| + | 
| +PrerenderLinkManager::PrerenderLinkManager( | 
| + PrerenderManager* manager) | 
| + : manager_(manager) { | 
| +} | 
| + | 
| +PrerenderLinkManager::~PrerenderLinkManager() { | 
| +} | 
| + | 
| +void PrerenderLinkManager::RemovePrerender( | 
| 
cbentzel
2012/04/24 15:42:59
Nit: ordering of class definitions should match de
 
gavinp
2012/04/26 23:55:39
Done.
 | 
| + const PrerenderIdToUrlMap::iterator& id_url_iter) { | 
| + DCHECK(CheckMapsAreInverseOfEachOther(id_map_, url_map_)); | 
| + const GURL url = id_url_iter->second; | 
| + const ChildAndPrerenderIdPair child_and_prerender_id = id_url_iter->first; | 
| + id_map_.erase(id_url_iter); | 
| + | 
| + for (UrlToPrerenderIdMap::iterator i = url_map_.lower_bound(url), | 
| + e = url_map_.upper_bound(url); | 
| + i != e; ++i) { | 
| + if (i->second == child_and_prerender_id) { | 
| + url_map_.erase(i); | 
| + DCHECK(CheckMapsAreInverseOfEachOther(id_map_, url_map_)); | 
| + return; | 
| + } | 
| + } | 
| + NOTREACHED(); | 
| +} | 
| + | 
| +void PrerenderLinkManager::OnAddPrerender(const int prerender_id, | 
| 
cbentzel
2012/04/24 15:42:59
Curious - this doesn't match the signature in the
 
gavinp
2012/04/26 23:55:39
This does compile.  You can always add "const" in
 | 
| + const int child_id, | 
| + const GURL& orig_url, | 
| + const content::Referrer& referrer, | 
| + const gfx::Size& ALLOW_UNUSED size, | 
| + const int render_view_route_id) { | 
| + DVLOG(2) << "OnAddPrerender, child_id = " << child_id | 
| + << ", prerender_id = " << prerender_id | 
| + << ", url = " << orig_url.spec(); | 
| + DVLOG(3) << "... render_view_route_id = " << render_view_route_id | 
| + << ", referrer url = " << referrer.url.spec(); | 
| + DCHECK(CheckMapsAreInverseOfEachOther(id_map_, url_map_)); | 
| + // TODO(gavinp): Add tests to insure fragments work, then remove this fragment | 
| 
cbentzel
2012/04/24 15:42:59
Nit: ensure
 
gavinp
2012/04/26 23:55:39
Done.
 | 
| + // clearing code. | 
| + url_canon::Replacements<char> replacements; | 
| + replacements.ClearRef(); | 
| + const GURL url = orig_url.ReplaceComponents(replacements); | 
| + | 
| + manager_->AddPrerenderFromLinkRelPrerender( | 
| + child_id, render_view_route_id, url, referrer); | 
| 
mmenke
2012/04/24 15:26:15
Random comment:  When this fails, is there anythin
 | 
| + const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); | 
| + DCHECK(id_map_.find(child_and_prerender_id) == id_map_.end()); | 
| + id_map_.insert(std::make_pair(child_and_prerender_id, url)); | 
| 
cbentzel
2012/04/24 15:42:59
Should this be done prior to the AddPrerender case
 
gavinp
2012/04/26 23:55:39
See my reply to mmenke above...
 | 
| + url_map_.insert(std::make_pair(url, child_and_prerender_id)); | 
| + DCHECK(CheckMapsAreInverseOfEachOther(id_map_, url_map_)); | 
| +} | 
| + | 
| +void PrerenderLinkManager::OnCancelPrerender(const int prerender_id, | 
| + const int child_id) { | 
| + DVLOG(2) << "OnCancelPrerender, child_id = " << child_id | 
| + << ", prerender_id = " << prerender_id; | 
| + const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); | 
| + PrerenderIdToUrlMap::iterator id_url_iter = | 
| + id_map_.find(child_and_prerender_id); | 
| + if (id_url_iter == id_map_.end()) { | 
| + NOTREACHED() << "Canceling a prerender that doesn't exist."; | 
| + return; | 
| + } | 
| + const GURL url = id_url_iter->second; | 
| + RemovePrerender(id_url_iter); | 
| + | 
| + if (url_map_.find(url) != url_map_.end()) | 
| + return; | 
| + | 
| + // TODO(gavinp): Track down the correct prerender and stop it, rather than | 
| 
cbentzel
2012/04/24 15:42:59
Why not fix this now?
 
gavinp
2012/04/26 23:55:39
This here is advanced quite a lot from what was in
 | 
| + // this nuclear option, which assumes that only one prerender at a time | 
| + // runs. | 
| + if (PrerenderContents* contents = manager_->GetEntry(url)) | 
| + contents->Destroy(FINAL_STATUS_CANCELLED); | 
| 
cbentzel
2012/04/24 15:42:59
Yes, this seems like the appropriate FINAL_STATUS
 | 
| +} | 
| + | 
| +void PrerenderLinkManager::OnAbandonPrerender( | 
| + int prerender_id, | 
| 
cbentzel
2012/04/24 15:42:59
Nit: could this fit on the previous line?
 
gavinp
2012/04/26 23:55:39
Done.  This removes the last sign of the horrible
 | 
| + int child_id) { | 
| + DVLOG(2) << "OnAbandonPrerender, child_id = " << child_id | 
| + << ", prerender_id = " << prerender_id; | 
| + // TODO(gavinp,cbentzel): Implement reasonable behaviour for | 
| + // navigation away from launcher. | 
| + const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id); | 
| + PrerenderIdToUrlMap::iterator id_url_iter = | 
| + id_map_.find(child_and_prerender_id); | 
| + if (id_url_iter == id_map_.end()) { | 
| + // FIXME(gavinp): Currently, canceled prerenders also get abandoned later. | 
| + // When the WebKit fix to stop this lands, add a NOTREACHED() here. | 
| + return; | 
| + } | 
| + RemovePrerender(id_url_iter); | 
| +} | 
| + | 
| +void PrerenderLinkManager::OnChannelClosing(int child_id) { | 
| + DVLOG(2) << "OnChannelClosing, child id = " << child_id; | 
| + const ChildAndPrerenderIdPair child_and_minimum_prerender_id( | 
| + child_id, std::numeric_limits<int>::min()); | 
| + const ChildAndPrerenderIdPair child_and_maximum_prerender_id( | 
| + child_id, std::numeric_limits<int>::max()); | 
| + std::queue<int> prerender_ids_to_abandon; | 
| + for (PrerenderIdToUrlMap::iterator | 
| + i = id_map_.lower_bound(child_and_minimum_prerender_id), | 
| 
cbentzel
2012/04/24 15:42:59
Clever.
Just to be sure though - if id_map_ only
 
gavinp
2012/04/26 23:55:39
Yes.  But we'd never run the loop body in that cas
 | 
| + e = id_map_.upper_bound(child_and_maximum_prerender_id); | 
| + i != e; ++i) { | 
| + prerender_ids_to_abandon.push(i->first.second); | 
| + } | 
| + while (!prerender_ids_to_abandon.empty()) { | 
| + DVLOG(4) << "---> abandon prerender_id = " | 
| + << prerender_ids_to_abandon.front(); | 
| + OnAbandonPrerender(prerender_ids_to_abandon.front(), child_id); | 
| 
cbentzel
2012/04/24 15:42:59
Why is this overloading OnAbandonPrerender, if we
 
gavinp
2012/04/26 23:55:39
What about the case of the user navigating away fr
 | 
| + prerender_ids_to_abandon.pop(); | 
| + } | 
| +} | 
| + | 
| +} // namespace prerender |