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

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

Issue 989473003: Reland of Refactor the loading tracking logic in WebContentsImpl. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comment. 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 20 matching lines...) Expand all
159 } 154 }
160 155
161 // Helper function for retrieving all the sites in a frame tree. 156 // Helper function for retrieving all the sites in a frame tree.
162 bool CollectSites(BrowserContext* context, 157 bool CollectSites(BrowserContext* context,
163 std::set<GURL>* sites, 158 std::set<GURL>* sites,
164 FrameTreeNode* node) { 159 FrameTreeNode* node) {
165 sites->insert(SiteInstance::GetSiteForURL(context, node->current_url())); 160 sites->insert(SiteInstance::GetSiteForURL(context, node->current_url()));
166 return true; 161 return true;
167 } 162 }
168 163
164 // Helper function used with FrameTree::ForEach() for retrieving the total
165 // loading progress and number of frames in a frame tree.
166 bool CollectLoadProgress(double* progress,
167 int* frame_count,
168 FrameTreeNode* node) {
169 // Ignore the current frame if it has not started loading.
170 double frame_progress = node->GetLoadingProgress();
171 if (frame_progress == RenderFrameHostImpl::kLoadingProgressNotStarted)
172 return true;
173
174 // Collect progress.
175 *progress += node->GetLoadingProgress();
176 (*frame_count)++;
177 return true;
178 }
179
180 // Helper function used with FrameTree::ForEach() to check if at least one of
181 // the nodes is loading.
182 bool IsNodeLoading(bool* is_loading, FrameTreeNode* node) {
183 if (node->IsLoading()) {
184 // There is at least one node loading, so abort traversal.
185 *is_loading = true;
186 return false;
187 }
188 return true;
189 }
190
191 // Helper function used with FrameTree::ForEach() to reset the load progress.
192 bool ResetLoadProgress(FrameTreeNode* node) {
193 node->current_frame_host()->set_loading_progress(
194 RenderFrameHostImpl::kLoadingProgressNotStarted);
195 return true;
196 }
197
169 bool ForEachFrameInternal( 198 bool ForEachFrameInternal(
170 const base::Callback<void(RenderFrameHost*)>& on_frame, 199 const base::Callback<void(RenderFrameHost*)>& on_frame,
171 FrameTreeNode* node) { 200 FrameTreeNode* node) {
172 on_frame.Run(node->current_frame_host()); 201 on_frame.Run(node->current_frame_host());
173 return true; 202 return true;
174 } 203 }
175 204
176 bool ForEachPendingFrameInternal( 205 bool ForEachPendingFrameInternal(
177 const base::Callback<void(RenderFrameHost*)>& on_frame, 206 const base::Callback<void(RenderFrameHost*)>& on_frame,
178 FrameTreeNode* node) { 207 FrameTreeNode* node) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 // termination is not allowed for the current RenderFrameHost of 249 // termination is not allowed for the current RenderFrameHost of
221 // |frame_tree_node|. Used with FrameTree::ForEach. 250 // |frame_tree_node|. Used with FrameTree::ForEach.
222 bool SuddenTerminationAllowed(bool* sudden_termination_allowed, 251 bool SuddenTerminationAllowed(bool* sudden_termination_allowed,
223 FrameTreeNode* frame_tree_node) { 252 FrameTreeNode* frame_tree_node) {
224 if (frame_tree_node->current_frame_host()->SuddenTerminationAllowed()) 253 if (frame_tree_node->current_frame_host()->SuddenTerminationAllowed())
225 return true; 254 return true;
226 *sudden_termination_allowed = false; 255 *sudden_termination_allowed = false;
227 return false; 256 return false;
228 } 257 }
229 258
259 // Returns true if at least one of the nodes in the |frame_tree| is loading.
260 bool IsFrameTreeLoading(FrameTree& frame_tree) {
261 bool is_loading = false;
262 frame_tree.ForEach(base::Bind(&IsNodeLoading, &is_loading));
263 return is_loading;
264 }
265
230 } // namespace 266 } // namespace
231 267
232 WebContents* WebContents::Create(const WebContents::CreateParams& params) { 268 WebContents* WebContents::Create(const WebContents::CreateParams& params) {
233 return WebContentsImpl::CreateWithOpener( 269 return WebContentsImpl::CreateWithOpener(
234 params, static_cast<WebContentsImpl*>(params.opener)); 270 params, static_cast<WebContentsImpl*>(params.opener));
235 } 271 }
236 272
237 WebContents* WebContents::CreateWithSessionStorage( 273 WebContents* WebContents::CreateWithSessionStorage(
238 const WebContents::CreateParams& params, 274 const WebContents::CreateParams& params,
239 const SessionStorageNamespaceMap& session_storage_namespace_map) { 275 const SessionStorageNamespaceMap& session_storage_namespace_map) {
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 this, 365 this,
330 this, 366 this,
331 this), 367 this),
332 is_loading_(false), 368 is_loading_(false),
333 is_load_to_different_document_(false), 369 is_load_to_different_document_(false),
334 crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING), 370 crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING),
335 crashed_error_code_(0), 371 crashed_error_code_(0),
336 waiting_for_response_(false), 372 waiting_for_response_(false),
337 load_state_(net::LOAD_STATE_IDLE, base::string16()), 373 load_state_(net::LOAD_STATE_IDLE, base::string16()),
338 loading_total_progress_(0.0), 374 loading_total_progress_(0.0),
339 loading_frames_in_progress_(0),
340 upload_size_(0), 375 upload_size_(0),
341 upload_position_(0), 376 upload_position_(0),
342 displayed_insecure_content_(false), 377 displayed_insecure_content_(false),
343 has_accessed_initial_document_(false), 378 has_accessed_initial_document_(false),
344 theme_color_(SK_ColorTRANSPARENT), 379 theme_color_(SK_ColorTRANSPARENT),
345 last_sent_theme_color_(SK_ColorTRANSPARENT), 380 last_sent_theme_color_(SK_ColorTRANSPARENT),
346 capturer_count_(0), 381 capturer_count_(0),
347 should_normally_be_visible_(true), 382 should_normally_be_visible_(true),
348 is_being_destroyed_(false), 383 is_being_destroyed_(false),
349 notify_disconnection_(false), 384 notify_disconnection_(false),
(...skipping 2519 matching lines...) Expand 10 before | Expand all | Expand 10 after
2869 FOR_EACH_OBSERVER( 2904 FOR_EACH_OBSERVER(
2870 WebContentsObserver, observers_, DidFinishLoad(rfh, validated_url)); 2905 WebContentsObserver, observers_, DidFinishLoad(rfh, validated_url));
2871 } 2906 }
2872 2907
2873 void WebContentsImpl::OnDidStartLoading(bool to_different_document) { 2908 void WebContentsImpl::OnDidStartLoading(bool to_different_document) {
2874 if (!HasValidFrameSource()) 2909 if (!HasValidFrameSource())
2875 return; 2910 return;
2876 2911
2877 RenderFrameHostImpl* rfh = 2912 RenderFrameHostImpl* rfh =
2878 static_cast<RenderFrameHostImpl*>(render_frame_message_source_); 2913 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2879 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2880 2914
2881 // Any main frame load to a new document should reset the load progress, since 2915 // Any main frame load to a new document should reset the load progress, since
2882 // it will replace the current page and any frames. 2916 // it will replace the current page and any frames.
2883 if (to_different_document && !rfh->GetParent()) { 2917 if (to_different_document && !rfh->GetParent()) {
2884 ResetLoadProgressState(); 2918 ResetLoadProgressState();
2885 loading_frames_in_progress_ = 0; 2919 rfh->set_is_loading(false);
2886 rfh->frame_tree_node()->set_is_loading(false);
2887 } 2920 }
2888 2921
2889 // It is possible to get multiple calls to OnDidStartLoading that don't have 2922 // This method should never be called when the frame is loading.
2890 // corresponding calls to OnDidStopLoading: 2923 // Unfortunately, it can happen if a history navigation happens during a
2891 // - With "swappedout://" URLs, this happens when a RenderView gets swapped 2924 // BeforeUnload or Unload event.
2892 // out for a cross-process navigation, and it turns into a placeholder for 2925 // TODO(fdegans): Change this to a DCHECK after LoadEventProgress has been
2893 // one being rendered in a different process. 2926 // refactored in Blink.
Charlie Reis 2015/03/10 22:25:28 nit: Please list a bug number for this work, here
Fabrice (no longer in Chrome) 2015/03/11 15:30:38 Done.
2894 // - Also, there might be more than one RenderFrameHost sharing the same 2927 if (rfh->is_loading()) {
2895 // FrameTreeNode (and thus sharing its ID) each sending a start. 2928 LOG(WARNING) << "OnDidStartLoading was called twice.";
2896 // - But in the future, once clamy@ moves navigation network requests to the
2897 // browser process, there's a good chance that callbacks about starting and
2898 // stopping will all be handled by the browser. When that happens, there
2899 // should no longer be a start/stop call imbalance. TODO(avi): When this
2900 // future arrives, update this code to not allow this case.
2901 if (rfh->frame_tree_node()->is_loading())
2902 return; 2929 return;
2930 }
2903 2931
2904 DCHECK_GE(loading_frames_in_progress_, 0); 2932 if (!IsFrameTreeLoading(frame_tree_))
2905 if (loading_frames_in_progress_ == 0)
2906 DidStartLoading(rfh, to_different_document); 2933 DidStartLoading(rfh, to_different_document);
2907 2934
2908 ++loading_frames_in_progress_; 2935 rfh->set_is_loading(true);
2909 rfh->frame_tree_node()->set_is_loading(true); 2936 rfh->set_loading_progress(RenderFrameHostImpl::kLoadingProgressMinimum);
2910 2937
2911 // Notify the RenderFrameHostManager of the event. 2938 // Notify the RenderFrameHostManager of the event.
2912 rfh->frame_tree_node()->render_manager()->OnDidStartLoading(); 2939 rfh->frame_tree_node()->render_manager()->OnDidStartLoading();
2913 2940
2914 loading_progresses_[render_frame_id] = kMinimumLoadingProgress;
2915 SendLoadProgressChanged(); 2941 SendLoadProgressChanged();
2916 } 2942 }
2917 2943
2918 void WebContentsImpl::OnDidStopLoading() { 2944 void WebContentsImpl::OnDidStopLoading() {
2919 if (!HasValidFrameSource()) 2945 if (!HasValidFrameSource())
2920 return; 2946 return;
2921 2947
2922 RenderFrameHostImpl* rfh = 2948 RenderFrameHostImpl* rfh =
2923 static_cast<RenderFrameHostImpl*>(render_frame_message_source_); 2949 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2924 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2925 rfh->frame_tree_node()->set_is_loading(false);
2926 2950
2927 if (loading_progresses_.find(render_frame_id) != loading_progresses_.end()) { 2951 // This method should never be called when the frame is not loading.
2928 // Load stopped while we were still tracking load. Make sure we update 2952 // Unfortunately, it can happen if a history navigation happens during a
2929 // progress based on this frame's completion. 2953 // BeforeUnload or Unload event.
2930 loading_progresses_[render_frame_id] = 1.0; 2954 // TODO(fdegans): Change this to a DCHECK after LoadEventProgress has been
2931 SendLoadProgressChanged(); 2955 // refactored in Blink.
2932 // Then we clean-up our states. 2956 if (!rfh->is_loading()) {
2933 if (loading_total_progress_ == 1.0) 2957 LOG(WARNING) << "OnDidStopLoading was called twice.";
2934 ResetLoadProgressState(); 2958 return;
2935 } 2959 }
2936 2960
2961 rfh->set_is_loading(false);
2962 rfh->set_loading_progress(RenderFrameHostImpl::kLoadingProgressDone);
2963
2964 // Update progress based on this frame's completion.
2965 SendLoadProgressChanged();
2966
2967 // Then clean-up the states.
2968 if (loading_total_progress_ == 1.0)
2969 ResetLoadProgressState();
2970
2937 // Notify the RenderFrameHostManager of the event. 2971 // Notify the RenderFrameHostManager of the event.
2938 rfh->frame_tree_node()->render_manager()->OnDidStopLoading(); 2972 rfh->frame_tree_node()->render_manager()->OnDidStopLoading();
2939 2973
2940 // TODO(japhet): This should be a DCHECK, but the pdf plugin sometimes 2974 if (!IsFrameTreeLoading(frame_tree_))
2941 // calls DidStopLoading() without a matching DidStartLoading().
2942 if (loading_frames_in_progress_ == 0)
2943 return;
2944 --loading_frames_in_progress_;
2945 if (loading_frames_in_progress_ == 0)
2946 DidStopLoading(rfh); 2975 DidStopLoading(rfh);
2947 } 2976 }
2948 2977
2949 void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) { 2978 void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) {
2950 if (!HasValidFrameSource()) 2979 if (!HasValidFrameSource())
2951 return; 2980 return;
2952 2981
2953 RenderFrameHostImpl* rfh = 2982 RenderFrameHostImpl* rfh =
2954 static_cast<RenderFrameHostImpl*>(render_frame_message_source_); 2983 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2955 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2956 2984
2957 loading_progresses_[render_frame_id] = load_progress; 2985 rfh->set_loading_progress(load_progress);
2958 2986
2959 // We notify progress change immediately for the first and last updates. 2987 // We notify progress change immediately for the first and last updates.
2960 // Also, since the message loop may be pretty busy when a page is loaded, it 2988 // Also, since the message loop may be pretty busy when a page is loaded, it
2961 // might not execute a posted task in a timely manner so we make sure to 2989 // might not execute a posted task in a timely manner so we make sure to
2962 // immediately send progress report if enough time has passed. 2990 // immediately send progress report if enough time has passed.
2963 base::TimeDelta min_delay = 2991 base::TimeDelta min_delay =
2964 base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS); 2992 base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS);
2965 if (load_progress == 1.0 || loading_last_progress_update_.is_null() || 2993 if (load_progress == 1.0 || loading_last_progress_update_.is_null() ||
2966 base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) { 2994 base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) {
2967 // If there is a pending task to send progress, it is now obsolete. 2995 // If there is a pending task to send progress, it is now obsolete.
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after
3432 Details<std::pair<NavigationEntry*, bool> >(&details)); 3460 Details<std::pair<NavigationEntry*, bool> >(&details));
3433 3461
3434 return true; 3462 return true;
3435 } 3463 }
3436 3464
3437 void WebContentsImpl::SendLoadProgressChanged() { 3465 void WebContentsImpl::SendLoadProgressChanged() {
3438 loading_last_progress_update_ = base::TimeTicks::Now(); 3466 loading_last_progress_update_ = base::TimeTicks::Now();
3439 double progress = 0.0; 3467 double progress = 0.0;
3440 int frame_count = 0; 3468 int frame_count = 0;
3441 3469
3442 for (LoadingProgressMap::iterator it = loading_progresses_.begin(); 3470 frame_tree_.ForEach(
3443 it != loading_progresses_.end(); 3471 base::Bind(&CollectLoadProgress, &progress, &frame_count));
3444 ++it) { 3472 if (frame_count != 0)
3445 progress += it->second; 3473 progress /= frame_count;
3446 ++frame_count; 3474 DCHECK_LE(progress, 1.0);
3447 }
3448 if (frame_count == 0)
3449 return;
3450 progress /= frame_count;
3451 DCHECK(progress <= 1.0);
3452 3475
3453 if (progress <= loading_total_progress_) 3476 if (progress <= loading_total_progress_)
3454 return; 3477 return;
3455 loading_total_progress_ = progress; 3478 loading_total_progress_ = progress;
3456 3479
3457 if (delegate_) 3480 if (delegate_)
3458 delegate_->LoadProgressChanged(this, progress); 3481 delegate_->LoadProgressChanged(this, progress);
3459 } 3482 }
3460 3483
3461 void WebContentsImpl::ResetLoadProgressState() { 3484 void WebContentsImpl::ResetLoadProgressState() {
3462 loading_progresses_.clear(); 3485 frame_tree_.ForEach(base::Bind(&ResetLoadProgress));
3463 loading_total_progress_ = 0.0; 3486 loading_total_progress_ = 0.0;
3464 loading_weak_factory_.InvalidateWeakPtrs(); 3487 loading_weak_factory_.InvalidateWeakPtrs();
3465 loading_last_progress_update_ = base::TimeTicks(); 3488 loading_last_progress_update_ = base::TimeTicks();
3466 } 3489 }
3467 3490
3468 void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host, 3491 void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host,
3469 RenderViewHost* new_host) { 3492 RenderViewHost* new_host) {
3470 // After sending out a swap notification, we need to send a disconnect 3493 // After sending out a swap notification, we need to send a disconnect
3471 // notification so that clients that pick up a pointer to |this| can NULL the 3494 // notification so that clients that pick up a pointer to |this| can NULL the
3472 // pointer. See Bug 1230284. 3495 // pointer. See Bug 1230284.
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
3757 3780
3758 SetIsLoading(rvh, false, true, NULL); 3781 SetIsLoading(rvh, false, true, NULL);
3759 NotifyDisconnected(); 3782 NotifyDisconnected();
3760 SetIsCrashed(status, error_code); 3783 SetIsCrashed(status, error_code);
3761 3784
3762 // Reset the loading progress. TODO(avi): What does it mean to have a 3785 // Reset the loading progress. TODO(avi): What does it mean to have a
3763 // "renderer crash" when there is more than one renderer process serving a 3786 // "renderer crash" when there is more than one renderer process serving a
3764 // webpage? Once this function is called at a more granular frame level, we 3787 // webpage? Once this function is called at a more granular frame level, we
3765 // probably will need to more granularly reset the state here. 3788 // probably will need to more granularly reset the state here.
3766 ResetLoadProgressState(); 3789 ResetLoadProgressState();
3767 loading_frames_in_progress_ = 0;
3768 3790
3769 FOR_EACH_OBSERVER(WebContentsObserver, 3791 FOR_EACH_OBSERVER(WebContentsObserver,
3770 observers_, 3792 observers_,
3771 RenderProcessGone(GetCrashedStatus())); 3793 RenderProcessGone(GetCrashedStatus()));
3772 } 3794 }
3773 3795
3774 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) { 3796 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) {
3775 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewDeleted(rvh)); 3797 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewDeleted(rvh));
3776 } 3798 }
3777 3799
(...skipping 778 matching lines...) Expand 10 before | Expand all | Expand 10 after
4556 node->render_manager()->ResumeResponseDeferredAtStart(); 4578 node->render_manager()->ResumeResponseDeferredAtStart();
4557 } 4579 }
4558 4580
4559 void WebContentsImpl::SetForceDisableOverscrollContent(bool force_disable) { 4581 void WebContentsImpl::SetForceDisableOverscrollContent(bool force_disable) {
4560 force_disable_overscroll_content_ = force_disable; 4582 force_disable_overscroll_content_ = force_disable;
4561 if (view_) 4583 if (view_)
4562 view_->SetOverscrollControllerEnabled(CanOverscrollContent()); 4584 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
4563 } 4585 }
4564 4586
4565 } // namespace content 4587 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/web_contents/web_contents_impl.h ('k') | content/browser/web_contents/web_contents_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698