Roll src/third_party/WebKit f298044:aa8346d (svn 202628:202629)
[chromium-blink-merge.git] / chrome / browser / prerender / prerender_tab_helper.cc
blobb3912b2a1bdcf69fae00ace508003efb5b5da64c
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.
5 #include "chrome/browser/prerender/prerender_tab_helper.h"
7 #include "base/bind.h"
8 #include "base/metrics/histogram.h"
9 #include "base/time/time.h"
10 #include "chrome/browser/prerender/prerender_histograms.h"
11 #include "chrome/browser/prerender/prerender_manager.h"
12 #include "chrome/browser/prerender/prerender_manager_factory.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/resource_request_details.h"
16 #include "content/public/browser/web_contents.h"
18 using content::WebContents;
20 DEFINE_WEB_CONTENTS_USER_DATA_KEY(prerender::PrerenderTabHelper);
22 namespace prerender {
24 PrerenderTabHelper::PrerenderTabHelper(content::WebContents* web_contents)
25 : content::WebContentsObserver(web_contents),
26 origin_(ORIGIN_NONE),
27 next_load_is_control_prerender_(false),
28 next_load_origin_(ORIGIN_NONE),
29 weak_factory_(this) {
30 // Determine if this is a prerender.
31 PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
32 if (prerender_manager &&
33 prerender_manager->IsWebContentsPrerendering(web_contents, &origin_)) {
34 navigation_type_ = NAVIGATION_TYPE_PRERENDERED;
35 } else {
36 navigation_type_ = NAVIGATION_TYPE_NORMAL;
40 PrerenderTabHelper::~PrerenderTabHelper() {
43 void PrerenderTabHelper::DidGetRedirectForResourceRequest(
44 content::RenderFrameHost* render_frame_host,
45 const content::ResourceRedirectDetails& details) {
46 if (details.resource_type != content::RESOURCE_TYPE_MAIN_FRAME)
47 return;
49 MainFrameUrlDidChange(details.new_url);
52 void PrerenderTabHelper::DidCommitProvisionalLoadForFrame(
53 content::RenderFrameHost* render_frame_host,
54 const GURL& validated_url,
55 ui::PageTransition transition_type) {
56 if (render_frame_host->GetParent())
57 return;
58 url_ = validated_url;
59 PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
60 if (!prerender_manager)
61 return;
62 if (prerender_manager->IsWebContentsPrerendering(web_contents(), NULL))
63 return;
64 prerender_manager->RecordNavigation(validated_url);
67 void PrerenderTabHelper::DidStopLoading() {
68 // Compute the PPLT metric and report it in a histogram, if needed. If the
69 // page is still prerendering, record the not swapped in page load time
70 // instead.
71 if (!pplt_load_start_.is_null()) {
72 base::TimeTicks now = base::TimeTicks::Now();
73 if (IsPrerendering()) {
74 PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
75 if (prerender_manager) {
76 prerender_manager->RecordPageLoadTimeNotSwappedIn(
77 origin_, now - pplt_load_start_, url_);
78 } else {
79 NOTREACHED();
81 } else {
82 double fraction_elapsed_at_swapin = -1.0;
83 if (!actual_load_start_.is_null()) {
84 double plt = (now - actual_load_start_).InMillisecondsF();
85 if (plt > 0.0) {
86 fraction_elapsed_at_swapin = 1.0 -
87 (now - pplt_load_start_).InMillisecondsF() / plt;
88 } else {
89 fraction_elapsed_at_swapin = 1.0;
91 DCHECK_GE(fraction_elapsed_at_swapin, 0.0);
92 DCHECK_LE(fraction_elapsed_at_swapin, 1.0);
95 RecordPerceivedPageLoadTime(
96 now - pplt_load_start_, fraction_elapsed_at_swapin);
100 // Reset the PPLT metric.
101 pplt_load_start_ = base::TimeTicks();
102 actual_load_start_ = base::TimeTicks();
105 void PrerenderTabHelper::DidStartProvisionalLoadForFrame(
106 content::RenderFrameHost* render_frame_host,
107 const GURL& validated_url,
108 bool is_error_page,
109 bool is_iframe_srcdoc) {
110 if (render_frame_host->GetParent())
111 return;
113 // Record PPLT state for the beginning of a new navigation.
114 pplt_load_start_ = base::TimeTicks::Now();
115 actual_load_start_ = base::TimeTicks();
117 if (next_load_is_control_prerender_) {
118 DCHECK_EQ(NAVIGATION_TYPE_NORMAL, navigation_type_);
119 navigation_type_ = NAVIGATION_TYPE_WOULD_HAVE_BEEN_PRERENDERED;
120 origin_ = next_load_origin_;
121 next_load_is_control_prerender_ = false;
122 next_load_origin_ = ORIGIN_NONE;
125 MainFrameUrlDidChange(validated_url);
128 void PrerenderTabHelper::MainFrameUrlDidChange(const GURL& url) {
129 url_ = url;
132 PrerenderManager* PrerenderTabHelper::MaybeGetPrerenderManager() const {
133 return PrerenderManagerFactory::GetForProfile(
134 Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
137 bool PrerenderTabHelper::IsPrerendering() {
138 PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
139 if (!prerender_manager)
140 return false;
141 return prerender_manager->IsWebContentsPrerendering(web_contents(), NULL);
144 void PrerenderTabHelper::PrerenderSwappedIn() {
145 // Ensure we are not prerendering any more.
146 DCHECK_EQ(NAVIGATION_TYPE_PRERENDERED, navigation_type_);
147 DCHECK(!IsPrerendering());
148 if (pplt_load_start_.is_null()) {
149 // If we have already finished loading, report a 0 PPLT.
150 RecordPerceivedPageLoadTime(base::TimeDelta(), 1.0);
151 DCHECK_EQ(NAVIGATION_TYPE_NORMAL, navigation_type_);
152 } else {
153 // If we have not finished loading yet, record the actual load start, and
154 // rebase the start time to now.
155 actual_load_start_ = pplt_load_start_;
156 pplt_load_start_ = base::TimeTicks::Now();
160 void PrerenderTabHelper::WouldHavePrerenderedNextLoad(Origin origin) {
161 next_load_is_control_prerender_ = true;
162 next_load_origin_ = origin;
165 void PrerenderTabHelper::RecordPerceivedPageLoadTime(
166 base::TimeDelta perceived_page_load_time,
167 double fraction_plt_elapsed_at_swap_in) {
168 DCHECK(!IsPrerendering());
169 PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
170 if (!prerender_manager)
171 return;
173 // Note: it is possible for |next_load_is_control_prerender_| to be true at
174 // this point. This does not affect the classification of the current load,
175 // but only the next load. (This occurs if a WOULD_HAVE_BEEN_PRERENDERED
176 // navigation interrupts and aborts another navigation.)
177 prerender_manager->RecordPerceivedPageLoadTime(
178 origin_, navigation_type_, perceived_page_load_time,
179 fraction_plt_elapsed_at_swap_in, url_);
181 // Reset state for the next navigation.
182 navigation_type_ = NAVIGATION_TYPE_NORMAL;
183 origin_ = ORIGIN_NONE;
186 } // namespace prerender