Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: content/browser/web_contents/web_contents_impl.cc

Issue 925623002: Refactor the loading tracking logic in WebContentsImpl. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/web_contents/web_contents_impl.h" 5 #include "content/browser/web_contents/web_contents_impl.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 #endif 114 #endif
115 115
116 #if defined(OS_MACOSX) 116 #if defined(OS_MACOSX)
117 #include "base/mac/foundation_util.h" 117 #include "base/mac/foundation_util.h"
118 #endif 118 #endif
119 119
120 namespace content { 120 namespace content {
121 namespace { 121 namespace {
122 122
123 const int kMinimumDelayBetweenLoadingUpdatesMS = 100; 123 const int kMinimumDelayBetweenLoadingUpdatesMS = 100;
124
125 // This matches what Blink's ProgressTracker has traditionally used for a
126 // minimum progress value.
127 const double kMinimumLoadingProgress = 0.1;
128
129 const char kDotGoogleDotCom[] = ".google.com"; 124 const char kDotGoogleDotCom[] = ".google.com";
130 125
131 #if defined(OS_ANDROID) 126 #if defined(OS_ANDROID)
132 const char kWebContentsAndroidKey[] = "web_contents_android"; 127 const char kWebContentsAndroidKey[] = "web_contents_android";
133 #endif // OS_ANDROID 128 #endif // OS_ANDROID
134 129
135 base::LazyInstance<std::vector<WebContentsImpl::CreatedCallback> > 130 base::LazyInstance<std::vector<WebContentsImpl::CreatedCallback> >
136 g_created_callbacks = LAZY_INSTANCE_INITIALIZER; 131 g_created_callbacks = LAZY_INSTANCE_INITIALIZER;
137 132
138 static int StartDownload(RenderFrameHost* rfh, 133 static int StartDownload(RenderFrameHost* rfh,
(...skipping 18 matching lines...) Expand all
157 } 152 }
158 153
159 // Helper function for retrieving all the sites in a frame tree. 154 // Helper function for retrieving all the sites in a frame tree.
160 bool CollectSites(BrowserContext* context, 155 bool CollectSites(BrowserContext* context,
161 std::set<GURL>* sites, 156 std::set<GURL>* sites,
162 FrameTreeNode* node) { 157 FrameTreeNode* node) {
163 sites->insert(SiteInstance::GetSiteForURL(context, node->current_url())); 158 sites->insert(SiteInstance::GetSiteForURL(context, node->current_url()));
164 return true; 159 return true;
165 } 160 }
166 161
162 // Helper function used with FrameTree::ForEach() for retrieving the total
163 // loading progress and number of frames in a frame tree.
164 bool CollectLoadProgress(double* progress,
165 int* frame_count,
Charlie Reis 2015/03/05 04:46:18 nit: Wrong indent.
Fabrice (no longer in Chrome) 2015/03/05 12:37:43 Done.
166 FrameTreeNode* node) {
167 // Ignore the current frame if it has not started loading.
168 double frame_progress = node->GetLoadingProgress();
169 if (frame_progress == RenderFrameHostImpl::kLoadingProgressNotStarted)
170 return true;
171
172 // Collect progress.
173 *progress += node->GetLoadingProgress();
174 (*frame_count)++;
175 return true;
176 }
177
178 // Helper function used with FrameTree::ForEach() to check if at least one of
179 // the nodes is loading.
180 bool IsNodeLoading(bool* is_loading, FrameTreeNode* node) {
181 if (node->IsLoading()) {
182 // There is at least one node loading, so abort traversal.
183 *is_loading = true;
184 return false;
185 }
186 return true;
187 }
188
189 // Helper function used with FrameTree::ForEach() to reset the load progress.
190 bool ResetLoadProgress(FrameTreeNode* node) {
191 node->current_frame_host()->set_loading_progress(
192 RenderFrameHostImpl::kLoadingProgressNotStarted);
193 return true;
194 }
195
167 bool ForEachFrameInternal( 196 bool ForEachFrameInternal(
168 const base::Callback<void(RenderFrameHost*)>& on_frame, 197 const base::Callback<void(RenderFrameHost*)>& on_frame,
169 FrameTreeNode* node) { 198 FrameTreeNode* node) {
170 on_frame.Run(node->current_frame_host()); 199 on_frame.Run(node->current_frame_host());
171 return true; 200 return true;
172 } 201 }
173 202
174 bool ForEachPendingFrameInternal( 203 bool ForEachPendingFrameInternal(
175 const base::Callback<void(RenderFrameHost*)>& on_frame, 204 const base::Callback<void(RenderFrameHost*)>& on_frame,
176 FrameTreeNode* node) { 205 FrameTreeNode* node) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 // termination is not allowed for the current RenderFrameHost of 247 // termination is not allowed for the current RenderFrameHost of
219 // |frame_tree_node|. Used with FrameTree::ForEach. 248 // |frame_tree_node|. Used with FrameTree::ForEach.
220 bool SuddenTerminationAllowed(bool* sudden_termination_allowed, 249 bool SuddenTerminationAllowed(bool* sudden_termination_allowed,
221 FrameTreeNode* frame_tree_node) { 250 FrameTreeNode* frame_tree_node) {
222 if (frame_tree_node->current_frame_host()->SuddenTerminationAllowed()) 251 if (frame_tree_node->current_frame_host()->SuddenTerminationAllowed())
223 return true; 252 return true;
224 *sudden_termination_allowed = false; 253 *sudden_termination_allowed = false;
225 return false; 254 return false;
226 } 255 }
227 256
257 // Returns true if at least one of the nodes in the |frame_tree| is loading.
258 bool IsFrameTreeLoading(FrameTree& frame_tree) {
259 bool is_loading = false;
260 frame_tree.ForEach(base::Bind(&IsNodeLoading, &is_loading));
261 return is_loading;
262 }
263
228 } // namespace 264 } // namespace
229 265
230 WebContents* WebContents::Create(const WebContents::CreateParams& params) { 266 WebContents* WebContents::Create(const WebContents::CreateParams& params) {
231 return WebContentsImpl::CreateWithOpener( 267 return WebContentsImpl::CreateWithOpener(
232 params, static_cast<WebContentsImpl*>(params.opener)); 268 params, static_cast<WebContentsImpl*>(params.opener));
233 } 269 }
234 270
235 WebContents* WebContents::CreateWithSessionStorage( 271 WebContents* WebContents::CreateWithSessionStorage(
236 const WebContents::CreateParams& params, 272 const WebContents::CreateParams& params,
237 const SessionStorageNamespaceMap& session_storage_namespace_map) { 273 const SessionStorageNamespaceMap& session_storage_namespace_map) {
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 this, 363 this,
328 this, 364 this,
329 this), 365 this),
330 is_loading_(false), 366 is_loading_(false),
331 is_load_to_different_document_(false), 367 is_load_to_different_document_(false),
332 crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING), 368 crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING),
333 crashed_error_code_(0), 369 crashed_error_code_(0),
334 waiting_for_response_(false), 370 waiting_for_response_(false),
335 load_state_(net::LOAD_STATE_IDLE, base::string16()), 371 load_state_(net::LOAD_STATE_IDLE, base::string16()),
336 loading_total_progress_(0.0), 372 loading_total_progress_(0.0),
337 loading_frames_in_progress_(0),
338 upload_size_(0), 373 upload_size_(0),
339 upload_position_(0), 374 upload_position_(0),
340 displayed_insecure_content_(false), 375 displayed_insecure_content_(false),
341 has_accessed_initial_document_(false), 376 has_accessed_initial_document_(false),
342 capturer_count_(0), 377 capturer_count_(0),
343 should_normally_be_visible_(true), 378 should_normally_be_visible_(true),
344 is_being_destroyed_(false), 379 is_being_destroyed_(false),
345 notify_disconnection_(false), 380 notify_disconnection_(false),
346 dialog_manager_(NULL), 381 dialog_manager_(NULL),
347 is_showing_before_unload_dialog_(false), 382 is_showing_before_unload_dialog_(false),
(...skipping 2507 matching lines...) Expand 10 before | Expand all | Expand 10 after
2855 FOR_EACH_OBSERVER( 2890 FOR_EACH_OBSERVER(
2856 WebContentsObserver, observers_, DidFinishLoad(rfh, validated_url)); 2891 WebContentsObserver, observers_, DidFinishLoad(rfh, validated_url));
2857 } 2892 }
2858 2893
2859 void WebContentsImpl::OnDidStartLoading(bool to_different_document) { 2894 void WebContentsImpl::OnDidStartLoading(bool to_different_document) {
2860 if (!HasValidFrameSource()) 2895 if (!HasValidFrameSource())
2861 return; 2896 return;
2862 2897
2863 RenderFrameHostImpl* rfh = 2898 RenderFrameHostImpl* rfh =
2864 static_cast<RenderFrameHostImpl*>(render_frame_message_source_); 2899 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2865 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2866 2900
2867 // Any main frame load to a new document should reset the load progress, since 2901 // Any main frame load to a new document should reset the load progress, since
2868 // it will replace the current page and any frames. 2902 // it will replace the current page and any frames.
2869 if (to_different_document && !rfh->GetParent()) { 2903 if (to_different_document && !rfh->GetParent()) {
2870 ResetLoadProgressState(); 2904 ResetLoadProgressState();
2871 loading_frames_in_progress_ = 0; 2905 rfh->set_is_loading(false);
2872 rfh->frame_tree_node()->set_is_loading(false);
2873 } 2906 }
2874 2907
2875 // It is possible to get multiple calls to OnDidStartLoading that don't have 2908 // This method should never be called when the frame is loading.
2876 // corresponding calls to OnDidStopLoading: 2909 DCHECK(!rfh->is_loading());
2877 // - With "swappedout://" URLs, this happens when a RenderView gets swapped
2878 // out for a cross-process navigation, and it turns into a placeholder for
2879 // one being rendered in a different process.
2880 // - Also, there might be more than one RenderFrameHost sharing the same
2881 // FrameTreeNode (and thus sharing its ID) each sending a start.
2882 // - But in the future, once clamy@ moves navigation network requests to the
2883 // browser process, there's a good chance that callbacks about starting and
2884 // stopping will all be handled by the browser. When that happens, there
2885 // should no longer be a start/stop call imbalance. TODO(avi): When this
2886 // future arrives, update this code to not allow this case.
2887 if (rfh->frame_tree_node()->is_loading())
2888 return;
2889 2910
2890 DCHECK_GE(loading_frames_in_progress_, 0); 2911 if (!IsFrameTreeLoading(frame_tree_))
2891 if (loading_frames_in_progress_ == 0)
2892 DidStartLoading(rfh, to_different_document); 2912 DidStartLoading(rfh, to_different_document);
2893 2913
2894 ++loading_frames_in_progress_; 2914 rfh->set_is_loading(true);
2895 rfh->frame_tree_node()->set_is_loading(true); 2915 rfh->set_loading_progress(RenderFrameHostImpl::kLoadingProgressMinimum);
2896 2916
2897 // Notify the RenderFrameHostManager of the event. 2917 // Notify the RenderFrameHostManager of the event.
2898 rfh->frame_tree_node()->render_manager()->OnDidStartLoading(); 2918 rfh->frame_tree_node()->render_manager()->OnDidStartLoading();
2899 2919
2900 loading_progresses_[render_frame_id] = kMinimumLoadingProgress;
2901 SendLoadProgressChanged(); 2920 SendLoadProgressChanged();
2902 } 2921 }
2903 2922
2904 void WebContentsImpl::OnDidStopLoading() { 2923 void WebContentsImpl::OnDidStopLoading() {
2905 if (!HasValidFrameSource()) 2924 if (!HasValidFrameSource())
2906 return; 2925 return;
2907 2926
2908 RenderFrameHostImpl* rfh = 2927 RenderFrameHostImpl* rfh =
2909 static_cast<RenderFrameHostImpl*>(render_frame_message_source_); 2928 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2910 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2911 rfh->frame_tree_node()->set_is_loading(false);
2912 2929
2913 if (loading_progresses_.find(render_frame_id) != loading_progresses_.end()) { 2930 // This method should never be called when the frame is not loading.
2914 // Load stopped while we were still tracking load. Make sure we update 2931 DCHECK(rfh->is_loading());
2915 // progress based on this frame's completion. 2932 rfh->set_is_loading(false);
2916 loading_progresses_[render_frame_id] = 1.0; 2933 rfh->set_loading_progress(RenderFrameHostImpl::kLoadingProgressDone);
2917 SendLoadProgressChanged(); 2934
2918 // Then we clean-up our states. 2935 // Update progress based on this frame's completion.
2919 if (loading_total_progress_ == 1.0) 2936 SendLoadProgressChanged();
2920 ResetLoadProgressState(); 2937
2921 } 2938 // Then clean-up the states.
2939 if (loading_total_progress_ == 1.0)
2940 ResetLoadProgressState();
2922 2941
2923 // Notify the RenderFrameHostManager of the event. 2942 // Notify the RenderFrameHostManager of the event.
2924 rfh->frame_tree_node()->render_manager()->OnDidStopLoading(); 2943 rfh->frame_tree_node()->render_manager()->OnDidStopLoading();
2925 2944
2926 // TODO(japhet): This should be a DCHECK, but the pdf plugin sometimes 2945 if (!IsFrameTreeLoading(frame_tree_))
2927 // calls DidStopLoading() without a matching DidStartLoading().
2928 if (loading_frames_in_progress_ == 0)
2929 return;
2930 --loading_frames_in_progress_;
2931 if (loading_frames_in_progress_ == 0)
2932 DidStopLoading(rfh); 2946 DidStopLoading(rfh);
2933 } 2947 }
2934 2948
2935 void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) { 2949 void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) {
2936 if (!HasValidFrameSource()) 2950 if (!HasValidFrameSource())
2937 return; 2951 return;
2938 2952
2939 RenderFrameHostImpl* rfh = 2953 RenderFrameHostImpl* rfh =
2940 static_cast<RenderFrameHostImpl*>(render_frame_message_source_); 2954 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2941 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2942 2955
2943 loading_progresses_[render_frame_id] = load_progress; 2956 rfh->set_loading_progress(load_progress);
2944 2957
2945 // We notify progress change immediately for the first and last updates. 2958 // We notify progress change immediately for the first and last updates.
2946 // Also, since the message loop may be pretty busy when a page is loaded, it 2959 // Also, since the message loop may be pretty busy when a page is loaded, it
2947 // might not execute a posted task in a timely manner so we make sure to 2960 // might not execute a posted task in a timely manner so we make sure to
2948 // immediately send progress report if enough time has passed. 2961 // immediately send progress report if enough time has passed.
2949 base::TimeDelta min_delay = 2962 base::TimeDelta min_delay =
2950 base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS); 2963 base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS);
2951 if (load_progress == 1.0 || loading_last_progress_update_.is_null() || 2964 if (load_progress == 1.0 || loading_last_progress_update_.is_null() ||
2952 base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) { 2965 base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) {
2953 // If there is a pending task to send progress, it is now obsolete. 2966 // If there is a pending task to send progress, it is now obsolete.
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after
3411 Details<std::pair<NavigationEntry*, bool> >(&details)); 3424 Details<std::pair<NavigationEntry*, bool> >(&details));
3412 3425
3413 return true; 3426 return true;
3414 } 3427 }
3415 3428
3416 void WebContentsImpl::SendLoadProgressChanged() { 3429 void WebContentsImpl::SendLoadProgressChanged() {
3417 loading_last_progress_update_ = base::TimeTicks::Now(); 3430 loading_last_progress_update_ = base::TimeTicks::Now();
3418 double progress = 0.0; 3431 double progress = 0.0;
3419 int frame_count = 0; 3432 int frame_count = 0;
3420 3433
3421 for (LoadingProgressMap::iterator it = loading_progresses_.begin(); 3434 frame_tree_.ForEach(
3422 it != loading_progresses_.end(); 3435 base::Bind(&CollectLoadProgress, &progress, &frame_count));
3423 ++it) { 3436 if (frame_count != 0)
3424 progress += it->second; 3437 progress /= frame_count;
3425 ++frame_count; 3438 DCHECK_LE(progress, 1.0);
3426 }
3427 if (frame_count == 0)
3428 return;
3429 progress /= frame_count;
3430 DCHECK(progress <= 1.0);
3431 3439
3432 if (progress <= loading_total_progress_) 3440 if (progress <= loading_total_progress_)
3433 return; 3441 return;
3434 loading_total_progress_ = progress; 3442 loading_total_progress_ = progress;
3435 3443
3436 if (delegate_) 3444 if (delegate_)
3437 delegate_->LoadProgressChanged(this, progress); 3445 delegate_->LoadProgressChanged(this, progress);
3438 } 3446 }
3439 3447
3440 void WebContentsImpl::ResetLoadProgressState() { 3448 void WebContentsImpl::ResetLoadProgressState() {
3441 loading_progresses_.clear(); 3449 frame_tree_.ForEach(base::Bind(&ResetLoadProgress));
3442 loading_total_progress_ = 0.0; 3450 loading_total_progress_ = 0.0;
3443 loading_weak_factory_.InvalidateWeakPtrs(); 3451 loading_weak_factory_.InvalidateWeakPtrs();
3444 loading_last_progress_update_ = base::TimeTicks(); 3452 loading_last_progress_update_ = base::TimeTicks();
3445 } 3453 }
3446 3454
3447 void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host, 3455 void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host,
3448 RenderViewHost* new_host) { 3456 RenderViewHost* new_host) {
3449 // After sending out a swap notification, we need to send a disconnect 3457 // After sending out a swap notification, we need to send a disconnect
3450 // notification so that clients that pick up a pointer to |this| can NULL the 3458 // notification so that clients that pick up a pointer to |this| can NULL the
3451 // pointer. See Bug 1230284. 3459 // pointer. See Bug 1230284.
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
3736 3744
3737 SetIsLoading(rvh, false, true, NULL); 3745 SetIsLoading(rvh, false, true, NULL);
3738 NotifyDisconnected(); 3746 NotifyDisconnected();
3739 SetIsCrashed(status, error_code); 3747 SetIsCrashed(status, error_code);
3740 3748
3741 // Reset the loading progress. TODO(avi): What does it mean to have a 3749 // Reset the loading progress. TODO(avi): What does it mean to have a
3742 // "renderer crash" when there is more than one renderer process serving a 3750 // "renderer crash" when there is more than one renderer process serving a
3743 // webpage? Once this function is called at a more granular frame level, we 3751 // webpage? Once this function is called at a more granular frame level, we
3744 // probably will need to more granularly reset the state here. 3752 // probably will need to more granularly reset the state here.
3745 ResetLoadProgressState(); 3753 ResetLoadProgressState();
3746 loading_frames_in_progress_ = 0;
3747 3754
3748 FOR_EACH_OBSERVER(WebContentsObserver, 3755 FOR_EACH_OBSERVER(WebContentsObserver,
3749 observers_, 3756 observers_,
3750 RenderProcessGone(GetCrashedStatus())); 3757 RenderProcessGone(GetCrashedStatus()));
3751 } 3758 }
3752 3759
3753 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) { 3760 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) {
3754 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewDeleted(rvh)); 3761 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewDeleted(rvh));
3755 } 3762 }
3756 3763
(...skipping 778 matching lines...) Expand 10 before | Expand all | Expand 10 after
4535 node->render_manager()->ResumeResponseDeferredAtStart(); 4542 node->render_manager()->ResumeResponseDeferredAtStart();
4536 } 4543 }
4537 4544
4538 void WebContentsImpl::SetForceDisableOverscrollContent(bool force_disable) { 4545 void WebContentsImpl::SetForceDisableOverscrollContent(bool force_disable) {
4539 force_disable_overscroll_content_ = force_disable; 4546 force_disable_overscroll_content_ = force_disable;
4540 if (view_) 4547 if (view_)
4541 view_->SetOverscrollControllerEnabled(CanOverscrollContent()); 4548 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
4542 } 4549 }
4543 4550
4544 } // namespace content 4551 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698