OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 there is a BeforeUnload event while the |
clamy
2015/03/10 13:49:10
I thought the problem was doing a history navigati
Fabrice (no longer in Chrome)
2015/03/10 14:44:18
Yes that's what happens, clarified the comment.
| |
2891 // - With "swappedout://" URLs, this happens when a RenderView gets swapped | 2924 // LoadEvent has not completed. |
2892 // out for a cross-process navigation, and it turns into a placeholder for | 2925 // TODO(fdegans): Refactor tracking of LoadEventProgress in Blink. |
2893 // one being rendered in a different process. | 2926 if (rfh->is_loading()) { |
2894 // - Also, there might be more than one RenderFrameHost sharing the same | 2927 LOG(WARNING) << "OnDidStartLoading was called twice."; |
2895 // FrameTreeNode (and thus sharing its ID) each sending a start. | |
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; | 2928 return; |
2929 } | |
2903 | 2930 |
2904 DCHECK_GE(loading_frames_in_progress_, 0); | 2931 if (!IsFrameTreeLoading(frame_tree_)) |
2905 if (loading_frames_in_progress_ == 0) | |
2906 DidStartLoading(rfh, to_different_document); | 2932 DidStartLoading(rfh, to_different_document); |
2907 | 2933 |
2908 ++loading_frames_in_progress_; | 2934 rfh->set_is_loading(true); |
2909 rfh->frame_tree_node()->set_is_loading(true); | 2935 rfh->set_loading_progress(RenderFrameHostImpl::kLoadingProgressMinimum); |
2910 | 2936 |
2911 // Notify the RenderFrameHostManager of the event. | 2937 // Notify the RenderFrameHostManager of the event. |
2912 rfh->frame_tree_node()->render_manager()->OnDidStartLoading(); | 2938 rfh->frame_tree_node()->render_manager()->OnDidStartLoading(); |
2913 | 2939 |
2914 loading_progresses_[render_frame_id] = kMinimumLoadingProgress; | |
2915 SendLoadProgressChanged(); | 2940 SendLoadProgressChanged(); |
2916 } | 2941 } |
2917 | 2942 |
2918 void WebContentsImpl::OnDidStopLoading() { | 2943 void WebContentsImpl::OnDidStopLoading() { |
2919 if (!HasValidFrameSource()) | 2944 if (!HasValidFrameSource()) |
2920 return; | 2945 return; |
2921 | 2946 |
2922 RenderFrameHostImpl* rfh = | 2947 RenderFrameHostImpl* rfh = |
2923 static_cast<RenderFrameHostImpl*>(render_frame_message_source_); | 2948 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 | 2949 |
2927 if (loading_progresses_.find(render_frame_id) != loading_progresses_.end()) { | 2950 // 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 | 2951 // Unfortunately, it can happen if there is a BeforeUnload event while the |
2929 // progress based on this frame's completion. | 2952 // LoadEvent has not completed. |
2930 loading_progresses_[render_frame_id] = 1.0; | 2953 // TODO(fdegans): Refactor tracking of LoadEventProgress in Blink. |
2931 SendLoadProgressChanged(); | 2954 if (!rfh->is_loading()) { |
2932 // Then we clean-up our states. | 2955 LOG(WARNING) << "OnDidStopLoading was called twice."; |
2933 if (loading_total_progress_ == 1.0) | 2956 return; |
2934 ResetLoadProgressState(); | |
2935 } | 2957 } |
2936 | 2958 |
2959 rfh->set_is_loading(false); | |
2960 rfh->set_loading_progress(RenderFrameHostImpl::kLoadingProgressDone); | |
2961 | |
2962 // Update progress based on this frame's completion. | |
2963 SendLoadProgressChanged(); | |
2964 | |
2965 // Then clean-up the states. | |
2966 if (loading_total_progress_ == 1.0) | |
2967 ResetLoadProgressState(); | |
2968 | |
2937 // Notify the RenderFrameHostManager of the event. | 2969 // Notify the RenderFrameHostManager of the event. |
2938 rfh->frame_tree_node()->render_manager()->OnDidStopLoading(); | 2970 rfh->frame_tree_node()->render_manager()->OnDidStopLoading(); |
2939 | 2971 |
2940 // TODO(japhet): This should be a DCHECK, but the pdf plugin sometimes | 2972 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); | 2973 DidStopLoading(rfh); |
2947 } | 2974 } |
2948 | 2975 |
2949 void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) { | 2976 void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) { |
2950 if (!HasValidFrameSource()) | 2977 if (!HasValidFrameSource()) |
2951 return; | 2978 return; |
2952 | 2979 |
2953 RenderFrameHostImpl* rfh = | 2980 RenderFrameHostImpl* rfh = |
2954 static_cast<RenderFrameHostImpl*>(render_frame_message_source_); | 2981 static_cast<RenderFrameHostImpl*>(render_frame_message_source_); |
2955 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id(); | |
2956 | 2982 |
2957 loading_progresses_[render_frame_id] = load_progress; | 2983 rfh->set_loading_progress(load_progress); |
2958 | 2984 |
2959 // We notify progress change immediately for the first and last updates. | 2985 // 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 | 2986 // 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 | 2987 // 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. | 2988 // immediately send progress report if enough time has passed. |
2963 base::TimeDelta min_delay = | 2989 base::TimeDelta min_delay = |
2964 base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS); | 2990 base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS); |
2965 if (load_progress == 1.0 || loading_last_progress_update_.is_null() || | 2991 if (load_progress == 1.0 || loading_last_progress_update_.is_null() || |
2966 base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) { | 2992 base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) { |
2967 // If there is a pending task to send progress, it is now obsolete. | 2993 // 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 Loading... | |
3432 Details<std::pair<NavigationEntry*, bool> >(&details)); | 3458 Details<std::pair<NavigationEntry*, bool> >(&details)); |
3433 | 3459 |
3434 return true; | 3460 return true; |
3435 } | 3461 } |
3436 | 3462 |
3437 void WebContentsImpl::SendLoadProgressChanged() { | 3463 void WebContentsImpl::SendLoadProgressChanged() { |
3438 loading_last_progress_update_ = base::TimeTicks::Now(); | 3464 loading_last_progress_update_ = base::TimeTicks::Now(); |
3439 double progress = 0.0; | 3465 double progress = 0.0; |
3440 int frame_count = 0; | 3466 int frame_count = 0; |
3441 | 3467 |
3442 for (LoadingProgressMap::iterator it = loading_progresses_.begin(); | 3468 frame_tree_.ForEach( |
3443 it != loading_progresses_.end(); | 3469 base::Bind(&CollectLoadProgress, &progress, &frame_count)); |
3444 ++it) { | 3470 if (frame_count != 0) |
3445 progress += it->second; | 3471 progress /= frame_count; |
3446 ++frame_count; | 3472 DCHECK_LE(progress, 1.0); |
3447 } | |
3448 if (frame_count == 0) | |
3449 return; | |
3450 progress /= frame_count; | |
3451 DCHECK(progress <= 1.0); | |
3452 | 3473 |
3453 if (progress <= loading_total_progress_) | 3474 if (progress <= loading_total_progress_) |
3454 return; | 3475 return; |
3455 loading_total_progress_ = progress; | 3476 loading_total_progress_ = progress; |
3456 | 3477 |
3457 if (delegate_) | 3478 if (delegate_) |
3458 delegate_->LoadProgressChanged(this, progress); | 3479 delegate_->LoadProgressChanged(this, progress); |
3459 } | 3480 } |
3460 | 3481 |
3461 void WebContentsImpl::ResetLoadProgressState() { | 3482 void WebContentsImpl::ResetLoadProgressState() { |
3462 loading_progresses_.clear(); | 3483 frame_tree_.ForEach(base::Bind(&ResetLoadProgress)); |
3463 loading_total_progress_ = 0.0; | 3484 loading_total_progress_ = 0.0; |
3464 loading_weak_factory_.InvalidateWeakPtrs(); | 3485 loading_weak_factory_.InvalidateWeakPtrs(); |
3465 loading_last_progress_update_ = base::TimeTicks(); | 3486 loading_last_progress_update_ = base::TimeTicks(); |
3466 } | 3487 } |
3467 | 3488 |
3468 void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host, | 3489 void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host, |
3469 RenderViewHost* new_host) { | 3490 RenderViewHost* new_host) { |
3470 // After sending out a swap notification, we need to send a disconnect | 3491 // 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 | 3492 // notification so that clients that pick up a pointer to |this| can NULL the |
3472 // pointer. See Bug 1230284. | 3493 // pointer. See Bug 1230284. |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3757 | 3778 |
3758 SetIsLoading(rvh, false, true, NULL); | 3779 SetIsLoading(rvh, false, true, NULL); |
3759 NotifyDisconnected(); | 3780 NotifyDisconnected(); |
3760 SetIsCrashed(status, error_code); | 3781 SetIsCrashed(status, error_code); |
3761 | 3782 |
3762 // Reset the loading progress. TODO(avi): What does it mean to have a | 3783 // 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 | 3784 // "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 | 3785 // webpage? Once this function is called at a more granular frame level, we |
3765 // probably will need to more granularly reset the state here. | 3786 // probably will need to more granularly reset the state here. |
3766 ResetLoadProgressState(); | 3787 ResetLoadProgressState(); |
3767 loading_frames_in_progress_ = 0; | |
3768 | 3788 |
3769 FOR_EACH_OBSERVER(WebContentsObserver, | 3789 FOR_EACH_OBSERVER(WebContentsObserver, |
3770 observers_, | 3790 observers_, |
3771 RenderProcessGone(GetCrashedStatus())); | 3791 RenderProcessGone(GetCrashedStatus())); |
3772 } | 3792 } |
3773 | 3793 |
3774 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) { | 3794 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) { |
3775 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewDeleted(rvh)); | 3795 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewDeleted(rvh)); |
3776 } | 3796 } |
3777 | 3797 |
(...skipping 778 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4556 node->render_manager()->ResumeResponseDeferredAtStart(); | 4576 node->render_manager()->ResumeResponseDeferredAtStart(); |
4557 } | 4577 } |
4558 | 4578 |
4559 void WebContentsImpl::SetForceDisableOverscrollContent(bool force_disable) { | 4579 void WebContentsImpl::SetForceDisableOverscrollContent(bool force_disable) { |
4560 force_disable_overscroll_content_ = force_disable; | 4580 force_disable_overscroll_content_ = force_disable; |
4561 if (view_) | 4581 if (view_) |
4562 view_->SetOverscrollControllerEnabled(CanOverscrollContent()); | 4582 view_->SetOverscrollControllerEnabled(CanOverscrollContent()); |
4563 } | 4583 } |
4564 | 4584 |
4565 } // namespace content | 4585 } // namespace content |
OLD | NEW |