diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-05-15 13:56:58 +0200 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@qt.io> | 2017-07-11 13:20:14 +0000 |
commit | c99afcd115268e2b864cc9f2be0a25e84c6565ca (patch) | |
tree | f09b676286170641e29d6dad8b1989d301dad69d | |
parent | 2d14bca522d164901e316b8a39c5e4f999cf2ea3 (diff) |
(Reland) Discard compositor frames from unloaded web content
This is a reland of https://codereview.chromium.org/2707243005/ with a
small change to fix an uninitialized memory error that fails on MSAN
bots.
BUG=672847,648117
TBR=danakj@chromium.org, creis@chromium.org
CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_site_isolation
Review-Url: https://codereview.chromium.org/2731283003
Cr-Commit-Position: refs/heads/master@{#454954}
(cherry picked from commit 5d78b84d39bd34bc9fce9d01c0dcd5a22a330d34)
Change-Id: I5552a8bd1af7581b695abeddc94b2e13f9015069
Review-Url: https://codereview.chromium.org/2793013002 .
Cr-Commit-Position: refs/branch-heads/3029@{#547}
Cr-Branched-From: 939b32ee5ba05c396eef3fd992822fcca9a2e262-refs/heads/master@{#454471}
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r-- | chromium/cc/output/compositor_frame_metadata.h | 6 | ||||
-rw-r--r-- | chromium/cc/trees/layer_tree_host.cc | 12 | ||||
-rw-r--r-- | chromium/cc/trees/layer_tree_host.h | 5 | ||||
-rw-r--r-- | chromium/cc/trees/layer_tree_host_impl.cc | 1 | ||||
-rw-r--r-- | chromium/cc/trees/layer_tree_impl.cc | 3 | ||||
-rw-r--r-- | chromium/cc/trees/layer_tree_impl.h | 5 | ||||
-rw-r--r-- | chromium/content/browser/frame_host/render_frame_host_impl.cc | 2 | ||||
-rw-r--r-- | chromium/content/browser/renderer_host/render_widget_host_impl.cc | 12 | ||||
-rw-r--r-- | chromium/content/browser/renderer_host/render_widget_host_impl.h | 15 | ||||
-rw-r--r-- | chromium/content/common/cc_messages.h | 1 | ||||
-rw-r--r-- | chromium/content/common/frame_messages.h | 5 | ||||
-rw-r--r-- | chromium/content/renderer/gpu/render_widget_compositor.cc | 4 | ||||
-rw-r--r-- | chromium/content/renderer/gpu/render_widget_compositor.h | 1 | ||||
-rw-r--r-- | chromium/content/renderer/render_frame_impl.cc | 4 | ||||
-rw-r--r-- | chromium/content/renderer/render_widget.cc | 13 | ||||
-rw-r--r-- | chromium/content/renderer/render_widget.h | 16 |
16 files changed, 98 insertions, 7 deletions
diff --git a/chromium/cc/output/compositor_frame_metadata.h b/chromium/cc/output/compositor_frame_metadata.h index ad3cdd8d428..97d6862546c 100644 --- a/chromium/cc/output/compositor_frame_metadata.h +++ b/chromium/cc/output/compositor_frame_metadata.h @@ -63,6 +63,12 @@ class CC_EXPORT CompositorFrameMetadata { // This is the set of Surfaces that are referenced by this frame. std::vector<SurfaceId> referenced_surfaces; + + // This is a value that allows the browser to associate compositor frames + // with the content that they represent -- typically top-level page loads. + // TODO(kenrb, fsamuel): This should eventually by SurfaceID, when they + // become available in all renderer processes. See https://crbug.com/695579. + uint32_t content_source_id = 0; }; } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc index cb9619b1eba..686a1bb7424 100644 --- a/chromium/cc/trees/layer_tree_host.cc +++ b/chromium/cc/trees/layer_tree_host.cc @@ -133,6 +133,7 @@ LayerTreeHost::LayerTreeHost(InitParams* params, CompositorMode mode) device_scale_factor_(1.f), painted_device_scale_factor_(1.f), visible_(false), + content_source_id_(0), page_scale_factor_(1.f), min_page_scale_factor_(1.f), max_page_scale_factor_(1.f), @@ -363,6 +364,9 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) { sync_tree->SetDeviceScaleFactor(device_scale_factor_); sync_tree->set_painted_device_scale_factor(painted_device_scale_factor_); host_impl->SetDebugState(debug_state_); + + sync_tree->set_content_source_id(content_source_id_); + if (pending_page_scale_animation_) { sync_tree->SetPendingPageScaleAnimation( std::move(pending_page_scale_animation_)); @@ -516,6 +520,14 @@ void LayerTreeHost::SetNeedsDisplayOnAllLayers() { } } +void LayerTreeHost::SetContentSourceId(uint32_t id) { + if (content_source_id_ == id) + return; + content_source_id_ = id; + SetNeedsCommit(); +} + + const RendererCapabilities& LayerTreeHost::GetRendererCapabilities() const { return proxy_->GetRendererCapabilities(); } diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h index d8eba8d1073..554146fa07a 100644 --- a/chromium/cc/trees/layer_tree_host.h +++ b/chromium/cc/trees/layer_tree_host.h @@ -253,6 +253,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void SetDeviceScaleFactor(float device_scale_factor); void SetPaintedDeviceScaleFactor(float painted_device_scale_factor); + void SetContentSourceId(uint32_t); + uint32_t content_source_id() const { return content_source_id_; } + float device_scale_factor() const { return device_scale_factor_; } void UpdateTopControlsState(TopControlsState constraints, @@ -492,6 +495,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { bool visible_; + uint32_t content_source_id_; + float page_scale_factor_; float min_page_scale_factor_; float max_page_scale_factor_; diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc index 7446a69daa5..cbab911e4f5 100644 --- a/chromium/cc/trees/layer_tree_host_impl.cc +++ b/chromium/cc/trees/layer_tree_host_impl.cc @@ -1620,6 +1620,7 @@ CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const { metadata.location_bar_content_translation = gfx::Vector2dF(0.f, top_controls_manager_->ContentTopOffset()); metadata.root_background_color = active_tree_->background_color(); + metadata.content_source_id = active_tree_->content_source_id(); active_tree_->GetViewportSelection(&metadata.selection); diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc index c16792c1b2f..7ffc22a3460 100644 --- a/chromium/cc/trees/layer_tree_impl.cc +++ b/chromium/cc/trees/layer_tree_impl.cc @@ -78,6 +78,7 @@ LayerTreeImpl::LayerTreeImpl( max_page_scale_factor_(0), device_scale_factor_(1.f), painted_device_scale_factor_(1.f), + content_source_id_(0), elastic_overscroll_(elastic_overscroll), viewport_size_invalid_(false), needs_update_draw_properties_(true), @@ -340,6 +341,8 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { target_tree->set_painted_device_scale_factor(painted_device_scale_factor()); target_tree->elastic_overscroll()->PushPendingToActive(); + target_tree->set_content_source_id(content_source_id()); + target_tree->pending_page_scale_animation_ = std::move(pending_page_scale_animation_); diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h index 91e346686d1..ffbe6736838 100644 --- a/chromium/cc/trees/layer_tree_impl.h +++ b/chromium/cc/trees/layer_tree_impl.h @@ -229,6 +229,9 @@ class CC_EXPORT LayerTreeImpl { return painted_device_scale_factor_; } + void set_content_source_id(uint32_t id) { content_source_id_ = id; } + uint32_t content_source_id() { return content_source_id_; } + SyncedElasticOverscroll* elastic_overscroll() { return elastic_overscroll_.get(); } @@ -480,6 +483,8 @@ class CC_EXPORT LayerTreeImpl { float device_scale_factor_; float painted_device_scale_factor_; + uint32_t content_source_id_; + scoped_refptr<SyncedElasticOverscroll> elastic_overscroll_; typedef base::hash_map<int, LayerImpl*> LayerIdMap; diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.cc b/chromium/content/browser/frame_host/render_frame_host_impl.cc index e88b0855231..fb433833520 100644 --- a/chromium/content/browser/frame_host/render_frame_host_impl.cc +++ b/chromium/content/browser/frame_host/render_frame_host_impl.cc @@ -1019,7 +1019,7 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) { if (frame_tree_node_->IsMainFrame() && GetView() && !validated_params.was_within_same_page) { RenderWidgetHostImpl::From(GetView()->GetRenderWidgetHost()) - ->StartNewContentRenderingTimeout(); + ->StartNewContentRenderingTimeout(validated_params.content_source_id); } // PlzNavigate diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.cc b/chromium/content/browser/renderer_host/render_widget_host_impl.cc index 6516e5ec903..4690ff25e65 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_impl.cc +++ b/chromium/content/browser/renderer_host/render_widget_host_impl.cc @@ -215,6 +215,7 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate, base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)), new_content_rendering_delay_( base::TimeDelta::FromMilliseconds(kNewContentRenderingDelayMs)), + current_content_source_id_(0), mouse_wheel_coalesce_timer_(new base::ElapsedTimer()), weak_factory_(this) { CHECK(delegate_); @@ -943,7 +944,8 @@ void RenderWidgetHostImpl::StopHangMonitorTimeout() { RendererIsResponsive(); } -void RenderWidgetHostImpl::StartNewContentRenderingTimeout() { +void RenderWidgetHostImpl::StartNewContentRenderingTimeout(uint32_t next_source_id) { + current_content_source_id_ = next_source_id; // It is possible for a compositor frame to arrive before the browser is // notified about the page being committed, in which case no timer is // necessary. @@ -1592,7 +1594,13 @@ bool RenderWidgetHostImpl::OnSwapCompositorFrame( if (touch_emulator_) touch_emulator_->SetDoubleTapSupportForPageEnabled(!is_mobile_optimized); - if (view_) { + // Ignore this frame if its content has already been unloaded. Source ID + // is always zero for an OOPIF because we are only concerned with displaying + // stale graphics on top-level frames. We accept frames that have a source ID + // greater than |current_content_source_id_| because in some cases the first + // compositor frame can arrive before the navigation commit message that + // updates that value. + if (view_ && frame->metadata.content_source_id >= current_content_source_id_) { view_->OnSwapCompositorFrame(output_surface_id, std::move(frame)); view_->DidReceiveRendererFrame(); } else { diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.h b/chromium/content/browser/renderer_host/render_widget_host_impl.h index d5d9d5ad654..0ad1e005df8 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_impl.h +++ b/chromium/content/browser/renderer_host/render_widget_host_impl.h @@ -275,9 +275,10 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost, // responsive. void StopHangMonitorTimeout(); - // Starts the rendering timeout, which will clear displayed graphics if - // a new compositor frame is not received before it expires. - void StartNewContentRenderingTimeout(); + // a new compositor frame is not received before it expires. This also causes + // any new compositor frames received with content_source_id less than + // |next_source_id| to be discarded. + void StartNewContentRenderingTimeout(uint32_t next_source_id); // Notification that a new compositor frame has been generated following // a page load. This stops |new_content_rendering_timeout_|, or prevents @@ -819,6 +820,14 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost, // renderer process before clearing any previously displayed content. base::TimeDelta new_content_rendering_delay_; + // This identifier tags compositor frames according to the page load with + // which they are associated, to prevent an unloaded web page from being + // drawn after a navigation to a new page has already committed. This is + // a no-op for non-top-level RenderWidgets, as that should always be zero. + // TODO(kenrb, fsamuel): We should use SurfaceIDs for this purpose when they + // are available in the renderer process. See https://crbug.com/695579. + uint32_t current_content_source_id_; + // Timer used to batch together mouse wheel events for the delegate // OnUserInteraction method. A wheel event is only dispatched when a wheel // event has not been seen for kMouseWheelCoalesceInterval seconds prior. diff --git a/chromium/content/common/cc_messages.h b/chromium/content/common/cc_messages.h index 9f2e84ece39..e61f265650e 100644 --- a/chromium/content/common/cc_messages.h +++ b/chromium/content/common/cc_messages.h @@ -319,6 +319,7 @@ IPC_STRUCT_TRAITS_BEGIN(cc::CompositorFrameMetadata) IPC_STRUCT_TRAITS_MEMBER(latency_info) IPC_STRUCT_TRAITS_MEMBER(satisfies_sequences) IPC_STRUCT_TRAITS_MEMBER(referenced_surfaces) + IPC_STRUCT_TRAITS_MEMBER(content_source_id) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(cc::GLFrameData) diff --git a/chromium/content/common/frame_messages.h b/chromium/content/common/frame_messages.h index 6fcad1a90df..2722b9905a9 100644 --- a/chromium/content/common/frame_messages.h +++ b/chromium/content/common/frame_messages.h @@ -276,6 +276,11 @@ IPC_STRUCT_BEGIN_WITH_PARENT(FrameHostMsg_DidCommitProvisionalLoad_Params, // True if the document for the load is enforcing strict mixed content // checking. IPC_STRUCT_MEMBER(bool, should_enforce_strict_mixed_content_checking) + + // This is a non-decreasing value that the browser process can use to + // identify and discard compositor frames that correspond to now-unloaded + // web content. + IPC_STRUCT_MEMBER(uint32_t, content_source_id) IPC_STRUCT_END() IPC_STRUCT_BEGIN(FrameMsg_PostMessage_Params) diff --git a/chromium/content/renderer/gpu/render_widget_compositor.cc b/chromium/content/renderer/gpu/render_widget_compositor.cc index 4048e3b6ffd..fde8cd57515 100644 --- a/chromium/content/renderer/gpu/render_widget_compositor.cc +++ b/chromium/content/renderer/gpu/render_widget_compositor.cc @@ -1135,4 +1135,8 @@ void RenderWidgetCompositor::SetPaintedDeviceScaleFactor( layer_tree_host_->SetPaintedDeviceScaleFactor(device_scale); } +void RenderWidgetCompositor::SetContentSourceId(uint32_t id) { + layer_tree_host_->SetContentSourceId(id); +} + } // namespace content diff --git a/chromium/content/renderer/gpu/render_widget_compositor.h b/chromium/content/renderer/gpu/render_widget_compositor.h index 0eac7cd9739..7f4be57a7c2 100644 --- a/chromium/content/renderer/gpu/render_widget_compositor.h +++ b/chromium/content/renderer/gpu/render_widget_compositor.h @@ -92,6 +92,7 @@ class CONTENT_EXPORT RenderWidgetCompositor cc::ManagedMemoryPolicy GetGpuMemoryPolicy( const cc::ManagedMemoryPolicy& policy); void SetPaintedDeviceScaleFactor(float device_scale); + void SetContentSourceId(uint32_t); // WebLayerTreeView implementation. void setRootLayer(const blink::WebLayer& layer) override; diff --git a/chromium/content/renderer/render_frame_impl.cc b/chromium/content/renderer/render_frame_impl.cc index 56e1adc3bf1..2daa02a6da1 100644 --- a/chromium/content/renderer/render_frame_impl.cc +++ b/chromium/content/renderer/render_frame_impl.cc @@ -3157,6 +3157,7 @@ void RenderFrameImpl::didCommitProvisionalLoad( // For new page navigations, the browser process needs to be notified of the // first paint of that page, so it can cancel the timer that waits for it. if (is_main_frame_ && !navigation_state->WasWithinSamePage()) { + GetRenderWidget()->IncrementContentSourceId(); render_view_->QueueMessage( new ViewHostMsg_DidFirstPaintAfterLoad(render_view_->routing_id_), MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE); @@ -4498,6 +4499,9 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad( params.page_state = SingleHistoryItemToPageState(item); post_id = ExtractPostId(item); } + + params.content_source_id = GetRenderWidget()->GetContentSourceId(); + params.frame_unique_name = item.target().utf8(); params.item_sequence_number = item.itemSequenceNumber(); params.document_sequence_number = item.documentSequenceNumber(); diff --git a/chromium/content/renderer/render_widget.cc b/chromium/content/renderer/render_widget.cc index 0ddaf21eee1..a5a93d209c3 100644 --- a/chromium/content/renderer/render_widget.cc +++ b/chromium/content/renderer/render_widget.cc @@ -477,7 +477,8 @@ RenderWidget::RenderWidget(CompositorDependencies* compositor_deps, popup_origin_scale_for_emulation_(0.f), frame_swap_message_queue_(new FrameSwapMessageQueue()), resizing_mode_selector_(new ResizingModeSelector()), - has_host_context_menu_location_(false) { + has_host_context_menu_location_(false), + current_content_source_id_(0) { if (!swapped_out) RenderProcess::current()->AddRefProcess(); DCHECK(RenderThread::Get()); @@ -1251,6 +1252,7 @@ void RenderWidget::initializeLayerTreeView() { compositor_ = RenderWidgetCompositor::Create(this, compositor_deps_); compositor_->setViewportSize(physical_backing_size_); OnDeviceScaleFactorChanged(); + compositor_->SetContentSourceId(current_content_source_id_); // For background pages and certain tests, we don't want to trigger // OutputSurface creation. if (compositor_never_visible_ || !RenderThreadImpl::current()) @@ -2117,6 +2119,15 @@ void RenderWidget::didUpdateTextOfFocusedElementByNonUserInput() { #endif } +uint32_t RenderWidget::GetContentSourceId() { + return current_content_source_id_; +} + +void RenderWidget::IncrementContentSourceId() { + if (compositor_) + compositor_->SetContentSourceId(++current_content_source_id_); +} + scoped_ptr<WebGraphicsContext3DCommandBufferImpl> RenderWidget::CreateGraphicsContext3D(GpuChannelHost* gpu_channel_host) { // Explicitly disable antialiasing for the compositor. As of the time of diff --git a/chromium/content/renderer/render_widget.h b/chromium/content/renderer/render_widget.h index 20d98e87de2..20e5a41ca99 100644 --- a/chromium/content/renderer/render_widget.h +++ b/chromium/content/renderer/render_widget.h @@ -342,6 +342,9 @@ class CONTENT_EXPORT RenderWidget bool host_closing() const { return host_closing_; } + uint32_t GetContentSourceId(); + void IncrementContentSourceId(); + protected: // Friend RefCounted so that the dtor can be non-public. Using this class // without ref-counting is an error. @@ -755,6 +758,19 @@ class CONTENT_EXPORT RenderWidget scoped_ptr<scheduler::RenderWidgetSchedulingState> render_widget_scheduling_state_; + // This is initialized to zero and is incremented on each non-same-page + // navigation commit by RenderFrameImpl. At that time it is sent to the + // compositor so that it can tag compositor frames, and RenderFrameImpl is + // responsible for sending it to the browser process to be used to match + // each compositor frame to the most recent page navigation before it was + // generated. + // This only applies to main frames, and is not touched for subframe + // RenderWidgets, where there is no concern around displaying unloaded + // content. + // TODO(kenrb, fsamuel): This should be removed when SurfaceIDs can be used + // to replace it. See https://crbug.com/695579. + uint32_t current_content_source_id_; + DISALLOW_COPY_AND_ASSIGN(RenderWidget); }; |