Chromium Code Reviews| Index: content/browser/web_contents/web_contents_impl.cc |
| diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc |
| index b02984b877e81175d44226033125e7bff05f4c42..873475ff41c78a899c72869512ca806b1ccc28bd 100644 |
| --- a/content/browser/web_contents/web_contents_impl.cc |
| +++ b/content/browser/web_contents/web_contents_impl.cc |
| @@ -160,6 +160,12 @@ |
| namespace content { |
| namespace { |
| +const int kMinimumDelayBetweenLoadingUpdatesMS = 100; |
| + |
| +// This matches what Blink's ProgressTracker has traditionally used for a |
| +// minimum progress value. |
| +const double kMinimumLoadingProgress = 0.1; |
| + |
| const char kDotGoogleDotCom[] = ".google.com"; |
| #if defined(OS_ANDROID) |
| @@ -332,6 +338,9 @@ WebContentsImpl::WebContentsImpl( |
| crashed_error_code_(0), |
| waiting_for_response_(false), |
| load_state_(net::LOAD_STATE_IDLE, base::string16()), |
| + loading_total_progress_(0.0), |
| + loading_weak_factory_(this), |
| + loading_frames_in_progress_(0), |
| upload_size_(0), |
| upload_position_(0), |
| displayed_insecure_content_(false), |
| @@ -502,6 +511,10 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host, |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishDocumentLoad, |
| OnDocumentLoadedInFrame) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishLoad, OnDidFinishLoad) |
| + IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartLoading, OnDidStartLoading) |
| + IPC_MESSAGE_HANDLER(FrameHostMsg_DidStopLoading, OnDidStopLoading) |
| + IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeLoadProgress, |
| + OnDidChangeLoadProgress) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_OpenColorChooser, OnOpenColorChooser) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_EndColorChooser, OnEndColorChooser) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_SetSelectedColorInColorChooser, |
| @@ -2318,8 +2331,6 @@ void WebContentsImpl::DidStartProvisionalLoad( |
| bool is_error_page, |
| bool is_iframe_srcdoc) { |
| bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame(); |
| - if (is_main_frame) |
| - DidChangeLoadProgress(0); |
| // Notify observers about the start of the provisional load. |
| int render_frame_id = render_frame_host->GetRoutingID(); |
| @@ -2624,6 +2635,86 @@ void WebContentsImpl::OnDidFinishLoad( |
| is_main_frame, render_view_host)); |
| } |
| +void WebContentsImpl::OnDidStartLoading(bool to_different_document) { |
| + RenderFrameHostImpl* rfh = |
| + static_cast<RenderFrameHostImpl*>(render_frame_message_source_); |
| + int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id(); |
| + |
| + // It is possible for a frame to make multiple calls to OnDidStartLoading |
|
nasko
2014/05/16 22:19:46
nit: It will be nice to qualify "frame" here to di
Avi (use Gerrit)
2014/05/16 23:29:59
Rewritten; please verify.
|
| + // without calling OnDidStopLoading. (This happens when a RenderView gets |
| + // swapped out for a cross-process navigation, and it turns into a placeholder |
| + // for one being rendered in a different process.) TODO(avi): Once |
| + // "swappedout://" URLs go away and Camille moves navigation network requests |
|
nasko
2014/05/16 22:19:46
nit: If a specific person is mentioned, shouldn't
Avi (use Gerrit)
2014/05/16 23:29:59
Done.
|
| + // to the browser process, this should no longer happen; update this code to |
| + // not allow this case. |
| + DCHECK_GE(loading_frames_in_progress_, 0); |
| + if (loading_progresses_.find(render_frame_id) == loading_progresses_.end()) { |
| + if (loading_frames_in_progress_ == 0) |
| + DidStartLoading(rfh, to_different_document); |
| + ++loading_frames_in_progress_; |
| + } |
| + |
| + loading_progresses_[render_frame_id] = kMinimumLoadingProgress; |
| + SendLoadProgressChanged(); |
| +} |
| + |
| +void WebContentsImpl::OnDidStopLoading() { |
| + RenderFrameHostImpl* rfh = |
| + static_cast<RenderFrameHostImpl*>(render_frame_message_source_); |
| + int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id(); |
| + |
| + if (loading_progresses_.find(render_frame_id) != loading_progresses_.end()) { |
| + // Load stopped while we were still tracking load. Make sure we update |
| + // progress based on this frame's completion. |
| + loading_progresses_[render_frame_id] = 1.0; |
| + SendLoadProgressChanged(); |
| + // Then we clean-up our states. |
| + if (loading_total_progress_ == 1.0) |
| + ResetLoadProgressState(); |
| + } |
| + |
| + // TODO(japhet): This should be a DCHECK, but the pdf plugin sometimes |
| + // calls DidStopLoading() without a matching DidStartLoading(). |
| + if (loading_frames_in_progress_ == 0) |
| + return; |
| + --loading_frames_in_progress_; |
| + if (loading_frames_in_progress_ == 0) |
| + DidStopLoading(rfh); |
| +} |
| + |
| +void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) { |
| + RenderFrameHostImpl* rfh = |
| + static_cast<RenderFrameHostImpl*>(render_frame_message_source_); |
| + int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id(); |
| + |
| + loading_progresses_[render_frame_id] = load_progress; |
| + |
| + // We notify progress change immediately for the first and last updates. |
| + // Also, since the message loop may be pretty busy when a page is loaded, it |
| + // might not execute a posted task in a timely manner so we make sure to |
| + // immediately send progress report if enough time has passed. |
| + base::TimeDelta min_delay = |
| + base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS); |
| + if (load_progress == 1.0 || loading_last_progress_update_.is_null() || |
| + base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) { |
| + // If there is a pending task to send progress, it is now obsolete. |
| + loading_weak_factory_.InvalidateWeakPtrs(); |
| + SendLoadProgressChanged(); |
| + if (loading_total_progress_ == 1.0) |
| + ResetLoadProgressState(); |
| + return; |
| + } |
| + |
| + if (loading_weak_factory_.HasWeakPtrs()) |
| + return; |
| + |
| + base::MessageLoop::current()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&WebContentsImpl::SendLoadProgressChanged, |
| + loading_weak_factory_.GetWeakPtr()), |
| + min_delay); |
| +} |
| + |
| void WebContentsImpl::OnGoToEntryAtOffset(int offset) { |
| if (!delegate_ || delegate_->OnGoToEntryOffset(offset)) |
| controller_.GoToOffset(offset); |
| @@ -3009,6 +3100,37 @@ bool WebContentsImpl::UpdateTitleForEntry(NavigationEntryImpl* entry, |
| return true; |
| } |
| +void WebContentsImpl::SendLoadProgressChanged() { |
| + loading_last_progress_update_ = base::TimeTicks::Now(); |
| + double progress = 0.0; |
| + int frame_count = 0; |
| + |
| + for (LoadingProgressMap::iterator it = loading_progresses_.begin(); |
| + it != loading_progresses_.end(); |
| + ++it) { |
| + progress += it->second; |
| + ++frame_count; |
| + } |
| + if (frame_count == 0) |
| + return; |
| + progress /= frame_count; |
| + DCHECK(progress <= 1.0); |
| + |
| + if (progress <= loading_total_progress_) |
| + return; |
| + loading_total_progress_ = progress; |
| + |
| + if (delegate_) |
| + delegate_->LoadProgressChanged(this, progress); |
| +} |
| + |
| +void WebContentsImpl::ResetLoadProgressState() { |
| + loading_progresses_.clear(); |
| + loading_total_progress_ = 0.0; |
| + loading_weak_factory_.InvalidateWeakPtrs(); |
| + loading_last_progress_update_ = base::TimeTicks(); |
| +} |
| + |
| void WebContentsImpl::NotifySwapped(RenderViewHost* old_host, |
| RenderViewHost* new_host) { |
| // After sending out a swap notification, we need to send a disconnect |
| @@ -3289,6 +3411,12 @@ void WebContentsImpl::RenderViewTerminated(RenderViewHost* rvh, |
| NotifyDisconnected(); |
| SetIsCrashed(status, error_code); |
| + // Reset the loading progress. TODO(avi): What does it mean to have a |
|
Charlie Reis
2014/05/16 23:13:45
Yeah, leaving this as a TODO is fine for now, but
|
| + // "renderer crash" when there is more than one renderer process serving a |
| + // webpage? |
| + ResetLoadProgressState(); |
| + loading_frames_in_progress_ = 0; |
| + |
| #if defined(OS_ANDROID) |
| if (GetRenderViewHostImpl()->media_player_manager()) |
| GetRenderViewHostImpl()->media_player_manager()->DestroyAllMediaPlayers(); |
| @@ -3408,11 +3536,6 @@ void WebContentsImpl::DidCancelLoading() { |
| NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); |
| } |
| -void WebContentsImpl::DidChangeLoadProgress(double progress) { |
| - if (delegate_) |
| - delegate_->LoadProgressChanged(this, progress); |
| -} |
| - |
| void WebContentsImpl::DidAccessInitialDocument() { |
| has_accessed_initial_document_ = true; |