diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-08-01 12:59:39 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2016-08-04 12:40:43 +0000 |
commit | 28b1110370900897ab652cb420c371fab8857ad4 (patch) | |
tree | 41b32127d23b0df4f2add2a27e12dc87bddb260e /chromium/content/renderer | |
parent | 399c965b6064c440ddcf4015f5f8e9d131c7a0a6 (diff) | |
download | qtwebengine-chromium-28b1110370900897ab652cb420c371fab8857ad4.tar.gz |
BASELINE: Update Chromium to 53.0.2785.41
Also adds a few extra files for extensions.
Change-Id: Iccdd55d98660903331cf8b7b29188da781830af4
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/content/renderer')
321 files changed, 7052 insertions, 4912 deletions
diff --git a/chromium/content/renderer/BUILD.gn b/chromium/content/renderer/BUILD.gn index 13138ab148a..3f9286e2144 100644 --- a/chromium/content/renderer/BUILD.gn +++ b/chromium/content/renderer/BUILD.gn @@ -7,6 +7,7 @@ import("//build/config/ui.gni") import("//content/renderer/renderer.gni") import("//media/media_options.gni") import("//third_party/webrtc/build/webrtc.gni") +import("//tools/ipc_fuzzer/ipc_fuzzer.gni") source_set("renderer") { # Only the public target should depend on this. All other targets (even @@ -51,19 +52,19 @@ source_set("renderer") { "//device/bluetooth", "//device/usb/public/interfaces", "//device/vibration:mojo_bindings", + "//device/vr:mojo_bindings", "//gin", "//gpu", "//gpu/command_buffer/client:gles2_interface", - "//ipc/mojo", "//jingle:jingle_glue", "//media", "//media/blink", + "//media/capture", "//media/gpu", "//media/gpu/ipc/client", "//media/gpu/ipc/common", "//media/midi", "//mojo/common", - "//mojo/converters/geometry", "//mojo/edk/js", "//mojo/public/cpp/bindings", "//mojo/public/js", @@ -72,7 +73,6 @@ source_set("renderer") { "//services/shell/public/cpp", "//services/shell/public/interfaces", "//skia", - "//skia/public", "//storage/common", "//third_party/WebKit/public:blink", "//third_party/WebKit/public:mojo_bindings", @@ -89,6 +89,7 @@ source_set("renderer") { "//ui/events:dom_keycode_converter", "//ui/events:events_base", "//ui/events/blink", + "//ui/gfx/geometry/mojo", "//ui/gl", "//ui/native_theme", "//ui/surface", @@ -99,25 +100,24 @@ source_set("renderer") { if (use_aura) { public_deps += [ "//content/renderer/mus" ] allow_circular_includes_from += [ "//content/renderer/mus" ] + deps += [ "//components/mus/common:mus_common" ] } - if (is_mac) { - sources -= [ - "webscrollbarbehavior_impl_gtkoraura.cc", - "webscrollbarbehavior_impl_gtkoraura.h", - ] + if (use_external_popup_menu) { sources += [ "external_popup_menu.cc", "external_popup_menu.h", ] } - if (is_android) { - sources += [ - "external_popup_menu.cc", - "external_popup_menu.h", + if (is_mac) { + sources -= [ + "webscrollbarbehavior_impl_gtkoraura.cc", + "webscrollbarbehavior_impl_gtkoraura.h", ] + } + if (is_android) { # Add back the Linux file which Android shares. set_sources_assignment_filter([]) sources += [ "render_view_linux.cc" ] @@ -240,7 +240,7 @@ source_set("renderer") { "//media/mojo/interfaces", # Defines in mojo_media_config are also pulled in here. - "//media/mojo/services:proxy", + "//media/mojo/clients", ] } @@ -251,6 +251,10 @@ source_set("renderer") { if (use_ozone) { deps += [ "//ui/ozone" ] } + + if (enable_ipc_fuzzer) { + configs += [ "//tools/ipc_fuzzer:ipc_fuzzer_config" ] + } } # See comment at the top of //content/BUILD.gn for how this works. diff --git a/chromium/content/renderer/DEPS b/chromium/content/renderer/DEPS index 4a800d455d1..3ea84f5c94a 100644 --- a/chromium/content/renderer/DEPS +++ b/chromium/content/renderer/DEPS @@ -1,6 +1,7 @@ include_rules = [ - # Allow inclusion of specific components that we depend on. We may only - # depend on components which we share with the mojo html_viewer. + # Allow inclusion of specific components that we depend on. + # See comment in content/DEPS for which components are allowed. + "+components/mus/common", "+components/mus/public", "+components/scheduler", "+components/url_formatter", diff --git a/chromium/content/renderer/accessibility/blink_ax_enum_conversion.cc b/chromium/content/renderer/accessibility/blink_ax_enum_conversion.cc index ff82c5669af..02e85a92856 100644 --- a/chromium/content/renderer/accessibility/blink_ax_enum_conversion.cc +++ b/chromium/content/renderer/accessibility/blink_ax_enum_conversion.cc @@ -405,6 +405,19 @@ ui::AXEvent AXEventFromBlink(blink::WebAXEvent event) { } } +ui::AXMarkerType AXMarkerTypeFromBlink(blink::WebAXMarkerType marker_type) { + switch (marker_type) { + case blink::WebAXMarkerTypeSpelling: + return ui::AX_MARKER_TYPE_SPELLING; + case blink::WebAXMarkerTypeGrammar: + return ui::AX_MARKER_TYPE_GRAMMAR; + case blink::WebAXMarkerTypeTextMatch: + return ui::AX_MARKER_TYPE_TEXT_MATCH; + } + NOTREACHED(); + return ui::AX_MARKER_TYPE_NONE; +} + ui::AXTextDirection AXTextDirectionFromBlink( blink::WebAXTextDirection text_direction) { switch (text_direction) { @@ -416,10 +429,8 @@ ui::AXTextDirection AXTextDirectionFromBlink( return ui::AX_TEXT_DIRECTION_TTB; case blink::WebAXTextDirectionBT: return ui::AX_TEXT_DIRECTION_BTT; - default: - NOTREACHED(); } - + NOTREACHED(); return ui::AX_TEXT_DIRECTION_NONE; } @@ -477,7 +488,6 @@ ui::AXInvalidState AXInvalidStateFromBlink( case blink::WebAXInvalidStateOther: return ui::AX_INVALID_STATE_OTHER; } - NOTREACHED(); return ui::AX_INVALID_STATE_NONE; } @@ -495,10 +505,8 @@ ui::AXSortDirection AXSortDirectionFromBlink( return ui::AX_SORT_DIRECTION_DESCENDING; case blink::WebAXSortDirectionOther: return ui::AX_SORT_DIRECTION_OTHER; - default: - NOTREACHED(); } - + NOTREACHED(); return ui::AX_SORT_DIRECTION_NONE; } @@ -520,11 +528,9 @@ ui::AXNameFrom AXNameFromFromBlink(blink::WebAXNameFrom name_from) { return ui::AX_NAME_FROM_VALUE; case blink::WebAXNameFromTitle: return ui::AX_NAME_FROM_ATTRIBUTE; - default: - NOTREACHED(); } - - return ui::AX_NAME_FROM_UNINITIALIZED; + NOTREACHED(); + return ui::AX_NAME_FROM_NONE; } ui::AXDescriptionFrom AXDescriptionFromFromBlink( @@ -540,11 +546,9 @@ ui::AXDescriptionFrom AXDescriptionFromFromBlink( return ui::AX_DESCRIPTION_FROM_PLACEHOLDER; case blink::WebAXDescriptionFromRelatedElement: return ui::AX_DESCRIPTION_FROM_RELATED_ELEMENT; - default: - NOTREACHED(); } - - return ui::AX_DESCRIPTION_FROM_UNINITIALIZED; + NOTREACHED(); + return ui::AX_DESCRIPTION_FROM_NONE; } } // namespace content. diff --git a/chromium/content/renderer/accessibility/blink_ax_enum_conversion.h b/chromium/content/renderer/accessibility/blink_ax_enum_conversion.h index 4342971ba74..a2e932cd337 100644 --- a/chromium/content/renderer/accessibility/blink_ax_enum_conversion.h +++ b/chromium/content/renderer/accessibility/blink_ax_enum_conversion.h @@ -24,6 +24,8 @@ ui::AXEvent AXEventFromBlink(blink::WebAXEvent event); // in AXNodeData instead.) uint32_t AXStateFromBlink(const blink::WebAXObject& o); +ui::AXMarkerType AXMarkerTypeFromBlink(blink::WebAXMarkerType marker_type); + ui::AXTextDirection AXTextDirectionFromBlink( blink::WebAXTextDirection text_direction); diff --git a/chromium/content/renderer/accessibility/blink_ax_tree_source.cc b/chromium/content/renderer/accessibility/blink_ax_tree_source.cc index cd6d2f87338..79f5324c143 100644 --- a/chromium/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/chromium/content/renderer/accessibility/blink_ax_tree_source.cc @@ -13,7 +13,7 @@ #include "base/strings/utf_string_conversions.h" #include "content/common/accessibility_messages.h" #include "content/renderer/accessibility/blink_ax_enum_conversion.h" -#include "content/renderer/accessibility/renderer_accessibility.h" +#include "content/renderer/accessibility/render_accessibility_impl.h" #include "content/renderer/browser_plugin/browser_plugin.h" #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_frame_proxy.h" @@ -133,22 +133,20 @@ bool BlinkAXTreeSource::IsInTree(blink::WebAXObject node) const { return false; } -AXContentTreeData BlinkAXTreeSource::GetTreeData() const { - AXContentTreeData tree_data; - +bool BlinkAXTreeSource::GetTreeData(AXContentTreeData* tree_data) const { blink::WebDocument document = BlinkAXTreeSource::GetMainDocument(); const blink::WebAXObject& root = GetRoot(); - tree_data.doctype = "html"; - tree_data.loaded = root.isLoaded(); - tree_data.loading_progress = root.estimatedLoadingProgress(); - tree_data.mimetype = document.isXHTMLDocument() ? "text/xhtml" : "text/html"; - tree_data.title = document.title().utf8(); - tree_data.url = document.url().string().utf8(); + tree_data->doctype = "html"; + tree_data->loaded = root.isLoaded(); + tree_data->loading_progress = root.estimatedLoadingProgress(); + tree_data->mimetype = document.isXHTMLDocument() ? "text/xhtml" : "text/html"; + tree_data->title = document.title().utf8(); + tree_data->url = document.url().string().utf8(); WebAXObject focus = document.focusedAccessibilityObject(); if (!focus.isNull()) - tree_data.focus_id = focus.axID(); + tree_data->focus_id = focus.axID(); WebAXObject anchor_object, focus_object; int anchor_offset, focus_offset; @@ -157,27 +155,27 @@ AXContentTreeData BlinkAXTreeSource::GetTreeData() const { anchor_offset >= 0 && focus_offset >= 0) { int32_t anchor_id = anchor_object.axID(); int32_t focus_id = focus_object.axID(); - tree_data.sel_anchor_object_id = anchor_id; - tree_data.sel_anchor_offset = anchor_offset; - tree_data.sel_focus_object_id = focus_id; - tree_data.sel_focus_offset = focus_offset; + tree_data->sel_anchor_object_id = anchor_id; + tree_data->sel_anchor_offset = anchor_offset; + tree_data->sel_focus_object_id = focus_id; + tree_data->sel_focus_offset = focus_offset; } // Get the tree ID for this frame and the parent frame. WebLocalFrame* web_frame = document.frame(); if (web_frame) { RenderFrame* render_frame = RenderFrame::FromWebFrame(web_frame); - tree_data.routing_id = render_frame->GetRoutingID(); + tree_data->routing_id = render_frame->GetRoutingID(); // Get the tree ID for the parent frame. blink::WebFrame* parent_web_frame = web_frame->parent(); if (parent_web_frame) { - tree_data.parent_routing_id = + tree_data->parent_routing_id = GetRoutingIdForFrameOrProxy(parent_web_frame); } } - return tree_data; + return true; } blink::WebAXObject BlinkAXTreeSource::GetRoot() const { @@ -445,6 +443,32 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src, if (src.canvasHasFallbackContent()) dst->AddBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK, true); + // Spelling, grammar and other document markers. + WebVector<blink::WebAXMarkerType> src_marker_types; + WebVector<int> src_marker_starts; + WebVector<int> src_marker_ends; + src.markers(src_marker_types, src_marker_starts, src_marker_ends); + DCHECK_EQ(src_marker_types.size(), src_marker_starts.size()); + DCHECK_EQ(src_marker_starts.size(), src_marker_ends.size()); + + if (src_marker_types.size()) { + std::vector<int32_t> marker_types; + std::vector<int32_t> marker_starts; + std::vector<int32_t> marker_ends; + marker_types.reserve(src_marker_types.size()); + marker_starts.reserve(src_marker_starts.size()); + marker_ends.reserve(src_marker_ends.size()); + for (size_t i = 0; i < src_marker_types.size(); ++i) { + marker_types.push_back( + static_cast<int32_t>(AXMarkerTypeFromBlink(src_marker_types[i]))); + marker_starts.push_back(src_marker_starts[i]); + marker_ends.push_back(src_marker_ends[i]); + } + dst->AddIntListAttribute(ui::AX_ATTR_MARKER_TYPES, marker_types); + dst->AddIntListAttribute(ui::AX_ATTR_MARKER_STARTS, marker_starts); + dst->AddIntListAttribute(ui::AX_ATTR_MARKER_ENDS, marker_ends); + } + WebNode node = src.node(); bool is_iframe = false; @@ -471,7 +495,7 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src, WebVector<int> src_line_breaks; src.lineBreaks(src_line_breaks); - if (src_line_breaks.size() > 0) { + if (src_line_breaks.size()) { std::vector<int32_t> line_breaks; line_breaks.reserve(src_line_breaks.size()); for (size_t i = 0; i < src_line_breaks.size(); ++i) @@ -525,6 +549,12 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src, dst->AddStringAttribute( ui::AX_ATTR_LIVE_RELEVANT, src.liveRegionRelevant().utf8()); + // If we are not at the root of an atomic live region. + if (src.containerLiveRegionAtomic() && !src.liveRegionRoot().isDetached() && + !src.liveRegionAtomic()) { + dst->AddIntAttribute(ui::AX_ATTR_MEMBER_OF_ID, + src.liveRegionRoot().axID()); + } dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC, src.containerLiveRegionAtomic()); dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY, diff --git a/chromium/content/renderer/accessibility/blink_ax_tree_source.h b/chromium/content/renderer/accessibility/blink_ax_tree_source.h index e7a7d4aa90f..90f7f152224 100644 --- a/chromium/content/renderer/accessibility/blink_ax_tree_source.h +++ b/chromium/content/renderer/accessibility/blink_ax_tree_source.h @@ -39,7 +39,7 @@ class BlinkAXTreeSource void set_accessibility_focus_id(int id) { accessibility_focus_id_ = id; } // AXTreeSource implementation. - AXContentTreeData GetTreeData() const override; + bool GetTreeData(AXContentTreeData* tree_data) const override; blink::WebAXObject GetRoot() const override; blink::WebAXObject GetFromId(int32_t id) const override; int32_t GetId(blink::WebAXObject node) const override; diff --git a/chromium/content/renderer/accessibility/renderer_accessibility.cc b/chromium/content/renderer/accessibility/render_accessibility_impl.cc index 9b630650233..5611c7f3182 100644 --- a/chromium/content/renderer/accessibility/renderer_accessibility.cc +++ b/chromium/content/renderer/accessibility/render_accessibility_impl.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/accessibility/renderer_accessibility.h" +#include "content/renderer/accessibility/render_accessibility_impl.h" #include <stddef.h> #include <stdint.h> @@ -25,9 +25,11 @@ #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebSettings.h" #include "third_party/WebKit/public/web/WebView.h" +#include "ui/accessibility/ax_node.h" using blink::WebAXObject; using blink::WebDocument; +using blink::WebElement; using blink::WebLocalFrame; using blink::WebNode; using blink::WebPoint; @@ -44,7 +46,7 @@ namespace content { const size_t kMaxSnapshotNodeCount = 5000; // static -void RendererAccessibility::SnapshotAccessibilityTree( +void RenderAccessibilityImpl::SnapshotAccessibilityTree( RenderFrameImpl* render_frame, AXContentTreeUpdate* response) { DCHECK(render_frame); @@ -61,11 +63,12 @@ void RendererAccessibility::SnapshotAccessibilityTree( serializer.SerializeChanges(context.root(), response); } -RendererAccessibility::RendererAccessibility(RenderFrameImpl* render_frame) +RenderAccessibilityImpl::RenderAccessibilityImpl(RenderFrameImpl* render_frame) : RenderFrameObserver(render_frame), render_frame_(render_frame), tree_source_(render_frame), serializer_(&tree_source_), + pdf_tree_source_(nullptr), last_scroll_offset_(gfx::Size()), ack_pending_(false), reset_token_(0), @@ -102,12 +105,12 @@ RendererAccessibility::RendererAccessibility(RenderFrameImpl* render_frame) } } -RendererAccessibility::~RendererAccessibility() { +RenderAccessibilityImpl::~RenderAccessibilityImpl() { } -bool RendererAccessibility::OnMessageReceived(const IPC::Message& message) { +bool RenderAccessibilityImpl::OnMessageReceived(const IPC::Message& message) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP(RendererAccessibility, message) + IPC_BEGIN_MESSAGE_MAP(RenderAccessibilityImpl, message) IPC_MESSAGE_HANDLER(AccessibilityMsg_SetFocus, OnSetFocus) IPC_MESSAGE_HANDLER(AccessibilityMsg_DoDefaultAction, OnDoDefaultAction) IPC_MESSAGE_HANDLER(AccessibilityMsg_Events_ACK, OnEventsAck) @@ -128,12 +131,12 @@ bool RendererAccessibility::OnMessageReceived(const IPC::Message& message) { return handled; } -void RendererAccessibility::HandleWebAccessibilityEvent( +void RenderAccessibilityImpl::HandleWebAccessibilityEvent( const blink::WebAXObject& obj, blink::WebAXEvent event) { HandleAXEvent(obj, AXEventFromBlink(event)); } -void RendererAccessibility::HandleAccessibilityFindInPageResult( +void RenderAccessibilityImpl::HandleAccessibilityFindInPageResult( int identifier, int match_index, const blink::WebAXObject& start_object, @@ -150,7 +153,7 @@ void RendererAccessibility::HandleAccessibilityFindInPageResult( Send(new AccessibilityHostMsg_FindInPageResult(routing_id(), params)); } -void RendererAccessibility::AccessibilityFocusedNodeChanged( +void RenderAccessibilityImpl::AccessibilityFocusedNodeChanged( const WebNode& node) { const WebDocument& document = GetMainDocument(); if (document.isNull()) @@ -163,7 +166,7 @@ void RendererAccessibility::AccessibilityFocusedNodeChanged( } } -void RendererAccessibility::DisableAccessibility() { +void RenderAccessibilityImpl::DisableAccessibility() { RenderView* render_view = render_frame_->GetRenderView(); if (!render_view) return; @@ -179,7 +182,7 @@ void RendererAccessibility::DisableAccessibility() { settings->setAccessibilityEnabled(false); } -void RendererAccessibility::HandleAXEvent( +void RenderAccessibilityImpl::HandleAXEvent( const blink::WebAXObject& obj, ui::AXEvent event) { const WebDocument& document = GetMainDocument(); if (document.isNull()) @@ -226,18 +229,55 @@ void RendererAccessibility::HandleAXEvent( // up additional events. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, - base::Bind(&RendererAccessibility::SendPendingAccessibilityEvents, + base::Bind(&RenderAccessibilityImpl::SendPendingAccessibilityEvents, weak_factory_.GetWeakPtr())); } } -WebDocument RendererAccessibility::GetMainDocument() { +int RenderAccessibilityImpl::GenerateAXID() { + WebAXObject root = tree_source_.GetRoot(); + return root.generateAXID(); +} + +void RenderAccessibilityImpl::SetPdfTreeSource( + RenderAccessibilityImpl::PdfAXTreeSource* pdf_tree_source) { + pdf_tree_source_ = pdf_tree_source; + pdf_serializer_.reset(new PdfAXTreeSerializer(pdf_tree_source_)); + + WebAXObject root = tree_source_.GetRoot(); + if (!root.updateLayoutAndCheckValidity()) + return; + + std::queue<WebAXObject> objs_to_explore; + objs_to_explore.push(root); + while (objs_to_explore.size()) { + WebAXObject obj = objs_to_explore.front(); + objs_to_explore.pop(); + + WebNode node = obj.node(); + if (!node.isNull() && node.isElementNode()) { + WebElement element = node.to<WebElement>(); + if (element.hasHTMLTagName("embed")) { + HandleAXEvent(obj, ui::AX_EVENT_CHILDREN_CHANGED); + break; + } + } + + // Explore children of this object. + std::vector<blink::WebAXObject> children; + tree_source_.GetChildren(obj, &children); + for (size_t i = 0; i < children.size(); ++i) + objs_to_explore.push(children[i]); + } +} + +WebDocument RenderAccessibilityImpl::GetMainDocument() { if (render_frame_ && render_frame_->GetWebFrame()) return render_frame_->GetWebFrame()->document(); return WebDocument(); } -void RendererAccessibility::SendPendingAccessibilityEvents() { +void RenderAccessibilityImpl::SendPendingAccessibilityEvents() { const WebDocument& document = GetMainDocument(); if (document.isNull()) return; @@ -289,6 +329,9 @@ void RendererAccessibility::SendPendingAccessibilityEvents() { continue; } + if (pdf_tree_source_) + AddPdfTreeToUpdate(&event_msg.update); + event_msgs.push_back(event_msg); // For each node in the update, set the location in our map from @@ -310,7 +353,7 @@ void RendererAccessibility::SendPendingAccessibilityEvents() { SendLocationChanges(); } -void RendererAccessibility::SendLocationChanges() { +void RenderAccessibilityImpl::SendLocationChanges() { std::vector<AccessibilityHostMsg_LocationChangeParams> messages; // Update layout on the root of the tree. @@ -356,7 +399,7 @@ void RendererAccessibility::SendLocationChanges() { Send(new AccessibilityHostMsg_LocationChanges(routing_id(), messages)); } -void RendererAccessibility::OnDoDefaultAction(int acc_obj_id) { +void RenderAccessibilityImpl::OnDoDefaultAction(int acc_obj_id) { const WebDocument& document = GetMainDocument(); if (document.isNull()) return; @@ -372,17 +415,17 @@ void RendererAccessibility::OnDoDefaultAction(int acc_obj_id) { obj.performDefaultAction(); } -void RendererAccessibility::OnEventsAck() { +void RenderAccessibilityImpl::OnEventsAck() { DCHECK(ack_pending_); ack_pending_ = false; SendPendingAccessibilityEvents(); } -void RendererAccessibility::OnFatalError() { +void RenderAccessibilityImpl::OnFatalError() { CHECK(false) << "Invalid accessibility tree."; } -void RendererAccessibility::OnHitTest(gfx::Point point) { +void RenderAccessibilityImpl::OnHitTest(gfx::Point point) { const WebDocument& document = GetMainDocument(); if (document.isNull()) return; @@ -411,7 +454,7 @@ void RendererAccessibility::OnHitTest(gfx::Point point) { HandleAXEvent(obj, ui::AX_EVENT_HOVER); } -void RendererAccessibility::OnSetAccessibilityFocus(int acc_obj_id) { +void RenderAccessibilityImpl::OnSetAccessibilityFocus(int acc_obj_id) { if (tree_source_.accessibility_focus_id() == acc_obj_id) return; @@ -431,7 +474,7 @@ void RendererAccessibility::OnSetAccessibilityFocus(int acc_obj_id) { HandleAXEvent(obj, ui::AX_EVENT_TREE_CHANGED); } -void RendererAccessibility::OnReset(int reset_token) { +void RenderAccessibilityImpl::OnReset(int reset_token) { reset_token_ = reset_token; serializer_.Reset(); pending_events_.clear(); @@ -446,7 +489,7 @@ void RendererAccessibility::OnReset(int reset_token) { } } -void RendererAccessibility::OnScrollToMakeVisible( +void RenderAccessibilityImpl::OnScrollToMakeVisible( int acc_obj_id, gfx::Rect subfocus) { const WebDocument& document = GetMainDocument(); if (document.isNull()) @@ -470,7 +513,8 @@ void RendererAccessibility::OnScrollToMakeVisible( HandleAXEvent(document.accessibilityObject(), ui::AX_EVENT_LAYOUT_COMPLETE); } -void RendererAccessibility::OnScrollToPoint(int acc_obj_id, gfx::Point point) { +void RenderAccessibilityImpl::OnScrollToPoint( + int acc_obj_id, gfx::Point point) { const WebDocument& document = GetMainDocument(); if (document.isNull()) return; @@ -492,7 +536,7 @@ void RendererAccessibility::OnScrollToPoint(int acc_obj_id, gfx::Point point) { HandleAXEvent(document.accessibilityObject(), ui::AX_EVENT_LAYOUT_COMPLETE); } -void RendererAccessibility::OnSetScrollOffset(int acc_obj_id, +void RenderAccessibilityImpl::OnSetScrollOffset(int acc_obj_id, gfx::Point offset) { const WebDocument& document = GetMainDocument(); if (document.isNull()) @@ -505,7 +549,7 @@ void RendererAccessibility::OnSetScrollOffset(int acc_obj_id, obj.setScrollOffset(WebPoint(offset.x(), offset.y())); } -void RendererAccessibility::OnSetFocus(int acc_obj_id) { +void RenderAccessibilityImpl::OnSetFocus(int acc_obj_id) { const WebDocument& document = GetMainDocument(); if (document.isNull()) return; @@ -535,7 +579,7 @@ void RendererAccessibility::OnSetFocus(int acc_obj_id) { obj.setFocused(true); } -void RendererAccessibility::OnSetSelection(int anchor_acc_obj_id, +void RenderAccessibilityImpl::OnSetSelection(int anchor_acc_obj_id, int anchor_offset, int focus_acc_obj_id, int focus_offset) { @@ -573,7 +617,7 @@ void RendererAccessibility::OnSetSelection(int anchor_acc_obj_id, HandleAXEvent(root, ui::AX_EVENT_LAYOUT_COMPLETE); } -void RendererAccessibility::OnSetValue( +void RenderAccessibilityImpl::OnSetValue( int acc_obj_id, base::string16 value) { const WebDocument& document = GetMainDocument(); @@ -592,7 +636,7 @@ void RendererAccessibility::OnSetValue( HandleAXEvent(obj, ui::AX_EVENT_VALUE_CHANGED); } -void RendererAccessibility::OnShowContextMenu(int acc_obj_id) { +void RenderAccessibilityImpl::OnShowContextMenu(int acc_obj_id) { const WebDocument& document = GetMainDocument(); if (document.isNull()) return; @@ -608,4 +652,30 @@ void RendererAccessibility::OnShowContextMenu(int acc_obj_id) { obj.showContextMenu(); } +void RenderAccessibilityImpl::OnDestruct() { + delete this; +} + +void RenderAccessibilityImpl::AddPdfTreeToUpdate(AXContentTreeUpdate* update) { + for (size_t i = 0; i < update->nodes.size(); ++i) { + if (update->nodes[i].role == ui::AX_ROLE_EMBEDDED_OBJECT) { + const ui::AXNode* root = pdf_tree_source_->GetRoot(); + update->nodes[i].child_ids.push_back(root->id()); + + ui::AXTreeUpdate pdf_update; + pdf_serializer_->SerializeChanges(root, &pdf_update); + + // We have to copy the updated nodes using a loop because we're + // converting from a generic ui::AXNodeData to a vector of its + // content-specific subclass AXContentNodeData. + size_t old_count = update->nodes.size(); + size_t new_count = pdf_update.nodes.size(); + update->nodes.resize(old_count + new_count); + for (size_t i = 0; i < new_count; ++i) + update->nodes[old_count + i] = pdf_update.nodes[i]; + break; + } + } +} + } // namespace content diff --git a/chromium/content/renderer/accessibility/renderer_accessibility.h b/chromium/content/renderer/accessibility/render_accessibility_impl.h index 91bcd553afc..f56d2add2cf 100644 --- a/chromium/content/renderer/accessibility/renderer_accessibility.h +++ b/chromium/content/renderer/accessibility/render_accessibility_impl.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_ACCESSIBILITY_RENDERER_ACCESSIBILITY_H_ -#define CONTENT_RENDERER_ACCESSIBILITY_RENDERER_ACCESSIBILITY_H_ +#ifndef CONTENT_RENDERER_ACCESSIBILITY_RENDER_ACCESSIBILITY_IMPL_H_ +#define CONTENT_RENDERER_ACCESSIBILITY_RENDER_ACCESSIBILITY_IMPL_H_ #include <vector> @@ -11,9 +11,11 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "content/common/ax_content_node_data.h" +#include "content/public/renderer/render_accessibility.h" #include "content/public/renderer/render_frame_observer.h" #include "content/renderer/accessibility/blink_ax_tree_source.h" #include "third_party/WebKit/public/web/WebAXObject.h" +#include "ui/accessibility/ax_tree.h" #include "ui/accessibility/ax_tree_serializer.h" struct AccessibilityHostMsg_EventParams; @@ -47,7 +49,9 @@ class RenderFrameImpl; // representation of that tree whenever it changes. It also handles requests // from the browser to perform accessibility actions on nodes in the tree // (e.g., change focus, or click on a button). -class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { +class CONTENT_EXPORT RenderAccessibilityImpl + : public RenderAccessibility, + RenderFrameObserver { public: // Request a one-time snapshot of the accessibility tree without // enabling accessibility if it wasn't already enabled. @@ -55,8 +59,12 @@ class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { RenderFrameImpl* render_frame, AXContentTreeUpdate* response); - explicit RendererAccessibility(RenderFrameImpl* render_frame); - ~RendererAccessibility() override; + explicit RenderAccessibilityImpl(RenderFrameImpl* render_frame); + ~RenderAccessibilityImpl() override; + + // RenderAccessibility implementation. + int GenerateAXID() override; + void SetPdfTreeSource(PdfAXTreeSource* source) override; // RenderFrameObserver implementation. bool OnMessageReceived(const IPC::Message& message) override; @@ -76,7 +84,7 @@ class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { void AccessibilityFocusedNodeChanged(const blink::WebNode& node); - // This can be called before deleting a RendererAccessibility instance due + // This can be called before deleting a RenderAccessibilityImpl instance due // to the accessibility mode changing, as opposed to during frame destruction // (when there'd be no point). void DisableAccessibility(); @@ -100,6 +108,9 @@ class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { RenderFrameImpl* render_frame_; private: + // RenderFrameObserver implementation. + void OnDestruct() override; + // Handlers for messages from the browser to the renderer. void OnDoDefaultAction(int acc_obj_id); void OnEventsAck(); @@ -118,6 +129,8 @@ class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { void OnSetValue(int acc_obj_id, base::string16 value); void OnShowContextMenu(int acc_obj_id); + void AddPdfTreeToUpdate(AXContentTreeUpdate* update); + // Events from Blink are collected until they are ready to be // sent to the browser. std::vector<AccessibilityHostMsg_EventParams> pending_events_; @@ -132,6 +145,12 @@ class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { AXContentTreeData>; BlinkAXTreeSerializer serializer_; + using PdfAXTreeSerializer = ui::AXTreeSerializer<const ui::AXNode*, + ui::AXNodeData, + ui::AXTreeData>; + std::unique_ptr<PdfAXTreeSerializer> pdf_serializer_; + PdfAXTreeSource* pdf_tree_source_; + // Current location of every object, so we can detect when it moves. base::hash_map<int, gfx::Rect> locations_; @@ -148,9 +167,9 @@ class CONTENT_EXPORT RendererAccessibility : public RenderFrameObserver { int reset_token_; // So we can queue up tasks to be executed later. - base::WeakPtrFactory<RendererAccessibility> weak_factory_; + base::WeakPtrFactory<RenderAccessibilityImpl> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(RendererAccessibility); + DISALLOW_COPY_AND_ASSIGN(RenderAccessibilityImpl); }; } // namespace content diff --git a/chromium/content/renderer/accessibility/renderer_accessibility_browsertest.cc b/chromium/content/renderer/accessibility/render_accessibility_impl_browsertest.cc index 19566520c3d..77c180742c6 100644 --- a/chromium/content/renderer/accessibility/renderer_accessibility_browsertest.cc +++ b/chromium/content/renderer/accessibility/render_accessibility_impl_browsertest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <tuple> + #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" @@ -12,7 +14,7 @@ #include "content/common/view_message_enums.h" #include "content/public/common/content_switches.h" #include "content/public/test/render_view_test.h" -#include "content/renderer/accessibility/renderer_accessibility.h" +#include "content/renderer/accessibility/render_accessibility_impl.h" #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_view_impl.h" #include "testing/gtest/include/gtest/gtest.h" @@ -27,20 +29,20 @@ using blink::WebDocument; namespace content { -class TestRendererAccessibility : public RendererAccessibility { +class TestRenderAccessibilityImpl : public RenderAccessibilityImpl { public: - explicit TestRendererAccessibility(RenderFrameImpl* render_frame) - : RendererAccessibility(render_frame) { + explicit TestRenderAccessibilityImpl(RenderFrameImpl* render_frame) + : RenderAccessibilityImpl(render_frame) { } void SendPendingAccessibilityEvents() { - RendererAccessibility::SendPendingAccessibilityEvents(); + RenderAccessibilityImpl::SendPendingAccessibilityEvents(); } }; -class RendererAccessibilityTest : public RenderViewTest { +class RenderAccessibilityImplTest : public RenderViewTest { public: - RendererAccessibilityTest() {} + RenderAccessibilityImplTest() {} RenderViewImpl* view() { return static_cast<RenderViewImpl*>(view_); @@ -73,9 +75,9 @@ class RendererAccessibilityTest : public RenderViewTest { const IPC::Message* message = sink_->GetUniqueMessageMatching(AccessibilityHostMsg_Events::ID); ASSERT_TRUE(message); - base::Tuple<std::vector<AccessibilityHostMsg_EventParams>, int> param; + std::tuple<std::vector<AccessibilityHostMsg_EventParams>, int> param; AccessibilityHostMsg_Events::Read(message, ¶m); - *param_list = base::get<0>(param); + *param_list = std::get<0>(param); } void GetLastAccEvent( @@ -95,12 +97,12 @@ class RendererAccessibilityTest : public RenderViewTest { protected: IPC::TestSink* sink_; - DISALLOW_COPY_AND_ASSIGN(RendererAccessibilityTest); + DISALLOW_COPY_AND_ASSIGN(RenderAccessibilityImplTest); }; -TEST_F(RendererAccessibilityTest, SendFullAccessibilityTreeOnReload) { - // The job of RendererAccessibility is to serialize the +TEST_F(RenderAccessibilityImplTest, SendFullAccessibilityTreeOnReload) { + // The job of RenderAccessibilityImpl is to serialize the // accessibility tree built by WebKit and send it to the browser. // When the accessibility tree changes, it tries to send only // the nodes that actually changed or were reparented. This test @@ -115,9 +117,9 @@ TEST_F(RendererAccessibilityTest, SendFullAccessibilityTreeOnReload) { "</body>"; LoadHTML(html.c_str()); - // Creating a RendererAccessibility should sent the tree to the browser. - std::unique_ptr<TestRendererAccessibility> accessibility( - new TestRendererAccessibility(frame())); + // Creating a RenderAccessibilityImpl should sent the tree to the browser. + std::unique_ptr<TestRenderAccessibilityImpl> accessibility( + new TestRenderAccessibilityImpl(frame())); accessibility->SendPendingAccessibilityEvents(); EXPECT_EQ(4, CountAccessibilityNodesSentToBrowser()); @@ -166,8 +168,8 @@ TEST_F(RendererAccessibilityTest, SendFullAccessibilityTreeOnReload) { EXPECT_EQ(4, CountAccessibilityNodesSentToBrowser()); } -TEST_F(RendererAccessibilityTest, HideAccessibilityObject) { - // Test RendererAccessibility and make sure it sends the +TEST_F(RenderAccessibilityImplTest, HideAccessibilityObject) { + // Test RenderAccessibilityImpl and make sure it sends the // proper event to the browser when an object in the tree // is hidden, but its children are not. std::string html = @@ -181,8 +183,8 @@ TEST_F(RendererAccessibilityTest, HideAccessibilityObject) { "</body>"; LoadHTML(html.c_str()); - std::unique_ptr<TestRendererAccessibility> accessibility( - new TestRendererAccessibility(frame())); + std::unique_ptr<TestRenderAccessibilityImpl> accessibility( + new TestRenderAccessibilityImpl(frame())); accessibility->SendPendingAccessibilityEvents(); EXPECT_EQ(4, CountAccessibilityNodesSentToBrowser()); @@ -209,7 +211,7 @@ TEST_F(RendererAccessibilityTest, HideAccessibilityObject) { GetLastAccEvent(&event); ASSERT_EQ(2U, event.update.nodes.size()); - // RendererAccessibility notices that 'C' is being reparented, + // RenderAccessibilityImpl notices that 'C' is being reparented, // so it clears the subtree rooted at 'A', then updates 'A' and then 'C'. EXPECT_EQ(node_a.axID(), event.update.node_id_to_clear); EXPECT_EQ(node_a.axID(), event.update.nodes[0].id); @@ -217,8 +219,8 @@ TEST_F(RendererAccessibilityTest, HideAccessibilityObject) { EXPECT_EQ(2, CountAccessibilityNodesSentToBrowser()); } -TEST_F(RendererAccessibilityTest, ShowAccessibilityObject) { - // Test RendererAccessibility and make sure it sends the +TEST_F(RenderAccessibilityImplTest, ShowAccessibilityObject) { + // Test RenderAccessibilityImpl and make sure it sends the // proper event to the browser when an object in the tree // is shown, causing its own already-visible children to be // reparented to it. @@ -233,8 +235,8 @@ TEST_F(RendererAccessibilityTest, ShowAccessibilityObject) { "</body>"; LoadHTML(html.c_str()); - std::unique_ptr<TestRendererAccessibility> accessibility( - new TestRendererAccessibility(frame())); + std::unique_ptr<TestRenderAccessibilityImpl> accessibility( + new TestRenderAccessibilityImpl(frame())); accessibility->SendPendingAccessibilityEvents(); EXPECT_EQ(3, CountAccessibilityNodesSentToBrowser()); @@ -266,8 +268,8 @@ TEST_F(RendererAccessibilityTest, ShowAccessibilityObject) { EXPECT_EQ(3, CountAccessibilityNodesSentToBrowser()); } -TEST_F(RendererAccessibilityTest, DetachAccessibilityObject) { - // Test RendererAccessibility and make sure it sends the +TEST_F(RenderAccessibilityImplTest, DetachAccessibilityObject) { + // Test RenderAccessibilityImpl and make sure it sends the // proper event to the browser when an object in the tree // is detached, but its children are not. This can happen when // a layout occurs and an anonymous render block is no longer needed. @@ -277,8 +279,8 @@ TEST_F(RendererAccessibilityTest, DetachAccessibilityObject) { "</body>"; LoadHTML(html.c_str()); - std::unique_ptr<TestRendererAccessibility> accessibility( - new TestRendererAccessibility(frame())); + std::unique_ptr<TestRenderAccessibilityImpl> accessibility( + new TestRenderAccessibilityImpl(frame())); accessibility->SendPendingAccessibilityEvents(); EXPECT_EQ(7, CountAccessibilityNodesSentToBrowser()); diff --git a/chromium/content/renderer/android/disambiguation_popup_helper.cc b/chromium/content/renderer/android/disambiguation_popup_helper.cc index 93a561f3839..19f2c563ff8 100644 --- a/chromium/content/renderer/android/disambiguation_popup_helper.cc +++ b/chromium/content/renderer/android/disambiguation_popup_helper.cc @@ -6,6 +6,8 @@ #include <stddef.h> +#include <algorithm> + #include "third_party/WebKit/public/platform/WebRect.h" #include "ui/gfx/geometry/size_conversions.h" @@ -33,23 +35,25 @@ const float kDisambiguationPopupMinScale = 2.0; // a certain clickable size after zooming float FindOptimalScaleFactor(const WebVector<WebRect>& target_rects, float total_scale) { - using std::min; - using std::max; - if (!target_rects.size()) // shall never reach + DCHECK_GT(total_scale, 0.0f); + if (!target_rects.size()) { + NOTREACHED(); return kDisambiguationPopupMinScale; - float smallest_target = min(target_rects[0].width * total_scale, - target_rects[0].height * total_scale); + } + int smallest_target = std::min(target_rects[0].width, target_rects[0].height); for (size_t i = 1; i < target_rects.size(); i++) { - smallest_target = min(smallest_target, target_rects[i].width * total_scale); - smallest_target = min(smallest_target, - target_rects[i].height * total_scale); + smallest_target = std::min( + {smallest_target, target_rects[i].width, target_rects[i].height}); } - smallest_target = max(smallest_target, 1.0f); - return min(kDisambiguationPopupMaxScale, max(kDisambiguationPopupMinScale, - kDisambiguationPopupMinimumTouchSize / smallest_target)) * total_scale; + const float smallest_target_f = std::max(smallest_target * total_scale, 1.0f); + return std::min(kDisambiguationPopupMaxScale, + std::max(kDisambiguationPopupMinScale, + kDisambiguationPopupMinimumTouchSize / + smallest_target_f)) * + total_scale; } -void TrimEdges(int *e1, int *e2, int max_combined) { +void TrimEdges(int* e1, int* e2, int max_combined) { if (*e1 + *e2 <= max_combined) return; @@ -89,6 +93,7 @@ gfx::Rect CropZoomArea(const gfx::Rect& zoom_rect, namespace content { +// static float DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor( const gfx::Rect& tap_rect, const WebVector<WebRect>& target_rects, diff --git a/chromium/content/renderer/android/renderer_date_time_picker.cc b/chromium/content/renderer/android/renderer_date_time_picker.cc index b936490b032..d8c0c652214 100644 --- a/chromium/content/renderer/android/renderer_date_time_picker.cc +++ b/chromium/content/renderer/android/renderer_date_time_picker.cc @@ -110,4 +110,8 @@ void RendererDateTimePicker::OnCancel() { static_cast<RenderViewImpl*>(render_view())->DismissDateTimeDialog(); } +void RendererDateTimePicker::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/android/renderer_date_time_picker.h b/chromium/content/renderer/android/renderer_date_time_picker.h index d04016bf271..2e9741aa0db 100644 --- a/chromium/content/renderer/android/renderer_date_time_picker.h +++ b/chromium/content/renderer/android/renderer_date_time_picker.h @@ -34,6 +34,7 @@ class RendererDateTimePicker : public RenderViewObserver { // RenderViewObserver bool OnMessageReceived(const IPC::Message& message) override; + void OnDestruct() override; blink::WebDateTimeChooserParams chooser_params_; blink::WebDateTimeChooserCompletion* chooser_completion_; // Not owned by us diff --git a/chromium/content/renderer/android/synchronous_compositor_external_begin_frame_source.cc b/chromium/content/renderer/android/synchronous_compositor_external_begin_frame_source.cc deleted file mode 100644 index 7bb1dc8f727..00000000000 --- a/chromium/content/renderer/android/synchronous_compositor_external_begin_frame_source.cc +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/android/synchronous_compositor_external_begin_frame_source.h" - -#include "cc/output/begin_frame_args.h" -#include "content/renderer/android/synchronous_compositor_registry.h" - -namespace content { - -SynchronousCompositorExternalBeginFrameSource:: - SynchronousCompositorExternalBeginFrameSource( - int routing_id, - SynchronousCompositorRegistry* registry) - : routing_id_(routing_id), - registry_(registry), - registered_(false), - client_(nullptr) { - thread_checker_.DetachFromThread(); -} - -SynchronousCompositorExternalBeginFrameSource:: - ~SynchronousCompositorExternalBeginFrameSource() { - DCHECK(CalledOnValidThread()); - - if (registered_) { - registry_->UnregisterBeginFrameSource(routing_id_, this); - } - DCHECK(!client_); -} - -void SynchronousCompositorExternalBeginFrameSource::BeginFrame( - const cc::BeginFrameArgs& args) { - DCHECK(CalledOnValidThread()); - CallOnBeginFrame(args); -} - -void SynchronousCompositorExternalBeginFrameSource::SetClient( - SynchronousCompositorExternalBeginFrameSourceClient* client) { - DCHECK(CalledOnValidThread()); - if (client_ == client) - return; - - if (client_) - client_->OnNeedsBeginFramesChange(false); - - client_ = client; - - if (client_) - client_->OnNeedsBeginFramesChange(needs_begin_frames()); - - // State without client is paused, and default client state is not paused. - SetBeginFrameSourcePaused(!client_); -} - -void SynchronousCompositorExternalBeginFrameSource::OnNeedsBeginFramesChanged( - bool needs_begin_frames) { - DCHECK(CalledOnValidThread()); - if (client_) - client_->OnNeedsBeginFramesChange(needs_begin_frames); -} - -void SynchronousCompositorExternalBeginFrameSource::AddObserver( - cc::BeginFrameObserver* obs) { - DCHECK(CalledOnValidThread()); - BeginFrameSourceBase::AddObserver(obs); - if (registered_) - return; - registry_->RegisterBeginFrameSource(routing_id_, this); - registered_ = true; -} - -bool -SynchronousCompositorExternalBeginFrameSource::CalledOnValidThread() const { - return thread_checker_.CalledOnValidThread(); -} - -} // namespace content diff --git a/chromium/content/renderer/android/synchronous_compositor_external_begin_frame_source.h b/chromium/content/renderer/android/synchronous_compositor_external_begin_frame_source.h deleted file mode 100644 index e058c37662e..00000000000 --- a/chromium/content/renderer/android/synchronous_compositor_external_begin_frame_source.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_ANDROID_SYNCHRONOUS_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_ -#define CONTENT_RENDERER_ANDROID_SYNCHRONOUS_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_ - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/threading/thread_checker.h" -#include "cc/scheduler/begin_frame_source.h" - -namespace content { - -class SynchronousCompositorRegistry; - -class SynchronousCompositorExternalBeginFrameSourceClient { - public: - virtual void OnNeedsBeginFramesChange(bool needs_begin_frames) = 0; - - protected: - virtual ~SynchronousCompositorExternalBeginFrameSourceClient() {} -}; - -// Make sure that this is initialized and set to client before output -// surface is bound to compositor. -class SynchronousCompositorExternalBeginFrameSource - : public cc::BeginFrameSourceBase { - public: - SynchronousCompositorExternalBeginFrameSource( - int routing_id, - SynchronousCompositorRegistry* registry); - ~SynchronousCompositorExternalBeginFrameSource() override; - - void BeginFrame(const cc::BeginFrameArgs& args); - void SetClient(SynchronousCompositorExternalBeginFrameSourceClient* client); - using cc::BeginFrameSourceBase::SetBeginFrameSourcePaused; - - // cc::BeginFrameSourceBase implementation. - void OnNeedsBeginFramesChanged(bool needs_begin_frames) override; - void AddObserver(cc::BeginFrameObserver* obs) override; - - private: - bool CalledOnValidThread() const; - - const int routing_id_; - SynchronousCompositorRegistry* const registry_; - bool registered_; - - // Not owned. - SynchronousCompositorExternalBeginFrameSourceClient* client_; - - base::ThreadChecker thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorExternalBeginFrameSource); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_ANDROID_SYNCHRONOUS_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_ diff --git a/chromium/content/renderer/android/synchronous_compositor_filter.cc b/chromium/content/renderer/android/synchronous_compositor_filter.cc index 43b7131a2b0..a73fde1af96 100644 --- a/chromium/content/renderer/android/synchronous_compositor_filter.cc +++ b/chromium/content/renderer/android/synchronous_compositor_filter.cc @@ -154,32 +154,6 @@ void SynchronousCompositorFilter::UnregisterOutputSurface( RemoveEntryIfNeeded(routing_id); } -void SynchronousCompositorFilter::RegisterBeginFrameSource( - int routing_id, - SynchronousCompositorExternalBeginFrameSource* begin_frame_source) { - DCHECK(compositor_task_runner_->BelongsToCurrentThread()); - DCHECK(begin_frame_source); - Entry& entry = entry_map_[routing_id]; - DCHECK(!entry.begin_frame_source); - entry.begin_frame_source = begin_frame_source; - CheckIsReady(routing_id); -} - -void SynchronousCompositorFilter::UnregisterBeginFrameSource( - int routing_id, - SynchronousCompositorExternalBeginFrameSource* begin_frame_source) { - DCHECK(compositor_task_runner_->BelongsToCurrentThread()); - DCHECK(begin_frame_source); - DCHECK(ContainsKey(entry_map_, routing_id)); - Entry& entry = entry_map_[routing_id]; - DCHECK_EQ(begin_frame_source, entry.begin_frame_source); - - if (entry.IsReady()) - UnregisterObjects(routing_id); - entry.begin_frame_source = nullptr; - RemoveEntryIfNeeded(routing_id); -} - void SynchronousCompositorFilter::CheckIsReady(int routing_id) { DCHECK(compositor_task_runner_->BelongsToCurrentThread()); DCHECK(ContainsKey(entry_map_, routing_id)); @@ -187,9 +161,8 @@ void SynchronousCompositorFilter::CheckIsReady(int routing_id) { if (filter_ready_ && entry.IsReady()) { DCHECK(!sync_compositor_map_.contains(routing_id)); std::unique_ptr<SynchronousCompositorProxy> proxy( - new SynchronousCompositorProxy( - routing_id, this, entry.begin_frame_source, - entry.synchronous_input_handler_proxy, &input_handler_)); + new SynchronousCompositorProxy(routing_id, this, + entry.synchronous_input_handler_proxy)); if (entry.output_surface) proxy->SetOutputSurface(entry.output_surface); sync_compositor_map_.add(routing_id, std::move(proxy)); @@ -206,53 +179,11 @@ void SynchronousCompositorFilter::RemoveEntryIfNeeded(int routing_id) { DCHECK(compositor_task_runner_->BelongsToCurrentThread()); DCHECK(ContainsKey(entry_map_, routing_id)); Entry& entry = entry_map_[routing_id]; - if (!entry.begin_frame_source && !entry.output_surface && - !entry.synchronous_input_handler_proxy) { + if (!entry.output_surface && !entry.synchronous_input_handler_proxy) { entry_map_.erase(routing_id); } } -void SynchronousCompositorFilter::SetBoundHandler(const Handler& handler) { - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind( - &SynchronousCompositorFilter::SetBoundHandlerOnCompositorThread, this, - handler)); -} - -void SynchronousCompositorFilter::RegisterRoutingID(int routing_id) {} -void SynchronousCompositorFilter::UnregisterRoutingID(int routing_id) {} - -void SynchronousCompositorFilter::SetBoundHandlerOnCompositorThread( - const Handler& handler) { - DCHECK(compositor_task_runner_->BelongsToCurrentThread()); - input_handler_ = handler; -} - -void SynchronousCompositorFilter::DidOverscroll( - int routing_id, - const DidOverscrollParams& params) { - DCHECK(compositor_task_runner_->BelongsToCurrentThread()); - SynchronousCompositorProxy* proxy = FindProxy(routing_id); - if (!proxy) { - DLOG(WARNING) << "No matching proxy in DidOverScroll " << routing_id; - return; - } - proxy->DidOverscroll(params); -} - -void SynchronousCompositorFilter::DidStartFlinging(int routing_id) {} - -void SynchronousCompositorFilter::DidStopFlinging(int routing_id) { - DCHECK(compositor_task_runner_->BelongsToCurrentThread()); - Send(new InputHostMsg_DidStopFlinging(routing_id)); -} - -void SynchronousCompositorFilter::NotifyInputEventHandled( - int routing_id, - blink::WebInputEvent::Type type, - InputEventAckState ack_result) {} - void SynchronousCompositorFilter::DidAddSynchronousHandlerProxy( int routing_id, ui::SynchronousInputHandlerProxy* synchronous_input_handler_proxy) { @@ -277,12 +208,12 @@ void SynchronousCompositorFilter::DidRemoveSynchronousHandlerProxy( } SynchronousCompositorFilter::Entry::Entry() - : begin_frame_source(nullptr), - output_surface(nullptr), + : output_surface(nullptr), synchronous_input_handler_proxy(nullptr) {} +// TODO(boliu): refactor this bool SynchronousCompositorFilter::Entry::IsReady() { - return begin_frame_source && synchronous_input_handler_proxy; + return synchronous_input_handler_proxy; } } // namespace content diff --git a/chromium/content/renderer/android/synchronous_compositor_filter.h b/chromium/content/renderer/android/synchronous_compositor_filter.h index b7cee7bbf42..a188fdbd7af 100644 --- a/chromium/content/renderer/android/synchronous_compositor_filter.h +++ b/chromium/content/renderer/android/synchronous_compositor_filter.h @@ -29,7 +29,6 @@ class SynchronousCompositorFilter : public IPC::MessageFilter, public IPC::Sender, public SynchronousCompositorRegistry, - public InputHandlerManagerClient, public SynchronousInputHandlerProxyClient { public: SynchronousCompositorFilter(const scoped_refptr<base::SingleThreadTaskRunner>& @@ -53,24 +52,6 @@ class SynchronousCompositorFilter void UnregisterOutputSurface( int routing_id, SynchronousCompositorOutputSurface* output_surface) override; - void RegisterBeginFrameSource(int routing_id, - SynchronousCompositorExternalBeginFrameSource* - begin_frame_source) override; - void UnregisterBeginFrameSource(int routing_id, - SynchronousCompositorExternalBeginFrameSource* - begin_frame_source) override; - - // InputHandlerManagerClient overrides. - void SetBoundHandler(const Handler& handler) override; - void RegisterRoutingID(int routing_id) override; - void UnregisterRoutingID(int routing_id) override; - void DidOverscroll(int routing_id, - const DidOverscrollParams& params) override; - void DidStartFlinging(int routing_id) override; - void DidStopFlinging(int routing_id) override; - void NotifyInputEventHandled(int routing_id, - blink::WebInputEvent::Type type, - InputEventAckState ack_result) override; // SynchronousInputHandlerProxyClient overrides. void DidAddSynchronousHandlerProxy( @@ -88,7 +69,6 @@ class SynchronousCompositorFilter // Compositor thread methods. void FilterReadyyOnCompositorThread(); void OnMessageReceivedOnCompositorThread(const IPC::Message& message); - void SetBoundHandlerOnCompositorThread(const Handler& handler); void CheckIsReady(int routing_id); void UnregisterObjects(int routing_id); void RemoveEntryIfNeeded(int routing_id); @@ -105,11 +85,9 @@ class SynchronousCompositorFilter base::ScopedPtrHashMap<int /* routing_id */, std::unique_ptr<SynchronousCompositorProxy>>; SyncCompositorMap sync_compositor_map_; - Handler input_handler_; bool filter_ready_; struct Entry { - SynchronousCompositorExternalBeginFrameSource* begin_frame_source; SynchronousCompositorOutputSurface* output_surface; ui::SynchronousInputHandlerProxy* synchronous_input_handler_proxy; diff --git a/chromium/content/renderer/android/synchronous_compositor_output_surface.cc b/chromium/content/renderer/android/synchronous_compositor_output_surface.cc index 119dac59883..37d3a23e90f 100644 --- a/chromium/content/renderer/android/synchronous_compositor_output_surface.cc +++ b/chromium/content/renderer/android/synchronous_compositor_output_surface.cc @@ -7,14 +7,17 @@ #include <vector> #include "base/auto_reset.h" +#include "base/location.h" #include "base/logging.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" #include "cc/output/compositor_frame.h" #include "cc/output/context_provider.h" #include "cc/output/output_surface_client.h" #include "cc/output/software_output_device.h" #include "content/common/android/sync_compositor_messages.h" -#include "content/renderer/android/synchronous_compositor_external_begin_frame_source.h" #include "content/renderer/android/synchronous_compositor_filter.h" #include "content/renderer/android/synchronous_compositor_registry.h" #include "content/renderer/gpu/frame_swap_message_queue.h" @@ -69,17 +72,15 @@ class SynchronousCompositorOutputSurface::SoftwareDevice }; SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface( - const scoped_refptr<cc::ContextProvider>& context_provider, - const scoped_refptr<cc::ContextProvider>& worker_context_provider, + scoped_refptr<cc::ContextProvider> context_provider, + scoped_refptr<cc::ContextProvider> worker_context_provider, int routing_id, uint32_t output_surface_id, SynchronousCompositorRegistry* registry, scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue) - : cc::OutputSurface( - context_provider, - worker_context_provider, - nullptr, - std::unique_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))), + : cc::OutputSurface(std::move(context_provider), + std::move(worker_context_provider), + base::MakeUnique<SoftwareDevice>(this)), routing_id_(routing_id), output_surface_id_(output_surface_id), registry_(registry), @@ -107,6 +108,8 @@ void SynchronousCompositorOutputSurface::SetSyncClient( SynchronousCompositorOutputSurfaceClient* compositor) { DCHECK(CalledOnValidThread()); sync_client_ = compositor; + if (sync_client_) + Send(new SyncCompositorHostMsg_OutputSurfaceCreated(routing_id_)); } bool SynchronousCompositorOutputSurface::OnMessageReceived( @@ -132,7 +135,6 @@ bool SynchronousCompositorOutputSurface::BindToClient( base::Unretained(this))); registry_->RegisterOutputSurface(routing_id_, this); registered_ = true; - Send(new SyncCompositorHostMsg_OutputSurfaceCreated(routing_id_)); return true; } @@ -146,18 +148,20 @@ void SynchronousCompositorOutputSurface::DetachFromClient() { CancelFallbackTick(); } -void SynchronousCompositorOutputSurface::Reshape(const gfx::Size& size, - float scale_factor, - bool has_alpha) { +void SynchronousCompositorOutputSurface::Reshape( + const gfx::Size& size, + float scale_factor, + const gfx::ColorSpace& color_space, + bool has_alpha) { // Intentional no-op: surface size is controlled by the embedder. } void SynchronousCompositorOutputSurface::SwapBuffers( - cc::CompositorFrame* frame) { + cc::CompositorFrame frame) { DCHECK(CalledOnValidThread()); DCHECK(sync_client_); if (!fallback_tick_running_) { - sync_client_->SwapBuffers(output_surface_id_, frame); + sync_client_->SwapBuffers(output_surface_id_, std::move(frame)); DeliverMessages(); } client_->DidSwapBuffers(); @@ -191,13 +195,24 @@ void SynchronousCompositorOutputSurface::Invalidate() { fallback_tick_.Reset( base::Bind(&SynchronousCompositorOutputSurface::FallbackTickFired, base::Unretained(this))); - base::MessageLoop::current()->PostDelayedTask( + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, fallback_tick_.callback(), base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds)); fallback_tick_pending_ = true; } } +void SynchronousCompositorOutputSurface::BindFramebuffer() { + // This is a delegating output surface, no framebuffer/direct drawing support. + NOTREACHED(); +} + +uint32_t SynchronousCompositorOutputSurface::GetFramebufferCopyTextureFormat() { + // This is a delegating output surface, no framebuffer/direct drawing support. + NOTREACHED(); + return 0; +} + void SynchronousCompositorOutputSurface::DemandDrawHw( const gfx::Size& surface_size, const gfx::Transform& transform, diff --git a/chromium/content/renderer/android/synchronous_compositor_output_surface.h b/chromium/content/renderer/android/synchronous_compositor_output_surface.h index 672cf2d234c..09720941418 100644 --- a/chromium/content/renderer/android/synchronous_compositor_output_surface.h +++ b/chromium/content/renderer/android/synchronous_compositor_output_surface.h @@ -42,7 +42,7 @@ class SynchronousCompositorOutputSurfaceClient { virtual void DidActivatePendingTree() = 0; virtual void Invalidate() = 0; virtual void SwapBuffers(uint32_t output_surface_id, - cc::CompositorFrame* frame) = 0; + cc::CompositorFrame frame) = 0; protected: virtual ~SynchronousCompositorOutputSurfaceClient() {} @@ -60,8 +60,8 @@ class SynchronousCompositorOutputSurface : NON_EXPORTED_BASE(public cc::OutputSurface) { public: SynchronousCompositorOutputSurface( - const scoped_refptr<cc::ContextProvider>& context_provider, - const scoped_refptr<cc::ContextProvider>& worker_context_provider, + scoped_refptr<cc::ContextProvider> context_provider, + scoped_refptr<cc::ContextProvider> worker_context_provider, int routing_id, uint32_t output_surface_id, SynchronousCompositorRegistry* registry, @@ -76,9 +76,12 @@ class SynchronousCompositorOutputSurface void DetachFromClient() override; void Reshape(const gfx::Size& size, float scale_factor, + const gfx::ColorSpace& color_space, bool has_alpha) override; - void SwapBuffers(cc::CompositorFrame* frame) override; + void SwapBuffers(cc::CompositorFrame frame) override; void Invalidate() override; + void BindFramebuffer() override; + uint32_t GetFramebufferCopyTextureFormat() override; // Partial SynchronousCompositor API implementation. void DemandDrawHw(const gfx::Size& surface_size, diff --git a/chromium/content/renderer/android/synchronous_compositor_proxy.cc b/chromium/content/renderer/android/synchronous_compositor_proxy.cc index ae6a13135e0..6b9883b5a21 100644 --- a/chromium/content/renderer/android/synchronous_compositor_proxy.cc +++ b/chromium/content/renderer/android/synchronous_compositor_proxy.cc @@ -17,7 +17,6 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkRegion.h" -#include "ui/events/latency_info.h" #include "ui/gfx/skia_util.h" namespace content { @@ -25,14 +24,10 @@ namespace content { SynchronousCompositorProxy::SynchronousCompositorProxy( int routing_id, IPC::Sender* sender, - SynchronousCompositorExternalBeginFrameSource* begin_frame_source, - ui::SynchronousInputHandlerProxy* input_handler_proxy, - InputHandlerManagerClient::Handler* handler) + ui::SynchronousInputHandlerProxy* input_handler_proxy) : routing_id_(routing_id), sender_(sender), - begin_frame_source_(begin_frame_source), input_handler_proxy_(input_handler_proxy), - input_handler_(handler), use_in_process_zero_copy_software_draw_( base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kSingleProcess)), @@ -46,18 +41,15 @@ SynchronousCompositorProxy::SynchronousCompositorProxy( max_page_scale_factor_(0.f), need_animate_scroll_(false), need_invalidate_count_(0u), - need_begin_frame_(false), did_activate_pending_tree_count_(0u) { - DCHECK(begin_frame_source_); DCHECK(input_handler_proxy_); - DCHECK(input_handler_); - begin_frame_source_->SetClient(this); input_handler_proxy_->SetOnlySynchronouslyAnimateRootFlings(this); } SynchronousCompositorProxy::~SynchronousCompositorProxy() { - SetOutputSurface(nullptr); - begin_frame_source_->SetClient(nullptr); + // The OutputSurface is destroyed/removed by the compositor before shutting + // down everything. + DCHECK_EQ(output_surface_, nullptr); input_handler_proxy_->SetOnlySynchronouslyAnimateRootFlings(nullptr); } @@ -102,14 +94,6 @@ void SynchronousCompositorProxy::UpdateRootLayerState( } } -void SynchronousCompositorProxy::OnNeedsBeginFramesChange( - bool needs_begin_frames) { - if (need_begin_frame_ == needs_begin_frames) - return; - need_begin_frame_ = needs_begin_frames; - SendAsyncRendererStateIfNeeded(); -} - void SynchronousCompositorProxy::Invalidate() { ++need_invalidate_count_; SendAsyncRendererStateIfNeeded(); @@ -139,7 +123,6 @@ void SynchronousCompositorProxy::PopulateCommonParams( params->max_page_scale_factor = max_page_scale_factor_; params->need_animate_scroll = need_animate_scroll_; params->need_invalidate_count = need_invalidate_count_; - params->need_begin_frame = need_begin_frame_; params->did_activate_pending_tree_count = did_activate_pending_tree_count_; } @@ -149,8 +132,8 @@ void SynchronousCompositorProxy::OnMessageReceived( return; IPC_BEGIN_MESSAGE_MAP(SynchronousCompositorProxy, message) - IPC_MESSAGE_HANDLER(SyncCompositorMsg_HandleInputEvent, HandleInputEvent) - IPC_MESSAGE_HANDLER(SyncCompositorMsg_BeginFrame, BeginFrame) + IPC_MESSAGE_HANDLER(SyncCompositorMsg_SynchronizeRendererState, + PopulateCommonParams) IPC_MESSAGE_HANDLER(SyncCompositorMsg_ComputeScroll, OnComputeScroll) IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncCompositorMsg_DemandDrawHw, DemandDrawHw) @@ -158,7 +141,6 @@ void SynchronousCompositorProxy::OnMessageReceived( IPC_MESSAGE_HANDLER(SyncCompositorMsg_ZeroSharedMemory, ZeroSharedMemory) IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncCompositorMsg_DemandDrawSw, DemandDrawSw) - IPC_MESSAGE_HANDLER(SyncCompositorMsg_UpdateState, ProcessCommonParams) IPC_MESSAGE_HANDLER(SyncCompositorMsg_ZoomBy, SynchronouslyZoomBy) IPC_MESSAGE_HANDLER(SyncCompositorMsg_SetScroll, SetScroll) IPC_END_MESSAGE_MAP() @@ -168,44 +150,13 @@ bool SynchronousCompositorProxy::Send(IPC::Message* message) { return sender_->Send(message); } -void SynchronousCompositorProxy::HandleInputEvent( - const SyncCompositorCommonBrowserParams& common_params, - const blink::WebInputEvent* event, - SyncCompositorCommonRendererParams* common_renderer_params, - InputEventAckState* ack) { - DCHECK(!inside_receive_); - base::AutoReset<bool> scoped_inside_receive(&inside_receive_, true); - - ProcessCommonParams(common_params); - DCHECK(!input_handler_->is_null()); - ui::LatencyInfo latency; - *ack = input_handler_->Run(routing_id_, event, &latency); - PopulateCommonParams(common_renderer_params); -} - -void SynchronousCompositorProxy::BeginFrame( - const SyncCompositorCommonBrowserParams& common_params, - const cc::BeginFrameArgs& args, - SyncCompositorCommonRendererParams* common_renderer_params) { - DCHECK(!inside_receive_); - base::AutoReset<bool> scoped_inside_receive(&inside_receive_, true); - - ProcessCommonParams(common_params); - if (need_begin_frame_) { - begin_frame_source_->BeginFrame(args); - } - PopulateCommonParams(common_renderer_params); -} - void SynchronousCompositorProxy::DemandDrawHw( - const SyncCompositorCommonBrowserParams& common_params, const SyncCompositorDemandDrawHwParams& params, IPC::Message* reply_message) { DCHECK(!inside_receive_); DCHECK(reply_message); inside_receive_ = true; - ProcessCommonParams(common_params); if (output_surface_) { base::AutoReset<IPC::Message*> scoped_hardware_draw_reply( @@ -218,29 +169,28 @@ void SynchronousCompositorProxy::DemandDrawHw( if (inside_receive_) { // Did not swap. - cc::CompositorFrame empty_frame; - SendDemandDrawHwReply(&empty_frame, 0u, reply_message); + SendDemandDrawHwReply(cc::CompositorFrame(), 0u, reply_message); inside_receive_ = false; } } void SynchronousCompositorProxy::SwapBuffersHw(uint32_t output_surface_id, - cc::CompositorFrame* frame) { + cc::CompositorFrame frame) { DCHECK(inside_receive_); DCHECK(hardware_draw_reply_); - DCHECK(frame); - SendDemandDrawHwReply(frame, output_surface_id, hardware_draw_reply_); + SendDemandDrawHwReply(std::move(frame), output_surface_id, + hardware_draw_reply_); inside_receive_ = false; } void SynchronousCompositorProxy::SendDemandDrawHwReply( - cc::CompositorFrame* frame, + cc::CompositorFrame frame, uint32_t output_surface_id, IPC::Message* reply_message) { SyncCompositorCommonRendererParams common_renderer_params; PopulateCommonParams(&common_renderer_params); SyncCompositorMsg_DemandDrawHw::WriteReplyParams( - reply_message, common_renderer_params, output_surface_id, *frame); + reply_message, common_renderer_params, output_surface_id, frame); Send(reply_message); } @@ -254,7 +204,6 @@ struct SynchronousCompositorProxy::SharedMemoryWithSize { }; void SynchronousCompositorProxy::SetSharedMemory( - const SyncCompositorCommonBrowserParams& common_params, const SyncCompositorSetSharedMemoryParams& params, bool* success, SyncCompositorCommonRendererParams* common_renderer_params) { @@ -262,7 +211,6 @@ void SynchronousCompositorProxy::SetSharedMemory( base::AutoReset<bool> scoped_inside_receive(&inside_receive_, true); *success = false; - ProcessCommonParams(common_params); if (!base::SharedMemory::IsHandleValid(params.shm_handle)) return; @@ -276,18 +224,21 @@ void SynchronousCompositorProxy::SetSharedMemory( } void SynchronousCompositorProxy::ZeroSharedMemory() { - DCHECK(!software_draw_shm_->zeroed); + // It is possible for this to get called twice, eg. if draw is called before + // the OutputSurface is ready. Just ignore duplicated calls rather than + // inventing a complicated system to avoid it. + if (software_draw_shm_->zeroed) + return; + memset(software_draw_shm_->shm.memory(), 0, software_draw_shm_->buffer_size); software_draw_shm_->zeroed = true; } void SynchronousCompositorProxy::DemandDrawSw( - const SyncCompositorCommonBrowserParams& common_params, const SyncCompositorDemandDrawSwParams& params, IPC::Message* reply_message) { DCHECK(!inside_receive_); inside_receive_ = true; - ProcessCommonParams(common_params); if (output_surface_) { base::AutoReset<IPC::Message*> scoped_software_draw_reply( &software_draw_reply_, reply_message); @@ -302,8 +253,7 @@ void SynchronousCompositorProxy::DemandDrawSw( } if (inside_receive_) { // Did not swap. - cc::CompositorFrame empty_frame; - SendDemandDrawSwReply(false, &empty_frame, reply_message); + SendDemandDrawSwReply(false, cc::CompositorFrame(), reply_message); inside_receive_ = false; } } @@ -330,40 +280,37 @@ void SynchronousCompositorProxy::DoDemandDrawSw( output_surface_->DemandDrawSw(&canvas); } -void SynchronousCompositorProxy::SwapBuffersSw(cc::CompositorFrame* frame) { +void SynchronousCompositorProxy::SwapBuffersSw(cc::CompositorFrame frame) { DCHECK(inside_receive_); DCHECK(software_draw_reply_); - DCHECK(frame); - SendDemandDrawSwReply(true, frame, software_draw_reply_); + SendDemandDrawSwReply(true, std::move(frame), software_draw_reply_); inside_receive_ = false; } void SynchronousCompositorProxy::SendDemandDrawSwReply( bool success, - cc::CompositorFrame* frame, + cc::CompositorFrame frame, IPC::Message* reply_message) { SyncCompositorCommonRendererParams common_renderer_params; PopulateCommonParams(&common_renderer_params); SyncCompositorMsg_DemandDrawSw::WriteReplyParams( - reply_message, success, common_renderer_params, *frame); + reply_message, success, common_renderer_params, frame); Send(reply_message); } void SynchronousCompositorProxy::SwapBuffers(uint32_t output_surface_id, - cc::CompositorFrame* frame) { + cc::CompositorFrame frame) { DCHECK(hardware_draw_reply_ || software_draw_reply_); DCHECK(!(hardware_draw_reply_ && software_draw_reply_)); if (hardware_draw_reply_) { - SwapBuffersHw(output_surface_id, frame); + SwapBuffersHw(output_surface_id, std::move(frame)); } else if (software_draw_reply_) { - SwapBuffersSw(frame); + SwapBuffersSw(std::move(frame)); } } void SynchronousCompositorProxy::OnComputeScroll( - const SyncCompositorCommonBrowserParams& common_params, base::TimeTicks animation_time) { - ProcessCommonParams(common_params); if (need_animate_scroll_) { need_animate_scroll_ = false; input_handler_proxy_->SynchronouslyAnimate(animation_time); @@ -371,13 +318,11 @@ void SynchronousCompositorProxy::OnComputeScroll( } void SynchronousCompositorProxy::SynchronouslyZoomBy( - const SyncCompositorCommonBrowserParams& common_params, float zoom_delta, const gfx::Point& anchor, SyncCompositorCommonRendererParams* common_renderer_params) { DCHECK(!inside_receive_); base::AutoReset<bool> scoped_inside_receive(&inside_receive_, true); - ProcessCommonParams(common_params); input_handler_proxy_->SynchronouslyZoomBy(zoom_delta, anchor); PopulateCommonParams(common_renderer_params); } @@ -390,18 +335,4 @@ void SynchronousCompositorProxy::SetScroll( input_handler_proxy_->SynchronouslySetRootScrollOffset(total_scroll_offset_); } -void SynchronousCompositorProxy::DidOverscroll( - const DidOverscrollParams& did_overscroll_params) { - SyncCompositorCommonRendererParams params; - PopulateCommonParams(¶ms); - Send(new SyncCompositorHostMsg_OverScroll(routing_id_, params, - did_overscroll_params)); -} - -void SynchronousCompositorProxy::ProcessCommonParams( - const SyncCompositorCommonBrowserParams& common_params) { - begin_frame_source_->SetBeginFrameSourcePaused( - common_params.begin_frame_source_paused); -} - } // namespace content diff --git a/chromium/content/renderer/android/synchronous_compositor_proxy.h b/chromium/content/renderer/android/synchronous_compositor_proxy.h index d6f9e1ae996..6058aad9adc 100644 --- a/chromium/content/renderer/android/synchronous_compositor_proxy.h +++ b/chromium/content/renderer/android/synchronous_compositor_proxy.h @@ -10,9 +10,7 @@ #include "base/macros.h" #include "content/common/input/input_event_ack_state.h" -#include "content/renderer/android/synchronous_compositor_external_begin_frame_source.h" #include "content/renderer/android/synchronous_compositor_output_surface.h" -#include "content/renderer/input/input_handler_manager_client.h" #include "ui/events/blink/synchronous_input_handler_proxy.h" #include "ui/gfx/geometry/scroll_offset.h" #include "ui/gfx/geometry/size_f.h" @@ -35,7 +33,6 @@ class CompositorFrame; namespace content { class SynchronousCompositorOutputSurface; -struct SyncCompositorCommonBrowserParams; struct SyncCompositorCommonRendererParams; struct SyncCompositorDemandDrawHwParams; struct SyncCompositorDemandDrawSwParams; @@ -43,15 +40,12 @@ struct SyncCompositorSetSharedMemoryParams; class SynchronousCompositorProxy : public ui::SynchronousInputHandler, - public SynchronousCompositorExternalBeginFrameSourceClient, public SynchronousCompositorOutputSurfaceClient { public: SynchronousCompositorProxy( int routing_id, IPC::Sender* sender, - SynchronousCompositorExternalBeginFrameSource* begin_frame_source, - ui::SynchronousInputHandlerProxy* input_handler_proxy, - InputHandlerManagerClient::Handler* handler); + ui::SynchronousInputHandlerProxy* input_handler_proxy); ~SynchronousCompositorProxy() override; // ui::SynchronousInputHandler overrides. @@ -63,73 +57,51 @@ class SynchronousCompositorProxy float min_page_scale_factor, float max_page_scale_factor) override; - // SynchronousCompositorExternalBeginFrameSourceClient overrides. - void OnNeedsBeginFramesChange(bool needs_begin_frames) override; - // SynchronousCompositorOutputSurfaceClient overrides. void DidActivatePendingTree() override; void Invalidate() override; void SwapBuffers(uint32_t output_surface_id, - cc::CompositorFrame* frame) override; + cc::CompositorFrame frame) override; void SetOutputSurface(SynchronousCompositorOutputSurface* output_surface); void OnMessageReceived(const IPC::Message& message); bool Send(IPC::Message* message); - void DidOverscroll(const DidOverscrollParams& did_overscroll_params); private: struct SharedMemoryWithSize; - void ProcessCommonParams( - const SyncCompositorCommonBrowserParams& common_params); - void PopulateCommonParams(SyncCompositorCommonRendererParams* params) const; - // IPC handlers. - void HandleInputEvent( - const SyncCompositorCommonBrowserParams& common_params, - const blink::WebInputEvent* event, - SyncCompositorCommonRendererParams* common_renderer_params, - InputEventAckState* ack); - void BeginFrame(const SyncCompositorCommonBrowserParams& common_params, - const cc::BeginFrameArgs& args, - SyncCompositorCommonRendererParams* common_renderer_params); - void OnComputeScroll(const SyncCompositorCommonBrowserParams& common_params, - base::TimeTicks animation_time); - void DemandDrawHw(const SyncCompositorCommonBrowserParams& common_params, - const SyncCompositorDemandDrawHwParams& params, + void PopulateCommonParams(SyncCompositorCommonRendererParams* params) const; + void OnComputeScroll(base::TimeTicks animation_time); + void DemandDrawHw(const SyncCompositorDemandDrawHwParams& params, IPC::Message* reply_message); void SetSharedMemory( - const SyncCompositorCommonBrowserParams& common_params, const SyncCompositorSetSharedMemoryParams& params, bool* success, SyncCompositorCommonRendererParams* common_renderer_params); void ZeroSharedMemory(); - void DemandDrawSw(const SyncCompositorCommonBrowserParams& common_params, - const SyncCompositorDemandDrawSwParams& params, + void DemandDrawSw(const SyncCompositorDemandDrawSwParams& params, IPC::Message* reply_message); void SynchronouslyZoomBy( - const SyncCompositorCommonBrowserParams& common_params, float zoom_delta, const gfx::Point& anchor, SyncCompositorCommonRendererParams* common_renderer_params); void SetScroll(const gfx::ScrollOffset& total_scroll_offset); - void SwapBuffersHw(uint32_t output_surface_id, cc::CompositorFrame* frame); - void SendDemandDrawHwReply(cc::CompositorFrame* frame, + void SwapBuffersHw(uint32_t output_surface_id, cc::CompositorFrame frame); + void SendDemandDrawHwReply(cc::CompositorFrame frame, uint32_t output_surface_id, IPC::Message* reply_message); void DoDemandDrawSw(const SyncCompositorDemandDrawSwParams& params); - void SwapBuffersSw(cc::CompositorFrame* frame); + void SwapBuffersSw(cc::CompositorFrame frame); void SendDemandDrawSwReply(bool success, - cc::CompositorFrame* frame, + cc::CompositorFrame frame, IPC::Message* reply_message); void SendAsyncRendererStateIfNeeded(); const int routing_id_; IPC::Sender* const sender_; - SynchronousCompositorExternalBeginFrameSource* const begin_frame_source_; ui::SynchronousInputHandlerProxy* const input_handler_proxy_; - InputHandlerManagerClient::Handler* const input_handler_; const bool use_in_process_zero_copy_software_draw_; SynchronousCompositorOutputSurface* output_surface_; bool inside_receive_; @@ -149,7 +121,6 @@ class SynchronousCompositorProxy float max_page_scale_factor_; bool need_animate_scroll_; uint32_t need_invalidate_count_; - bool need_begin_frame_; uint32_t did_activate_pending_tree_count_; DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorProxy); diff --git a/chromium/content/renderer/android/synchronous_compositor_registry.h b/chromium/content/renderer/android/synchronous_compositor_registry.h index 381d394b78b..11ba68bd656 100644 --- a/chromium/content/renderer/android/synchronous_compositor_registry.h +++ b/chromium/content/renderer/android/synchronous_compositor_registry.h @@ -8,7 +8,6 @@ namespace content { -class SynchronousCompositorExternalBeginFrameSource; class SynchronousCompositorOutputSurface; class SynchronousCompositorRegistry { @@ -19,12 +18,6 @@ class SynchronousCompositorRegistry { virtual void UnregisterOutputSurface( int routing_id, SynchronousCompositorOutputSurface* output_surface) = 0; - virtual void RegisterBeginFrameSource( - int routing_id, - SynchronousCompositorExternalBeginFrameSource* begin_frame_source) = 0; - virtual void UnregisterBeginFrameSource( - int routing_id, - SynchronousCompositorExternalBeginFrameSource* begin_frame_source) = 0; protected: virtual ~SynchronousCompositorRegistry() {} diff --git a/chromium/content/renderer/background_sync/background_sync_client_impl.h b/chromium/content/renderer/background_sync/background_sync_client_impl.h index 921ca854ebd..a264ffc9514 100644 --- a/chromium/content/renderer/background_sync/background_sync_client_impl.h +++ b/chromium/content/renderer/background_sync/background_sync_client_impl.h @@ -26,8 +26,6 @@ class CONTENT_EXPORT BackgroundSyncClientImpl ~BackgroundSyncClientImpl() override; private: - using SyncCallback = - mojo::Callback<void(blink::mojom::ServiceWorkerEventStatus)>; explicit BackgroundSyncClientImpl( mojo::InterfaceRequest<blink::mojom::BackgroundSyncServiceClient> request); diff --git a/chromium/content/renderer/bluetooth/bluetooth_dispatcher.cc b/chromium/content/renderer/bluetooth/bluetooth_dispatcher.cc deleted file mode 100644 index 2ff8caaf74c..00000000000 --- a/chromium/content/renderer/bluetooth/bluetooth_dispatcher.cc +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/bluetooth/bluetooth_dispatcher.h" - -#include <stddef.h> - -#include <memory> -#include <utility> - -#include "base/lazy_instance.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/threading/thread_task_runner_handle.h" -#include "content/child/thread_safe_sender.h" -#include "content/common/bluetooth/bluetooth_messages.h" -#include "device/bluetooth/bluetooth_uuid.h" -#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDeviceInit.h" -#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h" -#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTService.h" -#include "third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h" - -using blink::WebBluetoothDeviceInit; -using blink::WebBluetoothError; -using blink::WebBluetoothRemoteGATTService; -using blink::WebBluetoothReadValueCallbacks; -using blink::WebBluetoothRequestDeviceCallbacks; -using blink::WebBluetoothScanFilter; -using blink::WebRequestDeviceOptions; -using blink::WebString; -using blink::WebVector; - -namespace content { - -namespace { - -base::LazyInstance<base::ThreadLocalPointer<void>>::Leaky g_dispatcher_tls = - LAZY_INSTANCE_INITIALIZER; - -void* const kHasBeenDeleted = reinterpret_cast<void*>(0x1); - -int CurrentWorkerId() { - return WorkerThread::GetCurrentId(); -} - -} // namespace - -BluetoothDispatcher::BluetoothDispatcher(ThreadSafeSender* sender) - : thread_safe_sender_(sender) { - g_dispatcher_tls.Pointer()->Set(static_cast<void*>(this)); -} - -BluetoothDispatcher::~BluetoothDispatcher() { - g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted); -} - -BluetoothDispatcher* BluetoothDispatcher::GetOrCreateThreadSpecificInstance( - ThreadSafeSender* thread_safe_sender) { - if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) { - NOTREACHED() << "Re-instantiating TLS BluetoothDispatcher."; - g_dispatcher_tls.Pointer()->Set(NULL); - } - if (g_dispatcher_tls.Pointer()->Get()) - return static_cast<BluetoothDispatcher*>(g_dispatcher_tls.Pointer()->Get()); - - BluetoothDispatcher* dispatcher = new BluetoothDispatcher(thread_safe_sender); - if (CurrentWorkerId()) - WorkerThread::AddObserver(dispatcher); - return dispatcher; -} - -bool BluetoothDispatcher::Send(IPC::Message* msg) { - return thread_safe_sender_->Send(msg); -} - -void BluetoothDispatcher::OnMessageReceived(const IPC::Message& msg) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcher, msg) - IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceSuccess, - OnRequestDeviceSuccess); - IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceError, OnRequestDeviceError); - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - DCHECK(handled) << "Unhandled message:" << msg.type(); -} - -void BluetoothDispatcher::requestDevice( - int frame_routing_id, - const WebRequestDeviceOptions& options, - blink::WebBluetoothRequestDeviceCallbacks* callbacks) { - int request_id = pending_requests_.Add(callbacks); - - // Convert |options| to its IPC form. - std::vector<content::BluetoothScanFilter> filters(options.filters.size()); - for (size_t i = 0; i < options.filters.size(); ++i) { - const WebBluetoothScanFilter& web_filter = options.filters[i]; - BluetoothScanFilter& filter = filters[i]; - filter.services.reserve(web_filter.services.size()); - for (const WebString& service : web_filter.services) { - filter.services.push_back(device::BluetoothUUID(service.utf8())); - } - filter.name = web_filter.name.utf8(); - filter.namePrefix = web_filter.namePrefix.utf8(); - } - std::vector<device::BluetoothUUID> optional_services; - optional_services.reserve(options.optionalServices.size()); - for (const WebString& optional_service : options.optionalServices) { - optional_services.push_back(device::BluetoothUUID(optional_service.utf8())); - } - - Send(new BluetoothHostMsg_RequestDevice(CurrentWorkerId(), request_id, - frame_routing_id, filters, - optional_services)); -} - -void BluetoothDispatcher::WillStopCurrentWorkerThread() { - delete this; -} - -void BluetoothDispatcher::OnRequestDeviceSuccess( - int thread_id, - int request_id, - const BluetoothDevice& device) { - DCHECK(pending_requests_.Lookup(request_id)) << request_id; - - WebVector<WebString> uuids(device.uuids.size()); - for (size_t i = 0; i < device.uuids.size(); ++i) - uuids[i] = WebString::fromUTF8(device.uuids[i].c_str()); - - pending_requests_.Lookup(request_id) - ->onSuccess(base::WrapUnique(new WebBluetoothDeviceInit( - WebString::fromUTF8(device.id), WebString(device.name), uuids))); - pending_requests_.Remove(request_id); -} - -void BluetoothDispatcher::OnRequestDeviceError(int thread_id, - int request_id, - WebBluetoothError error) { - DCHECK(pending_requests_.Lookup(request_id)) << request_id; - pending_requests_.Lookup(request_id)->onError(WebBluetoothError(error)); - pending_requests_.Remove(request_id); -} - -} // namespace content diff --git a/chromium/content/renderer/bluetooth/bluetooth_dispatcher.h b/chromium/content/renderer/bluetooth/bluetooth_dispatcher.h deleted file mode 100644 index e627d53ebdb..00000000000 --- a/chromium/content/renderer/bluetooth/bluetooth_dispatcher.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_CHILD_BLUETOOTH_BLUETOOTH_DISPATCHER_H_ -#define CONTENT_CHILD_BLUETOOTH_BLUETOOTH_DISPATCHER_H_ - -#include <stdint.h> - -#include <map> -#include <queue> - -#include "base/id_map.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "content/common/bluetooth/bluetooth_device.h" -#include "content/public/child/worker_thread.h" -#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h" -#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h" - -namespace base { -class MessageLoop; -class TaskRunner; -} - -namespace IPC { -class Message; -} - -namespace content { -class ThreadSafeSender; - -// Dispatcher for child process threads which communicates to the browser's -// BluetoothDispatcherHost. -// -// Instances are created for each thread as necessary by WebBluetoothImpl. -// -// Incoming IPC messages are received by the BluetoothMessageFilter and -// directed to the thread specific instance of this class. -// Outgoing messages come from WebBluetoothImpl. -class BluetoothDispatcher : public WorkerThread::Observer { - public: - explicit BluetoothDispatcher(ThreadSafeSender* sender); - ~BluetoothDispatcher() override; - - // Gets or Creates a BluetoothDispatcher for the current thread. - // |thread_safe_sender| is required when constructing a BluetoothDispatcher. - static BluetoothDispatcher* GetOrCreateThreadSpecificInstance( - ThreadSafeSender* thread_safe_sender); - - // IPC Send and Receiving interface, see IPC::Sender and IPC::Listener. - bool Send(IPC::Message* msg); - void OnMessageReceived(const IPC::Message& msg); - - // Corresponding to WebBluetoothImpl methods. - void requestDevice(int frame_routing_id, - const blink::WebRequestDeviceOptions& options, - blink::WebBluetoothRequestDeviceCallbacks* callbacks); - - // WorkerThread::Observer implementation. - void WillStopCurrentWorkerThread() override; - - private: - // IPC Handlers, see definitions in bluetooth_messages.h. - void OnRequestDeviceSuccess(int thread_id, - int request_id, - const BluetoothDevice& device); - void OnRequestDeviceError(int thread_id, - int request_id, - blink::WebBluetoothError error); - - scoped_refptr<ThreadSafeSender> thread_safe_sender_; - - // Tracks device requests sent to browser to match replies with callbacks. - // Owns callback objects. - IDMap<blink::WebBluetoothRequestDeviceCallbacks, IDMapOwnPointer> - pending_requests_; - - DISALLOW_COPY_AND_ASSIGN(BluetoothDispatcher); -}; - -} // namespace content - -#endif // CONTENT_CHILD_BLUETOOTH_BLUETOOTH_DISPATCHER_H_ diff --git a/chromium/content/renderer/bluetooth/bluetooth_message_filter.cc b/chromium/content/renderer/bluetooth/bluetooth_message_filter.cc deleted file mode 100644 index bd688da95c3..00000000000 --- a/chromium/content/renderer/bluetooth/bluetooth_message_filter.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/bluetooth/bluetooth_message_filter.h" - -#include "content/child/thread_safe_sender.h" -#include "content/renderer/bluetooth/bluetooth_dispatcher.h" -#include "ipc/ipc_message_macros.h" - -namespace content { - -BluetoothMessageFilter::BluetoothMessageFilter(ThreadSafeSender* sender) - : WorkerThreadMessageFilter(sender) { -} - -BluetoothMessageFilter::~BluetoothMessageFilter() { -} - -bool BluetoothMessageFilter::ShouldHandleMessage( - const IPC::Message& msg) const { - return IPC_MESSAGE_CLASS(msg) == BluetoothMsgStart; -} - -void BluetoothMessageFilter::OnFilteredMessageReceived( - const IPC::Message& msg) { - BluetoothDispatcher::GetOrCreateThreadSpecificInstance(thread_safe_sender()) - ->OnMessageReceived(msg); -} - -bool BluetoothMessageFilter::GetWorkerThreadIdForMessage( - const IPC::Message& msg, - int* ipc_thread_id) { - return base::PickleIterator(msg).ReadInt(ipc_thread_id); -} - -} // namespace content diff --git a/chromium/content/renderer/bluetooth/bluetooth_message_filter.h b/chromium/content/renderer/bluetooth/bluetooth_message_filter.h deleted file mode 100644 index 365e21aeb71..00000000000 --- a/chromium/content/renderer/bluetooth/bluetooth_message_filter.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_CHILD_BLUETOOTH_BLUETOOTH_MESSAGE_FILTER_H_ -#define CONTENT_CHILD_BLUETOOTH_BLUETOOTH_MESSAGE_FILTER_H_ - -#include "base/macros.h" -#include "content/child/worker_thread_message_filter.h" - -namespace content { - -class BluetoothMessageFilter : public WorkerThreadMessageFilter { - public: - explicit BluetoothMessageFilter(ThreadSafeSender* thread_safe_sender); - - private: - ~BluetoothMessageFilter() override; - - // WorkerThreadMessageFilter: - bool ShouldHandleMessage(const IPC::Message& msg) const override; - void OnFilteredMessageReceived(const IPC::Message& msg) override; - bool GetWorkerThreadIdForMessage(const IPC::Message& msg, - int* ipc_thread_id) override; - - DISALLOW_COPY_AND_ASSIGN(BluetoothMessageFilter); -}; - -} // namespace content - -#endif // CONTENT_CHILD_BLUETOOTH_BLUETOOTH_MESSAGE_FILTER_H_ diff --git a/chromium/content/renderer/bluetooth/bluetooth_type_converters.cc b/chromium/content/renderer/bluetooth/bluetooth_type_converters.cc new file mode 100644 index 00000000000..c7bf1a79489 --- /dev/null +++ b/chromium/content/renderer/bluetooth/bluetooth_type_converters.cc @@ -0,0 +1,60 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/bluetooth/bluetooth_type_converters.h" + +#include "content/child/mojo/type_converters.h" +#include "third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h" + +namespace mojo { + +// static +blink::mojom::WebBluetoothScanFilterPtr TypeConverter< + blink::mojom::WebBluetoothScanFilterPtr, + blink::WebBluetoothScanFilter>::Convert(const blink::WebBluetoothScanFilter& + web_filter) { + blink::mojom::WebBluetoothScanFilterPtr filter = + blink::mojom::WebBluetoothScanFilter::New(); + + if (!web_filter.services.isEmpty()) + filter->services = + Array<base::Optional<device::BluetoothUUID>>::From(web_filter.services); + + if (web_filter.hasName) + filter->name = String::From(web_filter.name); + + if (!web_filter.namePrefix.isEmpty()) + filter->name_prefix = String::From(web_filter.namePrefix); + return filter; +} + +// static +blink::mojom::WebBluetoothRequestDeviceOptionsPtr +TypeConverter<blink::mojom::WebBluetoothRequestDeviceOptionsPtr, + blink::WebRequestDeviceOptions>:: + Convert(const blink::WebRequestDeviceOptions& web_options) { + blink::mojom::WebBluetoothRequestDeviceOptionsPtr options = + blink::mojom::WebBluetoothRequestDeviceOptions::New(); + + options->filters = mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>::From( + web_options.filters); + options->optional_services = + mojo::Array<base::Optional<device::BluetoothUUID>>::From( + web_options.optionalServices); + return options; +} + +// static +base::Optional<device::BluetoothUUID> +TypeConverter<base::Optional<device::BluetoothUUID>, blink::WebString>::Convert( + const blink::WebString& web_string) { + base::Optional<device::BluetoothUUID> uuid = + device::BluetoothUUID(web_string.utf8()); + + DCHECK(uuid->IsValid()); + + return uuid; +} + +} // namespace mojo diff --git a/chromium/content/renderer/bluetooth/bluetooth_type_converters.h b/chromium/content/renderer/bluetooth/bluetooth_type_converters.h new file mode 100644 index 00000000000..2b6e5263d4f --- /dev/null +++ b/chromium/content/renderer/bluetooth/bluetooth_type_converters.h @@ -0,0 +1,43 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_BLUETOOTH_BLUETOOTH_TYPE_CONVERTERS_H_ +#define CONTENT_RENDERER_BLUETOOTH_BLUETOOTH_TYPE_CONVERTERS_H_ + +#include "base/optional.h" +#include "device/bluetooth/bluetooth_uuid.h" +#include "mojo/public/cpp/bindings/type_converter.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h" + +namespace blink { +struct WebBluetoothScanFilter; +struct WebRequestDeviceOptions; +} + +namespace mojo { + +template <> +struct TypeConverter<blink::mojom::WebBluetoothScanFilterPtr, + blink::WebBluetoothScanFilter> { + static blink::mojom::WebBluetoothScanFilterPtr Convert( + const blink::WebBluetoothScanFilter& web_filter); +}; + +template <> +struct TypeConverter<blink::mojom::WebBluetoothRequestDeviceOptionsPtr, + blink::WebRequestDeviceOptions> { + static blink::mojom::WebBluetoothRequestDeviceOptionsPtr Convert( + const blink::WebRequestDeviceOptions& web_options); +}; + +template <> +struct TypeConverter<base::Optional<device::BluetoothUUID>, blink::WebString> { + static base::Optional<device::BluetoothUUID> Convert( + const blink::WebString& web_string); +}; + +} // namespace mojo + +#endif // CONTENT_RENDERER_BLUETOOTH_BLUETOOTH_TYPE_CONVERTERS_H_ diff --git a/chromium/content/renderer/bluetooth/web_bluetooth_impl.cc b/chromium/content/renderer/bluetooth/web_bluetooth_impl.cc index 2f4da53dcdf..f245362d225 100644 --- a/chromium/content/renderer/bluetooth/web_bluetooth_impl.cc +++ b/chromium/content/renderer/bluetooth/web_bluetooth_impl.cc @@ -9,26 +9,24 @@ #include <vector> #include "base/memory/ptr_util.h" +#include "base/optional.h" #include "content/child/mojo/type_converters.h" #include "content/child/thread_safe_sender.h" -#include "content/public/common/service_registry.h" -#include "content/renderer/bluetooth/bluetooth_dispatcher.h" +#include "content/renderer/bluetooth/bluetooth_type_converters.h" #include "ipc/ipc_message.h" #include "mojo/public/cpp/bindings/array.h" +#include "services/shell/public/cpp/interface_provider.h" #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h" +#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDeviceInit.h" #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristic.h" #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTCharacteristicInit.h" #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothRemoteGATTService.h" +#include "third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h" namespace content { -WebBluetoothImpl::WebBluetoothImpl(ServiceRegistry* service_registry, - ThreadSafeSender* thread_safe_sender, - int frame_routing_id) - : service_registry_(service_registry), - binding_(this), - thread_safe_sender_(thread_safe_sender), - frame_routing_id_(frame_routing_id) {} +WebBluetoothImpl::WebBluetoothImpl(shell::InterfaceProvider* remote_interfaces) + : remote_interfaces_(remote_interfaces), binding_(this) {} WebBluetoothImpl::~WebBluetoothImpl() { } @@ -36,7 +34,11 @@ WebBluetoothImpl::~WebBluetoothImpl() { void WebBluetoothImpl::requestDevice( const blink::WebRequestDeviceOptions& options, blink::WebBluetoothRequestDeviceCallbacks* callbacks) { - GetDispatcher()->requestDevice(frame_routing_id_, options, callbacks); + GetWebBluetoothService().RequestDevice( + blink::mojom::WebBluetoothRequestDeviceOptions::From(options), + base::Bind(&WebBluetoothImpl::OnRequestDeviceComplete, + base::Unretained(this), + base::Passed(base::WrapUnique(callbacks)))); } void WebBluetoothImpl::connect( @@ -60,13 +62,18 @@ void WebBluetoothImpl::disconnect(const blink::WebString& device_id) { mojo::String::From(device_id)); } -void WebBluetoothImpl::getPrimaryService( +void WebBluetoothImpl::getPrimaryServices( const blink::WebString& device_id, - const blink::WebString& service_uuid, - blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks) { - GetWebBluetoothService().RemoteServerGetPrimaryService( - mojo::String::From(device_id), mojo::String::From(service_uuid), - base::Bind(&WebBluetoothImpl::OnGetPrimaryServiceComplete, + + blink::mojom::WebBluetoothGATTQueryQuantity quantity, + const blink::WebString& services_uuid, + blink::WebBluetoothGetPrimaryServicesCallbacks* callbacks) { + GetWebBluetoothService().RemoteServerGetPrimaryServices( + mojo::String::From(device_id), quantity, + services_uuid.isEmpty() + ? base::nullopt + : base::make_optional(device::BluetoothUUID(services_uuid.utf8())), + base::Bind(&WebBluetoothImpl::OnGetPrimaryServicesComplete, base::Unretained(this), device_id, base::Passed(base::WrapUnique(callbacks)))); } @@ -78,8 +85,10 @@ void WebBluetoothImpl::getCharacteristics( blink::WebBluetoothGetCharacteristicsCallbacks* callbacks) { GetWebBluetoothService().RemoteServiceGetCharacteristics( mojo::String::From(service_instance_id), quantity, - characteristics_uuid.isEmpty() ? nullptr - : mojo::String::From(characteristics_uuid), + characteristics_uuid.isEmpty() + ? base::nullopt + : base::make_optional( + device::BluetoothUUID(characteristics_uuid.utf8())), base::Bind(&WebBluetoothImpl::OnGetCharacteristicsComplete, base::Unretained(this), service_instance_id, base::Passed(base::WrapUnique(callbacks)))); @@ -154,11 +163,32 @@ void WebBluetoothImpl::RemoteCharacteristicValueChanged( value.PassStorage())); } +void WebBluetoothImpl::OnRequestDeviceComplete( + std::unique_ptr<blink::WebBluetoothRequestDeviceCallbacks> callbacks, + const blink::mojom::WebBluetoothError error, + blink::mojom::WebBluetoothDevicePtr device) { + if (error == blink::mojom::WebBluetoothError::SUCCESS) { + blink::WebVector<blink::WebString> uuids(device->uuids.size()); + for (size_t i = 0; i < device->uuids.size(); ++i) + uuids[i] = blink::WebString::fromUTF8(device->uuids[i]); + + callbacks->onSuccess(base::WrapUnique(new blink::WebBluetoothDeviceInit( + blink::WebString::fromUTF8(device->id), + blink::WebString::fromUTF8(device->name), uuids))); + } else { + callbacks->onError(error); + } +} + void WebBluetoothImpl::GattServerDisconnected(const mojo::String& device_id) { auto device_iter = connected_devices_.find(device_id); if (device_iter != connected_devices_.end()) { - device_iter->second->dispatchGattServerDisconnected(); + // Remove device from the map before calling dispatchGattServerDisconnected + // to avoid removing a device the gattserverdisconnected event handler might + // have re-connected. + blink::WebBluetoothDevice* device = device_iter->second; connected_devices_.erase(device_iter); + device->dispatchGattServerDisconnected(); } } @@ -173,17 +203,23 @@ void WebBluetoothImpl::OnConnectComplete( } } -void WebBluetoothImpl::OnGetPrimaryServiceComplete( +void WebBluetoothImpl::OnGetPrimaryServicesComplete( const blink::WebString& device_id, - std::unique_ptr<blink::WebBluetoothGetPrimaryServiceCallbacks> callbacks, + std::unique_ptr<blink::WebBluetoothGetPrimaryServicesCallbacks> callbacks, blink::mojom::WebBluetoothError error, - blink::mojom::WebBluetoothRemoteGATTServicePtr service) { + mojo::Array<blink::mojom::WebBluetoothRemoteGATTServicePtr> services) { if (error == blink::mojom::WebBluetoothError::SUCCESS) { - callbacks->onSuccess( - base::WrapUnique(new blink::WebBluetoothRemoteGATTService( - blink::WebString::fromUTF8(service->instance_id), - blink::WebString::fromUTF8(service->uuid), true /* isPrimary */, - device_id))); + // TODO(dcheng): This WebVector should use smart pointers. + blink::WebVector<blink::WebBluetoothRemoteGATTService*> promise_services( + services.size()); + + for (size_t i = 0; i < services.size(); i++) { + promise_services[i] = new blink::WebBluetoothRemoteGATTService( + blink::WebString::fromUTF8(services[i]->instance_id), + blink::WebString::fromUTF8(services[i]->uuid), true /* isPrimary */, + device_id); + } + callbacks->onSuccess(promise_services); } else { callbacks->onError(error); } @@ -260,15 +296,9 @@ void WebBluetoothImpl::DispatchCharacteristicValueChanged( } } -BluetoothDispatcher* WebBluetoothImpl::GetDispatcher() { - return BluetoothDispatcher::GetOrCreateThreadSpecificInstance( - thread_safe_sender_.get()); -} - blink::mojom::WebBluetoothService& WebBluetoothImpl::GetWebBluetoothService() { if (!web_bluetooth_service_) { - service_registry_->ConnectToRemoteService( - mojo::GetProxy(&web_bluetooth_service_)); + remote_interfaces_->GetInterface(mojo::GetProxy(&web_bluetooth_service_)); // Create an associated interface ptr and pass it to the WebBluetoothService // so that it can send us events without us prompting. blink::mojom::WebBluetoothServiceClientAssociatedPtrInfo ptr_info; diff --git a/chromium/content/renderer/bluetooth/web_bluetooth_impl.h b/chromium/content/renderer/bluetooth/web_bluetooth_impl.h index fae4ad485ee..13d7c7b9a18 100644 --- a/chromium/content/renderer/bluetooth/web_bluetooth_impl.h +++ b/chromium/content/renderer/bluetooth/web_bluetooth_impl.h @@ -25,11 +25,14 @@ namespace blink { class WebBluetoothRemoteGATTCharacteristic; } +namespace shell { +class InterfaceProvider; +} + namespace content { class BluetoothDispatcher; class ThreadSafeSender; -class ServiceRegistry; // Implementation of blink::WebBluetooth. Passes calls through to the thread // specific BluetoothDispatcher. @@ -37,9 +40,7 @@ class CONTENT_EXPORT WebBluetoothImpl : NON_EXPORTED_BASE(public blink::mojom::WebBluetoothServiceClient), NON_EXPORTED_BASE(public blink::WebBluetooth) { public: - WebBluetoothImpl(ServiceRegistry* service_registry, - ThreadSafeSender* thread_safe_sender, - int frame_routing_id); + WebBluetoothImpl(shell::InterfaceProvider* remote_interfaces); ~WebBluetoothImpl() override; // blink::WebBluetooth interface: @@ -51,10 +52,11 @@ class CONTENT_EXPORT WebBluetoothImpl blink::WebBluetoothDevice* device, blink::WebBluetoothRemoteGATTServerConnectCallbacks* callbacks) override; void disconnect(const blink::WebString& device_id) override; - void getPrimaryService( + void getPrimaryServices( const blink::WebString& device_id, - const blink::WebString& service_uuid, - blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks) override; + blink::mojom::WebBluetoothGATTQueryQuantity quantity, + const blink::WebString& services_uuid, + blink::WebBluetoothGetPrimaryServicesCallbacks* callbacks) override; void getCharacteristics( const blink::WebString& service_instance_id, blink::mojom::WebBluetoothGATTQueryQuantity quantity, @@ -87,15 +89,19 @@ class CONTENT_EXPORT WebBluetoothImpl void GattServerDisconnected(const mojo::String& device_id) override; // Callbacks for WebBluetoothService calls: + void OnRequestDeviceComplete( + std::unique_ptr<blink::WebBluetoothRequestDeviceCallbacks> callbacks, + const blink::mojom::WebBluetoothError error, + blink::mojom::WebBluetoothDevicePtr device); void OnConnectComplete( std::unique_ptr<blink::WebBluetoothRemoteGATTServerConnectCallbacks> callbacks, blink::mojom::WebBluetoothError error); - void OnGetPrimaryServiceComplete( + void OnGetPrimaryServicesComplete( const blink::WebString& device_id, - std::unique_ptr<blink::WebBluetoothGetPrimaryServiceCallbacks> callbacks, + std::unique_ptr<blink::WebBluetoothGetPrimaryServicesCallbacks> callbacks, blink::mojom::WebBluetoothError error, - blink::mojom::WebBluetoothRemoteGATTServicePtr service); + mojo::Array<blink::mojom::WebBluetoothRemoteGATTServicePtr> services); void OnGetCharacteristicsComplete( const blink::WebString& service_instance_id, std::unique_ptr<blink::WebBluetoothGetCharacteristicsCallbacks> callbacks, @@ -120,10 +126,8 @@ class CONTENT_EXPORT WebBluetoothImpl const std::string& characteristic_instance_id, const std::vector<uint8_t>& value); - BluetoothDispatcher* GetDispatcher(); - blink::mojom::WebBluetoothService& GetWebBluetoothService(); - ServiceRegistry* const service_registry_; + shell::InterfaceProvider* const remote_interfaces_; blink::mojom::WebBluetoothServicePtr web_bluetooth_service_; // Map of characteristic_instance_ids to @@ -142,9 +146,6 @@ class CONTENT_EXPORT WebBluetoothImpl // Binding associated with |web_bluetooth_service_|. mojo::AssociatedBinding<blink::mojom::WebBluetoothServiceClient> binding_; - const scoped_refptr<ThreadSafeSender> thread_safe_sender_; - const int frame_routing_id_; - DISALLOW_COPY_AND_ASSIGN(WebBluetoothImpl); }; diff --git a/chromium/content/renderer/browser_plugin/browser_plugin.cc b/chromium/content/renderer/browser_plugin/browser_plugin.cc index 76e71752418..75d15c837cc 100644 --- a/chromium/content/renderer/browser_plugin/browser_plugin.cc +++ b/chromium/content/renderer/browser_plugin/browser_plugin.cc @@ -325,7 +325,7 @@ void BrowserPlugin::destroy() { render_frame ? render_frame->GetRenderView() : nullptr); if (render_view) render_view->mouse_lock_dispatcher()->OnLockTargetDestroyed(this); - base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); } v8::Local<v8::Object> BrowserPlugin::v8ScriptableObject(v8::Isolate* isolate) { diff --git a/chromium/content/renderer/browser_plugin/browser_plugin.h b/chromium/content/renderer/browser_plugin/browser_plugin.h index 6cd8bebea23..99092e4ba99 100644 --- a/chromium/content/renderer/browser_plugin/browser_plugin.h +++ b/chromium/content/renderer/browser_plugin/browser_plugin.h @@ -23,7 +23,7 @@ struct BrowserPluginHostMsg_ResizeGuest_Params; struct FrameMsg_BuffersSwapped_Params; namespace cc { -struct SurfaceId; +class SurfaceId; struct SurfaceSequence; } diff --git a/chromium/content/renderer/cache_storage/cache_storage_dispatcher.cc b/chromium/content/renderer/cache_storage/cache_storage_dispatcher.cc index 5bc3521dea1..a490e4c69b5 100644 --- a/chromium/content/renderer/cache_storage/cache_storage_dispatcher.cc +++ b/chromium/content/renderer/cache_storage/cache_storage_dispatcher.cc @@ -82,6 +82,9 @@ ServiceWorkerResponse ResponseFromWebResponse( const blink::WebServiceWorkerResponse& web_response) { ServiceWorkerHeaderMap headers; GetServiceWorkerHeaderMapFromWebResponse(web_response, &headers); + ServiceWorkerHeaderList cors_exposed_header_names; + GetCorsExposedHeaderNamesFromWebResponse(web_response, + &cors_exposed_header_names); // We don't support streaming for cache. DCHECK(web_response.streamURL().isEmpty()); return ServiceWorkerResponse( @@ -93,7 +96,7 @@ ServiceWorkerResponse ResponseFromWebResponse( blink::WebServiceWorkerResponseErrorUnknown, base::Time::FromInternalValue(web_response.responseTime()), !web_response.cacheStorageCacheName().isNull(), - web_response.cacheStorageCacheName().utf8()); + web_response.cacheStorageCacheName().utf8(), cors_exposed_header_names); } CacheStorageCacheQueryParams QueryParamsFromWebQueryParams( @@ -655,6 +658,13 @@ void CacheStorageDispatcher::PopulateWebResponseFromResponse( response.is_in_cache_storage ? blink::WebString::fromUTF8(response.cache_storage_cache_name) : blink::WebString()); + blink::WebVector<blink::WebString> headers( + response.cors_exposed_header_names.size()); + std::transform( + response.cors_exposed_header_names.begin(), + response.cors_exposed_header_names.end(), headers.begin(), + [](const std::string& h) { return blink::WebString::fromLatin1(h); }); + web_response->setCorsExposedHeaderNames(headers); for (const auto& i : response.headers) { web_response->setHeader(base::ASCIIToUTF16(i.first), diff --git a/chromium/content/renderer/raster_worker_pool.cc b/chromium/content/renderer/categorized_worker_pool.cc index 8c50e01b3b9..41814b4bcd3 100644 --- a/chromium/content/renderer/raster_worker_pool.cc +++ b/chromium/content/renderer/categorized_worker_pool.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/raster_worker_pool.h" +#include "content/renderer/categorized_worker_pool.h" #include <string> #include <utility> @@ -17,15 +17,16 @@ namespace content { namespace { -// A thread which forwards to RasterWorkerPool::Run with the runnable +// A thread which forwards to CategorizedWorkerPool::Run with the runnable // categories. -class RasterWorkerPoolThread : public base::SimpleThread { +class CategorizedWorkerPoolThread : public base::SimpleThread { public: - RasterWorkerPoolThread(const std::string& name_prefix, - const Options& options, - RasterWorkerPool* pool, - std::vector<cc::TaskCategory> categories, - base::ConditionVariable* has_ready_to_run_tasks_cv) + CategorizedWorkerPoolThread( + const std::string& name_prefix, + const Options& options, + CategorizedWorkerPool* pool, + std::vector<cc::TaskCategory> categories, + base::ConditionVariable* has_ready_to_run_tasks_cv) : SimpleThread(name_prefix, options), pool_(pool), categories_(categories), @@ -34,18 +35,18 @@ class RasterWorkerPoolThread : public base::SimpleThread { void Run() override { pool_->Run(categories_, has_ready_to_run_tasks_cv_); } private: - RasterWorkerPool* const pool_; + CategorizedWorkerPool* const pool_; const std::vector<cc::TaskCategory> categories_; base::ConditionVariable* const has_ready_to_run_tasks_cv_; }; } // namespace -// A sequenced task runner which posts tasks to a RasterWorkerPool. -class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner +// A sequenced task runner which posts tasks to a CategorizedWorkerPool. +class CategorizedWorkerPool::CategorizedWorkerPoolSequencedTaskRunner : public base::SequencedTaskRunner { public: - explicit RasterWorkerPoolSequencedTaskRunner( + explicit CategorizedWorkerPoolSequencedTaskRunner( cc::TaskGraphRunner* task_graph_runner) : task_graph_runner_(task_graph_runner), namespace_token_(task_graph_runner->GetNamespaceToken()) {} @@ -95,7 +96,7 @@ class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner } private: - ~RasterWorkerPoolSequencedTaskRunner() override { + ~CategorizedWorkerPoolSequencedTaskRunner() override { task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); task_graph_runner_->CollectCompletedTasks(namespace_token_, &completed_tasks_); @@ -117,14 +118,14 @@ class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner cc::Task::Vector completed_tasks_; }; -RasterWorkerPool::RasterWorkerPool() +CategorizedWorkerPool::CategorizedWorkerPool() : namespace_token_(GetNamespaceToken()), has_ready_to_run_foreground_tasks_cv_(&lock_), has_ready_to_run_background_tasks_cv_(&lock_), has_namespaces_with_finished_running_tasks_cv_(&lock_), shutdown_(false) {} -void RasterWorkerPool::Start(int num_threads) { +void CategorizedWorkerPool::Start(int num_threads) { DCHECK(threads_.empty()); // Start |num_threads| threads for foreground work, including nonconcurrent @@ -134,7 +135,7 @@ void RasterWorkerPool::Start(int num_threads) { foreground_categories.push_back(cc::TASK_CATEGORY_FOREGROUND); for (int i = 0; i < num_threads; i++) { - std::unique_ptr<base::SimpleThread> thread(new RasterWorkerPoolThread( + std::unique_ptr<base::SimpleThread> thread(new CategorizedWorkerPoolThread( base::StringPrintf("CompositorTileWorker%u", static_cast<unsigned>(threads_.size() + 1)) .c_str(), @@ -154,14 +155,14 @@ void RasterWorkerPool::Start(int num_threads) { thread_options.set_priority(base::ThreadPriority::BACKGROUND); #endif - std::unique_ptr<base::SimpleThread> thread(new RasterWorkerPoolThread( + std::unique_ptr<base::SimpleThread> thread(new CategorizedWorkerPoolThread( "CompositorTileWorkerBackground", thread_options, this, background_categories, &has_ready_to_run_background_tasks_cv_)); thread->Start(); threads_.push_back(std::move(thread)); } -void RasterWorkerPool::Shutdown() { +void CategorizedWorkerPool::Shutdown() { WaitForTasksToFinishRunning(namespace_token_); CollectCompletedTasks(namespace_token_, &completed_tasks_); // Shutdown raster threads. @@ -185,7 +186,7 @@ void RasterWorkerPool::Shutdown() { } // Overridden from base::TaskRunner: -bool RasterWorkerPool::PostDelayedTask( +bool CategorizedWorkerPool::PostDelayedTask( const tracked_objects::Location& from_here, const base::Closure& task, base::TimeDelta delay) { @@ -218,12 +219,13 @@ bool RasterWorkerPool::PostDelayedTask( return true; } -bool RasterWorkerPool::RunsTasksOnCurrentThread() const { +bool CategorizedWorkerPool::RunsTasksOnCurrentThread() const { return true; } -void RasterWorkerPool::Run(const std::vector<cc::TaskCategory>& categories, - base::ConditionVariable* has_ready_to_run_tasks_cv) { +void CategorizedWorkerPool::Run( + const std::vector<cc::TaskCategory>& categories, + base::ConditionVariable* has_ready_to_run_tasks_cv) { base::AutoLock lock(lock_); while (true) { @@ -243,7 +245,7 @@ void RasterWorkerPool::Run(const std::vector<cc::TaskCategory>& categories, } } -void RasterWorkerPool::FlushForTesting() { +void CategorizedWorkerPool::FlushForTesting() { base::AutoLock lock(lock_); while (!work_queue_.HasFinishedRunningTasksInAllNamespaces()) { @@ -252,21 +254,21 @@ void RasterWorkerPool::FlushForTesting() { } scoped_refptr<base::SequencedTaskRunner> -RasterWorkerPool::CreateSequencedTaskRunner() { - return new RasterWorkerPoolSequencedTaskRunner(this); +CategorizedWorkerPool::CreateSequencedTaskRunner() { + return new CategorizedWorkerPoolSequencedTaskRunner(this); } -RasterWorkerPool::~RasterWorkerPool() {} +CategorizedWorkerPool::~CategorizedWorkerPool() {} -cc::NamespaceToken RasterWorkerPool::GetNamespaceToken() { +cc::NamespaceToken CategorizedWorkerPool::GetNamespaceToken() { base::AutoLock lock(lock_); return work_queue_.GetNamespaceToken(); } -void RasterWorkerPool::ScheduleTasks(cc::NamespaceToken token, - cc::TaskGraph* graph) { +void CategorizedWorkerPool::ScheduleTasks(cc::NamespaceToken token, + cc::TaskGraph* graph) { TRACE_EVENT2("disabled-by-default-cc.debug", - "RasterWorkerPool::ScheduleTasks", "num_nodes", + "CategorizedWorkerPool::ScheduleTasks", "num_nodes", graph->nodes.size(), "num_edges", graph->edges.size()); { base::AutoLock lock(lock_); @@ -274,8 +276,9 @@ void RasterWorkerPool::ScheduleTasks(cc::NamespaceToken token, } } -void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, - cc::TaskGraph* graph) { +void CategorizedWorkerPool::ScheduleTasksWithLockAcquired( + cc::NamespaceToken token, + cc::TaskGraph* graph) { DCHECK(token.IsValid()); DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph)); DCHECK(!shutdown_); @@ -286,9 +289,10 @@ void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, SignalHasReadyToRunTasksWithLockAcquired(); } -void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { +void CategorizedWorkerPool::WaitForTasksToFinishRunning( + cc::NamespaceToken token) { TRACE_EVENT0("disabled-by-default-cc.debug", - "RasterWorkerPool::WaitForTasksToFinishRunning"); + "CategorizedWorkerPool::WaitForTasksToFinishRunning"); DCHECK(token.IsValid()); @@ -310,11 +314,11 @@ void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { } } -void RasterWorkerPool::CollectCompletedTasks( +void CategorizedWorkerPool::CollectCompletedTasks( cc::NamespaceToken token, cc::Task::Vector* completed_tasks) { TRACE_EVENT0("disabled-by-default-cc.debug", - "RasterWorkerPool::CollectCompletedTasks"); + "CategorizedWorkerPool::CollectCompletedTasks"); { base::AutoLock lock(lock_); @@ -322,14 +326,14 @@ void RasterWorkerPool::CollectCompletedTasks( } } -void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( +void CategorizedWorkerPool::CollectCompletedTasksWithLockAcquired( cc::NamespaceToken token, cc::Task::Vector* completed_tasks) { DCHECK(token.IsValid()); work_queue_.CollectCompletedTasks(token, completed_tasks); } -bool RasterWorkerPool::RunTaskWithLockAcquired( +bool CategorizedWorkerPool::RunTaskWithLockAcquired( const std::vector<cc::TaskCategory>& categories) { for (const auto& category : categories) { if (ShouldRunTaskForCategoryWithLockAcquired(category)) { @@ -340,7 +344,7 @@ bool RasterWorkerPool::RunTaskWithLockAcquired( return false; } -void RasterWorkerPool::RunTaskInCategoryWithLockAcquired( +void CategorizedWorkerPool::RunTaskInCategoryWithLockAcquired( cc::TaskCategory category) { TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); @@ -366,7 +370,7 @@ void RasterWorkerPool::RunTaskInCategoryWithLockAcquired( has_namespaces_with_finished_running_tasks_cv_.Signal(); } -bool RasterWorkerPool::ShouldRunTaskForCategoryWithLockAcquired( +bool CategorizedWorkerPool::ShouldRunTaskForCategoryWithLockAcquired( cc::TaskCategory category) { lock_.AssertAcquired(); @@ -399,7 +403,7 @@ bool RasterWorkerPool::ShouldRunTaskForCategoryWithLockAcquired( return true; } -void RasterWorkerPool::SignalHasReadyToRunTasksWithLockAcquired() { +void CategorizedWorkerPool::SignalHasReadyToRunTasksWithLockAcquired() { lock_.AssertAcquired(); if (ShouldRunTaskForCategoryWithLockAcquired(cc::TASK_CATEGORY_FOREGROUND) || @@ -413,15 +417,15 @@ void RasterWorkerPool::SignalHasReadyToRunTasksWithLockAcquired() { } } -RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) +CategorizedWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) : closure_(closure) {} // Overridden from cc::Task: -void RasterWorkerPool::ClosureTask::RunOnWorkerThread() { +void CategorizedWorkerPool::ClosureTask::RunOnWorkerThread() { closure_.Run(); closure_.Reset(); } -RasterWorkerPool::ClosureTask::~ClosureTask() {} +CategorizedWorkerPool::ClosureTask::~ClosureTask() {} } // namespace content diff --git a/chromium/content/renderer/raster_worker_pool.h b/chromium/content/renderer/categorized_worker_pool.h index 10c312be68b..2f75f2183f2 100644 --- a/chromium/content/renderer/raster_worker_pool.h +++ b/chromium/content/renderer/categorized_worker_pool.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_RASTER_WORKER_POOL_H_ -#define CONTENT_RENDERER_RASTER_WORKER_POOL_H_ +#ifndef CONTENT_RENDERER_CATEGORIZED_WORKER_POOL_H_ +#define CONTENT_RENDERER_CATEGORIZED_WORKER_POOL_H_ #include <memory> @@ -21,18 +21,18 @@ namespace content { -// A pool of threads used to run raster work. -// Work can be scheduled on the threads using different interfaces. -// The pool itself implements TaskRunner interface and tasks posted via that -// interface might run in parallel. -// CreateSequencedTaskRunner creates a sequenced task runner that might run in -// parallel with other instances of sequenced task runners. -// It's also possible to get the underlying TaskGraphRunner to schedule a graph -// of tasks with their dependencies. -class CONTENT_EXPORT RasterWorkerPool : public base::TaskRunner, - public cc::TaskGraphRunner { +// A pool of threads used to run categorized work. The work can be scheduled on +// the threads using different interfaces. +// 1. The pool itself implements TaskRunner interface and tasks posted via that +// interface might run in parallel. +// 2. The pool also implements TaskGraphRunner interface which allows to +// schedule a graph of tasks with their dependencies. +// 3. CreateSequencedTaskRunner() creates a sequenced task runner that might run +// in parallel with other instances of sequenced task runners. +class CONTENT_EXPORT CategorizedWorkerPool : public base::TaskRunner, + public cc::TaskGraphRunner { public: - RasterWorkerPool(); + CategorizedWorkerPool(); // Overridden from base::TaskRunner: bool PostDelayedTask(const tracked_objects::Location& from_here, @@ -70,11 +70,11 @@ class CONTENT_EXPORT RasterWorkerPool : public base::TaskRunner, scoped_refptr<base::SequencedTaskRunner> CreateSequencedTaskRunner(); protected: - ~RasterWorkerPool() override; + ~CategorizedWorkerPool() override; private: - class RasterWorkerPoolSequencedTaskRunner; - friend class RasterWorkerPoolSequencedTaskRunner; + class CategorizedWorkerPoolSequencedTaskRunner; + friend class CategorizedWorkerPoolSequencedTaskRunner; // Simple Task for the TaskGraphRunner that wraps a closure. // This class is used to schedule TaskRunner tasks on the @@ -145,4 +145,4 @@ class CONTENT_EXPORT RasterWorkerPool : public base::TaskRunner, } // namespace content -#endif // CONTENT_RENDERER_RASTER_WORKER_POOL_H_ +#endif // CONTENT_RENDERER_CATEGORIZED_WORKER_POOL_H_ diff --git a/chromium/content/renderer/categorized_worker_pool_unittest.cc b/chromium/content/renderer/categorized_worker_pool_unittest.cc new file mode 100644 index 00000000000..9e6fb19ec0a --- /dev/null +++ b/chromium/content/renderer/categorized_worker_pool_unittest.cc @@ -0,0 +1,122 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/test/sequenced_task_runner_test_template.h" +#include "base/test/task_runner_test_template.h" +#include "base/threading/simple_thread.h" +#include "cc/test/task_graph_runner_test_template.h" +#include "content/renderer/categorized_worker_pool.h" + +namespace base { +namespace { + +// Number of threads spawned in tests. +const int kNumThreads = 4; + +class CategorizedWorkerPoolTestDelegate { + public: + CategorizedWorkerPoolTestDelegate() + : categorized_worker_pool_(new content::CategorizedWorkerPool()) {} + + void StartTaskRunner() { categorized_worker_pool_->Start(kNumThreads); } + + scoped_refptr<content::CategorizedWorkerPool> GetTaskRunner() { + return categorized_worker_pool_; + } + + void StopTaskRunner() { categorized_worker_pool_->FlushForTesting(); } + + ~CategorizedWorkerPoolTestDelegate() { categorized_worker_pool_->Shutdown(); } + + private: + scoped_refptr<content::CategorizedWorkerPool> categorized_worker_pool_; +}; + +INSTANTIATE_TYPED_TEST_CASE_P(CategorizedWorkerPool, + TaskRunnerTest, + CategorizedWorkerPoolTestDelegate); + +class CategorizedWorkerPoolSequencedTestDelegate { + public: + CategorizedWorkerPoolSequencedTestDelegate() + : categorized_worker_pool_(new content::CategorizedWorkerPool()) {} + + void StartTaskRunner() { categorized_worker_pool_->Start(kNumThreads); } + + scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() { + return categorized_worker_pool_->CreateSequencedTaskRunner(); + } + + void StopTaskRunner() { categorized_worker_pool_->FlushForTesting(); } + + ~CategorizedWorkerPoolSequencedTestDelegate() { + categorized_worker_pool_->Shutdown(); + } + + private: + scoped_refptr<content::CategorizedWorkerPool> categorized_worker_pool_; +}; + +INSTANTIATE_TYPED_TEST_CASE_P(CategorizedWorkerPool, + SequencedTaskRunnerTest, + CategorizedWorkerPoolSequencedTestDelegate); + +} // namespace +} // namespace base + +namespace cc { +namespace { + +template <int NumThreads> +class CategorizedWorkerPoolTaskGraphRunnerTestDelegate { + public: + CategorizedWorkerPoolTaskGraphRunnerTestDelegate() + : categorized_worker_pool_(new content::CategorizedWorkerPool()) {} + + void StartTaskGraphRunner() { categorized_worker_pool_->Start(NumThreads); } + + cc::TaskGraphRunner* GetTaskGraphRunner() { + return categorized_worker_pool_->GetTaskGraphRunner(); + } + + void StopTaskGraphRunner() { categorized_worker_pool_->FlushForTesting(); } + + ~CategorizedWorkerPoolTaskGraphRunnerTestDelegate() { + categorized_worker_pool_->Shutdown(); + } + + private: + scoped_refptr<content::CategorizedWorkerPool> categorized_worker_pool_; +}; + +// Multithreaded tests. +INSTANTIATE_TYPED_TEST_CASE_P( + CategorizedWorkerPool_1_Threads, + TaskGraphRunnerTest, + CategorizedWorkerPoolTaskGraphRunnerTestDelegate<1>); +INSTANTIATE_TYPED_TEST_CASE_P( + CategorizedWorkerPool_2_Threads, + TaskGraphRunnerTest, + CategorizedWorkerPoolTaskGraphRunnerTestDelegate<2>); +INSTANTIATE_TYPED_TEST_CASE_P( + CategorizedWorkerPool_3_Threads, + TaskGraphRunnerTest, + CategorizedWorkerPoolTaskGraphRunnerTestDelegate<3>); +INSTANTIATE_TYPED_TEST_CASE_P( + CategorizedWorkerPool_4_Threads, + TaskGraphRunnerTest, + CategorizedWorkerPoolTaskGraphRunnerTestDelegate<4>); +INSTANTIATE_TYPED_TEST_CASE_P( + CategorizedWorkerPool_5_Threads, + TaskGraphRunnerTest, + CategorizedWorkerPoolTaskGraphRunnerTestDelegate<5>); + +// Single threaded tests. +INSTANTIATE_TYPED_TEST_CASE_P( + CategorizedWorkerPool, + SingleThreadTaskGraphRunnerTest, + CategorizedWorkerPoolTaskGraphRunnerTestDelegate<1>); + +} // namespace +} // namespace cc diff --git a/chromium/content/renderer/child_frame_compositing_helper.cc b/chromium/content/renderer/child_frame_compositing_helper.cc index cc2ba004c4d..9b98bc69ec1 100644 --- a/chromium/content/renderer/child_frame_compositing_helper.cc +++ b/chromium/content/renderer/child_frame_compositing_helper.cc @@ -149,7 +149,7 @@ void ChildFrameCompositingHelper::ChildFrameGone() { void ChildFrameCompositingHelper::SatisfyCallback( scoped_refptr<ThreadSafeSender> sender, int host_routing_id, - cc::SurfaceSequence sequence) { + const cc::SurfaceSequence& sequence) { // This may be called on either the main or impl thread. sender->Send(new FrameHostMsg_SatisfySequence(host_routing_id, sequence)); } @@ -159,7 +159,7 @@ void ChildFrameCompositingHelper::SatisfyCallbackBrowserPlugin( scoped_refptr<ThreadSafeSender> sender, int host_routing_id, int browser_plugin_instance_id, - cc::SurfaceSequence sequence) { + const cc::SurfaceSequence& sequence) { sender->Send(new BrowserPluginHostMsg_SatisfySequence( host_routing_id, browser_plugin_instance_id, sequence)); } @@ -168,8 +168,8 @@ void ChildFrameCompositingHelper::SatisfyCallbackBrowserPlugin( void ChildFrameCompositingHelper::RequireCallback( scoped_refptr<ThreadSafeSender> sender, int host_routing_id, - cc::SurfaceId id, - cc::SurfaceSequence sequence) { + const cc::SurfaceId& id, + const cc::SurfaceSequence& sequence) { // This may be called on either the main or impl thread. sender->Send(new FrameHostMsg_RequireSequence(host_routing_id, id, sequence)); } @@ -178,8 +178,8 @@ void ChildFrameCompositingHelper::RequireCallbackBrowserPlugin( scoped_refptr<ThreadSafeSender> sender, int host_routing_id, int browser_plugin_instance_id, - cc::SurfaceId id, - cc::SurfaceSequence sequence) { + const cc::SurfaceId& id, + const cc::SurfaceSequence& sequence) { // This may be called on either the main or impl thread. sender->Send(new BrowserPluginHostMsg_RequireSequence( host_routing_id, browser_plugin_instance_id, id, sequence)); diff --git a/chromium/content/renderer/child_frame_compositing_helper.h b/chromium/content/renderer/child_frame_compositing_helper.h index e51ab82870b..09548c71f92 100644 --- a/chromium/content/renderer/child_frame_compositing_helper.h +++ b/chromium/content/renderer/child_frame_compositing_helper.h @@ -93,22 +93,22 @@ class CONTENT_EXPORT ChildFrameCompositingHelper cc::Layer* layer); static void SatisfyCallback(scoped_refptr<ThreadSafeSender> sender, int host_routing_id, - cc::SurfaceSequence sequence); + const cc::SurfaceSequence& sequence); static void SatisfyCallbackBrowserPlugin( scoped_refptr<ThreadSafeSender> sender, int host_routing_id, int browser_plugin_instance_id, - cc::SurfaceSequence sequence); + const cc::SurfaceSequence& sequence); static void RequireCallback(scoped_refptr<ThreadSafeSender> sender, int host_routing_id, - cc::SurfaceId id, - cc::SurfaceSequence sequence); + const cc::SurfaceId& id, + const cc::SurfaceSequence& sequence); static void RequireCallbackBrowserPlugin( scoped_refptr<ThreadSafeSender> sender, int host_routing_id, int browser_plugin_instance_id, - cc::SurfaceId id, - cc::SurfaceSequence sequence); + const cc::SurfaceId& id, + const cc::SurfaceSequence& sequence); void UpdateWebLayer(blink::WebLayer* layer); int host_routing_id_; diff --git a/chromium/content/renderer/devtools/devtools_agent.cc b/chromium/content/renderer/devtools/devtools_agent.cc index 87820f63c32..858e75fd0b9 100644 --- a/chromium/content/renderer/devtools/devtools_agent.cc +++ b/chromium/content/renderer/devtools/devtools_agent.cc @@ -22,6 +22,7 @@ #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_widget.h" #include "ipc/ipc_channel.h" +#include "third_party/WebKit/public/platform/WebFloatRect.h" #include "third_party/WebKit/public/platform/WebPoint.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/web/WebDevToolsAgent.h" @@ -107,6 +108,10 @@ void DevToolsAgent::WidgetWillClose() { ContinueProgram(); } +void DevToolsAgent::OnDestruct() { + delete this; +} + void DevToolsAgent::sendProtocolMessage(int session_id, int call_id, const blink::WebString& message, @@ -258,7 +263,9 @@ void DevToolsAgent::OnDispatchOnInspectorBackend(int session_id, } void DevToolsAgent::OnInspectElement(int x, int y) { - GetWebAgent()->inspectElementAt(WebPoint(x, y)); + blink::WebFloatRect point_rect(x, y, 0, 0); + frame_->GetRenderWidget()->convertWindowToViewport(&point_rect); + GetWebAgent()->inspectElementAt(WebPoint(point_rect.x, point_rect.y)); } void DevToolsAgent::OnRequestNewWindowACK(bool success) { diff --git a/chromium/content/renderer/devtools/devtools_agent.h b/chromium/content/renderer/devtools/devtools_agent.h index 04a5ddec5be..f1a2ea4c315 100644 --- a/chromium/content/renderer/devtools/devtools_agent.h +++ b/chromium/content/renderer/devtools/devtools_agent.h @@ -58,6 +58,7 @@ class CONTENT_EXPORT DevToolsAgent // RenderFrameObserver implementation. bool OnMessageReceived(const IPC::Message& message) override; void WidgetWillClose() override; + void OnDestruct() override; // WebDevToolsAgentClient implementation. void sendProtocolMessage(int session_id, diff --git a/chromium/content/renderer/devtools/devtools_agent_filter.cc b/chromium/content/renderer/devtools/devtools_agent_filter.cc index 0ccf71b20a4..1e015f7910f 100644 --- a/chromium/content/renderer/devtools/devtools_agent_filter.cc +++ b/chromium/content/renderer/devtools/devtools_agent_filter.cc @@ -21,8 +21,12 @@ namespace { class MessageImpl : public WebDevToolsAgent::MessageDescriptor { public: - MessageImpl(const std::string& message, int routing_id) - : msg_(message), + MessageImpl( + const std::string& method, + const std::string& message, + int routing_id) + : method_(method), + msg_(message), routing_id_(routing_id) { } ~MessageImpl() override {} @@ -33,8 +37,10 @@ class MessageImpl : public WebDevToolsAgent::MessageDescriptor { return agent->GetWebAgent(); } WebString message() override { return WebString::fromUTF8(msg_); } + WebString method() override { return WebString::fromUTF8(method_); } private: + std::string method_; std::string msg_; int routing_id_; }; @@ -72,7 +78,7 @@ void DevToolsAgentFilter::OnDispatchOnInspectorBackend( if (WebDevToolsAgent::shouldInterruptForMethod( WebString::fromUTF8(method))) { WebDevToolsAgent::interruptAndDispatch( - session_id, new MessageImpl(message, current_routing_id_)); + session_id, new MessageImpl(method, message, current_routing_id_)); } } diff --git a/chromium/content/renderer/devtools/devtools_client.cc b/chromium/content/renderer/devtools/devtools_client.cc index 3f961293824..edc31a3f368 100644 --- a/chromium/content/renderer/devtools/devtools_client.cc +++ b/chromium/content/renderer/devtools/devtools_client.cc @@ -39,6 +39,10 @@ void DevToolsClient::DidClearWindowObject() { render_frame()->ExecuteJavaScript(base::UTF8ToUTF16(compatibility_script_)); } +void DevToolsClient::OnDestruct() { + delete this; +} + void DevToolsClient::sendMessageToEmbedder(const WebString& message) { Send(new DevToolsHostMsg_DispatchOnEmbedder(routing_id(), message.utf8())); diff --git a/chromium/content/renderer/devtools/devtools_client.h b/chromium/content/renderer/devtools/devtools_client.h index 3d14c4a69c5..d4206e5a8a0 100644 --- a/chromium/content/renderer/devtools/devtools_client.h +++ b/chromium/content/renderer/devtools/devtools_client.h @@ -38,6 +38,7 @@ class CONTENT_EXPORT DevToolsClient private: // RenderFrameObserver overrides. void DidClearWindowObject() override; + void OnDestruct() override; // WebDevToolsFrontendClient implementation. void sendMessageToEmbedder(const blink::WebString&) override; diff --git a/chromium/content/renderer/devtools/render_widget_screen_metrics_emulator.cc b/chromium/content/renderer/devtools/render_widget_screen_metrics_emulator.cc index bad6fa72699..d5f4983f139 100644 --- a/chromium/content/renderer/devtools/render_widget_screen_metrics_emulator.cc +++ b/chromium/content/renderer/devtools/render_widget_screen_metrics_emulator.cc @@ -25,10 +25,10 @@ RenderWidgetScreenMetricsEmulator::RenderWidgetScreenMetricsEmulator( } RenderWidgetScreenMetricsEmulator::~RenderWidgetScreenMetricsEmulator() { + delegate_->Resize(original_resize_params_); delegate_->SetScreenMetricsEmulationParameters(false, emulation_params_); delegate_->SetScreenRects(original_view_screen_rect_, original_window_screen_rect_); - delegate_->Resize(original_resize_params_); } void RenderWidgetScreenMetricsEmulator::ChangeEmulationParams( diff --git a/chromium/content/renderer/devtools/v8_sampling_profiler.cc b/chromium/content/renderer/devtools/v8_sampling_profiler.cc index 5aca412225c..baf2e50b372 100644 --- a/chromium/content/renderer/devtools/v8_sampling_profiler.cc +++ b/chromium/content/renderer/devtools/v8_sampling_profiler.cc @@ -639,7 +639,9 @@ void V8SamplingProfiler::EnableSamplingEventForTesting(int code_added_events, int sample_events) { render_thread_sampler_->SetEventsToCollectForTest(code_added_events, sample_events); - waitable_event_for_testing_.reset(new base::WaitableEvent(false, false)); + waitable_event_for_testing_.reset( + new base::WaitableEvent(base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED)); } void V8SamplingProfiler::WaitSamplingEventForTesting() { diff --git a/chromium/content/renderer/devtools/v8_sampling_profiler_browsertest.cc b/chromium/content/renderer/devtools/v8_sampling_profiler_browsertest.cc index af31cde91c3..eb1f2af080f 100644 --- a/chromium/content/renderer/devtools/v8_sampling_profiler_browsertest.cc +++ b/chromium/content/renderer/devtools/v8_sampling_profiler_browsertest.cc @@ -2,15 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "content/renderer/devtools/v8_sampling_profiler.h" + #include <stddef.h> +#include <utility> + #include "base/json/json_reader.h" #include "base/memory/ref_counted_memory.h" #include "base/run_loop.h" #include "base/trace_event/trace_buffer.h" #include "base/trace_event/trace_event.h" #include "content/public/test/render_view_test.h" -#include "content/renderer/devtools/v8_sampling_profiler.h" using base::DictionaryValue; using base::ListValue; @@ -37,7 +40,9 @@ class V8SamplingProfilerTest : public RenderViewTest { void KickV8() { ExecuteJavaScriptForTests("1"); } void SyncFlush(TraceLog* trace_log) { - base::WaitableEvent flush_complete_event(false, false); + base::WaitableEvent flush_complete_event( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); trace_log->Flush( base::Bind(&V8SamplingProfilerTest::OnTraceDataCollected, base::Unretained(static_cast<V8SamplingProfilerTest*>(this)), @@ -73,7 +78,7 @@ class V8SamplingProfilerTest : public RenderViewTest { while (root_list->GetSize()) { std::unique_ptr<Value> item; root_list->Remove(0, &item); - trace_parsed_.Append(item.release()); + trace_parsed_.Append(std::move(item)); } if (!has_more_events) diff --git a/chromium/content/renderer/dom_automation_controller.cc b/chromium/content/renderer/dom_automation_controller.cc index 3f119b6920d..91b456a3832 100644 --- a/chromium/content/renderer/dom_automation_controller.cc +++ b/chromium/content/renderer/dom_automation_controller.cc @@ -102,8 +102,8 @@ bool DomAutomationController::SendMsg(const gin::Arguments& args) { (args.PeekNext()->IsString() || args.PeekNext()->IsBoolean() || args.PeekNext()->IsNumber())) { V8ValueConverterImpl conv; - value.reset( - conv.FromV8Value(args.PeekNext(), args.isolate()->GetCurrentContext())); + value = + conv.FromV8Value(args.PeekNext(), args.isolate()->GetCurrentContext()); } else { return false; } diff --git a/chromium/content/renderer/dom_serializer_browsertest.cc b/chromium/content/renderer/dom_serializer_browsertest.cc index 3c3e549c12b..d475fe2e0da 100644 --- a/chromium/content/renderer/dom_serializer_browsertest.cc +++ b/chromium/content/renderer/dom_serializer_browsertest.cc @@ -75,6 +75,9 @@ class LoadObserver : public RenderViewObserver { } private: + // RenderViewObserver implementation. + void OnDestruct() override { delete this; } + base::Closure quit_closure_; }; diff --git a/chromium/content/renderer/external_popup_menu.cc b/chromium/content/renderer/external_popup_menu.cc index 7bb01a1d320..95b41a757e6 100644 --- a/chromium/content/renderer/external_popup_menu.cc +++ b/chromium/content/renderer/external_popup_menu.cc @@ -63,6 +63,7 @@ void ExternalPopupMenu::close() { // |this| was deleted. } +#if defined(USE_EXTERNAL_POPUP_MENU) #if defined(OS_MACOSX) void ExternalPopupMenu::DidSelectItem(int index) { if (!popup_menu_client_) @@ -72,9 +73,7 @@ void ExternalPopupMenu::DidSelectItem(int index) { else popup_menu_client_->didAcceptIndex(index); } -#endif - -#if defined(OS_ANDROID) +#else void ExternalPopupMenu::DidSelectItems(bool canceled, const std::vector<int>& indices) { if (!popup_menu_client_) @@ -85,5 +84,6 @@ void ExternalPopupMenu::DidSelectItems(bool canceled, popup_menu_client_->didAcceptIndices(indices); } #endif +#endif } // namespace content diff --git a/chromium/content/renderer/external_popup_menu.h b/chromium/content/renderer/external_popup_menu.h index 0d99eb7e6d9..0158f99fc0d 100644 --- a/chromium/content/renderer/external_popup_menu.h +++ b/chromium/content/renderer/external_popup_menu.h @@ -31,16 +31,16 @@ class ExternalPopupMenu : public blink::WebExternalPopupMenu { void SetOriginScaleAndOffsetForEmulation( float scale, const gfx::PointF& offset); +#if defined(USE_EXTERNAL_POPUP_MENU) #if defined(OS_MACOSX) // Called when the user has selected an item. |selected_item| is -1 if the // user canceled the popup. void DidSelectItem(int selected_index); -#endif - -#if defined(OS_ANDROID) +#else // Called when the user has selected items or canceled the popup. void DidSelectItems(bool canceled, const std::vector<int>& selected_indices); #endif +#endif // blink::WebExternalPopupMenu implementation: void show(const blink::WebRect& bounds) override; diff --git a/chromium/content/renderer/external_popup_menu_browsertest.cc b/chromium/content/renderer/external_popup_menu_browsertest.cc index ea6054b92d3..d1eb5a4520d 100644 --- a/chromium/content/renderer/external_popup_menu_browsertest.cc +++ b/chromium/content/renderer/external_popup_menu_browsertest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <tuple> + #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "content/common/frame_messages.h" @@ -87,10 +89,10 @@ TEST_F(ExternalPopupMenuTest, NormalCase) { const IPC::Message* message = sink.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID); ASSERT_TRUE(message != NULL); - base::Tuple<FrameHostMsg_ShowPopup_Params> param; + std::tuple<FrameHostMsg_ShowPopup_Params> param; FrameHostMsg_ShowPopup::Read(message, ¶m); - ASSERT_EQ(3U, base::get<0>(param).popup_items.size()); - EXPECT_EQ(1, base::get<0>(param).selected_item); + ASSERT_EQ(3U, std::get<0>(param).popup_items.size()); + EXPECT_EQ(1, std::get<0>(param).selected_item); // Simulate the user canceling the popup; the index should not have changed. frame()->OnSelectPopupMenuItem(-1); @@ -107,8 +109,8 @@ TEST_F(ExternalPopupMenuTest, NormalCase) { message = sink.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID); ASSERT_TRUE(message != NULL); FrameHostMsg_ShowPopup::Read(message, ¶m); - ASSERT_EQ(3U, base::get<0>(param).popup_items.size()); - EXPECT_EQ(0, base::get<0>(param).selected_item); + ASSERT_EQ(3U, std::get<0>(param).popup_items.size()); + EXPECT_EQ(0, std::get<0>(param).selected_item); } // Page shows popup, then navigates away while popup showing, then select. @@ -190,11 +192,11 @@ TEST_F(ExternalPopupMenuDisplayNoneTest, SelectItem) { const IPC::Message* message = sink.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID); ASSERT_TRUE(message != NULL); - base::Tuple<FrameHostMsg_ShowPopup_Params> param; + std::tuple<FrameHostMsg_ShowPopup_Params> param; FrameHostMsg_ShowPopup::Read(message, ¶m); // Number of items should match item count minus the number // of "display: none" items. - ASSERT_EQ(5U, base::get<0>(param).popup_items.size()); + ASSERT_EQ(5U, std::get<0>(param).popup_items.size()); // Select index 1 item. This should select item with index 2, // skipping the item with 'display: none' diff --git a/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.cc b/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.cc index d97dbe23377..1eea2aafb99 100644 --- a/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.cc +++ b/chromium/content/renderer/fetchers/multi_resolution_image_resource_fetcher.cc @@ -44,7 +44,7 @@ MultiResolutionImageResourceFetcher::MultiResolutionImageResourceFetcher( // workers. This should ideally not happen or at least not all the time. // See https://crbug.com/448427 if (request_context == WebURLRequest::RequestContextFavicon) - fetcher_->SetSkipServiceWorker(true); + fetcher_->SetSkipServiceWorker(WebURLRequest::SkipServiceWorker::All); fetcher_->SetCachePolicy(cache_policy); diff --git a/chromium/content/renderer/fetchers/resource_fetcher_impl.cc b/chromium/content/renderer/fetchers/resource_fetcher_impl.cc index fa58f999c84..51878491e6a 100644 --- a/chromium/content/renderer/fetchers/resource_fetcher_impl.cc +++ b/chromium/content/renderer/fetchers/resource_fetcher_impl.cc @@ -69,7 +69,8 @@ void ResourceFetcherImpl::SetHeader(const std::string& header, } } -void ResourceFetcherImpl::SetSkipServiceWorker(bool skip_service_worker) { +void ResourceFetcherImpl::SetSkipServiceWorker( + blink::WebURLRequest::SkipServiceWorker skip_service_worker) { DCHECK(!request_.isNull()); DCHECK(!loader_); diff --git a/chromium/content/renderer/fetchers/resource_fetcher_impl.h b/chromium/content/renderer/fetchers/resource_fetcher_impl.h index 38f3bb39940..731ca48832c 100644 --- a/chromium/content/renderer/fetchers/resource_fetcher_impl.h +++ b/chromium/content/renderer/fetchers/resource_fetcher_impl.h @@ -35,7 +35,8 @@ class ResourceFetcherImpl : public ResourceFetcher, void SetMethod(const std::string& method) override; void SetBody(const std::string& body) override; void SetHeader(const std::string& header, const std::string& value) override; - void SetSkipServiceWorker(bool skip_service_worker) override; + void SetSkipServiceWorker( + blink::WebURLRequest::SkipServiceWorker skip_service_worker) override; void SetCachePolicy(blink::WebCachePolicy policy) override; void SetLoaderOptions(const blink::WebURLLoaderOptions& options) override; void Start(blink::WebFrame* frame, diff --git a/chromium/content/renderer/frame_blame_context.cc b/chromium/content/renderer/frame_blame_context.cc index 74ed6ee2b25..a73f347cb4d 100644 --- a/chromium/content/renderer/frame_blame_context.cc +++ b/chromium/content/renderer/frame_blame_context.cc @@ -24,7 +24,7 @@ base::trace_event::BlameContext* GetParentBlameContext( const char kFrameBlameContextCategory[] = "blink"; const char kFrameBlameContextName[] = "FrameBlameContext"; -const char kFrameBlameContextType[] = "Frame"; +const char kFrameBlameContextType[] = "RenderFrame"; const char kFrameBlameContextScope[] = "RenderFrame"; FrameBlameContext::FrameBlameContext(RenderFrameImpl* render_frame, diff --git a/chromium/content/renderer/gamepad_shared_memory_reader.cc b/chromium/content/renderer/gamepad_shared_memory_reader.cc index 89ed79eb1fd..f561e5dee84 100644 --- a/chromium/content/renderer/gamepad_shared_memory_reader.cc +++ b/chromium/content/renderer/gamepad_shared_memory_reader.cc @@ -7,7 +7,6 @@ #include "base/metrics/histogram.h" #include "base/trace_event/trace_event.h" #include "content/common/gamepad_hardware_buffer.h" -#include "content/common/gamepad_user_gesture.h" #include "content/public/renderer/render_thread.h" #include "content/renderer/renderer_blink_platform_impl.h" #include "ipc/ipc_sync_message_filter.h" diff --git a/chromium/content/renderer/gpu/compositor_dependencies.h b/chromium/content/renderer/gpu/compositor_dependencies.h index cee05271378..9a886ddf948 100644 --- a/chromium/content/renderer/gpu/compositor_dependencies.h +++ b/chromium/content/renderer/gpu/compositor_dependencies.h @@ -54,6 +54,8 @@ class CompositorDependencies { virtual cc::SharedBitmapManager* GetSharedBitmapManager() = 0; virtual gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() = 0; virtual scheduler::RendererScheduler* GetRendererScheduler() = 0; + // TODO(danakj): This should be part of RenderThreadImpl (or some API from it + // to RenderWidget). But RenderThreadImpl is null in RenderViewTest. virtual std::unique_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource( int routing_id) = 0; virtual cc::ImageSerializationProcessor* GetImageSerializationProcessor() = 0; diff --git a/chromium/content/renderer/gpu/compositor_external_begin_frame_source.cc b/chromium/content/renderer/gpu/compositor_external_begin_frame_source.cc index aa4a456ac29..e2d13608ac7 100644 --- a/chromium/content/renderer/gpu/compositor_external_begin_frame_source.cc +++ b/chromium/content/renderer/gpu/compositor_external_begin_frame_source.cc @@ -32,19 +32,19 @@ CompositorExternalBeginFrameSource::~CompositorExternalBeginFrameSource() { } } -void CompositorExternalBeginFrameSource::OnNeedsBeginFramesChanged( - bool needs_begin_frames) { - DCHECK(CalledOnValidThread()); - if (!needs_begin_frames) - missed_begin_frame_args_ = cc::BeginFrameArgs(); - Send(new ViewHostMsg_SetNeedsBeginFrames(routing_id_, needs_begin_frames)); -} - void CompositorExternalBeginFrameSource::AddObserver( cc::BeginFrameObserver* obs) { DCHECK(CalledOnValidThread()); + DCHECK(obs); + DCHECK(observers_.find(obs) == observers_.end()); + SetClientReady(); - BeginFrameSourceBase::AddObserver(obs); + bool observers_was_empty = observers_.empty(); + observers_.insert(obs); + obs->OnBeginFrameSourcePausedChanged(paused_); + if (observers_was_empty) + Send(new ViewHostMsg_SetNeedsBeginFrames(routing_id_, true)); + // Send a MISSED begin frame if necessary. if (missed_begin_frame_args_.IsValid()) { cc::BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); @@ -55,6 +55,18 @@ void CompositorExternalBeginFrameSource::AddObserver( } } +void CompositorExternalBeginFrameSource::RemoveObserver( + cc::BeginFrameObserver* obs) { + DCHECK(obs); + DCHECK(observers_.find(obs) != observers_.end()); + + observers_.erase(obs); + if (observers_.empty()) { + missed_begin_frame_args_ = cc::BeginFrameArgs(); + Send(new ViewHostMsg_SetNeedsBeginFrames(routing_id_, false)); + } +} + void CompositorExternalBeginFrameSource::SetClientReady() { DCHECK(CalledOnValidThread()); if (begin_frame_source_proxy_) @@ -74,16 +86,30 @@ void CompositorExternalBeginFrameSource::OnMessageReceived( DCHECK(CalledOnValidThread()); DCHECK(begin_frame_source_proxy_.get()); IPC_BEGIN_MESSAGE_MAP(CompositorExternalBeginFrameSource, message) + IPC_MESSAGE_HANDLER(ViewMsg_SetBeginFramePaused, + OnSetBeginFrameSourcePaused) IPC_MESSAGE_HANDLER(ViewMsg_BeginFrame, OnBeginFrame) IPC_END_MESSAGE_MAP() } +void CompositorExternalBeginFrameSource::OnSetBeginFrameSourcePaused( + bool paused) { + if (paused_ == paused) + return; + paused_ = paused; + std::unordered_set<cc::BeginFrameObserver*> observers(observers_); + for (auto* obs : observers) + obs->OnBeginFrameSourcePausedChanged(paused_); +} + void CompositorExternalBeginFrameSource::OnBeginFrame( const cc::BeginFrameArgs& args) { DCHECK(CalledOnValidThread()); missed_begin_frame_args_ = args; missed_begin_frame_args_.type = cc::BeginFrameArgs::MISSED; - CallOnBeginFrame(args); + std::unordered_set<cc::BeginFrameObserver*> observers(observers_); + for (auto* obs : observers) + obs->OnBeginFrame(args); } bool CompositorExternalBeginFrameSource::Send(IPC::Message* message) { diff --git a/chromium/content/renderer/gpu/compositor_external_begin_frame_source.h b/chromium/content/renderer/gpu/compositor_external_begin_frame_source.h index 116529a229f..8a965772f36 100644 --- a/chromium/content/renderer/gpu/compositor_external_begin_frame_source.h +++ b/chromium/content/renderer/gpu/compositor_external_begin_frame_source.h @@ -5,6 +5,8 @@ #ifndef CONTENT_RENDERER_GPU_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_ #define CONTENT_RENDERER_GPU_COMPOSITOR_EXTERNAL_BEGIN_FRAME_SOURCE_H_ +#include <unordered_set> + #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -21,7 +23,7 @@ namespace content { // This class can be created only on the main thread, but then becomes pinned // to a fixed thread where cc::Scheduler is running. class CompositorExternalBeginFrameSource - : public cc::BeginFrameSourceBase, + : public cc::BeginFrameSource, public NON_EXPORTED_BASE(base::NonThreadSafe) { public: explicit CompositorExternalBeginFrameSource( @@ -30,9 +32,11 @@ class CompositorExternalBeginFrameSource int routing_id); ~CompositorExternalBeginFrameSource() override; - // cc::BeginFrameSourceBase implementation. + // cc::BeginFrameSource implementation. void AddObserver(cc::BeginFrameObserver* obs) override; - void OnNeedsBeginFramesChanged(bool needs_begin_frames) override; + void RemoveObserver(cc::BeginFrameObserver* obs) override; + void DidFinishFrame(cc::BeginFrameObserver* obs, + size_t remaining_frames) override {} private: class CompositorExternalBeginFrameSourceProxy @@ -61,6 +65,7 @@ class CompositorExternalBeginFrameSource void SetClientReady(); void OnMessageReceived(const IPC::Message& message); + void OnSetBeginFrameSourcePaused(bool paused); void OnBeginFrame(const cc::BeginFrameArgs& args); bool Send(IPC::Message* message); @@ -71,6 +76,8 @@ class CompositorExternalBeginFrameSource int routing_id_; CompositorForwardingMessageFilter::Handler begin_frame_source_filter_handler_; cc::BeginFrameArgs missed_begin_frame_args_; + std::unordered_set<cc::BeginFrameObserver*> observers_; + bool paused_ = false; DISALLOW_COPY_AND_ASSIGN(CompositorExternalBeginFrameSource); }; diff --git a/chromium/content/renderer/gpu/compositor_forwarding_message_filter.cc b/chromium/content/renderer/gpu/compositor_forwarding_message_filter.cc index ff657dc58f6..4914fd3fe63 100644 --- a/chromium/content/renderer/gpu/compositor_forwarding_message_filter.cc +++ b/chromium/content/renderer/gpu/compositor_forwarding_message_filter.cc @@ -47,6 +47,7 @@ void CompositorForwardingMessageFilter::RemoveHandlerOnCompositorThread( bool CompositorForwardingMessageFilter::OnMessageReceived( const IPC::Message& message) { switch(message.type()) { + case ViewMsg_SetBeginFramePaused::ID: // Fall through. case ViewMsg_BeginFrame::ID: // Fall through. case ViewMsg_ReclaimCompositorResources::ID: // Fall through. case ViewMsg_SwapCompositorFrameAck::ID: // Fall through. diff --git a/chromium/content/renderer/gpu/compositor_output_surface.cc b/chromium/content/renderer/gpu/compositor_output_surface.cc index 1284fe47d65..a240b19736e 100644 --- a/chromium/content/renderer/gpu/compositor_output_surface.cc +++ b/chromium/content/renderer/gpu/compositor_output_surface.cc @@ -30,31 +30,43 @@ namespace content { CompositorOutputSurface::CompositorOutputSurface( int32_t routing_id, uint32_t output_surface_id, - const scoped_refptr<ContextProviderCommandBuffer>& context_provider, - const scoped_refptr<ContextProviderCommandBuffer>& worker_context_provider, - const scoped_refptr<cc::VulkanContextProvider>& vulkan_context_provider, - std::unique_ptr<cc::SoftwareOutputDevice> software_device, - scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue, - bool use_swap_compositor_frame_message) - : OutputSurface(context_provider, - worker_context_provider, - vulkan_context_provider, - std::move(software_device)), + scoped_refptr<cc::ContextProvider> context_provider, + scoped_refptr<cc::ContextProvider> worker_context_provider, + scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue) + : OutputSurface(std::move(context_provider), + std::move(worker_context_provider), + nullptr), output_surface_id_(output_surface_id), - use_swap_compositor_frame_message_(use_swap_compositor_frame_message), output_surface_filter_( RenderThreadImpl::current()->compositor_message_filter()), + message_sender_(RenderThreadImpl::current()->sync_message_filter()), frame_swap_message_queue_(swap_frame_message_queue), - routing_id_(routing_id), - layout_test_mode_(RenderThreadImpl::current()->layout_test_mode()), - weak_ptrs_(this) { - DCHECK(output_surface_filter_.get()); - DCHECK(frame_swap_message_queue_.get()); - message_sender_ = RenderThreadImpl::current()->sync_message_filter(); - DCHECK(message_sender_.get()); + routing_id_(routing_id) { + DCHECK(output_surface_filter_); + DCHECK(frame_swap_message_queue_); + DCHECK(message_sender_); + capabilities_.delegated_rendering = true; } -CompositorOutputSurface::~CompositorOutputSurface() {} +CompositorOutputSurface::CompositorOutputSurface( + int32_t routing_id, + uint32_t output_surface_id, + scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider, + scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue) + : OutputSurface(std::move(vulkan_context_provider)), + output_surface_id_(output_surface_id), + output_surface_filter_( + RenderThreadImpl::current()->compositor_message_filter()), + message_sender_(RenderThreadImpl::current()->sync_message_filter()), + frame_swap_message_queue_(swap_frame_message_queue), + routing_id_(routing_id) { + DCHECK(output_surface_filter_); + DCHECK(frame_swap_message_queue_); + DCHECK(message_sender_); + capabilities_.delegated_rendering = true; +} + +CompositorOutputSurface::~CompositorOutputSurface() = default; bool CompositorOutputSurface::BindToClient( cc::OutputSurfaceClient* client) { @@ -91,70 +103,33 @@ void CompositorOutputSurface::DetachFromClient() { cc::OutputSurface::DetachFromClient(); } -void CompositorOutputSurface::ShortcutSwapAck( - uint32_t output_surface_id, - std::unique_ptr<cc::GLFrameData> gl_frame_data) { - if (!layout_test_previous_frame_ack_) { - layout_test_previous_frame_ack_.reset(new cc::CompositorFrameAck); - layout_test_previous_frame_ack_->gl_frame_data.reset(new cc::GLFrameData); +void CompositorOutputSurface::SwapBuffers(cc::CompositorFrame frame) { + { + std::unique_ptr<FrameSwapMessageQueue::SendMessageScope> + send_message_scope = + frame_swap_message_queue_->AcquireSendMessageScope(); + std::vector<std::unique_ptr<IPC::Message>> messages; + std::vector<IPC::Message> messages_to_deliver_with_frame; + frame_swap_message_queue_->DrainMessages(&messages); + FrameSwapMessageQueue::TransferMessages(&messages, + &messages_to_deliver_with_frame); + Send(new ViewHostMsg_SwapCompositorFrame(routing_id_, output_surface_id_, + frame, + messages_to_deliver_with_frame)); + // ~send_message_scope. } + client_->DidSwapBuffers(); +} - OnSwapAck(output_surface_id, *layout_test_previous_frame_ack_); - - layout_test_previous_frame_ack_->gl_frame_data = std::move(gl_frame_data); +void CompositorOutputSurface::BindFramebuffer() { + // This is a delegating output surface, no framebuffer/direct drawing support. + NOTREACHED(); } -void CompositorOutputSurface::SwapBuffers(cc::CompositorFrame* frame) { - DCHECK(use_swap_compositor_frame_message_); - if (layout_test_mode_) { - // This code path is here to support layout tests that are currently - // doing a readback in the renderer instead of the browser. So they - // are using deprecated code paths in the renderer and don't need to - // actually swap anything to the browser. We shortcut the swap to the - // browser here and just ack directly within the renderer process. - // Once crbug.com/311404 is fixed, this can be removed. - - // This would indicate that crbug.com/311404 is being fixed, and this - // block needs to be removed. - DCHECK(!frame->delegated_frame_data); - - base::Closure closure = base::Bind( - &CompositorOutputSurface::ShortcutSwapAck, weak_ptrs_.GetWeakPtr(), - output_surface_id_, base::Passed(&frame->gl_frame_data)); - - if (context_provider()) { - gpu::gles2::GLES2Interface* context = context_provider()->ContextGL(); - const uint64_t fence_sync = context->InsertFenceSyncCHROMIUM(); - context->Flush(); - - gpu::SyncToken sync_token; - context->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); - - context_provider()->ContextSupport()->SignalSyncToken(sync_token, - closure); - } else { - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure); - } - client_->DidSwapBuffers(); - return; - } else { - { - std::vector<std::unique_ptr<IPC::Message>> messages; - std::vector<IPC::Message> messages_to_deliver_with_frame; - std::unique_ptr<FrameSwapMessageQueue::SendMessageScope> - send_message_scope = - frame_swap_message_queue_->AcquireSendMessageScope(); - frame_swap_message_queue_->DrainMessages(&messages); - FrameSwapMessageQueue::TransferMessages(&messages, - &messages_to_deliver_with_frame); - Send(new ViewHostMsg_SwapCompositorFrame(routing_id_, - output_surface_id_, - *frame, - messages_to_deliver_with_frame)); - // ~send_message_scope. - } - client_->DidSwapBuffers(); - } +uint32_t CompositorOutputSurface::GetFramebufferCopyTextureFormat() { + // This is a delegating output surface, no framebuffer/direct drawing support. + NOTREACHED(); + return 0; } void CompositorOutputSurface::OnMessageReceived(const IPC::Message& message) { diff --git a/chromium/content/renderer/gpu/compositor_output_surface.h b/chromium/content/renderer/gpu/compositor_output_surface.h index fc311698e98..d3e78b21400 100644 --- a/chromium/content/renderer/gpu/compositor_output_surface.h +++ b/chromium/content/renderer/gpu/compositor_output_surface.h @@ -29,15 +29,14 @@ class Message; namespace cc { class CompositorFrame; class CompositorFrameAck; -class GLFrameData; +class ContextProvider; } namespace content { -class ContextProviderCommandBuffer; class FrameSwapMessageQueue; // This class can be created only on the main thread, but then becomes pinned -// to a fixed thread when bindToClient is called. +// to a fixed thread when BindToClient is called. class CompositorOutputSurface : NON_EXPORTED_BASE(public cc::OutputSurface), NON_EXPORTED_BASE(public base::NonThreadSafe) { @@ -45,27 +44,24 @@ class CompositorOutputSurface CompositorOutputSurface( int32_t routing_id, uint32_t output_surface_id, - const scoped_refptr<ContextProviderCommandBuffer>& context_provider, - const scoped_refptr<ContextProviderCommandBuffer>& - worker_context_provider, - const scoped_refptr<cc::VulkanContextProvider>& vulkan_context_provider, - std::unique_ptr<cc::SoftwareOutputDevice> software, - scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue, - bool use_swap_compositor_frame_message); + scoped_refptr<cc::ContextProvider> context_provider, + scoped_refptr<cc::ContextProvider> worker_context_provider, + scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue); + CompositorOutputSurface( + int32_t routing_id, + uint32_t output_surface_id, + scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider, + scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue); ~CompositorOutputSurface() override; // cc::OutputSurface implementation. bool BindToClient(cc::OutputSurfaceClient* client) override; void DetachFromClient() override; - void SwapBuffers(cc::CompositorFrame* frame) override; + void SwapBuffers(cc::CompositorFrame frame) override; + void BindFramebuffer() override; + uint32_t GetFramebufferCopyTextureFormat() override; protected: - void ShortcutSwapAck(uint32_t output_surface_id, - std::unique_ptr<cc::GLFrameData> gl_frame_data); - virtual void OnSwapAck(uint32_t output_surface_id, - const cc::CompositorFrameAck& ack); - virtual void OnReclaimResources(uint32_t output_surface_id, - const cc::CompositorFrameAck& ack); uint32_t output_surface_id_; private: @@ -92,21 +88,17 @@ class CompositorOutputSurface void OnMessageReceived(const IPC::Message& message); void OnUpdateVSyncParametersFromBrowser(base::TimeTicks timebase, base::TimeDelta interval); + void OnSwapAck(uint32_t output_surface_id, const cc::CompositorFrameAck& ack); + void OnReclaimResources(uint32_t output_surface_id, + const cc::CompositorFrameAck& ack); bool Send(IPC::Message* message); - bool use_swap_compositor_frame_message_; - scoped_refptr<CompositorForwardingMessageFilter> output_surface_filter_; CompositorForwardingMessageFilter::Handler output_surface_filter_handler_; scoped_refptr<CompositorOutputSurfaceProxy> output_surface_proxy_; scoped_refptr<IPC::SyncMessageFilter> message_sender_; scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue_; int routing_id_; - - // TODO(danakj): Remove this when crbug.com/311404 - bool layout_test_mode_; - std::unique_ptr<cc::CompositorFrameAck> layout_test_previous_frame_ack_; - base::WeakPtrFactory<CompositorOutputSurface> weak_ptrs_; }; } // namespace content diff --git a/chromium/content/renderer/gpu/delegated_compositor_output_surface.cc b/chromium/content/renderer/gpu/delegated_compositor_output_surface.cc deleted file mode 100644 index 97d838ead7e..00000000000 --- a/chromium/content/renderer/gpu/delegated_compositor_output_surface.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/gpu/delegated_compositor_output_surface.h" -#include "content/renderer/gpu/frame_swap_message_queue.h" - -namespace content { - -DelegatedCompositorOutputSurface::DelegatedCompositorOutputSurface( - int32_t routing_id, - uint32_t output_surface_id, - const scoped_refptr<ContextProviderCommandBuffer>& context_provider, - const scoped_refptr<ContextProviderCommandBuffer>& worker_context_provider, - const scoped_refptr<cc::VulkanContextProvider>& vulkan_context_provider, - scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue) - : CompositorOutputSurface(routing_id, - output_surface_id, - context_provider, - worker_context_provider, - vulkan_context_provider, - std::unique_ptr<cc::SoftwareOutputDevice>(), - swap_frame_message_queue, - true) { - capabilities_.delegated_rendering = true; -} - -} // namespace content diff --git a/chromium/content/renderer/gpu/delegated_compositor_output_surface.h b/chromium/content/renderer/gpu/delegated_compositor_output_surface.h deleted file mode 100644 index aca19155b8d..00000000000 --- a/chromium/content/renderer/gpu/delegated_compositor_output_surface.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_GPU_DELEGATED_COMPOSITOR_OUTPUT_SURFACE_H_ -#define CONTENT_RENDERER_GPU_DELEGATED_COMPOSITOR_OUTPUT_SURFACE_H_ - -#include <stdint.h> - -#include "base/memory/ref_counted.h" -#include "content/renderer/gpu/compositor_output_surface.h" - -namespace content { -class FrameSwapMessageQueue; - -class DelegatedCompositorOutputSurface : public CompositorOutputSurface { - public: - DelegatedCompositorOutputSurface( - int32_t routing_id, - uint32_t output_surface_id, - const scoped_refptr<ContextProviderCommandBuffer>& context_provider, - const scoped_refptr<ContextProviderCommandBuffer>& - worker_context_provider, - const scoped_refptr<cc::VulkanContextProvider>& vulkan_context_provider, - scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue); - ~DelegatedCompositorOutputSurface() override {} -}; - -} // namespace content - -#endif // CONTENT_RENDERER_GPU_DELEGATED_COMPOSITOR_OUTPUT_SURFACE_H_ diff --git a/chromium/content/renderer/gpu/gpu_benchmarking_extension.cc b/chromium/content/renderer/gpu/gpu_benchmarking_extension.cc index 8fe5bae7d48..42f6995ff23 100644 --- a/chromium/content/renderer/gpu/gpu_benchmarking_extension.cc +++ b/chromium/content/renderer/gpu/gpu_benchmarking_extension.cc @@ -910,7 +910,7 @@ int GpuBenchmarking::RunMicroBenchmark(gin::Arguments* args) { base::WrapUnique(V8ValueConverter::create()); v8::Local<v8::Context> v8_context = callback_and_context->GetContext(); std::unique_ptr<base::Value> value = - base::WrapUnique(converter->FromV8Value(arguments, v8_context)); + converter->FromV8Value(arguments, v8_context); return context.compositor()->ScheduleMicroBenchmark( name, std::move(value), @@ -930,7 +930,7 @@ bool GpuBenchmarking::SendMessageToMicroBenchmark( v8::Local<v8::Context> v8_context = context.web_frame()->mainWorldScriptContext(); std::unique_ptr<base::Value> value = - base::WrapUnique(converter->FromV8Value(message, v8_context)); + converter->FromV8Value(message, v8_context); return context.compositor()->SendMessageToMicroBenchmark(id, std::move(value)); diff --git a/chromium/content/renderer/gpu/mailbox_output_surface.cc b/chromium/content/renderer/gpu/mailbox_output_surface.cc deleted file mode 100644 index 4d90944759b..00000000000 --- a/chromium/content/renderer/gpu/mailbox_output_surface.cc +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/gpu/mailbox_output_surface.h" - -#include "base/logging.h" -#include "cc/output/compositor_frame.h" -#include "cc/output/compositor_frame_ack.h" -#include "cc/output/gl_frame_data.h" -#include "cc/resources/resource_provider.h" -#include "content/renderer/gpu/frame_swap_message_queue.h" -#include "gpu/command_buffer/client/gles2_interface.h" -#include "third_party/khronos/GLES2/gl2.h" -#include "third_party/khronos/GLES2/gl2ext.h" - -using cc::CompositorFrame; -using cc::GLFrameData; -using cc::ResourceProvider; -using gpu::Mailbox; -using gpu::gles2::GLES2Interface; - -namespace content { - -MailboxOutputSurface::MailboxOutputSurface( - int32_t routing_id, - uint32_t output_surface_id, - const scoped_refptr<ContextProviderCommandBuffer>& context_provider, - const scoped_refptr<ContextProviderCommandBuffer>& worker_context_provider, - scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue, - cc::ResourceFormat format) - : CompositorOutputSurface(routing_id, - output_surface_id, - context_provider, - worker_context_provider, - nullptr, - nullptr, - swap_frame_message_queue, - true), - fbo_(0), - is_backbuffer_discarded_(false), - format_(format) { - pending_textures_.push_back(TransferableFrame()); - capabilities_.uses_default_gl_framebuffer = false; -} - -MailboxOutputSurface::~MailboxOutputSurface() {} - -void MailboxOutputSurface::DetachFromClient() { - DiscardBackbuffer(); - while (!pending_textures_.empty()) { - if (pending_textures_.front().texture_id) { - context_provider_->ContextGL()->DeleteTextures( - 1, &pending_textures_.front().texture_id); - } - pending_textures_.pop_front(); - } - cc::OutputSurface::DetachFromClient(); -} - -void MailboxOutputSurface::EnsureBackbuffer() { - is_backbuffer_discarded_ = false; - - GLES2Interface* gl = context_provider_->ContextGL(); - - if (!current_backing_.texture_id) { - // Find a texture of matching size to recycle. - while (!returned_textures_.empty()) { - TransferableFrame& texture = returned_textures_.front(); - if (texture.size == surface_size_) { - current_backing_ = texture; - if (current_backing_.sync_token.HasData()) - gl->WaitSyncTokenCHROMIUM(current_backing_.sync_token.GetConstData()); - returned_textures_.pop(); - break; - } - - gl->DeleteTextures(1, &texture.texture_id); - returned_textures_.pop(); - } - - if (!current_backing_.texture_id) { - gl->GenTextures(1, ¤t_backing_.texture_id); - current_backing_.size = surface_size_; - gl->BindTexture(GL_TEXTURE_2D, current_backing_.texture_id); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl->TexImage2D(GL_TEXTURE_2D, - 0, - GLInternalFormat(format_), - surface_size_.width(), - surface_size_.height(), - 0, - GLDataFormat(format_), - GLDataType(format_), - NULL); - gl->GenMailboxCHROMIUM(current_backing_.mailbox.name); - gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, current_backing_.mailbox.name); - } - } -} - -void MailboxOutputSurface::DiscardBackbuffer() { - is_backbuffer_discarded_ = true; - - GLES2Interface* gl = context_provider_->ContextGL(); - - if (current_backing_.texture_id) { - gl->DeleteTextures(1, ¤t_backing_.texture_id); - current_backing_ = TransferableFrame(); - } - - while (!returned_textures_.empty()) { - const TransferableFrame& frame = returned_textures_.front(); - gl->DeleteTextures(1, &frame.texture_id); - returned_textures_.pop(); - } - - if (fbo_) { - gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); - gl->DeleteFramebuffers(1, &fbo_); - fbo_ = 0; - } -} - -void MailboxOutputSurface::Reshape(const gfx::Size& size, - float scale_factor, - bool alpha) { - if (size == surface_size_) - return; - - surface_size_ = size; - device_scale_factor_ = scale_factor; - DiscardBackbuffer(); - EnsureBackbuffer(); -} - -void MailboxOutputSurface::BindFramebuffer() { - EnsureBackbuffer(); - DCHECK(current_backing_.texture_id); - - GLES2Interface* gl = context_provider_->ContextGL(); - - if (!fbo_) - gl->GenFramebuffers(1, &fbo_); - gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); - gl->FramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - current_backing_.texture_id, - 0); -} - -void MailboxOutputSurface::OnSwapAck(uint32_t output_surface_id, - const cc::CompositorFrameAck& ack) { - // Ignore message if it's a stale one coming from a different output surface - // (e.g. after a lost context). - if (output_surface_id != output_surface_id_) { - CompositorOutputSurface::OnSwapAck(output_surface_id, ack); - return; - } - if (!ack.gl_frame_data->mailbox.IsZero()) { - DCHECK(!ack.gl_frame_data->size.IsEmpty()); - // The browser could be returning the oldest or any other pending texture - // if it decided to skip a frame. - std::deque<TransferableFrame>::iterator it; - for (it = pending_textures_.begin(); it != pending_textures_.end(); it++) { - DCHECK(!it->mailbox.IsZero()); - if (!memcmp(it->mailbox.name, - ack.gl_frame_data->mailbox.name, - sizeof(it->mailbox.name))) { - DCHECK(it->size == ack.gl_frame_data->size); - break; - } - } - DCHECK(it != pending_textures_.end()); - it->sync_token = ack.gl_frame_data->sync_token; - - if (!is_backbuffer_discarded_) { - returned_textures_.push(*it); - } else { - context_provider_->ContextGL()->DeleteTextures(1, &it->texture_id); - } - - pending_textures_.erase(it); - } else { - DCHECK(!pending_textures_.empty()); - // The browser always keeps one texture as the frontbuffer. - // If it does not return a mailbox, it discarded the frontbuffer which is - // the oldest texture we sent. - uint32_t texture_id = pending_textures_.front().texture_id; - if (texture_id) - context_provider_->ContextGL()->DeleteTextures(1, &texture_id); - pending_textures_.pop_front(); - } - CompositorOutputSurface::OnSwapAck(output_surface_id, ack); -} - -void MailboxOutputSurface::SwapBuffers(cc::CompositorFrame* frame) { - DCHECK(frame->gl_frame_data); - DCHECK(!surface_size_.IsEmpty()); - DCHECK(surface_size_ == current_backing_.size); - DCHECK(frame->gl_frame_data->size == current_backing_.size); - DCHECK(!current_backing_.mailbox.IsZero() || - context_provider_->ContextGL()->GetGraphicsResetStatusKHR() != - GL_NO_ERROR); - - frame->gl_frame_data->mailbox = current_backing_.mailbox; - - gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); - - const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM(); - gl->Flush(); - - gl->GenSyncTokenCHROMIUM(fence_sync, - frame->gl_frame_data->sync_token.GetData()); - - CompositorOutputSurface::SwapBuffers(frame); - - pending_textures_.push_back(current_backing_); - current_backing_ = TransferableFrame(); -} - -size_t MailboxOutputSurface::GetNumAcksPending() { - DCHECK(pending_textures_.size()); - return pending_textures_.size() - 1; -} - -MailboxOutputSurface::TransferableFrame::TransferableFrame() : texture_id(0) {} - -MailboxOutputSurface::TransferableFrame::TransferableFrame( - uint32_t texture_id, - const gpu::Mailbox& mailbox, - const gfx::Size size) - : texture_id(texture_id), mailbox(mailbox), size(size) {} - -} // namespace content diff --git a/chromium/content/renderer/gpu/mailbox_output_surface.h b/chromium/content/renderer/gpu/mailbox_output_surface.h deleted file mode 100644 index 1d4b95559f8..00000000000 --- a/chromium/content/renderer/gpu/mailbox_output_surface.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_GPU_MAILBOX_OUTPUT_SURFACE_H_ -#define CONTENT_RENDERER_GPU_MAILBOX_OUTPUT_SURFACE_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <queue> - -#include "base/memory/ref_counted.h" -#include "cc/resources/resource_format.h" -#include "cc/resources/transferable_resource.h" -#include "content/renderer/gpu/compositor_output_surface.h" -#include "ui/gfx/geometry/size.h" - -namespace cc { -class CompositorFrameAck; -} - -namespace content { -class FrameSwapMessageQueue; - -// Implementation of CompositorOutputSurface that renders to textures which -// are sent to the browser through the mailbox extension. -// This class can be created only on the main thread, but then becomes pinned -// to a fixed thread when bindToClient is called. -class MailboxOutputSurface : public CompositorOutputSurface { - public: - MailboxOutputSurface( - int32_t routing_id, - uint32_t output_surface_id, - const scoped_refptr<ContextProviderCommandBuffer>& context_provider, - const scoped_refptr<ContextProviderCommandBuffer>& - worker_context_provider, - scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue, - cc::ResourceFormat format); - ~MailboxOutputSurface() override; - - // cc::OutputSurface implementation. - void DetachFromClient() override; - void EnsureBackbuffer() override; - void DiscardBackbuffer() override; - void Reshape(const gfx::Size& size, float scale_factor, bool alpha) override; - void BindFramebuffer() override; - void SwapBuffers(cc::CompositorFrame* frame) override; - - private: - // CompositorOutputSurface overrides. - void OnSwapAck(uint32_t output_surface_id, - const cc::CompositorFrameAck& ack) override; - - size_t GetNumAcksPending(); - - struct TransferableFrame { - TransferableFrame(); - TransferableFrame(uint32_t texture_id, - const gpu::Mailbox& mailbox, - const gfx::Size size); - - uint32_t texture_id; - gpu::Mailbox mailbox; - gpu::SyncToken sync_token; - gfx::Size size; - }; - - TransferableFrame current_backing_; - std::deque<TransferableFrame> pending_textures_; - std::queue<TransferableFrame> returned_textures_; - - uint32_t fbo_; - bool is_backbuffer_discarded_; - cc::ResourceFormat format_; -}; - -} // namespace content - -#endif // CONTENT_RENDERER_GPU_MAILBOX_OUTPUT_SURFACE_H_ diff --git a/chromium/content/renderer/gpu/queue_message_swap_promise.cc b/chromium/content/renderer/gpu/queue_message_swap_promise.cc index 9653375e65c..8b99a17256c 100644 --- a/chromium/content/renderer/gpu/queue_message_swap_promise.cc +++ b/chromium/content/renderer/gpu/queue_message_swap_promise.cc @@ -4,6 +4,9 @@ #include "content/renderer/gpu/queue_message_swap_promise.h" +#include "base/command_line.h" +#include "content/public/common/content_switches.h" +#include "content/public/renderer/render_thread.h" #include "content/renderer/gpu/frame_swap_message_queue.h" #include "ipc/ipc_sync_message_filter.h" @@ -38,6 +41,20 @@ void QueueMessageSwapPromise::DidActivate() { #endif message_queue_->DidActivate(source_frame_number_); // The OutputSurface will take care of the Drain+Send. + + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kUseRemoteCompositing)) { + // The remote compositing mode doesn't have an output surface, so we need to + // Drain+Send on activation. Also, we can't use the SyncMessageFilter, since + // this call is actually made on the main thread. + std::vector<std::unique_ptr<IPC::Message>> messages_to_deliver; + std::unique_ptr<FrameSwapMessageQueue::SendMessageScope> + send_message_scope = message_queue_->AcquireSendMessageScope(); + message_queue_->DrainMessages(&messages_to_deliver); + for (auto& message : messages_to_deliver) + RenderThread::Get()->Send(message.release()); + PromiseCompleted(); + } } void QueueMessageSwapPromise::DidSwap(cc::CompositorFrameMetadata* metadata) { diff --git a/chromium/content/renderer/gpu/render_widget_compositor.cc b/chromium/content/renderer/gpu/render_widget_compositor.cc index 5d5a155fd8b..c73ca064a9d 100644 --- a/chromium/content/renderer/gpu/render_widget_compositor.cc +++ b/chromium/content/renderer/gpu/render_widget_compositor.cc @@ -23,6 +23,7 @@ #include "build/build_config.h" #include "cc/animation/animation_host.h" #include "cc/animation/animation_timeline.h" +#include "cc/animation/layer_tree_mutator.h" #include "cc/base/switches.h" #include "cc/blink/web_layer_impl.h" #include "cc/debug/layer_tree_debug_state.h" @@ -43,7 +44,6 @@ #include "components/scheduler/renderer/renderer_scheduler.h" #include "content/common/content_switches_internal.h" #include "content/common/gpu/client/context_provider_command_buffer.h" -#include "content/common/input/input_event_utils.h" #include "content/public/common/content_client.h" #include "content/public/common/content_switches.h" #include "content/renderer/gpu/render_widget_compositor_delegate.h" @@ -51,6 +51,7 @@ #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/service/gpu_switches.h" #include "third_party/WebKit/public/platform/WebCompositeAndReadbackAsyncCallback.h" +#include "third_party/WebKit/public/platform/WebCompositorMutatorClient.h" #include "third_party/WebKit/public/platform/WebLayoutAndPaintAsyncCallback.h" #include "third_party/WebKit/public/platform/WebSize.h" #include "third_party/WebKit/public/web/WebKit.h" @@ -109,14 +110,14 @@ cc::LayerSelectionBound ConvertWebSelectionBound( const blink::WebSelectionBound& web_bound = is_start ? web_selection.start() : web_selection.end(); DCHECK(web_bound.layerId); - cc_bound.type = cc::SELECTION_BOUND_CENTER; + cc_bound.type = gfx::SelectionBound::CENTER; if (web_selection.isRange()) { if (is_start) { - cc_bound.type = web_bound.isTextDirectionRTL ? cc::SELECTION_BOUND_RIGHT - : cc::SELECTION_BOUND_LEFT; + cc_bound.type = web_bound.isTextDirectionRTL ? gfx::SelectionBound::RIGHT + : gfx::SelectionBound::LEFT; } else { - cc_bound.type = web_bound.isTextDirectionRTL ? cc::SELECTION_BOUND_LEFT - : cc::SELECTION_BOUND_RIGHT; + cc_bound.type = web_bound.isTextDirectionRTL ? gfx::SelectionBound::LEFT + : gfx::SelectionBound::RIGHT; } } cc_bound.layer_id = web_bound.layerId; @@ -220,6 +221,7 @@ RenderWidgetCompositor::RenderWidgetCompositor( : num_failed_recreate_attempts_(0), delegate_(delegate), compositor_deps_(compositor_deps), + threaded_(!!compositor_deps_->GetCompositorImplThreadTaskRunner()), never_visible_(false), layout_and_paint_async_callback_(nullptr), remote_proto_channel_receiver_(nullptr), @@ -227,16 +229,54 @@ RenderWidgetCompositor::RenderWidgetCompositor( void RenderWidgetCompositor::Initialize(float device_scale_factor) { base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); + cc::LayerTreeSettings settings = + GenerateLayerTreeSettings(*cmd, compositor_deps_, device_scale_factor); + cc::LayerTreeHost::InitParams params; + params.client = this; + params.shared_bitmap_manager = compositor_deps_->GetSharedBitmapManager(); + params.gpu_memory_buffer_manager = + compositor_deps_->GetGpuMemoryBufferManager(); + params.settings = &settings; + params.task_graph_runner = compositor_deps_->GetTaskGraphRunner(); + params.main_task_runner = + compositor_deps_->GetCompositorMainThreadTaskRunner(); + if (settings.use_external_begin_frame_source) { + params.external_begin_frame_source = + delegate_->CreateExternalBeginFrameSource(); + } + params.animation_host = cc::AnimationHost::CreateMainInstance(); + + if (cmd->HasSwitch(switches::kUseRemoteCompositing)) { + DCHECK(!threaded_); + params.image_serialization_processor = + compositor_deps_->GetImageSerializationProcessor(); + layer_tree_host_ = cc::LayerTreeHost::CreateRemoteServer(this, ¶ms); + } else if (!threaded_) { + // Single-threaded layout tests. + layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded(this, ¶ms); + } else { + layer_tree_host_ = cc::LayerTreeHost::CreateThreaded( + compositor_deps_->GetCompositorImplThreadTaskRunner(), ¶ms); + } + DCHECK(layer_tree_host_); +} + +RenderWidgetCompositor::~RenderWidgetCompositor() = default; +// static +cc::LayerTreeSettings RenderWidgetCompositor::GenerateLayerTreeSettings( + const base::CommandLine& cmd, + CompositorDependencies* compositor_deps, + float device_scale_factor) { cc::LayerTreeSettings settings; // For web contents, layer transforms should scale up the contents of layers // to keep content always crisp when possible. settings.layer_transforms_should_scale_layer_contents = true; - if (cmd->HasSwitch(switches::kDisableGpuVsync)) { + if (cmd.HasSwitch(switches::kDisableGpuVsync)) { std::string display_vsync_string = - cmd->GetSwitchValueASCII(switches::kDisableGpuVsync); + cmd.GetSwitchValueASCII(switches::kDisableGpuVsync); if (display_vsync_string == "gpu") { settings.renderer_settings.disable_display_vsync = true; } else if (display_vsync_string == "beginframe") { @@ -247,38 +287,33 @@ void RenderWidgetCompositor::Initialize(float device_scale_factor) { } } settings.main_frame_before_activation_enabled = - cmd->HasSwitch(cc::switches::kEnableMainFrameBeforeActivation); - settings.use_mouse_wheel_gestures = UseGestureBasedWheelScrolling(); + cmd.HasSwitch(cc::switches::kEnableMainFrameBeforeActivation); + // TODO(danakj): This should not be a setting O_O; it should change when the + // device scale factor on LayerTreeHost changes. settings.default_tile_size = CalculateDefaultTileSize(device_scale_factor); - if (cmd->HasSwitch(switches::kDefaultTileWidth)) { + if (cmd.HasSwitch(switches::kDefaultTileWidth)) { int tile_width = 0; - GetSwitchValueAsInt(*cmd, - switches::kDefaultTileWidth, - 1, - std::numeric_limits<int>::max(), - &tile_width); + GetSwitchValueAsInt(cmd, switches::kDefaultTileWidth, 1, + std::numeric_limits<int>::max(), &tile_width); settings.default_tile_size.set_width(tile_width); } - if (cmd->HasSwitch(switches::kDefaultTileHeight)) { + if (cmd.HasSwitch(switches::kDefaultTileHeight)) { int tile_height = 0; - GetSwitchValueAsInt(*cmd, - switches::kDefaultTileHeight, - 1, - std::numeric_limits<int>::max(), - &tile_height); + GetSwitchValueAsInt(cmd, switches::kDefaultTileHeight, 1, + std::numeric_limits<int>::max(), &tile_height); settings.default_tile_size.set_height(tile_height); } int max_untiled_layer_width = settings.max_untiled_layer_size.width(); - if (cmd->HasSwitch(switches::kMaxUntiledLayerWidth)) { - GetSwitchValueAsInt(*cmd, switches::kMaxUntiledLayerWidth, 1, + if (cmd.HasSwitch(switches::kMaxUntiledLayerWidth)) { + GetSwitchValueAsInt(cmd, switches::kMaxUntiledLayerWidth, 1, std::numeric_limits<int>::max(), &max_untiled_layer_width); } int max_untiled_layer_height = settings.max_untiled_layer_size.height(); - if (cmd->HasSwitch(switches::kMaxUntiledLayerHeight)) { - GetSwitchValueAsInt(*cmd, switches::kMaxUntiledLayerHeight, 1, + if (cmd.HasSwitch(switches::kMaxUntiledLayerHeight)) { + GetSwitchValueAsInt(cmd, switches::kMaxUntiledLayerHeight, 1, std::numeric_limits<int>::max(), &max_untiled_layer_height); } @@ -287,50 +322,50 @@ void RenderWidgetCompositor::Initialize(float device_scale_factor) { max_untiled_layer_height); settings.gpu_rasterization_msaa_sample_count = - compositor_deps_->GetGpuRasterizationMSAASampleCount(); + compositor_deps->GetGpuRasterizationMSAASampleCount(); settings.gpu_rasterization_forced = - compositor_deps_->IsGpuRasterizationForced(); + compositor_deps->IsGpuRasterizationForced(); settings.gpu_rasterization_enabled = - compositor_deps_->IsGpuRasterizationEnabled(); + compositor_deps->IsGpuRasterizationEnabled(); settings.async_worker_context_enabled = - compositor_deps_->IsAsyncWorkerContextEnabled(); + compositor_deps->IsAsyncWorkerContextEnabled(); - settings.can_use_lcd_text = compositor_deps_->IsLcdTextEnabled(); + settings.can_use_lcd_text = compositor_deps->IsLcdTextEnabled(); settings.use_distance_field_text = - compositor_deps_->IsDistanceFieldTextEnabled(); - settings.use_zero_copy = compositor_deps_->IsZeroCopyEnabled(); - settings.use_partial_raster = compositor_deps_->IsPartialRasterEnabled(); + compositor_deps->IsDistanceFieldTextEnabled(); + settings.use_zero_copy = compositor_deps->IsZeroCopyEnabled(); + settings.use_partial_raster = compositor_deps->IsPartialRasterEnabled(); settings.enable_elastic_overscroll = - compositor_deps_->IsElasticOverscrollEnabled(); + compositor_deps->IsElasticOverscrollEnabled(); settings.renderer_settings.use_gpu_memory_buffer_resources = - compositor_deps_->IsGpuMemoryBufferCompositorResourcesEnabled(); + compositor_deps->IsGpuMemoryBufferCompositorResourcesEnabled(); settings.use_image_texture_targets = - compositor_deps_->GetImageTextureTargets(); + compositor_deps->GetImageTextureTargets(); settings.image_decode_tasks_enabled = - compositor_deps_->AreImageDecodeTasksEnabled(); - - if (cmd->HasSwitch(cc::switches::kTopControlsShowThreshold)) { - std::string top_threshold_str = - cmd->GetSwitchValueASCII(cc::switches::kTopControlsShowThreshold); - double show_threshold; - if (base::StringToDouble(top_threshold_str, &show_threshold) && - show_threshold >= 0.f && show_threshold <= 1.f) - settings.top_controls_show_threshold = show_threshold; + compositor_deps->AreImageDecodeTasksEnabled(); + + if (cmd.HasSwitch(cc::switches::kTopControlsShowThreshold)) { + std::string top_threshold_str = + cmd.GetSwitchValueASCII(cc::switches::kTopControlsShowThreshold); + double show_threshold; + if (base::StringToDouble(top_threshold_str, &show_threshold) && + show_threshold >= 0.f && show_threshold <= 1.f) + settings.top_controls_show_threshold = show_threshold; } - if (cmd->HasSwitch(cc::switches::kTopControlsHideThreshold)) { - std::string top_threshold_str = - cmd->GetSwitchValueASCII(cc::switches::kTopControlsHideThreshold); - double hide_threshold; - if (base::StringToDouble(top_threshold_str, &hide_threshold) && - hide_threshold >= 0.f && hide_threshold <= 1.f) - settings.top_controls_hide_threshold = hide_threshold; + if (cmd.HasSwitch(cc::switches::kTopControlsHideThreshold)) { + std::string top_threshold_str = + cmd.GetSwitchValueASCII(cc::switches::kTopControlsHideThreshold); + double hide_threshold; + if (base::StringToDouble(top_threshold_str, &hide_threshold) && + hide_threshold >= 0.f && hide_threshold <= 1.f) + settings.top_controls_hide_threshold = hide_threshold; } - settings.use_layer_lists = cmd->HasSwitch(cc::switches::kEnableLayerLists); + settings.use_layer_lists = cmd.HasSwitch(cc::switches::kEnableLayerLists); settings.renderer_settings.allow_antialiasing &= - !cmd->HasSwitch(cc::switches::kDisableCompositedAntialiasing); + !cmd.HasSwitch(cc::switches::kDisableCompositedAntialiasing); // The means the renderer compositor has 2 possible modes: // - Threaded compositing with a scheduler. // - Single threaded compositing without a scheduler (for layout tests only). @@ -340,30 +375,28 @@ void RenderWidgetCompositor::Initialize(float device_scale_factor) { // These flags should be mirrored by UI versions in ui/compositor/. settings.initial_debug_state.show_debug_borders = - cmd->HasSwitch(cc::switches::kShowCompositedLayerBorders); + cmd.HasSwitch(cc::switches::kShowCompositedLayerBorders); settings.initial_debug_state.show_layer_animation_bounds_rects = - cmd->HasSwitch(cc::switches::kShowLayerAnimationBounds); + cmd.HasSwitch(cc::switches::kShowLayerAnimationBounds); settings.initial_debug_state.show_paint_rects = - cmd->HasSwitch(switches::kShowPaintRects); + cmd.HasSwitch(switches::kShowPaintRects); settings.initial_debug_state.show_property_changed_rects = - cmd->HasSwitch(cc::switches::kShowPropertyChangedRects); + cmd.HasSwitch(cc::switches::kShowPropertyChangedRects); settings.initial_debug_state.show_surface_damage_rects = - cmd->HasSwitch(cc::switches::kShowSurfaceDamageRects); + cmd.HasSwitch(cc::switches::kShowSurfaceDamageRects); settings.initial_debug_state.show_screen_space_rects = - cmd->HasSwitch(cc::switches::kShowScreenSpaceRects); + cmd.HasSwitch(cc::switches::kShowScreenSpaceRects); settings.initial_debug_state.show_replica_screen_space_rects = - cmd->HasSwitch(cc::switches::kShowReplicaScreenSpaceRects); + cmd.HasSwitch(cc::switches::kShowReplicaScreenSpaceRects); settings.initial_debug_state.SetRecordRenderingStats( - cmd->HasSwitch(cc::switches::kEnableGpuBenchmarking)); + cmd.HasSwitch(cc::switches::kEnableGpuBenchmarking)); - if (cmd->HasSwitch(cc::switches::kSlowDownRasterScaleFactor)) { + if (cmd.HasSwitch(cc::switches::kSlowDownRasterScaleFactor)) { const int kMinSlowDownScaleFactor = 0; const int kMaxSlowDownScaleFactor = INT_MAX; GetSwitchValueAsInt( - *cmd, - cc::switches::kSlowDownRasterScaleFactor, - kMinSlowDownScaleFactor, + cmd, cc::switches::kSlowDownRasterScaleFactor, kMinSlowDownScaleFactor, kMaxSlowDownScaleFactor, &settings.initial_debug_state.slow_down_raster_scale_factor); } @@ -403,7 +436,7 @@ void RenderWidgetCompositor::Initialize(float device_scale_factor) { // RGBA_4444 textures are only enabled by default for low end devices // and are disabled for Android WebView as it doesn't support the format. - if (!cmd->HasSwitch(switches::kDisableRGBA4444Textures)) + if (!cmd.HasSwitch(switches::kDisableRGBA4444Textures)) settings.renderer_settings.preferred_tile_format = cc::RGBA_4444; } else { // On other devices we have increased memory excessively to avoid @@ -420,7 +453,8 @@ void RenderWidgetCompositor::Initialize(float device_scale_factor) { settings.use_external_begin_frame_source = true; -#elif !defined(OS_MACOSX) +#else // defined(OS_ANDROID) +#if !defined(OS_MACOSX) if (ui::IsOverlayScrollbarEnabled()) { settings.scrollbar_animator = cc::LayerTreeSettings::THINNING; settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128); @@ -431,21 +465,36 @@ void RenderWidgetCompositor::Initialize(float device_scale_factor) { settings.scrollbar_fade_delay_ms = 500; settings.scrollbar_fade_resize_delay_ms = 500; settings.scrollbar_fade_duration_ms = 300; -#endif +#endif // !defined(OS_MACOSX) + + // On desktop, if there's over 4GB of memory on the machine, increase the + // image decode budget to 256MB for both gpu and software. + const int kImageDecodeMemoryThresholdMB = 4 * 1024; + if (base::SysInfo::AmountOfPhysicalMemoryMB() >= + kImageDecodeMemoryThresholdMB) { + settings.gpu_decoded_image_budget_bytes = 256 * 1024 * 1024; + settings.software_decoded_image_budget_bytes = 256 * 1024 * 1024; + } else { + // These are the defaults, but recorded here as well. + settings.gpu_decoded_image_budget_bytes = 96 * 1024 * 1024; + settings.software_decoded_image_budget_bytes = 128 * 1024 * 1024; + } - if (cmd->HasSwitch(switches::kEnableLowResTiling)) +#endif // defined(OS_ANDROID) + + if (cmd.HasSwitch(switches::kEnableLowResTiling)) settings.create_low_res_tiling = true; - if (cmd->HasSwitch(switches::kDisableLowResTiling)) + if (cmd.HasSwitch(switches::kDisableLowResTiling)) settings.create_low_res_tiling = false; - if (cmd->HasSwitch(cc::switches::kEnableBeginFrameScheduling)) + if (cmd.HasSwitch(cc::switches::kEnableBeginFrameScheduling)) settings.use_external_begin_frame_source = true; - if (cmd->HasSwitch(switches::kEnableRGBA4444Textures) && - !cmd->HasSwitch(switches::kDisableRGBA4444Textures)) { + if (cmd.HasSwitch(switches::kEnableRGBA4444Textures) && + !cmd.HasSwitch(switches::kDisableRGBA4444Textures)) { settings.renderer_settings.preferred_tile_format = cc::RGBA_4444; } - if (cmd->HasSwitch(cc::switches::kEnableTileCompression)) { + if (cmd.HasSwitch(cc::switches::kEnableTileCompression)) { settings.renderer_settings.preferred_tile_format = cc::ETC1; } @@ -457,55 +506,96 @@ void RenderWidgetCompositor::Initialize(float device_scale_factor) { cc::ManagedMemoryPolicy current = settings.memory_policy_; settings.memory_policy_ = GetGpuMemoryPolicy(current); - settings.use_cached_picture_raster = !cmd->HasSwitch( - cc::switches::kDisableCachedPictureRaster); - - scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner = - compositor_deps_->GetCompositorImplThreadTaskRunner(); - scoped_refptr<base::SingleThreadTaskRunner> - main_thread_compositor_task_runner = - compositor_deps_->GetCompositorMainThreadTaskRunner(); - cc::SharedBitmapManager* shared_bitmap_manager = - compositor_deps_->GetSharedBitmapManager(); - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = - compositor_deps_->GetGpuMemoryBufferManager(); - cc::TaskGraphRunner* task_graph_runner = - compositor_deps_->GetTaskGraphRunner(); - - bool use_remote_compositing = cmd->HasSwitch(switches::kUseRemoteCompositing); + settings.use_cached_picture_raster = + !cmd.HasSwitch(cc::switches::kDisableCachedPictureRaster); - if (use_remote_compositing) + if (cmd.HasSwitch(switches::kUseRemoteCompositing)) settings.use_external_begin_frame_source = false; - std::unique_ptr<cc::BeginFrameSource> external_begin_frame_source; - if (settings.use_external_begin_frame_source) { - external_begin_frame_source = delegate_->CreateExternalBeginFrameSource(); + return settings; +} + +// static +cc::ManagedMemoryPolicy RenderWidgetCompositor::GetGpuMemoryPolicy( + const cc::ManagedMemoryPolicy& policy) { + cc::ManagedMemoryPolicy actual = policy; + actual.bytes_limit_when_visible = 0; + + // If the value was overridden on the command line, use the specified value. + static bool client_hard_limit_bytes_overridden = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kForceGpuMemAvailableMb); + if (client_hard_limit_bytes_overridden) { + if (base::StringToSizeT( + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kForceGpuMemAvailableMb), + &actual.bytes_limit_when_visible)) + actual.bytes_limit_when_visible *= 1024 * 1024; + return actual; } - cc::LayerTreeHost::InitParams params; - params.client = this; - params.shared_bitmap_manager = shared_bitmap_manager; - params.gpu_memory_buffer_manager = gpu_memory_buffer_manager; - params.settings = &settings; - params.task_graph_runner = task_graph_runner; - params.main_task_runner = main_thread_compositor_task_runner; - params.external_begin_frame_source = std::move(external_begin_frame_source); - if (use_remote_compositing) { - DCHECK(!compositor_thread_task_runner.get()); - params.image_serialization_processor = - compositor_deps_->GetImageSerializationProcessor(); - layer_tree_host_ = cc::LayerTreeHost::CreateRemoteServer(this, ¶ms); - } else if (compositor_thread_task_runner.get()) { - layer_tree_host_ = cc::LayerTreeHost::CreateThreaded( - compositor_thread_task_runner, ¶ms); - } else { - layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded(this, ¶ms); +#if defined(OS_ANDROID) + // We can't query available GPU memory from the system on Android. + // Physical memory is also mis-reported sometimes (eg. Nexus 10 reports + // 1262MB when it actually has 2GB, while Razr M has 1GB but only reports + // 128MB java heap size). First we estimate physical memory using both. + size_t dalvik_mb = base::SysInfo::DalvikHeapSizeMB(); + size_t physical_mb = base::SysInfo::AmountOfPhysicalMemoryMB(); + size_t physical_memory_mb = 0; + if (dalvik_mb >= 256) + physical_memory_mb = dalvik_mb * 4; + else + physical_memory_mb = std::max(dalvik_mb * 4, (physical_mb * 4) / 3); + + // Now we take a default of 1/8th of memory on high-memory devices, + // and gradually scale that back for low-memory devices (to be nicer + // to other apps so they don't get killed). Examples: + // Nexus 4/10(2GB) 256MB (normally 128MB) + // Droid Razr M(1GB) 114MB (normally 57MB) + // Galaxy Nexus(1GB) 100MB (normally 50MB) + // Xoom(1GB) 100MB (normally 50MB) + // Nexus S(low-end) 8MB (normally 8MB) + // Note that the compositor now uses only some of this memory for + // pre-painting and uses the rest only for 'emergencies'. + if (actual.bytes_limit_when_visible == 0) { + // NOTE: Non-low-end devices use only 50% of these limits, + // except during 'emergencies' where 100% can be used. + if (!base::SysInfo::IsLowEndDevice()) { + if (physical_memory_mb >= 1536) + actual.bytes_limit_when_visible = physical_memory_mb / 8; // >192MB + else if (physical_memory_mb >= 1152) + actual.bytes_limit_when_visible = physical_memory_mb / 8; // >144MB + else if (physical_memory_mb >= 768) + actual.bytes_limit_when_visible = physical_memory_mb / 10; // >76MB + else + actual.bytes_limit_when_visible = physical_memory_mb / 12; // <64MB + } else { + // Low-end devices have 512MB or less memory by definition + // so we hard code the limit rather than relying on the heuristics + // above. Low-end devices use 4444 textures so we can use a lower limit. + actual.bytes_limit_when_visible = 8; + } + actual.bytes_limit_when_visible = + actual.bytes_limit_when_visible * 1024 * 1024; + // Clamp the observed value to a specific range on Android. + actual.bytes_limit_when_visible = std::max( + actual.bytes_limit_when_visible, static_cast<size_t>(8 * 1024 * 1024)); + actual.bytes_limit_when_visible = + std::min(actual.bytes_limit_when_visible, + static_cast<size_t>(256 * 1024 * 1024)); } - DCHECK(layer_tree_host_); + actual.priority_cutoff_when_visible = + gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING; +#else + // Ignore what the system said and give all clients the same maximum + // allocation on desktop platforms. + actual.bytes_limit_when_visible = 512 * 1024 * 1024; + actual.priority_cutoff_when_visible = + gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE; +#endif + return actual; } -RenderWidgetCompositor::~RenderWidgetCompositor() {} - void RenderWidgetCompositor::SetNeverVisible() { DCHECK(!layer_tree_host_->visible()); never_visible_ = true; @@ -657,6 +747,10 @@ void RenderWidgetCompositor::startPageScaleAnimation( duration); } +bool RenderWidgetCompositor::hasPendingPageScaleAnimation() const { + return layer_tree_host_->HasPendingPageScaleAnimation(); +} + void RenderWidgetCompositor::heuristicsForGpuRasterizationUpdated( bool matches_heuristics) { layer_tree_host_->SetHasGpuRasterizationTrigger(matches_heuristics); @@ -724,6 +818,12 @@ void RenderWidgetCompositor::clearSelection() { layer_tree_host_->RegisterSelection(empty_selection); } +void RenderWidgetCompositor::setMutatorClient( + std::unique_ptr<blink::WebCompositorMutatorClient> client) { + TRACE_EVENT0("compositor-worker", "RenderWidgetCompositor::setMutatorClient"); + layer_tree_host_->SetLayerTreeMutator(std::move(client)); +} + static_assert(static_cast<cc::EventListenerClass>( blink::WebEventListenerClass::TouchStartOrMove) == cc::EventListenerClass::kTouchStartOrMove, @@ -786,8 +886,11 @@ void CompositeAndReadbackAsyncCallback( } bool RenderWidgetCompositor::CompositeIsSynchronous() const { - return !compositor_deps_->GetCompositorImplThreadTaskRunner().get() && - !layer_tree_host_->settings().single_thread_proxy_scheduler; + if (!threaded_) { + DCHECK(!layer_tree_host_->settings().single_thread_proxy_scheduler); + return true; + } + return false; } void RenderWidgetCompositor::layoutAndPaintAsync( @@ -989,8 +1092,7 @@ void RenderWidgetCompositor::DidCommitAndDrawFrame() { void RenderWidgetCompositor::DidCompleteSwapBuffers() { delegate_->DidCompleteSwapBuffers(); - bool threaded = !!compositor_deps_->GetCompositorImplThreadTaskRunner().get(); - if (!threaded) + if (!threaded_) delegate_->OnSwapBuffersComplete(); } @@ -998,13 +1100,6 @@ void RenderWidgetCompositor::DidCompletePageScaleAnimation() { delegate_->DidCompletePageScaleAnimation(); } -void RenderWidgetCompositor::ReportFixedRasterScaleUseCounters( - bool has_blurry_content, - bool has_potential_performance_regression) { - delegate_->ReportFixedRasterScaleUseCounters( - has_blurry_content, has_potential_performance_regression); -} - void RenderWidgetCompositor::RequestScheduleAnimation() { delegate_->RequestScheduleAnimation(); } @@ -1050,86 +1145,6 @@ void RenderWidgetCompositor::OnHandleCompositorProto( remote_proto_channel_receiver_->OnProtoReceived(std::move(deserialized)); } -cc::ManagedMemoryPolicy RenderWidgetCompositor::GetGpuMemoryPolicy( - const cc::ManagedMemoryPolicy& policy) { - cc::ManagedMemoryPolicy actual = policy; - actual.bytes_limit_when_visible = 0; - - // If the value was overridden on the command line, use the specified value. - static bool client_hard_limit_bytes_overridden = - base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kForceGpuMemAvailableMb); - if (client_hard_limit_bytes_overridden) { - if (base::StringToSizeT( - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kForceGpuMemAvailableMb), - &actual.bytes_limit_when_visible)) - actual.bytes_limit_when_visible *= 1024 * 1024; - return actual; - } - -#if defined(OS_ANDROID) - // We can't query available GPU memory from the system on Android. - // Physical memory is also mis-reported sometimes (eg. Nexus 10 reports - // 1262MB when it actually has 2GB, while Razr M has 1GB but only reports - // 128MB java heap size). First we estimate physical memory using both. - size_t dalvik_mb = base::SysInfo::DalvikHeapSizeMB(); - size_t physical_mb = base::SysInfo::AmountOfPhysicalMemoryMB(); - size_t physical_memory_mb = 0; - if (dalvik_mb >= 256) - physical_memory_mb = dalvik_mb * 4; - else - physical_memory_mb = std::max(dalvik_mb * 4, (physical_mb * 4) / 3); - - // Now we take a default of 1/8th of memory on high-memory devices, - // and gradually scale that back for low-memory devices (to be nicer - // to other apps so they don't get killed). Examples: - // Nexus 4/10(2GB) 256MB (normally 128MB) - // Droid Razr M(1GB) 114MB (normally 57MB) - // Galaxy Nexus(1GB) 100MB (normally 50MB) - // Xoom(1GB) 100MB (normally 50MB) - // Nexus S(low-end) 8MB (normally 8MB) - // Note that the compositor now uses only some of this memory for - // pre-painting and uses the rest only for 'emergencies'. - if (actual.bytes_limit_when_visible == 0) { - // NOTE: Non-low-end devices use only 50% of these limits, - // except during 'emergencies' where 100% can be used. - if (!base::SysInfo::IsLowEndDevice()) { - if (physical_memory_mb >= 1536) - actual.bytes_limit_when_visible = physical_memory_mb / 8; // >192MB - else if (physical_memory_mb >= 1152) - actual.bytes_limit_when_visible = physical_memory_mb / 8; // >144MB - else if (physical_memory_mb >= 768) - actual.bytes_limit_when_visible = physical_memory_mb / 10; // >76MB - else - actual.bytes_limit_when_visible = physical_memory_mb / 12; // <64MB - } else { - // Low-end devices have 512MB or less memory by definition - // so we hard code the limit rather than relying on the heuristics - // above. Low-end devices use 4444 textures so we can use a lower limit. - actual.bytes_limit_when_visible = 8; - } - actual.bytes_limit_when_visible = - actual.bytes_limit_when_visible * 1024 * 1024; - // Clamp the observed value to a specific range on Android. - actual.bytes_limit_when_visible = std::max( - actual.bytes_limit_when_visible, static_cast<size_t>(8 * 1024 * 1024)); - actual.bytes_limit_when_visible = - std::min(actual.bytes_limit_when_visible, - static_cast<size_t>(256 * 1024 * 1024)); - } - actual.priority_cutoff_when_visible = - gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING; -#else - // Ignore what the system said and give all clients the same maximum - // allocation on desktop platforms. - actual.bytes_limit_when_visible = 512 * 1024 * 1024; - actual.priority_cutoff_when_visible = - gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE; -#endif - return actual; -} - void RenderWidgetCompositor::SetPaintedDeviceScaleFactor( float device_scale) { layer_tree_host_->SetPaintedDeviceScaleFactor(device_scale); diff --git a/chromium/content/renderer/gpu/render_widget_compositor.h b/chromium/content/renderer/gpu/render_widget_compositor.h index 3b8637ebf8e..68349ec2b9a 100644 --- a/chromium/content/renderer/gpu/render_widget_compositor.h +++ b/chromium/content/renderer/gpu/render_widget_compositor.h @@ -22,11 +22,10 @@ #include "content/common/content_export.h" #include "content/renderer/gpu/compositor_dependencies.h" #include "third_party/WebKit/public/platform/WebLayerTreeView.h" -#include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/geometry/rect.h" -namespace ui { -class LatencyInfo; +namespace base { +class CommandLine; } namespace cc { @@ -34,11 +33,13 @@ class CopyOutputRequest; class InputHandler; class Layer; class LayerTreeHost; - namespace proto { class CompositorMessage; } +} +namespace ui { +class LatencyInfo; } namespace content { @@ -60,6 +61,13 @@ class CONTENT_EXPORT RenderWidgetCompositor ~RenderWidgetCompositor() override; + static cc::LayerTreeSettings GenerateLayerTreeSettings( + const base::CommandLine& cmd, + CompositorDependencies* compositor_deps, + float device_scale_factor); + static cc::ManagedMemoryPolicy GetGpuMemoryPolicy( + const cc::ManagedMemoryPolicy& policy); + void SetNeverVisible(); const base::WeakPtr<cc::InputHandler>& GetInputHandler(); bool BeginMainFrameRequested() const; @@ -91,8 +99,6 @@ class CONTENT_EXPORT RenderWidgetCompositor bool SendMessageToMicroBenchmark(int id, std::unique_ptr<base::Value> value); void SetSurfaceIdNamespace(uint32_t surface_id_namespace); void OnHandleCompositorProto(const std::vector<uint8_t>& proto); - cc::ManagedMemoryPolicy GetGpuMemoryPolicy( - const cc::ManagedMemoryPolicy& policy); void SetPaintedDeviceScaleFactor(float device_scale); // WebLayerTreeView implementation. @@ -116,6 +122,7 @@ class CONTENT_EXPORT RenderWidgetCompositor bool use_anchor, float new_page_scale, double duration_sec) override; + bool hasPendingPageScaleAnimation() const override; void heuristicsForGpuRasterizationUpdated(bool matches_heuristics) override; void setNeedsAnimate() override; void setNeedsBeginFrame() override; @@ -134,6 +141,8 @@ class CONTENT_EXPORT RenderWidgetCompositor void clearViewportLayers() override; void registerSelection(const blink::WebSelection& selection) override; void clearSelection() override; + void setMutatorClient( + std::unique_ptr<blink::WebCompositorMutatorClient>) override; void setEventListenerProperties( blink::WebEventListenerClass eventClass, blink::WebEventListenerProperties properties) override; @@ -172,9 +181,6 @@ class CONTENT_EXPORT RenderWidgetCompositor void DidCommitAndDrawFrame() override; void DidCompleteSwapBuffers() override; void DidCompletePageScaleAnimation() override; - void ReportFixedRasterScaleUseCounters( - bool has_blurry_content, - bool has_potential_performance_regression) override; // cc::LayerTreeHostSingleThreadClient implementation. void RequestScheduleAnimation() override; @@ -208,6 +214,7 @@ class CONTENT_EXPORT RenderWidgetCompositor int num_failed_recreate_attempts_; RenderWidgetCompositorDelegate* const delegate_; CompositorDependencies* const compositor_deps_; + const bool threaded_; std::unique_ptr<cc::LayerTreeHost> layer_tree_host_; bool never_visible_; diff --git a/chromium/content/renderer/gpu/render_widget_compositor_delegate.h b/chromium/content/renderer/gpu/render_widget_compositor_delegate.h index c688ef9fdad..e31e19e26b5 100644 --- a/chromium/content/renderer/gpu/render_widget_compositor_delegate.h +++ b/chromium/content/renderer/gpu/render_widget_compositor_delegate.h @@ -83,12 +83,6 @@ class CONTENT_EXPORT RenderWidgetCompositorDelegate { // perform actual painting work. virtual void WillBeginCompositorFrame() = 0; - // Indicates that the last commit would have a blurry content or potential - // performance regression in a fixed raster scale layer. - virtual void ReportFixedRasterScaleUseCounters( - bool has_blurry_content, - bool has_potential_performance_regression) = 0; - protected: virtual ~RenderWidgetCompositorDelegate() {} }; diff --git a/chromium/content/renderer/gpu/render_widget_compositor_unittest.cc b/chromium/content/renderer/gpu/render_widget_compositor_unittest.cc index 11c3a575a4c..6dae54c12f7 100644 --- a/chromium/content/renderer/gpu/render_widget_compositor_unittest.cc +++ b/chromium/content/renderer/gpu/render_widget_compositor_unittest.cc @@ -13,6 +13,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "cc/output/begin_frame_args.h" #include "cc/test/failure_output_surface.h" +#include "cc/test/fake_external_begin_frame_source.h" #include "cc/trees/layer_tree_host.h" #include "components/scheduler/renderer/renderer_scheduler.h" #include "content/public/test/mock_render_thread.h" @@ -29,89 +30,112 @@ using testing::Field; namespace content { namespace { -class MockWebWidget : public blink::WebWidget { +class StubRenderWidgetCompositorDelegate + : public RenderWidgetCompositorDelegate { public: - MOCK_METHOD1(beginFrame, void(double lastFrameTimeMonotonic)); -}; - -class TestRenderWidget : public RenderWidget { - public: - explicit TestRenderWidget(CompositorDependencies* compositor_deps) - : RenderWidget(compositor_deps, - blink::WebPopupTypeNone, - blink::WebScreenInfo(), - true, - false, - false) { - webwidget_ = &mock_webwidget_; - SetRoutingID(++next_routing_id_); + // RenderWidgetCompositorDelegate implementation. + void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, + const gfx::Vector2dF& outer_delta, + const gfx::Vector2dF& elastic_overscroll_delta, + float page_scale, + float top_controls_delta) override {} + void BeginMainFrame(double frame_time_sec) override {} + std::unique_ptr<cc::OutputSurface> CreateOutputSurface( + bool fallback) override { + return nullptr; } - - MockWebWidget mock_webwidget_; - - protected: - ~TestRenderWidget() override { webwidget_ = NULL; } - static int next_routing_id_; - - DISALLOW_COPY_AND_ASSIGN(TestRenderWidget); + std::unique_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource() + override { + return nullptr; + } + void DidCommitAndDrawCompositorFrame() override {} + void DidCommitCompositorFrame() override {} + void DidCompletePageScaleAnimation() override {} + void DidCompleteSwapBuffers() override {} + void ForwardCompositorProto(const std::vector<uint8_t>& proto) override {} + bool IsClosing() const override { return false; } + void OnSwapBuffersAborted() override {} + void OnSwapBuffersComplete() override {} + void OnSwapBuffersPosted() override {} + void RequestScheduleAnimation() override {} + void UpdateVisualState() override {} + void WillBeginCompositorFrame() override {} }; -int TestRenderWidget::next_routing_id_ = 0; - -class RenderWidgetCompositorTest : public testing::Test { +class FakeRenderWidgetCompositorDelegate + : public StubRenderWidgetCompositorDelegate { public: - RenderWidgetCompositorTest() - : compositor_deps_(new FakeCompositorDependencies), - render_widget_(new TestRenderWidget(compositor_deps_.get())), - render_widget_compositor_(RenderWidgetCompositor::Create( - render_widget_.get(), - 1.f /* initial_device_scale_factor */, - compositor_deps_.get())) {} - ~RenderWidgetCompositorTest() override {} + FakeRenderWidgetCompositorDelegate() = default; - protected: - base::MessageLoop loop_; - MockRenderThread render_thread_; - std::unique_ptr<FakeCompositorDependencies> compositor_deps_; - scoped_refptr<TestRenderWidget> render_widget_; - std::unique_ptr<RenderWidgetCompositor> render_widget_compositor_; - - private: - DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorTest); -}; - -TEST_F(RenderWidgetCompositorTest, BeginMainFrame) { - base::TimeTicks frame_time(base::TimeTicks() + - base::TimeDelta::FromSeconds(1)); - base::TimeTicks deadline(base::TimeTicks() + base::TimeDelta::FromSeconds(2)); - base::TimeDelta interval(base::TimeDelta::FromSeconds(3)); - cc::BeginFrameArgs args( - cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline, - interval, cc::BeginFrameArgs::NORMAL)); + std::unique_ptr<cc::OutputSurface> CreateOutputSurface( + bool fallback) override { + EXPECT_EQ( + num_requests_since_last_success_ > + RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK, + fallback); + last_create_was_fallback_ = fallback; + bool success = num_failures_ >= num_failures_before_success_; + if (success) { + std::unique_ptr<cc::TestWebGraphicsContext3D> context = + cc::TestWebGraphicsContext3D::Create(); + // Image support required for synchronous compositing. + context->set_support_image(true); + // Create delegating surface so that max_pending_frames = 1. + return cc::FakeOutputSurface::CreateDelegating3d(std::move(context)); + } + return use_null_output_surface_ + ? nullptr + : base::WrapUnique(new cc::FailureOutputSurface(true)); + } - EXPECT_CALL(render_widget_->mock_webwidget_, beginFrame(1)); + std::unique_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource() + override { + double refresh_rate = 200.0; + bool tick_automatically = true; + return base::MakeUnique<cc::FakeExternalBeginFrameSource>( + refresh_rate, tick_automatically); + } - render_widget_compositor_->BeginMainFrame(args); -} + void add_success() { + if (last_create_was_fallback_) + ++num_fallback_successes_; + else + ++num_successes_; + num_requests_since_last_success_ = 0; + } + int num_successes() const { return num_successes_; } + int num_fallback_successes() const { return num_fallback_successes_; } -class RenderWidgetCompositorOutputSurface; + void add_request() { + ++num_requests_since_last_success_; + ++num_requests_; + } + int num_requests() const { return num_requests_; } -class RenderWidgetOutputSurface : public TestRenderWidget { - public: - explicit RenderWidgetOutputSurface(CompositorDependencies* compositor_deps) - : TestRenderWidget(compositor_deps), compositor_(NULL) {} - void SetCompositor(RenderWidgetCompositorOutputSurface* compositor); + void add_failure() { ++num_failures_; } + int num_failures() const { return num_failures_; } - std::unique_ptr<cc::OutputSurface> CreateOutputSurface( - bool fallback) override; + void set_num_failures_before_success(int n) { + num_failures_before_success_ = n; + } + int num_failures_before_success() const { + return num_failures_before_success_; + } - protected: - ~RenderWidgetOutputSurface() override {} + void set_use_null_output_surface(bool u) { use_null_output_surface_ = u; } + bool use_null_output_surface() const { return use_null_output_surface_; } private: - RenderWidgetCompositorOutputSurface* compositor_; - - DISALLOW_COPY_AND_ASSIGN(RenderWidgetOutputSurface); + int num_requests_ = 0; + int num_requests_since_last_success_ = 0; + int num_failures_ = 0; + int num_failures_before_success_ = 0; + int num_fallback_successes_ = 0; + int num_successes_ = 0; + bool last_create_was_fallback_ = false; + bool use_null_output_surface_ = true; + + DISALLOW_COPY_AND_ASSIGN(FakeRenderWidgetCompositorDelegate); }; // Verify that failing to create an output surface will cause the compositor @@ -122,42 +146,14 @@ class RenderWidgetOutputSurface : public TestRenderWidget { // the compositor (couldn't bind the output surface) are handled identically. class RenderWidgetCompositorOutputSurface : public RenderWidgetCompositor { public: - RenderWidgetCompositorOutputSurface(RenderWidget* widget, - CompositorDependencies* compositor_deps) - : RenderWidgetCompositor(widget, compositor_deps), - num_failures_before_success_(0), - expected_successes_(0), - expected_fallback_successes_(0), - expected_requests_(0), - num_requests_(0), - num_requests_since_last_success_(0), - num_successes_(0), - num_fallback_successes_(0), - num_failures_(0), - last_create_was_fallback_(false), - use_null_output_surface_(true) {} + RenderWidgetCompositorOutputSurface( + FakeRenderWidgetCompositorDelegate* delegate, + CompositorDependencies* compositor_deps) + : RenderWidgetCompositor(delegate, compositor_deps), + delegate_(delegate) {} using RenderWidgetCompositor::Initialize; - std::unique_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback) { - EXPECT_EQ(num_requests_since_last_success_ > - OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK, - fallback); - last_create_was_fallback_ = fallback; - bool success = num_failures_ >= num_failures_before_success_; - if (success) { - std::unique_ptr<cc::TestWebGraphicsContext3D> context = - cc::TestWebGraphicsContext3D::Create(); - // Image support required for synchronous compositing. - context->set_support_image(true); - // Create delegating surface so that max_pending_frames = 1. - return cc::FakeOutputSurface::CreateDelegating3d(std::move(context)); - } - return use_null_output_surface_ - ? nullptr - : base::WrapUnique(new cc::FailureOutputSurface(true)); - } - // Force a new output surface to be created. void SynchronousComposite() { layer_tree_host()->DidLoseOutputSurface(); @@ -167,21 +163,15 @@ class RenderWidgetCompositorOutputSurface : public RenderWidgetCompositor { } void RequestNewOutputSurface() override { - ++num_requests_; - ++num_requests_since_last_success_; + delegate_->add_request(); RenderWidgetCompositor::RequestNewOutputSurface(); } void DidInitializeOutputSurface() override { - if (last_create_was_fallback_) - ++num_fallback_successes_; - else - ++num_successes_; - - if (num_requests_ == expected_requests_) { + delegate_->add_success(); + if (delegate_->num_requests() == expected_requests_) { EndTest(); } else { - num_requests_since_last_success_ = 0; RenderWidgetCompositor::DidInitializeOutputSurface(); // Post the synchronous composite task so that it is not called // reentrantly as a part of RequestNewOutputSurface. @@ -193,8 +183,8 @@ class RenderWidgetCompositorOutputSurface : public RenderWidgetCompositor { } void DidFailToInitializeOutputSurface() override { - ++num_failures_; - if (num_requests_ == expected_requests_) { + delegate_->add_failure(); + if (delegate_->num_requests() == expected_requests_) { EndTest(); return; } @@ -202,39 +192,29 @@ class RenderWidgetCompositorOutputSurface : public RenderWidgetCompositor { RenderWidgetCompositor::DidFailToInitializeOutputSurface(); } - void SetUp(bool use_null_output_surface, - int num_failures_before_success, - int expected_successes, - int expected_fallback_succeses) { - use_null_output_surface_ = use_null_output_surface; - num_failures_before_success_ = num_failures_before_success; + void SetUp(int expected_successes, int expected_fallback_succeses) { expected_successes_ = expected_successes; expected_fallback_successes_ = expected_fallback_succeses; - expected_requests_ = num_failures_before_success_ + expected_successes_ + - expected_fallback_successes_; + expected_requests_ = delegate_->num_failures_before_success() + + expected_successes_ + expected_fallback_successes_; } void EndTest() { base::MessageLoop::current()->QuitWhenIdle(); } void AfterTest() { - EXPECT_EQ(num_failures_before_success_, num_failures_); - EXPECT_EQ(expected_successes_, num_successes_); - EXPECT_EQ(expected_fallback_successes_, num_fallback_successes_); - EXPECT_EQ(expected_requests_, num_requests_); + EXPECT_EQ(delegate_->num_failures_before_success(), + delegate_->num_failures()); + EXPECT_EQ(expected_successes_, delegate_->num_successes()); + EXPECT_EQ(expected_fallback_successes_, + delegate_->num_fallback_successes()); + EXPECT_EQ(expected_requests_, delegate_->num_requests()); } private: - int num_failures_before_success_; - int expected_successes_; - int expected_fallback_successes_; - int expected_requests_; - int num_requests_; - int num_requests_since_last_success_; - int num_successes_; - int num_fallback_successes_; - int num_failures_; - bool last_create_was_fallback_; - bool use_null_output_surface_; + FakeRenderWidgetCompositorDelegate* delegate_; + int expected_successes_ = 0; + int expected_fallback_successes_ = 0; + int expected_requests_ = 0; DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurface); }; @@ -242,53 +222,39 @@ class RenderWidgetCompositorOutputSurface : public RenderWidgetCompositor { class RenderWidgetCompositorOutputSurfaceTest : public testing::Test { public: RenderWidgetCompositorOutputSurfaceTest() - : compositor_deps_(new FakeCompositorDependencies), - render_widget_(new RenderWidgetOutputSurface(compositor_deps_.get())) { - render_widget_compositor_.reset(new RenderWidgetCompositorOutputSurface( - render_widget_.get(), compositor_deps_.get())); - render_widget_compositor_->Initialize( - 1.f /* initial_device_scale_factor */); - render_widget_->SetCompositor(render_widget_compositor_.get()); + : render_widget_compositor_(&compositor_delegate_, &compositor_deps_) { + render_widget_compositor_.Initialize(1.f /* initial_device_scale_factor */); } void RunTest(bool use_null_output_surface, int num_failures_before_success, int expected_successes, int expected_fallback_succeses) { - render_widget_compositor_->SetUp( - use_null_output_surface, num_failures_before_success, - expected_successes, expected_fallback_succeses); - render_widget_compositor_->setVisible(true); + compositor_delegate_.set_use_null_output_surface(use_null_output_surface); + compositor_delegate_.set_num_failures_before_success( + num_failures_before_success); + render_widget_compositor_.SetUp(expected_successes, + expected_fallback_succeses); + render_widget_compositor_.setVisible(true); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&RenderWidgetCompositorOutputSurface::SynchronousComposite, - base::Unretained(render_widget_compositor_.get()))); + base::Unretained(&render_widget_compositor_))); base::MessageLoop::current()->Run(); - render_widget_compositor_->AfterTest(); + render_widget_compositor_.AfterTest(); } protected: base::MessageLoop ye_olde_message_loope_; MockRenderThread render_thread_; - std::unique_ptr<FakeCompositorDependencies> compositor_deps_; - scoped_refptr<RenderWidgetOutputSurface> render_widget_; - std::unique_ptr<RenderWidgetCompositorOutputSurface> - render_widget_compositor_; + FakeCompositorDependencies compositor_deps_; + FakeRenderWidgetCompositorDelegate compositor_delegate_; + RenderWidgetCompositorOutputSurface render_widget_compositor_; private: DISALLOW_COPY_AND_ASSIGN(RenderWidgetCompositorOutputSurfaceTest); }; -std::unique_ptr<cc::OutputSurface> -RenderWidgetOutputSurface::CreateOutputSurface(bool fallback) { - return compositor_->CreateOutputSurface(fallback); -} - -void RenderWidgetOutputSurface::SetCompositor( - RenderWidgetCompositorOutputSurface* compositor) { - compositor_ = compositor; -} - TEST_F(RenderWidgetCompositorOutputSurfaceTest, SucceedOnce) { RunTest(false, 0, 1, 0); } diff --git a/chromium/content/renderer/history_controller.cc b/chromium/content/renderer/history_controller.cc index 8f1bc3462f7..14ced356b88 100644 --- a/chromium/content/renderer/history_controller.cc +++ b/chromium/content/renderer/history_controller.cc @@ -196,8 +196,32 @@ void HistoryController::UpdateForCommit(RenderFrameImpl* frame, bool navigation_within_page) { switch (commit_type) { case blink::WebBackForwardCommit: - if (!provisional_entry_) + if (!provisional_entry_) { + // The provisional entry may have been discarded due to a navigation in + // a different frame. For main frames, it is not safe to leave the + // current_entry_ in place, which may have a cross-site page and will be + // included in the PageState for this commit. Replace it with a new + // HistoryEntry corresponding to the commit, and clear any stale + // NavigationParams which might point to the wrong entry. + // + // This will lack any subframe history items that were in the original + // provisional entry, but we don't know what those were after discarding + // it. We'll load the default URL in those subframes instead. + // + // TODO(creis): It's also possible to get here for subframe commits. + // We'll leave a stale current_entry_ in that case, but that only causes + // an earlier URL to load in the subframe when leaving and coming back, + // and only in rare cases. It does not risk a URL spoof, unlike the + // main frame case. Since this bug is not present in the new + // FrameNavigationEntry-based navigation path (https://crbug.com/236848) + // we'll wait for that to fix the subframe case. + if (frame->IsMainFrame()) { + current_entry_.reset(new HistoryEntry(item)); + navigation_params_.reset(); + } + return; + } // If the current entry is null, this must be a main frame commit. DCHECK(current_entry_ || frame->IsMainFrame()); @@ -230,6 +254,13 @@ void HistoryController::UpdateForCommit(RenderFrameImpl* frame, if (HistoryEntry::HistoryNode* node = current_entry_->GetHistoryNodeForFrame(frame)) { + // Clear the children and any NavigationParams if this commit isn't for + // the same item. Otherwise we might have stale data from a race. + if (node->item().itemSequenceNumber() != item.itemSequenceNumber()) { + node->RemoveChildren(); + navigation_params_.reset(); + } + node->set_item(item); } break; diff --git a/chromium/content/renderer/history_controller.h b/chromium/content/renderer/history_controller.h index ff205967014..ac522418889 100644 --- a/chromium/content/renderer/history_controller.h +++ b/chromium/content/renderer/history_controller.h @@ -153,11 +153,15 @@ class CONTENT_EXPORT HistoryController { // A HistoryEntry representing the page that is being loaded, or an empty // scoped_ptr if no page is being loaded. std::unique_ptr<HistoryEntry> provisional_entry_; - // The NavigationParams corresponding to the last load that was initiated by - // |GoToEntry|. This is kept around so that it can be passed into existing - // frames modified during a history navigation in GoToEntry(), and can be + + // The NavigationParams corresponding to the last back/forward load that was + // initiated by |GoToEntry|. This is kept around so that it can be passed into + // existing frames affected by a history navigation in GoToEntry(), and can be // passed into frames created after the commit that resulted from the // navigation in GetItemForNewChildFrame(). + // + // This is reset in UpdateForCommit if we see a commit from a different + // navigation, to avoid using stale parameters. std::unique_ptr<NavigationParams> navigation_params_; DISALLOW_COPY_AND_ASSIGN(HistoryController); diff --git a/chromium/content/renderer/history_entry.cc b/chromium/content/renderer/history_entry.cc index edc21f94a08..61bcb3acf9f 100644 --- a/chromium/content/renderer/history_entry.cc +++ b/chromium/content/renderer/history_entry.cc @@ -69,8 +69,10 @@ HistoryEntry::HistoryNode* HistoryEntry::HistoryNode::CloneAndReplace( // the frame. See https://crbug.com/612713#c12. const WebHistoryItem& current_item = current_frame->current_history_item(); if (is_target_frame && clone_children_of_target && !current_item.isNull()) { - new_history_node->item().setDocumentSequenceNumber( - current_item.documentSequenceNumber()); + // TODO(creis): Setting the document sequence number here appears to be + // unnecessary. Remove this block if this DCHECK never fires. + DCHECK_EQ(current_item.documentSequenceNumber(), + new_history_node->item().documentSequenceNumber()); } // TODO(creis): This needs to be updated to handle HistoryEntry in diff --git a/chromium/content/renderer/history_serialization.cc b/chromium/content/renderer/history_serialization.cc index 0a4376c023c..ee5981afa3f 100644 --- a/chromium/content/renderer/history_serialization.cc +++ b/chromium/content/renderer/history_serialization.cc @@ -6,9 +6,12 @@ #include <stddef.h> +#include "base/strings/nullable_string16.h" +#include "content/child/web_url_request_util.h" #include "content/common/page_state_serialization.h" #include "content/public/common/page_state.h" #include "content/renderer/history_entry.h" +#include "third_party/WebKit/public/platform/WebData.h" #include "third_party/WebKit/public/platform/WebFloatPoint.h" #include "third_party/WebKit/public/platform/WebHTTPBody.h" #include "third_party/WebKit/public/platform/WebPoint.h" @@ -17,6 +20,7 @@ #include "third_party/WebKit/public/web/WebHistoryItem.h" #include "third_party/WebKit/public/web/WebSerializedScriptValue.h" +using blink::WebData; using blink::WebHTTPBody; using blink::WebHistoryItem; using blink::WebSerializedScriptValue; @@ -33,56 +37,6 @@ void ToNullableString16Vector(const WebVector<WebString>& input, output->push_back(input[i]); } -void ToExplodedHttpBodyElement(const WebHTTPBody::Element& input, - ExplodedHttpBodyElement* output) { - switch (input.type) { - case WebHTTPBody::Element::TypeData: - output->data.assign(input.data.data(), input.data.size()); - break; - case WebHTTPBody::Element::TypeFile: - output->file_path = input.filePath; - output->file_start = input.fileStart; - output->file_length = input.fileLength; - output->file_modification_time = input.modificationTime; - break; - case WebHTTPBody::Element::TypeFileSystemURL: - output->filesystem_url = input.fileSystemURL; - output->file_start = input.fileStart; - output->file_length = input.fileLength; - output->file_modification_time = input.modificationTime; - break; - case WebHTTPBody::Element::TypeBlob: - output->blob_uuid = input.blobUUID.utf8(); - break; - } -} - -void AppendHTTPBodyElement(const ExplodedHttpBodyElement& element, - WebHTTPBody* http_body) { - switch (element.type) { - case WebHTTPBody::Element::TypeData: - http_body->appendData(element.data); - break; - case WebHTTPBody::Element::TypeFile: - http_body->appendFileRange( - element.file_path, - element.file_start, - element.file_length, - element.file_modification_time); - break; - case WebHTTPBody::Element::TypeFileSystemURL: - http_body->appendFileSystemURLRange( - element.filesystem_url, - element.file_start, - element.file_length, - element.file_modification_time); - break; - case WebHTTPBody::Element::TypeBlob: - http_body->appendBlob(WebString::fromUTF8(element.blob_uuid)); - break; - } -} - void GenerateFrameStateFromItem(const WebHistoryItem& item, ExplodedFrameState* state) { state->url_string = item.urlString(); @@ -102,15 +56,8 @@ void GenerateFrameStateFromItem(const WebHistoryItem& item, state->http_body.http_content_type = item.httpContentType(); const WebHTTPBody& http_body = item.httpBody(); - state->http_body.is_null = http_body.isNull(); - if (!state->http_body.is_null) { - state->http_body.identifier = http_body.identifier(); - state->http_body.elements.resize(http_body.elementCount()); - for (size_t i = 0; i < http_body.elementCount(); ++i) { - WebHTTPBody::Element element; - http_body.elementAt(i, element); - ToExplodedHttpBodyElement(element, &state->http_body.elements[i]); - } + if (!http_body.isNull()) { + state->http_body.request_body = GetRequestBodyForWebHTTPBody(http_body); state->http_body.contains_passwords = http_body.containsPasswordData(); } } @@ -157,13 +104,9 @@ void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state, item.setDocumentSequenceNumber(state.document_sequence_number); item.setHTTPContentType(state.http_body.http_content_type); - if (!state.http_body.is_null) { - WebHTTPBody http_body; - http_body.initialize(); - http_body.setIdentifier(state.http_body.identifier); - for (size_t i = 0; i < state.http_body.elements.size(); ++i) - AppendHTTPBodyElement(state.http_body.elements[i], &http_body); - item.setHTTPBody(http_body); + if (state.http_body.request_body != nullptr) { + item.setHTTPBody( + GetWebHTTPBodyForRequestBody(state.http_body.request_body)); } node->set_item(item); diff --git a/chromium/content/renderer/idle_user_detector.cc b/chromium/content/renderer/idle_user_detector.cc index 9ca35709fbc..a2f2fd0d2b8 100644 --- a/chromium/content/renderer/idle_user_detector.cc +++ b/chromium/content/renderer/idle_user_detector.cc @@ -37,4 +37,8 @@ void IdleUserDetector::OnHandleInputEvent( } } +void IdleUserDetector::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/idle_user_detector.h b/chromium/content/renderer/idle_user_detector.h index cbe85a0f697..8d55af7ddc6 100644 --- a/chromium/content/renderer/idle_user_detector.h +++ b/chromium/content/renderer/idle_user_detector.h @@ -29,6 +29,7 @@ class IdleUserDetector : public RenderViewObserver { private: // RenderViewObserver implementation: bool OnMessageReceived(const IPC::Message& message) override; + void OnDestruct() override; void OnHandleInputEvent(const blink::WebInputEvent* event, const ui::LatencyInfo& latency_info, diff --git a/chromium/content/renderer/image_downloader/image_downloader_impl.cc b/chromium/content/renderer/image_downloader/image_downloader_impl.cc index 0fd476c1ecd..84c13a5f72a 100644 --- a/chromium/content/renderer/image_downloader/image_downloader_impl.cc +++ b/chromium/content/renderer/image_downloader/image_downloader_impl.cc @@ -7,17 +7,16 @@ #include <utility> #include "base/bind.h" +#include "base/location.h" #include "base/logging.h" -#include "base/message_loop/message_loop.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" #include "content/child/image_decoder.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_thread.h" #include "content/renderer/fetchers/multi_resolution_image_resource_fetcher.h" -#include "mojo/common/url_type_converters.h" -#include "mojo/converters/geometry/geometry_type_converters.h" #include "net/base/data_url.h" #include "skia/ext/image_operations.h" -#include "skia/public/type_converters.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "third_party/WebKit/public/platform/WebVector.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -145,13 +144,11 @@ void ImageDownloaderImpl::OnRenderProcessShutdown() { } // ImageDownloader methods: -void ImageDownloaderImpl::DownloadImage(const mojo::String& url, +void ImageDownloaderImpl::DownloadImage(const GURL& image_url, bool is_favicon, uint32_t max_bitmap_size, bool bypass_cache, const DownloadImageCallback& callback) { - const GURL image_url = url.To<GURL>(); - std::vector<SkBitmap> result_images; std::vector<gfx::Size> result_original_image_sizes; @@ -211,7 +208,7 @@ void ImageDownloaderImpl::DidFetchImage( std::find(image_fetchers_.begin(), image_fetchers_.end(), fetcher); if (iter != image_fetchers_.end()) { image_fetchers_.weak_erase(iter); - base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher); + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, fetcher); } } @@ -220,9 +217,12 @@ void ImageDownloaderImpl::ReplyDownloadResult( const std::vector<SkBitmap>& result_images, const std::vector<gfx::Size>& result_original_image_sizes, const DownloadImageCallback& callback) { - callback.Run(http_status_code, - mojo::Array<skia::mojom::BitmapPtr>::From(result_images), - mojo::Array<mojo::SizePtr>::From(result_original_image_sizes)); + callback.Run(http_status_code, mojo::Array<SkBitmap>::From(result_images), + result_original_image_sizes); +} + +void ImageDownloaderImpl::OnDestruct() { + delete this; } } // namespace content diff --git a/chromium/content/renderer/image_downloader/image_downloader_impl.h b/chromium/content/renderer/image_downloader/image_downloader_impl.h index 07ba01516fc..cc4a11aba5c 100644 --- a/chromium/content/renderer/image_downloader/image_downloader_impl.h +++ b/chromium/content/renderer/image_downloader/image_downloader_impl.h @@ -45,8 +45,11 @@ class ImageDownloaderImpl : public content::mojom::ImageDownloader, mojo::InterfaceRequest<content::mojom::ImageDownloader> request); ~ImageDownloaderImpl() override; + // RenderFrameObserver implementation. + void OnDestruct() override; + // ImageDownloader methods: - void DownloadImage(const mojo::String& url, + void DownloadImage(const GURL& url, bool is_favicon, uint32_t max_bitmap_size, bool bypass_cache, diff --git a/chromium/content/renderer/input/input_event_filter.cc b/chromium/content/renderer/input/input_event_filter.cc index 94e5ba2758c..7f7b09fa6c3 100644 --- a/chromium/content/renderer/input/input_event_filter.cc +++ b/chromium/content/renderer/input/input_event_filter.cc @@ -4,6 +4,7 @@ #include "content/renderer/input/input_event_filter.h" +#include <tuple> #include <utility> #include "base/auto_reset.h" @@ -174,9 +175,9 @@ void InputEventFilter::ForwardToHandler(const IPC::Message& message) { InputMsg_HandleInputEvent::Param params; if (!InputMsg_HandleInputEvent::Read(&message, ¶ms)) return; - const WebInputEvent* event = base::get<0>(params); - ui::LatencyInfo latency_info = base::get<1>(params); - InputEventDispatchType dispatch_type = base::get<2>(params); + const WebInputEvent* event = std::get<0>(params); + ui::LatencyInfo latency_info = std::get<1>(params); + InputEventDispatchType dispatch_type = std::get<2>(params); DCHECK(event); DCHECK(dispatch_type == DISPATCH_TYPE_BLOCKING || dispatch_type == DISPATCH_TYPE_NON_BLOCKING); diff --git a/chromium/content/renderer/input/input_event_filter_unittest.cc b/chromium/content/renderer/input/input_event_filter_unittest.cc index 9692720a81b..39547e27514 100644 --- a/chromium/content/renderer/input/input_event_filter_unittest.cc +++ b/chromium/content/renderer/input/input_event_filter_unittest.cc @@ -5,11 +5,13 @@ #include <stddef.h> #include <new> +#include <tuple> #include <utility> #include <vector> #include "base/bind.h" #include "base/macros.h" +#include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "content/common/input/synthetic_web_input_event_builders.h" @@ -114,7 +116,7 @@ void AddMessagesToFilter(IPC::MessageFilter* message_filter, for (size_t i = 0; i < events.size(); ++i) message_filter->OnMessageReceived(events[i]); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } template <typename T> @@ -191,8 +193,8 @@ TEST_F(InputEventFilterTest, Basic) { InputHostMsg_HandleInputEvent_ACK::Param params; EXPECT_TRUE(InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms)); - WebInputEvent::Type event_type = base::get<0>(params).type; - InputEventAckState ack_result = base::get<0>(params).state; + WebInputEvent::Type event_type = std::get<0>(params).type; + InputEventAckState ack_result = std::get<0>(params).state; EXPECT_EQ(kEvents[i].type, event_type); EXPECT_EQ(ack_result, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); @@ -217,7 +219,7 @@ TEST_F(InputEventFilterTest, Basic) { ASSERT_EQ(InputMsg_HandleInputEvent::ID, message.type()); InputMsg_HandleInputEvent::Param params; EXPECT_TRUE(InputMsg_HandleInputEvent::Read(&message, ¶ms)); - const WebInputEvent* event = base::get<0>(params); + const WebInputEvent* event = std::get<0>(params); EXPECT_EQ(kEvents[i].size, event->size); EXPECT_TRUE(memcmp(&kEvents[i], event, event->size) == 0); @@ -243,8 +245,8 @@ TEST_F(InputEventFilterTest, Basic) { InputHostMsg_HandleInputEvent_ACK::Param params; EXPECT_TRUE(InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms)); - WebInputEvent::Type event_type = base::get<0>(params).type; - InputEventAckState ack_result = base::get<0>(params).state; + WebInputEvent::Type event_type = std::get<0>(params).type; + InputEventAckState ack_result = std::get<0>(params).state; EXPECT_EQ(kEvents[i].type, event_type); EXPECT_EQ(ack_result, INPUT_EVENT_ACK_STATE_CONSUMED); } @@ -330,7 +332,7 @@ TEST_F(InputEventFilterTest, NonBlockingWheel) { // Second event was queued; ack the first. filter_->NotifyInputEventHandled(kTestRoutingID, WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); ASSERT_EQ(4u, ipc_sink_.message_count()); EXPECT_EQ(2u, message_recorder_.message_count()); @@ -338,13 +340,13 @@ TEST_F(InputEventFilterTest, NonBlockingWheel) { // different. filter_->NotifyInputEventHandled(kTestRoutingID, WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(3u, message_recorder_.message_count()); // The last events will be coalesced. filter_->NotifyInputEventHandled(kTestRoutingID, WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(3u, message_recorder_.message_count()); // First two messages should be identical. @@ -354,8 +356,8 @@ TEST_F(InputEventFilterTest, NonBlockingWheel) { ASSERT_EQ(InputMsg_HandleInputEvent::ID, message.type()); InputMsg_HandleInputEvent::Param params; EXPECT_TRUE(InputMsg_HandleInputEvent::Read(&message, ¶ms)); - const WebInputEvent* event = base::get<0>(params); - InputEventDispatchType dispatch_type = base::get<2>(params); + const WebInputEvent* event = std::get<0>(params); + InputEventDispatchType dispatch_type = std::get<2>(params); EXPECT_EQ(kEvents[i].size, event->size); kEvents[i].dispatchType = @@ -373,8 +375,8 @@ TEST_F(InputEventFilterTest, NonBlockingWheel) { InputMsg_HandleInputEvent::Param params; EXPECT_TRUE(InputMsg_HandleInputEvent::Read(&message, ¶ms)); const WebMouseWheelEvent* event = - static_cast<const WebMouseWheelEvent*>(base::get<0>(params)); - InputEventDispatchType dispatch_type = base::get<2>(params); + static_cast<const WebMouseWheelEvent*>(std::get<0>(params)); + InputEventDispatchType dispatch_type = std::get<2>(params); kEvents[2].dispatchType = WebInputEvent::DispatchType::ListenersNonBlockingPassive; @@ -411,7 +413,7 @@ TEST_F(InputEventFilterTest, NonBlockingTouch) { // Second event was queued; ack the first. filter_->NotifyInputEventHandled(kTestRoutingID, WebInputEvent::TouchStart, INPUT_EVENT_ACK_STATE_CONSUMED); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); ASSERT_EQ(4u, ipc_sink_.message_count()); EXPECT_EQ(2u, message_recorder_.message_count()); @@ -419,13 +421,13 @@ TEST_F(InputEventFilterTest, NonBlockingTouch) { // different. filter_->NotifyInputEventHandled(kTestRoutingID, WebInputEvent::TouchMove, INPUT_EVENT_ACK_STATE_CONSUMED); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(3u, message_recorder_.message_count()); // The last events will be coalesced. filter_->NotifyInputEventHandled(kTestRoutingID, WebInputEvent::TouchMove, INPUT_EVENT_ACK_STATE_CONSUMED); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(3u, message_recorder_.message_count()); // First two messages should be identical. @@ -435,8 +437,8 @@ TEST_F(InputEventFilterTest, NonBlockingTouch) { ASSERT_EQ(InputMsg_HandleInputEvent::ID, message.type()); InputMsg_HandleInputEvent::Param params; EXPECT_TRUE(InputMsg_HandleInputEvent::Read(&message, ¶ms)); - const WebInputEvent* event = base::get<0>(params); - InputEventDispatchType dispatch_type = base::get<2>(params); + const WebInputEvent* event = std::get<0>(params); + InputEventDispatchType dispatch_type = std::get<2>(params); EXPECT_EQ(kEvents[i].size, event->size); kEvents[i].dispatchType = @@ -454,8 +456,8 @@ TEST_F(InputEventFilterTest, NonBlockingTouch) { InputMsg_HandleInputEvent::Param params; EXPECT_TRUE(InputMsg_HandleInputEvent::Read(&message, ¶ms)); const WebTouchEvent* event = - static_cast<const WebTouchEvent*>(base::get<0>(params)); - InputEventDispatchType dispatch_type = base::get<2>(params); + static_cast<const WebTouchEvent*>(std::get<0>(params)); + InputEventDispatchType dispatch_type = std::get<2>(params); EXPECT_EQ(kEvents[3].size, event->size); EXPECT_EQ(1u, kEvents[3].touchesLength); @@ -494,8 +496,8 @@ TEST_F(InputEventFilterTest, IntermingledNonBlockingTouch) { ASSERT_EQ(InputMsg_HandleInputEvent::ID, message.type()); InputMsg_HandleInputEvent::Param params; EXPECT_TRUE(InputMsg_HandleInputEvent::Read(&message, ¶ms)); - const WebInputEvent* event = base::get<0>(params); - InputEventDispatchType dispatch_type = base::get<2>(params); + const WebInputEvent* event = std::get<0>(params); + InputEventDispatchType dispatch_type = std::get<2>(params); EXPECT_EQ(kEvents[0].size, event->size); kEvents[0].dispatchType = @@ -509,15 +511,15 @@ TEST_F(InputEventFilterTest, IntermingledNonBlockingTouch) { // Second event was queued; ack the first. filter_->NotifyInputEventHandled(kTestRoutingID, WebInputEvent::TouchStart, INPUT_EVENT_ACK_STATE_CONSUMED); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(2u, message_recorder_.message_count()); const IPC::Message& message = message_recorder_.message_at(1); ASSERT_EQ(InputMsg_HandleInputEvent::ID, message.type()); InputMsg_HandleInputEvent::Param params; EXPECT_TRUE(InputMsg_HandleInputEvent::Read(&message, ¶ms)); - const WebInputEvent* event = base::get<0>(params); - InputEventDispatchType dispatch_type = base::get<2>(params); + const WebInputEvent* event = std::get<0>(params); + InputEventDispatchType dispatch_type = std::get<2>(params); EXPECT_EQ(kEvents[1].size, event->size); kEvents[1].dispatchType = @@ -531,15 +533,15 @@ TEST_F(InputEventFilterTest, IntermingledNonBlockingTouch) { // Third event should be put in the queue. filter_->NotifyInputEventHandled(kTestRoutingID, WebInputEvent::TouchEnd, INPUT_EVENT_ACK_STATE_CONSUMED); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(3u, message_recorder_.message_count()); const IPC::Message& message = message_recorder_.message_at(2); ASSERT_EQ(InputMsg_HandleInputEvent::ID, message.type()); InputMsg_HandleInputEvent::Param params; EXPECT_TRUE(InputMsg_HandleInputEvent::Read(&message, ¶ms)); - const WebInputEvent* event = base::get<0>(params); - InputEventDispatchType dispatch_type = base::get<2>(params); + const WebInputEvent* event = std::get<0>(params); + InputEventDispatchType dispatch_type = std::get<2>(params); EXPECT_EQ(kBlockingEvents[0].size, event->size); EXPECT_TRUE(memcmp(&kBlockingEvents[0], event, event->size) == 0); diff --git a/chromium/content/renderer/input/input_handler_manager.cc b/chromium/content/renderer/input/input_handler_manager.cc index 2e28534089f..0821d8225fc 100644 --- a/chromium/content/renderer/input/input_handler_manager.cc +++ b/chromium/content/renderer/input/input_handler_manager.cc @@ -67,20 +67,18 @@ void InputHandlerManager::AddInputHandler( int routing_id, const base::WeakPtr<cc::InputHandler>& input_handler, const base::WeakPtr<RenderViewImpl>& render_view_impl, - bool enable_smooth_scrolling, - bool enable_wheel_gestures) { + bool enable_smooth_scrolling) { if (task_runner_->BelongsToCurrentThread()) { AddInputHandlerOnCompositorThread( routing_id, base::ThreadTaskRunnerHandle::Get(), input_handler, - render_view_impl, enable_smooth_scrolling, enable_wheel_gestures); + render_view_impl, enable_smooth_scrolling); } else { task_runner_->PostTask( FROM_HERE, base::Bind(&InputHandlerManager::AddInputHandlerOnCompositorThread, base::Unretained(this), routing_id, base::ThreadTaskRunnerHandle::Get(), input_handler, - render_view_impl, enable_smooth_scrolling, - enable_wheel_gestures)); + render_view_impl, enable_smooth_scrolling)); } } @@ -89,8 +87,7 @@ void InputHandlerManager::AddInputHandlerOnCompositorThread( const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, const base::WeakPtr<cc::InputHandler>& input_handler, const base::WeakPtr<RenderViewImpl>& render_view_impl, - bool enable_smooth_scrolling, - bool enable_wheel_gestures) { + bool enable_smooth_scrolling) { DCHECK(task_runner_->BelongsToCurrentThread()); // The handler could be gone by this point if the compositor has shut down. @@ -104,9 +101,9 @@ void InputHandlerManager::AddInputHandlerOnCompositorThread( TRACE_EVENT1("input", "InputHandlerManager::AddInputHandlerOnCompositorThread", "result", "AddingRoute"); - std::unique_ptr<InputHandlerWrapper> wrapper(new InputHandlerWrapper( - this, routing_id, main_task_runner, input_handler, render_view_impl, - enable_smooth_scrolling, enable_wheel_gestures)); + std::unique_ptr<InputHandlerWrapper> wrapper( + new InputHandlerWrapper(this, routing_id, main_task_runner, input_handler, + render_view_impl, enable_smooth_scrolling)); client_->RegisterRoutingID(routing_id); if (synchronous_handler_proxy_client_) { synchronous_handler_proxy_client_->DidAddSynchronousHandlerProxy( @@ -162,32 +159,6 @@ void InputHandlerManager::UnregisterRoutingIDOnCompositorThread( client_->UnregisterRoutingID(routing_id); } -void InputHandlerManager::ObserveWheelEventAndResultOnMainThread( - int routing_id, - const blink::WebMouseWheelEvent& wheel_event, - const cc::InputHandlerScrollResult& scroll_result) { - task_runner_->PostTask( - FROM_HERE, - base::Bind( - &InputHandlerManager::ObserveWheelEventAndResultOnCompositorThread, - base::Unretained(this), routing_id, wheel_event, scroll_result)); -} - -void InputHandlerManager::ObserveWheelEventAndResultOnCompositorThread( - int routing_id, - const blink::WebMouseWheelEvent& wheel_event, - const cc::InputHandlerScrollResult& scroll_result) { - DCHECK(task_runner_->BelongsToCurrentThread()); - auto it = input_handlers_.find(routing_id); - if (it == input_handlers_.end()) - return; - - InputHandlerProxy* proxy = it->second->input_handler_proxy(); - DCHECK(proxy->scroll_elasticity_controller()); - proxy->scroll_elasticity_controller()->ObserveWheelEventAndResult( - wheel_event, scroll_result); -} - void InputHandlerManager::ObserveGestureEventAndResultOnMainThread( int routing_id, const blink::WebGestureEvent& gesture_event, diff --git a/chromium/content/renderer/input/input_handler_manager.h b/chromium/content/renderer/input/input_handler_manager.h index bb3ef894820..1935a2e04a3 100644 --- a/chromium/content/renderer/input/input_handler_manager.h +++ b/chromium/content/renderer/input/input_handler_manager.h @@ -56,17 +56,11 @@ class CONTENT_EXPORT InputHandlerManager { void AddInputHandler(int routing_id, const base::WeakPtr<cc::InputHandler>& input_handler, const base::WeakPtr<RenderViewImpl>& render_view_impl, - bool enable_smooth_scrolling, - bool enable_wheel_gestures); + bool enable_smooth_scrolling); void RegisterRoutingID(int routing_id); void UnregisterRoutingID(int routing_id); - void ObserveWheelEventAndResultOnMainThread( - int routing_id, - const blink::WebMouseWheelEvent& wheel_event, - const cc::InputHandlerScrollResult& scroll_result); - void ObserveGestureEventAndResultOnMainThread( int routing_id, const blink::WebGestureEvent& gesture_event, @@ -102,8 +96,7 @@ class CONTENT_EXPORT InputHandlerManager { const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, const base::WeakPtr<cc::InputHandler>& input_handler, const base::WeakPtr<RenderViewImpl>& render_view_impl, - bool enable_smooth_scrolling, - bool enable_wheel_gestures); + bool enable_smooth_scrolling); void RegisterRoutingIDOnCompositorThread(int routing_id); void UnregisterRoutingIDOnCompositorThread(int routing_id); diff --git a/chromium/content/renderer/input/input_handler_wrapper.cc b/chromium/content/renderer/input/input_handler_wrapper.cc index 7678f9337c1..77416f37212 100644 --- a/chromium/content/renderer/input/input_handler_wrapper.cc +++ b/chromium/content/renderer/input/input_handler_wrapper.cc @@ -20,8 +20,7 @@ InputHandlerWrapper::InputHandlerWrapper( const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, const base::WeakPtr<cc::InputHandler>& input_handler, const base::WeakPtr<RenderViewImpl>& render_view_impl, - bool enable_smooth_scrolling, - bool enable_wheel_gestures) + bool enable_smooth_scrolling) : input_handler_manager_(input_handler_manager), routing_id_(routing_id), input_handler_proxy_(input_handler.get(), this), @@ -29,8 +28,6 @@ InputHandlerWrapper::InputHandlerWrapper( render_view_impl_(render_view_impl) { DCHECK(input_handler); input_handler_proxy_.set_smooth_scroll_enabled(enable_smooth_scrolling); - input_handler_proxy_.set_use_gesture_events_for_mouse_wheel( - enable_wheel_gestures); } InputHandlerWrapper::~InputHandlerWrapper() { diff --git a/chromium/content/renderer/input/input_handler_wrapper.h b/chromium/content/renderer/input/input_handler_wrapper.h index 35c96e97dfb..5a9248ed74e 100644 --- a/chromium/content/renderer/input/input_handler_wrapper.h +++ b/chromium/content/renderer/input/input_handler_wrapper.h @@ -28,8 +28,7 @@ class InputHandlerWrapper : public ui::InputHandlerProxyClient { const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, const base::WeakPtr<cc::InputHandler>& input_handler, const base::WeakPtr<RenderViewImpl>& render_view_impl, - bool enable_smooth_scrolling, - bool enable_wheel_gestures); + bool enable_smooth_scrolling); ~InputHandlerWrapper() override; int routing_id() const { return routing_id_; } diff --git a/chromium/content/renderer/input/render_widget_input_handler.cc b/chromium/content/renderer/input/render_widget_input_handler.cc index 25bd40139ca..878f087f78c 100644 --- a/chromium/content/renderer/input/render_widget_input_handler.cc +++ b/chromium/content/renderer/input/render_widget_input_handler.cc @@ -387,21 +387,11 @@ void RenderWidgetInputHandler::HandleInputEvent( } } - // Send mouse wheel events and their disposition to the compositor thread, so - // that they can be used to produce the elastic overscroll effect on Mac. - if (input_event.type == WebInputEvent::MouseWheel) { - const WebMouseWheelEvent& wheel_event = - static_cast<const WebMouseWheelEvent&>(input_event); - if (wheel_event.canScroll) { - delegate_->ObserveWheelEventAndResult( - wheel_event, - event_overscroll ? event_overscroll->latest_overscroll_delta - : gfx::Vector2dF(), - processed != WebInputEventResult::NotHandled); - } - } else if (input_event.type == WebInputEvent::GestureScrollBegin || - input_event.type == WebInputEvent::GestureScrollEnd || - input_event.type == WebInputEvent::GestureScrollUpdate) { + // Send gesture scroll events and their dispositions to the compositor thread, + // so that they can be used to produce the elastic overscroll effect on Mac. + if (input_event.type == WebInputEvent::GestureScrollBegin || + input_event.type == WebInputEvent::GestureScrollEnd || + input_event.type == WebInputEvent::GestureScrollUpdate) { const WebGestureEvent& gesture_event = static_cast<const WebGestureEvent&>(input_event); if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad) { diff --git a/chromium/content/renderer/input/render_widget_input_handler_delegate.h b/chromium/content/renderer/input/render_widget_input_handler_delegate.h index 55465fd5787..bbb58d006be 100644 --- a/chromium/content/renderer/input/render_widget_input_handler_delegate.h +++ b/chromium/content/renderer/input/render_widget_input_handler_delegate.h @@ -43,13 +43,6 @@ class CONTENT_EXPORT RenderWidgetInputHandlerDelegate { // at the given point. virtual bool HasTouchEventHandlersAt(const gfx::Point& point) const = 0; - // Called to forward a mouse wheel event to the compositor thread, to effect - // the elastic overscroll effect. - virtual void ObserveWheelEventAndResult( - const blink::WebMouseWheelEvent& wheel_event, - const gfx::Vector2dF& wheel_unused_delta, - bool event_processed) = 0; - // Called to forward a gesture event to the compositor thread, to effect // the elastic overscroll effect. virtual void ObserveGestureEventAndResult( diff --git a/chromium/content/renderer/java/gin_java_bridge_dispatcher.cc b/chromium/content/renderer/java/gin_java_bridge_dispatcher.cc index 0d6d07350d1..a7a9a449887 100644 --- a/chromium/content/renderer/java/gin_java_bridge_dispatcher.cc +++ b/chromium/content/renderer/java/gin_java_bridge_dispatcher.cc @@ -133,4 +133,8 @@ void GinJavaBridgeDispatcher::OnGinJavaBridgeObjectDeleted( new GinJavaBridgeHostMsg_ObjectWrapperDeleted(routing_id(), object_id)); } +void GinJavaBridgeDispatcher::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/java/gin_java_bridge_dispatcher.h b/chromium/content/renderer/java/gin_java_bridge_dispatcher.h index f795c288f78..297da75247d 100644 --- a/chromium/content/renderer/java/gin_java_bridge_dispatcher.h +++ b/chromium/content/renderer/java/gin_java_bridge_dispatcher.h @@ -59,6 +59,9 @@ class GinJavaBridgeDispatcher void OnGinJavaBridgeObjectDeleted(GinJavaBridgeObject* object); private: + // RenderFrameObserver implementation. + void OnDestruct() override; + void OnAddNamedObject(const std::string& name, ObjectID object_id); void OnRemoveNamedObject(const std::string& name); diff --git a/chromium/content/renderer/java/gin_java_bridge_value_converter.cc b/chromium/content/renderer/java/gin_java_bridge_value_converter.cc index 527b541c5b3..309d77d43d8 100644 --- a/chromium/content/renderer/java/gin_java_bridge_value_converter.cc +++ b/chromium/content/renderer/java/gin_java_bridge_value_converter.cc @@ -38,20 +38,19 @@ v8::Local<v8::Value> GinJavaBridgeValueConverter::ToV8Value( std::unique_ptr<base::Value> GinJavaBridgeValueConverter::FromV8Value( v8::Local<v8::Value> value, v8::Local<v8::Context> context) const { - return base::WrapUnique(converter_->FromV8Value(value, context)); + return converter_->FromV8Value(value, context); } bool GinJavaBridgeValueConverter::FromV8Object( v8::Local<v8::Object> value, - base::Value** out, + std::unique_ptr<base::Value>* out, v8::Isolate* isolate, const FromV8ValueCallback& callback) const { GinJavaBridgeObject* unwrapped; if (!gin::ConvertFromV8(isolate, value, &unwrapped)) { return false; } - *out = - GinJavaBridgeValue::CreateObjectIDValue(unwrapped->object_id()).release(); + *out = GinJavaBridgeValue::CreateObjectIDValue(unwrapped->object_id()); return true; } @@ -124,10 +123,10 @@ std::unique_ptr<TypedArraySerializer> TypedArraySerializer::Create( bool GinJavaBridgeValueConverter::FromV8ArrayBuffer( v8::Local<v8::Object> value, - base::Value** out, + std::unique_ptr<base::Value>* out, v8::Isolate* isolate) const { if (!value->IsTypedArray()) { - *out = GinJavaBridgeValue::CreateUndefinedValue().release(); + *out = GinJavaBridgeValue::CreateUndefinedValue(); return true; } @@ -139,29 +138,31 @@ bool GinJavaBridgeValueConverter::FromV8ArrayBuffer( data_length = view.num_bytes(); } if (!data) { - *out = GinJavaBridgeValue::CreateUndefinedValue().release(); + *out = GinJavaBridgeValue::CreateUndefinedValue(); return true; } - base::ListValue* result = new base::ListValue(); - *out = result; + std::unique_ptr<base::ListValue> result(new base::ListValue); std::unique_ptr<TypedArraySerializer> serializer( TypedArraySerializer::Create(value.As<v8::TypedArray>())); - serializer->serializeTo(data, data_length, result); + serializer->serializeTo(data, data_length, result.get()); + *out = std::move(result); return true; } -bool GinJavaBridgeValueConverter::FromV8Number(v8::Local<v8::Number> value, - base::Value** out) const { +bool GinJavaBridgeValueConverter::FromV8Number( + v8::Local<v8::Number> value, + std::unique_ptr<base::Value>* out) const { double double_value = value->Value(); if (std::isfinite(double_value)) return false; - *out = GinJavaBridgeValue::CreateNonFiniteValue(double_value).release(); + *out = GinJavaBridgeValue::CreateNonFiniteValue(double_value); return true; } -bool GinJavaBridgeValueConverter::FromV8Undefined(base::Value** out) const { - *out = GinJavaBridgeValue::CreateUndefinedValue().release(); +bool GinJavaBridgeValueConverter::FromV8Undefined( + std::unique_ptr<base::Value>* out) const { + *out = GinJavaBridgeValue::CreateUndefinedValue(); return true; } diff --git a/chromium/content/renderer/java/gin_java_bridge_value_converter.h b/chromium/content/renderer/java/gin_java_bridge_value_converter.h index 2e48f199db3..9ab3849a3f5 100644 --- a/chromium/content/renderer/java/gin_java_bridge_value_converter.h +++ b/chromium/content/renderer/java/gin_java_bridge_value_converter.h @@ -27,15 +27,15 @@ class GinJavaBridgeValueConverter : public content::V8ValueConverter::Strategy { // content::V8ValueConverter::Strategy bool FromV8Object(v8::Local<v8::Object> value, - base::Value** out, + std::unique_ptr<base::Value>* out, v8::Isolate* isolate, const FromV8ValueCallback& callback) const override; bool FromV8ArrayBuffer(v8::Local<v8::Object> value, - base::Value** out, + std::unique_ptr<base::Value>* out, v8::Isolate* isolate) const override; bool FromV8Number(v8::Local<v8::Number> value, - base::Value** out) const override; - bool FromV8Undefined(base::Value** out) const override; + std::unique_ptr<base::Value>* out) const override; + bool FromV8Undefined(std::unique_ptr<base::Value>* out) const override; private: std::unique_ptr<V8ValueConverter> converter_; diff --git a/chromium/content/renderer/layout_test_dependencies.h b/chromium/content/renderer/layout_test_dependencies.h new file mode 100644 index 00000000000..743c61d2c7a --- /dev/null +++ b/chromium/content/renderer/layout_test_dependencies.h @@ -0,0 +1,38 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDER_LAYOUT_TEST_DEPENDENCIES_H_ +#define CONTENT_RENDER_LAYOUT_TEST_DEPENDENCIES_H_ + +#include <stdint.h> +#include <memory> + +#include "base/memory/ref_counted.h" + +namespace cc { +class ContextProvider; +class OutputSurface; +} + +namespace gpu { +class GpuChannelHost; +} + +namespace content { +class CompositorDependencies; + +// This class allows injection of LayoutTest-specific behaviour to the +// RenderThreadImpl. +class LayoutTestDependencies { + public: + virtual std::unique_ptr<cc::OutputSurface> CreateOutputSurface( + scoped_refptr<gpu::GpuChannelHost> gpu_channel, + scoped_refptr<cc::ContextProvider> compositor_context_provider, + scoped_refptr<cc::ContextProvider> worker_context_provider, + CompositorDependencies* deps) = 0; +}; + +} // namespace content + +#endif // CONTENT_RENDER_LAYOUT_TEST_DEPENDENCIES_H_ diff --git a/chromium/content/renderer/manifest/manifest_manager.cc b/chromium/content/renderer/manifest/manifest_manager.cc index 1f9d4ed9bbc..69a75de2500 100644 --- a/chromium/content/renderer/manifest/manifest_manager.cc +++ b/chromium/content/renderer/manifest/manifest_manager.cc @@ -206,4 +206,8 @@ void ManifestManager::ResolveCallbacks(ResolveState state) { } } +void ManifestManager::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/manifest/manifest_manager.h b/chromium/content/renderer/manifest/manifest_manager.h index 6ed61226ef3..554617cdcbe 100644 --- a/chromium/content/renderer/manifest/manifest_manager.h +++ b/chromium/content/renderer/manifest/manifest_manager.h @@ -54,6 +54,9 @@ class ManifestManager : public RenderFrameObserver { ResolveStateFailure }; + // RenderFrameObserver implementation. + void OnDestruct() override; + // Called when receiving a ManifestManagerMsg_RequestManifest from the browser // process. void OnHasManifest(int request_id); diff --git a/chromium/content/renderer/manifest/manifest_parser.cc b/chromium/content/renderer/manifest/manifest_parser.cc index 1222a556c48..23dca88bb9b 100644 --- a/chromium/content/renderer/manifest/manifest_parser.cc +++ b/chromium/content/renderer/manifest/manifest_parser.cc @@ -17,76 +17,14 @@ #include "content/public/common/manifest.h" #include "content/renderer/manifest/manifest_uma_util.h" #include "third_party/WebKit/public/platform/WebColor.h" +#include "third_party/WebKit/public/platform/WebIconSizesParser.h" +#include "third_party/WebKit/public/platform/WebSize.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/web/WebCSSParser.h" #include "ui/gfx/geometry/size.h" namespace content { -namespace { - -// Helper function that returns whether the given |str| is a valid width or -// height value for an icon sizes per: -// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes -bool IsValidIconWidthOrHeight(const std::string& str) { - if (str.empty() || str[0] == '0') - return false; - for (size_t i = 0; i < str.size(); ++i) - if (!base::IsAsciiDigit(str[i])) - return false; - return true; -} - -// Parses the 'sizes' attribute of an icon as described in the HTML spec: -// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes -// Return a vector of gfx::Size that contains the valid sizes found. "Any" is -// represented by gfx::Size(0, 0). -// TODO(mlamouri): this is implemented as a separate function because it should -// be refactored with the other icon sizes parsing implementations, see -// http://crbug.com/416477 -std::vector<gfx::Size> ParseIconSizesHTML(const base::string16& sizes_str16) { - if (!base::IsStringASCII(sizes_str16)) - return std::vector<gfx::Size>(); - - std::vector<gfx::Size> sizes; - std::string sizes_str = - base::ToLowerASCII(base::UTF16ToUTF8(sizes_str16)); - std::vector<std::string> sizes_str_list = base::SplitString( - sizes_str, base::kWhitespaceASCII, base::KEEP_WHITESPACE, - base::SPLIT_WANT_NONEMPTY); - - for (size_t i = 0; i < sizes_str_list.size(); ++i) { - std::string& size_str = sizes_str_list[i]; - if (size_str == "any") { - sizes.push_back(gfx::Size(0, 0)); - continue; - } - - // It is expected that [0] => width and [1] => height after the split. - std::vector<std::string> size_list = base::SplitString( - size_str, "x", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); - if (size_list.size() != 2) - continue; - if (!IsValidIconWidthOrHeight(size_list[0]) || - !IsValidIconWidthOrHeight(size_list[1])) { - continue; - } - - int width, height; - if (!base::StringToInt(size_list[0], &width) || - !base::StringToInt(size_list[1], &height)) { - continue; - } - - sizes.push_back(gfx::Size(width, height)); - } - - return sizes; -} - -} // anonymous namespace - - ManifestParser::ManifestParser(const base::StringPiece& data, const GURL& manifest_url, const GURL& document_url) @@ -126,6 +64,7 @@ void ManifestParser::Parse() { manifest_.name = ParseName(*dictionary); manifest_.short_name = ParseShortName(*dictionary); manifest_.start_url = ParseStartURL(*dictionary); + manifest_.scope = ParseScope(*dictionary, manifest_.start_url); manifest_.display = ParseDisplay(*dictionary); manifest_.orientation = ParseOrientation(*dictionary); manifest_.icons = ParseIcons(*dictionary); @@ -218,7 +157,10 @@ GURL ManifestParser::ParseURL(const base::DictionaryValue& dictionary, if (url_str.is_null()) return GURL(); - return base_url.Resolve(url_str.string()); + GURL resolved = base_url.Resolve(url_str.string()); + if (!resolved.is_valid()) + AddErrorInfo("property '" + key + "' ignored, URL is invalid."); + return resolved; } base::NullableString16 ManifestParser::ParseName( @@ -245,6 +187,34 @@ GURL ManifestParser::ParseStartURL(const base::DictionaryValue& dictionary) { return start_url; } +GURL ManifestParser::ParseScope(const base::DictionaryValue& dictionary, + const GURL& start_url) { + GURL scope = ParseURL(dictionary, "scope", manifest_url_); + if (!scope.is_valid()) { + return GURL(); + } + + if (scope.GetOrigin() != document_url_.GetOrigin()) { + AddErrorInfo("property 'scope' ignored, should be " + "same origin as document."); + return GURL(); + } + + // According to the spec, if the start_url cannot be parsed, the document URL + // should be used as the start URL. If the start_url could not be parsed, + // check that the document URL is within scope. + GURL check_in_scope = start_url.is_empty() ? document_url_ : start_url; + if (check_in_scope.GetOrigin() != scope.GetOrigin() || + !base::StartsWith(check_in_scope.path(), scope.path(), + base::CompareCase::SENSITIVE)) { + AddErrorInfo( + "property 'scope' ignored. Start url should be within scope " + "of scope URL."); + return GURL(); + } + return scope; +} + blink::WebDisplayMode ManifestParser::ParseDisplay( const base::DictionaryValue& dictionary) { base::NullableString16 display = ParseString(dictionary, "display", Trim); @@ -311,11 +281,16 @@ base::NullableString16 ManifestParser::ParseIconType( std::vector<gfx::Size> ManifestParser::ParseIconSizes( const base::DictionaryValue& icon) { base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim); + std::vector<gfx::Size> sizes; if (sizes_str.is_null()) - return std::vector<gfx::Size>(); + return sizes; - std::vector<gfx::Size> sizes = ParseIconSizesHTML(sizes_str.string()); + blink::WebVector<blink::WebSize> web_sizes = + blink::WebIconSizesParser::parseIconSizes(sizes_str.string()); + sizes.resize(web_sizes.size()); + for (size_t i = 0; i < web_sizes.size(); ++i) + sizes[i] = web_sizes[i]; if (sizes.empty()) { AddErrorInfo("found icon with no valid size."); } diff --git a/chromium/content/renderer/manifest/manifest_parser.h b/chromium/content/renderer/manifest/manifest_parser.h index 0f12c5a4745..2c8d2076e33 100644 --- a/chromium/content/renderer/manifest/manifest_parser.h +++ b/chromium/content/renderer/manifest/manifest_parser.h @@ -90,6 +90,12 @@ class CONTENT_EXPORT ManifestParser { base::NullableString16 ParseShortName( const base::DictionaryValue& dictionary); + // Parses the 'scope' field of the manifest, as defined in: + // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-scope-member + // Returns the parsed GURL if any, an empty GURL if the parsing failed. + GURL ParseScope(const base::DictionaryValue& dictionary, + const GURL& start_url); + // Parses the 'start_url' field of the manifest, as defined in: // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-start_url-member // Returns the parsed GURL if any, an empty GURL if the parsing failed. diff --git a/chromium/content/renderer/manifest/manifest_parser_unittest.cc b/chromium/content/renderer/manifest/manifest_parser_unittest.cc index b86a0e7e6ca..4311531436d 100644 --- a/chromium/content/renderer/manifest/manifest_parser_unittest.cc +++ b/chromium/content/renderer/manifest/manifest_parser_unittest.cc @@ -29,9 +29,9 @@ class ManifestParserTest : public testing::Test { ~ManifestParserTest() override {} Manifest ParseManifestWithURLs(const base::StringPiece& data, - const GURL& document_url, - const GURL& manifest_url) { - ManifestParser parser(data, document_url, manifest_url); + const GURL& manifest_url, + const GURL& document_url) { + ManifestParser parser(data, manifest_url, document_url); parser.Parse(); std::vector<ManifestDebugInfo::Error> errors; parser.TakeErrors(&errors); @@ -44,7 +44,7 @@ class ManifestParserTest : public testing::Test { Manifest ParseManifest(const base::StringPiece& data) { return ParseManifestWithURLs( - data, default_document_url, default_manifest_url); + data, default_manifest_url, default_document_url); } const std::vector<std::string>& errors() const { @@ -101,6 +101,7 @@ TEST_F(ManifestParserTest, EmptyStringNull) { ASSERT_EQ(manifest.theme_color, Manifest::kInvalidOrMissingColor); ASSERT_EQ(manifest.background_color, Manifest::kInvalidOrMissingColor); ASSERT_TRUE(manifest.gcm_sender_id.is_null()); + ASSERT_TRUE(manifest.scope.is_empty()); } TEST_F(ManifestParserTest, ValidNoContentParses) { @@ -119,6 +120,7 @@ TEST_F(ManifestParserTest, ValidNoContentParses) { ASSERT_EQ(manifest.theme_color, Manifest::kInvalidOrMissingColor); ASSERT_EQ(manifest.background_color, Manifest::kInvalidOrMissingColor); ASSERT_TRUE(manifest.gcm_sender_id.is_null()); + ASSERT_TRUE(manifest.scope.is_empty()); } TEST_F(ManifestParserTest, MultipleErrorsReporting) { @@ -253,6 +255,14 @@ TEST_F(ManifestParserTest, StartURLParseRules) { errors()[0]); } + // Don't parse if property isn't a valid URL. + { + Manifest manifest = ParseManifest("{ \"start_url\": \"http://www.google.ca:a\" }"); + ASSERT_TRUE(manifest.start_url.is_empty()); + EXPECT_EQ(1u, GetErrorCount()); + EXPECT_EQ("property 'start_url' ignored, URL is invalid.", errors()[0]); + } + // Absolute start_url, same origin with document. { Manifest manifest = @@ -287,6 +297,151 @@ TEST_F(ManifestParserTest, StartURLParseRules) { } } +TEST_F(ManifestParserTest, ScopeParseRules) { + // Smoke test. + { + Manifest manifest = ParseManifest( + "{ \"scope\": \"land\", \"start_url\": \"land/landing.html\" }"); + ASSERT_EQ(manifest.scope.spec(), + default_document_url.Resolve("land").spec()); + ASSERT_FALSE(manifest.IsEmpty()); + EXPECT_EQ(0u, GetErrorCount()); + } + + // Whitespaces. + { + Manifest manifest = ParseManifest( + "{ \"scope\": \" land \", \"start_url\": \"land/landing.html\" }"); + ASSERT_EQ(manifest.scope.spec(), + default_document_url.Resolve("land").spec()); + EXPECT_EQ(0u, GetErrorCount()); + } + + // Don't parse if property isn't a string. + { + Manifest manifest = ParseManifest("{ \"scope\": {} }"); + ASSERT_TRUE(manifest.scope.is_empty()); + EXPECT_EQ(1u, GetErrorCount()); + EXPECT_EQ("property 'scope' ignored, type string expected.", errors()[0]); + } + + // Don't parse if property isn't a string. + { + Manifest manifest = ParseManifest("{ \"scope\": 42 }"); + ASSERT_TRUE(manifest.scope.is_empty()); + EXPECT_EQ(1u, GetErrorCount()); + EXPECT_EQ("property 'scope' ignored, type string expected.", errors()[0]); + } + + // Absolute scope, start URL is in scope. + { + Manifest manifest = ParseManifestWithURLs( + "{ \"scope\": \"http://foo.com/land\", " + "\"start_url\": \"http://foo.com/land/landing.html\" }", + GURL("http://foo.com/manifest.json"), + GURL("http://foo.com/index.html")); + ASSERT_EQ(manifest.scope.spec(), "http://foo.com/land"); + EXPECT_EQ(0u, GetErrorCount()); + } + + // Absolute scope, start URL is not in scope. + { + Manifest manifest = + ParseManifestWithURLs("{ \"scope\": \"http://foo.com/land\", " + "\"start_url\": \"http://foo.com/index.html\" }", + GURL("http://foo.com/manifest.json"), + GURL("http://foo.com/index.html")); + ASSERT_TRUE(manifest.scope.is_empty()); + EXPECT_EQ(1u, GetErrorCount()); + EXPECT_EQ("property 'scope' ignored. Start url should be within scope " + "of scope URL.", + errors()[0]); + } + + // Absolute scope, start URL has different origin than scope URL. + { + Manifest manifest = + ParseManifestWithURLs("{ \"scope\": \"http://foo.com/land\", " + "\"start_url\": \"http://bar.com/land/landing.html\" }", + GURL("http://foo.com/manifest.json"), + GURL("http://foo.com/index.html")); + ASSERT_TRUE(manifest.scope.is_empty()); + ASSERT_EQ(2u, GetErrorCount()); + EXPECT_EQ( + "property 'start_url' ignored, should be same origin as document.", + errors()[0]); + EXPECT_EQ("property 'scope' ignored. Start url should be within scope " + "of scope URL.", + errors()[1]); + } + + // scope and start URL have diferent origin than document URL. + { + Manifest manifest = + ParseManifestWithURLs("{ \"scope\": \"http://foo.com/land\", " + "\"start_url\": \"http://foo.com/land/landing.html\" }", + GURL("http://foo.com/manifest.json"), + GURL("http://bar.com/index.html")); + ASSERT_TRUE(manifest.scope.is_empty()); + ASSERT_EQ(2u, GetErrorCount()); + EXPECT_EQ( + "property 'start_url' ignored, should be same origin as document.", + errors()[0]); + EXPECT_EQ("property 'scope' ignored, should be same origin as document.", + errors()[1]); + } + + // No start URL. Document URL is in scope. + { + Manifest manifest = ParseManifestWithURLs("{ \"scope\": \"http://foo.com/land\" }", + GURL("http://foo.com/manifest.json"), + GURL("http://foo.com/land/index.html")); + ASSERT_EQ(manifest.scope.spec(), "http://foo.com/land"); + ASSERT_EQ(0u, GetErrorCount()); + } + + // No start URL. Document is out of scope. + { + Manifest manifest = ParseManifestWithURLs("{ \"scope\": \"http://foo.com/land\" }", + GURL("http://foo.com/manifest.json"), + GURL("http://foo.com/index.html")); + ASSERT_EQ(1u, GetErrorCount()); + EXPECT_EQ("property 'scope' ignored. Start url should be within scope " + "of scope URL.", + errors()[0]); + } + + // Resolving has to happen based on the manifest_url. + { + Manifest manifest = ParseManifestWithURLs( + "{ \"scope\": \"treasure\" }", + GURL("http://foo.com/map/manifest.json"), + GURL("http://foo.com/map/treasure/island/index.html")); + ASSERT_EQ(manifest.scope.spec(), "http://foo.com/map/treasure"); + EXPECT_EQ(0u, GetErrorCount()); + } + + // Scope is parent directory. + { + Manifest manifest = + ParseManifestWithURLs("{ \"scope\": \"..\" }", + GURL("http://foo.com/map/manifest.json"), + GURL("http://foo.com/index.html")); + ASSERT_EQ(manifest.scope.spec(), "http://foo.com/"); + EXPECT_EQ(0u, GetErrorCount()); + } + + // Scope tries to go up past domain. + { + Manifest manifest = + ParseManifestWithURLs("{ \"scope\": \"../..\" }", + GURL("http://foo.com/map/manifest.json"), + GURL("http://foo.com/index.html")); + ASSERT_EQ(manifest.scope.spec(), "http://foo.com/"); + EXPECT_EQ(0u, GetErrorCount()); + } +} + TEST_F(ManifestParserTest, DisplayParserRules) { // Smoke test. { @@ -512,7 +667,7 @@ TEST_F(ManifestParserTest, IconsParseRules) { { Manifest manifest = ParseManifest("{ \"icons\": [ { \"src\": \"\" } ] }"); EXPECT_EQ(manifest.icons.size(), 1u); - EXPECT_EQ(manifest.icons[0].src.spec(), "http://foo.com/index.html"); + EXPECT_EQ(manifest.icons[0].src.spec(), "http://foo.com/manifest.json"); EXPECT_FALSE(manifest.IsEmpty()); EXPECT_EQ(0u, GetErrorCount()); } @@ -716,7 +871,6 @@ TEST_F(ManifestParserTest, IconSizesParseRules) { { Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\"," "\"sizes\": \"x 40xx 1x2x3 x42 42xx42\" } ] }"); - gfx::Size any = gfx::Size(0, 0); EXPECT_EQ(manifest.icons[0].sizes.size(), 0u); EXPECT_EQ(1u, GetErrorCount()); EXPECT_EQ("found icon with no valid size.", diff --git a/chromium/content/renderer/media/DEPS b/chromium/content/renderer/media/DEPS index 29c1d241f42..37029086b55 100644 --- a/chromium/content/renderer/media/DEPS +++ b/chromium/content/renderer/media/DEPS @@ -1,7 +1,5 @@ include_rules = [ "+third_party/libvpx", - # For video copying, cropping and scaling. - # TODO(wuchengli): remove this when RTCVideoEncoder supports zero copy. "+third_party/libyuv", '+third_party/openh264/src/codec/api/svc', '+third_party/opus', diff --git a/chromium/content/renderer/media/android/media_info_loader_unittest.cc b/chromium/content/renderer/media/android/media_info_loader_unittest.cc index 306ccdb50b8..3e0e1460410 100644 --- a/chromium/content/renderer/media/android/media_info_loader_unittest.cc +++ b/chromium/content/renderer/media/android/media_info_loader_unittest.cc @@ -5,6 +5,7 @@ #include "base/bind.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "content/renderer/media/android/media_info_loader.h" #include "content/test/mock_webframeclient.h" #include "content/test/mock_weburlloader.h" @@ -39,7 +40,7 @@ static const int kHttpNotFound = 404; class MediaInfoLoaderTest : public testing::Test { public: MediaInfoLoaderTest() - : view_(WebView::create(NULL)), + : view_(WebView::create(nullptr, blink::WebPageVisibilityStateVisible)), frame_(WebLocalFrame::create(blink::WebTreeScopeType::Document, &client_)) { view_->setMainFrame(frame_); @@ -84,7 +85,7 @@ class MediaInfoLoaderTest : public testing::Test { loader_->willFollowRedirect(url_loader_, new_request, redirect_response); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } void SendResponse( diff --git a/chromium/content/renderer/media/android/renderer_media_player_manager.cc b/chromium/content/renderer/media/android/renderer_media_player_manager.cc index a115772c0bc..b49a98e6563 100644 --- a/chromium/content/renderer/media/android/renderer_media_player_manager.cc +++ b/chromium/content/renderer/media/android/renderer_media_player_manager.cc @@ -281,6 +281,10 @@ media::RendererMediaPlayerInterface* RendererMediaPlayerManager::GetMediaPlayer( return NULL; } +void RendererMediaPlayerManager::OnDestruct() { + delete this; +} + #if defined(VIDEO_HOLE) void RendererMediaPlayerManager::RequestExternalSurface( int player_id, diff --git a/chromium/content/renderer/media/android/renderer_media_player_manager.h b/chromium/content/renderer/media/android/renderer_media_player_manager.h index 2baa846a0ad..9976488814d 100644 --- a/chromium/content/renderer/media/android/renderer_media_player_manager.h +++ b/chromium/content/renderer/media/android/renderer_media_player_manager.h @@ -116,6 +116,9 @@ class RendererMediaPlayerManager : #endif // defined(VIDEO_HOLE) private: + // RenderFrameObserver implementation. + void OnDestruct() override; + // Message handlers. void OnMediaMetadataChanged(int player_id, base::TimeDelta duration, diff --git a/chromium/content/renderer/media/android/renderer_media_session_manager.cc b/chromium/content/renderer/media/android/renderer_media_session_manager.cc index 93d19281f94..b5331c7472a 100644 --- a/chromium/content/renderer/media/android/renderer_media_session_manager.cc +++ b/chromium/content/renderer/media/android/renderer_media_session_manager.cc @@ -33,6 +33,10 @@ bool RendererMediaSessionManager::OnMessageReceived(const IPC::Message& msg) { return handled; } +void RendererMediaSessionManager::OnDestruct() { + delete this; +} + int RendererMediaSessionManager::RegisterMediaSession( WebMediaSessionAndroid* session) { sessions_[next_session_id_] = session; diff --git a/chromium/content/renderer/media/android/renderer_media_session_manager.h b/chromium/content/renderer/media/android/renderer_media_session_manager.h index bc1808c3feb..fbfd5c848b0 100644 --- a/chromium/content/renderer/media/android/renderer_media_session_manager.h +++ b/chromium/content/renderer/media/android/renderer_media_session_manager.h @@ -44,6 +44,9 @@ class CONTENT_EXPORT RendererMediaSessionManager : public RenderFrameObserver { private: friend class WebMediaSessionTest; + // RenderFrameObserver implementation. + void OnDestruct() override; + std::map<int, WebMediaSessionAndroid*> sessions_; int next_session_id_; diff --git a/chromium/content/renderer/media/android/renderer_surface_view_manager.cc b/chromium/content/renderer/media/android/renderer_surface_view_manager.cc index 6f54b1e30a1..48fd548c5ac 100644 --- a/chromium/content/renderer/media/android/renderer_surface_view_manager.cc +++ b/chromium/content/renderer/media/android/renderer_surface_view_manager.cc @@ -42,9 +42,14 @@ void RendererSurfaceViewManager::NaturalSizeChanged(const gfx::Size& size) { void RendererSurfaceViewManager::OnFullscreenSurfaceCreated(int surface_id) { DVLOG(3) << __FUNCTION__ << ": surface_id: " << surface_id; - DCHECK(!pending_surface_created_cb_.is_null()); - pending_surface_created_cb_.Run(surface_id); - pending_surface_created_cb_.Reset(); + if (!pending_surface_created_cb_.is_null()) { + pending_surface_created_cb_.Run(surface_id); + pending_surface_created_cb_.Reset(); + } +} + +void RendererSurfaceViewManager::OnDestruct() { + delete this; } } // namespace content diff --git a/chromium/content/renderer/media/android/renderer_surface_view_manager.h b/chromium/content/renderer/media/android/renderer_surface_view_manager.h index 7022744bae1..f2918f37877 100644 --- a/chromium/content/renderer/media/android/renderer_surface_view_manager.h +++ b/chromium/content/renderer/media/android/renderer_surface_view_manager.h @@ -33,6 +33,9 @@ class CONTENT_EXPORT RendererSurfaceViewManager : public media::SurfaceManager, void NaturalSizeChanged(const gfx::Size& size) override; private: + // RenderFrameObserver implementation. + void OnDestruct() override; + void OnFullscreenSurfaceCreated(int surface_id); // Set when a surface request is in progress. diff --git a/chromium/content/renderer/media/android/webmediaplayer_android.cc b/chromium/content/renderer/media/android/webmediaplayer_android.cc index eab113b48d6..7adb15e764c 100644 --- a/chromium/content/renderer/media/android/webmediaplayer_android.cc +++ b/chromium/content/renderer/media/android/webmediaplayer_android.cc @@ -287,7 +287,8 @@ WebMediaPlayerAndroid::~WebMediaPlayerAndroid() { // Part of |media_source_delegate_| needs to be stopped on the media thread. // Wait until |media_source_delegate_| is fully stopped before tearing // down other objects. - base::WaitableEvent waiter(false, false); + base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); media_source_delegate_->Stop( base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); waiter.Wait(); @@ -865,7 +866,7 @@ void WebMediaPlayerAndroid::OnPlaybackComplete() { // If the loop attribute is set, timeChanged() will update the current time // to 0. It will perform a seek to 0. Issue a command to the player to start // playing after seek completes. - if (seeking_ && seek_time_.is_zero()) + if (is_playing_ && seeking_ && seek_time_.is_zero()) player_manager_->Start(player_id_); else playback_completed_ = true; @@ -1513,11 +1514,6 @@ void WebMediaPlayerAndroid::OnWaitingForDecryptionKey() { } void WebMediaPlayerAndroid::OnHidden() { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableMediaSuspend)) { - return; - } - OnSuspendRequested(false); } @@ -1527,6 +1523,12 @@ void WebMediaPlayerAndroid::OnShown() { } void WebMediaPlayerAndroid::OnSuspendRequested(bool must_suspend) { + if (!must_suspend && + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableMediaSuspend)) { + return; + } + // If we're idle or playing video, pause and release resources; audio only // players are allowed to continue unless indicated otherwise by the call. if (must_suspend || (paused() && playback_completed_) || hasVideo()) diff --git a/chromium/content/renderer/media/audio_device_factory.cc b/chromium/content/renderer/media/audio_device_factory.cc index a4b1d77c034..9f9b8c15962 100644 --- a/chromium/content/renderer/media/audio_device_factory.cc +++ b/chromium/content/renderer/media/audio_device_factory.cc @@ -15,7 +15,9 @@ #include "content/renderer/render_thread_impl.h" #include "media/audio/audio_input_device.h" #include "media/audio/audio_output_device.h" +#include "media/base/audio_latency.h" #include "media/base/audio_renderer_mixer_input.h" +#include "media/base/media_switches.h" #include "url/origin.h" namespace content { @@ -29,11 +31,31 @@ namespace { // chance device authorization response is never received from the browser side. // In this case we will time out, to avoid renderer hang forever waiting for // device authorization (http://crbug/615589). This will result in "no audio". -const int64_t kMaxAuthorizationTimeoutMs = 900; +const int64_t kMaxAuthorizationTimeoutMs = 1000; #else const int64_t kMaxAuthorizationTimeoutMs = 0; // No timeout. #endif // defined(OS_WIN) +media::AudioLatency::LatencyType GetSourceLatencyType( + AudioDeviceFactory::SourceType source) { + switch (source) { + case AudioDeviceFactory::kSourceWebAudioInteractive: + return media::AudioLatency::LATENCY_INTERACTIVE; + case AudioDeviceFactory::kSourceNone: + case AudioDeviceFactory::kSourceWebRtc: + case AudioDeviceFactory::kSourceNonRtcAudioTrack: + case AudioDeviceFactory::kSourceWebAudioBalanced: + return media::AudioLatency::LATENCY_RTC; + case AudioDeviceFactory::kSourceMediaElement: + case AudioDeviceFactory::kSourceWebAudioPlayback: + return media::AudioLatency::LATENCY_PLAYBACK; + case AudioDeviceFactory::kSourceWebAudioExact: + return media::AudioLatency::LATENCY_EXACT_MS; + } + NOTREACHED(); + return media::AudioLatency::LATENCY_INTERACTIVE; +} + scoped_refptr<media::AudioOutputDevice> NewOutputDevice( int render_frame_id, int session_id, @@ -57,12 +79,12 @@ bool IsMixable(AudioDeviceFactory::SourceType source_type) { if (source_type == AudioDeviceFactory::kSourceMediaElement) return true; // Must ALWAYS go through mixer. - // TODO(olka): make a decision for the rest of the sources basing on OS - // type and configuration parameters. - return false; + // Mix everything if experiment is enabled; otherwise mix nothing else. + return base::FeatureList::IsEnabled(media::kNewAudioRenderingMixingStrategy); } scoped_refptr<media::SwitchableAudioRendererSink> NewMixableSink( + AudioDeviceFactory::SourceType source_type, int render_frame_id, int session_id, const std::string& device_id, @@ -70,7 +92,8 @@ scoped_refptr<media::SwitchableAudioRendererSink> NewMixableSink( RenderThreadImpl* render_thread = RenderThreadImpl::current(); return scoped_refptr<media::AudioRendererMixerInput>( render_thread->GetAudioRendererMixerManager()->CreateInput( - render_frame_id, session_id, device_id, security_origin)); + render_frame_id, session_id, device_id, security_origin, + GetSourceLatencyType(source_type))); } } // namespace @@ -102,7 +125,7 @@ AudioDeviceFactory::NewAudioRendererSink(SourceType source_type, } if (IsMixable(source_type)) - return NewMixableSink(render_frame_id, session_id, device_id, + return NewMixableSink(source_type, render_frame_id, session_id, device_id, security_origin); return NewFinalAudioRendererSink(render_frame_id, session_id, device_id, @@ -127,7 +150,7 @@ AudioDeviceFactory::NewSwitchableAudioRendererSink( } if (IsMixable(source_type)) - return NewMixableSink(render_frame_id, session_id, device_id, + return NewMixableSink(source_type, render_frame_id, session_id, device_id, security_origin); // AudioOutputDevice is not RestartableAudioRendererSink, so we can't return @@ -152,22 +175,16 @@ AudioDeviceFactory::NewAudioCapturerSource(int render_frame_id) { } // static -// TODO(http://crbug.com/587461): Find a better way to check if device exists -// and is authorized. media::OutputDeviceInfo AudioDeviceFactory::GetOutputDeviceInfo( int render_frame_id, int session_id, const std::string& device_id, const url::Origin& security_origin) { - scoped_refptr<media::AudioRendererSink> sink = NewFinalAudioRendererSink( + RenderThreadImpl* render_thread = RenderThreadImpl::current(); + DCHECK(render_thread) << "RenderThreadImpl is not instantiated, or " + << "GetOutputDeviceInfo() is called on a wrong thread "; + return render_thread->GetAudioRendererMixerManager()->GetOutputDeviceInfo( render_frame_id, session_id, device_id, security_origin); - - const media::OutputDeviceInfo& device_info = sink->GetOutputDeviceInfo(); - - // TODO(olka): Cache it and reuse, http://crbug.com/586161 - sink->Stop(); // Must be stopped. - - return device_info; } AudioDeviceFactory::AudioDeviceFactory() { diff --git a/chromium/content/renderer/media/audio_device_factory.h b/chromium/content/renderer/media/audio_device_factory.h index a8b8cb8b335..66936892b0b 100644 --- a/chromium/content/renderer/media/audio_device_factory.h +++ b/chromium/content/renderer/media/audio_device_factory.h @@ -32,14 +32,20 @@ namespace content { // AudioCapturerSourceFactory. class CONTENT_EXPORT AudioDeviceFactory { public: - // Types of audio sources. + // Types of audio sources. Each source can have individual mixing and/or + // latency requirements for output. The source is specified by the client when + // requesting output sink from the factory, and the factory creates the output + // sink basing on those requirements. enum SourceType { kSourceNone = 0, kSourceMediaElement, kSourceWebRtc, kSourceNonRtcAudioTrack, - kSourceWebAudio, - kSourceLast = kSourceWebAudio // Only used for validation of format. + kSourceWebAudioInteractive, + kSourceWebAudioBalanced, + kSourceWebAudioPlayback, + kSourceWebAudioExact, + kSourceLast = kSourceWebAudioExact // Only used for validation of format. }; // Creates a sink for AudioRendererMixer. diff --git a/chromium/content/renderer/media/audio_renderer_mixer_manager.cc b/chromium/content/renderer/media/audio_renderer_mixer_manager.cc index 75b7ed60f30..30f66fb3771 100644 --- a/chromium/content/renderer/media/audio_renderer_mixer_manager.cc +++ b/chromium/content/renderer/media/audio_renderer_mixer_manager.cc @@ -4,20 +4,116 @@ #include "content/renderer/media/audio_renderer_mixer_manager.h" +#include <algorithm> #include <string> #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" +#include "base/metrics/sparse_histogram.h" #include "build/build_config.h" -#include "content/renderer/media/audio_device_factory.h" +#include "content/renderer/media/audio_renderer_sink_cache.h" #include "media/audio/audio_device_description.h" #include "media/base/audio_hardware_config.h" #include "media/base/audio_renderer_mixer.h" #include "media/base/audio_renderer_mixer_input.h" +namespace { +// Calculate mixer output parameters based on mixer input parameters and +// hardware parameters for audio output. +media::AudioParameters GetMixerOutputParams( + const media::AudioParameters& input_params, + const media::AudioParameters& hardware_params, + media::AudioLatency::LatencyType latency) { + int output_sample_rate = input_params.sample_rate(); + bool valid_not_fake_hardware_params = + hardware_params.format() != media::AudioParameters::AUDIO_FAKE && + hardware_params.IsValid(); + int preferred_high_latency_output_buffer_size = 0; + +#if !defined(OS_CHROMEOS) + // On ChromeOS as well as when a fake device is used, we can rely on the + // playback device to handle resampling, so don't waste cycles on it here. + // On other systems if hardware parameters are valid and the device is not + // fake, resample to hardware sample rate. Otherwise, pass the input one and + // let the browser side handle automatic fallback. + if (valid_not_fake_hardware_params) { + output_sample_rate = hardware_params.sample_rate(); + preferred_high_latency_output_buffer_size = + hardware_params.frames_per_buffer(); + } +#endif + + int output_buffer_size = 0; + + // Adjust output buffer size according to the latency requirement. + switch (latency) { + case media::AudioLatency::LATENCY_INTERACTIVE: + output_buffer_size = media::AudioLatency::GetInteractiveBufferSize( + hardware_params.frames_per_buffer()); + break; + case media::AudioLatency::LATENCY_RTC: + output_buffer_size = media::AudioLatency::GetRtcBufferSize( + output_sample_rate, valid_not_fake_hardware_params + ? hardware_params.frames_per_buffer() + : 0); + break; + case media::AudioLatency::LATENCY_PLAYBACK: + output_buffer_size = media::AudioLatency::GetHighLatencyBufferSize( + output_sample_rate, preferred_high_latency_output_buffer_size); + break; + case media::AudioLatency::LATENCY_EXACT_MS: + // TODO(olka): add support when WebAudio requires it. + default: + NOTREACHED(); + } + + DCHECK_NE(output_buffer_size, 0); + + // Force to 16-bit output for now since we know that works everywhere; + // ChromeOS does not support other bit depths. + return media::AudioParameters(input_params.format(), + input_params.channel_layout(), + output_sample_rate, 16, output_buffer_size); +} + +void LogMixerUmaHistogram(media::AudioLatency::LatencyType latency, int value) { + switch (latency) { + case media::AudioLatency::LATENCY_EXACT_MS: + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Media.Audio.Render.AudioInputsPerMixer.LatencyExact", value, 1, 20, + 21); + return; + case media::AudioLatency::LATENCY_INTERACTIVE: + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Media.Audio.Render.AudioInputsPerMixer.LatencyInteractive", value, 1, + 20, 21); + return; + case media::AudioLatency::LATENCY_RTC: + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Media.Audio.Render.AudioInputsPerMixer.LatencyRtc", value, 1, 20, + 21); + return; + case media::AudioLatency::LATENCY_PLAYBACK: + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Media.Audio.Render.AudioInputsPerMixer.LatencyPlayback", value, 1, + 20, 21); + return; + default: + NOTREACHED(); + } +} + +} // namespace + namespace content { -AudioRendererMixerManager::AudioRendererMixerManager() {} +AudioRendererMixerManager::AudioRendererMixerManager( + std::unique_ptr<AudioRendererSinkCache> sink_cache) + : sink_cache_(std::move(sink_cache)) { + DCHECK(sink_cache_); +} AudioRendererMixerManager::~AudioRendererMixerManager() { // References to AudioRendererMixers may be owned by garbage collected @@ -25,122 +121,130 @@ AudioRendererMixerManager::~AudioRendererMixerManager() { // |mixers_| may leak (i.e., may be non-empty at this time) as well. } +// static +std::unique_ptr<AudioRendererMixerManager> AudioRendererMixerManager::Create() { + return base::WrapUnique( + new AudioRendererMixerManager(AudioRendererSinkCache::Create())); +} + media::AudioRendererMixerInput* AudioRendererMixerManager::CreateInput( int source_render_frame_id, int session_id, const std::string& device_id, - const url::Origin& security_origin) { - // base::Unretained() is safe since AudioRendererMixerManager lives on the - // renderer thread and is destroyed on renderer thread destruction. + const url::Origin& security_origin, + media::AudioLatency::LatencyType latency) { + // AudioRendererMixerManager lives on the renderer thread and is destroyed on + // renderer thread destruction, so it's safe to pass its pointer to a mixer + // input. return new media::AudioRendererMixerInput( - base::Bind(&AudioRendererMixerManager::GetMixer, base::Unretained(this), - source_render_frame_id), - base::Bind(&AudioRendererMixerManager::RemoveMixer, - base::Unretained(this), source_render_frame_id), + this, source_render_frame_id, media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, device_id) - ? AudioDeviceFactory::GetOutputDeviceInfo( - source_render_frame_id, session_id, device_id, security_origin) + ? GetOutputDeviceInfo(source_render_frame_id, session_id, device_id, + security_origin) .device_id() : device_id, - security_origin); + security_origin, latency); } media::AudioRendererMixer* AudioRendererMixerManager::GetMixer( int source_render_frame_id, - const media::AudioParameters& params, + const media::AudioParameters& input_params, + media::AudioLatency::LatencyType latency, const std::string& device_id, const url::Origin& security_origin, media::OutputDeviceStatus* device_status) { // Effects are not passed through to output creation, so ensure none are set. - DCHECK_EQ(params.effects(), media::AudioParameters::NO_EFFECTS); + DCHECK_EQ(input_params.effects(), media::AudioParameters::NO_EFFECTS); - const MixerKey key(source_render_frame_id, params, device_id, + const MixerKey key(source_render_frame_id, input_params, latency, device_id, security_origin); base::AutoLock auto_lock(mixers_lock_); + // Update latency map when the mixer is requested, i.e. there is an attempt to + // mix and output audio with a given latency. This is opposite to + // CreateInput() which creates a sink which is probably never used for output. + if (!latency_map_[latency]) { + latency_map_[latency] = 1; + // Log the updated latency map. This can't be done once in the end of the + // renderer lifetime, because the destructor is usually not called. So, + // we'll have a sort of exponential scale here, with a smaller subset + // logged both on its own and as a part of any larger subset. + UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.Render.AudioMixing.LatencyMap", + latency_map_.to_ulong()); + } + AudioRendererMixerMap::iterator it = mixers_.find(key); if (it != mixers_.end()) { if (device_status) *device_status = media::OUTPUT_DEVICE_STATUS_OK; it->second.ref_count++; + DVLOG(1) << "Reusing mixer: " << it->second.mixer; return it->second.mixer; } scoped_refptr<media::AudioRendererSink> sink = - AudioDeviceFactory::NewAudioRendererMixerSink(source_render_frame_id, 0, - device_id, security_origin); + sink_cache_->GetSink(source_render_frame_id, device_id, security_origin); const media::OutputDeviceInfo& device_info = sink->GetOutputDeviceInfo(); if (device_status) *device_status = device_info.device_status(); if (device_info.device_status() != media::OUTPUT_DEVICE_STATUS_OK) { + sink_cache_->ReleaseSink(sink.get()); sink->Stop(); return nullptr; } - // On ChromeOS as well as when a fake device is used, we can rely on the - // playback device to handle resampling, so don't waste cycles on it here. - int sample_rate = params.sample_rate(); - int buffer_size = - media::AudioHardwareConfig::GetHighLatencyBufferSize(sample_rate, 0); - -#if !defined(OS_CHROMEOS) - const media::AudioParameters& hardware_params = device_info.output_params(); - - // If we have valid, non-fake hardware parameters, use them. Otherwise, pass - // on the input params and let the browser side handle automatic fallback. - if (hardware_params.format() != media::AudioParameters::AUDIO_FAKE && - hardware_params.IsValid()) { - sample_rate = hardware_params.sample_rate(); - buffer_size = media::AudioHardwareConfig::GetHighLatencyBufferSize( - sample_rate, hardware_params.frames_per_buffer()); - } -#endif - - // Create output parameters based on the audio hardware configuration for - // passing on to the output sink. Force to 16-bit output for now since we - // know that works everywhere; ChromeOS does not support other bit depths. - media::AudioParameters output_params( - media::AudioParameters::AUDIO_PCM_LOW_LATENCY, params.channel_layout(), - sample_rate, 16, buffer_size); - DCHECK(output_params.IsValid()); - - media::AudioRendererMixer* mixer = - new media::AudioRendererMixer(output_params, sink); - AudioRendererMixerReference mixer_reference = { mixer, 1 }; + const media::AudioParameters& mixer_output_params = + GetMixerOutputParams(input_params, device_info.output_params(), latency); + media::AudioRendererMixer* mixer = new media::AudioRendererMixer( + mixer_output_params, sink, base::Bind(LogMixerUmaHistogram, latency)); + AudioRendererMixerReference mixer_reference = {mixer, 1, sink.get()}; mixers_[key] = mixer_reference; + DVLOG(1) << __FUNCTION__ << " mixer: " << mixer << " latency: " << latency + << "\n input: " << input_params.AsHumanReadableString() + << "\noutput: " << mixer_output_params.AsHumanReadableString(); return mixer; } -void AudioRendererMixerManager::RemoveMixer( - int source_render_frame_id, - const media::AudioParameters& params, - const std::string& device_id, - const url::Origin& security_origin) { - const MixerKey key(source_render_frame_id, params, device_id, - security_origin); +void AudioRendererMixerManager::ReturnMixer(media::AudioRendererMixer* mixer) { base::AutoLock auto_lock(mixers_lock_); - - AudioRendererMixerMap::iterator it = mixers_.find(key); + AudioRendererMixerMap::iterator it = std::find_if( + mixers_.begin(), mixers_.end(), + [mixer](const std::pair<MixerKey, AudioRendererMixerReference>& val) { + return val.second.mixer == mixer; + }); DCHECK(it != mixers_.end()); // Only remove the mixer if AudioRendererMixerManager is the last owner. it->second.ref_count--; if (it->second.ref_count == 0) { + // The mixer will be deleted now, so release the sink. + sink_cache_->ReleaseSink(it->second.sink_ptr); delete it->second.mixer; mixers_.erase(it); } } +media::OutputDeviceInfo AudioRendererMixerManager::GetOutputDeviceInfo( + int source_render_frame_id, + int session_id, + const std::string& device_id, + const url::Origin& security_origin) { + return sink_cache_->GetSinkInfo(source_render_frame_id, session_id, device_id, + security_origin); +} + AudioRendererMixerManager::MixerKey::MixerKey( int source_render_frame_id, const media::AudioParameters& params, + media::AudioLatency::LatencyType latency, const std::string& device_id, const url::Origin& security_origin) : source_render_frame_id(source_render_frame_id), params(params), + latency(latency), device_id(device_id), security_origin(security_origin) {} diff --git a/chromium/content/renderer/media/audio_renderer_mixer_manager.h b/chromium/content/renderer/media/audio_renderer_mixer_manager.h index 20a1aa59eaf..7d77212bbe6 100644 --- a/chromium/content/renderer/media/audio_renderer_mixer_manager.h +++ b/chromium/content/renderer/media/audio_renderer_mixer_manager.h @@ -5,31 +5,36 @@ #ifndef CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_MIXER_MANAGER_H_ #define CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_MIXER_MANAGER_H_ +#include <bitset> #include <map> +#include <memory> #include <string> -#include <utility> #include "base/macros.h" #include "base/synchronization/lock.h" #include "content/common/content_export.h" #include "media/audio/audio_device_description.h" +#include "media/base/audio_latency.h" #include "media/base/audio_parameters.h" +#include "media/base/audio_renderer_mixer_pool.h" #include "media/base/output_device_info.h" #include "url/origin.h" namespace media { -class AudioHardwareConfig; class AudioRendererMixer; class AudioRendererMixerInput; class AudioRendererSink; } namespace content { +class AudioRendererSinkCache; // Manages sharing of an AudioRendererMixer among AudioRendererMixerInputs based // on their AudioParameters configuration. Inputs with the same AudioParameters // configuration will share a mixer while a new AudioRendererMixer will be -// lazily created if one with the exact AudioParameters does not exist. +// lazily created if one with the exact AudioParameters does not exist. When an +// AudioRendererMixer is returned by AudioRendererMixerInput, it will be deleted +// if its only other reference is held by AudioRendererMixerManager. // // There should only be one instance of AudioRendererMixerManager per render // thread. @@ -39,10 +44,12 @@ namespace content { // with floats. However, bits per channel is currently used to interleave the // audio data by AudioOutputDevice::AudioThreadCallback::Process for consumption // via the shared memory. See http://crbug.com/114700. -class CONTENT_EXPORT AudioRendererMixerManager { +class CONTENT_EXPORT AudioRendererMixerManager + : public media::AudioRendererMixerPool { public: - AudioRendererMixerManager(); - ~AudioRendererMixerManager(); + ~AudioRendererMixerManager() final; + + static std::unique_ptr<AudioRendererMixerManager> Create(); // Creates an AudioRendererMixerInput with the proper callbacks necessary to // retrieve an AudioRendererMixer instance from AudioRendererMixerManager. @@ -56,23 +63,30 @@ class CONTENT_EXPORT AudioRendererMixerManager { int source_render_frame_id, int session_id, const std::string& device_id, - const url::Origin& security_origin); - - // Returns a mixer instance based on AudioParameters; an existing one if one - // with the provided AudioParameters exists or a new one if not. - media::AudioRendererMixer* GetMixer(int source_render_frame_id, - const media::AudioParameters& params, - const std::string& device_id, - const url::Origin& security_origin, - media::OutputDeviceStatus* device_status); - - // Remove a mixer instance given a mixer if the only other reference is held - // by AudioRendererMixerManager. Every AudioRendererMixer owner must call - // this method when it's done with a mixer. - void RemoveMixer(int source_render_frame_id, - const media::AudioParameters& params, - const std::string& device_id, - const url::Origin& security_origin); + const url::Origin& security_origin, + media::AudioLatency::LatencyType latency); + + // AudioRendererMixerPool implementation. + + media::AudioRendererMixer* GetMixer( + int source_render_frame_id, + const media::AudioParameters& input_params, + media::AudioLatency::LatencyType latency, + const std::string& device_id, + const url::Origin& security_origin, + media::OutputDeviceStatus* device_status) final; + + void ReturnMixer(media::AudioRendererMixer* mixer) final; + + media::OutputDeviceInfo GetOutputDeviceInfo( + int source_render_frame_id, + int session_id, + const std::string& device_id, + const url::Origin& security_origin) final; + + protected: + explicit AudioRendererMixerManager( + std::unique_ptr<AudioRendererSinkCache> sink_cache); private: friend class AudioRendererMixerManagerTest; @@ -82,11 +96,13 @@ class CONTENT_EXPORT AudioRendererMixerManager { struct MixerKey { MixerKey(int source_render_frame_id, const media::AudioParameters& params, + media::AudioLatency::LatencyType latency, const std::string& device_id, const url::Origin& security_origin); MixerKey(const MixerKey& other); int source_render_frame_id; media::AudioParameters params; + media::AudioLatency::LatencyType latency; std::string device_id; url::Origin security_origin; }; @@ -100,6 +116,13 @@ class CONTENT_EXPORT AudioRendererMixerManager { if (a.params.channels() != b.params.channels()) return a.params.channels() < b.params.channels(); + if (a.latency != b.latency) + return a.latency < b.latency; + + // TODO(olka) add buffer duration comparison for LATENCY_EXACT_MS when + // adding support for it. + DCHECK_NE(media::AudioLatency::LATENCY_EXACT_MS, a.latency); + // Ignore effects(), bits_per_sample(), format(), and frames_per_buffer(), // these parameters do not affect mixer reuse. All AudioRendererMixer // units disable FIFO, so frames_per_buffer() can be safely ignored. @@ -127,14 +150,24 @@ class CONTENT_EXPORT AudioRendererMixerManager { struct AudioRendererMixerReference { media::AudioRendererMixer* mixer; int ref_count; + // Mixer sink pointer, to remove a sink from cache upon mixer destruction. + const media::AudioRendererSink* sink_ptr; }; - typedef std::map<MixerKey, AudioRendererMixerReference, MixerKeyCompare> - AudioRendererMixerMap; + + using AudioRendererMixerMap = + std::map<MixerKey, AudioRendererMixerReference, MixerKeyCompare>; // Active mixers. AudioRendererMixerMap mixers_; base::Lock mixers_lock_; + // Mixer sink cache. + const std::unique_ptr<AudioRendererSinkCache> sink_cache_; + + // Map of the output latencies encountered throughout mixer manager lifetime. + // Used for UMA histogram logging. + std::bitset<media::AudioLatency::LATENCY_COUNT> latency_map_; + DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManager); }; diff --git a/chromium/content/renderer/media/audio_renderer_mixer_manager_unittest.cc b/chromium/content/renderer/media/audio_renderer_mixer_manager_unittest.cc index e3eb3b3718f..fbdb0c55076 100644 --- a/chromium/content/renderer/media/audio_renderer_mixer_manager_unittest.cc +++ b/chromium/content/renderer/media/audio_renderer_mixer_manager_unittest.cc @@ -6,12 +6,13 @@ #include <memory> +#include "base/bind.h" +#include "build/build_config.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "content/renderer/media/audio_device_factory.h" +#include "content/renderer/media/audio_renderer_sink_cache.h" #include "media/audio/audio_device_description.h" -#include "media/base/audio_capturer_source.h" #include "media/base/audio_parameters.h" #include "media/base/audio_renderer_mixer.h" #include "media/base/audio_renderer_mixer_input.h" @@ -23,56 +24,109 @@ namespace content { -static const int kBitsPerChannel = 16; -static const int kSampleRate = 48000; -static const int kBufferSize = 8192; -static const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO; -static const media::ChannelLayout kAnotherChannelLayout = - media::CHANNEL_LAYOUT_2_1; -static const char* const kDefaultDeviceId = +namespace { +const int kBitsPerChannel = 16; +const int kSampleRate = 48000; +const int kBufferSize = 8192; +const int kHardwareSampleRate = 44100; +const int kHardwareBufferSize = 128; +const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO; +const media::ChannelLayout kAnotherChannelLayout = media::CHANNEL_LAYOUT_2_1; +const char* const kDefaultDeviceId = media::AudioDeviceDescription::kDefaultDeviceId; -static const char kAnotherDeviceId[] = "another-device-id"; -static const char kMatchedDeviceId[] = "matched-device-id"; -static const char kNonexistentDeviceId[] = "nonexistent-device-id"; +const char kAnotherDeviceId[] = "another-device-id"; +const char kMatchedDeviceId[] = "matched-device-id"; +const char kNonexistentDeviceId[] = "nonexistent-device-id"; -static const int kRenderFrameId = 124; -static const int kAnotherRenderFrameId = 678; +const int kRenderFrameId = 124; +const int kAnotherRenderFrameId = 678; +} // namespace; using media::AudioParameters; +using media::AudioLatency; -class AudioRendererMixerManagerTest : public testing::Test, - public AudioDeviceFactory { +class FakeAudioRendererSinkCache : public AudioRendererSinkCache { + public: + using GetSinkCallback = + base::Callback<scoped_refptr<media::AudioRendererSink>( + int render_frame_id, + int session_id, + const std::string& device_id, + const url::Origin& security_origin)>; + + using ReleaseSinkCallback = + base::Callback<void(const media::AudioRendererSink*)>; + + FakeAudioRendererSinkCache(const GetSinkCallback& get_sink_cb, + const ReleaseSinkCallback& release_sink_cb) + : get_sink_cb_(get_sink_cb), release_sink_cb_(release_sink_cb) {} + + media::OutputDeviceInfo GetSinkInfo( + int source_render_frame_id, + int session_id, + const std::string& device_id, + const url::Origin& security_origin) final { + return get_sink_cb_ + .Run(source_render_frame_id, session_id, device_id, security_origin) + ->GetOutputDeviceInfo(); + } + + scoped_refptr<media::AudioRendererSink> GetSink( + int source_render_frame_id, + const std::string& device_id, + const url::Origin& security_origin) final { + return get_sink_cb_.Run(source_render_frame_id, 0, device_id, + security_origin); + } + + void ReleaseSink(const media::AudioRendererSink* sink) final { + release_sink_cb_.Run(sink); + } + + private: + GetSinkCallback get_sink_cb_; + ReleaseSinkCallback release_sink_cb_; +}; + +class AudioRendererMixerManagerTest : public testing::Test { public: AudioRendererMixerManagerTest() - : manager_(new AudioRendererMixerManager()), - mock_sink_(new media::MockAudioRendererSink()), + : manager_(new AudioRendererMixerManager( + std::unique_ptr<AudioRendererSinkCache>( + new FakeAudioRendererSinkCache( + base::Bind(&AudioRendererMixerManagerTest::GetSinkPtr, + base::Unretained(this)), + base::Bind(&AudioRendererMixerManagerTest::ReleaseSinkPtr, + base::Unretained(this)))))), + mock_sink_(new media::MockAudioRendererSink( + kDefaultDeviceId, + media::OUTPUT_DEVICE_STATUS_OK, + AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, + kChannelLayout, + kHardwareSampleRate, + kBitsPerChannel, + kHardwareBufferSize))), mock_sink_no_device_(new media::MockAudioRendererSink( kNonexistentDeviceId, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND)), mock_sink_matched_device_( new media::MockAudioRendererSink(kMatchedDeviceId, media::OUTPUT_DEVICE_STATUS_OK)), - mock_sink_for_session_id_( - new media::MockAudioRendererSink(kMatchedDeviceId, - media::OUTPUT_DEVICE_STATUS_OK)), kSecurityOrigin2(GURL("http://localhost")) {} media::AudioRendererMixer* GetMixer( int source_render_frame_id, const media::AudioParameters& params, + AudioLatency::LatencyType latency, const std::string& device_id, const url::Origin& security_origin, media::OutputDeviceStatus* device_status) { - return manager_->GetMixer(source_render_frame_id, params, device_id, - security_origin, device_status); + return manager_->GetMixer(source_render_frame_id, params, latency, + device_id, security_origin, device_status); } - void RemoveMixer(int source_render_frame_id, - const media::AudioParameters& params, - const std::string& device_id, - const url::Origin& security_origin) { - return manager_->RemoveMixer(source_render_frame_id, params, device_id, - security_origin); + void ReturnMixer(media::AudioRendererMixer* mixer) { + return manager_->ReturnMixer(mixer); } // Number of instantiated mixers. @@ -81,24 +135,8 @@ class AudioRendererMixerManagerTest : public testing::Test, } protected: - MOCK_METHOD1(CreateAudioCapturerSource, - scoped_refptr<media::AudioCapturerSource>(int)); - MOCK_METHOD5( - CreateSwitchableAudioRendererSink, - scoped_refptr<media::SwitchableAudioRendererSink>(SourceType, - int, - int, - const std::string&, - const url::Origin&)); - MOCK_METHOD5(CreateAudioRendererSink, - scoped_refptr<media::AudioRendererSink>(SourceType, - int, - int, - const std::string&, - const url::Origin&)); - - scoped_refptr<media::AudioRendererSink> CreateFinalAudioRendererSink( - int render_frame_id, + scoped_refptr<media::AudioRendererSink> GetSinkPtr( + int source_render_frame_id, int session_id, const std::string& device_id, const url::Origin& security_origin) { @@ -110,7 +148,7 @@ class AudioRendererMixerManagerTest : public testing::Test, return mock_sink_no_device_; if (device_id.empty()) { // The sink used to get device ID from session ID if it's not empty - return session_id ? mock_sink_for_session_id_ : mock_sink_; + return session_id ? mock_sink_matched_device_ : mock_sink_; } if (device_id == kMatchedDeviceId) return mock_sink_matched_device_; @@ -119,11 +157,13 @@ class AudioRendererMixerManagerTest : public testing::Test, return nullptr; } + MOCK_METHOD1(ReleaseSinkPtr, void(const media::AudioRendererSink*)); + std::unique_ptr<AudioRendererMixerManager> manager_; + scoped_refptr<media::MockAudioRendererSink> mock_sink_; scoped_refptr<media::MockAudioRendererSink> mock_sink_no_device_; scoped_refptr<media::MockAudioRendererSink> mock_sink_matched_device_; - scoped_refptr<media::MockAudioRendererSink> mock_sink_for_session_id_; // To avoid global/static non-POD constants. const url::Origin kSecurityOrigin; @@ -133,50 +173,56 @@ class AudioRendererMixerManagerTest : public testing::Test, DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManagerTest); }; -// Verify GetMixer() and RemoveMixer() both work as expected; particularly with +// Verify GetMixer() and ReturnMixer() both work as expected; particularly with // respect to the explicit ref counting done. -TEST_F(AudioRendererMixerManagerTest, GetRemoveMixer) { +TEST_F(AudioRendererMixerManagerTest, GetReturnMixer) { // Since we're testing two different sets of parameters, we expect // AudioRendererMixerManager to call Start and Stop on our mock twice. EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); + // We expect 2 mixers to be created; each of them should release the sink. + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2); + // There should be no mixers outstanding to start with. EXPECT_EQ(0, mixer_count()); - media::AudioParameters params1( - AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, - kBitsPerChannel, kBufferSize); + media::AudioParameters params1(media::AudioParameters::AUDIO_PCM_LINEAR, + kChannelLayout, kSampleRate, kBitsPerChannel, + kBufferSize); - media::AudioRendererMixer* mixer1 = GetMixer( - kRenderFrameId, params1, kDefaultDeviceId, kSecurityOrigin, nullptr); + media::AudioRendererMixer* mixer1 = + GetMixer(kRenderFrameId, params1, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); ASSERT_TRUE(mixer1); EXPECT_EQ(1, mixer_count()); // The same parameters should return the same mixer1. - EXPECT_EQ(mixer1, GetMixer(kRenderFrameId, params1, kDefaultDeviceId, - kSecurityOrigin, nullptr)); + EXPECT_EQ(mixer1, + GetMixer(kRenderFrameId, params1, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr)); EXPECT_EQ(1, mixer_count()); - // Remove the extra mixer we just acquired. - RemoveMixer(kRenderFrameId, params1, kDefaultDeviceId, kSecurityOrigin); + // Return the extra mixer we just acquired. + ReturnMixer(mixer1); EXPECT_EQ(1, mixer_count()); media::AudioParameters params2( AudioParameters::AUDIO_PCM_LINEAR, kAnotherChannelLayout, kSampleRate * 2, kBitsPerChannel, kBufferSize * 2); - media::AudioRendererMixer* mixer2 = GetMixer( - kRenderFrameId, params2, kDefaultDeviceId, kSecurityOrigin, nullptr); + media::AudioRendererMixer* mixer2 = + GetMixer(kRenderFrameId, params2, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); ASSERT_TRUE(mixer2); EXPECT_EQ(2, mixer_count()); // Different parameters should result in a different mixer1. EXPECT_NE(mixer1, mixer2); - // Remove both outstanding mixers. - RemoveMixer(kRenderFrameId, params1, kDefaultDeviceId, kSecurityOrigin); + // Return both outstanding mixers. + ReturnMixer(mixer1); EXPECT_EQ(1, mixer_count()); - RemoveMixer(kRenderFrameId, params2, kDefaultDeviceId, kSecurityOrigin); + ReturnMixer(mixer2); EXPECT_EQ(0, mixer_count()); } @@ -187,13 +233,17 @@ TEST_F(AudioRendererMixerManagerTest, MixerReuse) { EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); EXPECT_EQ(mixer_count(), 0); + // We expect 2 mixers to be created; each of them should release the sink. + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2); + media::AudioParameters params1(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, kBitsPerChannel, kBufferSize); - media::AudioRendererMixer* mixer1 = GetMixer( - kRenderFrameId, params1, kDefaultDeviceId, kSecurityOrigin, nullptr); + media::AudioRendererMixer* mixer1 = + GetMixer(kRenderFrameId, params1, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); ASSERT_TRUE(mixer1); EXPECT_EQ(1, mixer_count()); @@ -204,10 +254,12 @@ TEST_F(AudioRendererMixerManagerTest, MixerReuse) { kSampleRate * 2, kBitsPerChannel * 2, kBufferSize * 2); - EXPECT_EQ(mixer1, GetMixer(kRenderFrameId, params2, kDefaultDeviceId, - kSecurityOrigin, nullptr)); + media::AudioRendererMixer* mixer2 = + GetMixer(kRenderFrameId, params2, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); + EXPECT_EQ(mixer1, mixer2); EXPECT_EQ(1, mixer_count()); - RemoveMixer(kRenderFrameId, params2, kDefaultDeviceId, kSecurityOrigin); + ReturnMixer(mixer2); EXPECT_EQ(1, mixer_count()); // Modify some parameters that do matter: channel layout @@ -217,28 +269,32 @@ TEST_F(AudioRendererMixerManagerTest, MixerReuse) { kBitsPerChannel, kBufferSize); ASSERT_NE(params3.channel_layout(), params1.channel_layout()); - - EXPECT_NE(mixer1, GetMixer(kRenderFrameId, params3, kDefaultDeviceId, - kSecurityOrigin, nullptr)); + media::AudioRendererMixer* mixer3 = + GetMixer(kRenderFrameId, params3, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); + EXPECT_NE(mixer1, mixer3); EXPECT_EQ(2, mixer_count()); - RemoveMixer(kRenderFrameId, params3, kDefaultDeviceId, kSecurityOrigin); + ReturnMixer(mixer3); EXPECT_EQ(1, mixer_count()); - // Remove final mixer. - RemoveMixer(kRenderFrameId, params1, kDefaultDeviceId, kSecurityOrigin); + // Return final mixer. + ReturnMixer(mixer1); EXPECT_EQ(0, mixer_count()); } // Verify CreateInput() provides AudioRendererMixerInput with the appropriate // callbacks and they are working as expected. Also, verify that separate -// mixers are created for separate render views, even though the AudioParameters -// are the same. +// mixers are created for separate RenderFrames, even though the +// AudioParameters are the same. TEST_F(AudioRendererMixerManagerTest, CreateInput) { // Expect AudioRendererMixerManager to call Start and Stop on our mock twice // each. Note: Under normal conditions, each mixer would get its own sink! EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); + // We expect 2 mixers to be created; each of them should release the sink. + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2); + media::AudioParameters params( AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, kBitsPerChannel, kBufferSize); @@ -246,19 +302,20 @@ TEST_F(AudioRendererMixerManagerTest, CreateInput) { // Create two mixer inputs and ensure this doesn't instantiate any mixers yet. EXPECT_EQ(0, mixer_count()); media::FakeAudioRenderCallback callback(0); - scoped_refptr<media::AudioRendererMixerInput> input(manager_->CreateInput( - kRenderFrameId, 0, kDefaultDeviceId, kSecurityOrigin)); + scoped_refptr<media::AudioRendererMixerInput> input( + manager_->CreateInput(kRenderFrameId, 0, kDefaultDeviceId, + kSecurityOrigin, AudioLatency::LATENCY_PLAYBACK)); input->Initialize(params, &callback); EXPECT_EQ(0, mixer_count()); media::FakeAudioRenderCallback another_callback(1); scoped_refptr<media::AudioRendererMixerInput> another_input( manager_->CreateInput(kAnotherRenderFrameId, 0, kDefaultDeviceId, - kSecurityOrigin)); + kSecurityOrigin, AudioLatency::LATENCY_PLAYBACK)); another_input->Initialize(params, &another_callback); EXPECT_EQ(0, mixer_count()); // Implicitly test that AudioRendererMixerInput was provided with the expected - // callbacks needed to acquire an AudioRendererMixer and remove it. + // callbacks needed to acquire an AudioRendererMixer and return it. input->Start(); EXPECT_EQ(1, mixer_count()); another_input->Start(); @@ -287,6 +344,10 @@ TEST_F(AudioRendererMixerManagerTest, CreateInputWithSessionId) { EXPECT_CALL(*mock_sink_matched_device_.get(), Start()).Times(1); EXPECT_CALL(*mock_sink_matched_device_.get(), Stop()).Times(1); + // We expect 3 mixers to be created; each of them should release a sink. + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2); + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_matched_device_.get())).Times(1); + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, kBitsPerChannel, kBufferSize); @@ -296,34 +357,37 @@ TEST_F(AudioRendererMixerManagerTest, CreateInputWithSessionId) { // Empty device id, zero session id; scoped_refptr<media::AudioRendererMixerInput> input_to_default_device( manager_->CreateInput(kRenderFrameId, 0, // session_id - std::string(), kSecurityOrigin)); + std::string(), kSecurityOrigin, + AudioLatency::LATENCY_PLAYBACK)); input_to_default_device->Initialize(params, &callback); EXPECT_EQ(0, mixer_count()); // Specific device id, zero session id; scoped_refptr<media::AudioRendererMixerInput> input_to_matched_device( manager_->CreateInput(kRenderFrameId, 0, // session_id - kMatchedDeviceId, kSecurityOrigin)); + kMatchedDeviceId, kSecurityOrigin, + AudioLatency::LATENCY_PLAYBACK)); input_to_matched_device->Initialize(params, &callback); EXPECT_EQ(0, mixer_count()); // Specific device id, non-zero session id (to be ignored); scoped_refptr<media::AudioRendererMixerInput> input_to_another_device( manager_->CreateInput(kRenderFrameId, 1, // session id - kAnotherDeviceId, kSecurityOrigin)); + kAnotherDeviceId, kSecurityOrigin, + AudioLatency::LATENCY_PLAYBACK)); input_to_another_device->Initialize(params, &callback); EXPECT_EQ(0, mixer_count()); // Empty device id, non-zero session id; scoped_refptr<media::AudioRendererMixerInput> - input_to_matched_device_with_session_id( - manager_->CreateInput(kRenderFrameId, 2, // session id - std::string(), kSecurityOrigin)); + input_to_matched_device_with_session_id(manager_->CreateInput( + kRenderFrameId, 2, // session id + std::string(), kSecurityOrigin, AudioLatency::LATENCY_PLAYBACK)); input_to_matched_device_with_session_id->Initialize(params, &callback); EXPECT_EQ(0, mixer_count()); // Implicitly test that AudioRendererMixerInput was provided with the expected - // callbacks needed to acquire an AudioRendererMixer and remove it. + // callbacks needed to acquire an AudioRendererMixer and return it. input_to_default_device->Start(); EXPECT_EQ(1, mixer_count()); @@ -359,32 +423,38 @@ TEST_F(AudioRendererMixerManagerTest, MixerDevices) { EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3); EXPECT_EQ(0, mixer_count()); + // We expect 3 mixers to be created; each of them should release a sink. + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(3); + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, kBitsPerChannel, kBufferSize); - media::AudioRendererMixer* mixer1 = GetMixer( - kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin, nullptr); + media::AudioRendererMixer* mixer1 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); ASSERT_TRUE(mixer1); EXPECT_EQ(1, mixer_count()); - media::AudioRendererMixer* mixer2 = GetMixer( - kRenderFrameId, params, kAnotherDeviceId, kSecurityOrigin, nullptr); + media::AudioRendererMixer* mixer2 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kAnotherDeviceId, kSecurityOrigin, nullptr); ASSERT_TRUE(mixer2); EXPECT_EQ(2, mixer_count()); EXPECT_NE(mixer1, mixer2); - media::AudioRendererMixer* mixer3 = GetMixer( - kRenderFrameId, params, kAnotherDeviceId, kSecurityOrigin2, nullptr); + media::AudioRendererMixer* mixer3 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kAnotherDeviceId, kSecurityOrigin2, nullptr); ASSERT_TRUE(mixer3); EXPECT_EQ(3, mixer_count()); EXPECT_NE(mixer1, mixer3); EXPECT_NE(mixer2, mixer3); - RemoveMixer(kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin); + ReturnMixer(mixer1); EXPECT_EQ(2, mixer_count()); - RemoveMixer(kRenderFrameId, params, kAnotherDeviceId, kSecurityOrigin); + ReturnMixer(mixer2); EXPECT_EQ(1, mixer_count()); - RemoveMixer(kRenderFrameId, params, kAnotherDeviceId, kSecurityOrigin2); + ReturnMixer(mixer3); EXPECT_EQ(0, mixer_count()); } @@ -395,39 +465,46 @@ TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentOriginsDefaultDevice) { EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); EXPECT_EQ(0, mixer_count()); + // We expect 1 mixer to be created; it should release its sink. + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1); + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, kBitsPerChannel, kBufferSize); - media::AudioRendererMixer* mixer1 = GetMixer( - kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin, nullptr); + media::AudioRendererMixer* mixer1 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); ASSERT_TRUE(mixer1); EXPECT_EQ(1, mixer_count()); media::AudioRendererMixer* mixer2 = - GetMixer(kRenderFrameId, params, std::string(), kSecurityOrigin, nullptr); + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + std::string(), kSecurityOrigin, nullptr); ASSERT_TRUE(mixer2); EXPECT_EQ(1, mixer_count()); EXPECT_EQ(mixer1, mixer2); - media::AudioRendererMixer* mixer3 = GetMixer( - kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin2, nullptr); + media::AudioRendererMixer* mixer3 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin2, nullptr); ASSERT_TRUE(mixer3); EXPECT_EQ(1, mixer_count()); EXPECT_EQ(mixer1, mixer3); - media::AudioRendererMixer* mixer4 = GetMixer( - kRenderFrameId, params, std::string(), kSecurityOrigin2, nullptr); + media::AudioRendererMixer* mixer4 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + std::string(), kSecurityOrigin2, nullptr); ASSERT_TRUE(mixer4); EXPECT_EQ(1, mixer_count()); EXPECT_EQ(mixer1, mixer4); - RemoveMixer(kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin); + ReturnMixer(mixer1); EXPECT_EQ(1, mixer_count()); - RemoveMixer(kRenderFrameId, params, std::string(), kSecurityOrigin); + ReturnMixer(mixer2); EXPECT_EQ(1, mixer_count()); - RemoveMixer(kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin2); + ReturnMixer(mixer3); EXPECT_EQ(1, mixer_count()); - RemoveMixer(kRenderFrameId, params, std::string(), kSecurityOrigin2); + ReturnMixer(mixer4); EXPECT_EQ(0, mixer_count()); } @@ -435,17 +512,320 @@ TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentOriginsDefaultDevice) { // status code when a nonexistent device is requested. TEST_F(AudioRendererMixerManagerTest, NonexistentDevice) { EXPECT_EQ(0, mixer_count()); + + // Mixer manager should release a not-ok sink when failing to create a mixer. + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_no_device_.get())).Times(1); + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, kBitsPerChannel, kBufferSize); media::OutputDeviceStatus device_status = media::OUTPUT_DEVICE_STATUS_OK; - EXPECT_CALL(*mock_sink_no_device_.get(), Stop()); + media::AudioRendererMixer* mixer = - GetMixer(kRenderFrameId, params, kNonexistentDeviceId, kSecurityOrigin, - &device_status); + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kNonexistentDeviceId, kSecurityOrigin, &device_status); + EXPECT_FALSE(mixer); EXPECT_EQ(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, device_status); EXPECT_EQ(0, mixer_count()); } +// Verify GetMixer() correctly deduplicate mixers basing on latency +// requirements. +TEST_F(AudioRendererMixerManagerTest, LatencyMixing) { + EXPECT_CALL(*mock_sink_.get(), Start()).Times(3); + EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3); + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(3); + + EXPECT_EQ(0, mixer_count()); + + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, + kChannelLayout, kSampleRate, kBitsPerChannel, + kBufferSize); + media::AudioRendererMixer* mixer1 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); + ASSERT_TRUE(mixer1); + EXPECT_EQ(1, mixer_count()); + + media::AudioRendererMixer* mixer2 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); + ASSERT_TRUE(mixer2); + EXPECT_EQ(mixer1, mixer2); // Same latency => same mixer. + EXPECT_EQ(1, mixer_count()); + + media::AudioRendererMixer* mixer3 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC, + kDefaultDeviceId, kSecurityOrigin, nullptr); + ASSERT_TRUE(mixer3); + EXPECT_NE(mixer1, mixer3); + EXPECT_EQ(2, mixer_count()); // Another latency => another mixer. + + media::AudioRendererMixer* mixer4 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC, + kDefaultDeviceId, kSecurityOrigin, nullptr); + EXPECT_EQ(mixer3, mixer4); + EXPECT_EQ(2, mixer_count()); // Same latency => same mixer. + + media::AudioRendererMixer* mixer5 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_INTERACTIVE, + kDefaultDeviceId, kSecurityOrigin, nullptr); + ASSERT_TRUE(mixer5); + EXPECT_EQ(3, mixer_count()); // Another latency => another mixer. + + media::AudioRendererMixer* mixer6 = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_INTERACTIVE, + kDefaultDeviceId, kSecurityOrigin, nullptr); + EXPECT_EQ(mixer5, mixer6); + EXPECT_EQ(3, mixer_count()); // Same latency => same mixer. + + ReturnMixer(mixer1); + EXPECT_EQ(3, mixer_count()); + ReturnMixer(mixer2); + EXPECT_EQ(2, mixer_count()); + ReturnMixer(mixer3); + EXPECT_EQ(2, mixer_count()); + ReturnMixer(mixer4); + EXPECT_EQ(1, mixer_count()); + ReturnMixer(mixer5); + EXPECT_EQ(1, mixer_count()); + ReturnMixer(mixer6); + EXPECT_EQ(0, mixer_count()); +} + +// Verify output bufer size of the mixer is correctly adjusted for Playback +// latency. +TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlayback) { + // Expecting hardware buffer size of 128 frames + EXPECT_EQ(44100, + mock_sink_->GetOutputDeviceInfo().output_params().sample_rate()); + // Expecting hardware buffer size of 128 frames + EXPECT_EQ( + 128, + mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer()); + + EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); + EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1); + + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, + kChannelLayout, 32000, kBitsPerChannel, 512); + + media::AudioRendererMixer* mixer = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); + +#if defined(OS_CHROMEOS) + // Expecting input sample rate + EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate()); + // Round up 20 ms (640) to the power of 2. + EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer()); + +#else + // Expecting hardware sample rate + EXPECT_EQ(44100, mixer->GetOutputParamsForTesting().sample_rate()); + +// 20 ms at 44100 is 882 frames per buffer. +#if defined(OS_WIN) + // Round up 882 to the nearest multiple of the output buffer size (128). which + // is 7 * 128 = 896 + EXPECT_EQ(896, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#else + // Round up 882 to the power of 2. + EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#endif // defined(OS_WIN) + +#endif // defined(OS_CHROMEOS) + + ReturnMixer(mixer); +} + +// Verify output bufer size of the mixer is correctly adjusted for Playback +// latency when the device buffer size exceeds 20 ms. +TEST_F(AudioRendererMixerManagerTest, + MixerParamsLatencyPlaybackLargeDeviceBufferSize) { + mock_sink_ = new media::MockAudioRendererSink( + std::string(), media::OUTPUT_DEVICE_STATUS_OK, + AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 44100, + kBitsPerChannel, 2048)); + + EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); + EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1); + + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, + kChannelLayout, 32000, kBitsPerChannel, 512); + + media::AudioRendererMixer* mixer = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); + +// 20 ms at 44100 is 882 frames per buffer. +#if defined(OS_CHROMEOS) + // Expecting input sample rate + EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate()); + // Ignore device buffer size, round up 20 ms (640) to the power of 2. + EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#else + // Expecting hardware sample rate + EXPECT_EQ(44100, mixer->GetOutputParamsForTesting().sample_rate()); + // Prefer device buffer size (2048) if is larger than 20 ms buffer size (882). + EXPECT_EQ(2048, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#endif + + ReturnMixer(mixer); +} + +// Verify output bufer size of the mixer is correctly adjusted for Playback +// latency when output audio is fake. +TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlaybackFakeAudio) { + mock_sink_ = new media::MockAudioRendererSink( + std::string(), media::OUTPUT_DEVICE_STATUS_OK, + AudioParameters(AudioParameters::AUDIO_FAKE, kChannelLayout, 44100, + kBitsPerChannel, 2048)); + + EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); + EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1); + + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, + kChannelLayout, 32000, kBitsPerChannel, 512); + + media::AudioRendererMixer* mixer = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK, + kDefaultDeviceId, kSecurityOrigin, nullptr); + + // Expecting input sample rate + EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate()); + +// 20 ms at 32000 is 640 frames per buffer. +#if defined(OS_WIN) + // Use 20 ms buffer. + EXPECT_EQ(640, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#else + // Ignore device buffer size, round up 640 to the power of 2. + EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#endif // defined(OS_WIN) + + ReturnMixer(mixer); +} + +// Verify output bufer size of the mixer is correctly adjusted for RTC latency. +TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtc) { + // Expecting hardware buffer size of 128 frames + EXPECT_EQ(44100, + mock_sink_->GetOutputDeviceInfo().output_params().sample_rate()); + // Expecting hardware buffer size of 128 frames + EXPECT_EQ( + 128, + mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer()); + + EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); + EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1); + + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, + kChannelLayout, 32000, kBitsPerChannel, 512); + + media::AudioRendererMixer* mixer = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC, + kDefaultDeviceId, kSecurityOrigin, nullptr); + +#if defined(OS_CHROMEOS) + int output_sample_rate = 32000; +#else + // Expecting hardware sample rate. + int output_sample_rate = 44100; +#endif // defined(OS_CHROMEOS) + + EXPECT_EQ(output_sample_rate, + mixer->GetOutputParamsForTesting().sample_rate()); + +#if defined(OS_LINUX) || defined(OS_MACOSX) + // Use 10 ms buffer (441 frames per buffer). + EXPECT_EQ(output_sample_rate / 100, + mixer->GetOutputParamsForTesting().frames_per_buffer()); +#elif defined(OS_ANDROID) + // If hardware buffer size (128) is less than 20 ms (882), use 20 ms buffer + // (otherwise, use hardware buffer). + EXPECT_EQ(882, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#else + // Use hardware buffer size (128). + EXPECT_EQ(128, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#endif // defined(OS_LINUX) || defined(OS_MACOSX) + + ReturnMixer(mixer); +} + +// Verify output bufer size of the mixer is correctly adjusted for RTC latency +// when output audio is fake. +TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtcFakeAudio) { + mock_sink_ = new media::MockAudioRendererSink( + std::string(), media::OUTPUT_DEVICE_STATUS_OK, + AudioParameters(AudioParameters::AUDIO_FAKE, kChannelLayout, 44100, + kBitsPerChannel, 128)); + + EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); + EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1); + + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, + kChannelLayout, 32000, kBitsPerChannel, 512); + + media::AudioRendererMixer* mixer = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC, + kDefaultDeviceId, kSecurityOrigin, nullptr); + + // Expecting input sample rate. + EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate()); + + // 10 ms at 32000 is 320 frames per buffer. Expect it on all the platforms for + // fake audio output. + EXPECT_EQ(320, mixer->GetOutputParamsForTesting().frames_per_buffer()); + + ReturnMixer(mixer); +} + +// Verify output bufer size of the mixer is correctly adjusted for Interactive +// latency. +TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyInteractive) { + // Expecting hardware buffer size of 128 frames + EXPECT_EQ(44100, + mock_sink_->GetOutputDeviceInfo().output_params().sample_rate()); + // Expecting hardware buffer size of 128 frames + EXPECT_EQ( + 128, + mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer()); + + EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); + EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); + EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1); + + media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, + kChannelLayout, 32000, kBitsPerChannel, 512); + + media::AudioRendererMixer* mixer = + GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_INTERACTIVE, + kDefaultDeviceId, kSecurityOrigin, nullptr); + +#if defined(OS_CHROMEOS) + // Expecting input sample rate. + EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate()); +#else + // Expecting hardware sample rate. + EXPECT_EQ(44100, mixer->GetOutputParamsForTesting().sample_rate()); +#endif // defined(OS_CHROMEOS) + +#if defined(OS_ANDROID) + // If hardware buffer size (128) is less than 1024, use 2048. + EXPECT_EQ(2048, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#else + // Expect hardware buffer size. + EXPECT_EQ(128, mixer->GetOutputParamsForTesting().frames_per_buffer()); +#endif + + ReturnMixer(mixer); +} + } // namespace content diff --git a/chromium/content/renderer/media/audio_renderer_sink_cache.h b/chromium/content/renderer/media/audio_renderer_sink_cache.h new file mode 100644 index 00000000000..25ab762e8b2 --- /dev/null +++ b/chromium/content/renderer/media/audio_renderer_sink_cache.h @@ -0,0 +1,62 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_SINK_CACHE_H_ +#define CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_SINK_CACHE_H_ + +#include <string> + +#include "content/common/content_export.h" +#include "media/base/output_device_info.h" + +namespace url { +class Origin; +} + +namespace media { +class AudioRendererSink; +} + +namespace content { + +// Caches AudioRendererSink instances, provides them to the clients for usage, +// tracks their used/unused state, reuses them to obtain output device +// information, garbage-collects unused sinks. +// Thread safe. +class CONTENT_EXPORT AudioRendererSinkCache { + public: + virtual ~AudioRendererSinkCache() {} + + // Creates default cache, to be used by AudioRendererMixerManager. + static std::unique_ptr<AudioRendererSinkCache> Create(); + + // Returns output device information for a specified sink. + virtual media::OutputDeviceInfo GetSinkInfo( + int source_render_frame_id, + int session_id, + const std::string& device_id, + const url::Origin& security_origin) = 0; + + // Provides a sink for usage. The sink must be returned to the cache by + // calling ReleaseSink(). The sink must be stopped by the user before + // deletion, but after releasing it from the cache. + virtual scoped_refptr<media::AudioRendererSink> GetSink( + int source_render_frame_id, + const std::string& device_id, + const url::Origin& security_origin) = 0; + + // Notifies the cache that the sink is not in use any more. Must be + // called by the client, so that the cache can garbage-collect the sink + // reference. + virtual void ReleaseSink(const media::AudioRendererSink* sink_ptr) = 0; + + protected: + AudioRendererSinkCache() {} + + DISALLOW_COPY_AND_ASSIGN(AudioRendererSinkCache); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_SINK_CACHE_H_ diff --git a/chromium/content/renderer/media/audio_renderer_sink_cache_impl.cc b/chromium/content/renderer/media/audio_renderer_sink_cache_impl.cc new file mode 100644 index 00000000000..9fef7d0937b --- /dev/null +++ b/chromium/content/renderer/media/audio_renderer_sink_cache_impl.cc @@ -0,0 +1,253 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <algorithm> + +#include "base/bind.h" +#include "base/location.h" +#include "base/memory/ptr_util.h" +#include "base/synchronization/lock.h" +#include "base/threading/thread_task_runner_handle.h" +#include "content/renderer/media/audio_device_factory.h" +#include "content/renderer/media/audio_renderer_sink_cache_impl.h" +#include "media/audio/audio_device_description.h" +#include "media/base/audio_renderer_sink.h" +#include "url/origin.h" + +namespace content { + +constexpr int kDeleteTimeoutMs = 5000; + +// Cached sink data. +struct AudioRendererSinkCacheImpl::CacheEntry { + int source_render_frame_id; + std::string device_id; + url::Origin security_origin; + scoped_refptr<media::AudioRendererSink> sink; // Sink instance + bool used; // True if in use by a client. +}; + +// static +std::unique_ptr<AudioRendererSinkCache> AudioRendererSinkCache::Create() { + return base::WrapUnique(new AudioRendererSinkCacheImpl( + base::ThreadTaskRunnerHandle::Get(), + base::Bind(&AudioDeviceFactory::NewAudioRendererMixerSink), + base::TimeDelta::FromMilliseconds(kDeleteTimeoutMs))); +} + +AudioRendererSinkCacheImpl::AudioRendererSinkCacheImpl( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + const CreateSinkCallback& create_sink_cb, + base::TimeDelta delete_timeout) + : task_runner_(std::move(task_runner)), + create_sink_cb_(create_sink_cb), + delete_timeout_(delete_timeout), + weak_ptr_factory_(this) { + weak_this_ = weak_ptr_factory_.GetWeakPtr(); +} + +AudioRendererSinkCacheImpl::~AudioRendererSinkCacheImpl() { + // We just release all the cached sinks here. +} + +media::OutputDeviceInfo AudioRendererSinkCacheImpl::GetSinkInfo( + int source_render_frame_id, + int session_id, + const std::string& device_id, + const url::Origin& security_origin) { + CacheEntry cache_entry = {source_render_frame_id, + std::string() /* device_id */, security_origin, + nullptr /* sink */, false /* not used */}; + + if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, + device_id)) { + // We are provided with session id instead of device id. Session id is + // unique, so we can't find any matching sink. Creating a new one. + cache_entry.sink = create_sink_cb_.Run(source_render_frame_id, session_id, + device_id, security_origin); + cache_entry.device_id = cache_entry.sink->GetOutputDeviceInfo().device_id(); + + DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() + << " - used session to create new sink."; + + // Cache a newly-created sink. + base::AutoLock auto_lock(cache_lock_); + cache_.push_back(cache_entry); + + } else { + // Ignore session id. + base::AutoLock auto_lock(cache_lock_); + + auto cache_iter = + FindCacheEntry_Locked(source_render_frame_id, device_id, + security_origin, false /* unused_only */); + + if (cache_iter != cache_.end()) { + // A matching cached sink is found. + DVLOG(1) << "GetSinkInfo: address: " << cache_iter->sink.get() + << " - reused a cached sink."; + + return cache_iter->sink->GetOutputDeviceInfo(); + } + + // No matching sink found, create a new one. + cache_entry.device_id = device_id; + cache_entry.sink = create_sink_cb_.Run( + source_render_frame_id, 0 /* session_id */, device_id, security_origin); + + DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() + << " - no matching cached sink found, created a new one."; + + // Cache a newly-created sink. + cache_.push_back(cache_entry); + } + + // Schedule it for deletion. + DeleteLaterIfUnused(cache_entry.sink.get()); + + DVLOG(1) << "GetSinkInfo: address: " << cache_entry.sink.get() + << " created. source_render_frame_id: " << source_render_frame_id + << " session_id: " << session_id << " device_id: " << device_id + << " security_origin: " << security_origin; + + return cache_entry.sink->GetOutputDeviceInfo(); +} + +scoped_refptr<media::AudioRendererSink> AudioRendererSinkCacheImpl::GetSink( + int source_render_frame_id, + const std::string& device_id, + const url::Origin& security_origin) { + base::AutoLock auto_lock(cache_lock_); + + auto cache_iter = + FindCacheEntry_Locked(source_render_frame_id, device_id, security_origin, + true /* unused_only */); + + if (cache_iter != cache_.end()) { + // Found unused sink; mark it as used and return. + DVLOG(1) << "GetSink: address: " << cache_iter->sink.get() + << " - found unused cached sink, reusing it."; + + cache_iter->used = true; + return cache_iter->sink; + } + + // No unused sink is found, create one, mark it used, cache it and return. + CacheEntry cache_entry = { + source_render_frame_id, device_id, security_origin, + create_sink_cb_.Run(source_render_frame_id, 0 /* session_id */, device_id, + security_origin), + true /* used */}; + + cache_.push_back(cache_entry); + + DVLOG(1) << "GetSink: address: " << cache_entry.sink.get() + << " - no unused cached sink found, created a new one." + << " source_render_frame_id: " << source_render_frame_id + << " device_id: " << device_id + << " security_origin: " << security_origin; + return cache_entry.sink; +} + +void AudioRendererSinkCacheImpl::ReleaseSink( + const media::AudioRendererSink* sink_ptr) { + // We don't know the sink state, so won't reuse it. Delete it immediately. + DeleteSink(sink_ptr, true); +} + +void AudioRendererSinkCacheImpl::DeleteLaterIfUnused( + const media::AudioRendererSink* sink_ptr) { + task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&AudioRendererSinkCacheImpl::DeleteSink, weak_this_, + sink_ptr, false /*do not delete if used*/), + delete_timeout_); +} + +void AudioRendererSinkCacheImpl::DeleteSink( + const media::AudioRendererSink* sink_ptr, + bool force_delete_used) { + DCHECK(sink_ptr); + + scoped_refptr<media::AudioRendererSink> sink_to_stop; + + { + base::AutoLock auto_lock(cache_lock_); + + // Looking up the sink by its pointer. + auto cache_iter = std::find_if(cache_.begin(), cache_.end(), + [sink_ptr](const CacheEntry& val) { + return val.sink.get() == sink_ptr; + }); + + if (cache_iter == cache_.end()) { + // If |force_delete_used| is not set it means the sink scheduled for + // deletion got aquired and released before scheduled deletion - it's ok. + DCHECK(!force_delete_used) + << "DeleteSink: address: " << sink_ptr + << " could not find a sink which is supposed to be in use"; + + DVLOG(1) << "DeleteSink: address: " << sink_ptr + << " force_delete_used = false - already deleted."; + return; + } + + // When |force_delete_used| is set, it's expected that we are deleting a + // used sink. + DCHECK((!force_delete_used) || (force_delete_used && cache_iter->used)) + << "Attempt to delete a non-aquired sink."; + + if (!force_delete_used && cache_iter->used) { + DVLOG(1) << "DeleteSink: address: " << sink_ptr + << " sink in use, skipping deletion."; + return; + } + + // To stop the sink before deletion if it's not used, we need to hold + // a ref to it. + if (!cache_iter->used) + sink_to_stop = cache_iter->sink; + + cache_.erase(cache_iter); + DVLOG(1) << "DeleteSink: address: " << sink_ptr; + } // Lock scope; + + // Stop the sink out of the lock scope. + if (sink_to_stop.get()) { + DCHECK_EQ(sink_ptr, sink_to_stop.get()); + sink_to_stop->Stop(); + DVLOG(1) << "DeleteSink: address: " << sink_ptr << " stopped."; + } +} + +AudioRendererSinkCacheImpl::CacheContainer::iterator +AudioRendererSinkCacheImpl::FindCacheEntry_Locked( + int source_render_frame_id, + const std::string& device_id, + const url::Origin& security_origin, + bool unused_only) { + return std::find_if( + cache_.begin(), cache_.end(), + [source_render_frame_id, &device_id, &security_origin, + unused_only](const CacheEntry& val) { + if (val.used && unused_only) + return false; + if (val.source_render_frame_id != source_render_frame_id) + return false; + if (media::AudioDeviceDescription::IsDefaultDevice(device_id) && + media::AudioDeviceDescription::IsDefaultDevice(val.device_id)) { + // Both device IDs represent the same default device => do not compare + // them; the default device is always authorized => ignore security + // origin. + return true; + } + return val.device_id == device_id && + val.security_origin == security_origin; + }); +}; + +int AudioRendererSinkCacheImpl::GetCacheSizeForTesting() { + return cache_.size(); +} + +} // namespace content diff --git a/chromium/content/renderer/media/audio_renderer_sink_cache_impl.h b/chromium/content/renderer/media/audio_renderer_sink_cache_impl.h new file mode 100644 index 00000000000..7d163d9074c --- /dev/null +++ b/chromium/content/renderer/media/audio_renderer_sink_cache_impl.h @@ -0,0 +1,110 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_SINK_CACHE_IMPL_H_ +#define CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_SINK_CACHE_IMPL_H_ + +#include "content/renderer/media/audio_renderer_sink_cache.h" + +#include <vector> + +#include "base/single_thread_task_runner.h" +#include "base/synchronization/lock.h" +#include "base/time/time.h" +#include "content/common/content_export.h" + +namespace content { + +// AudioRendererSinkCache implementation. +class CONTENT_EXPORT AudioRendererSinkCacheImpl + : public AudioRendererSinkCache { + public: + // Callback to be used for AudioRendererSink creation + using CreateSinkCallback = + base::Callback<scoped_refptr<media::AudioRendererSink>( + int render_frame_id, + int session_id, + const std::string& device_id, + const url::Origin& security_origin)>; + + AudioRendererSinkCacheImpl( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + const CreateSinkCallback& create_sink_callback, + base::TimeDelta delete_timeout); + + ~AudioRendererSinkCacheImpl() final; + + media::OutputDeviceInfo GetSinkInfo(int source_render_frame_id, + int session_id, + const std::string& device_id, + const url::Origin& security_origin) final; + + scoped_refptr<media::AudioRendererSink> GetSink( + int source_render_frame_id, + const std::string& device_id, + const url::Origin& security_origin) final; + + void ReleaseSink(const media::AudioRendererSink* sink_ptr) final; + + private: + friend class AudioRendererSinkCacheTest; + friend class CacheEntryFinder; + + struct CacheEntry; + using CacheContainer = std::vector<CacheEntry>; + + // Schedules a sink for deletion. Deletion will be performed on the same + // thread the cache is created on. + void DeleteLaterIfUnused(const media::AudioRendererSink* sink_ptr); + + // Deletes a sink from the cache. If |force_delete_used| is set, a sink being + // deleted can (and should) be in use at the moment of deletion; otherwise the + // sink is deleted only if unused. + void DeleteSink(const media::AudioRendererSink* sink_ptr, + bool force_delete_used); + + CacheContainer::iterator FindCacheEntry_Locked( + int source_render_frame_id, + const std::string& device_id, + const url::Origin& security_origin, + bool unused_only); + + // To avoid publishing CacheEntry structure in the header. + int GetCacheSizeForTesting(); + + // Task runner for scheduled sink garbage collection. + const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + // Callback used for sink creation. + const CreateSinkCallback create_sink_cb_; + + // Cached sink deletion timeout. + // For example: (1) sink was created and cached in GetSinkInfo(), and then (2) + // the same sink is requested in GetSink(), if time interval between (1) and + // (2) is less than |kDeleteTimeoutMs|, then sink cached in (1) is reused in + // (2). On the other hand, if after (1) nobody is interested in the sink + // within |kDeleteTimeoutMs|, it is garbage-collected. + const base::TimeDelta delete_timeout_; + + // Cached sinks, protected by lock. + base::Lock cache_lock_; + CacheContainer cache_; + + // Weak pointer to be used for delayed sink deletion on |task_runner_|. + // Pre-created in constructor and is used to post all the delayed tasks. + // A delayed task can be concurrently posted from any thread the cache is used + // on, so on-the-flight weak pointer creation with + // weak_ptr_factory_.GetWeakPtr() can't be used, because it will result in the + // racy access to the factory. + base::WeakPtr<AudioRendererSinkCacheImpl> weak_this_; + + // Used to produce |weak_this_| on AudioRendererSinkCacheImpl construction. + base::WeakPtrFactory<AudioRendererSinkCacheImpl> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(AudioRendererSinkCacheImpl); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_SINK_CACHE_IMPL_H_ diff --git a/chromium/content/renderer/media/audio_renderer_sink_cache_unittest.cc b/chromium/content/renderer/media/audio_renderer_sink_cache_unittest.cc new file mode 100644 index 00000000000..81e349c24fa --- /dev/null +++ b/chromium/content/renderer/media/audio_renderer_sink_cache_unittest.cc @@ -0,0 +1,374 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <array> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/logging.h" +#include "base/test/test_simple_task_runner.h" +#include "base/test/test_timeouts.h" +#include "content/renderer/media/audio_renderer_sink_cache_impl.h" +#include "media/audio/audio_device_description.h" +#include "media/base/audio_parameters.h" +#include "media/base/mock_audio_renderer_sink.h" +#include "media/base/test_helpers.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace content { + +namespace { +const char* const kDefaultDeviceId = + media::AudioDeviceDescription::kDefaultDeviceId; +const char kAnotherDeviceId[] = "another-device-id"; +const int kRenderFrameId = 124; +const int kDeleteTimeoutMs = 500; +} // namespace + +class AudioRendererSinkCacheTest : public testing::Test { + public: + AudioRendererSinkCacheTest() + : cache_(new AudioRendererSinkCacheImpl( + message_loop_.task_runner(), + base::Bind(&AudioRendererSinkCacheTest::CreateSink, + base::Unretained(this)), + base::TimeDelta::FromMilliseconds(kDeleteTimeoutMs))) {} + + void GetSink(int render_frame_id, + const std::string& device_id, + const url::Origin& security_origin, + media::AudioRendererSink** sink) { + *sink = cache_->GetSink(render_frame_id, device_id, security_origin).get(); + } + + void GetRandomSinkInfo(int frame) { + // Get info and check if memory is not corrupted. + EXPECT_EQ(kDefaultDeviceId, + cache_->GetSinkInfo(frame, 0, kDefaultDeviceId, url::Origin()) + .device_id()); + } + + void GetRandomSink(int frame, base::TimeDelta sleep_timeout) { + scoped_refptr<media::AudioRendererSink> sink = + cache_->GetSink(frame, kDefaultDeviceId, url::Origin()).get(); + ExpectToStop(sink.get()); + base::PlatformThread::Sleep(sleep_timeout); + cache_->ReleaseSink(sink.get()); + sink->Stop(); // Call a method to make the object is not corrupted. + } + + protected: + int sink_count() { + DCHECK(message_loop_.task_runner()->BelongsToCurrentThread()); + return cache_->GetCacheSizeForTesting(); + } + + scoped_refptr<media::AudioRendererSink> CreateSink( + int render_frame_id, + int session_id, + const std::string& device_id, + const url::Origin& security_origin) { + return new media::MockAudioRendererSink(device_id, + media::OUTPUT_DEVICE_STATUS_OK); + } + + void ExpectToStop(media::AudioRendererSink* sink) { + // Sink must be stoped before deletion. + EXPECT_CALL(*static_cast<media::MockAudioRendererSink*>(sink), Stop()) + .Times(1); + } + + void ExpectNotToStop(media::AudioRendererSink* sink) { + // The sink must be stoped before deletion. + EXPECT_CALL(*static_cast<media::MockAudioRendererSink*>(sink), Stop()) + .Times(0); + } + + // Posts the task to the specified thread and runs current message loop until + // the task is completed. + void PostAndRunUntilDone(const base::Thread& thread, + const base::Closure& task) { + media::WaitableMessageLoopEvent event; + thread.task_runner()->PostTaskAndReply(FROM_HERE, task, event.GetClosure()); + // Runs the loop and waits for the thread to call event's closure. + event.RunAndWait(); + } + + void WaitOnAnotherThread(const base::Thread& thread, int timeout_ms) { + PostAndRunUntilDone( + thread, base::Bind(base::IgnoreResult(&base::PlatformThread::Sleep), + base::TimeDelta::FromMilliseconds(timeout_ms))); + } + + base::MessageLoop message_loop_; + std::unique_ptr<AudioRendererSinkCacheImpl> cache_; + + private: + DISALLOW_COPY_AND_ASSIGN(AudioRendererSinkCacheTest); +}; + +// Verify that normal get/release sink sequence works. +TEST_F(AudioRendererSinkCacheTest, GetReleaseSink) { + // Verify that a new sink is successfully created. + EXPECT_EQ(0, sink_count()); + scoped_refptr<media::AudioRendererSink> sink = + cache_->GetSink(kRenderFrameId, kDefaultDeviceId, url::Origin()).get(); + ExpectNotToStop(sink.get()); // Cache should not stop sinks marked as used. + EXPECT_EQ(kDefaultDeviceId, sink->GetOutputDeviceInfo().device_id()); + EXPECT_EQ(1, sink_count()); + + // Verify that another sink with the same key is successfully created + scoped_refptr<media::AudioRendererSink> another_sink = + cache_->GetSink(kRenderFrameId, kDefaultDeviceId, url::Origin()).get(); + ExpectNotToStop(another_sink.get()); + EXPECT_EQ(kDefaultDeviceId, another_sink->GetOutputDeviceInfo().device_id()); + EXPECT_EQ(2, sink_count()); + EXPECT_NE(sink, another_sink); + + // Verify that another sink with a different kay is successfully created. + scoped_refptr<media::AudioRendererSink> yet_another_sink = + cache_->GetSink(kRenderFrameId, kAnotherDeviceId, url::Origin()).get(); + ExpectNotToStop(yet_another_sink.get()); + EXPECT_EQ(kAnotherDeviceId, + yet_another_sink->GetOutputDeviceInfo().device_id()); + EXPECT_EQ(3, sink_count()); + EXPECT_NE(sink, yet_another_sink); + EXPECT_NE(another_sink, yet_another_sink); + + // Verify that the first sink is successfully deleted. + cache_->ReleaseSink(sink.get()); + EXPECT_EQ(2, sink_count()); + sink = nullptr; + + // Make sure we deleted the right sink, and the memory for the rest is not + // corrupted. + EXPECT_EQ(kDefaultDeviceId, another_sink->GetOutputDeviceInfo().device_id()); + EXPECT_EQ(kAnotherDeviceId, + yet_another_sink->GetOutputDeviceInfo().device_id()); + + // Verify that the second sink is successfully deleted. + cache_->ReleaseSink(another_sink.get()); + EXPECT_EQ(1, sink_count()); + EXPECT_EQ(kAnotherDeviceId, + yet_another_sink->GetOutputDeviceInfo().device_id()); + + cache_->ReleaseSink(yet_another_sink.get()); + EXPECT_EQ(0, sink_count()); +} + +// Verify that the sink created with GetSinkInfo() is reused when possible. +TEST_F(AudioRendererSinkCacheTest, GetDeviceInfo) { + EXPECT_EQ(0, sink_count()); + media::OutputDeviceInfo device_info = + cache_->GetSinkInfo(kRenderFrameId, 0, kDefaultDeviceId, url::Origin()); + EXPECT_EQ(1, sink_count()); + + // The info on the same device is requested, so no new sink is created. + media::OutputDeviceInfo one_more_device_info = + cache_->GetSinkInfo(kRenderFrameId, 0, kDefaultDeviceId, url::Origin()); + EXPECT_EQ(1, sink_count()); + EXPECT_EQ(device_info.device_id(), one_more_device_info.device_id()); + + // Aquire the sink that was created on GetSinkInfo(). + scoped_refptr<media::AudioRendererSink> sink = + cache_->GetSink(kRenderFrameId, kDefaultDeviceId, url::Origin()).get(); + EXPECT_EQ(1, sink_count()); + EXPECT_EQ(device_info.device_id(), sink->GetOutputDeviceInfo().device_id()); + + // Now the sink is in used, but we can still get the device info out of it, no + // new sink is created. + one_more_device_info = + cache_->GetSinkInfo(kRenderFrameId, 0, kDefaultDeviceId, url::Origin()); + EXPECT_EQ(1, sink_count()); + EXPECT_EQ(device_info.device_id(), one_more_device_info.device_id()); + + // Request sink for the same device. The first sink is in use, so a new one + // should be created. + scoped_refptr<media::AudioRendererSink> another_sink = + cache_->GetSink(kRenderFrameId, kDefaultDeviceId, url::Origin()).get(); + EXPECT_EQ(2, sink_count()); + EXPECT_EQ(device_info.device_id(), + another_sink->GetOutputDeviceInfo().device_id()); +} + +// Verify that the sink created with GetSinkInfo() is deleted if unused. +// The test produces 2 "Uninteresting mock" warnings for +// MockAudioRendererSink::Stop(). +TEST_F(AudioRendererSinkCacheTest, GarbageCollection) { + EXPECT_EQ(0, sink_count()); + media::OutputDeviceInfo device_info = + cache_->GetSinkInfo(kRenderFrameId, 0, kDefaultDeviceId, url::Origin()); + EXPECT_EQ(1, sink_count()); + + media::OutputDeviceInfo another_device_info = + cache_->GetSinkInfo(kRenderFrameId, 0, kAnotherDeviceId, url::Origin()); + EXPECT_EQ(2, sink_count()); + + base::Thread thread("timeout_thread"); + thread.Start(); + + // 100 ms more than garbage collection timeout. + WaitOnAnotherThread(thread, kDeleteTimeoutMs + 100); + + // All the sinks should be garbage-collected by now. + EXPECT_EQ(0, sink_count()); +} + +// Verify that the sink created with GetSinkInfo() is not deleted if used within +// the timeout. +TEST_F(AudioRendererSinkCacheTest, NoGarbageCollectionForUsedSink) { + EXPECT_EQ(0, sink_count()); + media::OutputDeviceInfo device_info = + cache_->GetSinkInfo(kRenderFrameId, 0, kDefaultDeviceId, url::Origin()); + EXPECT_EQ(1, sink_count()); + + base::Thread thread("timeout_thread"); + thread.Start(); + + // Wait significantly less than grabage collection timeout. + int wait_a_bit = 100; + DCHECK_GT(kDeleteTimeoutMs, wait_a_bit * 2); + WaitOnAnotherThread(thread, wait_a_bit); + + // Sink is not deleted yet. + EXPECT_EQ(1, sink_count()); + + // Request it: + scoped_refptr<media::AudioRendererSink> sink = + cache_->GetSink(kRenderFrameId, kDefaultDeviceId, url::Origin()).get(); + EXPECT_EQ(kDefaultDeviceId, sink->GetOutputDeviceInfo().device_id()); + EXPECT_EQ(1, sink_count()); + + // Wait more to hit garbage collection timeout. + WaitOnAnotherThread(thread, kDeleteTimeoutMs); + + // The sink is still in place. + EXPECT_EQ(1, sink_count()); +} + +// Verify that cache works fine if a sink scheduled for delettion is aquired and +// released before deletion timeout elapses. +// The test produces one "Uninteresting mock" warning for +// MockAudioRendererSink::Stop(). +TEST_F(AudioRendererSinkCacheTest, ReleaseSinkBeforeScheduledDeletion) { + EXPECT_EQ(0, sink_count()); + + media::OutputDeviceInfo device_info = + cache_->GetSinkInfo(kRenderFrameId, 0, kDefaultDeviceId, url::Origin()); + EXPECT_EQ(1, sink_count()); // This sink is scheduled for deletion now. + + // Request it: + scoped_refptr<media::AudioRendererSink> sink = + cache_->GetSink(kRenderFrameId, kDefaultDeviceId, url::Origin()).get(); + ExpectNotToStop(sink.get()); + EXPECT_EQ(1, sink_count()); + + // Release it: + cache_->ReleaseSink(sink.get()); + EXPECT_EQ(0, sink_count()); + + media::OutputDeviceInfo another_device_info = + cache_->GetSinkInfo(kRenderFrameId, 0, kAnotherDeviceId, url::Origin()); + EXPECT_EQ(1, sink_count()); // This sink is scheduled for deletion now. + + base::Thread thread("timeout_thread"); + thread.Start(); + + // 100 ms more than garbage collection timeout. + WaitOnAnotherThread(thread, kDeleteTimeoutMs + 100); + + // Nothing crashed and the second sink deleted on schedule. + EXPECT_EQ(0, sink_count()); +} + +// Check that a sink created on one thread in response to GetSinkInfo can be +// used on another thread. +TEST_F(AudioRendererSinkCacheTest, MultithreadedAccess) { + EXPECT_EQ(0, sink_count()); + + base::Thread thread1("thread1"); + thread1.Start(); + + base::Thread thread2("thread2"); + thread2.Start(); + + // Request device information on the first thread. + PostAndRunUntilDone( + thread1, + base::Bind(base::IgnoreResult(&AudioRendererSinkCacheImpl::GetSinkInfo), + base::Unretained(cache_.get()), kRenderFrameId, 0, + kDefaultDeviceId, url::Origin())); + + EXPECT_EQ(1, sink_count()); + + // Request the sink on the second thread. + media::AudioRendererSink* sink; + + PostAndRunUntilDone( + thread2, + base::Bind(&AudioRendererSinkCacheTest::GetSink, base::Unretained(this), + kRenderFrameId, kDefaultDeviceId, url::Origin(), &sink)); + + EXPECT_EQ(kDefaultDeviceId, sink->GetOutputDeviceInfo().device_id()); + EXPECT_EQ(1, sink_count()); + + // Request device information on the first thread again. + PostAndRunUntilDone( + thread1, + base::Bind(base::IgnoreResult(&AudioRendererSinkCacheImpl::GetSinkInfo), + base::Unretained(cache_.get()), kRenderFrameId, 0, + kDefaultDeviceId, url::Origin())); + EXPECT_EQ(1, sink_count()); + + // Release the sink on the second thread. + PostAndRunUntilDone(thread2, + base::Bind(&AudioRendererSinkCache::ReleaseSink, + base::Unretained(cache_.get()), sink)); + + EXPECT_EQ(0, sink_count()); +} + +// Intensive parallell access to the cache. Produces a ton of "Uninteresting +// mock" warnings for Stop() calls - this is fine. +TEST_F(AudioRendererSinkCacheTest, SmokeTest) { + const int kExperimentSize = 1000; + const int kSinkCount = 10; + const int kThreadCount = 3; + + // Sleep no more than (kDeleteTimeoutMs * 3) in total per thread. + const base::TimeDelta kSleepTimeout = + base::TimeDelta::FromMilliseconds(kDeleteTimeoutMs * 3 / kExperimentSize); + + srand(42); // Does not matter. + + std::array<std::unique_ptr<base::Thread>, kThreadCount> threads; + for (int i = 0; i < kThreadCount; ++i) { + threads[i].reset(new base::Thread(std::to_string(i))); + threads[i]->Start(); + } + + for (int i = 0; i < kExperimentSize; ++i) { + for (auto& thread : threads) { + thread->task_runner()->PostTask( + FROM_HERE, base::Bind(&AudioRendererSinkCacheTest::GetRandomSinkInfo, + base::Unretained(this), rand() % kSinkCount)); + thread->task_runner()->PostTask( + FROM_HERE, base::Bind(&AudioRendererSinkCacheTest::GetRandomSink, + base::Unretained(this), rand() % kSinkCount, + kSleepTimeout)); + } + } + + // Wait for completion of all the tasks posted to at least one thread. + media::WaitableMessageLoopEvent loop_event( + TestTimeouts::action_max_timeout()); + threads[kThreadCount - 1]->task_runner()->PostTaskAndReply( + FROM_HERE, base::Bind(&base::DoNothing), loop_event.GetClosure()); + // Runs the loop and waits for the thread to call event's closure. + loop_event.RunAndWait(); +} + +} // namespace content diff --git a/chromium/content/renderer/media/audio_track_recorder.cc b/chromium/content/renderer/media/audio_track_recorder.cc index 603cbd99597..5d5e75235fa 100644 --- a/chromium/content/renderer/media/audio_track_recorder.cc +++ b/chromium/content/renderer/media/audio_track_recorder.cc @@ -15,6 +15,7 @@ #include "media/base/audio_converter.h" #include "media/base/audio_fifo.h" #include "media/base/audio_parameters.h" +#include "media/base/audio_sample_types.h" #include "media/base/bind_to_current_loop.h" #include "third_party/opus/src/include/opus.h" @@ -76,19 +77,6 @@ bool DoEncode(OpusEncoder* opus_encoder, return false; } -// Interleaves |audio_bus| channels() of floats into a single output linear -// |buffer|. -// TODO(mcasas) https://crbug.com/580391 use AudioBus::ToInterleavedFloat(). -void ToInterleaved(media::AudioBus* audio_bus, float* buffer) { - for (int ch = 0; ch < audio_bus->channels(); ++ch) { - const float* src = audio_bus->channel(ch); - const float* const src_end = src + audio_bus->frames(); - float* dest = buffer + ch; - for (; src < src_end; ++src, dest += audio_bus->channels()) - *dest = *src; - } -} - } // anonymous namespace // Nested class encapsulating opus-related encoding details. It contains an @@ -119,7 +107,7 @@ class AudioTrackRecorder::AudioEncoder // media::AudioConverted::InputCallback implementation. double ProvideInput(media::AudioBus* audio_bus, - base::TimeDelta buffer_delay) override; + uint32_t frames_delayed) override; void DestroyExistingOpusEncoder(); @@ -259,7 +247,8 @@ void AudioTrackRecorder::AudioEncoder::EncodeAudio( std::unique_ptr<media::AudioBus> audio_bus = media::AudioBus::Create( output_params_.channels(), kOpusPreferredFramesPerBuffer); converter_->Convert(audio_bus.get()); - ToInterleaved(audio_bus.get(), buffer_.get()); + audio_bus->ToInterleaved<media::Float32SampleTypeTraits>( + audio_bus->frames(), buffer_.get()); std::unique_ptr<std::string> encoded_data(new std::string()); if (DoEncode(opus_encoder_, buffer_.get(), kOpusPreferredFramesPerBuffer, @@ -277,7 +266,7 @@ void AudioTrackRecorder::AudioEncoder::EncodeAudio( double AudioTrackRecorder::AudioEncoder::ProvideInput( media::AudioBus* audio_bus, - base::TimeDelta buffer_delay) { + uint32_t frames_delayed) { fifo_->Consume(audio_bus, 0, audio_bus->frames()); return 1.0; // Return volume greater than zero to indicate we have more data. } diff --git a/chromium/content/renderer/media/canvas_capture_handler.cc b/chromium/content/renderer/media/canvas_capture_handler.cc index 91d67f7e5d6..11f9ed7d43c 100644 --- a/chromium/content/renderer/media/canvas_capture_handler.cc +++ b/chromium/content/renderer/media/canvas_capture_handler.cc @@ -20,6 +20,7 @@ #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/libyuv/include/libyuv.h" +#include "third_party/skia/include/core/SkImage.h" namespace { @@ -288,7 +289,7 @@ void CanvasCaptureHandler::AddVideoCapturerSourceToVideoTrack( web_track->initialize(webkit_source); blink::WebMediaConstraints constraints; constraints.initialize(); - web_track->setExtraData(new MediaStreamVideoTrack( + web_track->setTrackData(new MediaStreamVideoTrack( media_stream_source.release(), constraints, MediaStreamVideoSource::ConstraintsCallback(), true)); } diff --git a/chromium/content/renderer/media/canvas_capture_handler.h b/chromium/content/renderer/media/canvas_capture_handler.h index 4df1692223a..d4cd2568311 100644 --- a/chromium/content/renderer/media/canvas_capture_handler.h +++ b/chromium/content/renderer/media/canvas_capture_handler.h @@ -19,7 +19,9 @@ #include "third_party/WebKit/public/platform/WebCanvasCaptureHandler.h" #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" #include "third_party/WebKit/public/platform/WebSize.h" -#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkImageInfo.h" + +class SkImage; namespace content { diff --git a/chromium/content/renderer/media/canvas_capture_handler_unittest.cc b/chromium/content/renderer/media/canvas_capture_handler_unittest.cc index 98fe1c7d4fc..117fa8953a9 100644 --- a/chromium/content/renderer/media/canvas_capture_handler_unittest.cc +++ b/chromium/content/renderer/media/canvas_capture_handler_unittest.cc @@ -15,6 +15,8 @@ #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" #include "third_party/WebKit/public/platform/WebSize.h" #include "third_party/WebKit/public/web/WebHeap.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkRefCnt.h" using ::testing::_; using ::testing::InSequence; diff --git a/chromium/content/renderer/media/cdm/renderer_cdm_manager.cc b/chromium/content/renderer/media/cdm/renderer_cdm_manager.cc index 67402da7a84..4bf322a15fa 100644 --- a/chromium/content/renderer/media/cdm/renderer_cdm_manager.cc +++ b/chromium/content/renderer/media/cdm/renderer_cdm_manager.cc @@ -50,6 +50,10 @@ bool RendererCdmManager::OnMessageReceived(const IPC::Message& msg) { return handled; } +void RendererCdmManager::OnDestruct() { + delete this; +} + void RendererCdmManager::InitializeCdm(int cdm_id, uint32_t promise_id, ProxyMediaKeys* media_keys, diff --git a/chromium/content/renderer/media/cdm/renderer_cdm_manager.h b/chromium/content/renderer/media/cdm/renderer_cdm_manager.h index e25ce556d49..143d8035be4 100644 --- a/chromium/content/renderer/media/cdm/renderer_cdm_manager.h +++ b/chromium/content/renderer/media/cdm/renderer_cdm_manager.h @@ -74,6 +74,9 @@ class RendererCdmManager : public RenderFrameObserver { void UnregisterMediaKeys(int cdm_id); private: + // RenderFrameObserver implementation. + void OnDestruct() override; + // Gets the pointer to ProxyMediaKeys given the |cdm_id|. ProxyMediaKeys* GetMediaKeys(int cdm_id); diff --git a/chromium/content/renderer/media/gpu/OWNERS b/chromium/content/renderer/media/gpu/OWNERS new file mode 100644 index 00000000000..a1be1928a1c --- /dev/null +++ b/chromium/content/renderer/media/gpu/OWNERS @@ -0,0 +1,2 @@ +posciak@chromium.org +wuchengli@chromium.org diff --git a/chromium/content/renderer/media/rtc_video_decoder.cc b/chromium/content/renderer/media/gpu/rtc_video_decoder.cc index 32de1175114..1729882ab0d 100644 --- a/chromium/content/renderer/media/rtc_video_decoder.cc +++ b/chromium/content/renderer/media/gpu/rtc_video_decoder.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/rtc_video_decoder.h" +#include "content/renderer/media/gpu/rtc_video_decoder.h" #include <utility> @@ -67,6 +67,7 @@ RTCVideoDecoder::RTCVideoDecoder(webrtc::VideoCodecType type, video_codec_type_(type), factories_(factories), decoder_texture_target_(0), + pixel_format_(media::PIXEL_FORMAT_UNKNOWN), next_picture_buffer_id_(0), state_(UNINITIALIZED), decode_complete_callback_(nullptr), @@ -120,7 +121,8 @@ std::unique_ptr<RTCVideoDecoder> RTCVideoDecoder::Create( return decoder; } - base::WaitableEvent waiter(true, false); + base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); decoder.reset(new RTCVideoDecoder(type, factories)); decoder->factories_->GetTaskRunner()->PostTask( FROM_HERE, @@ -234,6 +236,10 @@ int32_t RTCVideoDecoder::Decode( reset_bitstream_buffer_id_)) { // TODO(wuchengli): VDA should handle it. Remove this when // http://crosbug.com/p/21913 is fixed. + + // If we're are in an error condition, increase the counter. + vda_error_counter_ += vda_error_counter_ ? 1 : 0; + DVLOG(1) << "The first frame should be a key frame. Drop this."; return WEBRTC_VIDEO_CODEC_ERROR; } @@ -267,8 +273,6 @@ int32_t RTCVideoDecoder::Decode( base::AutoUnlock auto_unlock(lock_); Release(); } - - TryResetVDAErrorCounter_Locked(); return WEBRTC_VIDEO_CODEC_OK; } @@ -277,7 +281,6 @@ int32_t RTCVideoDecoder::Decode( FROM_HERE, base::Bind(&RTCVideoDecoder::RequestBufferDecode, weak_factory_.GetWeakPtr())); - TryResetVDAErrorCounter_Locked(); return WEBRTC_VIDEO_CODEC_OK; } @@ -315,6 +318,7 @@ int32_t RTCVideoDecoder::Release() { } void RTCVideoDecoder::ProvidePictureBuffers(uint32_t count, + media::VideoPixelFormat format, uint32_t textures_per_buffer, const gfx::Size& size, uint32_t texture_target) { @@ -328,6 +332,17 @@ void RTCVideoDecoder::ProvidePictureBuffers(uint32_t count, std::vector<uint32_t> texture_ids; std::vector<gpu::Mailbox> texture_mailboxes; decoder_texture_target_ = texture_target; + + if (format == media::PIXEL_FORMAT_UNKNOWN) + format = media::PIXEL_FORMAT_ARGB; + + if ((pixel_format_ != media::PIXEL_FORMAT_UNKNOWN) && + (format != pixel_format_)) { + NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); + return; + } + + pixel_format_ = format; if (!factories_->CreateTextures(count, size, &texture_ids, @@ -404,12 +419,8 @@ void RTCVideoDecoder::PictureReady(const media::Picture& picture) { return; } - media::VideoPixelFormat pixel_format = vda_->GetOutputFormat(); - if (pixel_format == media::PIXEL_FORMAT_UNKNOWN) - pixel_format = media::PIXEL_FORMAT_ARGB; - scoped_refptr<media::VideoFrame> frame = - CreateVideoFrame(picture, pb, timestamp, visible_rect, pixel_format); + CreateVideoFrame(picture, pb, timestamp, visible_rect, pixel_format_); if (!frame) { NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); return; @@ -433,6 +444,8 @@ void RTCVideoDecoder::PictureReady(const media::Picture& picture) { reset_bitstream_buffer_id_)) { decode_complete_callback_->Decoded(decoded_image); } + // Reset error counter as we successfully decoded a frame. + vda_error_counter_ = 0; } } @@ -879,12 +892,4 @@ void RTCVideoDecoder::ClearPendingBuffers() { pending_buffers_.clear(); } -void RTCVideoDecoder::TryResetVDAErrorCounter_Locked() { - lock_.AssertAcquired(); - - if (vda_error_counter_ == 0) - return; - vda_error_counter_ = 0; -} - } // namespace content diff --git a/chromium/content/renderer/media/rtc_video_decoder.h b/chromium/content/renderer/media/gpu/rtc_video_decoder.h index 68d1c4baa76..274f6dfb6f6 100644 --- a/chromium/content/renderer/media/rtc_video_decoder.h +++ b/chromium/content/renderer/media/gpu/rtc_video_decoder.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_RTC_VIDEO_DECODER_H_ -#define CONTENT_RENDERER_MEDIA_RTC_VIDEO_DECODER_H_ +#ifndef CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_DECODER_H_ +#define CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_DECODER_H_ #include <stddef.h> #include <stdint.h> @@ -82,6 +82,7 @@ class CONTENT_EXPORT RTCVideoDecoder // VideoDecodeAccelerator::Client implementation. void ProvidePictureBuffers(uint32_t count, + media::VideoPixelFormat format, uint32_t textures_per_buffer, const gfx::Size& size, uint32_t texture_target) override; @@ -200,9 +201,6 @@ class CONTENT_EXPORT RTCVideoDecoder // Clears the pending_buffers_ queue, freeing memory. void ClearPendingBuffers(); - // Resets |vda_error_counter_| after a successfull run of decode. - void TryResetVDAErrorCounter_Locked(); - enum State { UNINITIALIZED, // The decoder has not initialized. INITIALIZED, // The decoder has initialized. @@ -233,6 +231,9 @@ class CONTENT_EXPORT RTCVideoDecoder // The texture target used for decoded pictures. uint32_t decoder_texture_target_; + // The format of the decoded pictures. + media::VideoPixelFormat pixel_format_; + // Metadata of the buffers that have been sent for decode. std::list<BufferData> input_buffer_data_; @@ -302,4 +303,4 @@ class CONTENT_EXPORT RTCVideoDecoder } // namespace content -#endif // CONTENT_RENDERER_MEDIA_RTC_VIDEO_DECODER_H_ +#endif // CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_DECODER_H_ diff --git a/chromium/content/renderer/media/rtc_video_decoder_factory.cc b/chromium/content/renderer/media/gpu/rtc_video_decoder_factory.cc index 0802698385e..04b9c1c648b 100644 --- a/chromium/content/renderer/media/rtc_video_decoder_factory.cc +++ b/chromium/content/renderer/media/gpu/rtc_video_decoder_factory.cc @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/rtc_video_decoder_factory.h" +#include "content/renderer/media/gpu/rtc_video_decoder_factory.h" #include <memory> -#include "content/renderer/media/rtc_video_decoder.h" +#include "content/renderer/media/gpu/rtc_video_decoder.h" #include "media/renderers/gpu_video_accelerator_factories.h" namespace content { diff --git a/chromium/content/renderer/media/rtc_video_decoder_factory.h b/chromium/content/renderer/media/gpu/rtc_video_decoder_factory.h index 7212b98bc78..5d53b2b125a 100644 --- a/chromium/content/renderer/media/rtc_video_decoder_factory.h +++ b/chromium/content/renderer/media/gpu/rtc_video_decoder_factory.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_RTC_VIDEO_DECODER_FACTORY_H_ -#define CONTENT_RENDERER_MEDIA_RTC_VIDEO_DECODER_FACTORY_H_ +#ifndef CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_DECODER_FACTORY_H_ +#define CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_DECODER_FACTORY_H_ #include "base/macros.h" #include "base/threading/thread.h" @@ -46,4 +46,4 @@ class CONTENT_EXPORT RTCVideoDecoderFactory } // namespace content -#endif // CONTENT_RENDERER_MEDIA_RTC_VIDEO_DECODER_FACTORY_H_ +#endif // CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_DECODER_FACTORY_H_ diff --git a/chromium/content/renderer/media/rtc_video_decoder_unittest.cc b/chromium/content/renderer/media/gpu/rtc_video_decoder_unittest.cc index a3150048e8e..151e8fcb285 100644 --- a/chromium/content/renderer/media/rtc_video_decoder_unittest.cc +++ b/chromium/content/renderer/media/gpu/rtc_video_decoder_unittest.cc @@ -11,7 +11,7 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" -#include "content/renderer/media/rtc_video_decoder.h" +#include "content/renderer/media/gpu/rtc_video_decoder.h" #include "media/base/gmock_callback_support.h" #include "media/renderers/mock_gpu_video_accelerator_factories.h" #include "media/video/mock_video_decode_accelerator.h" @@ -49,7 +49,8 @@ class RTCVideoDecoderTest : mock_gpu_factories_( new media::MockGpuVideoAcceleratorFactories(nullptr)), vda_thread_("vda_thread"), - idle_waiter_(false, false) { + idle_waiter_(base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED) { memset(&codec_, 0, sizeof(codec_)); } @@ -281,7 +282,8 @@ TEST_F(RTCVideoDecoderTest, IsFirstBufferAfterReset) { rtc_decoder_->IsFirstBufferAfterReset(1, RTCVideoDecoder::ID_LAST)); } - +// Tests/Verifies that |rtc_encoder_| drops incoming frames and its error +// counter is increased when in an error condition. TEST_P(RTCVideoDecoderTest, GetVDAErrorCounterForTesting) { const webrtc::VideoCodecType codec_type = GetParam(); CreateDecoder(codec_type); @@ -292,6 +294,7 @@ TEST_P(RTCVideoDecoderTest, GetVDAErrorCounterForTesting) { input_image._encodedWidth = kMinResolutionWidth; input_image._encodedHeight = kMaxResolutionHeight; input_image._frameType = webrtc::kVideoFrameDelta; + input_image._length = kMinResolutionWidth * kMaxResolutionHeight; EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); RunUntilIdle(); @@ -307,16 +310,11 @@ TEST_P(RTCVideoDecoderTest, GetVDAErrorCounterForTesting) { rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); EXPECT_EQ(1, rtc_decoder_->GetVDAErrorCounterForTesting()); - // Decoder expects a keyframe after reset, so drops any other frames. + // Decoder expects a keyframe after reset, so drops any other frames. However, + // we should still increment the error counter. EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); - EXPECT_EQ(1, rtc_decoder_->GetVDAErrorCounterForTesting()); - - // Decoder resets error counter after a successfull decode. - input_image._frameType = webrtc::kVideoFrameKey; - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 10)); - EXPECT_EQ(0, rtc_decoder_->GetVDAErrorCounterForTesting()); + EXPECT_EQ(2, rtc_decoder_->GetVDAErrorCounterForTesting()); } INSTANTIATE_TEST_CASE_P(CodecProfiles, diff --git a/chromium/content/renderer/media/rtc_video_encoder.cc b/chromium/content/renderer/media/gpu/rtc_video_encoder.cc index 103e0c102b0..9cf55df82d3 100644 --- a/chromium/content/renderer/media/rtc_video_encoder.cc +++ b/chromium/content/renderer/media/gpu/rtc_video_encoder.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/rtc_video_encoder.h" +#include "content/renderer/media/gpu/rtc_video_encoder.h" #include <string.h> @@ -149,7 +149,8 @@ class RTCVideoEncoder::Impl size_t output_buffer_size) override; void BitstreamBufferReady(int32_t bitstream_buffer_id, size_t payload_size, - bool key_frame) override; + bool key_frame, + base::TimeDelta timestamp) override; void NotifyError(media::VideoEncodeAccelerator::Error error) override; private: @@ -449,12 +450,13 @@ void RTCVideoEncoder::Impl::RequireBitstreamBuffers( } void RTCVideoEncoder::Impl::BitstreamBufferReady(int32_t bitstream_buffer_id, - size_t payload_size, - bool key_frame) { - DVLOG(3) << "Impl::BitstreamBufferReady(): " - "bitstream_buffer_id=" << bitstream_buffer_id - << ", payload_size=" << payload_size - << ", key_frame=" << key_frame; + size_t payload_size, + bool key_frame, + base::TimeDelta timestamp) { + DVLOG(3) << "Impl::BitstreamBufferReady(): bitstream_buffer_id=" + << bitstream_buffer_id << ", payload_size=" << payload_size + << ", key_frame=" << key_frame + << ", timestamp ms=" << timestamp.InMilliseconds(); DCHECK(thread_checker_.CalledOnValidThread()); if (bitstream_buffer_id < 0 || @@ -471,14 +473,17 @@ void RTCVideoEncoder::Impl::BitstreamBufferReady(int32_t bitstream_buffer_id, } output_buffers_free_count_--; - // Use webrtc timestamps to ensure correct RTP sender behavior. - // TODO(hshi): obtain timestamp from the capturer, see crbug.com/350106. + // CrOS Nyan provides invalid timestamp. Use the current time for now. + // TODO(wuchengli): use the timestamp in BitstreamBufferReady after Nyan is + // fixed. http://crbug.com/620565. const int64_t capture_time_us = rtc::TimeMicros(); // Derive the capture time (in ms) and RTP timestamp (in 90KHz ticks). - const int64_t capture_time_ms = capture_time_us / 1000; - const uint32_t rtp_timestamp = - static_cast<uint32_t>(capture_time_us * 90 / 1000); + const int64_t capture_time_ms = + capture_time_us / base::Time::kMicrosecondsPerMillisecond; + + const uint32_t rtp_timestamp = static_cast<uint32_t>( + capture_time_us * 90 / base::Time::kMicrosecondsPerMillisecond); webrtc::EncodedImage image( reinterpret_cast<uint8_t*>(output_buffer->memory()), payload_size, @@ -568,7 +573,7 @@ void RTCVideoEncoder::Impl::EncodeOneFrame() { gfx::Rect(input_visible_size_), input_visible_size_, reinterpret_cast<uint8_t*>(input_buffer->memory()), input_buffer->mapped_size(), input_buffer->handle(), 0, - base::TimeDelta()); + base::TimeDelta::FromMilliseconds(next_frame->ntp_time_ms())); if (!frame.get()) { LogAndNotifyError(FROM_HERE, "failed to create frame", media::VideoEncodeAccelerator::kPlatformFailureError); @@ -740,7 +745,9 @@ int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, const media::VideoCodecProfile profile = WebRTCVideoCodecToVideoCodecProfile( impl_->video_codec_type(), codec_settings); - base::WaitableEvent initialization_waiter(true, false); + base::WaitableEvent initialization_waiter( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; gpu_task_runner_->PostTask( FROM_HERE, @@ -770,7 +777,9 @@ int32_t RTCVideoEncoder::Encode( const bool want_key_frame = frame_types && frame_types->size() && frame_types->front() == webrtc::kVideoFrameKey; - base::WaitableEvent encode_waiter(true, false); + base::WaitableEvent encode_waiter( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; gpu_task_runner_->PostTask( FROM_HERE, @@ -795,7 +804,9 @@ int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback( return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } - base::WaitableEvent register_waiter(true, false); + base::WaitableEvent register_waiter( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); int32_t register_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; gpu_task_runner_->PostTask( FROM_HERE, @@ -810,7 +821,9 @@ int32_t RTCVideoEncoder::Release() { if (!impl_.get()) return WEBRTC_VIDEO_CODEC_OK; - base::WaitableEvent release_waiter(true, false); + base::WaitableEvent release_waiter( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); gpu_task_runner_->PostTask( FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_, &release_waiter)); diff --git a/chromium/content/renderer/media/rtc_video_encoder.h b/chromium/content/renderer/media/gpu/rtc_video_encoder.h index c71c3baaf59..6f8053f3957 100644 --- a/chromium/content/renderer/media/rtc_video_encoder.h +++ b/chromium/content/renderer/media/gpu/rtc_video_encoder.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_H_ -#define CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_H_ +#ifndef CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_ENCODER_H_ +#define CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_ENCODER_H_ #include <stddef.h> #include <stdint.h> @@ -80,4 +80,4 @@ class CONTENT_EXPORT RTCVideoEncoder } // namespace content -#endif // CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_H_ +#endif // CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_ENCODER_H_ diff --git a/chromium/content/renderer/media/rtc_video_encoder_factory.cc b/chromium/content/renderer/media/gpu/rtc_video_encoder_factory.cc index 7e99b7c1386..9295464f758 100644 --- a/chromium/content/renderer/media/rtc_video_encoder_factory.cc +++ b/chromium/content/renderer/media/gpu/rtc_video_encoder_factory.cc @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/rtc_video_encoder_factory.h" +#include "content/renderer/media/gpu/rtc_video_encoder_factory.h" #include "base/command_line.h" #include "content/public/common/content_switches.h" #include "content/public/common/feature_h264_with_openh264_ffmpeg.h" -#include "content/renderer/media/rtc_video_encoder.h" +#include "content/renderer/media/gpu/rtc_video_encoder.h" #include "media/gpu/ipc/client/gpu_video_encode_accelerator_host.h" #include "media/renderers/gpu_video_accelerator_factories.h" #include "media/video/video_encode_accelerator.h" diff --git a/chromium/content/renderer/media/rtc_video_encoder_factory.h b/chromium/content/renderer/media/gpu/rtc_video_encoder_factory.h index 45b48ca82e1..efe538d33e8 100644 --- a/chromium/content/renderer/media/rtc_video_encoder_factory.h +++ b/chromium/content/renderer/media/gpu/rtc_video_encoder_factory.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_FACTORY_H_ -#define CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_FACTORY_H_ +#ifndef CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_ENCODER_FACTORY_H_ +#define CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_ENCODER_FACTORY_H_ #include <vector> @@ -45,4 +45,4 @@ class CONTENT_EXPORT RTCVideoEncoderFactory } // namespace content -#endif // CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_FACTORY_H_ +#endif // CONTENT_RENDERER_MEDIA_GPU_RTC_VIDEO_ENCODER_FACTORY_H_ diff --git a/chromium/content/renderer/media/html_audio_element_capturer_source.cc b/chromium/content/renderer/media/html_audio_element_capturer_source.cc new file mode 100644 index 00000000000..7e0edfc9768 --- /dev/null +++ b/chromium/content/renderer/media/html_audio_element_capturer_source.cc @@ -0,0 +1,90 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/media/html_audio_element_capturer_source.h" + +#include "base/threading/thread_task_runner_handle.h" +#include "media/base/audio_parameters.h" +#include "media/base/audio_renderer_sink.h" +#include "media/blink/webaudiosourceprovider_impl.h" +#include "media/blink/webmediaplayer_impl.h" +#include "third_party/WebKit/public/platform/WebMediaPlayer.h" + +namespace content { + +//static +HtmlAudioElementCapturerSource* +HtmlAudioElementCapturerSource::CreateFromWebMediaPlayerImpl( + blink::WebMediaPlayer* player) { + DCHECK(player); + return new HtmlAudioElementCapturerSource( + static_cast<media::WebAudioSourceProviderImpl*>( + player->getAudioSourceProvider())); +} + +HtmlAudioElementCapturerSource::HtmlAudioElementCapturerSource( + media::WebAudioSourceProviderImpl* audio_source) + : MediaStreamAudioSource(true /* is_local_source */), + audio_source_(audio_source), + is_started_(false), + last_sample_rate_(0), + last_num_channels_(0), + last_bus_frames_(0) { + DCHECK(audio_source_); +} + +HtmlAudioElementCapturerSource::~HtmlAudioElementCapturerSource() { + DCHECK(thread_checker_.CalledOnValidThread()); + EnsureSourceIsStopped(); +} + +bool HtmlAudioElementCapturerSource::EnsureSourceIsStarted() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (audio_source_ && !is_started_) { + // base:Unretained() is safe here since EnsureSourceIsStopped() guarantees + // no more calls to OnAudioBus(). + audio_source_->SetCopyAudioCallback(base::Bind( + &HtmlAudioElementCapturerSource::OnAudioBus, base::Unretained(this))); + is_started_ = true; + } + return is_started_; +} + +void HtmlAudioElementCapturerSource::EnsureSourceIsStopped() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!is_started_) + return; + + if (audio_source_) { + audio_source_->ClearCopyAudioCallback(); + audio_source_ = nullptr; + } + is_started_ = false; +} + +void HtmlAudioElementCapturerSource::OnAudioBus( + std::unique_ptr<media::AudioBus> audio_bus, + uint32_t frames_delayed, + int sample_rate) { + const base::TimeTicks capture_time = + base::TimeTicks::Now() - + base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond * + frames_delayed / sample_rate); + + if (sample_rate != last_sample_rate_ || + audio_bus->channels() != last_num_channels_ || + audio_bus->frames() != last_bus_frames_) { + MediaStreamAudioSource::SetFormat( + media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, + media::GuessChannelLayout(audio_bus->channels()), + sample_rate, 16, audio_bus->frames())); + last_sample_rate_ = sample_rate; + last_num_channels_ = audio_bus->channels(); + last_bus_frames_ = audio_bus->frames(); + } + + MediaStreamAudioSource::DeliverDataToTracks(*audio_bus, capture_time); +} + +} // namespace content diff --git a/chromium/content/renderer/media/html_audio_element_capturer_source.h b/chromium/content/renderer/media/html_audio_element_capturer_source.h new file mode 100644 index 00000000000..48ea5006832 --- /dev/null +++ b/chromium/content/renderer/media/html_audio_element_capturer_source.h @@ -0,0 +1,63 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_HTML_AUDIO_ELEMENT_CAPTURER_SOURCE_H_ +#define CONTENT_RENDERER_MEDIA_HTML_AUDIO_ELEMENT_CAPTURER_SOURCE_H_ + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "base/threading/thread_checker.h" +#include "content/common/content_export.h" +#include "content/renderer/media/media_stream_audio_source.h" + +namespace blink { +class WebMediaPlayer; +} // namespace blink + +namespace media { +class AudioBus; +class WebAudioSourceProviderImpl; +} // namespace media + +namespace content { + +// This class is a MediaStreamAudioSource that registers to the constructor- +// passed weak WebAudioSourceProviderImpl to receive a copy of the audio data +// intended for rendering. This copied data is received on OnAudioBus() and sent +// to all the registered Tracks. +class CONTENT_EXPORT HtmlAudioElementCapturerSource final + : NON_EXPORTED_BASE(public MediaStreamAudioSource) { + public: + static HtmlAudioElementCapturerSource* + CreateFromWebMediaPlayerImpl(blink::WebMediaPlayer* player); + + explicit HtmlAudioElementCapturerSource( + media::WebAudioSourceProviderImpl* audio_source); + ~HtmlAudioElementCapturerSource() override; + + private: + // MediaStreamAudioSource implementation. + bool EnsureSourceIsStarted() final; + void EnsureSourceIsStopped() final; + + // To act as an WebAudioSourceProviderImpl::CopyAudioCB. + void OnAudioBus(std::unique_ptr<media::AudioBus> audio_bus, + uint32_t frames_delayed, + int sample_rate); + + scoped_refptr<media::WebAudioSourceProviderImpl> audio_source_; + + bool is_started_; + int last_sample_rate_; + int last_num_channels_; + int last_bus_frames_; + + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(HtmlAudioElementCapturerSource); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_HTML_AUDIO_ELEMENT_CAPTURER_SOURCE_H_ diff --git a/chromium/content/renderer/media/html_audio_element_capturer_source_unittest.cc b/chromium/content/renderer/media/html_audio_element_capturer_source_unittest.cc new file mode 100644 index 00000000000..10d24ed7ec5 --- /dev/null +++ b/chromium/content/renderer/media/html_audio_element_capturer_source_unittest.cc @@ -0,0 +1,154 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/weak_ptr.h" +#include "base/run_loop.h" +#include "base/threading/thread_task_runner_handle.h" +#include "content/public/renderer/media_stream_audio_sink.h" +#include "content/renderer/media/html_audio_element_capturer_source.h" +#include "content/renderer/media/media_stream_audio_track.h" +#include "media/audio/null_audio_sink.h" +#include "media/base/audio_parameters.h" +#include "media/base/fake_audio_render_callback.h" +#include "media/blink/webaudiosourceprovider_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/web/WebHeap.h" + +using ::testing::_; +using ::testing::AllOf; +using ::testing::InSequence; +using ::testing::Mock; +using ::testing::Property; + +namespace content { + +static const int kNumChannelsForTest = 1; +static const int kBufferDurationMs = 10; + +static const int kAudioTrackSampleRate = 48000; +static const int kAudioTrackSamplesPerBuffer = + kAudioTrackSampleRate * kBufferDurationMs / + base::Time::kMillisecondsPerSecond; + +ACTION_P(RunClosure, closure) { + closure.Run(); +} + +// +class MockMediaStreamAudioSink final : public MediaStreamAudioSink { + public: + MockMediaStreamAudioSink() : MediaStreamAudioSink() {} + ~MockMediaStreamAudioSink() = default; + + MOCK_METHOD1(OnSetFormat, void(const media::AudioParameters& params)); + MOCK_METHOD2(OnData, + void(const media::AudioBus& audio_bus, + base::TimeTicks estimated_capture_time)); + + DISALLOW_COPY_AND_ASSIGN(MockMediaStreamAudioSink); +}; + +// This test needs to bundle together plenty of objects, namely: +// - a WebAudioSourceProviderImpl, which in turn needs an Audio Sink, in this +// case a NullAudioSink. This is needed to plug HTMLAudioElementCapturerSource +// and inject audio. +// - a WebMediaStreamSource, that owns the HTMLAudioElementCapturerSource under +// test, and a WebMediaStreamAudioTrack, that the class under test needs to +// connect to in order to operate correctly. This class has an inner content +// MediaStreamAudioTrack. +// - finally, a MockMediaStreamAudioSink to observe captured audio frames, and +// that plugs into the former MediaStreamAudioTrack. +class HTMLAudioElementCapturerSourceTest : public testing::Test { + public: + HTMLAudioElementCapturerSourceTest() + : fake_callback_(0.1), + audio_source_(new media::WebAudioSourceProviderImpl( + new media::NullAudioSink(base::ThreadTaskRunnerHandle::Get()))) {} + + void SetUp() final { + const media::AudioParameters params( + media::AudioParameters::AUDIO_PCM_LOW_LATENCY, + media::GuessChannelLayout(kNumChannelsForTest), + kAudioTrackSampleRate /* sample_rate */, 16 /* bits_per_sample */, + kAudioTrackSamplesPerBuffer /* frames_per_buffer */); + audio_source_->Initialize(params, &fake_callback_); + + blink_audio_source_.initialize(blink::WebString::fromUTF8("audio_id"), + blink::WebMediaStreamSource::TypeAudio, + blink::WebString::fromUTF8("audio_track"), + false /* remote */); + blink_audio_track_.initialize(blink_audio_source_.id(), + blink_audio_source_); + + // |blink_audio_source_| takes ownership of HtmlAudioElementCapturerSource. + blink_audio_source_.setExtraData( + new HtmlAudioElementCapturerSource(audio_source_.get())); + ASSERT_TRUE(source()->ConnectToTrack(blink_audio_track_)); + } + + void TearDown() override { + blink_audio_track_.reset(); + blink_audio_source_.reset(); + blink::WebHeap::collectAllGarbageForTesting(); + } + + HtmlAudioElementCapturerSource* source() const { + return static_cast<HtmlAudioElementCapturerSource*>( + MediaStreamAudioSource::From(blink_audio_source_)); + } + + MediaStreamAudioTrack* track() const { + return MediaStreamAudioTrack::From(blink_audio_track_); + } + + int InjectAudio(media::AudioBus* audio_bus) { + return audio_source_->RenderForTesting(audio_bus); + } + + protected: + const base::MessageLoop message_loop_; + + blink::WebMediaStreamSource blink_audio_source_; + blink::WebMediaStreamTrack blink_audio_track_; + + media::FakeAudioRenderCallback fake_callback_; + scoped_refptr<media::WebAudioSourceProviderImpl> audio_source_; +}; + +// Constructs and destructs all objects. This is a non trivial sequence. +TEST_F(HTMLAudioElementCapturerSourceTest, ConstructAndDestruct) { +} + +// This test verifies that Audio can be properly captured when injected in the +// WebAudioSourceProviderImpl. +TEST_F(HTMLAudioElementCapturerSourceTest, CaptureAudio) { + InSequence s; + + base::RunLoop run_loop; + base::Closure quit_closure = run_loop.QuitClosure(); + + MockMediaStreamAudioSink sink; + track()->AddSink(&sink); + EXPECT_CALL(sink, OnSetFormat(_)).Times(1); + EXPECT_CALL( + sink, + OnData(AllOf(Property(&media::AudioBus::channels, kNumChannelsForTest), + Property(&media::AudioBus::frames, + kAudioTrackSamplesPerBuffer)), + _)) + .Times(1) + .WillOnce(RunClosure(quit_closure)); + + std::unique_ptr<media::AudioBus> bus = media::AudioBus::Create( + kNumChannelsForTest, kAudioTrackSamplesPerBuffer); + InjectAudio(bus.get()); + run_loop.Run(); + + track()->Stop(); + track()->RemoveSink(&sink); +} + +} // namespace content diff --git a/chromium/content/renderer/media/html_video_element_capturer_source.cc b/chromium/content/renderer/media/html_video_element_capturer_source.cc index 3087a47aae2..88108ee50e5 100644 --- a/chromium/content/renderer/media/html_video_element_capturer_source.cc +++ b/chromium/content/renderer/media/html_video_element_capturer_source.cc @@ -4,7 +4,9 @@ #include "content/renderer/media/html_video_element_capturer_source.h" +#include "base/location.h" #include "base/memory/ptr_util.h" +#include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "content/public/renderer/render_thread.h" @@ -12,11 +14,13 @@ #include "content/renderer/media/webrtc_uma_histograms.h" #include "media/base/limits.h" #include "media/blink/webmediaplayer_impl.h" +#include "skia/ext/platform_canvas.h" #include "third_party/WebKit/public/platform/WebMediaPlayer.h" #include "third_party/WebKit/public/platform/WebRect.h" #include "third_party/WebKit/public/platform/WebSize.h" #include "third_party/libyuv/include/libyuv.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/core/SkXfermode.h" namespace { @@ -91,9 +95,12 @@ void HtmlVideoElementCapturerSource::StartCapture( return; } const blink::WebSize resolution = web_media_player_->naturalSize(); - canvas_ = sk_sp<SkCanvas>(skia::CreatePlatformCanvas(resolution.width, - resolution.height, - true /* is_opaque */)); + surface_ = + SkSurface::MakeRasterN32Premul(resolution.width, resolution.height); + if (!surface_) { + running_callback_.Run(false); + return; + } new_frame_callback_ = new_frame_callback; // Force |capture_frame_rate_| to be in between k{Min,Max}FramesPerSecond. @@ -127,14 +134,15 @@ void HtmlVideoElementCapturerSource::sendNewFrame() { const base::TimeTicks current_time = base::TimeTicks::Now(); const blink::WebSize resolution = web_media_player_->naturalSize(); + SkCanvas* canvas = surface_->getCanvas(); web_media_player_->paint( - canvas_.get(), blink::WebRect(0, 0, resolution.width, resolution.height), + canvas, blink::WebRect(0, 0, resolution.width, resolution.height), 0xFF /* alpha */, SkXfermode::kSrc_Mode); - DCHECK_NE(kUnknown_SkColorType, canvas_->imageInfo().colorType()); - DCHECK_EQ(canvas_->imageInfo().width(), resolution.width); - DCHECK_EQ(canvas_->imageInfo().height(), resolution.height); + DCHECK_NE(kUnknown_SkColorType, canvas->imageInfo().colorType()); + DCHECK_EQ(canvas->imageInfo().width(), resolution.width); + DCHECK_EQ(canvas->imageInfo().height(), resolution.height); - const SkBitmap bitmap = skia::ReadPixels(canvas_.get()); + const SkBitmap bitmap = skia::ReadPixels(canvas); DCHECK_NE(kUnknown_SkColorType, bitmap.colorType()); DCHECK(!bitmap.drawsNothing()); DCHECK(bitmap.getPixels()); @@ -160,8 +168,8 @@ void HtmlVideoElementCapturerSource::sendNewFrame() { 0 /* crop_y */, bitmap.info().width(), bitmap.info().height(), - frame->natural_size().width(), - frame->natural_size().height(), + frame->coded_size().width(), + frame->coded_size().height(), libyuv::kRotate0, libyuv::FOURCC_ARGB) == 0) { // Success! @@ -182,7 +190,7 @@ void HtmlVideoElementCapturerSource::sendNewFrame() { next_capture_time_ = current_time; } // Schedule next capture. - base::MessageLoop::current()->PostDelayedTask( + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::Bind(&HtmlVideoElementCapturerSource::sendNewFrame, weak_factory_.GetWeakPtr()), next_capture_time_ - current_time); diff --git a/chromium/content/renderer/media/html_video_element_capturer_source.h b/chromium/content/renderer/media/html_video_element_capturer_source.h index e248358846d..2d7598b5ece 100644 --- a/chromium/content/renderer/media/html_video_element_capturer_source.h +++ b/chromium/content/renderer/media/html_video_element_capturer_source.h @@ -13,14 +13,15 @@ #include "media/base/video_capturer_source.h" #include "media/base/video_frame_pool.h" #include "media/base/video_types.h" -#include "skia/ext/platform_canvas.h" -#include "skia/ext/refptr.h" #include "third_party/WebKit/public/platform/WebSize.h" +#include "third_party/skia/include/core/SkRefCnt.h" namespace blink { class WebMediaPlayer; } // namespace blink +class SkSurface; + namespace content { // This class is a VideoCapturerSource taking video snapshots of the ctor-passed @@ -56,7 +57,7 @@ class CONTENT_EXPORT HtmlVideoElementCapturerSource final void sendNewFrame(); media::VideoFramePool frame_pool_; - sk_sp<SkCanvas> canvas_; + sk_sp<SkSurface> surface_; const base::WeakPtr<blink::WebMediaPlayer> web_media_player_; const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; diff --git a/chromium/content/renderer/media/image_capture_frame_grabber.cc b/chromium/content/renderer/media/image_capture_frame_grabber.cc index a7a37bf4d98..faeb43f8382 100644 --- a/chromium/content/renderer/media/image_capture_frame_grabber.cc +++ b/chromium/content/renderer/media/image_capture_frame_grabber.cc @@ -88,7 +88,7 @@ void ImageCaptureFrameGrabber::grabFrame( DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!!callbacks); - DCHECK(track && !track->isNull() && track->getExtraData()); + DCHECK(track && !track->isNull() && track->getTrackData()); DCHECK_EQ(blink::WebMediaStreamSource::TypeVideo, track->source().getType()); ScopedWebCallbacks<WebImageCaptureGrabFrameCallbacks> scoped_callbacks = diff --git a/chromium/content/renderer/media/media_interface_provider.cc b/chromium/content/renderer/media/media_interface_provider.cc index 84faca9bb32..8e3968e2182 100644 --- a/chromium/content/renderer/media/media_interface_provider.cc +++ b/chromium/content/renderer/media/media_interface_provider.cc @@ -37,6 +37,9 @@ void MediaInterfaceProvider::GetInterface(const mojo::String& interface_name, } else if (interface_name == media::mojom::AudioDecoder::Name_) { GetMediaServiceFactory()->CreateAudioDecoder( mojo::MakeRequest<media::mojom::AudioDecoder>(std::move(pipe))); + } else if (interface_name == media::mojom::VideoDecoder::Name_) { + GetMediaServiceFactory()->CreateVideoDecoder( + mojo::MakeRequest<media::mojom::VideoDecoder>(std::move(pipe))); } else { NOTREACHED(); } diff --git a/chromium/content/renderer/media/media_permission_dispatcher.cc b/chromium/content/renderer/media/media_permission_dispatcher.cc index 764a4a0b92f..b28bc0363e1 100644 --- a/chromium/content/renderer/media/media_permission_dispatcher.cc +++ b/chromium/content/renderer/media/media_permission_dispatcher.cc @@ -9,6 +9,7 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "media/base/bind_to_current_loop.h" +#include "third_party/WebKit/public/web/WebUserGestureIndicator.h" #include "url/gurl.h" namespace { @@ -98,6 +99,7 @@ void MediaPermissionDispatcher::RequestPermission( permission_service_->RequestPermission( MediaPermissionTypeToPermissionName(type), security_origin.spec(), + blink::WebUserGestureIndicator::isProcessingUserGesture(), base::Bind(&MediaPermissionDispatcher::OnPermissionStatus, weak_ptr_, request_id)); } diff --git a/chromium/content/renderer/media/media_recorder_handler.cc b/chromium/content/renderer/media/media_recorder_handler.cc index 3dc54b51ef4..19cec5a4e92 100644 --- a/chromium/content/renderer/media/media_recorder_handler.cc +++ b/chromium/content/renderer/media/media_recorder_handler.cc @@ -40,10 +40,8 @@ media::VideoCodec CodecIdToMediaVideoCodec(VideoTrackRecorder::CodecId id) { return media::kCodecVP8; case VideoTrackRecorder::CodecId::VP9: return media::kCodecVP9; -#if BUILDFLAG(RTC_USE_H264) case VideoTrackRecorder::CodecId::H264: return media::kCodecH264; -#endif } NOTREACHED() << "Unsupported codec"; return media::kUnknownVideoCodec; @@ -177,6 +175,11 @@ bool MediaRecorderHandler::start(int timeslice) { audio_tracks[0].source().getReadyState() != blink::WebMediaStreamSource::ReadyStateEnded; + if (!use_video_tracks && !use_audio_tracks) { + LOG(WARNING) << __FUNCTION__ << ": no tracks to be recorded."; + return false; + } + webm_muxer_.reset(new media::WebmMuxer( CodecIdToMediaVideoCodec(codec_id_), use_video_tracks, use_audio_tracks, base::Bind(&MediaRecorderHandler::WriteData, diff --git a/chromium/content/renderer/media/media_stream_audio_deliverer.h b/chromium/content/renderer/media/media_stream_audio_deliverer.h index 80a6a1c4193..cb0774eed54 100644 --- a/chromium/content/renderer/media/media_stream_audio_deliverer.h +++ b/chromium/content/renderer/media/media_stream_audio_deliverer.h @@ -137,7 +137,7 @@ class MediaStreamAudioDeliverer { // |consumers_| on the audio thread. std::vector<Consumer*> pending_consumers_; - // Consumers that are up-to-date on the current audio format and are receiving + // Consumers that are up to date on the current audio format and are receiving // audio data are placed in this list. std::vector<Consumer*> consumers_; diff --git a/chromium/content/renderer/media/media_stream_audio_processor.cc b/chromium/content/renderer/media/media_stream_audio_processor.cc index 68aefcbff88..c02696e0684 100644 --- a/chromium/content/renderer/media/media_stream_audio_processor.cc +++ b/chromium/content/renderer/media/media_stream_audio_processor.cc @@ -136,6 +136,11 @@ class MediaStreamAudioBus { thread_checker_.DetachFromThread(); } + void ReattachThreadChecker() { + thread_checker_.DetachFromThread(); + DCHECK(thread_checker_.CalledOnValidThread()); + } + media::AudioBus* bus() { DCHECK(thread_checker_.CalledOnValidThread()); return bus_.get(); @@ -194,6 +199,12 @@ class MediaStreamAudioFifo { thread_checker_.DetachFromThread(); } + void ReattachThreadChecker() { + thread_checker_.DetachFromThread(); + DCHECK(thread_checker_.CalledOnValidThread()); + destination_->ReattachThreadChecker(); + } + void Push(const media::AudioBus& source, base::TimeDelta audio_delay) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_EQ(source.channels(), source_channels_); @@ -276,6 +287,7 @@ MediaStreamAudioProcessor::MediaStreamAudioProcessor( WebRtcPlayoutDataSource* playout_data_source) : render_delay_ms_(0), playout_data_source_(playout_data_source), + main_thread_message_loop_(base::MessageLoop::current()), audio_mirroring_(false), typing_detected_(false), stopped_(false) { @@ -378,6 +390,7 @@ bool MediaStreamAudioProcessor::ProcessAndConsumeData( void MediaStreamAudioProcessor::Stop() { DCHECK(main_thread_checker_.CalledOnValidThread()); + if (stopped_) return; @@ -398,6 +411,9 @@ void MediaStreamAudioProcessor::Stop() { playout_data_source_->RemovePlayoutSink(this); playout_data_source_ = NULL; } + + if (echo_information_) + echo_information_->ReportAndResetAecDivergentFilterStats(); } const media::AudioParameters& MediaStreamAudioProcessor::InputFormat() const { @@ -474,6 +490,12 @@ void MediaStreamAudioProcessor::OnPlayoutDataSourceChanged() { render_fifo_.reset(); } +void MediaStreamAudioProcessor::OnRenderThreadChanged() { + render_thread_checker_.DetachFromThread(); + DCHECK(render_thread_checker_.CalledOnValidThread()); + render_fifo_->ReattachThreadChecker(); +} + void MediaStreamAudioProcessor::GetStats(AudioProcessorStats* stats) { stats->typing_noise_detected = (base::subtle::Acquire_Load(&typing_detected_) != false); @@ -739,13 +761,18 @@ int MediaStreamAudioProcessor::ProcessData(const float* const* process_ptrs, base::subtle::Release_Store(&typing_detected_, detected); } - if (echo_information_) { - echo_information_.get()->UpdateAecDelayStats(ap->echo_cancellation()); - } + main_thread_message_loop_->PostTask( + FROM_HERE, base::Bind(&MediaStreamAudioProcessor::UpdateAecStats, this)); // Return 0 if the volume hasn't been changed, and otherwise the new volume. return (agc->stream_analog_level() == volume) ? 0 : agc->stream_analog_level(); } +void MediaStreamAudioProcessor::UpdateAecStats() { + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (echo_information_) + echo_information_->UpdateAecStats(audio_processing_->echo_cancellation()); +} + } // namespace content diff --git a/chromium/content/renderer/media/media_stream_audio_processor.h b/chromium/content/renderer/media/media_stream_audio_processor.h index 66290159ce2..8b0c0943a46 100644 --- a/chromium/content/renderer/media/media_stream_audio_processor.h +++ b/chromium/content/renderer/media/media_stream_audio_processor.h @@ -124,6 +124,7 @@ class CONTENT_EXPORT MediaStreamAudioProcessor : int sample_rate, int audio_delay_milliseconds) override; void OnPlayoutDataSourceChanged() override; + void OnRenderThreadChanged() override; // webrtc::AudioProcessorInterface implementation. // This method is called on the libjingle thread. @@ -152,6 +153,9 @@ class CONTENT_EXPORT MediaStreamAudioProcessor : bool key_pressed, float* const* output_ptrs); + // Update AEC stats. Called on the main render thread. + void UpdateAecStats(); + // Cached value for the render delay latency. This member is accessed by // both the capture audio thread and the render audio thread. base::subtle::Atomic32 render_delay_ms_; @@ -189,13 +193,17 @@ class CONTENT_EXPORT MediaStreamAudioProcessor : // Used to DCHECK that some methods are called on the render audio thread. base::ThreadChecker render_thread_checker_; + // Message loop for the main render thread. We're assuming that we're created + // on the main render thread. + base::MessageLoop* main_thread_message_loop_; + // Flag to enable stereo channel mirroring. bool audio_mirroring_; + // Typing detector. |typing_detected_| is used to show the result of typing + // detection. It can be accessed by the capture audio thread and by the + // libjingle thread which calls GetStats(). std::unique_ptr<webrtc::TypingDetection> typing_detector_; - // This flag is used to show the result of typing detection. - // It can be accessed by the capture audio thread and by the libjingle thread - // which calls GetStats(). base::subtle::Atomic32 typing_detected_; // Communication with browser for AEC dump. @@ -204,8 +212,8 @@ class CONTENT_EXPORT MediaStreamAudioProcessor : // Flag to avoid executing Stop() more than once. bool stopped_; - // Object for logging echo information when the AEC is enabled. Accessible by - // the libjingle thread through GetStats(). + // Object for logging UMA stats for echo information when the AEC is enabled. + // Accessed on the main render thread. std::unique_ptr<EchoInformation> echo_information_; DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioProcessor); diff --git a/chromium/content/renderer/media/media_stream_audio_processor_options.cc b/chromium/content/renderer/media/media_stream_audio_processor_options.cc index 99bf7b590fb..d4ca596eac3 100644 --- a/chromium/content/renderer/media/media_stream_audio_processor_options.cc +++ b/chromium/content/renderer/media/media_stream_audio_processor_options.cc @@ -48,6 +48,9 @@ const char MediaAudioConstraints::kGoogAudioMirroring[] = "googAudioMirroring"; namespace { +// Controls whether the hotword audio stream is used on supported platforms. +const char kMediaStreamAudioHotword[] = "googHotword"; + // Constant constraint keys which enables default audio constraints on // mediastreams with audio. struct { @@ -297,13 +300,32 @@ std::string MediaAudioConstraints::GetGoogArrayGeometry() const { } EchoInformation::EchoInformation() - : num_chunks_(0), echo_frames_received_(false) { + : delay_stats_time_ms_(0), + echo_frames_received_(false), + divergent_filter_stats_time_ms_(0), + num_divergent_filter_fraction_(0), + num_non_zero_divergent_filter_fraction_(0) {} + +EchoInformation::~EchoInformation() { + DCHECK(thread_checker_.CalledOnValidThread()); + ReportAndResetAecDivergentFilterStats(); } -EchoInformation::~EchoInformation() {} +void EchoInformation::UpdateAecStats( + webrtc::EchoCancellation* echo_cancellation) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!echo_cancellation->is_enabled()) + return; + + UpdateAecDelayStats(echo_cancellation); + UpdateAecDivergentFilterStats(echo_cancellation); +} void EchoInformation::UpdateAecDelayStats( webrtc::EchoCancellation* echo_cancellation) { + DCHECK(thread_checker_.CalledOnValidThread()); + // Only start collecting stats if we know echo cancellation has measured an // echo. Otherwise we clutter the stats with for example cases where only the // microphone is used. @@ -311,19 +333,18 @@ void EchoInformation::UpdateAecDelayStats( return; echo_frames_received_ = true; + // In WebRTC, three echo delay metrics are calculated and updated every // five seconds. We use one of them, |fraction_poor_delays| to log in a UMA // histogram an Echo Cancellation quality metric. The stat in WebRTC has a // fixed aggregation window of five seconds, so we use the same query // frequency to avoid logging old values. - const int kNumChunksInFiveSeconds = 500; - if (!echo_cancellation->is_delay_logging_enabled() || - !echo_cancellation->is_enabled()) { + if (!echo_cancellation->is_delay_logging_enabled()) return; - } - num_chunks_++; - if (num_chunks_ < kNumChunksInFiveSeconds) { + delay_stats_time_ms_ += webrtc::AudioProcessing::kChunkSizeMs; + if (delay_stats_time_ms_ < + 500 * webrtc::AudioProcessing::kChunkSizeMs) { // 5 seconds return; } @@ -332,7 +353,7 @@ void EchoInformation::UpdateAecDelayStats( if (echo_cancellation->GetDelayMetrics( &dummy_median, &dummy_std, &fraction_poor_delays) == webrtc::AudioProcessing::kNoError) { - num_chunks_ = 0; + delay_stats_time_ms_ = 0; // Map |fraction_poor_delays| to an Echo Cancellation quality and log in UMA // histogram. See DelayBasedEchoQuality for information on histogram // buckets. @@ -342,6 +363,53 @@ void EchoInformation::UpdateAecDelayStats( } } +void EchoInformation::UpdateAecDivergentFilterStats( + webrtc::EchoCancellation* echo_cancellation) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!echo_cancellation->are_metrics_enabled()) + return; + + divergent_filter_stats_time_ms_ += webrtc::AudioProcessing::kChunkSizeMs; + if (divergent_filter_stats_time_ms_ < + 100 * webrtc::AudioProcessing::kChunkSizeMs) { // 1 second + return; + } + + webrtc::EchoCancellation::Metrics metrics; + if (echo_cancellation->GetMetrics(&metrics) == + webrtc::AudioProcessing::kNoError) { + // If not yet calculated, |metrics.divergent_filter_fraction| is -1.0. After + // being calculated the first time, it is updated periodically. + if (metrics.divergent_filter_fraction < 0.0f) { + DCHECK_EQ(num_divergent_filter_fraction_, 0); + return; + } + if (metrics.divergent_filter_fraction > 0.0f) { + ++num_non_zero_divergent_filter_fraction_; + } + } else { + DLOG(WARNING) << "Get echo cancellation metrics failed."; + } + ++num_divergent_filter_fraction_; + divergent_filter_stats_time_ms_ = 0; +} + +void EchoInformation::ReportAndResetAecDivergentFilterStats() { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (num_divergent_filter_fraction_ == 0) + return; + + int non_zero_percent = 100 * num_non_zero_divergent_filter_fraction_ / + num_divergent_filter_fraction_; + UMA_HISTOGRAM_PERCENTAGE("WebRTC.AecFilterHasDivergence", non_zero_percent); + + divergent_filter_stats_time_ms_ = 0; + num_non_zero_divergent_filter_fraction_ = 0; + num_divergent_filter_fraction_ = 0; +} + void EnableEchoCancellation(AudioProcessing* audio_processing) { #if defined(OS_ANDROID) // Mobile devices are using AECM. diff --git a/chromium/content/renderer/media/media_stream_audio_processor_options.h b/chromium/content/renderer/media/media_stream_audio_processor_options.h index 2d5af1d4f41..a0c6a56f4d4 100644 --- a/chromium/content/renderer/media/media_stream_audio_processor_options.h +++ b/chromium/content/renderer/media/media_stream_audio_processor_options.h @@ -9,6 +9,7 @@ #include "base/files/file.h" #include "base/macros.h" +#include "base/threading/thread_checker.h" #include "content/common/content_export.h" #include "content/public/common/media_stream_request.h" #include "third_party/WebKit/public/platform/WebMediaConstraints.h" @@ -103,14 +104,36 @@ class CONTENT_EXPORT EchoInformation { EchoInformation(); virtual ~EchoInformation(); - void UpdateAecDelayStats(webrtc::EchoCancellation* echo_cancellation); + // Updates stats, and reports delay metrics as UMA stats every 5 seconds. + // Must be called every time AudioProcessing::ProcessStream() is called. + void UpdateAecStats(webrtc::EchoCancellation* echo_cancellation); + + // Reports AEC divergent filter metrics as UMA and resets the associated data. + void ReportAndResetAecDivergentFilterStats(); private: - // Counter to track 5 seconds of processed 10 ms chunks in order to query a - // new metric from webrtc::EchoCancellation::GetEchoDelayMetrics(). - int num_chunks_; + void UpdateAecDelayStats(webrtc::EchoCancellation* echo_cancellation); + void UpdateAecDivergentFilterStats( + webrtc::EchoCancellation* echo_cancellation); + + // Counter to track 5 seconds of data in order to query a new metric from + // webrtc::EchoCancellation::GetEchoDelayMetrics(). + int delay_stats_time_ms_; bool echo_frames_received_; + // Counter to track 1 second of data in order to query a new divergent filter + // fraction metric from webrtc::EchoCancellation::GetMetrics(). + int divergent_filter_stats_time_ms_; + + // Total number of times we queried for the divergent filter fraction metric. + int num_divergent_filter_fraction_; + + // Number of non-zero divergent filter fraction metrics. + int num_non_zero_divergent_filter_fraction_; + + // Ensures that this class is accessed on the same thread. + base::ThreadChecker thread_checker_; + DISALLOW_COPY_AND_ASSIGN(EchoInformation); }; diff --git a/chromium/content/renderer/media/media_stream_audio_processor_unittest.cc b/chromium/content/renderer/media/media_stream_audio_processor_unittest.cc index 8cf5cccdccf..0b5e138e7cb 100644 --- a/chromium/content/renderer/media/media_stream_audio_processor_unittest.cc +++ b/chromium/content/renderer/media/media_stream_audio_processor_unittest.cc @@ -208,6 +208,7 @@ class MediaStreamAudioProcessorTest : public ::testing::Test { #define MAYBE_WithAudioProcessing WithAudioProcessing #endif TEST_F(MediaStreamAudioProcessorTest, MAYBE_WithAudioProcessing) { + base::MessageLoop message_loop; MockConstraintFactory constraint_factory; scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device( new WebRtcAudioDeviceImpl()); @@ -223,9 +224,10 @@ TEST_F(MediaStreamAudioProcessorTest, MAYBE_WithAudioProcessing) { kAudioProcessingSampleRate, kAudioProcessingNumberOfChannel, kAudioProcessingSampleRate / 100); - // Set |audio_processor| to NULL to make sure |webrtc_audio_device| outlives - // |audio_processor|. - audio_processor = NULL; + + // Stop |audio_processor| so that it removes itself from + // |webrtc_audio_device| and clears its pointer to it. + audio_processor->Stop(); } TEST_F(MediaStreamAudioProcessorTest, VerifyTabCaptureWithoutAudioProcessing) { @@ -259,9 +261,9 @@ TEST_F(MediaStreamAudioProcessorTest, VerifyTabCaptureWithoutAudioProcessing) { input_device_params_, webrtc_audio_device.get()); EXPECT_FALSE(audio_processor->has_audio_processing()); - // Set |audio_processor| to NULL to make sure |webrtc_audio_device| outlives - // |audio_processor|. - audio_processor = NULL; + // Stop |audio_processor| so that it removes itself from + // |webrtc_audio_device| and clears its pointer to it. + audio_processor->Stop(); } TEST_F(MediaStreamAudioProcessorTest, TurnOffDefaultConstraints) { @@ -281,9 +283,10 @@ TEST_F(MediaStreamAudioProcessorTest, TurnOffDefaultConstraints) { params_.sample_rate(), params_.channels(), params_.sample_rate() / 100); - // Set |audio_processor| to NULL to make sure |webrtc_audio_device| outlives - // |audio_processor|. - audio_processor = NULL; + + // Stop |audio_processor| so that it removes itself from + // |webrtc_audio_device| and clears its pointer to it. + audio_processor->Stop(); } TEST_F(MediaStreamAudioProcessorTest, VerifyConstraints) { @@ -440,6 +443,7 @@ TEST_F(MediaStreamAudioProcessorTest, SelectsConstraintsArrayGeometryIfExists) { #define MAYBE_TestAllSampleRates TestAllSampleRates #endif TEST_F(MediaStreamAudioProcessorTest, MAYBE_TestAllSampleRates) { + base::MessageLoop message_loop; MockConstraintFactory constraint_factory; scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device( new WebRtcAudioDeviceImpl()); @@ -467,9 +471,9 @@ TEST_F(MediaStreamAudioProcessorTest, MAYBE_TestAllSampleRates) { kAudioProcessingSampleRate / 100); } - // Set |audio_processor| to NULL to make sure |webrtc_audio_device| - // outlives |audio_processor|. - audio_processor = NULL; + // Stop |audio_processor| so that it removes itself from + // |webrtc_audio_device| and clears its pointer to it. + audio_processor->Stop(); } // Test that if we have an AEC dump message filter created, we are getting it @@ -491,7 +495,9 @@ TEST_F(MediaStreamAudioProcessorTest, GetAecDumpMessageFilter) { EXPECT_TRUE(audio_processor->aec_dump_message_filter_.get()); - audio_processor = NULL; + // Stop |audio_processor| so that it removes itself from + // |webrtc_audio_device| and clears its pointer to it. + audio_processor->Stop(); } TEST_F(MediaStreamAudioProcessorTest, TestStereoAudio) { @@ -549,9 +555,9 @@ TEST_F(MediaStreamAudioProcessorTest, TestStereoAudio) { EXPECT_EQ(pushed_capture_delay, capture_delay); } - // Set |audio_processor| to NULL to make sure |webrtc_audio_device| outlives - // |audio_processor|. - audio_processor = NULL; + // Stop |audio_processor| so that it removes itself from + // |webrtc_audio_device| and clears its pointer to it. + audio_processor->Stop(); } // Disabled on android clang builds due to crbug.com/470499 @@ -560,8 +566,8 @@ TEST_F(MediaStreamAudioProcessorTest, TestStereoAudio) { #else #define MAYBE_TestWithKeyboardMicChannel TestWithKeyboardMicChannel #endif - TEST_F(MediaStreamAudioProcessorTest, MAYBE_TestWithKeyboardMicChannel) { + base::MessageLoop message_loop; MockConstraintFactory constraint_factory; constraint_factory.basic().googExperimentalNoiseSuppression.setExact(true); scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device( @@ -581,9 +587,10 @@ TEST_F(MediaStreamAudioProcessorTest, MAYBE_TestWithKeyboardMicChannel) { kAudioProcessingSampleRate, kAudioProcessingNumberOfChannel, kAudioProcessingSampleRate / 100); - // Set |audio_processor| to NULL to make sure |webrtc_audio_device| outlives - // |audio_processor|. - audio_processor = NULL; + + // Stop |audio_processor| so that it removes itself from + // |webrtc_audio_device| and clears its pointer to it. + audio_processor->Stop(); } } // namespace content diff --git a/chromium/content/renderer/media/media_stream_audio_source.cc b/chromium/content/renderer/media/media_stream_audio_source.cc index 6e99deb54cd..8db50426ebc 100644 --- a/chromium/content/renderer/media/media_stream_audio_source.cc +++ b/chromium/content/renderer/media/media_stream_audio_source.cc @@ -58,7 +58,7 @@ bool MediaStreamAudioSource::ConnectToTrack( // Create and initialize a new MediaStreamAudioTrack and pass ownership of it // to the WebMediaStreamTrack. blink::WebMediaStreamTrack mutable_blink_track = blink_track; - mutable_blink_track.setExtraData( + mutable_blink_track.setTrackData( CreateMediaStreamAudioTrack(blink_track.id().utf8()).release()); // Propagate initial "enabled" state. diff --git a/chromium/content/renderer/media/media_stream_audio_track.cc b/chromium/content/renderer/media/media_stream_audio_track.cc index 575c277e8e3..b6ec78e871f 100644 --- a/chromium/content/renderer/media/media_stream_audio_track.cc +++ b/chromium/content/renderer/media/media_stream_audio_track.cc @@ -31,7 +31,7 @@ MediaStreamAudioTrack* MediaStreamAudioTrack::From( track.source().getType() != blink::WebMediaStreamSource::TypeAudio) { return nullptr; } - return static_cast<MediaStreamAudioTrack*>(track.getExtraData()); + return static_cast<MediaStreamAudioTrack*>(track.getTrackData()); } void MediaStreamAudioTrack::AddSink(MediaStreamAudioSink* sink) { @@ -131,4 +131,10 @@ void MediaStreamAudioTrack::OnData(const media::AudioBus& audio_bus, } } +void MediaStreamAudioTrack::getSettings( + blink::WebMediaStreamTrack::Settings& settings) { + // TODO(hta): Extract the real value. + settings.deviceId = blink::WebString("audio device ID"); +} + } // namespace content diff --git a/chromium/content/renderer/media/media_stream_audio_track.h b/chromium/content/renderer/media/media_stream_audio_track.h index c8c2b8482a8..2e43b42e756 100644 --- a/chromium/content/renderer/media/media_stream_audio_track.h +++ b/chromium/content/renderer/media/media_stream_audio_track.h @@ -90,6 +90,8 @@ class CONTENT_EXPORT MediaStreamAudioTrack : public MediaStreamTrack { // delivered to the sinks instead of the content of |audio_bus|. void OnData(const media::AudioBus& audio_bus, base::TimeTicks reference_time); + void getSettings(blink::WebMediaStreamTrack::Settings& settings) override; + private: // In debug builds, check that all methods that could cause object graph // or data flow changes are being called on the main thread. diff --git a/chromium/content/renderer/media/media_stream_audio_unittest.cc b/chromium/content/renderer/media/media_stream_audio_unittest.cc index 060dca37b07..022bedd37e3 100644 --- a/chromium/content/renderer/media/media_stream_audio_unittest.cc +++ b/chromium/content/renderer/media/media_stream_audio_unittest.cc @@ -38,8 +38,11 @@ class FakeMediaStreamAudioSource public base::PlatformThread::Delegate { public: FakeMediaStreamAudioSource() - : MediaStreamAudioSource(true), stop_event_(true, false), - next_buffer_size_(kBufferSize), sample_count_(0) {} + : MediaStreamAudioSource(true), + stop_event_(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED), + next_buffer_size_(kBufferSize), + sample_count_(0) {} ~FakeMediaStreamAudioSource() final { CHECK(main_thread_checker_.CalledOnValidThread()); diff --git a/chromium/content/renderer/media/media_stream_center.cc b/chromium/content/renderer/media/media_stream_center.cc index c08fcb56f27..2f5e1a40635 100644 --- a/chromium/content/renderer/media/media_stream_center.cc +++ b/chromium/content/renderer/media/media_stream_center.cc @@ -65,7 +65,7 @@ void CreateNativeAudioMediaStreamTrack( void CreateNativeVideoMediaStreamTrack( const blink::WebMediaStreamTrack& track) { - DCHECK(track.getExtraData() == NULL); + DCHECK(track.getTrackData() == NULL); blink::WebMediaStreamSource source = track.source(); DCHECK_EQ(source.getType(), blink::WebMediaStreamSource::TypeVideo); MediaStreamVideoSource* native_source = @@ -80,10 +80,9 @@ void CreateNativeVideoMediaStreamTrack( blink::WebMediaConstraints constraints = source.constraints(); if (constraints.isNull()) constraints.initialize(); - writable_track.setExtraData( - new MediaStreamVideoTrack(native_source, constraints, - MediaStreamVideoSource::ConstraintsCallback(), - track.isEnabled())); + writable_track.setTrackData(new MediaStreamVideoTrack( + native_source, constraints, MediaStreamVideoSource::ConstraintsCallback(), + track.isEnabled())); } } // namespace @@ -97,7 +96,7 @@ MediaStreamCenter::~MediaStreamCenter() {} void MediaStreamCenter::didCreateMediaStreamTrack( const blink::WebMediaStreamTrack& track) { DVLOG(1) << "MediaStreamCenter::didCreateMediaStreamTrack"; - DCHECK(!track.isNull() && !track.getExtraData()); + DCHECK(!track.isNull() && !track.getTrackData()); DCHECK(!track.source().isNull()); switch (track.source().getType()) { @@ -139,7 +138,7 @@ MediaStreamCenter::createWebAudioSourceFromMediaStreamTrack( const blink::WebMediaStreamTrack& track) { DVLOG(1) << "MediaStreamCenter::createWebAudioSourceFromMediaStreamTrack"; MediaStreamTrack* media_stream_track = - static_cast<MediaStreamTrack*>(track.getExtraData()); + static_cast<MediaStreamTrack*>(track.getTrackData()); if (!media_stream_track) { DLOG(ERROR) << "Native track missing for webaudio source."; return nullptr; diff --git a/chromium/content/renderer/media/media_stream_renderer_factory_impl.cc b/chromium/content/renderer/media/media_stream_renderer_factory_impl.cc index 78cd37500f0..b3d137883b8 100644 --- a/chromium/content/renderer/media/media_stream_renderer_factory_impl.cc +++ b/chromium/content/renderer/media/media_stream_renderer_factory_impl.cc @@ -57,17 +57,17 @@ MediaStreamRendererFactoryImpl::MediaStreamRendererFactoryImpl() { MediaStreamRendererFactoryImpl::~MediaStreamRendererFactoryImpl() { } -scoped_refptr<VideoFrameProvider> -MediaStreamRendererFactoryImpl::GetVideoFrameProvider( +scoped_refptr<MediaStreamVideoRenderer> +MediaStreamRendererFactoryImpl::GetVideoRenderer( const blink::WebMediaStream& web_stream, const base::Closure& error_cb, - const VideoFrameProvider::RepaintCB& repaint_cb, + const MediaStreamVideoRenderer::RepaintCB& repaint_cb, const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, const scoped_refptr<base::TaskRunner>& worker_task_runner, media::GpuVideoAcceleratorFactories* gpu_factories) { DCHECK(!web_stream.isNull()); - DVLOG(1) << "MediaStreamRendererFactoryImpl::GetVideoFrameProvider stream:" + DVLOG(1) << "MediaStreamRendererFactoryImpl::GetVideoRenderer stream:" << base::UTF16ToUTF8(base::StringPiece16(web_stream.id())); blink::WebVector<blink::WebMediaStreamTrack> video_tracks; diff --git a/chromium/content/renderer/media/media_stream_renderer_factory_impl.h b/chromium/content/renderer/media/media_stream_renderer_factory_impl.h index 33519efe73d..1305e086932 100644 --- a/chromium/content/renderer/media/media_stream_renderer_factory_impl.h +++ b/chromium/content/renderer/media/media_stream_renderer_factory_impl.h @@ -15,10 +15,10 @@ class MediaStreamRendererFactoryImpl : public MediaStreamRendererFactory { MediaStreamRendererFactoryImpl(); ~MediaStreamRendererFactoryImpl() override; - scoped_refptr<VideoFrameProvider> GetVideoFrameProvider( + scoped_refptr<MediaStreamVideoRenderer> GetVideoRenderer( const blink::WebMediaStream& web_stream, const base::Closure& error_cb, - const VideoFrameProvider::RepaintCB& repaint_cb, + const MediaStreamVideoRenderer::RepaintCB& repaint_cb, const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, const scoped_refptr<base::TaskRunner>& worker_task_runner, media::GpuVideoAcceleratorFactories* gpu_factories) override; diff --git a/chromium/content/renderer/media/media_stream_source.cc b/chromium/content/renderer/media/media_stream_source.cc index d2b4cbf7f9b..23a459dcbfa 100644 --- a/chromium/content/renderer/media/media_stream_source.cc +++ b/chromium/content/renderer/media/media_stream_source.cc @@ -15,13 +15,15 @@ MediaStreamSource::MediaStreamSource() { MediaStreamSource::~MediaStreamSource() { DCHECK(thread_checker_.CalledOnValidThread()); - RunStopCallbackAndEndStream(); + DCHECK(stop_callback_.is_null()); } void MediaStreamSource::StopSource() { DCHECK(thread_checker_.CalledOnValidThread()); DoStopSource(); - RunStopCallbackAndEndStream(); + if (!stop_callback_.is_null()) + base::ResetAndReturn(&stop_callback_).Run(owner()); + owner().setReadyState(blink::WebMediaStreamSource::ReadyStateEnded); } void MediaStreamSource::SetDeviceInfo(const StreamDeviceInfo& device_info) { @@ -42,12 +44,4 @@ void MediaStreamSource::ResetSourceStoppedCallback() { stop_callback_.Reset(); } -void MediaStreamSource::RunStopCallbackAndEndStream() { - DCHECK(thread_checker_.CalledOnValidThread()); - if (!stop_callback_.is_null()) - base::ResetAndReturn(&stop_callback_).Run(owner()); - if (!owner().isNull()) - owner().setReadyState(blink::WebMediaStreamSource::ReadyStateEnded); -} - } // namespace content diff --git a/chromium/content/renderer/media/media_stream_source.h b/chromium/content/renderer/media/media_stream_source.h index 7c451564d6f..23b896ae88e 100644 --- a/chromium/content/renderer/media/media_stream_source.h +++ b/chromium/content/renderer/media/media_stream_source.h @@ -66,11 +66,6 @@ class CONTENT_EXPORT MediaStreamSource virtual void DoStopSource() = 0; private: - // Called by both StopSource() and the destructor to ensure the - // |stop_callback_| has been run and the blink::WebMediaStreamSource's ready - // state has been set to "ended." - void RunStopCallbackAndEndStream(); - StreamDeviceInfo device_info_; SourceStoppedCallback stop_callback_; diff --git a/chromium/content/renderer/media/media_stream_track.cc b/chromium/content/renderer/media/media_stream_track.cc index fa0cb90d266..27fff26a874 100644 --- a/chromium/content/renderer/media/media_stream_track.cc +++ b/chromium/content/renderer/media/media_stream_track.cc @@ -10,7 +10,7 @@ namespace content { MediaStreamTrack* MediaStreamTrack::GetTrack( const blink::WebMediaStreamTrack& track) { return track.isNull() ? nullptr - : static_cast<MediaStreamTrack*>(track.getExtraData()); + : static_cast<MediaStreamTrack*>(track.getTrackData()); } MediaStreamTrack::MediaStreamTrack(bool is_local_track) diff --git a/chromium/content/renderer/media/media_stream_track.h b/chromium/content/renderer/media/media_stream_track.h index 8640f6a8238..c09c5088e1e 100644 --- a/chromium/content/renderer/media/media_stream_track.h +++ b/chromium/content/renderer/media/media_stream_track.h @@ -18,7 +18,7 @@ namespace content { // It is owned by blink::WebMediaStreamTrack as // blink::WebMediaStreamTrack::ExtraData. class CONTENT_EXPORT MediaStreamTrack - : NON_EXPORTED_BASE(public blink::WebMediaStreamTrack::ExtraData) { + : NON_EXPORTED_BASE(public blink::WebMediaStreamTrack::TrackData) { public: explicit MediaStreamTrack(bool is_local_track); ~MediaStreamTrack() override; @@ -29,6 +29,9 @@ class CONTENT_EXPORT MediaStreamTrack virtual void Stop() = 0; + // TODO(hta): Make method pure virtual when all tracks have the method. + void getSettings(blink::WebMediaStreamTrack::Settings& settings) override {} + bool is_local_track() const { return is_local_track_; } protected: diff --git a/chromium/content/renderer/media/media_stream_video_capturer_source.h b/chromium/content/renderer/media/media_stream_video_capturer_source.h index a6013d0fcbb..62301bc27e3 100644 --- a/chromium/content/renderer/media/media_stream_video_capturer_source.h +++ b/chromium/content/renderer/media/media_stream_video_capturer_source.h @@ -56,8 +56,7 @@ class CONTENT_EXPORT MediaStreamVideoCapturerSource const VideoCaptureDeliverFrameCB& frame_callback) override; void StopSourceImpl() override; - // RenderFrame does NOT own this object. Avoid unintended multiple destruction - // by overriding RenderFrameObserver::OnDestruct(). + // RenderFrameObserver implementation. void OnDestruct() final {} // Method to bind as RunningCallback in VideoCapturerSource::StartCapture(). diff --git a/chromium/content/renderer/media/media_stream_video_renderer_sink.cc b/chromium/content/renderer/media/media_stream_video_renderer_sink.cc index f9ce2df942e..1fe5e6501a2 100644 --- a/chromium/content/renderer/media/media_stream_video_renderer_sink.cc +++ b/chromium/content/renderer/media/media_stream_video_renderer_sink.cc @@ -75,7 +75,7 @@ void MediaStreamVideoRendererSink::Stop() { frame_size_.set_height(kMinFrameSize); } -void MediaStreamVideoRendererSink::Play() { +void MediaStreamVideoRendererSink::Resume() { DCHECK(task_runner_->BelongsToCurrentThread()); if (state_ == PAUSED) state_ = STARTED; diff --git a/chromium/content/renderer/media/media_stream_video_renderer_sink.h b/chromium/content/renderer/media/media_stream_video_renderer_sink.h index d858062a453..425ca6cc2c2 100644 --- a/chromium/content/renderer/media/media_stream_video_renderer_sink.h +++ b/chromium/content/renderer/media/media_stream_video_renderer_sink.h @@ -10,8 +10,8 @@ #include "base/memory/weak_ptr.h" #include "content/common/content_export.h" #include "content/common/media/video_capture.h" +#include "content/public/renderer/media_stream_video_renderer.h" #include "content/public/renderer/media_stream_video_sink.h" -#include "content/public/renderer/video_frame_provider.h" #include "media/video/gpu_memory_buffer_video_frame_pool.h" #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" #include "ui/gfx/geometry/size.h" @@ -27,12 +27,12 @@ class GpuVideoAcceleratorFactories; namespace content { -// MediaStreamVideoRendererSink is a VideoFrameProvider designed for rendering -// Video MediaStreamTracks [1], MediaStreamVideoRendererSink implements -// MediaStreamVideoSink in order to render video frames provided from a -// MediaStreamVideoTrack, to which it connects itself when the -// VideoFrameProvider is Start()ed, and disconnects itself when the latter is -// Stop()ed. +// MediaStreamVideoRendererSink is a MediaStreamVideoRenderer designed for +// rendering Video MediaStreamTracks [1], MediaStreamVideoRendererSink +// implements MediaStreamVideoSink in order to render video frames provided from +// a MediaStreamVideoTrack, to which it connects itself when the +// MediaStreamVideoRenderer is Start()ed, and disconnects itself when the latter +// is Stop()ed. // // [1] http://dev.w3.org/2011/webrtc/editor/getusermedia.html#mediastreamtrack // @@ -40,22 +40,23 @@ namespace content { // http://src.chromium.org/viewvc/chrome/trunk/src/content/renderer/media/rtc_vi // deo_decoder_unittest.cc?revision=180591&view=markup class CONTENT_EXPORT MediaStreamVideoRendererSink - : NON_EXPORTED_BASE(public VideoFrameProvider), + : NON_EXPORTED_BASE(public MediaStreamVideoRenderer), NON_EXPORTED_BASE(public MediaStreamVideoSink) { public: MediaStreamVideoRendererSink( const blink::WebMediaStreamTrack& video_track, const base::Closure& error_cb, - const RepaintCB& repaint_cb, + const MediaStreamVideoRenderer::RepaintCB& repaint_cb, const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, const scoped_refptr<base::TaskRunner>& worker_task_runner, media::GpuVideoAcceleratorFactories* gpu_factories); - // VideoFrameProvider implementation. Called on the main thread. + // MediaStreamVideoRenderer implementation. Called on the main thread. void Start() override; void Stop() override; - void Play() override; + void Resume() override; void Pause() override; + void SetGpuMemoryBufferVideoForTesting( media::GpuMemoryBufferVideoFramePool* gpu_memory_buffer_pool); diff --git a/chromium/content/renderer/media/media_stream_video_renderer_sink_unittest.cc b/chromium/content/renderer/media/media_stream_video_renderer_sink_unittest.cc index 77edaf85ce1..258b7a7bb39 100644 --- a/chromium/content/renderer/media/media_stream_video_renderer_sink_unittest.cc +++ b/chromium/content/renderer/media/media_stream_video_renderer_sink_unittest.cc @@ -108,7 +108,7 @@ TEST_F(MediaStreamVideoRendererSinkTest, StartStop) { media_stream_video_renderer_sink_->Pause(); EXPECT_TRUE(IsInPausedState()); - media_stream_video_renderer_sink_->Play(); // Should be called Resume(). + media_stream_video_renderer_sink_->Resume(); EXPECT_TRUE(IsInStartedState()); media_stream_video_renderer_sink_->Stop(); diff --git a/chromium/content/renderer/media/media_stream_video_source.cc b/chromium/content/renderer/media/media_stream_video_source.cc index 09ebd0ad76b..ae3df0fa96f 100644 --- a/chromium/content/renderer/media/media_stream_video_source.cc +++ b/chromium/content/renderer/media/media_stream_video_source.cc @@ -18,28 +18,6 @@ namespace content { -// Constraint keys. Specified by draft-alvestrand-constraints-resolution-00b -const char MediaStreamVideoSource::kMinAspectRatio[] = "minAspectRatio"; -const char MediaStreamVideoSource::kMaxAspectRatio[] = "maxAspectRatio"; -const char MediaStreamVideoSource::kMaxWidth[] = "maxWidth"; -const char MediaStreamVideoSource::kMinWidth[] = "minWidth"; -const char MediaStreamVideoSource::kMaxHeight[] = "maxHeight"; -const char MediaStreamVideoSource::kMinHeight[] = "minHeight"; -const char MediaStreamVideoSource::kMaxFrameRate[] = "maxFrameRate"; -const char MediaStreamVideoSource::kMinFrameRate[] = "minFrameRate"; - -// TODO(mcasas): Find a way to guarantee all constraints are added to the array. -const char* const kSupportedConstraints[] = { - MediaStreamVideoSource::kMaxAspectRatio, - MediaStreamVideoSource::kMinAspectRatio, - MediaStreamVideoSource::kMaxWidth, - MediaStreamVideoSource::kMinWidth, - MediaStreamVideoSource::kMaxHeight, - MediaStreamVideoSource::kMinHeight, - MediaStreamVideoSource::kMaxFrameRate, - MediaStreamVideoSource::kMinFrameRate, -}; - namespace { const char* const kLegalVideoConstraints[] = { @@ -305,14 +283,6 @@ MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource( return static_cast<MediaStreamVideoSource*>(source.getExtraData()); } -// static, deprecated -bool MediaStreamVideoSource::IsConstraintSupported(const std::string& name) { - return std::find(kSupportedConstraints, - kSupportedConstraints + arraysize(kSupportedConstraints), - name) != - kSupportedConstraints + arraysize(kSupportedConstraints); -} - MediaStreamVideoSource::MediaStreamVideoSource() : state_(NEW), track_adapter_( diff --git a/chromium/content/renderer/media/media_stream_video_source.h b/chromium/content/renderer/media/media_stream_video_source.h index 550adea207b..3d79aeafb77 100644 --- a/chromium/content/renderer/media/media_stream_video_source.h +++ b/chromium/content/renderer/media/media_stream_video_source.h @@ -47,17 +47,6 @@ class CONTENT_EXPORT MediaStreamVideoSource : public MediaStreamSource, NON_EXPORTED_BASE(public base::NonThreadSafe) { public: - // Constraint keys used by a video source. - // Specified by draft-alvestrand-constraints-resolution-00b - static const char kMinAspectRatio[]; // minAspectRatio - static const char kMaxAspectRatio[]; // maxAspectRatio - static const char kMaxWidth[]; // maxWidth - static const char kMinWidth[]; // minWidth - static const char kMaxHeight[]; // maxHeight - static const char kMinHeight[]; // minHeight - static const char kMaxFrameRate[]; // maxFrameRate - static const char kMinFrameRate[]; // minFrameRate - enum { // Default resolution. If no constraints are specified and the delegate // support it, this is the resolution that will be used. @@ -84,9 +73,6 @@ class CONTENT_EXPORT MediaStreamVideoSource void UpdateCapturingLinkSecure(MediaStreamVideoTrack* track, bool is_secure); - // Return true if |name| is a constraint supported by MediaStreamVideoSource. - static bool IsConstraintSupported(const std::string& name); - // Request underlying source to capture a new frame. virtual void RequestRefreshFrame() {} diff --git a/chromium/content/renderer/media/media_stream_video_source_unittest.cc b/chromium/content/renderer/media/media_stream_video_source_unittest.cc index 8509243a8ac..64395970c04 100644 --- a/chromium/content/renderer/media/media_stream_video_source_unittest.cc +++ b/chromium/content/renderer/media/media_stream_video_source_unittest.cc @@ -681,28 +681,6 @@ TEST_F(MediaStreamVideoSourceTest, SourceChangeFrameSize) { sink.DisconnectFromTrack(); } -TEST_F(MediaStreamVideoSourceTest, IsConstraintSupported) { - EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( - MediaStreamVideoSource::kMaxFrameRate)); - EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( - MediaStreamVideoSource::kMinFrameRate)); - EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( - MediaStreamVideoSource::kMaxWidth)); - EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( - MediaStreamVideoSource::kMinWidth)); - EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( - MediaStreamVideoSource::kMaxHeight)); - EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( - MediaStreamVideoSource::kMinHeight)); - EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( - MediaStreamVideoSource::kMaxAspectRatio)); - EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( - MediaStreamVideoSource::kMinAspectRatio)); - - EXPECT_FALSE(MediaStreamVideoSource::IsConstraintSupported( - "something unsupported")); -} - // Test that the constraint negotiation can handle 0.0 fps as frame rate. TEST_F(MediaStreamVideoSourceTest, Use0FpsSupportedFormat) { media::VideoCaptureFormats formats; diff --git a/chromium/content/renderer/media/media_stream_video_track.cc b/chromium/content/renderer/media/media_stream_video_track.cc index 74893dcc424..e23b290328d 100644 --- a/chromium/content/renderer/media/media_stream_video_track.cc +++ b/chromium/content/renderer/media/media_stream_video_track.cc @@ -202,10 +202,8 @@ blink::WebMediaStreamTrack MediaStreamVideoTrack::CreateVideoTrack( bool enabled) { blink::WebMediaStreamTrack track; track.initialize(source->owner()); - track.setExtraData(new MediaStreamVideoTrack(source, - constraints, - callback, - enabled)); + track.setTrackData( + new MediaStreamVideoTrack(source, constraints, callback, enabled)); return track; } @@ -216,7 +214,7 @@ MediaStreamVideoTrack* MediaStreamVideoTrack::GetVideoTrack( track.source().getType() != blink::WebMediaStreamSource::TypeVideo) { return nullptr; } - return static_cast<MediaStreamVideoTrack*>(track.getExtraData()); + return static_cast<MediaStreamVideoTrack*>(track.getTrackData()); } MediaStreamVideoTrack::MediaStreamVideoTrack( @@ -290,6 +288,20 @@ void MediaStreamVideoTrack::Stop() { OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateEnded); } +void MediaStreamVideoTrack::getSettings( + blink::WebMediaStreamTrack::Settings& settings) { + if (source_) { + const media::VideoCaptureFormat* format = source_->GetCurrentFormat(); + if (format) { + settings.frameRate = format->frame_rate; + settings.width = format->frame_size.width(); + settings.height = format->frame_size.height(); + } + } + // TODO(hta): Extract the real value. + settings.deviceId = blink::WebString("video device ID"); +} + void MediaStreamVideoTrack::OnReadyStateChanged( blink::WebMediaStreamSource::ReadyState state) { DCHECK(main_render_thread_checker_.CalledOnValidThread()); diff --git a/chromium/content/renderer/media/media_stream_video_track.h b/chromium/content/renderer/media/media_stream_video_track.h index e74e3bc2924..436c15f86ac 100644 --- a/chromium/content/renderer/media/media_stream_video_track.h +++ b/chromium/content/renderer/media/media_stream_video_track.h @@ -53,6 +53,7 @@ class CONTENT_EXPORT MediaStreamVideoTrack : public MediaStreamTrack { // MediaStreamTrack overrides. void SetEnabled(bool enabled) override; void Stop() override; + void getSettings(blink::WebMediaStreamTrack::Settings& settings) override; void OnReadyStateChanged(blink::WebMediaStreamSource::ReadyState state); diff --git a/chromium/content/renderer/media/midi_dispatcher.cc b/chromium/content/renderer/media/midi_dispatcher.cc index 65f42a95d44..f870105dee7 100644 --- a/chromium/content/renderer/media/midi_dispatcher.cc +++ b/chromium/content/renderer/media/midi_dispatcher.cc @@ -5,10 +5,11 @@ #include "content/renderer/media/midi_dispatcher.h" #include "base/bind.h" -#include "content/public/common/service_registry.h" #include "content/public/renderer/render_frame.h" +#include "services/shell/public/cpp/interface_provider.h" #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" #include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/web/WebUserGestureIndicator.h" #include "third_party/WebKit/public/web/modules/webmidi/WebMIDIOptions.h" #include "third_party/WebKit/public/web/modules/webmidi/WebMIDIPermissionRequest.h" @@ -24,12 +25,14 @@ MidiDispatcher::MidiDispatcher(RenderFrame* render_frame) MidiDispatcher::~MidiDispatcher() {} +void MidiDispatcher::OnDestruct() { + delete this; +} + void MidiDispatcher::requestPermission(const WebMIDIPermissionRequest& request, const WebMIDIOptions& options) { - if (!permission_service_.get()) { - render_frame()->GetServiceRegistry()->ConnectToRemoteService( - mojo::GetProxy(&permission_service_)); - } + if (!permission_service_.get()) + render_frame()->GetRemoteInterfaces()->GetInterface(&permission_service_); int permission_request_id = requests_.Add(new WebMIDIPermissionRequest(request)); @@ -41,6 +44,7 @@ void MidiDispatcher::requestPermission(const WebMIDIPermissionRequest& request, permission_service_->RequestPermission( permission_name, request.getSecurityOrigin().toString().utf8(), + blink::WebUserGestureIndicator::isProcessingUserGesture(), base::Bind(&MidiDispatcher::OnPermissionSet, base::Unretained(this), permission_request_id)); } diff --git a/chromium/content/renderer/media/midi_dispatcher.h b/chromium/content/renderer/media/midi_dispatcher.h index 802328a770c..2d98117d092 100644 --- a/chromium/content/renderer/media/midi_dispatcher.h +++ b/chromium/content/renderer/media/midi_dispatcher.h @@ -28,6 +28,9 @@ class MidiDispatcher : public RenderFrameObserver, ~MidiDispatcher() override; private: + // RenderFrameObserver implementation. + void OnDestruct() override; + // blink::WebMIDIClient implementation. void requestPermission(const blink::WebMIDIPermissionRequest& request, const blink::WebMIDIOptions& options) override; diff --git a/chromium/content/renderer/media/mock_media_stream_registry.cc b/chromium/content/renderer/media/mock_media_stream_registry.cc index bad1ae790c6..91fb227ecf1 100644 --- a/chromium/content/renderer/media/mock_media_stream_registry.cc +++ b/chromium/content/renderer/media/mock_media_stream_registry.cc @@ -72,7 +72,7 @@ void MockMediaStreamRegistry::AddVideoTrack(const std::string& track_id) { MediaStreamVideoTrack* native_track = new MediaStreamVideoTrack( native_source, constraints, MediaStreamVideoSource::ConstraintsCallback(), true /* enabled */); - blink_track.setExtraData(native_track); + blink_track.setTrackData(native_track); test_stream_.addTrack(blink_track); } diff --git a/chromium/content/renderer/media/peer_connection_identity_store.h b/chromium/content/renderer/media/peer_connection_identity_store.h index cdd0ec29836..3172a2cabf4 100644 --- a/chromium/content/renderer/media/peer_connection_identity_store.h +++ b/chromium/content/renderer/media/peer_connection_identity_store.h @@ -16,6 +16,8 @@ namespace content { // This class is associated with a peer connection and handles WebRTC DTLS // identity requests by delegating to the per-renderer WebRTCIdentityProxy. +// TODO(hbos): Remove this store, it is no longer used. +// See bugs.webrtc.org/5707, bugs.webrtc.org/5708. class PeerConnectionIdentityStore : public webrtc::DtlsIdentityStoreInterface { public: diff --git a/chromium/content/renderer/media/pepper_to_video_track_adapter.cc b/chromium/content/renderer/media/pepper_to_video_track_adapter.cc index f1dfa51f6fe..afd3b20be0f 100644 --- a/chromium/content/renderer/media/pepper_to_video_track_adapter.cc +++ b/chromium/content/renderer/media/pepper_to_video_track_adapter.cc @@ -209,7 +209,7 @@ class PpFrameWriterProxy : public FrameWriterInterface { public: explicit PpFrameWriterProxy(const base::WeakPtr<PpFrameWriter>& writer) : writer_(writer) { - DCHECK(writer_ != NULL); + DCHECK(writer_); } ~PpFrameWriterProxy() override {} diff --git a/chromium/content/renderer/media/pepper_to_video_track_adapter_unittest.cc b/chromium/content/renderer/media/pepper_to_video_track_adapter_unittest.cc index 0c13cb6fff7..da0d50cb975 100644 --- a/chromium/content/renderer/media/pepper_to_video_track_adapter_unittest.cc +++ b/chromium/content/renderer/media/pepper_to_video_track_adapter_unittest.cc @@ -98,7 +98,7 @@ TEST_F(PepperToVideoTrackAdapterTest, PutFrame) { // PostTaskAndReply to the IO thread and expects the reply to process // on the main render thread to clean up its resources. However, the // QuitClosure above ends before that. - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } EXPECT_EQ(1, sink.number_of_frames()); native_track->RemoveSink(&sink); diff --git a/chromium/content/renderer/media/remote_media_stream_impl.cc b/chromium/content/renderer/media/remote_media_stream_impl.cc index 5f449c03821..8dca0e663cd 100644 --- a/chromium/content/renderer/media/remote_media_stream_impl.cc +++ b/chromium/content/renderer/media/remote_media_stream_impl.cc @@ -167,7 +167,7 @@ class RemoteVideoTrackAdapter MediaStreamVideoTrack* media_stream_track = new MediaStreamVideoTrack(video_source.release(), constraints, MediaStreamVideoSource::ConstraintsCallback(), enabled); - webkit_track()->setExtraData(media_stream_track); + webkit_track()->setTrackData(media_stream_track); } }; diff --git a/chromium/content/renderer/media/render_media_log.cc b/chromium/content/renderer/media/render_media_log.cc index bcc3301aa35..25defe5c466 100644 --- a/chromium/content/renderer/media/render_media_log.cc +++ b/chromium/content/renderer/media/render_media_log.cc @@ -13,6 +13,8 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/default_tick_clock.h" #include "content/common/view_messages.h" +#include "content/public/common/content_client.h" +#include "content/public/renderer/content_renderer_client.h" #include "content/public/renderer/render_thread.h" namespace { @@ -34,8 +36,9 @@ void Log(media::MediaLogEvent* event) { namespace content { -RenderMediaLog::RenderMediaLog() - : task_runner_(base::ThreadTaskRunnerHandle::Get()), +RenderMediaLog::RenderMediaLog(const GURL& security_origin) + : security_origin_(security_origin), + task_runner_(base::ThreadTaskRunnerHandle::Get()), tick_clock_(new base::DefaultTickClock()), last_ipc_send_time_(tick_clock_->NowTicks()), ipc_send_pending_(false) { @@ -118,6 +121,17 @@ std::string RenderMediaLog::GetLastErrorMessage() { return result.str(); } +void RenderMediaLog::RecordRapporWithSecurityOrigin(const std::string& metric) { + if (!task_runner_->BelongsToCurrentThread()) { + task_runner_->PostTask( + FROM_HERE, base::Bind(&RenderMediaLog::RecordRapporWithSecurityOrigin, + this, metric)); + return; + } + + GetContentClient()->renderer()->RecordRapporURL(metric, security_origin_); +} + void RenderMediaLog::SendQueuedMediaEvents() { DCHECK(task_runner_->BelongsToCurrentThread()); diff --git a/chromium/content/renderer/media/render_media_log.h b/chromium/content/renderer/media/render_media_log.h index 3606b98e928..e9b655aed4b 100644 --- a/chromium/content/renderer/media/render_media_log.h +++ b/chromium/content/renderer/media/render_media_log.h @@ -13,6 +13,7 @@ #include "base/time/time.h" #include "content/common/content_export.h" #include "media/base/media_log.h" +#include "url/gurl.h" namespace base { class TickClock; @@ -32,11 +33,12 @@ namespace content { // It must be constructed on the render thread. class CONTENT_EXPORT RenderMediaLog : public media::MediaLog { public: - RenderMediaLog(); + explicit RenderMediaLog(const GURL& security_origin); // MediaLog implementation. void AddEvent(std::unique_ptr<media::MediaLogEvent> event) override; std::string GetLastErrorMessage() override; + void RecordRapporWithSecurityOrigin(const std::string& metric) override; // Will reset |last_ipc_send_time_| with the value of NowTicks(). void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock); @@ -50,6 +52,9 @@ class CONTENT_EXPORT RenderMediaLog : public media::MediaLog { // frequency. void SendQueuedMediaEvents(); + // Security origin of the current frame. + const GURL security_origin_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; // |lock_| protects access to all of the following member variables. It diff --git a/chromium/content/renderer/media/render_media_log_unittest.cc b/chromium/content/renderer/media/render_media_log_unittest.cc index 131da078c19..c383dcd86a1 100644 --- a/chromium/content/renderer/media/render_media_log_unittest.cc +++ b/chromium/content/renderer/media/render_media_log_unittest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <tuple> + #include "base/macros.h" #include "base/test/simple_test_tick_clock.h" #include "base/test/test_mock_time_task_runner.h" @@ -15,7 +17,7 @@ namespace content { class RenderMediaLogTest : public testing::Test { public: RenderMediaLogTest() - : log_(new RenderMediaLog()), + : log_(new RenderMediaLog(GURL("http://foo.com"))), tick_clock_(new base::SimpleTestTickClock()), task_runner_(new base::TestMockTimeTaskRunner()) { log_->SetTickClockForTesting(std::unique_ptr<base::TickClock>(tick_clock_)); @@ -47,9 +49,9 @@ class RenderMediaLogTest : public testing::Test { return std::vector<media::MediaLogEvent>(); } - base::Tuple<std::vector<media::MediaLogEvent>> events; + std::tuple<std::vector<media::MediaLogEvent>> events; ViewHostMsg_MediaLogEvents::Read(msg, &events); - return base::get<0>(events); + return std::get<0>(events); } private: diff --git a/chromium/content/renderer/media/renderer_webaudiodevice_impl.cc b/chromium/content/renderer/media/renderer_webaudiodevice_impl.cc index a9fba3b4e21..7f648538c69 100644 --- a/chromium/content/renderer/media/renderer_webaudiodevice_impl.cc +++ b/chromium/content/renderer/media/renderer_webaudiodevice_impl.cc @@ -72,7 +72,7 @@ void RendererWebAudioDeviceImpl::start() { RenderFrame* const render_frame = web_frame ? RenderFrame::FromWebFrame(web_frame) : NULL; sink_ = AudioDeviceFactory::NewAudioRendererSink( - AudioDeviceFactory::kSourceWebAudio, + AudioDeviceFactory::kSourceWebAudioInteractive, render_frame ? render_frame->GetRoutingID() : MSG_ROUTING_NONE, session_id_, std::string(), security_origin_); sink_->Initialize(params_, this); diff --git a/chromium/content/renderer/media/renderer_webmediaplayer_delegate.cc b/chromium/content/renderer/media/renderer_webmediaplayer_delegate.cc index 57a25e69958..f3b8125aa29 100644 --- a/chromium/content/renderer/media/renderer_webmediaplayer_delegate.cc +++ b/chromium/content/renderer/media/renderer_webmediaplayer_delegate.cc @@ -174,4 +174,8 @@ void RendererWebMediaPlayerDelegate::CleanupIdleDelegates() { idle_cleanup_timer_.Stop(); } +void RendererWebMediaPlayerDelegate::OnDestruct() { + delete this; +} + } // namespace media diff --git a/chromium/content/renderer/media/renderer_webmediaplayer_delegate.h b/chromium/content/renderer/media/renderer_webmediaplayer_delegate.h index b12a58f971d..0e8307744c1 100644 --- a/chromium/content/renderer/media/renderer_webmediaplayer_delegate.h +++ b/chromium/content/renderer/media/renderer_webmediaplayer_delegate.h @@ -53,6 +53,7 @@ class CONTENT_EXPORT RendererWebMediaPlayerDelegate void WasHidden() override; void WasShown() override; bool OnMessageReceived(const IPC::Message& msg) override; + void OnDestruct() override; // Zeros out |idle_cleanup_interval_|, and sets |idle_timeout_| to // |idle_timeout|. A zero cleanup interval will cause the idle timer to run diff --git a/chromium/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc b/chromium/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc index 4872ec891cd..4fe4fdb4525 100644 --- a/chromium/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc +++ b/chromium/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc @@ -2,11 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <tuple> + #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/location.h" #include "base/run_loop.h" +#include "base/single_thread_task_runner.h" #include "base/test/simple_test_tick_clock.h" -#include "base/tuple.h" +#include "base/threading/thread_task_runner_handle.h" #include "content/common/media/media_player_delegate_messages.h" #include "content/public/renderer/render_view.h" #include "content/public/test/render_view_test.h" @@ -78,13 +82,13 @@ TEST_F(RendererWebMediaPlayerDelegateTest, SendsMessagesCorrectly) { MediaPlayerDelegateHostMsg_OnMediaPlaying::ID); ASSERT_TRUE(msg); - base::Tuple<int, bool, bool, bool, base::TimeDelta> result; + std::tuple<int, bool, bool, bool, base::TimeDelta> result; ASSERT_TRUE(MediaPlayerDelegateHostMsg_OnMediaPlaying::Read(msg, &result)); - EXPECT_EQ(delegate_id, base::get<0>(result)); - EXPECT_EQ(kHasVideo, base::get<1>(result)); - EXPECT_EQ(kHasAudio, base::get<2>(result)); - EXPECT_EQ(kIsRemote, base::get<3>(result)); - EXPECT_EQ(kDuration, base::get<4>(result)); + EXPECT_EQ(delegate_id, std::get<0>(result)); + EXPECT_EQ(kHasVideo, std::get<1>(result)); + EXPECT_EQ(kHasAudio, std::get<2>(result)); + EXPECT_EQ(kIsRemote, std::get<3>(result)); + EXPECT_EQ(kDuration, std::get<4>(result)); } // Verify the paused message. @@ -97,10 +101,10 @@ TEST_F(RendererWebMediaPlayerDelegateTest, SendsMessagesCorrectly) { MediaPlayerDelegateHostMsg_OnMediaPaused::ID); ASSERT_TRUE(msg); - base::Tuple<int, bool> result; + std::tuple<int, bool> result; ASSERT_TRUE(MediaPlayerDelegateHostMsg_OnMediaPaused::Read(msg, &result)); - EXPECT_EQ(delegate_id, base::get<0>(result)); - EXPECT_EQ(kReachedEndOfStream, base::get<1>(result)); + EXPECT_EQ(delegate_id, std::get<0>(result)); + EXPECT_EQ(kReachedEndOfStream, std::get<1>(result)); } // Verify the destruction message. @@ -111,10 +115,10 @@ TEST_F(RendererWebMediaPlayerDelegateTest, SendsMessagesCorrectly) { MediaPlayerDelegateHostMsg_OnMediaDestroyed::ID); ASSERT_TRUE(msg); - base::Tuple<int> result; + std::tuple<int> result; ASSERT_TRUE( MediaPlayerDelegateHostMsg_OnMediaDestroyed::Read(msg, &result)); - EXPECT_EQ(delegate_id, base::get<0>(result)); + EXPECT_EQ(delegate_id, std::get<0>(result)); } delegate_manager_->RemoveObserver(delegate_id); @@ -184,7 +188,8 @@ TEST_F(RendererWebMediaPlayerDelegateTest, IdleDelegatesAreSuspended) { &RendererWebMediaPlayerDelegate::PlayerGone, base::Unretained(delegate_manager_.get()), delegate_id_2))); base::RunLoop run_loop; - base::MessageLoop::current()->PostTask(FROM_HERE, run_loop.QuitClosure()); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + run_loop.QuitClosure()); tick_clock.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); run_loop.Run(); } @@ -203,7 +208,8 @@ TEST_F(RendererWebMediaPlayerDelegateTest, IdleDelegatesAreSuspended) { EXPECT_CALL(observer_1, OnSuspendRequested(false)) .Times(testing::AtLeast(1)); base::RunLoop run_loop; - base::MessageLoop::current()->PostTask(FROM_HERE, run_loop.QuitClosure()); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + run_loop.QuitClosure()); tick_clock.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); run_loop.Run(); } @@ -222,7 +228,8 @@ TEST_F(RendererWebMediaPlayerDelegateTest, IdleDelegatesAreSuspended) { &RendererWebMediaPlayerDelegate::PlayerGone, base::Unretained(delegate_manager_.get()), delegate_id_1))); base::RunLoop run_loop; - base::MessageLoop::current()->PostTask(FROM_HERE, run_loop.QuitClosure()); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + run_loop.QuitClosure()); tick_clock.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); run_loop.Run(); } @@ -253,7 +260,8 @@ TEST_F(RendererWebMediaPlayerDelegateTest, IdleDelegatesIgnoresSuspendRequest) { // Wait for the suspend request, but don't call PlayerGone(). EXPECT_CALL(observer_1, OnSuspendRequested(false)); base::RunLoop run_loop; - base::MessageLoop::current()->PostTask(FROM_HERE, run_loop.QuitClosure()); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + run_loop.QuitClosure()); tick_clock.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); run_loop.Run(); diff --git a/chromium/content/renderer/media/rtc_certificate_generator.cc b/chromium/content/renderer/media/rtc_certificate_generator.cc index 94b94fb1c89..94626e50063 100644 --- a/chromium/content/renderer/media/rtc_certificate_generator.cc +++ b/chromium/content/renderer/media/rtc_certificate_generator.cc @@ -9,11 +9,13 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "content/renderer/media/peer_connection_identity_store.h" +#include "base/memory/ref_counted.h" +#include "base/single_thread_task_runner.h" #include "content/renderer/media/rtc_certificate.h" #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" #include "content/renderer/render_thread_impl.h" #include "third_party/webrtc/base/rtccertificate.h" +#include "third_party/webrtc/base/rtccertificategenerator.h" #include "third_party/webrtc/base/scoped_ref_ptr.h" #include "url/gurl.h" @@ -35,158 +37,109 @@ rtc::KeyParams WebRTCKeyParamsToKeyParams( } } -// Observer used by RTCCertificateGenerator::generateCertificate. -class RTCCertificateIdentityObserver - : public webrtc::DtlsIdentityRequestObserver { +// A certificate generation request spawned by +// |RTCCertificateGenerator::generateCertificateWithOptionalExpiration|. This +// is handled by a separate class so that reference counting can keep the +// request alive independently of the |RTCCertificateGenerator| that spawned it. +class RTCCertificateGeneratorRequest + : public base::RefCountedThreadSafe<RTCCertificateGeneratorRequest> { public: - RTCCertificateIdentityObserver( + RTCCertificateGeneratorRequest( const scoped_refptr<base::SingleThreadTaskRunner>& main_thread, - const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread) + const scoped_refptr<base::SingleThreadTaskRunner>& worker_thread) : main_thread_(main_thread), - signaling_thread_(signaling_thread), - observer_(nullptr) { + worker_thread_(worker_thread) { DCHECK(main_thread_); - DCHECK(signaling_thread_); + DCHECK(worker_thread_); } - ~RTCCertificateIdentityObserver() override {} - // Perform |store|->RequestIdentity with this identity observer and ensure - // that this identity observer is not deleted until the request has completed - // by holding on to a reference to itself for the duration of the request. - void RequestIdentity( + void GenerateCertificateAsync( const blink::WebRTCKeyParams& key_params, - const GURL& url, - const GURL& first_party_for_cookies, const rtc::Optional<uint64_t>& expires_ms, std::unique_ptr<blink::WebRTCCertificateCallback> observer) { DCHECK(main_thread_->BelongsToCurrentThread()); - DCHECK(!observer_) << "Already have a RequestIdentity in progress."; - key_params_ = key_params; - observer_ = std::move(observer); - DCHECK(observer_); - // Identity request must be performed on the WebRTC signaling thread. - signaling_thread_->PostTask(FROM_HERE, base::Bind( - &RTCCertificateIdentityObserver::RequestIdentityOnWebRtcSignalingThread, - this, url, first_party_for_cookies, expires_ms)); + DCHECK(observer); + worker_thread_->PostTask(FROM_HERE, base::Bind( + &RTCCertificateGeneratorRequest::GenerateCertificateOnWorkerThread, + this, + key_params, + expires_ms, + base::Passed(std::move(observer)))); } private: - void RequestIdentityOnWebRtcSignalingThread( - GURL url, - GURL first_party_for_cookies, - rtc::Optional<uint64_t> expires_ms) { - DCHECK(signaling_thread_->BelongsToCurrentThread()); - std::unique_ptr<PeerConnectionIdentityStore> store( - new PeerConnectionIdentityStore(main_thread_, signaling_thread_, url, - first_party_for_cookies)); - // Request identity with |this| as the observer. OnSuccess/OnFailure will be - // called asynchronously. - store->RequestIdentity(WebRTCKeyParamsToKeyParams(key_params_), - expires_ms, this); - } + friend class base::RefCountedThreadSafe<RTCCertificateGeneratorRequest>; + ~RTCCertificateGeneratorRequest() {} + + void GenerateCertificateOnWorkerThread( + const blink::WebRTCKeyParams key_params, + const rtc::Optional<uint64_t> expires_ms, + std::unique_ptr<blink::WebRTCCertificateCallback> observer) { + DCHECK(worker_thread_->BelongsToCurrentThread()); - // webrtc::DtlsIdentityRequestObserver implementation. - void OnFailure(int error) override { - DCHECK(signaling_thread_->BelongsToCurrentThread()); - DCHECK(observer_); - main_thread_->PostTask(FROM_HERE, base::Bind( - &RTCCertificateIdentityObserver::DoCallbackOnMainThread, - this, nullptr)); - } - void OnSuccess(const std::string& der_cert, - const std::string& der_private_key) override { - std::string pem_cert = rtc::SSLIdentity::DerToPem( - rtc::kPemTypeCertificate, - reinterpret_cast<const unsigned char*>(der_cert.data()), - der_cert.length()); - std::string pem_key = rtc::SSLIdentity::DerToPem( - rtc::kPemTypeRsaPrivateKey, - reinterpret_cast<const unsigned char*>(der_private_key.data()), - der_private_key.length()); - OnSuccess(std::unique_ptr<rtc::SSLIdentity>( - rtc::SSLIdentity::FromPEMStrings(pem_key, pem_cert))); - } - void OnSuccess(std::unique_ptr<rtc::SSLIdentity> identity) override { - DCHECK(signaling_thread_->BelongsToCurrentThread()); - DCHECK(observer_); rtc::scoped_refptr<rtc::RTCCertificate> certificate = - rtc::RTCCertificate::Create(std::move(identity)); - main_thread_->PostTask( - FROM_HERE, - base::Bind(&RTCCertificateIdentityObserver::DoCallbackOnMainThread, - this, base::Passed(base::WrapUnique( - new RTCCertificate(certificate))))); + rtc::RTCCertificateGenerator::GenerateCertificate( + WebRTCKeyParamsToKeyParams(key_params), expires_ms); + + main_thread_->PostTask(FROM_HERE, base::Bind( + &RTCCertificateGeneratorRequest::DoCallbackOnMainThread, + this, + base::Passed(std::move(observer)), + base::Passed(base::WrapUnique(new RTCCertificate(certificate))))); } void DoCallbackOnMainThread( + std::unique_ptr<blink::WebRTCCertificateCallback> observer, std::unique_ptr<blink::WebRTCCertificate> certificate) { DCHECK(main_thread_->BelongsToCurrentThread()); - DCHECK(observer_); + DCHECK(observer); if (certificate) - observer_->onSuccess(std::move(certificate)); + observer->onSuccess(std::move(certificate)); else - observer_->onError(); - observer_.reset(); + observer->onError(); } // The main thread is the renderer thread. const scoped_refptr<base::SingleThreadTaskRunner> main_thread_; - // The signaling thread is a WebRTC thread used to invoke - // PeerConnectionIdentityStore::RequestIdentity on, as is required. - const scoped_refptr<base::SingleThreadTaskRunner> signaling_thread_; - blink::WebRTCKeyParams key_params_; - std::unique_ptr<blink::WebRTCCertificateCallback> observer_; - - DISALLOW_COPY_AND_ASSIGN(RTCCertificateIdentityObserver); + // The WebRTC worker thread. + const scoped_refptr<base::SingleThreadTaskRunner> worker_thread_; }; } // namespace void RTCCertificateGenerator::generateCertificate( const blink::WebRTCKeyParams& key_params, - const blink::WebURL& url, - const blink::WebURL& first_party_for_cookies, std::unique_ptr<blink::WebRTCCertificateCallback> observer) { generateCertificateWithOptionalExpiration( - key_params, url, first_party_for_cookies, rtc::Optional<uint64_t>(), - std::move(observer)); + key_params, rtc::Optional<uint64_t>(), std::move(observer)); } void RTCCertificateGenerator::generateCertificateWithExpiration( const blink::WebRTCKeyParams& key_params, - const blink::WebURL& url, - const blink::WebURL& first_party_for_cookies, uint64_t expires_ms, std::unique_ptr<blink::WebRTCCertificateCallback> observer) { generateCertificateWithOptionalExpiration( - key_params, url, first_party_for_cookies, - rtc::Optional<uint64_t>(expires_ms), std::move(observer)); + key_params, rtc::Optional<uint64_t>(expires_ms), std::move(observer)); } void RTCCertificateGenerator::generateCertificateWithOptionalExpiration( const blink::WebRTCKeyParams& key_params, - const blink::WebURL& url, - const blink::WebURL& first_party_for_cookies, const rtc::Optional<uint64_t>& expires_ms, std::unique_ptr<blink::WebRTCCertificateCallback> observer) { DCHECK(isSupportedKeyParams(key_params)); - #if defined(ENABLE_WEBRTC) const scoped_refptr<base::SingleThreadTaskRunner> main_thread = base::ThreadTaskRunnerHandle::Get(); - PeerConnectionDependencyFactory* pc_dependency_factory = RenderThreadImpl::current()->GetPeerConnectionDependencyFactory(); pc_dependency_factory->EnsureInitialized(); - const scoped_refptr<base::SingleThreadTaskRunner> signaling_thread = - pc_dependency_factory->GetWebRtcSignalingThread(); - - rtc::scoped_refptr<RTCCertificateIdentityObserver> identity_observer( - new rtc::RefCountedObject<RTCCertificateIdentityObserver>( - main_thread, signaling_thread)); - // |identity_observer| lives until request has completed. - identity_observer->RequestIdentity(key_params, url, first_party_for_cookies, - expires_ms, std::move(observer)); + + scoped_refptr<RTCCertificateGeneratorRequest> request = + new RTCCertificateGeneratorRequest( + main_thread, + pc_dependency_factory->GetWebRtcWorkerThread()); + request->GenerateCertificateAsync( + key_params, expires_ms, std::move(observer)); #else observer->onError(); #endif diff --git a/chromium/content/renderer/media/rtc_certificate_generator.h b/chromium/content/renderer/media/rtc_certificate_generator.h index 3858db265cc..38811e5ef95 100644 --- a/chromium/content/renderer/media/rtc_certificate_generator.h +++ b/chromium/content/renderer/media/rtc_certificate_generator.h @@ -24,13 +24,9 @@ class RTCCertificateGenerator : public blink::WebRTCCertificateGenerator { // blink::WebRTCCertificateGenerator implementation. void generateCertificate( const blink::WebRTCKeyParams& key_params, - const blink::WebURL& url, - const blink::WebURL& first_party_for_cookies, std::unique_ptr<blink::WebRTCCertificateCallback> observer) override; void generateCertificateWithExpiration( const blink::WebRTCKeyParams& key_params, - const blink::WebURL& url, - const blink::WebURL& first_party_for_cookies, uint64_t expires_ms, std::unique_ptr<blink::WebRTCCertificateCallback> observer) override; bool isSupportedKeyParams(const blink::WebRTCKeyParams& key_params) override; @@ -41,8 +37,6 @@ class RTCCertificateGenerator : public blink::WebRTCCertificateGenerator { private: void generateCertificateWithOptionalExpiration( const blink::WebRTCKeyParams& key_params, - const blink::WebURL& url, - const blink::WebURL& first_party_for_cookies, const rtc::Optional<uint64_t>& expires_ms, std::unique_ptr<blink::WebRTCCertificateCallback> observer); diff --git a/chromium/content/renderer/media/rtc_peer_connection_handler.cc b/chromium/content/renderer/media/rtc_peer_connection_handler.cc index e273e5113a9..361948cde06 100644 --- a/chromium/content/renderer/media/rtc_peer_connection_handler.cc +++ b/chromium/content/renderer/media/rtc_peer_connection_handler.cc @@ -722,21 +722,6 @@ void ConvertConstraintsToWebrtcOfferOptions( base::LazyInstance<std::set<RTCPeerConnectionHandler*> >::Leaky g_peer_connection_handlers = LAZY_INSTANCE_INITIALIZER; -void OverrideDefaultCertificateBasedOnExperiment( - webrtc::PeerConnectionInterface::RTCConfiguration* config) { - if (base::FeatureList::IsEnabled(features::kWebRtcEcdsaDefault)) { - if (config->certificates.empty()) { - rtc::scoped_refptr<rtc::RTCCertificate> certificate = - PeerConnectionDependencyFactory::GenerateDefaultCertificate(); - config->certificates.push_back(certificate); - } - } - // If the ECDSA experiment is not running we rely on the default being RSA for - // the control group. See bug related to this: crbug.com/611698. - static_assert(rtc::KT_DEFAULT == rtc::KT_RSA, "This code relies on " - "KT_DEFAULT == KT_RSA for RSA certificate generation."); -} - } // namespace // Implementation of LocalRTCStatsRequest. @@ -811,7 +796,7 @@ class RTCPeerConnectionHandler::Observer } } - void OnAddStream(MediaStreamInterface* stream) override { + void OnAddStream(rtc::scoped_refptr<MediaStreamInterface> stream) override { DCHECK(stream); std::unique_ptr<RemoteMediaStreamImpl> remote_stream( new RemoteMediaStreamImpl(main_thread_, stream)); @@ -824,13 +809,16 @@ class RTCPeerConnectionHandler::Observer this, base::Passed(&remote_stream))); } - void OnRemoveStream(MediaStreamInterface* stream) override { - main_thread_->PostTask(FROM_HERE, + void OnRemoveStream( + rtc::scoped_refptr<MediaStreamInterface> stream) override { + main_thread_->PostTask( + FROM_HERE, base::Bind(&RTCPeerConnectionHandler::Observer::OnRemoveStreamImpl, - this, make_scoped_refptr(stream))); + this, make_scoped_refptr(stream.get()))); } - void OnDataChannel(DataChannelInterface* data_channel) override { + void OnDataChannel( + rtc::scoped_refptr<DataChannelInterface> data_channel) override { std::unique_ptr<RtcDataChannelHandler> handler( new RtcDataChannelHandler(main_thread_, data_channel)); main_thread_->PostTask(FROM_HERE, @@ -967,7 +955,6 @@ bool RTCPeerConnectionHandler::initialize( webrtc::PeerConnectionInterface::RTCConfiguration config; GetNativeRtcConfiguration(server_configuration, &config); - OverrideDefaultCertificateBasedOnExperiment(&config); // Choose between RTC smoothness algorithm and prerenderer smoothing. // Prerenderer smoothing is turned on if RTC smoothness is turned off. @@ -1004,7 +991,6 @@ bool RTCPeerConnectionHandler::InitializeForTest( DCHECK(thread_checker_.CalledOnValidThread()); webrtc::PeerConnectionInterface::RTCConfiguration config; GetNativeRtcConfiguration(server_configuration, &config); - OverrideDefaultCertificateBasedOnExperiment(&config); peer_connection_observer_ = new Observer(weak_factory_.GetWeakPtr()); CopyConstraintsIntoRtcConfiguration(options, &config); @@ -1270,6 +1256,12 @@ bool RTCPeerConnectionHandler::updateICE( return native_peer_connection_->UpdateIce(config.servers); } +void RTCPeerConnectionHandler::logSelectedRtcpMuxPolicy( + blink::RtcpMuxPolicy selectedRtcpMuxPolicy) { + UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SelectedRtcpMuxPolicy", + selectedRtcpMuxPolicy, blink::RtcpMuxPolicyMax); +} + bool RTCPeerConnectionHandler::addICECandidate( const blink::WebRTCVoidRequest& request, const blink::WebRTCICECandidate& candidate) { @@ -1779,7 +1771,8 @@ void RTCPeerConnectionHandler::RunSynchronousClosureOnSignalingThread( TRACE_EVENT0("webrtc", trace_event_name); closure.Run(); } else { - base::WaitableEvent event(false, false); + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); thread->PostTask(FROM_HERE, base::Bind(&RunSynchronousClosure, closure, base::Unretained(trace_event_name), diff --git a/chromium/content/renderer/media/rtc_peer_connection_handler.h b/chromium/content/renderer/media/rtc_peer_connection_handler.h index 7fe3bf259b7..04941df562c 100644 --- a/chromium/content/renderer/media/rtc_peer_connection_handler.h +++ b/chromium/content/renderer/media/rtc_peer_connection_handler.h @@ -135,6 +135,8 @@ class CONTENT_EXPORT RTCPeerConnectionHandler bool updateICE( const blink::WebRTCConfiguration& server_configuration) override; + void logSelectedRtcpMuxPolicy( + blink::RtcpMuxPolicy selectedRtcpMuxPolicy) override; bool addICECandidate(const blink::WebRTCICECandidate& candidate) override; bool addICECandidate(const blink::WebRTCVoidRequest& request, const blink::WebRTCICECandidate& candidate) override; diff --git a/chromium/content/renderer/media/rtc_peer_connection_handler_unittest.cc b/chromium/content/renderer/media/rtc_peer_connection_handler_unittest.cc index cd65ee7bca9..1032489c621 100644 --- a/chromium/content/renderer/media/rtc_peer_connection_handler_unittest.cc +++ b/chromium/content/renderer/media/rtc_peer_connection_handler_unittest.cc @@ -305,19 +305,19 @@ class RTCPeerConnectionHandlerTest : public ::testing::Test { // Creates a remote MediaStream and adds it to the mocked native // peer connection. - scoped_refptr<webrtc::MediaStreamInterface> - AddRemoteMockMediaStream(const std::string& stream_label, - const std::string& video_track_label, - const std::string& audio_track_label) { - scoped_refptr<webrtc::MediaStreamInterface> stream( - mock_dependency_factory_->CreateLocalMediaStream(stream_label)); + rtc::scoped_refptr<webrtc::MediaStreamInterface> AddRemoteMockMediaStream( + const std::string& stream_label, + const std::string& video_track_label, + const std::string& audio_track_label) { + rtc::scoped_refptr<webrtc::MediaStreamInterface> stream( + mock_dependency_factory_->CreateLocalMediaStream(stream_label).get()); if (!video_track_label.empty()) { stream->AddTrack(MockWebRtcVideoTrack::Create(video_track_label).get()); } if (!audio_track_label.empty()) { stream->AddTrack(MockWebRtcAudioTrack::Create(audio_track_label).get()); } - mock_peer_connection_->AddRemoteStream(stream.get()); + mock_peer_connection_->AddRemoteStream(stream); return stream; } @@ -376,18 +376,18 @@ TEST_F(RTCPeerConnectionHandlerTest, NoCallbacksToClientAfterStop) { EXPECT_CALL(*mock_client_.get(), didAddRemoteStream(_)).Times(0); std::string remote_stream_label("remote_stream"); - scoped_refptr<webrtc::MediaStreamInterface> remote_stream( + rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); - pc_handler_->observer()->OnAddStream(remote_stream.get()); + pc_handler_->observer()->OnAddStream(remote_stream); EXPECT_CALL(*mock_client_.get(), didRemoveRemoteStream(_)).Times(0); - pc_handler_->observer()->OnRemoveStream(remote_stream.get()); + pc_handler_->observer()->OnRemoveStream(remote_stream); EXPECT_CALL(*mock_client_.get(), didAddRemoteDataChannel(_)).Times(0); webrtc::DataChannelInit config; - scoped_refptr<webrtc::DataChannelInterface> remote_data_channel( + rtc::scoped_refptr<webrtc::DataChannelInterface> remote_data_channel( new rtc::RefCountedObject<MockDataChannel>("dummy", &config)); - pc_handler_->observer()->OnDataChannel(remote_data_channel.get()); + pc_handler_->observer()->OnDataChannel(remote_data_channel); base::RunLoop().RunUntilIdle(); } @@ -599,9 +599,9 @@ TEST_F(RTCPeerConnectionHandlerTest, GetStatsWithLocalSelector) { } TEST_F(RTCPeerConnectionHandlerTest, GetStatsWithRemoteSelector) { - scoped_refptr<webrtc::MediaStreamInterface> stream( + rtc::scoped_refptr<webrtc::MediaStreamInterface> stream( AddRemoteMockMediaStream("remote_stream", "video", "audio")); - pc_handler_->observer()->OnAddStream(stream.get()); + pc_handler_->observer()->OnAddStream(stream); base::RunLoop().RunUntilIdle(); const blink::WebMediaStream& remote_stream = mock_client_->remote_stream(); @@ -781,7 +781,7 @@ TEST_F(RTCPeerConnectionHandlerTest, OnIceGatheringChange) { TEST_F(RTCPeerConnectionHandlerTest, OnAddAndOnRemoveStream) { std::string remote_stream_label("remote_stream"); - scoped_refptr<webrtc::MediaStreamInterface> remote_stream( + rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); testing::InSequence sequence; @@ -803,23 +803,23 @@ TEST_F(RTCPeerConnectionHandlerTest, OnAddAndOnRemoveStream) { testing::Property(&blink::WebMediaStream::id, base::UTF8ToUTF16(remote_stream_label)))); - pc_handler_->observer()->OnAddStream(remote_stream.get()); + pc_handler_->observer()->OnAddStream(remote_stream); base::RunLoop().RunUntilIdle(); - pc_handler_->observer()->OnRemoveStream(remote_stream.get()); + pc_handler_->observer()->OnRemoveStream(remote_stream); base::RunLoop().RunUntilIdle(); } // This test that WebKit is notified about remote track state changes. TEST_F(RTCPeerConnectionHandlerTest, RemoteTrackState) { std::string remote_stream_label("remote_stream"); - scoped_refptr<webrtc::MediaStreamInterface> remote_stream( + rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); testing::InSequence sequence; EXPECT_CALL(*mock_client_.get(), didAddRemoteStream( testing::Property(&blink::WebMediaStream::id, base::UTF8ToUTF16(remote_stream_label)))); - pc_handler_->observer()->OnAddStream(remote_stream.get()); + pc_handler_->observer()->OnAddStream(remote_stream); base::RunLoop().RunUntilIdle(); const blink::WebMediaStream& webkit_stream = mock_client_->remote_stream(); @@ -859,9 +859,9 @@ TEST_F(RTCPeerConnectionHandlerTest, RemoveAndAddAudioTrackFromRemoteStream) { DoAll(SaveArg<0>(&webkit_stream), ExitMessageLoop(&message_loop_, run_loop.QuitClosure()))); - scoped_refptr<webrtc::MediaStreamInterface> remote_stream( + rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); - pc_handler_->observer()->OnAddStream(remote_stream.get()); + pc_handler_->observer()->OnAddStream(remote_stream); run_loop.Run(); { @@ -907,9 +907,9 @@ TEST_F(RTCPeerConnectionHandlerTest, RemoveAndAddVideoTrackFromRemoteStream) { DoAll(SaveArg<0>(&webkit_stream), ExitMessageLoop(&message_loop_, run_loop.QuitClosure()))); - scoped_refptr<webrtc::MediaStreamInterface> remote_stream( + rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); - pc_handler_->observer()->OnAddStream(remote_stream.get()); + pc_handler_->observer()->OnAddStream(remote_stream); run_loop.Run(); { @@ -954,9 +954,9 @@ TEST_F(RTCPeerConnectionHandlerTest, RemoveAndAddTracksFromRemoteStream) { DoAll(SaveArg<0>(&webkit_stream), ExitMessageLoop(&message_loop_, run_loop.QuitClosure()))); - scoped_refptr<webrtc::MediaStreamInterface> remote_stream( + rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); - pc_handler_->observer()->OnAddStream(remote_stream.get()); + pc_handler_->observer()->OnAddStream(remote_stream); run_loop.Run(); { diff --git a/chromium/content/renderer/media/speech_recognition_audio_sink.cc b/chromium/content/renderer/media/speech_recognition_audio_sink.cc index 08bb010a210..e09431ef4e5 100644 --- a/chromium/content/renderer/media/speech_recognition_audio_sink.cc +++ b/chromium/content/renderer/media/speech_recognition_audio_sink.cc @@ -162,7 +162,7 @@ void SpeechRecognitionAudioSink::OnData( } double SpeechRecognitionAudioSink::ProvideInput(media::AudioBus* audio_bus, - base::TimeDelta buffer_delay) { + uint32_t frames_delayed) { DCHECK(capture_thread_checker_.CalledOnValidThread()); if (fifo_->frames() >= audio_bus->frames()) fifo_->Consume(audio_bus, 0, audio_bus->frames()); diff --git a/chromium/content/renderer/media/speech_recognition_audio_sink.h b/chromium/content/renderer/media/speech_recognition_audio_sink.h index e756638363a..a7fa2800b3a 100644 --- a/chromium/content/renderer/media/speech_recognition_audio_sink.h +++ b/chromium/content/renderer/media/speech_recognition_audio_sink.h @@ -62,7 +62,7 @@ class CONTENT_EXPORT SpeechRecognitionAudioSink // media::AudioConverter::Inputcallback implementation. double ProvideInput(media::AudioBus* audio_bus, - base::TimeDelta buffer_delay) override; + uint32_t frames_delayed) override; // Returns the pointer to the audio input buffer mapped in the shared memory. media::AudioInputBuffer* GetAudioInputBuffer() const; diff --git a/chromium/content/renderer/media/track_audio_renderer.cc b/chromium/content/renderer/media/track_audio_renderer.cc index 7cadedc02ce..625a65d127b 100644 --- a/chromium/content/renderer/media/track_audio_renderer.cc +++ b/chromium/content/renderer/media/track_audio_renderer.cc @@ -12,8 +12,8 @@ #include "base/trace_event/trace_event.h" #include "content/renderer/media/audio_device_factory.h" #include "content/renderer/media/media_stream_audio_track.h" -#include "content/renderer/media/webrtc_audio_renderer.h" #include "media/base/audio_bus.h" +#include "media/base/audio_latency.h" #include "media/base/audio_shifter.h" namespace content { @@ -311,7 +311,7 @@ void TrackAudioRenderer::MaybeStartSink() { media::AudioParameters sink_params( hardware_params.format(), source_params_.channel_layout(), source_params_.sample_rate(), source_params_.bits_per_sample(), - WebRtcAudioRenderer::GetOptimalBufferSize( + media::AudioLatency::GetRtcBufferSize( source_params_.sample_rate(), hardware_params.frames_per_buffer())); DVLOG(1) << ("TrackAudioRenderer::MaybeStartSink() -- Starting sink. " "source_params_={") diff --git a/chromium/content/renderer/media/track_audio_renderer.h b/chromium/content/renderer/media/track_audio_renderer.h index 43c0d7fa71b..509f31988cc 100644 --- a/chromium/content/renderer/media/track_audio_renderer.h +++ b/chromium/content/renderer/media/track_audio_renderer.h @@ -127,7 +127,7 @@ class CONTENT_EXPORT TrackAudioRenderer // with the audio track. blink::WebMediaStreamTrack audio_track_; - // The render view and frame in which the audio is rendered into |sink_|. + // The RenderFrame in which the audio is rendered into |sink_|. const int playout_render_frame_id_; const int session_id_; diff --git a/chromium/content/renderer/media/user_media_client_impl.cc b/chromium/content/renderer/media/user_media_client_impl.cc index 1a8df36355c..cba0545d2d5 100644 --- a/chromium/content/renderer/media/user_media_client_impl.cc +++ b/chromium/content/renderer/media/user_media_client_impl.cc @@ -1186,4 +1186,8 @@ bool UserMediaClientImpl::UserMediaRequestInfo::HasPendingSources() const { return !sources_waiting_for_callback_.empty(); } +void UserMediaClientImpl::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/media/user_media_client_impl.h b/chromium/content/renderer/media/user_media_client_impl.h index f920ca7420d..0b189f52040 100644 --- a/chromium/content/renderer/media/user_media_client_impl.h +++ b/chromium/content/renderer/media/user_media_client_impl.h @@ -196,6 +196,9 @@ class CONTENT_EXPORT UserMediaClientImpl struct MediaDevicesRequestInfo; typedef ScopedVector<MediaDevicesRequestInfo> MediaDevicesRequests; + // RenderFrameObserver implementation. + void OnDestruct() override; + // Creates a WebKit representation of stream sources based on // |devices| from the MediaStreamDispatcher. void InitializeSourceObject( diff --git a/chromium/content/renderer/media/video_capture_impl.cc b/chromium/content/renderer/media/video_capture_impl.cc index 90026160a5e..1ccd6c63fce 100644 --- a/chromium/content/renderer/media/video_capture_impl.cc +++ b/chromium/content/renderer/media/video_capture_impl.cc @@ -191,7 +191,6 @@ void VideoCaptureImpl::StartCapture( } DVLOG(1) << "StartCapture: starting with first resolution " << params_.requested_format.frame_size.ToString(); - first_frame_timestamp_ = base::TimeTicks(); StartCaptureInternal(); } } @@ -304,7 +303,7 @@ void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { void VideoCaptureImpl::OnBufferReceived( int buffer_id, - base::TimeTicks timestamp, + base::TimeDelta timestamp, const base::DictionaryValue& metadata, media::VideoPixelFormat pixel_format, media::VideoFrame::StorageType storage_type, @@ -324,14 +323,31 @@ void VideoCaptureImpl::OnBufferReceived( gpu::SyncToken(), -1.0)); return; } - if (first_frame_timestamp_.is_null()) - first_frame_timestamp_ = timestamp; + base::TimeTicks reference_time; + media::VideoFrameMetadata frame_metadata; + frame_metadata.MergeInternalValuesFrom(metadata); + const bool success = frame_metadata.GetTimeTicks( + media::VideoFrameMetadata::REFERENCE_TIME, &reference_time); + DCHECK(success); + + if (first_frame_ref_time_.is_null()) + first_frame_ref_time_ = reference_time; + + // If the timestamp is not prepared, we use reference time to make a rough + // estimate. e.g. ThreadSafeCaptureOracle::DidCaptureFrame(). + // TODO(miu): Fix upstream capturers to always set timestamp and reference + // time. See http://crbug/618407/ for tracking. + if (timestamp.is_zero()) + timestamp = reference_time - first_frame_ref_time_; + + // TODO(qiangchen): Change the metric name to "reference_time" and + // "timestamp", so that we have consistent naming everywhere. // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc TRACE_EVENT_INSTANT2("cast_perf_test", "OnBufferReceived", TRACE_EVENT_SCOPE_THREAD, "timestamp", - timestamp.ToInternalValue(), "time_delta", - (timestamp - first_frame_timestamp_).ToInternalValue()); + (reference_time - base::TimeTicks()).InMicroseconds(), + "time_delta", timestamp.InMicroseconds()); scoped_refptr<media::VideoFrame> frame; BufferFinishedCallback buffer_finished_callback; @@ -343,11 +359,8 @@ void VideoCaptureImpl::OnBufferReceived( scoped_refptr<ClientBuffer2> buffer = iter->second; const auto& handles = buffer->gpu_memory_buffer_handles(); frame = media::VideoFrame::WrapExternalYuvGpuMemoryBuffers( - media::PIXEL_FORMAT_I420, - coded_size, - gfx::Rect(coded_size), - coded_size, - buffer->stride(media::VideoFrame::kYPlane), + media::PIXEL_FORMAT_I420, coded_size, gfx::Rect(coded_size), + coded_size, buffer->stride(media::VideoFrame::kYPlane), buffer->stride(media::VideoFrame::kUPlane), buffer->stride(media::VideoFrame::kVPlane), buffer->data(media::VideoFrame::kYPlane), @@ -355,8 +368,7 @@ void VideoCaptureImpl::OnBufferReceived( buffer->data(media::VideoFrame::kVPlane), handles[media::VideoFrame::kYPlane], handles[media::VideoFrame::kUPlane], - handles[media::VideoFrame::kVPlane], - timestamp - first_frame_timestamp_); + handles[media::VideoFrame::kVPlane], timestamp); buffer_finished_callback = media::BindToCurrentLoop( base::Bind(&VideoCaptureImpl::OnClientBufferFinished2, weak_factory_.GetWeakPtr(), buffer_id, buffer)); @@ -371,7 +383,7 @@ void VideoCaptureImpl::OnBufferReceived( gfx::Size(visible_rect.width(), visible_rect.height()), reinterpret_cast<uint8_t*>(buffer->buffer()->memory()), buffer->buffer_size(), buffer->buffer()->handle(), - 0 /* shared_memory_offset */, timestamp - first_frame_timestamp_); + 0 /* shared_memory_offset */, timestamp); buffer_finished_callback = media::BindToCurrentLoop( base::Bind(&VideoCaptureImpl::OnClientBufferFinished, weak_factory_.GetWeakPtr(), buffer_id, buffer)); @@ -387,16 +399,16 @@ void VideoCaptureImpl::OnBufferReceived( return; } - frame->metadata()->SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME, - timestamp); frame->AddDestructionObserver( base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame, frame->metadata(), base::Passed(&release_sync_token), buffer_finished_callback)); frame->metadata()->MergeInternalValuesFrom(metadata); + // TODO(qiangchen): Dive into the full code path to let frame metadata hold + // reference time rather than using an extra parameter. for (const auto& client : clients_) - client.second.deliver_frame_cb.Run(frame, timestamp); + client.second.deliver_frame_cb.Run(frame, reference_time); } void VideoCaptureImpl::OnClientBufferFinished( diff --git a/chromium/content/renderer/media/video_capture_impl.h b/chromium/content/renderer/media/video_capture_impl.h index b07823486d8..74c4d19d33f 100644 --- a/chromium/content/renderer/media/video_capture_impl.h +++ b/chromium/content/renderer/media/video_capture_impl.h @@ -120,14 +120,13 @@ class CONTENT_EXPORT VideoCaptureImpl const gfx::Size& size, int buffer_id) override; void OnBufferDestroyed(int buffer_id) override; - void OnBufferReceived( - int buffer_id, - base::TimeTicks timestamp, - const base::DictionaryValue& metadata, - media::VideoPixelFormat pixel_format, - media::VideoFrame::StorageType storage_type, - const gfx::Size& coded_size, - const gfx::Rect& visible_rect) override; + void OnBufferReceived(int buffer_id, + base::TimeDelta timestamp, + const base::DictionaryValue& metadata, + media::VideoPixelFormat pixel_format, + media::VideoFrame::StorageType storage_type, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect) override; void OnStateChanged(VideoCaptureState state) override; void OnDeviceSupportedFormatsEnumerated( const media::VideoCaptureFormats& supported_formats) override; @@ -189,8 +188,9 @@ class CONTENT_EXPORT VideoCaptureImpl // client to this class via StartCapture(). media::VideoCaptureParams params_; - // The device's first captured frame timestamp sent from browser process side. - base::TimeTicks first_frame_timestamp_; + // The device's first captured frame referecne time sent from browser process + // side. + base::TimeTicks first_frame_ref_time_; bool suspended_; VideoCaptureState state_; diff --git a/chromium/content/renderer/media/video_capture_impl_unittest.cc b/chromium/content/renderer/media/video_capture_impl_unittest.cc index 1fc43c024b8..7ad265e1919 100644 --- a/chromium/content/renderer/media/video_capture_impl_unittest.cc +++ b/chromium/content/renderer/media/video_capture_impl_unittest.cc @@ -168,10 +168,18 @@ class VideoCaptureImplTest : public ::testing::Test { } void BufferReceived(int buffer_id, const gfx::Size& size) { + base::TimeTicks now = base::TimeTicks::Now(); + base::TimeDelta timestamp = now - base::TimeTicks(); + + media::VideoFrameMetadata frame_metadata; + frame_metadata.SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME, + now); + base::DictionaryValue metadata; + frame_metadata.MergeInternalValuesInto(&metadata); + video_capture_impl_->OnBufferReceived( - buffer_id, base::TimeTicks::Now(), base::DictionaryValue(), - media::PIXEL_FORMAT_I420, media::VideoFrame::STORAGE_SHMEM, size, - gfx::Rect(size)); + buffer_id, timestamp, metadata, media::PIXEL_FORMAT_I420, + media::VideoFrame::STORAGE_SHMEM, size, gfx::Rect(size)); } void BufferDestroyed(int buffer_id) { diff --git a/chromium/content/renderer/media/video_capture_message_filter.h b/chromium/content/renderer/media/video_capture_message_filter.h index 9088cd38f24..05939715957 100644 --- a/chromium/content/renderer/media/video_capture_message_filter.h +++ b/chromium/content/renderer/media/video_capture_message_filter.h @@ -48,14 +48,13 @@ class CONTENT_EXPORT VideoCaptureMessageFilter : public IPC::MessageFilter { // Called when a buffer referencing a captured VideoFrame is received from // Browser process. - virtual void OnBufferReceived( - int buffer_id, - base::TimeTicks timestamp, - const base::DictionaryValue& metadata, - media::VideoPixelFormat pixel_format, - media::VideoFrame::StorageType storage_type, - const gfx::Size& coded_size, - const gfx::Rect& visible_rect) = 0; + virtual void OnBufferReceived(int buffer_id, + base::TimeDelta timestamp, + const base::DictionaryValue& metadata, + media::VideoPixelFormat pixel_format, + media::VideoFrame::StorageType storage_type, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect) = 0; // Called when state of a video capture device has changed in the browser // process. diff --git a/chromium/content/renderer/media/video_capture_message_filter_unittest.cc b/chromium/content/renderer/media/video_capture_message_filter_unittest.cc index 6a339404de1..05845bf3232 100644 --- a/chromium/content/renderer/media/video_capture_message_filter_unittest.cc +++ b/chromium/content/renderer/media/video_capture_message_filter_unittest.cc @@ -43,7 +43,7 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate { MOCK_METHOD1(OnBufferDestroyed, void(int buffer_id)); MOCK_METHOD7(OnBufferReceived, void(int buffer_id, - base::TimeTicks timestamp, + base::TimeDelta timestamp, const base::DictionaryValue& metadata, media::VideoPixelFormat pixel_format, media::VideoFrame::StorageType storage_type, @@ -122,8 +122,12 @@ TEST(VideoCaptureMessageFilterTest, Basic) { VideoCaptureMsg_BufferReady_Params params; params.device_id = delegate.device_id(); params.buffer_id = 22; - params.timestamp = base::TimeTicks::FromInternalValue(1); + params.timestamp = base::TimeDelta::FromMicroseconds(1); params.metadata.SetString("foo", "bar"); + media::VideoFrameMetadata frame_metadata; + frame_metadata.SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME, + base::TimeTicks::FromInternalValue(1)); + frame_metadata.MergeInternalValuesInto(¶ms.metadata); params.pixel_format = media::PIXEL_FORMAT_I420; params.storage_type = media::VideoFrame::STORAGE_SHMEM; params.coded_size = gfx::Size(234, 512); diff --git a/chromium/content/renderer/media/video_track_recorder.cc b/chromium/content/renderer/media/video_track_recorder.cc index 8da8f308492..d65e238e879 100644 --- a/chromium/content/renderer/media/video_track_recorder.cc +++ b/chromium/content/renderer/media/video_track_recorder.cc @@ -10,11 +10,17 @@ #include "base/logging.h" #include "base/macros.h" #include "base/sys_info.h" +#include "base/task_runner_util.h" #include "base/threading/thread.h" +#include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" +#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" +#include "content/renderer/render_thread_impl.h" +#include "media/base/bind_to_current_loop.h" #include "media/base/video_frame.h" #include "media/base/video_util.h" +#include "third_party/libyuv/include/libyuv/convert.h" #include "ui/gfx/geometry/size.h" #if BUILDFLAG(RTC_USE_H264) @@ -36,6 +42,62 @@ using media::VideoFrameMetadata; namespace content { +namespace { + +const int kVEAEncoderMinResolutionWidth = 640; +const int kVEAEncoderMinResolutionHeight = 480; +const int kVEAEncoderOutputBufferCount = 4; + +static struct { + VideoTrackRecorder::CodecId codec_id; + media::VideoCodecProfile min_profile; + media::VideoCodecProfile max_profile; +} const kSupportedVideoCodecIdToProfile[] = { + {VideoTrackRecorder::CodecId::VP8, + media::VP8PROFILE_MIN, + media::VP8PROFILE_MAX}, + {VideoTrackRecorder::CodecId::VP9, + media::VP9PROFILE_MIN, + media::VP9PROFILE_MAX}, + {VideoTrackRecorder::CodecId::H264, + media::H264PROFILE_MIN, + media::H264PROFILE_MAX}}; + +// Returns the corresponding codec profile from VEA supported codecs. If no +// profile is found, returns VIDEO_CODEC_PROFILE_UNKNOWN. +media::VideoCodecProfile CodecIdToVEAProfile( + content::VideoTrackRecorder::CodecId codec) { + // See https://crbug.com/616659. +#if defined(OS_CHROMEOS) + return media::VIDEO_CODEC_PROFILE_UNKNOWN; +#endif // defined(OS_CHROMEOS) + content::RenderThreadImpl* render_thread_impl = + content::RenderThreadImpl::current(); + if (!render_thread_impl) + return media::VIDEO_CODEC_PROFILE_UNKNOWN; + + media::GpuVideoAcceleratorFactories* gpu_factories = + content::RenderThreadImpl::current()->GetGpuFactories(); + if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) { + DVLOG(3) << "Couldn't initialize GpuVideoAcceleratorFactories"; + return media::VIDEO_CODEC_PROFILE_UNKNOWN; + } + + const media::VideoEncodeAccelerator::SupportedProfiles& vea_profiles = + gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles(); + for (const auto& vea_profile : vea_profiles) { + for (const auto& supported_profile : kSupportedVideoCodecIdToProfile) { + if (codec == supported_profile.codec_id && + vea_profile.profile >= supported_profile.min_profile && + vea_profile.profile <= supported_profile.max_profile) + return vea_profile.profile; + } + } + return media::VIDEO_CODEC_PROFILE_UNKNOWN; +} + +} // anonymous namespace + // Base class to describe a generic Encoder, encapsulating all actual encoder // (re)configurations, encoding and delivery of received frames. This class is // ref-counted to allow the MediaStreamVideoTrack to hold a reference to it (via @@ -56,13 +118,13 @@ class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> { int32_t bits_per_second, scoped_refptr<base::SingleThreadTaskRunner> encoding_task_runner = nullptr) - : main_task_runner_(base::MessageLoop::current()->task_runner()), + : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), encoding_task_runner_(encoding_task_runner), paused_(false), on_encoded_video_callback_(on_encoded_video_callback), bits_per_second_(bits_per_second) { DCHECK(!on_encoded_video_callback_.is_null()); - if (encoding_thread_) + if (encoding_task_runner_) return; encoding_thread_.reset(new base::Thread("EncodingThread")); encoding_thread_->Start(); @@ -116,7 +178,7 @@ void VideoTrackRecorder::Encoder::StartFrameEncode( base::TimeTicks capture_timestamp) { // Cache the thread sending frames on first frame arrival. if (!origin_task_runner_.get()) - origin_task_runner_ = base::MessageLoop::current()->task_runner(); + origin_task_runner_ = base::ThreadTaskRunnerHandle::Get(); DCHECK(origin_task_runner_->BelongsToCurrentThread()); if (paused_) return; @@ -179,6 +241,69 @@ static int GetNumberOfThreadsForEncoding() { return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); } +// Class encapsulating VideoEncodeAccelerator interactions. +// This class is created and destroyed in its owner thread. All other methods +// operate on the task runner pointed by GpuFactories. +class VEAEncoder final : public VideoTrackRecorder::Encoder, + public media::VideoEncodeAccelerator::Client { + public: + VEAEncoder( + const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, + int32_t bits_per_second, + media::VideoCodecProfile codec); + + // media::VideoEncodeAccelerator::Client implementation. + void RequireBitstreamBuffers(unsigned int input_count, + const gfx::Size& input_coded_size, + size_t output_buffer_size) override; + void BitstreamBufferReady(int32_t bitstream_buffer_id, + size_t payload_size, + bool key_frame, + base::TimeDelta timestamp) override; + void NotifyError(media::VideoEncodeAccelerator::Error error) override; + + private: + using VideoFrameAndTimestamp = + std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>; + + void UseOutputBitstreamBufferId(int32_t bitstream_buffer_id); + void FrameFinished(std::unique_ptr<base::SharedMemory> shm); + + // VideoTrackRecorder::Encoder implementation. + ~VEAEncoder() override; + void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, + base::TimeTicks capture_timestamp) override; + void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; + + media::GpuVideoAcceleratorFactories* const gpu_factories_; + + const media::VideoCodecProfile codec_; + + // The underlying VEA to perform encoding on. + std::unique_ptr<media::VideoEncodeAccelerator> video_encoder_; + + // Shared memory buffers for output with the VEA. + std::vector<std::unique_ptr<base::SharedMemory>> output_buffers_; + + // Shared memory buffers for output with the VEA as FIFO. + std::queue<std::unique_ptr<base::SharedMemory>> input_buffers_; + + // Tracks error status. + bool error_notified_; + + // Tracks the first frame to encode. + std::unique_ptr<VideoFrameAndTimestamp> first_frame_; + + // Size used to initialize encoder. + gfx::Size input_size_; + + // Coded size that encoder requests as input. + gfx::Size vea_requested_input_size_; + + // Frames and corresponding timestamps in encode as FIFO. + std::queue<VideoFrameAndTimestamp> frames_in_encode_; +}; + // Class encapsulating all libvpx interactions for VP8/VP9 encoding. class VpxEncoder final : public VideoTrackRecorder::Encoder { public: @@ -191,10 +316,10 @@ class VpxEncoder final : public VideoTrackRecorder::Encoder { int32_t bits_per_second); private: - // VideoTrackRecorder::Encoder + // VideoTrackRecorder::Encoder implementation. ~VpxEncoder() override; void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, - base::TimeTicks capture_timestamp) override; + base::TimeTicks capture_timestamp) override; void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; // Returns true if |codec_config_| has been filled in at least once. @@ -243,7 +368,7 @@ class H264Encoder final : public VideoTrackRecorder::Encoder { int32_t bits_per_second); private: - // VideoTrackRecorder::Encoder + // VideoTrackRecorder::Encoder implementation. ~H264Encoder() override; void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, base::TimeTicks capture_timestamp) override; @@ -264,6 +389,196 @@ class H264Encoder final : public VideoTrackRecorder::Encoder { #endif // #if BUILDFLAG(RTC_USE_H264) +VEAEncoder::VEAEncoder( + const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, + int32_t bits_per_second, + media::VideoCodecProfile codec) + : Encoder(on_encoded_video_callback, + bits_per_second, + RenderThreadImpl::current()->GetGpuFactories()->GetTaskRunner()), + gpu_factories_(RenderThreadImpl::current()->GetGpuFactories()), + codec_(codec), + error_notified_(false) { + DCHECK(gpu_factories_); +} + +VEAEncoder::~VEAEncoder() { + encoding_task_runner_->PostTask( + FROM_HERE, base::Bind(&media::VideoEncodeAccelerator::Destroy, + base::Unretained(video_encoder_.release()))); +} + +void VEAEncoder::RequireBitstreamBuffers(unsigned int /*input_count*/, + const gfx::Size& input_coded_size, + size_t output_buffer_size) { + DVLOG(3) << __FUNCTION__; + DCHECK(encoding_task_runner_->BelongsToCurrentThread()); + + vea_requested_input_size_ = input_coded_size; + output_buffers_.clear(); + std::queue<std::unique_ptr<base::SharedMemory>>().swap(input_buffers_); + + for (int i = 0; i < kVEAEncoderOutputBufferCount; ++i) { + std::unique_ptr<base::SharedMemory> shm = + gpu_factories_->CreateSharedMemory(output_buffer_size); + if (shm) + output_buffers_.push_back(base::WrapUnique(shm.release())); + } + + for (size_t i = 0; i < output_buffers_.size(); ++i) + UseOutputBitstreamBufferId(i); +} + +void VEAEncoder::BitstreamBufferReady(int32_t bitstream_buffer_id, + size_t payload_size, + bool keyframe, + base::TimeDelta timestamp) { + DVLOG(3) << __FUNCTION__; + DCHECK(encoding_task_runner_->BelongsToCurrentThread()); + + base::SharedMemory* output_buffer = + output_buffers_[bitstream_buffer_id].get(); + + std::unique_ptr<std::string> data(new std::string); + data->append(reinterpret_cast<char*>(output_buffer->memory()), payload_size); + + const auto front_frame = frames_in_encode_.front(); + frames_in_encode_.pop(); + origin_task_runner_->PostTask( + FROM_HERE, base::Bind(OnFrameEncodeCompleted, on_encoded_video_callback_, + front_frame.first, base::Passed(&data), + front_frame.second, keyframe)); + UseOutputBitstreamBufferId(bitstream_buffer_id); +} + +void VEAEncoder::NotifyError(media::VideoEncodeAccelerator::Error error) { + DVLOG(3) << __FUNCTION__; + DCHECK(encoding_task_runner_->BelongsToCurrentThread()); + + // TODO(emircan): Notify the owner via a callback. + error_notified_ = true; +} + +void VEAEncoder::UseOutputBitstreamBufferId(int32_t bitstream_buffer_id) { + DVLOG(3) << __FUNCTION__; + DCHECK(encoding_task_runner_->BelongsToCurrentThread()); + + video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer( + bitstream_buffer_id, output_buffers_[bitstream_buffer_id]->handle(), + output_buffers_[bitstream_buffer_id]->mapped_size())); +} + +void VEAEncoder::FrameFinished(std::unique_ptr<base::SharedMemory> shm) { + DVLOG(3) << __FUNCTION__; + DCHECK(encoding_task_runner_->BelongsToCurrentThread()); + input_buffers_.push(std::move(shm)); +} + +void VEAEncoder::EncodeOnEncodingTaskRunner( + const scoped_refptr<VideoFrame>& frame, + base::TimeTicks capture_timestamp) { + DVLOG(3) << __FUNCTION__; + DCHECK(encoding_task_runner_->BelongsToCurrentThread()); + + if (input_size_ != frame->visible_rect().size() && video_encoder_) { + video_encoder_->Destroy(); + video_encoder_.reset(); + } + + if (!video_encoder_) { + ConfigureEncoderOnEncodingTaskRunner(frame->visible_rect().size()); + first_frame_.reset( + new std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>( + frame, capture_timestamp)); + } + + if (error_notified_) { + DVLOG(3) << "An error occurred in VEA encoder"; + return; + } + + // Drop frames if there is no output buffers available. + if (output_buffers_.empty()) { + // TODO(emircan): Investigate if resetting encoder would help. + DVLOG(3) << "Dropped frame."; + return; + } + + // If first frame hasn't been encoded, do it first. + if (first_frame_) { + std::unique_ptr<VideoFrameAndTimestamp> first_frame(first_frame_.release()); + EncodeOnEncodingTaskRunner(first_frame->first, first_frame->second); + } + + // Lower resolutions may fall back to SW encoder in some platforms, i.e. Mac. + // In that case, the encoder expects more frames before returning result. + // Therefore, a copy is necessary to release the current frame. + scoped_refptr<media::VideoFrame> video_frame = frame; + if (vea_requested_input_size_ != input_size_ || + input_size_.width() < kVEAEncoderMinResolutionWidth || + input_size_.height() < kVEAEncoderMinResolutionHeight) { + // Create SharedMemory backed input buffers as necessary. These SharedMemory + // instances will be shared with GPU process. + std::unique_ptr<base::SharedMemory> input_buffer; + const size_t desired_mapped_size = media::VideoFrame::AllocationSize( + media::PIXEL_FORMAT_I420, vea_requested_input_size_); + if (input_buffers_.empty()) { + input_buffer = gpu_factories_->CreateSharedMemory(desired_mapped_size); + } else { + do { + input_buffer = std::move(input_buffers_.front()); + input_buffers_.pop(); + } while (!input_buffers_.empty() && + input_buffer->mapped_size() < desired_mapped_size); + if (!input_buffer || input_buffer->mapped_size() < desired_mapped_size) + return; + } + + video_frame = media::VideoFrame::WrapExternalSharedMemory( + media::PIXEL_FORMAT_I420, vea_requested_input_size_, + gfx::Rect(input_size_), input_size_, + reinterpret_cast<uint8_t*>(input_buffer->memory()), + input_buffer->mapped_size(), input_buffer->handle(), 0, + frame->timestamp()); + video_frame->AddDestructionObserver(media::BindToCurrentLoop( + base::Bind(&VEAEncoder::FrameFinished, this, + base::Passed(std::move(input_buffer))))); + libyuv::I420Copy(frame->visible_data(media::VideoFrame::kYPlane), + frame->stride(media::VideoFrame::kYPlane), + frame->visible_data(media::VideoFrame::kUPlane), + frame->stride(media::VideoFrame::kUPlane), + frame->visible_data(media::VideoFrame::kVPlane), + frame->stride(media::VideoFrame::kVPlane), + video_frame->visible_data(media::VideoFrame::kYPlane), + video_frame->stride(media::VideoFrame::kYPlane), + video_frame->visible_data(media::VideoFrame::kUPlane), + video_frame->stride(media::VideoFrame::kUPlane), + video_frame->visible_data(media::VideoFrame::kVPlane), + video_frame->stride(media::VideoFrame::kVPlane), + input_size_.width(), input_size_.height()); + } + frames_in_encode_.push(std::make_pair(video_frame, capture_timestamp)); + + encoding_task_runner_->PostTask( + FROM_HERE, + base::Bind(&media::VideoEncodeAccelerator::Encode, + base::Unretained(video_encoder_.get()), video_frame, false)); +} + +void VEAEncoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) { + DVLOG(3) << __FUNCTION__; + DCHECK(encoding_task_runner_->BelongsToCurrentThread()); + DCHECK(gpu_factories_->GetTaskRunner()->BelongsToCurrentThread()); + + input_size_ = size; + video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(); + if (!video_encoder_ || + !video_encoder_->Initialize(media::PIXEL_FORMAT_I420, input_size_, codec_, + bits_per_second_, this)) { + NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); + } +} + // static void VpxEncoder::ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, ScopedVpxCodecCtxPtr encoder) { @@ -624,21 +939,28 @@ VideoTrackRecorder::VideoTrackRecorder( : track_(track) { DCHECK(main_render_thread_checker_.CalledOnValidThread()); DCHECK(!track_.isNull()); - DCHECK(track_.getExtraData()); + DCHECK(track_.getTrackData()); - switch (codec) { + const auto& vea_supported_profile = CodecIdToVEAProfile(codec); + // TODO(emircan): Prioritize software based encoders in lower resolutions. + if (vea_supported_profile != media::VIDEO_CODEC_PROFILE_UNKNOWN) { + encoder_ = new VEAEncoder(on_encoded_video_callback, bits_per_second, + vea_supported_profile); + } else { + switch (codec) { #if BUILDFLAG(RTC_USE_H264) - case CodecId::H264: - encoder_ = new H264Encoder(on_encoded_video_callback, bits_per_second); - break; + case CodecId::H264: + encoder_ = new H264Encoder(on_encoded_video_callback, bits_per_second); + break; #endif - case CodecId::VP8: - case CodecId::VP9: - encoder_ = new VpxEncoder(codec == CodecId::VP9, - on_encoded_video_callback, bits_per_second); - break; - default: - NOTREACHED() << "Unsupported codec"; + case CodecId::VP8: + case CodecId::VP9: + encoder_ = new VpxEncoder(codec == CodecId::VP9, + on_encoded_video_callback, bits_per_second); + break; + default: + NOTREACHED() << "Unsupported codec"; + } } // StartFrameEncode() will be called on Render IO thread. diff --git a/chromium/content/renderer/media/video_track_recorder.h b/chromium/content/renderer/media/video_track_recorder.h index a49733f9d70..5e624549224 100644 --- a/chromium/content/renderer/media/video_track_recorder.h +++ b/chromium/content/renderer/media/video_track_recorder.h @@ -32,9 +32,7 @@ class CONTENT_EXPORT VideoTrackRecorder enum class CodecId { VP8, VP9, -#if BUILDFLAG(RTC_USE_H264) H264, -#endif }; class Encoder; diff --git a/chromium/content/renderer/media/video_track_recorder_unittest.cc b/chromium/content/renderer/media/video_track_recorder_unittest.cc index 0ca52bb3397..a8390825af8 100644 --- a/chromium/content/renderer/media/video_track_recorder_unittest.cc +++ b/chromium/content/renderer/media/video_track_recorder_unittest.cc @@ -65,7 +65,7 @@ class VideoTrackRecorderTest track_ = new MediaStreamVideoTrack(mock_source_, constraints, MediaStreamSource::ConstraintsCallback(), true /* enabled */); - blink_track_.setExtraData(track_); + blink_track_.setTrackData(track_); video_track_recorder_.reset(new VideoTrackRecorder( GetParam() /* codec */, blink_track_, diff --git a/chromium/content/renderer/media/webmediaplayer_ms.cc b/chromium/content/renderer/media/webmediaplayer_ms.cc index 489d65bc707..d437247d180 100644 --- a/chromium/content/renderer/media/webmediaplayer_ms.cc +++ b/chromium/content/renderer/media/webmediaplayer_ms.cc @@ -18,7 +18,7 @@ #include "content/common/gpu/client/context_provider_command_buffer.h" #include "content/public/renderer/media_stream_audio_renderer.h" #include "content/public/renderer/media_stream_renderer_factory.h" -#include "content/public/renderer/video_frame_provider.h" +#include "content/public/renderer/media_stream_video_renderer.h" #include "content/renderer/media/web_media_element_source_utils.h" #include "content/renderer/media/webmediaplayer_ms_compositor.h" #include "content/renderer/render_frame_impl.h" @@ -124,7 +124,7 @@ void WebMediaPlayerMS::load(LoadType load_type, web_stream.isNull() ? std::string() : web_stream.id().utf8(); media_log_->AddEvent(media_log_->CreateLoadEvent(stream_id)); - video_frame_provider_ = renderer_factory_->GetVideoFrameProvider( + video_frame_provider_ = renderer_factory_->GetVideoRenderer( web_stream, base::Bind(&WebMediaPlayerMS::OnSourceError, AsWeakPtr()), base::Bind(&WebMediaPlayerMS::OnFrameAvailable, AsWeakPtr()), media_task_runner_, worker_task_runner_, gpu_factories_); @@ -168,7 +168,7 @@ void WebMediaPlayerMS::play() { return; if (video_frame_provider_) - video_frame_provider_->Play(); + video_frame_provider_->Resume(); compositor_->StartRendering(); diff --git a/chromium/content/renderer/media/webmediaplayer_ms.h b/chromium/content/renderer/media/webmediaplayer_ms.h index 76b8da1991a..51d116099d7 100644 --- a/chromium/content/renderer/media/webmediaplayer_ms.h +++ b/chromium/content/renderer/media/webmediaplayer_ms.h @@ -45,7 +45,7 @@ class GLES2Interface; namespace content { class MediaStreamAudioRenderer; class MediaStreamRendererFactory; -class VideoFrameProvider; +class MediaStreamVideoRenderer; class WebMediaPlayerMSCompositor; class RenderFrameObserver; @@ -57,7 +57,7 @@ class RenderFrameObserver; // // WebMediaPlayerMS works with multiple objects, the most important ones are: // -// VideoFrameProvider +// MediaStreamVideoRenderer // provides video frames for rendering. // // blink::WebMediaPlayerClient @@ -68,7 +68,7 @@ class CONTENT_EXPORT WebMediaPlayerMS public NON_EXPORTED_BASE(base::SupportsWeakPtr<WebMediaPlayerMS>) { public: // Construct a WebMediaPlayerMS with reference to the client, and - // a MediaStreamClient which provides VideoFrameProvider. + // a MediaStreamClient which provides MediaStreamVideoRenderer. WebMediaPlayerMS( blink::WebFrame* frame, blink::WebMediaPlayerClient* client, @@ -161,7 +161,8 @@ class CONTENT_EXPORT WebMediaPlayerMS private: friend class WebMediaPlayerMSTest; - // The callback for VideoFrameProvider to signal a new frame is available. + // The callback for MediaStreamVideoRenderer to signal a new frame is + // available. void OnFrameAvailable(const scoped_refptr<media::VideoFrame>& frame); // Need repaint due to state change. void RepaintInternal(); @@ -193,12 +194,11 @@ class CONTENT_EXPORT WebMediaPlayerMS const base::WeakPtr<media::WebMediaPlayerDelegate> delegate_; int delegate_id_; - // Specify content:: to disambiguate from cc::. - scoped_refptr<content::VideoFrameProvider> video_frame_provider_; // Weak + scoped_refptr<MediaStreamVideoRenderer> video_frame_provider_; // Weak std::unique_ptr<cc_blink::WebLayerImpl> video_weblayer_; - scoped_refptr<MediaStreamAudioRenderer> audio_renderer_; // Weak + scoped_refptr<MediaStreamAudioRenderer> audio_renderer_; // Weak media::SkCanvasVideoRenderer video_renderer_; bool paused_; diff --git a/chromium/content/renderer/media/webmediaplayer_ms_unittest.cc b/chromium/content/renderer/media/webmediaplayer_ms_unittest.cc index 37078750f50..d02bb0d1ec5 100644 --- a/chromium/content/renderer/media/webmediaplayer_ms_unittest.cc +++ b/chromium/content/renderer/media/webmediaplayer_ms_unittest.cc @@ -112,13 +112,13 @@ class ReusableMessageLoopEvent { }; // The class is used mainly to inject VideoFrames into WebMediaPlayerMS. -class MockVideoFrameProvider : public VideoFrameProvider { +class MockMediaStreamVideoRenderer : public MediaStreamVideoRenderer { public: - MockVideoFrameProvider( + MockMediaStreamVideoRenderer( const scoped_refptr<base::SingleThreadTaskRunner> task_runner, ReusableMessageLoopEvent* message_loop_controller, const base::Closure& error_cb, - const VideoFrameProvider::RepaintCB& repaint_cb) + const MediaStreamVideoRenderer::RepaintCB& repaint_cb) : started_(false), task_runner_(task_runner), message_loop_controller_(message_loop_controller), @@ -127,10 +127,10 @@ class MockVideoFrameProvider : public VideoFrameProvider { delay_till_next_generated_frame_( base::TimeDelta::FromSecondsD(1.0 / 30.0)) {} - // Implementation of VideoFrameProvider + // Implementation of MediaStreamVideoRenderer void Start() override; void Stop() override; - void Play() override; + void Resume() override; void Pause() override; // Methods for test use @@ -142,7 +142,7 @@ class MockVideoFrameProvider : public VideoFrameProvider { bool Paused() { return paused_; } private: - ~MockVideoFrameProvider() override {} + ~MockMediaStreamVideoRenderer() override {} // Main function that pushes a frame into WebMediaPlayerMS void InjectFrame(); @@ -157,42 +157,43 @@ class MockVideoFrameProvider : public VideoFrameProvider { const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; ReusableMessageLoopEvent* const message_loop_controller_; const base::Closure error_cb_; - const VideoFrameProvider::RepaintCB repaint_cb_; + const MediaStreamVideoRenderer::RepaintCB repaint_cb_; std::deque<TestFrame> frames_; base::TimeDelta delay_till_next_generated_frame_; }; -void MockVideoFrameProvider::Start() { +void MockMediaStreamVideoRenderer::Start() { started_ = true; paused_ = false; task_runner_->PostTask( FROM_HERE, - base::Bind(&MockVideoFrameProvider::InjectFrame, base::Unretained(this))); + base::Bind(&MockMediaStreamVideoRenderer::InjectFrame, + base::Unretained(this))); } -void MockVideoFrameProvider::Stop() { +void MockMediaStreamVideoRenderer::Stop() { started_ = false; frames_.clear(); } -void MockVideoFrameProvider::Play() { +void MockMediaStreamVideoRenderer::Resume() { CHECK(started_); paused_ = false; } -void MockVideoFrameProvider::Pause() { +void MockMediaStreamVideoRenderer::Pause() { CHECK(started_); paused_ = true; } -void MockVideoFrameProvider::AddFrame( +void MockMediaStreamVideoRenderer::AddFrame( FrameType category, const scoped_refptr<media::VideoFrame>& frame) { frames_.push_back(std::make_pair(category, frame)); } -void MockVideoFrameProvider::QueueFrames( +void MockMediaStreamVideoRenderer::QueueFrames( const std::vector<int>& timestamp_or_frame_type, bool opaque_frame, bool odd_size_frame, @@ -236,7 +237,7 @@ void MockVideoFrameProvider::QueueFrames( } } -void MockVideoFrameProvider::InjectFrame() { +void MockMediaStreamVideoRenderer::InjectFrame() { DCHECK(task_runner_->BelongsToCurrentThread()); if (!started_) return; @@ -272,7 +273,8 @@ void MockVideoFrameProvider::InjectFrame() { task_runner_->PostDelayedTask( FROM_HERE, - base::Bind(&MockVideoFrameProvider::InjectFrame, base::Unretained(this)), + base::Bind(&MockMediaStreamVideoRenderer::InjectFrame, + base::Unretained(this)), delay_till_next_generated_frame_); // This will pause the |message_loop_|, and the purpose is to allow the main @@ -293,16 +295,16 @@ class MockRenderFactory : public MediaStreamRendererFactory { : task_runner_(task_runner), message_loop_controller_(message_loop_controller) {} - scoped_refptr<VideoFrameProvider> GetVideoFrameProvider( + scoped_refptr<MediaStreamVideoRenderer> GetVideoRenderer( const blink::WebMediaStream& web_stream, const base::Closure& error_cb, - const VideoFrameProvider::RepaintCB& repaint_cb, + const MediaStreamVideoRenderer::RepaintCB& repaint_cb, const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, const scoped_refptr<base::TaskRunner>& worker_task_runner, media::GpuVideoAcceleratorFactories* gpu_factories) override; - MockVideoFrameProvider* provider() { - return static_cast<MockVideoFrameProvider*>(provider_.get()); + MockMediaStreamVideoRenderer* provider() { + return static_cast<MockMediaStreamVideoRenderer*>(provider_.get()); } scoped_refptr<MediaStreamAudioRenderer> GetAudioRenderer( @@ -315,19 +317,19 @@ class MockRenderFactory : public MediaStreamRendererFactory { private: const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - scoped_refptr<VideoFrameProvider> provider_; + scoped_refptr<MediaStreamVideoRenderer> provider_; ReusableMessageLoopEvent* const message_loop_controller_; }; -scoped_refptr<VideoFrameProvider> MockRenderFactory::GetVideoFrameProvider( +scoped_refptr<MediaStreamVideoRenderer> MockRenderFactory::GetVideoRenderer( const blink::WebMediaStream& web_stream, const base::Closure& error_cb, - const VideoFrameProvider::RepaintCB& repaint_cb, + const MediaStreamVideoRenderer::RepaintCB& repaint_cb, const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, const scoped_refptr<base::TaskRunner>& worker_task_runner, media::GpuVideoAcceleratorFactories* gpu_factories) { - provider_ = new MockVideoFrameProvider(task_runner_, message_loop_controller_, - error_cb, repaint_cb); + provider_ = new MockMediaStreamVideoRenderer(task_runner_, + message_loop_controller_, error_cb, repaint_cb); return provider_; } @@ -335,8 +337,8 @@ scoped_refptr<VideoFrameProvider> MockRenderFactory::GetVideoFrameProvider( // This is the main class coordinating the tests. // Basic workflow: // 1. WebMediaPlayerMS::Load will generate and start -// content::VideoFrameProvider. -// 2. content::VideoFrameProvider will start pushing frames into +// content::MediaStreamVideoRenderer. +// 2. content::MediaStreamVideoRenderer will start pushing frames into // WebMediaPlayerMS repeatedly. // 3. On WebMediaPlayerMS receiving the first frame, a WebLayer will be created. // 4. The WebLayer will call @@ -346,7 +348,7 @@ scoped_refptr<VideoFrameProvider> MockRenderFactory::GetVideoFrameProvider( // WebMediaPlayerMSCompositor::UpdateCurrentFrame, GetCurrentFrame for // rendering repeatedly. // 6. When WebMediaPlayerMS::pause gets called, it should trigger -// content::VideoFrameProvider::Pause, and then the provider will stop +// content::MediaStreamVideoRenderer::Pause, and then the provider will stop // pushing frames into WebMediaPlayerMS, but instead digesting them; // simultanously, it should call cc::VideoFrameProviderClient::StopRendering, // so cc::VideoFrameProviderClient will stop asking frames from @@ -380,7 +382,7 @@ class WebMediaPlayerMSTest base::RunLoop().RunUntilIdle(); } - MockVideoFrameProvider* LoadAndGetFrameProvider(bool algorithm_enabled); + MockMediaStreamVideoRenderer* LoadAndGetFrameProvider(bool algorithm_enabled); // Implementation of WebMediaPlayerClient void networkStateChanged() override; @@ -396,7 +398,7 @@ class WebMediaPlayerMSTest const blink::WebString& label, const blink::WebString& language, bool enabled) override { - return 0; + return blink::WebMediaPlayer::TrackId(); } void removeAudioTrack(blink::WebMediaPlayer::TrackId) override {} blink::WebMediaPlayer::TrackId addVideoTrack(const blink::WebString& id, @@ -404,7 +406,7 @@ class WebMediaPlayerMSTest const blink::WebString& label, const blink::WebString& language, bool selected) override { - return 0; + return blink::WebMediaPlayer::TrackId(); } void removeVideoTrack(blink::WebMediaPlayer::TrackId) override {} void addTextTrack(blink::WebInbandTextTrack*) override {} @@ -454,7 +456,7 @@ class WebMediaPlayerMSTest bool background_rendering_; }; -MockVideoFrameProvider* WebMediaPlayerMSTest::LoadAndGetFrameProvider( +MockMediaStreamVideoRenderer* WebMediaPlayerMSTest::LoadAndGetFrameProvider( bool algorithm_enabled) { EXPECT_FALSE(!!render_factory_->provider()) << "There should not be a " "FrameProvider yet."; @@ -470,7 +472,7 @@ MockVideoFrameProvider* WebMediaPlayerMSTest::LoadAndGetFrameProvider( EXPECT_TRUE(!!compositor_); compositor_->SetAlgorithmEnabledForTesting(algorithm_enabled); - MockVideoFrameProvider* const provider = render_factory_->provider(); + MockMediaStreamVideoRenderer* const provider = render_factory_->provider(); EXPECT_TRUE(!!provider); EXPECT_TRUE(provider->Started()); @@ -556,7 +558,7 @@ TEST_F(WebMediaPlayerMSTest, Playing_Normal) { // and verifies that they are produced by WebMediaPlayerMS in appropriate // order. - MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true); + MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true); int tokens[] = {0, 33, 66, 100, 133, 166, 200, 233, 266, 300, 333, 366, 400, 433, 466, 500, 533, 566, 600}; @@ -583,7 +585,7 @@ TEST_F(WebMediaPlayerMSTest, Playing_ErrorFrame) { // This tests sends a broken frame to WebMediaPlayerMS, and verifies // OnSourceError function works as expected. - MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); + MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(false); const int kBrokenFrame = static_cast<int>(FrameType::BROKEN_FRAME); int tokens[] = {0, 33, 66, 100, 133, 166, 200, 233, 266, 300, @@ -615,7 +617,7 @@ TEST_P(WebMediaPlayerMSTest, PlayThenPause) { // In the middle of this test, WebMediaPlayerMS::pause will be called, and we // are going to verify that during the pause stage, a frame gets freezed, and // cc::VideoFrameProviderClient should also be paused. - MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); + MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(false); const int kTestBrake = static_cast<int>(FrameType::TEST_BRAKE); int tokens[] = {0, 33, 66, 100, 133, kTestBrake, 166, 200, 233, 266, @@ -655,7 +657,7 @@ TEST_P(WebMediaPlayerMSTest, PlayThenPauseThenPlay) { const bool odd_size_frame = testing::get<1>(GetParam()); // Similary to PlayAndPause test above, this one focuses on testing that // WebMediaPlayerMS can be resumed after a period of paused status. - MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); + MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(false); const int kTestBrake = static_cast<int>(FrameType::TEST_BRAKE); int tokens[] = {0, 33, 66, 100, 133, kTestBrake, 166, @@ -714,7 +716,7 @@ TEST_F(WebMediaPlayerMSTest, BackgroundRendering) { // WebMediaPlayerMS without an explicit notification. We should expect that // WebMediaPlayerMS can digest old frames, rather than piling frames up and // explode. - MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true); + MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true); const int kTestBrake = static_cast<int>(FrameType::TEST_BRAKE); int tokens[] = {0, 33, 66, 100, 133, kTestBrake, 166, @@ -760,7 +762,7 @@ TEST_F(WebMediaPlayerMSTest, FrameSizeChange) { // During this test, the frame size of the input changes. // We need to make sure, when sizeChanged() gets called, new size should be // returned by GetCurrentSize(). - MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true); + MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true); int tokens[] = {0, 33, 66, 100, 133, 166, 200, 233, 266, 300, 333, 366, 400, 433, 466, 500, 533, 566, 600}; diff --git a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.cc b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.cc index 928b1804c68..78ac79672cf 100644 --- a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.cc +++ b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source.cc @@ -72,6 +72,10 @@ MediaStreamRemoteVideoSource:: RemoteVideoSourceDelegate::~RemoteVideoSourceDelegate() { } +namespace { +void DoNothing(const scoped_refptr<rtc::RefCountInterface>& ref) {} +} // anonymous + void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame( const cricket::VideoFrame& incoming_frame) { const base::TimeDelta incoming_timestamp = base::TimeDelta::FromMicroseconds( @@ -89,16 +93,19 @@ void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame( incoming_timestamp - start_timestamp_; scoped_refptr<media::VideoFrame> video_frame; - if (incoming_frame.video_frame_buffer()->native_handle() != NULL) { + scoped_refptr<webrtc::VideoFrameBuffer> buffer( + incoming_frame.video_frame_buffer()); + + if (buffer->native_handle() != NULL) { video_frame = - static_cast<media::VideoFrame*>( - incoming_frame.video_frame_buffer()->native_handle()); + static_cast<media::VideoFrame*>(buffer->native_handle()); video_frame->set_timestamp(elapsed_timestamp); } else { - const cricket::VideoFrame* frame = - incoming_frame.GetCopyWithRotationApplied(); - - gfx::Size size(frame->width(), frame->height()); + // Note that the GetCopyWithRotationApplied returns a pointer to a + // frame owned by incoming_frame. + buffer = + incoming_frame.GetCopyWithRotationApplied()->video_frame_buffer(); + gfx::Size size(buffer->width(), buffer->height()); // Make a shallow copy. Both |frame| and |video_frame| will share a single // reference counted frame buffer. Const cast and hope no one will overwrite @@ -107,17 +114,17 @@ void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame( // need to const cast here. video_frame = media::VideoFrame::WrapExternalYuvData( media::PIXEL_FORMAT_YV12, size, gfx::Rect(size), size, - frame->video_frame_buffer()->StrideY(), - frame->video_frame_buffer()->StrideU(), - frame->video_frame_buffer()->StrideV(), - const_cast<uint8_t*>(frame->video_frame_buffer()->DataY()), - const_cast<uint8_t*>(frame->video_frame_buffer()->DataU()), - const_cast<uint8_t*>(frame->video_frame_buffer()->DataV()), + buffer->StrideY(), + buffer->StrideU(), + buffer->StrideV(), + const_cast<uint8_t*>(buffer->DataY()), + const_cast<uint8_t*>(buffer->DataU()), + const_cast<uint8_t*>(buffer->DataV()), elapsed_timestamp); if (!video_frame) return; - video_frame->AddDestructionObserver( - base::Bind(&base::DeletePointer<cricket::VideoFrame>, frame->Copy())); + // The bind ensures that we keep a reference to the underlying buffer. + video_frame->AddDestructionObserver(base::Bind(&DoNothing, buffer)); } video_frame->metadata()->SetTimeTicks( diff --git a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc index 5cd94260e38..b921adb8422 100644 --- a/chromium/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc +++ b/chromium/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc @@ -128,9 +128,13 @@ TEST_F(MediaStreamRemoteVideoSourceTest, StartTrack) { base::Closure quit_closure = run_loop.QuitClosure(); EXPECT_CALL(sink, OnVideoFrame()).WillOnce( RunClosure(quit_closure)); - cricket::WebRtcVideoFrame webrtc_frame; - webrtc_frame.InitToBlack(320, 240, 1); - source()->SinkInterfaceForTest()->OnFrame(webrtc_frame); + rtc::scoped_refptr<webrtc::I420Buffer> buffer( + new rtc::RefCountedObject<webrtc::I420Buffer>(320, 240)); + + buffer->SetToBlack(); + + source()->SinkInterfaceForTest()->OnFrame( + cricket::WebRtcVideoFrame(buffer, 1, webrtc::kVideoRotation_0)); run_loop.Run(); EXPECT_EQ(1, sink.number_of_frames()); diff --git a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc index 76888542d54..ea6e87ba9ad 100644 --- a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc +++ b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.cc @@ -20,6 +20,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/waitable_event.h" +#include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "content/common/media/media_stream_messages.h" #include "content/public/common/content_client.h" @@ -29,13 +30,12 @@ #include "content/public/common/renderer_preferences.h" #include "content/public/common/webrtc_ip_handling_policy.h" #include "content/public/renderer/content_renderer_client.h" +#include "content/renderer/media/gpu/rtc_video_decoder_factory.h" +#include "content/renderer/media/gpu/rtc_video_encoder_factory.h" #include "content/renderer/media/media_stream.h" #include "content/renderer/media/media_stream_video_source.h" #include "content/renderer/media/media_stream_video_track.h" -#include "content/renderer/media/peer_connection_identity_store.h" #include "content/renderer/media/rtc_peer_connection_handler.h" -#include "content/renderer/media/rtc_video_decoder_factory.h" -#include "content/renderer/media/rtc_video_encoder_factory.h" #include "content/renderer/media/webrtc/stun_field_trial.h" #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" #include "content/renderer/media/webrtc_audio_device_impl.h" @@ -61,7 +61,6 @@ #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" -#include "third_party/webrtc/api/dtlsidentitystore.h" #include "third_party/webrtc/api/mediaconstraintsinterface.h" #include "third_party/webrtc/base/ssladapter.h" #include "third_party/webrtc/modules/video_coding/codecs/h264/include/h264.h" @@ -186,13 +185,17 @@ void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() { CHECK(chrome_signaling_thread_.Start()); CHECK(chrome_worker_thread_.Start()); - base::WaitableEvent start_worker_event(true, false); + base::WaitableEvent start_worker_event( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); chrome_worker_thread_.task_runner()->PostTask( FROM_HERE, base::Bind(&PeerConnectionDependencyFactory::InitializeWorkerThread, base::Unretained(this), &worker_thread_, &start_worker_event)); - base::WaitableEvent create_network_manager_event(true, false); + base::WaitableEvent create_network_manager_event( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); chrome_worker_thread_.task_runner()->PostTask( FROM_HERE, base::Bind(&PeerConnectionDependencyFactory:: @@ -211,7 +214,9 @@ void PeerConnectionDependencyFactory::CreatePeerConnectionFactory() { return; } - base::WaitableEvent start_signaling_event(true, false); + base::WaitableEvent start_signaling_event( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); chrome_signaling_thread_.task_runner()->PostTask( FROM_HERE, base::Bind(&PeerConnectionDependencyFactory::InitializeSignalingThread, @@ -290,12 +295,6 @@ PeerConnectionDependencyFactory::CreatePeerConnection( if (!GetPcFactory().get()) return NULL; - std::unique_ptr<PeerConnectionIdentityStore> identity_store( - new PeerConnectionIdentityStore( - base::ThreadTaskRunnerHandle::Get(), GetWebRtcSignalingThread(), - GURL(web_frame->document().url()), - GURL(web_frame->document().firstPartyForCookies()))); - // Copy the flag from Preference associated with this WebFrame. P2PPortAllocator::Config port_config; @@ -387,36 +386,20 @@ PeerConnectionDependencyFactory::CreatePeerConnection( FilteringNetworkManager* filtering_network_manager = new FilteringNetworkManager(network_manager_, requesting_origin, media_permission); - if (media_permission) { - // Start permission check earlier to reduce any impact to call set up - // time. It's safe to use Unretained here since both destructor and - // Initialize can only be called on the worker thread. - chrome_worker_thread_.task_runner()->PostTask( - FROM_HERE, base::Bind(&FilteringNetworkManager::Initialize, - base::Unretained(filtering_network_manager))); - } network_manager.reset(filtering_network_manager); } else { network_manager.reset(new EmptyNetworkManager(network_manager_)); } std::unique_ptr<P2PPortAllocator> port_allocator(new P2PPortAllocator( p2p_socket_dispatcher_, std::move(network_manager), socket_factory_.get(), - port_config, requesting_origin, chrome_worker_thread_.task_runner())); + port_config, requesting_origin)); return GetPcFactory() ->CreatePeerConnection(config, std::move(port_allocator), - std::move(identity_store), observer) + nullptr, observer) .get(); } -// static -rtc::scoped_refptr<rtc::RTCCertificate> -PeerConnectionDependencyFactory::GenerateDefaultCertificate() { - std::unique_ptr<rtc::SSLIdentity> identity(rtc::SSLIdentity::Generate( - webrtc::kIdentityName, rtc::KeyParams::ECDSA(rtc::EC_NIST_P256))); - return rtc::RTCCertificate::Create(std::move(identity)); -} - scoped_refptr<webrtc::MediaStreamInterface> PeerConnectionDependencyFactory::CreateLocalMediaStream( const std::string& label) { @@ -496,7 +479,7 @@ void PeerConnectionDependencyFactory::TryScheduleStunProbeTrial() { // The underneath IPC channel has to be connected before sending any IPC // message. if (!p2p_socket_dispatcher_->connected()) { - base::MessageLoop::current()->PostDelayedTask( + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::Bind(&PeerConnectionDependencyFactory::TryScheduleStunProbeTrial, base::Unretained(this)), diff --git a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h index e5e017c5a7c..fc69d224759 100644 --- a/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h +++ b/chromium/content/renderer/media/webrtc/peer_connection_dependency_factory.h @@ -67,9 +67,6 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory blink::WebRTCPeerConnectionHandler* CreateRTCPeerConnectionHandler( blink::WebRTCPeerConnectionHandlerClient* client); - // Generate an ECDSA certificate. - static rtc::scoped_refptr<rtc::RTCCertificate> GenerateDefaultCertificate(); - // Asks the PeerConnection factory to create a Local MediaStream object. virtual scoped_refptr<webrtc::MediaStreamInterface> CreateLocalMediaStream(const std::string& label); diff --git a/chromium/content/renderer/media/webrtc/webrtc_audio_sink.cc b/chromium/content/renderer/media/webrtc/webrtc_audio_sink.cc index 213b2b0d650..2d789a9acc6 100644 --- a/chromium/content/renderer/media/webrtc/webrtc_audio_sink.cc +++ b/chromium/content/renderer/media/webrtc/webrtc_audio_sink.cc @@ -11,7 +11,7 @@ #include "base/bind_helpers.h" #include "base/location.h" #include "base/logging.h" -#include "base/message_loop/message_loop.h" +#include "base/threading/thread_task_runner_handle.h" namespace content { @@ -109,7 +109,7 @@ WebRtcAudioSink::Adapter::Adapter( : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label), source_(std::move(source)), signaling_task_runner_(std::move(signaling_task_runner)), - main_task_runner_(base::MessageLoop::current()->task_runner()) { + main_task_runner_(base::ThreadTaskRunnerHandle::Get()) { DCHECK(signaling_task_runner_); } diff --git a/chromium/content/renderer/media/webrtc/webrtc_audio_sink.h b/chromium/content/renderer/media/webrtc/webrtc_audio_sink.h index ce302fa88dc..3c437c69431 100644 --- a/chromium/content/renderer/media/webrtc/webrtc_audio_sink.h +++ b/chromium/content/renderer/media/webrtc/webrtc_audio_sink.h @@ -21,7 +21,6 @@ #include "media/base/audio_parameters.h" #include "media/base/audio_push_fifo.h" #include "third_party/webrtc/api/mediastreamtrack.h" -#include "third_party/webrtc/media/base/audiorenderer.h" namespace content { diff --git a/chromium/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc b/chromium/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc index 35843d0515c..17641916639 100644 --- a/chromium/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc +++ b/chromium/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc @@ -7,21 +7,6 @@ #include "base/logging.h" namespace content { -namespace { -int WebRtcToMediaPlaneType(webrtc::PlaneType type) { - switch (type) { - case webrtc::kYPlane: - return media::VideoFrame::kYPlane; - case webrtc::kUPlane: - return media::VideoFrame::kUPlane; - case webrtc::kVPlane: - return media::VideoFrame::kVPlane; - default: - NOTREACHED(); - return media::VideoFrame::kMaxPlanes; - } -} -} // anonymous namespace WebRtcVideoFrameAdapter::WebRtcVideoFrameAdapter( const scoped_refptr<media::VideoFrame>& frame) @@ -39,12 +24,24 @@ int WebRtcVideoFrameAdapter::height() const { return frame_->visible_rect().height(); } -const uint8_t* WebRtcVideoFrameAdapter::data(webrtc::PlaneType type) const { - return frame_->visible_data(WebRtcToMediaPlaneType(type)); +const uint8_t* WebRtcVideoFrameAdapter::DataY() const { + return frame_->visible_data(media::VideoFrame::kYPlane); +} +const uint8_t* WebRtcVideoFrameAdapter::DataU() const { + return frame_->visible_data(media::VideoFrame::kUPlane); +} +const uint8_t* WebRtcVideoFrameAdapter::DataV() const { + return frame_->visible_data(media::VideoFrame::kVPlane); } -int WebRtcVideoFrameAdapter::stride(webrtc::PlaneType type) const { - return frame_->stride(WebRtcToMediaPlaneType(type)); +int WebRtcVideoFrameAdapter::StrideY() const { + return frame_->stride(media::VideoFrame::kYPlane); +} +int WebRtcVideoFrameAdapter::StrideU() const { + return frame_->stride(media::VideoFrame::kUPlane); +} +int WebRtcVideoFrameAdapter::StrideV() const { + return frame_->stride(media::VideoFrame::kVPlane); } void* WebRtcVideoFrameAdapter::native_handle() const { diff --git a/chromium/content/renderer/media/webrtc/webrtc_video_frame_adapter.h b/chromium/content/renderer/media/webrtc/webrtc_video_frame_adapter.h index 61555d032ec..46dd87683d0 100644 --- a/chromium/content/renderer/media/webrtc/webrtc_video_frame_adapter.h +++ b/chromium/content/renderer/media/webrtc/webrtc_video_frame_adapter.h @@ -24,9 +24,13 @@ class WebRtcVideoFrameAdapter : public webrtc::VideoFrameBuffer { int width() const override; int height() const override; - const uint8_t* data(webrtc::PlaneType type) const override; + const uint8_t* DataY() const override; + const uint8_t* DataU() const override; + const uint8_t* DataV() const override; - int stride(webrtc::PlaneType type) const override; + int StrideY() const override; + int StrideU() const override; + int StrideV() const override; void* native_handle() const override; diff --git a/chromium/content/renderer/media/webrtc_audio_device_impl.cc b/chromium/content/renderer/media/webrtc_audio_device_impl.cc index 7f46506fada..2cb2eacbb32 100644 --- a/chromium/content/renderer/media/webrtc_audio_device_impl.cc +++ b/chromium/content/renderer/media/webrtc_audio_device_impl.cc @@ -4,6 +4,7 @@ #include "content/renderer/media/webrtc_audio_device_impl.h" +#include "base/logging.h" #include "base/metrics/histogram.h" #include "base/strings/string_util.h" #include "base/win/windows_version.h" @@ -62,9 +63,15 @@ void WebRtcAudioDeviceImpl::RenderData(media::AudioBus* audio_bus, int sample_rate, int audio_delay_milliseconds, base::TimeDelta* current_time) { - DCHECK(audio_renderer_thread_checker_.CalledOnValidThread()); { base::AutoLock auto_lock(lock_); +#if DCHECK_IS_ON() + DCHECK(renderer_->CurrentThreadIsRenderingThread()); + if (!audio_renderer_thread_checker_.CalledOnValidThread()) { + for (const auto& sink : playout_sinks_) + sink->OnRenderThreadChanged(); + } +#endif if (!playing_) { // Force silence to AudioBus after stopping playout in case // there is lingering audio data in AudioBus. diff --git a/chromium/content/renderer/media/webrtc_audio_device_impl.h b/chromium/content/renderer/media/webrtc_audio_device_impl.h index 6af4a869356..1e3f05f1a64 100644 --- a/chromium/content/renderer/media/webrtc_audio_device_impl.h +++ b/chromium/content/renderer/media/webrtc_audio_device_impl.h @@ -219,7 +219,7 @@ class WebRtcPlayoutDataSource { class Sink { public: // Callback to get the playout data. - // Called on the render audio thread. + // Called on the audio render thread. virtual void OnPlayoutData(media::AudioBus* audio_bus, int sample_rate, int audio_delay_milliseconds) = 0; @@ -228,6 +228,11 @@ class WebRtcPlayoutDataSource { // Called on the main render thread. virtual void OnPlayoutDataSourceChanged() = 0; + // Called to notify that the audio render thread has changed, and + // OnPlayoutData() will from now on be called on the new thread. + // Called on the new audio render thread. + virtual void OnRenderThreadChanged() = 0; + protected: virtual ~Sink() {} }; diff --git a/chromium/content/renderer/media/webrtc_audio_renderer.cc b/chromium/content/renderer/media/webrtc_audio_renderer.cc index 604ed959a0d..da693872812 100644 --- a/chromium/content/renderer/media/webrtc_audio_renderer.cc +++ b/chromium/content/renderer/media/webrtc_audio_renderer.cc @@ -20,10 +20,10 @@ #include "content/renderer/media/webrtc_logging.h" #include "media/audio/sample_rates.h" #include "media/base/audio_capturer_source.h" +#include "media/base/audio_latency.h" #include "media/base/audio_parameters.h" #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" #include "third_party/webrtc/api/mediastreaminterface.h" -#include "third_party/webrtc/media/base/audiorenderer.h" #if defined(OS_WIN) #include "base/win/windows_version.h" @@ -153,39 +153,6 @@ class SharedAudioRenderer : public MediaStreamAudioRenderer { } // namespace -int WebRtcAudioRenderer::GetOptimalBufferSize(int sample_rate, - int hardware_buffer_size) { - // Use native hardware buffer size as default. On Windows, we strive to open - // up using this native hardware buffer size to achieve best - // possible performance and to ensure that no FIFO is needed on the browser - // side to match the client request. That is why there is no #if case for - // Windows below. - int frames_per_buffer = hardware_buffer_size; - -#if defined(OS_LINUX) || defined(OS_MACOSX) - // On Linux and MacOS, the low level IO implementations on the browser side - // supports all buffer size the clients want. We use the native peer - // connection buffer size (10ms) to achieve best possible performance. - frames_per_buffer = sample_rate / 100; -#elif defined(OS_ANDROID) - // TODO(henrika): Keep tuning this scheme and espcicially for low-latency - // cases. Might not be possible to come up with the perfect solution using - // the render side only. - int frames_per_10ms = sample_rate / 100; - if (frames_per_buffer < 2 * frames_per_10ms) { - // Examples of low-latency frame sizes and the resulting |buffer_size|: - // Nexus 7 : 240 audio frames => 2*480 = 960 - // Nexus 10 : 256 => 2*441 = 882 - // Galaxy Nexus: 144 => 2*441 = 882 - frames_per_buffer = 2 * frames_per_10ms; - DVLOG(1) << "Low-latency output detected on Android"; - } -#endif - - DVLOG(1) << "Using sink output buffer size: " << frames_per_buffer; - return frames_per_buffer; -} - WebRtcAudioRenderer::WebRtcAudioRenderer( const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread, const blink::WebMediaStream& media_stream, @@ -209,7 +176,6 @@ WebRtcAudioRenderer::WebRtcAudioRenderer( WebRtcLogMessage(base::StringPrintf( "WAR::WAR. source_render_frame_id=%d, session_id=%d, effects=%i", source_render_frame_id, session_id, sink_params_.effects())); - audio_renderer_thread_checker_.DetachFromThread(); } WebRtcAudioRenderer::~WebRtcAudioRenderer() { @@ -241,7 +207,7 @@ bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) { PrepareSink(); { // No need to reassert the preconditions because the other thread accessing - // the fields (checked by |audio_renderer_thread_checker_|) only reads them. + // the fields only reads them. base::AutoLock auto_lock(lock_); source_ = source; @@ -267,6 +233,10 @@ bool WebRtcAudioRenderer::IsStarted() const { return start_ref_count_ != 0; } +bool WebRtcAudioRenderer::CurrentThreadIsRenderingThread() { + return sink_->CurrentThreadIsRenderingThread(); +} + void WebRtcAudioRenderer::Start() { DVLOG(1) << "WebRtcAudioRenderer::Start()"; DCHECK(thread_checker_.CalledOnValidThread()); @@ -407,7 +377,6 @@ void WebRtcAudioRenderer::SwitchOutputDevice( // callback may currently be executing and trying to grab the lock while we're // stopping the thread on which it runs. sink_->Stop(); - audio_renderer_thread_checker_.DetachFromThread(); sink_ = new_sink; output_device_id_ = device_id; security_origin_ = security_origin; @@ -424,7 +393,7 @@ void WebRtcAudioRenderer::SwitchOutputDevice( int WebRtcAudioRenderer::Render(media::AudioBus* audio_bus, uint32_t frames_delayed, uint32_t frames_skipped) { - DCHECK(audio_renderer_thread_checker_.CalledOnValidThread()); + DCHECK(sink_->CurrentThreadIsRenderingThread()); base::AutoLock auto_lock(lock_); if (!source_) return 0; @@ -481,7 +450,7 @@ void WebRtcAudioRenderer::OnRenderError() { // Called by AudioPullFifo when more data is necessary. void WebRtcAudioRenderer::SourceCallback( int fifo_frame_delay, media::AudioBus* audio_bus) { - DCHECK(audio_renderer_thread_checker_.CalledOnValidThread()); + DCHECK(sink_->CurrentThreadIsRenderingThread()); base::TimeTicks start_time = base::TimeTicks::Now(); DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" << fifo_frame_delay << ", " @@ -654,7 +623,7 @@ void WebRtcAudioRenderer::PrepareSink() { DVLOG(1) << "Using WebRTC output buffer size: " << source_frames_per_buffer; // Setup sink parameters. - const int sink_frames_per_buffer = GetOptimalBufferSize( + const int sink_frames_per_buffer = media::AudioLatency::GetRtcBufferSize( sample_rate, device_info.output_params().frames_per_buffer()); new_sink_params.set_sample_rate(sample_rate); new_sink_params.set_frames_per_buffer(sink_frames_per_buffer); diff --git a/chromium/content/renderer/media/webrtc_audio_renderer.h b/chromium/content/renderer/media/webrtc_audio_renderer.h index f13ac8d5bef..f4f677ee58f 100644 --- a/chromium/content/renderer/media/webrtc_audio_renderer.h +++ b/chromium/content/renderer/media/webrtc_audio_renderer.h @@ -73,10 +73,6 @@ class CONTENT_EXPORT WebRtcAudioRenderer float volume_; }; - - // Returns platform specific optimal buffer size for rendering audio. - static int GetOptimalBufferSize(int sample_rate, int hardware_buffer_size); - WebRtcAudioRenderer( const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread, const blink::WebMediaStream& media_stream, @@ -109,6 +105,9 @@ class CONTENT_EXPORT WebRtcAudioRenderer int sample_rate() const { return sink_params_.sample_rate(); } int frames_per_buffer() const { return sink_params_.frames_per_buffer(); } + // Returns true if called on rendering thread, otherwise false. + bool CurrentThreadIsRenderingThread(); + private: // MediaStreamAudioRenderer implementation. This is private since we want // callers to use proxy objects. @@ -155,7 +154,6 @@ class CONTENT_EXPORT WebRtcAudioRenderer // Used to DCHECK that we are called on the correct thread. base::ThreadChecker thread_checker_; - base::ThreadChecker audio_renderer_thread_checker_; // Flag to keep track the state of the renderer. State state_; diff --git a/chromium/content/renderer/media/webrtc_local_audio_source_provider.cc b/chromium/content/renderer/media/webrtc_local_audio_source_provider.cc index d77df9ac552..af465017c68 100644 --- a/chromium/content/renderer/media/webrtc_local_audio_source_provider.cc +++ b/chromium/content/renderer/media/webrtc_local_audio_source_provider.cc @@ -130,8 +130,8 @@ void WebRtcLocalAudioSourceProvider::provideInput( audio_converter_->Convert(output_wrapper_.get()); } -double WebRtcLocalAudioSourceProvider::ProvideInput( - media::AudioBus* audio_bus, base::TimeDelta buffer_delay) { +double WebRtcLocalAudioSourceProvider::ProvideInput(media::AudioBus* audio_bus, + uint32_t frames_delayed) { if (fifo_->frames() >= audio_bus->frames()) { fifo_->Consume(audio_bus, 0, audio_bus->frames()); } else { diff --git a/chromium/content/renderer/media/webrtc_local_audio_source_provider.h b/chromium/content/renderer/media/webrtc_local_audio_source_provider.h index f5a867fc949..cbf8d7980ad 100644 --- a/chromium/content/renderer/media/webrtc_local_audio_source_provider.h +++ b/chromium/content/renderer/media/webrtc_local_audio_source_provider.h @@ -75,7 +75,7 @@ class CONTENT_EXPORT WebRtcLocalAudioSourceProvider // This function is triggered by provideInput()on the WebAudio audio thread, // so it has been under the protection of |lock_|. double ProvideInput(media::AudioBus* audio_bus, - base::TimeDelta buffer_delay) override; + uint32_t frames_delayed) override; // Method to allow the unittests to inject its own sink parameters to avoid // query the hardware. diff --git a/chromium/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc b/chromium/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc index 6eda8f178ec..b4013097e2d 100644 --- a/chromium/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc +++ b/chromium/content/renderer/media/webrtc_local_audio_source_provider_unittest.cc @@ -33,7 +33,7 @@ class WebRtcLocalAudioSourceProviderTest : public testing::Test { false /* remote */); blink_track_.initialize(blink::WebString::fromUTF8("audio_track"), audio_source); - blink_track_.setExtraData(new MediaStreamAudioTrack(true)); + blink_track_.setTrackData(new MediaStreamAudioTrack(true)); source_provider_.reset(new WebRtcLocalAudioSourceProvider(blink_track_)); source_provider_->SetSinkParamsForTesting(sink_params_); source_provider_->OnSetFormat(source_params_); diff --git a/chromium/content/renderer/mojo/blink_service_registry_impl.cc b/chromium/content/renderer/mojo/blink_service_registry_impl.cc index 6a2fdf09a6a..408f6de8064 100644 --- a/chromium/content/renderer/mojo/blink_service_registry_impl.cc +++ b/chromium/content/renderer/mojo/blink_service_registry_impl.cc @@ -6,23 +6,36 @@ #include <utility> -#include "content/common/mojo/service_registry_impl.h" +#include "base/bind.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "services/shell/public/cpp/interface_provider.h" namespace content { BlinkServiceRegistryImpl::BlinkServiceRegistryImpl( - base::WeakPtr<content::ServiceRegistry> service_registry) - : service_registry_(service_registry) {} + base::WeakPtr<shell::InterfaceProvider> remote_interfaces) + : remote_interfaces_(remote_interfaces), + main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), + weak_ptr_factory_(this) {} BlinkServiceRegistryImpl::~BlinkServiceRegistryImpl() = default; void BlinkServiceRegistryImpl::connectToRemoteService( const char* name, mojo::ScopedMessagePipeHandle handle) { - if (!service_registry_) + if (!main_thread_task_runner_->BelongsToCurrentThread()) { + main_thread_task_runner_->PostTask( + FROM_HERE, base::Bind(&BlinkServiceRegistryImpl::connectToRemoteService, + weak_ptr_factory_.GetWeakPtr(), name, + base::Passed(&handle))); return; + } - service_registry_->ConnectToRemoteService(name, std::move(handle)); + if (!remote_interfaces_) + return; + + remote_interfaces_->GetInterface(name, std::move(handle)); } } // namespace content diff --git a/chromium/content/renderer/mojo/blink_service_registry_impl.h b/chromium/content/renderer/mojo/blink_service_registry_impl.h index 8bd86321e68..2fc08ae35f3 100644 --- a/chromium/content/renderer/mojo/blink_service_registry_impl.h +++ b/chromium/content/renderer/mojo/blink_service_registry_impl.h @@ -6,20 +6,27 @@ #define CONTENT_RENDERER_MOJO_BLINK_SERVICE_REGISTRY_IMPL_H_ #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "mojo/public/cpp/system/message_pipe.h" #include "third_party/WebKit/public/platform/ServiceRegistry.h" -namespace content { +namespace base { +class SingleThreadTaskRunner; +} + +namespace shell { +class InterfaceProvider; +} -class ServiceRegistry; +namespace content { // An implementation of blink::ServiceRegistry that forwards to a -// content::ServiceRegistry. +// shell::InterfaceProvider. class BlinkServiceRegistryImpl : public blink::ServiceRegistry { public: explicit BlinkServiceRegistryImpl( - base::WeakPtr<content::ServiceRegistry> service_registry); + base::WeakPtr<shell::InterfaceProvider> remote_interfaces); ~BlinkServiceRegistryImpl(); // blink::ServiceRegistry override. @@ -27,7 +34,11 @@ class BlinkServiceRegistryImpl : public blink::ServiceRegistry { mojo::ScopedMessagePipeHandle handle) override; private: - const base::WeakPtr<content::ServiceRegistry> service_registry_; + const base::WeakPtr<shell::InterfaceProvider> remote_interfaces_; + + scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; + + base::WeakPtrFactory<BlinkServiceRegistryImpl> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(BlinkServiceRegistryImpl); }; diff --git a/chromium/content/renderer/mojo/interface_provider_js_wrapper.cc b/chromium/content/renderer/mojo/interface_provider_js_wrapper.cc new file mode 100644 index 00000000000..174455d525a --- /dev/null +++ b/chromium/content/renderer/mojo/interface_provider_js_wrapper.cc @@ -0,0 +1,112 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/mojo/interface_provider_js_wrapper.h" + +#include <memory> +#include <utility> + +#include "mojo/edk/js/handle.h" +#include "services/shell/public/cpp/interface_provider.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" + +namespace content { + +gin::WrapperInfo InterfaceProviderJsWrapper::kWrapperInfo = { + gin::kEmbedderNativeGin}; +const char InterfaceProviderJsWrapper::kPerFrameModuleName[] = + "content/public/renderer/frame_service_registry"; +const char InterfaceProviderJsWrapper::kPerProcessModuleName[] = + "content/public/renderer/service_registry"; + +InterfaceProviderJsWrapper::~InterfaceProviderJsWrapper() { +} + +// static +gin::Handle<InterfaceProviderJsWrapper> +InterfaceProviderJsWrapper::Create( + v8::Isolate* isolate, + v8::Handle<v8::Context> context, + shell::InterfaceProvider* remote_interfaces) { + return gin::CreateHandle( + isolate, + new InterfaceProviderJsWrapper( + isolate, context, + remote_interfaces->GetWeakPtr())); +} + +gin::ObjectTemplateBuilder +InterfaceProviderJsWrapper::GetObjectTemplateBuilder(v8::Isolate* isolate) { + return Wrappable<InterfaceProviderJsWrapper>::GetObjectTemplateBuilder( + isolate) + .SetMethod("connectToService", + &InterfaceProviderJsWrapper::GetInterface) + .SetMethod("addServiceOverrideForTesting", + &InterfaceProviderJsWrapper::AddOverrideForTesting) + .SetMethod("clearServiceOverridesForTesting", + &InterfaceProviderJsWrapper::ClearOverridesForTesting); +} + +mojo::Handle InterfaceProviderJsWrapper::GetInterface( + const std::string& interface_name) { + mojo::MessagePipe pipe; + if (remote_interfaces_) { + remote_interfaces_->GetInterface( + interface_name, std::move(pipe.handle0)); + } + return pipe.handle1.release(); +} + +void InterfaceProviderJsWrapper::AddOverrideForTesting( + const std::string& interface_name, + v8::Local<v8::Function> service_factory) { + ScopedJsFactory factory(v8::Isolate::GetCurrent(), service_factory); + shell::InterfaceProvider::TestApi test_api(remote_interfaces_.get()); + test_api.SetBinderForName( + interface_name, + base::Bind(&InterfaceProviderJsWrapper::CallJsFactory, + weak_factory_.GetWeakPtr(), factory)); +} + +void InterfaceProviderJsWrapper::ClearOverridesForTesting() { + shell::InterfaceProvider::TestApi test_api(remote_interfaces_.get()); + test_api.ClearBinders(); +} + +InterfaceProviderJsWrapper::InterfaceProviderJsWrapper( + v8::Isolate* isolate, + v8::Handle<v8::Context> context, + base::WeakPtr<shell::InterfaceProvider> remote_interfaces) + : isolate_(isolate), + context_(isolate, context), + remote_interfaces_(remote_interfaces), + weak_factory_(this) { + context_.SetWeak(this, &InterfaceProviderJsWrapper::ClearContext, + v8::WeakCallbackType::kParameter); +} + +void InterfaceProviderJsWrapper::CallJsFactory( + const ScopedJsFactory& factory, + mojo::ScopedMessagePipeHandle pipe) { + if (context_.IsEmpty()) + return; + + v8::HandleScope handle_scope(isolate_); + v8::Handle<v8::Context> context = context_.Get(isolate_); + v8::Context::Scope context_scope(context); + v8::Local<v8::Value> argv[] = { + gin::ConvertToV8(isolate_, mojo::Handle(pipe.release().value()))}; + blink::WebLocalFrame::frameForContext(context) + ->callFunctionEvenIfScriptDisabled(factory.Get(isolate_), + v8::Undefined(isolate_), 1, argv); +} + +// static +void InterfaceProviderJsWrapper::ClearContext( + const v8::WeakCallbackInfo<InterfaceProviderJsWrapper>& data) { + InterfaceProviderJsWrapper* registry = data.GetParameter(); + registry->context_.Reset(); +} + +} // namespace content diff --git a/chromium/content/renderer/mojo/interface_provider_js_wrapper.h b/chromium/content/renderer/mojo/interface_provider_js_wrapper.h new file mode 100644 index 00000000000..0c5c6eb9bac --- /dev/null +++ b/chromium/content/renderer/mojo/interface_provider_js_wrapper.h @@ -0,0 +1,75 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MOJO_INTERFACE_PROVIDER_JS_WRAPPER_H_ +#define CONTENT_RENDERER_MOJO_INTERFACE_PROVIDER_JS_WRAPPER_H_ + +#include <string> + +#include "base/macros.h" +#include "content/common/content_export.h" +#include "gin/handle.h" +#include "gin/object_template_builder.h" +#include "gin/wrappable.h" +#include "mojo/public/cpp/system/message_pipe.h" +#include "v8/include/v8.h" + +namespace shell { +class InterfaceProvider; +} + +namespace content { + +// A JS wrapper around shell::InterfaceProvider that allows connecting to +// remote services. +class CONTENT_EXPORT InterfaceProviderJsWrapper + : public gin::Wrappable<InterfaceProviderJsWrapper> { + public: + ~InterfaceProviderJsWrapper() override; + static gin::Handle<InterfaceProviderJsWrapper> Create( + v8::Isolate* isolate, + v8::Handle<v8::Context> context, + shell::InterfaceProvider* remote_interfaces); + + // gin::Wrappable<InterfaceProviderJsWrapper> overrides. + gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) override; + + // JS interface implementation. + void AddOverrideForTesting(const std::string& interface_name, + v8::Local<v8::Function> interface_factory); + void ClearOverridesForTesting(); + mojo::Handle GetInterface(const std::string& interface_name); + + static gin::WrapperInfo kWrapperInfo; + static const char kPerFrameModuleName[]; + static const char kPerProcessModuleName[]; + + private: + using ScopedJsFactory = + v8::Persistent<v8::Function, v8::CopyablePersistentTraits<v8::Function>>; + + InterfaceProviderJsWrapper( + v8::Isolate* isolate, + v8::Handle<v8::Context> context, + base::WeakPtr<shell::InterfaceProvider> remote_interfaces); + + void CallJsFactory(const ScopedJsFactory& factory, + mojo::ScopedMessagePipeHandle pipe); + + static void ClearContext( + const v8::WeakCallbackInfo<InterfaceProviderJsWrapper>& data); + + v8::Isolate* isolate_; + v8::Global<v8::Context> context_; + base::WeakPtr<shell::InterfaceProvider> remote_interfaces_; + + base::WeakPtrFactory<InterfaceProviderJsWrapper> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(InterfaceProviderJsWrapper); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MOJO_INTERFACE_PROVIDER_JS_WRAPPER_H_ diff --git a/chromium/content/renderer/mojo/service_registry_js_wrapper.cc b/chromium/content/renderer/mojo/service_registry_js_wrapper.cc deleted file mode 100644 index 8b5793820e3..00000000000 --- a/chromium/content/renderer/mojo/service_registry_js_wrapper.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/mojo/service_registry_js_wrapper.h" - -#include <memory> -#include <utility> - -#include "content/common/mojo/service_registry_impl.h" -#include "content/public/common/service_registry.h" -#include "mojo/edk/js/handle.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" - -namespace content { - -gin::WrapperInfo ServiceRegistryJsWrapper::kWrapperInfo = { - gin::kEmbedderNativeGin}; -const char ServiceRegistryJsWrapper::kPerFrameModuleName[] = - "content/public/renderer/frame_service_registry"; -const char ServiceRegistryJsWrapper::kPerProcessModuleName[] = - "content/public/renderer/service_registry"; - -ServiceRegistryJsWrapper::~ServiceRegistryJsWrapper() { -} - -// static -gin::Handle<ServiceRegistryJsWrapper> ServiceRegistryJsWrapper::Create( - v8::Isolate* isolate, - v8::Handle<v8::Context> context, - ServiceRegistry* service_registry) { - return gin::CreateHandle( - isolate, - new ServiceRegistryJsWrapper( - isolate, context, - static_cast<ServiceRegistryImpl*>(service_registry)->GetWeakPtr())); -} - -gin::ObjectTemplateBuilder ServiceRegistryJsWrapper::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return Wrappable<ServiceRegistryJsWrapper>::GetObjectTemplateBuilder(isolate) - .SetMethod("connectToService", - &ServiceRegistryJsWrapper::ConnectToService) - .SetMethod("addServiceOverrideForTesting", - &ServiceRegistryJsWrapper::AddServiceOverrideForTesting) - .SetMethod("clearServiceOverridesForTesting", - &ServiceRegistryJsWrapper::ClearServiceOverridesForTesting); -} - -mojo::Handle ServiceRegistryJsWrapper::ConnectToService( - const std::string& service_name) { - mojo::MessagePipe pipe; - if (service_registry_) - service_registry_->ConnectToRemoteService(service_name, - std::move(pipe.handle0)); - return pipe.handle1.release(); -} - -void ServiceRegistryJsWrapper::AddServiceOverrideForTesting( - const std::string& service_name, - v8::Local<v8::Function> service_factory) { - ServiceRegistry* registry = service_registry_.get(); - if (!registry) - return; - ScopedJsFactory factory(v8::Isolate::GetCurrent(), service_factory); - registry->AddServiceOverrideForTesting( - service_name, base::Bind(&ServiceRegistryJsWrapper::CallJsFactory, - weak_factory_.GetWeakPtr(), factory)); -} - -void ServiceRegistryJsWrapper::ClearServiceOverridesForTesting() { - ServiceRegistryImpl* registry = - static_cast<ServiceRegistryImpl*>(service_registry_.get()); - if (!registry) - return; - - registry->ClearServiceOverridesForTesting(); -} - -ServiceRegistryJsWrapper::ServiceRegistryJsWrapper( - v8::Isolate* isolate, - v8::Handle<v8::Context> context, - base::WeakPtr<ServiceRegistry> service_registry) - : isolate_(isolate), - context_(isolate, context), - service_registry_(service_registry), - weak_factory_(this) { - context_.SetWeak(this, &ServiceRegistryJsWrapper::ClearContext, - v8::WeakCallbackType::kParameter); -} - -void ServiceRegistryJsWrapper::CallJsFactory( - const ScopedJsFactory& factory, - mojo::ScopedMessagePipeHandle pipe) { - if (context_.IsEmpty()) - return; - - v8::HandleScope handle_scope(isolate_); - v8::Handle<v8::Context> context = context_.Get(isolate_); - v8::Context::Scope context_scope(context); - v8::Local<v8::Value> argv[] = { - gin::ConvertToV8(isolate_, mojo::Handle(pipe.release().value()))}; - blink::WebLocalFrame::frameForContext(context) - ->callFunctionEvenIfScriptDisabled(factory.Get(isolate_), - v8::Undefined(isolate_), 1, argv); -} - -// static -void ServiceRegistryJsWrapper::ClearContext( - const v8::WeakCallbackInfo<ServiceRegistryJsWrapper>& data) { - ServiceRegistryJsWrapper* service_registry = data.GetParameter(); - service_registry->context_.Reset(); -} - -} // namespace content diff --git a/chromium/content/renderer/mojo/service_registry_js_wrapper.h b/chromium/content/renderer/mojo/service_registry_js_wrapper.h deleted file mode 100644 index 5fc2f63729b..00000000000 --- a/chromium/content/renderer/mojo/service_registry_js_wrapper.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_MOJO_SERVICE_REGISTRY_JS_WRAPPER_H_ -#define CONTENT_RENDERER_MOJO_SERVICE_REGISTRY_JS_WRAPPER_H_ - -#include <string> - -#include "base/macros.h" -#include "content/common/content_export.h" -#include "gin/handle.h" -#include "gin/object_template_builder.h" -#include "gin/wrappable.h" -#include "mojo/public/cpp/system/message_pipe.h" -#include "v8/include/v8.h" - -namespace content { - -class ServiceRegistry; - -// A JS wrapper around ServiceRegistry that allows connecting to remote -// services. -class CONTENT_EXPORT ServiceRegistryJsWrapper - : public gin::Wrappable<ServiceRegistryJsWrapper> { - public: - ~ServiceRegistryJsWrapper() override; - static gin::Handle<ServiceRegistryJsWrapper> Create( - v8::Isolate* isolate, - v8::Handle<v8::Context> context, - ServiceRegistry* service_registry); - - // gin::Wrappable<ServiceRegistryJsWrapper> overrides. - gin::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; - - // JS interface implementation. - void AddServiceOverrideForTesting(const std::string& service_name, - v8::Local<v8::Function> service_factory); - void ClearServiceOverridesForTesting(); - mojo::Handle ConnectToService(const std::string& service_name); - - static gin::WrapperInfo kWrapperInfo; - static const char kPerFrameModuleName[]; - static const char kPerProcessModuleName[]; - - private: - using ScopedJsFactory = - v8::Persistent<v8::Function, v8::CopyablePersistentTraits<v8::Function>>; - - ServiceRegistryJsWrapper(v8::Isolate* isolate, - v8::Handle<v8::Context> context, - base::WeakPtr<ServiceRegistry> service_registry); - - void CallJsFactory(const ScopedJsFactory& factory, - mojo::ScopedMessagePipeHandle pipe); - - static void ClearContext( - const v8::WeakCallbackInfo<ServiceRegistryJsWrapper>& data); - - v8::Isolate* isolate_; - v8::Global<v8::Context> context_; - base::WeakPtr<ServiceRegistry> service_registry_; - - base::WeakPtrFactory<ServiceRegistryJsWrapper> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(ServiceRegistryJsWrapper); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_MOJO_SERVICE_REGISTRY_JS_WRAPPER_H_ diff --git a/chromium/content/renderer/mojo_bindings_controller.cc b/chromium/content/renderer/mojo_bindings_controller.cc index 135c5adf0ef..56cf602c0c3 100644 --- a/chromium/content/renderer/mojo_bindings_controller.cc +++ b/chromium/content/renderer/mojo_bindings_controller.cc @@ -98,4 +98,8 @@ void MojoBindingsController::DidClearWindowObject() { DestroyContextState(render_frame()->GetWebFrame()->mainWorldScriptContext()); } +void MojoBindingsController::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/mojo_bindings_controller.h b/chromium/content/renderer/mojo_bindings_controller.h index d26f17a85cf..b0a3fb6f8e8 100644 --- a/chromium/content/renderer/mojo_bindings_controller.h +++ b/chromium/content/renderer/mojo_bindings_controller.h @@ -43,6 +43,7 @@ class MojoBindingsController void WillReleaseScriptContext(v8::Local<v8::Context> context, int world_id) override; void DidClearWindowObject() override; + void OnDestruct() override; const bool for_layout_tests_; diff --git a/chromium/content/renderer/mouse_lock_dispatcher_browsertest.cc b/chromium/content/renderer/mouse_lock_dispatcher_browsertest.cc index 2a0fd6b4778..685da6d7b57 100644 --- a/chromium/content/renderer/mouse_lock_dispatcher_browsertest.cc +++ b/chromium/content/renderer/mouse_lock_dispatcher_browsertest.cc @@ -30,7 +30,7 @@ class MouseLockDispatcherTest : public RenderViewTest { public: void SetUp() override { RenderViewTest::SetUp(); - route_id_ = view()->GetRoutingID(); + route_id_ = view()->GetWidget()->routing_id(); target_ = new MockLockTarget(); alternate_target_ = new MockLockTarget(); } @@ -43,6 +43,7 @@ class MouseLockDispatcherTest : public RenderViewTest { protected: RenderViewImpl* view() { return static_cast<RenderViewImpl*>(view_); } + RenderWidget* widget() { return view()->GetWidget(); } MouseLockDispatcher* dispatcher() { return view()->mouse_lock_dispatcher(); } int route_id_; MockLockTarget* target_; @@ -54,22 +55,22 @@ class MouseLockDispatcherTest : public RenderViewTest { // Test simple use of RenderViewImpl interface to WebKit for pointer lock. TEST_F(MouseLockDispatcherTest, BasicWebWidget) { // Start unlocked. - EXPECT_FALSE(view()->isPointerLocked()); + EXPECT_FALSE(widget()->isPointerLocked()); // Lock. - EXPECT_TRUE(view()->requestPointerLock()); - view()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); - EXPECT_TRUE(view()->isPointerLocked()); + EXPECT_TRUE(widget()->requestPointerLock()); + widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); + EXPECT_TRUE(widget()->isPointerLocked()); // Unlock. - view()->requestPointerUnlock(); - view()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); - EXPECT_FALSE(view()->isPointerLocked()); + widget()->requestPointerUnlock(); + widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); + EXPECT_FALSE(widget()->isPointerLocked()); // Attempt a lock, and have it fail. - EXPECT_TRUE(view()->requestPointerLock()); - view()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, false)); - EXPECT_FALSE(view()->isPointerLocked()); + EXPECT_TRUE(widget()->requestPointerLock()); + widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, false)); + EXPECT_FALSE(widget()->isPointerLocked()); } // Test simple use of MouseLockDispatcher with a mock LockTarget. @@ -86,7 +87,7 @@ TEST_F(MouseLockDispatcherTest, BasicMockLockTarget) { // Lock. EXPECT_TRUE(dispatcher()->LockMouse(target_)); - view()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); + widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); EXPECT_TRUE(dispatcher()->IsMouseLockedTo(target_)); // Receive mouse event. @@ -94,12 +95,12 @@ TEST_F(MouseLockDispatcherTest, BasicMockLockTarget) { // Unlock. dispatcher()->UnlockMouse(target_); - view()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); + widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); // Attempt a lock, and have it fail. EXPECT_TRUE(dispatcher()->LockMouse(target_)); - view()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, false)); + widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, false)); EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); } @@ -112,7 +113,7 @@ TEST_F(MouseLockDispatcherTest, DeleteAndUnlock) { // Lock. EXPECT_TRUE(dispatcher()->LockMouse(target_)); - view()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); + widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); EXPECT_TRUE(dispatcher()->IsMouseLockedTo(target_)); // Unlock, with a deleted target. @@ -121,7 +122,7 @@ TEST_F(MouseLockDispatcherTest, DeleteAndUnlock) { delete target_; target_ = NULL; dispatcher()->WillHandleMouseEvent(blink::WebMouseEvent()); - view()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); + widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); } @@ -140,7 +141,7 @@ TEST_F(MouseLockDispatcherTest, DeleteWithPendingLockSuccess) { target_ = NULL; // Lock response. - view()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); + widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); } // Test deleting a target that is pending a lock request failure response. @@ -158,7 +159,7 @@ TEST_F(MouseLockDispatcherTest, DeleteWithPendingLockFail) { target_ = NULL; // Lock response. - view()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, false)); + widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, false)); } // Test not receiving mouse events when a target is not locked. @@ -175,7 +176,7 @@ TEST_F(MouseLockDispatcherTest, MouseEventsNotReceived) { // Lock. EXPECT_TRUE(dispatcher()->LockMouse(target_)); - view()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); + widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); EXPECT_TRUE(dispatcher()->IsMouseLockedTo(target_)); // Receive mouse event. @@ -183,7 +184,7 @@ TEST_F(MouseLockDispatcherTest, MouseEventsNotReceived) { // Unlock. dispatcher()->UnlockMouse(target_); - view()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); + widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); // (Don't) receive mouse event. @@ -208,7 +209,7 @@ TEST_F(MouseLockDispatcherTest, MultipleTargets) { EXPECT_FALSE(dispatcher()->LockMouse(alternate_target_)); // Lock completion for target. - view()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); + widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); EXPECT_TRUE(dispatcher()->IsMouseLockedTo(target_)); // Fail attempt to lock alternate. @@ -226,7 +227,7 @@ TEST_F(MouseLockDispatcherTest, MultipleTargets) { // Though the call to UnlockMouse should not unlock any target, we will // cause an unlock (as if e.g. user escaped mouse lock) and verify the // correct target is unlocked. - view()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); + widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); } diff --git a/chromium/content/renderer/mus/BUILD.gn b/chromium/content/renderer/mus/BUILD.gn index c2d3f93d317..12500af1f8b 100644 --- a/chromium/content/renderer/mus/BUILD.gn +++ b/chromium/content/renderer/mus/BUILD.gn @@ -26,12 +26,10 @@ source_set("mus") { "//content/public/common:common_sources", "//mojo/common", "//mojo/converters/blink", - "//mojo/converters/geometry", - "//mojo/converters/input_events", - "//mojo/converters/surfaces", "//services/shell/public/cpp", "//third_party/WebKit/public:blink", "//ui/events:events", "//ui/events:events_base", + "//ui/gfx/geometry/mojo", ] } diff --git a/chromium/content/renderer/mus/compositor_mus_connection.cc b/chromium/content/renderer/mus/compositor_mus_connection.cc index fe2445fc600..322fa11becb 100644 --- a/chromium/content/renderer/mus/compositor_mus_connection.cc +++ b/chromium/content/renderer/mus/compositor_mus_connection.cc @@ -9,8 +9,8 @@ #include "content/renderer/input/input_handler_manager.h" #include "content/renderer/mus/render_widget_mus_connection.h" #include "mojo/converters/blink/blink_input_events_type_converters.h" -#include "mojo/converters/input_events/input_events_type_converters.h" #include "ui/events/latency_info.h" +#include "ui/events/mojo/event.mojom.h" using mus::mojom::EventResult; @@ -36,7 +36,7 @@ CompositorMusConnection::CompositorMusConnection( DCHECK(main_task_runner_->BelongsToCurrentThread()); compositor_task_runner_->PostTask( FROM_HERE, base::Bind(&CompositorMusConnection:: - CreateWindowTreeConnectionOnCompositorThread, + CreateWindowTreeClientOnCompositorThread, this, base::Passed(std::move(request)))); } @@ -61,12 +61,10 @@ void CompositorMusConnection::AttachSurfaceOnCompositorThread( } } -void CompositorMusConnection::CreateWindowTreeConnectionOnCompositorThread( +void CompositorMusConnection::CreateWindowTreeClientOnCompositorThread( mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request) { DCHECK(compositor_task_runner_->BelongsToCurrentThread()); - mus::WindowTreeConnection::Create( - this, std::move(request), - mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED); + new mus::WindowTreeClient(this, nullptr, std::move(request)); } void CompositorMusConnection::OnConnectionLostOnMainThread() { @@ -98,8 +96,8 @@ void CompositorMusConnection::OnWindowInputEventAckOnMainThread( compositor_task_runner_->PostTask(FROM_HERE, base::Bind(ack, result)); } -void CompositorMusConnection::OnConnectionLost( - mus::WindowTreeConnection* connection) { +void CompositorMusConnection::OnWindowTreeClientDestroyed( + mus::WindowTreeClient* client) { DCHECK(compositor_task_runner_->BelongsToCurrentThread()); main_task_runner_->PostTask( FROM_HERE, diff --git a/chromium/content/renderer/mus/compositor_mus_connection.h b/chromium/content/renderer/mus/compositor_mus_connection.h index d8a75a67df5..a49b3a7bc2f 100644 --- a/chromium/content/renderer/mus/compositor_mus_connection.h +++ b/chromium/content/renderer/mus/compositor_mus_connection.h @@ -10,8 +10,8 @@ #include "base/macros.h" #include "components/mus/public/cpp/input_event_handler.h" #include "components/mus/public/cpp/window.h" -#include "components/mus/public/cpp/window_tree_connection.h" -#include "components/mus/public/cpp/window_tree_delegate.h" +#include "components/mus/public/cpp/window_tree_client.h" +#include "components/mus/public/cpp/window_tree_client_delegate.h" #include "content/common/content_export.h" #include "third_party/WebKit/public/web/WebInputEvent.h" @@ -26,7 +26,7 @@ class InputHandlerManager; // default all other methods are assumed to run on the compositor thread unless // explicited suffixed with OnMainThread. class CONTENT_EXPORT CompositorMusConnection - : NON_EXPORTED_BASE(public mus::WindowTreeDelegate), + : NON_EXPORTED_BASE(public mus::WindowTreeClientDelegate), NON_EXPORTED_BASE(public mus::InputEventHandler), public base::RefCountedThreadSafe<CompositorMusConnection> { public: @@ -52,8 +52,8 @@ class CONTENT_EXPORT CompositorMusConnection void AttachSurfaceOnCompositorThread( std::unique_ptr<mus::WindowSurfaceBinding> surface_binding); - void CreateWindowTreeConnectionOnCompositorThread( - mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request); + void CreateWindowTreeClientOnCompositorThread( + mus::mojom::WindowTreeClientRequest request); void OnConnectionLostOnMainThread(); @@ -65,8 +65,8 @@ class CONTENT_EXPORT CompositorMusConnection const base::Callback<void(mus::mojom::EventResult)>& ack, mus::mojom::EventResult result); - // WindowTreeDelegate implementation: - void OnConnectionLost(mus::WindowTreeConnection* connection) override; + // WindowTreeClientDelegate implementation: + void OnWindowTreeClientDestroyed(mus::WindowTreeClient* client) override; void OnEmbed(mus::Window* root) override; void OnEventObserved(const ui::Event& event, mus::Window* target) override; diff --git a/chromium/content/renderer/mus/compositor_mus_connection_unittest.cc b/chromium/content/renderer/mus/compositor_mus_connection_unittest.cc index 45f621bd771..441674ce4b6 100644 --- a/chromium/content/renderer/mus/compositor_mus_connection_unittest.cc +++ b/chromium/content/renderer/mus/compositor_mus_connection_unittest.cc @@ -11,9 +11,6 @@ #include "base/test/test_simple_task_runner.h" #include "base/time/time.h" #include "components/mus/public/cpp/tests/test_window.h" -#include "components/mus/public/interfaces/input_event_constants.mojom.h" -#include "components/mus/public/interfaces/input_events.mojom.h" -#include "components/mus/public/interfaces/input_key_codes.mojom.h" #include "content/common/input/did_overscroll_params.h" #include "content/common/input/input_event_ack.h" #include "content/common/input/input_event_ack_state.h" @@ -28,6 +25,9 @@ #include "mojo/public/cpp/bindings/interface_request.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/event_utils.h" +#include "ui/events/mojo/event.mojom.h" +#include "ui/events/mojo/event_constants.mojom.h" +#include "ui/events/mojo/keyboard_codes.mojom.h" using mus::mojom::EventResult; @@ -442,9 +442,10 @@ TEST_F(CompositorMusConnectionTest, InputHandlerConsumes) { // CompositorMusConnection does not consume the ack, nor calls it. TEST_F(CompositorMusConnectionTest, RendererWillNotSendAck) { mus::TestWindow test_window; - ui::PointerEvent event(ui::ET_POINTER_DOWN, - ui::EventPointerType::POINTER_TYPE_MOUSE, gfx::Point(), - gfx::Point(), ui::EF_NONE, 0, ui::EventTimeForNow()); + ui::PointerEvent event( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_NONE, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), + ui::EventTimeForNow()); scoped_refptr<TestCallback> test_callback(new TestCallback); std::unique_ptr<base::Callback<void(EventResult)>> ack_callback( @@ -466,9 +467,10 @@ TEST_F(CompositorMusConnectionTest, TouchEventConsumed) { input_handler->set_state(InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED); mus::TestWindow test_window; - ui::PointerEvent event(ui::ET_POINTER_DOWN, - ui::EventPointerType::POINTER_TYPE_TOUCH, gfx::Point(), - gfx::Point(), ui::EF_NONE, 0, ui::EventTimeForNow()); + ui::PointerEvent event( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_NONE, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + ui::EventTimeForNow()); scoped_refptr<TestCallback> test_callback(new TestCallback); std::unique_ptr<base::Callback<void(EventResult)>> ack_callback( diff --git a/chromium/content/renderer/mus/render_widget_mus_connection.cc b/chromium/content/renderer/mus/render_widget_mus_connection.cc index 6916b324111..b5890e5ba28 100644 --- a/chromium/content/renderer/mus/render_widget_mus_connection.cc +++ b/chromium/content/renderer/mus/render_widget_mus_connection.cc @@ -11,15 +11,12 @@ #include "components/mus/public/cpp/context_provider.h" #include "components/mus/public/cpp/output_surface.h" #include "components/mus/public/interfaces/command_buffer.mojom.h" -#include "components/mus/public/interfaces/compositor_frame.mojom.h" -#include "components/mus/public/interfaces/gpu.mojom.h" +#include "components/mus/public/interfaces/surface.mojom.h" #include "components/mus/public/interfaces/window_tree.mojom.h" #include "content/public/common/mojo_shell_connection.h" #include "content/renderer/mus/compositor_mus_connection.h" #include "content/renderer/render_thread_impl.h" #include "content/renderer/render_view_impl.h" -#include "mojo/converters/geometry/geometry_type_converters.h" -#include "mojo/converters/surfaces/surfaces_utils.h" #include "services/shell/public/cpp/connector.h" namespace content { @@ -49,13 +46,9 @@ std::unique_ptr<cc::OutputSurface> RenderWidgetMusConnection::CreateOutputSurface() { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!window_surface_binding_); - mus::mojom::GpuPtr gpu_service; - MojoShellConnection::Get()->GetConnector()->ConnectToInterface("mojo:mus", - &gpu_service); - mus::mojom::CommandBufferPtr cb; - gpu_service->CreateOffscreenGLES2Context(GetProxy(&cb)); - scoped_refptr<cc::ContextProvider> context_provider( - new mus::ContextProvider(cb.PassInterface().PassHandle())); + scoped_refptr<cc::ContextProvider> context_provider(new mus::ContextProvider( + MojoShellConnection::GetForProcess()->GetConnector())); + std::unique_ptr<cc::OutputSurface> surface(new mus::OutputSurface( context_provider, mus::WindowSurface::Create(&window_surface_binding_))); if (compositor_mus_connection_) { @@ -100,13 +93,6 @@ bool RenderWidgetMusConnection::HasTouchEventHandlersAt( return true; } -void RenderWidgetMusConnection::ObserveWheelEventAndResult( - const blink::WebMouseWheelEvent& wheel_event, - const gfx::Vector2dF& wheel_unused_delta, - bool event_processed) { - NOTIMPLEMENTED(); -} - void RenderWidgetMusConnection::ObserveGestureEventAndResult( const blink::WebGestureEvent& gesture_event, const gfx::Vector2dF& wheel_unused_delta, diff --git a/chromium/content/renderer/mus/render_widget_mus_connection.h b/chromium/content/renderer/mus/render_widget_mus_connection.h index 4e61189fb06..bb0abe34a34 100644 --- a/chromium/content/renderer/mus/render_widget_mus_connection.h +++ b/chromium/content/renderer/mus/render_widget_mus_connection.h @@ -43,9 +43,6 @@ class CONTENT_EXPORT RenderWidgetMusConnection // RenderWidgetInputHandlerDelegate implementation: void FocusChangeComplete() override; bool HasTouchEventHandlersAt(const gfx::Point& point) const override; - void ObserveWheelEventAndResult(const blink::WebMouseWheelEvent& wheel_event, - const gfx::Vector2dF& wheel_unused_delta, - bool event_processed) override; void ObserveGestureEventAndResult(const blink::WebGestureEvent& gesture_event, const gfx::Vector2dF& gesture_unused_delta, bool event_processed) override; diff --git a/chromium/content/renderer/mus/render_widget_window_tree_client_factory.cc b/chromium/content/renderer/mus/render_widget_window_tree_client_factory.cc index 83ca42443de..dd862b0e8f0 100644 --- a/chromium/content/renderer/mus/render_widget_window_tree_client_factory.cc +++ b/chromium/content/renderer/mus/render_widget_window_tree_client_factory.cc @@ -16,6 +16,7 @@ #include "mojo/public/cpp/bindings/binding_set.h" #include "services/shell/public/cpp/connection.h" #include "services/shell/public/cpp/interface_factory.h" +#include "services/shell/public/cpp/shell_client.h" #include "url/gurl.h" namespace content { @@ -23,21 +24,21 @@ namespace content { namespace { // This object's lifetime is managed by MojoShellConnection because it's a -// MojoShellConnection::Listener. +// registered with it. class RenderWidgetWindowTreeClientFactoryImpl - : public MojoShellConnection::Listener, + : public shell::ShellClient, public shell::InterfaceFactory< mojom::RenderWidgetWindowTreeClientFactory>, public mojom::RenderWidgetWindowTreeClientFactory { public: RenderWidgetWindowTreeClientFactoryImpl() { - DCHECK(MojoShellConnection::Get()); + DCHECK(MojoShellConnection::GetForProcess()); } ~RenderWidgetWindowTreeClientFactoryImpl() override {} private: - // MojoShellConnection::Listener implementation: + // shell::ShellClient implementation: bool AcceptConnection(shell::Connection* connection) override { connection->AddInterface<mojom::RenderWidgetWindowTreeClientFactory>(this); return true; @@ -67,8 +68,8 @@ class RenderWidgetWindowTreeClientFactoryImpl } // namespace void CreateRenderWidgetWindowTreeClientFactory() { - MojoShellConnection::Get()->AddListener( - base::WrapUnique(new RenderWidgetWindowTreeClientFactoryImpl())); + MojoShellConnection::GetForProcess()->AddEmbeddedShellClient( + base::WrapUnique(new RenderWidgetWindowTreeClientFactoryImpl)); } } // namespace content diff --git a/chromium/content/renderer/notification_permission_dispatcher.cc b/chromium/content/renderer/notification_permission_dispatcher.cc index f038b5c2dfb..0e7e402a791 100644 --- a/chromium/content/renderer/notification_permission_dispatcher.cc +++ b/chromium/content/renderer/notification_permission_dispatcher.cc @@ -7,12 +7,13 @@ #include <utility> #include "base/bind.h" -#include "content/public/common/service_registry.h" #include "content/public/renderer/render_frame.h" +#include "services/shell/public/cpp/interface_provider.h" #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom-blink.h" #include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h" +#include "third_party/WebKit/public/web/WebUserGestureIndicator.h" #include "third_party/WebKit/public/web/modules/notifications/WebNotificationPermissionCallback.h" using blink::WebNotificationPermissionCallback; @@ -29,8 +30,7 @@ void NotificationPermissionDispatcher::RequestPermission( const blink::WebSecurityOrigin& origin, WebNotificationPermissionCallback* callback) { if (!permission_service_.get()) { - render_frame()->GetServiceRegistry()->ConnectToRemoteService( - mojo::GetProxy(&permission_service_)); + render_frame()->GetRemoteInterfaces()->GetInterface(&permission_service_); } std::unique_ptr<WebNotificationPermissionCallback> owned_callback(callback); @@ -39,6 +39,7 @@ void NotificationPermissionDispatcher::RequestPermission( // callbacks, will be deleted before the "this" instance is deleted. permission_service_->RequestPermission( blink::mojom::PermissionName::NOTIFICATIONS, origin.toString().utf8(), + blink::WebUserGestureIndicator::isProcessingUserGesture(), base::Bind(&NotificationPermissionDispatcher::OnPermissionRequestComplete, base::Unretained(this), base::Passed(std::move(owned_callback)))); @@ -55,4 +56,8 @@ void NotificationPermissionDispatcher::OnPermissionRequestComplete( callback->permissionRequestComplete(blink_status); } +void NotificationPermissionDispatcher::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/notification_permission_dispatcher.h b/chromium/content/renderer/notification_permission_dispatcher.h index 77fbb63c2a0..8b1eb58adfa 100644 --- a/chromium/content/renderer/notification_permission_dispatcher.h +++ b/chromium/content/renderer/notification_permission_dispatcher.h @@ -33,6 +33,9 @@ class NotificationPermissionDispatcher : public RenderFrameObserver { blink::WebNotificationPermissionCallback* callback); private: + // RenderFrameObserver implementation. + void OnDestruct() override; + void OnPermissionRequestComplete( std::unique_ptr<blink::WebNotificationPermissionCallback> callback, blink::mojom::PermissionStatus status); diff --git a/chromium/content/renderer/p2p/filtering_network_manager.cc b/chromium/content/renderer/p2p/filtering_network_manager.cc index dba704a571a..4112d56f513 100644 --- a/chromium/content/renderer/p2p/filtering_network_manager.cc +++ b/chromium/content/renderer/p2p/filtering_network_manager.cc @@ -27,29 +27,13 @@ FilteringNetworkManager::FilteringNetworkManager( // If the feature is not enabled, just return ALLOWED as it's requested. if (!media_permission_) { - initialized_ = true; + started_permission_check_ = true; set_enumeration_permission(ENUMERATION_ALLOWED); VLOG(3) << "media_permission is not passed, granting permission"; return; } } -void FilteringNetworkManager::Initialize() { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(!initialized_); - - initialized_ = true; - pending_permission_checks_ = 2; - - // Request for media permission asynchronously. - media_permission_->HasPermission( - media::MediaPermission::AUDIO_CAPTURE, requesting_origin_, - base::Bind(&FilteringNetworkManager::OnPermissionStatus, GetWeakPtr())); - media_permission_->HasPermission( - media::MediaPermission::VIDEO_CAPTURE, requesting_origin_, - base::Bind(&FilteringNetworkManager::OnPermissionStatus, GetWeakPtr())); -} - FilteringNetworkManager::~FilteringNetworkManager() { DCHECK(thread_checker_.CalledOnValidThread()); // This helps to catch the case if permission never comes back. @@ -61,9 +45,15 @@ base::WeakPtr<FilteringNetworkManager> FilteringNetworkManager::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } +void FilteringNetworkManager::Initialize() { + rtc::NetworkManagerBase::Initialize(); + if (media_permission_) + CheckPermission(); +} + void FilteringNetworkManager::StartUpdating() { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(initialized_); + DCHECK(started_permission_check_); if (start_updating_time_.is_null()) { start_updating_time_ = base::TimeTicks::Now(); @@ -101,6 +91,22 @@ bool FilteringNetworkManager::GetDefaultLocalAddress( return network_manager_->GetDefaultLocalAddress(family, ipaddress); } +void FilteringNetworkManager::CheckPermission() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!started_permission_check_); + + started_permission_check_ = true; + pending_permission_checks_ = 2; + + // Request for media permission asynchronously. + media_permission_->HasPermission( + media::MediaPermission::AUDIO_CAPTURE, requesting_origin_, + base::Bind(&FilteringNetworkManager::OnPermissionStatus, GetWeakPtr())); + media_permission_->HasPermission( + media::MediaPermission::VIDEO_CAPTURE, requesting_origin_, + base::Bind(&FilteringNetworkManager::OnPermissionStatus, GetWeakPtr())); +} + void FilteringNetworkManager::OnPermissionStatus(bool granted) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_GT(pending_permission_checks_, 0); diff --git a/chromium/content/renderer/p2p/filtering_network_manager.h b/chromium/content/renderer/p2p/filtering_network_manager.h index 7b0fca26231..01b0ccd2442 100644 --- a/chromium/content/renderer/p2p/filtering_network_manager.h +++ b/chromium/content/renderer/p2p/filtering_network_manager.h @@ -46,11 +46,8 @@ class FilteringNetworkManager : public rtc::NetworkManagerBase, CONTENT_EXPORT ~FilteringNetworkManager() override; - // Check mic/camera permission. - // This is called by PeerConnectionDependencyFactory. - CONTENT_EXPORT void Initialize(); - // rtc::NetworkManager: + void Initialize() override; void StartUpdating() override; void StopUpdating() override; void GetNetworks(NetworkList* networks) const override; @@ -58,6 +55,9 @@ class FilteringNetworkManager : public rtc::NetworkManagerBase, rtc::IPAddress* ipaddress) const override; private: + // Check mic/camera permission. + void CheckPermission(); + // Receive callback from MediaPermission when the permission status is // available. void OnPermissionStatus(bool granted); @@ -110,8 +110,8 @@ class FilteringNetworkManager : public rtc::NetworkManagerBase, // StartUpdating. int start_count_ = 0; - // Track whether Initialize has been called before StartUpdating. - bool initialized_ = false; + // Track whether CheckPermission has been called before StartUpdating. + bool started_permission_check_ = false; // Track how long it takes for client to receive SignalNetworksChanged. This // helps to identify if the signal is delayed by permission check and increase diff --git a/chromium/content/renderer/p2p/port_allocator.cc b/chromium/content/renderer/p2p/port_allocator.cc index c9bc9fadf1d..00ee3beddab 100644 --- a/chromium/content/renderer/p2p/port_allocator.cc +++ b/chromium/content/renderer/p2p/port_allocator.cc @@ -21,14 +21,15 @@ P2PPortAllocator::P2PPortAllocator( std::unique_ptr<rtc::NetworkManager> network_manager, rtc::PacketSocketFactory* socket_factory, const Config& config, - const GURL& origin, - const scoped_refptr<base::SingleThreadTaskRunner> task_runner) + const GURL& origin) : cricket::BasicPortAllocator(network_manager.get(), socket_factory), network_manager_(std::move(network_manager)), socket_dispatcher_(socket_dispatcher), config_(config), - origin_(origin), - network_manager_task_runner_(task_runner) { + origin_(origin) { + DCHECK(socket_dispatcher); + DCHECK(network_manager_); + DCHECK(socket_factory); uint32_t flags = 0; if (!config_.enable_multiple_routes) { flags |= cricket::PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION; @@ -51,13 +52,11 @@ P2PPortAllocator::P2PPortAllocator( } } -// TODO(guoweis): P2PPortAllocator is also deleted in the wrong thread -// here. It's created in signaling thread, and held by webrtc::PeerConnection, -// only used on worker thread. The destructor is invoked on signaling thread -// again. crbug.com/535761. DeleteSoon can be removed once the bug is fixed. -P2PPortAllocator::~P2PPortAllocator() { - network_manager_task_runner_->DeleteSoon(FROM_HERE, - network_manager_.release()); +P2PPortAllocator::~P2PPortAllocator() {} + +void P2PPortAllocator::Initialize() { + BasicPortAllocator::Initialize(); + network_manager_->Initialize(); } } // namespace content diff --git a/chromium/content/renderer/p2p/port_allocator.h b/chromium/content/renderer/p2p/port_allocator.h index 945b5f87e6e..f686b39643e 100644 --- a/chromium/content/renderer/p2p/port_allocator.h +++ b/chromium/content/renderer/p2p/port_allocator.h @@ -38,26 +38,22 @@ class P2PPortAllocator : public cricket::BasicPortAllocator { bool enable_default_local_candidate = true; }; - P2PPortAllocator( - const scoped_refptr<P2PSocketDispatcher>& socket_dispatcher, - std::unique_ptr<rtc::NetworkManager> network_manager, - rtc::PacketSocketFactory* socket_factory, - const Config& config, - const GURL& origin, - const scoped_refptr<base::SingleThreadTaskRunner> task_runner); + P2PPortAllocator(const scoped_refptr<P2PSocketDispatcher>& socket_dispatcher, + std::unique_ptr<rtc::NetworkManager> network_manager, + rtc::PacketSocketFactory* socket_factory, + const Config& config, + const GURL& origin); ~P2PPortAllocator() override; + // Will also initialize the network manager passed into the constructor. + void Initialize() override; + private: std::unique_ptr<rtc::NetworkManager> network_manager_; scoped_refptr<P2PSocketDispatcher> socket_dispatcher_; Config config_; GURL origin_; - // This is the thread |network_manager_| is associated with and must be used - // to delete |network_manager_|. - const scoped_refptr<base::SingleThreadTaskRunner> - network_manager_task_runner_; - DISALLOW_COPY_AND_ASSIGN(P2PPortAllocator); }; diff --git a/chromium/content/renderer/pepper/message_channel.cc b/chromium/content/renderer/pepper/message_channel.cc index f14f0041969..4566631717e 100644 --- a/chromium/content/renderer/pepper/message_channel.cc +++ b/chromium/content/renderer/pepper/message_channel.cc @@ -12,7 +12,6 @@ #include "base/logging.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" -#include "content/renderer/pepper/host_array_buffer_var.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "content/renderer/pepper/pepper_try_catch.h" #include "content/renderer/pepper/plugin_module.h" @@ -27,20 +26,12 @@ #include "ppapi/shared_impl/var.h" #include "ppapi/shared_impl/var_tracker.h" #include "third_party/WebKit/public/web/WebDOMMessageEvent.h" -#include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebElement.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebNode.h" #include "third_party/WebKit/public/web/WebPluginContainer.h" -#include "third_party/WebKit/public/web/WebSerializedScriptValue.h" #include "v8/include/v8.h" -using ppapi::ArrayBufferVar; using ppapi::PpapiGlobals; using ppapi::ScopedPPVar; using ppapi::StringVar; -using blink::WebElement; -using blink::WebDOMEvent; using blink::WebDOMMessageEvent; using blink::WebPluginContainer; using blink::WebSerializedScriptValue; diff --git a/chromium/content/renderer/pepper/mock_renderer_ppapi_host.cc b/chromium/content/renderer/pepper/mock_renderer_ppapi_host.cc index 0a4bc6e3a53..6f39f0fb7d9 100644 --- a/chromium/content/renderer/pepper/mock_renderer_ppapi_host.cc +++ b/chromium/content/renderer/pepper/mock_renderer_ppapi_host.cc @@ -4,6 +4,7 @@ #include "content/renderer/pepper/mock_renderer_ppapi_host.h" +#include "content/public/renderer/render_view.h" #include "content/renderer/pepper/fake_pepper_plugin_instance.h" #include "ui/gfx/geometry/point.h" @@ -16,7 +17,10 @@ MockRendererPpapiHost::MockRendererPpapiHost(RenderView* render_view, render_view_(render_view), pp_instance_(instance), has_user_gesture_(false), - plugin_instance_(new FakePepperPluginInstance) {} + plugin_instance_(new FakePepperPluginInstance) { + if (render_view) + render_frame_ = render_view->GetMainRenderFrame(); +} MockRendererPpapiHost::~MockRendererPpapiHost() {} @@ -35,6 +39,8 @@ PepperPluginInstance* MockRendererPpapiHost::GetPluginInstance( RenderFrame* MockRendererPpapiHost::GetRenderFrameForInstance( PP_Instance instance) const { + if (instance == pp_instance_) + return render_frame_; return NULL; } diff --git a/chromium/content/renderer/pepper/mock_renderer_ppapi_host.h b/chromium/content/renderer/pepper/mock_renderer_ppapi_host.h index 84e6ff4d253..30dd766ed26 100644 --- a/chromium/content/renderer/pepper/mock_renderer_ppapi_host.h +++ b/chromium/content/renderer/pepper/mock_renderer_ppapi_host.h @@ -65,6 +65,7 @@ class MockRendererPpapiHost : public RendererPpapiHost { ppapi::host::PpapiHost ppapi_host_; RenderView* render_view_; + RenderFrame* render_frame_; PP_Instance pp_instance_; bool has_user_gesture_; diff --git a/chromium/content/renderer/pepper/pepper_audio_controller.cc b/chromium/content/renderer/pepper/pepper_audio_controller.cc new file mode 100644 index 00000000000..88d80f11bd0 --- /dev/null +++ b/chromium/content/renderer/pepper/pepper_audio_controller.cc @@ -0,0 +1,77 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/pepper/pepper_audio_controller.h" + +#include "content/renderer/pepper/pepper_plugin_instance_impl.h" +#include "content/renderer/pepper/ppb_audio_impl.h" +#include "content/renderer/render_frame_impl.h" + +namespace content { + +PepperAudioController::PepperAudioController( + PepperPluginInstanceImpl* instance) + : instance_(instance) { + DCHECK(instance_); +} + +PepperAudioController::~PepperAudioController() { + if (instance_) + OnPepperInstanceDeleted(); +} + +void PepperAudioController::AddInstance(PPB_Audio_Impl* audio) { + if (!instance_) + return; + if (ppb_audios_.count(audio)) + return; + + if (ppb_audios_.empty()) { + RenderFrameImpl* render_frame = instance_->render_frame(); + if (render_frame) + render_frame->PepperStartsPlayback(instance_); + } + + ppb_audios_.insert(audio); +} + +void PepperAudioController::RemoveInstance(PPB_Audio_Impl* audio) { + if (!instance_) + return; + if (!ppb_audios_.count(audio)) + return; + + ppb_audios_.erase(audio); + + if (ppb_audios_.empty()) + NotifyPlaybackStopsOnEmpty(); +} + +void PepperAudioController::SetVolume(double volume) { + if (!instance_) + return; + + for (auto* ppb_audio : ppb_audios_) + ppb_audio->SetVolume(volume); +} + +void PepperAudioController::OnPepperInstanceDeleted() { + DCHECK(instance_); + + if (!ppb_audios_.empty()) + NotifyPlaybackStopsOnEmpty(); + + ppb_audios_.clear(); + instance_ = nullptr; +} + +void PepperAudioController::NotifyPlaybackStopsOnEmpty() { + DCHECK(instance_); + + RenderFrameImpl* render_frame = instance_->render_frame(); + if (render_frame) + render_frame->PepperStopsPlayback(instance_); +} + +} // namespace content diff --git a/chromium/content/renderer/pepper/pepper_audio_controller.h b/chromium/content/renderer/pepper/pepper_audio_controller.h new file mode 100644 index 00000000000..29241ab8e63 --- /dev/null +++ b/chromium/content/renderer/pepper/pepper_audio_controller.h @@ -0,0 +1,57 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_PEPPER_PEPPER_AUDIO_CONTROLLER_H_ +#define CONTENT_RENDERER_PEPPER_PEPPER_AUDIO_CONTROLLER_H_ + +#include <set> + +#include "base/macros.h" + +namespace content { + +class PepperPluginInstanceImpl; +class PPB_Audio_Impl; + +/** + * This class controls all the active audio instances of a Pepper instance. + * This class can only be a non-shareable member of PepperPluginInstanceImpl. + */ +class PepperAudioController { + public: + explicit PepperAudioController(PepperPluginInstanceImpl* instance); + virtual ~PepperAudioController(); + + // Adds an audio instance to the controller. + void AddInstance(PPB_Audio_Impl* audio); + + // Removes an audio instance from the controller. + void RemoveInstance(PPB_Audio_Impl* audio); + + // Sets the volume of all audio instances. + void SetVolume(double volume); + + // The pepper instance has been deleted. This method can only be called + // once. The controller will be invalidated after this call, and then all + // other methods will be no-op. + void OnPepperInstanceDeleted(); + + private: + // Notifies the RenderFrame that the playback has stopped. This method should + // only be called when |ppb_audios_| turns from non-empty to empty. + void NotifyPlaybackStopsOnEmpty(); + + // All active audio instances. + std::set<PPB_Audio_Impl*> ppb_audios_; + + // The Pepper instance which this controller is for. Will be null after + // OnPepperInstanceDeleted() is called. + PepperPluginInstanceImpl* instance_; + + DISALLOW_COPY_AND_ASSIGN(PepperAudioController); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_PEPPER_PEPPER_AUDIO_CONTROLLER_H_ diff --git a/chromium/content/renderer/pepper/pepper_browser_connection.cc b/chromium/content/renderer/pepper/pepper_browser_connection.cc index 43affea1374..19ba1cc7a35 100644 --- a/chromium/content/renderer/pepper/pepper_browser_connection.cc +++ b/chromium/content/renderer/pepper/pepper_browser_connection.cc @@ -96,4 +96,8 @@ int32_t PepperBrowserConnection::GetNextSequence() { return ret; } +void PepperBrowserConnection::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/pepper/pepper_browser_connection.h b/chromium/content/renderer/pepper/pepper_browser_connection.h index 6e5a3d692cb..07d1501c398 100644 --- a/chromium/content/renderer/pepper/pepper_browser_connection.h +++ b/chromium/content/renderer/pepper/pepper_browser_connection.h @@ -60,6 +60,9 @@ class PepperBrowserConnection void DidDeleteInProcessInstance(PP_Instance instance); private: + // RenderFrameObserver implementation. + void OnDestruct() override; + // Message handlers. void OnMsgCreateResourceHostsFromHostReply( int32_t sequence_number, diff --git a/chromium/content/renderer/pepper/pepper_compositor_host.cc b/chromium/content/renderer/pepper/pepper_compositor_host.cc index f16ef70ea4a..c2768361c0e 100644 --- a/chromium/content/renderer/pepper/pepper_compositor_host.cc +++ b/chromium/content/renderer/pepper/pepper_compositor_host.cc @@ -65,7 +65,7 @@ int32_t VerifyCommittedLayer(const ppapi::CompositorLayerData* old_layer, if (new_layer->texture) { if (old_layer) { // Make sure the old layer is a texture layer too. - if (!new_layer->texture) + if (!old_layer->texture) return PP_ERROR_BADARGUMENT; // The mailbox should be same, if the resource_id is not changed. if (new_layer->common.resource_id == old_layer->common.resource_id) { @@ -87,7 +87,7 @@ int32_t VerifyCommittedLayer(const ppapi::CompositorLayerData* old_layer, if (new_layer->image) { if (old_layer) { // Make sure the old layer is an image layer too. - if (!new_layer->image) + if (!old_layer->image) return PP_ERROR_BADARGUMENT; // The image data resource should be same, if the resource_id is not // changed. diff --git a/chromium/content/renderer/pepper/pepper_file_chooser_host.cc b/chromium/content/renderer/pepper/pepper_file_chooser_host.cc index b70ab83c3d1..f2f8be3b2e5 100644 --- a/chromium/content/renderer/pepper/pepper_file_chooser_host.cc +++ b/chromium/content/renderer/pepper/pepper_file_chooser_host.cc @@ -154,9 +154,10 @@ int32_t PepperFileChooserHost::OnShow( params.requestor = renderer_ppapi_host_->GetDocumentURL(pp_instance()); handler_ = new CompletionHandler(AsWeakPtr()); - RenderViewImpl* render_view = static_cast<RenderViewImpl*>( - renderer_ppapi_host_->GetRenderViewForInstance(pp_instance())); - if (!render_view || !render_view->runFileChooser(params, handler_)) { + RenderFrameImpl* render_frame = static_cast<RenderFrameImpl*>( + renderer_ppapi_host_->GetRenderFrameForInstance(pp_instance())); + + if (!render_frame || !render_frame->runFileChooser(params, handler_)) { delete handler_; handler_ = NULL; return PP_ERROR_NOACCESS; diff --git a/chromium/content/renderer/pepper/pepper_file_chooser_host_unittest.cc b/chromium/content/renderer/pepper/pepper_file_chooser_host_unittest.cc index f74c0a181b3..d610636955d 100644 --- a/chromium/content/renderer/pepper/pepper_file_chooser_host_unittest.cc +++ b/chromium/content/renderer/pepper/pepper_file_chooser_host_unittest.cc @@ -3,10 +3,12 @@ // found in the LICENSE file. #include <stdint.h> +#include <tuple> #include "base/files/file_path.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "content/common/frame_messages.h" #include "content/common/view_messages.h" #include "content/public/common/file_chooser_file_info.h" #include "content/public/common/file_chooser_params.h" @@ -91,11 +93,11 @@ TEST_F(PepperFileChooserHostTest, Show) { // The render view should have sent a chooser request to the browser // (caught by the render thread's test message sink). const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching( - ViewHostMsg_RunFileChooser::ID); + FrameHostMsg_RunFileChooser::ID); ASSERT_TRUE(msg); - ViewHostMsg_RunFileChooser::Schema::Param call_msg_param; - ASSERT_TRUE(ViewHostMsg_RunFileChooser::Read(msg, &call_msg_param)); - const FileChooserParams& chooser_params = base::get<0>(call_msg_param); + FrameHostMsg_RunFileChooser::Schema::Param call_msg_param; + ASSERT_TRUE(FrameHostMsg_RunFileChooser::Read(msg, &call_msg_param)); + const FileChooserParams& chooser_params = std::get<0>(call_msg_param); // Basic validation of request. EXPECT_EQ(FileChooserParams::Open, chooser_params.mode); @@ -109,10 +111,11 @@ TEST_F(PepperFileChooserHostTest, Show) { selected_info.file_path = base::FilePath(FILE_PATH_LITERAL("myp\\ath/foo")); std::vector<content::FileChooserFileInfo> selected_info_vector; selected_info_vector.push_back(selected_info); - RenderViewImpl* view_impl = static_cast<RenderViewImpl*>(view_); - ViewMsg_RunFileChooserResponse response(view_impl->GetRoutingID(), - selected_info_vector); - EXPECT_TRUE(view_impl->OnMessageReceived(response)); + RenderFrameImpl* frame_impl = + static_cast<RenderFrameImpl*>(view_->GetMainRenderFrame()); + FrameMsg_RunFileChooserResponse response(frame_impl->GetRoutingID(), + selected_info_vector); + EXPECT_TRUE(frame_impl->OnMessageReceived(response)); // This should have sent the Pepper reply to our test sink. ppapi::proxy::ResourceMessageReplyParams reply_params; @@ -127,7 +130,7 @@ TEST_F(PepperFileChooserHostTest, Show) { ASSERT_TRUE( PpapiPluginMsg_FileChooser_ShowReply::Read(&reply_msg, &reply_msg_param)); const std::vector<ppapi::FileRefCreateInfo>& chooser_results = - base::get<0>(reply_msg_param); + std::get<0>(reply_msg_param); ASSERT_EQ(1u, chooser_results.size()); EXPECT_EQ(FilePathToUTF8(selected_info.display_name), chooser_results[0].display_name); diff --git a/chromium/content/renderer/pepper/pepper_graphics_2d_host.cc b/chromium/content/renderer/pepper/pepper_graphics_2d_host.cc index 478e90536d7..41c82fca255 100644 --- a/chromium/content/renderer/pepper/pepper_graphics_2d_host.cc +++ b/chromium/content/renderer/pepper/pepper_graphics_2d_host.cc @@ -383,8 +383,6 @@ void PepperGraphics2DHost::ViewInitiatedPaint() { } } -void PepperGraphics2DHost::SetScale(float scale) { scale_ = scale; } - float PepperGraphics2DHost::GetScale() const { return scale_; } bool PepperGraphics2DHost::IsAlwaysOpaque() const { return is_always_opaque_; } diff --git a/chromium/content/renderer/pepper/pepper_graphics_2d_host.h b/chromium/content/renderer/pepper/pepper_graphics_2d_host.h index 6fb01c29e8f..e50b095d8c1 100644 --- a/chromium/content/renderer/pepper/pepper_graphics_2d_host.h +++ b/chromium/content/renderer/pepper/pepper_graphics_2d_host.h @@ -85,7 +85,6 @@ class CONTENT_EXPORT PepperGraphics2DHost // These messages are used to send Flush callbacks to the plugin. void ViewInitiatedPaint(); - void SetScale(float scale); float GetScale() const; void SetLayerTransform(float scale, const PP_Point& transform); bool IsAlwaysOpaque() const; diff --git a/chromium/content/renderer/pepper/pepper_media_device_manager.cc b/chromium/content/renderer/pepper/pepper_media_device_manager.cc index 1b21f75c920..42abb0802af 100644 --- a/chromium/content/renderer/pepper/pepper_media_device_manager.cc +++ b/chromium/content/renderer/pepper/pepper_media_device_manager.cc @@ -61,12 +61,9 @@ int PepperMediaDeviceManager::EnumerateDevices( PepperMediaDeviceManager::FromPepperDeviceType(type), url::Origin(document_url.GetOrigin())); #else - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&PepperMediaDeviceManager::OnDevicesEnumerated, - AsWeakPtr(), - request_id, - StreamDeviceInfoArray())); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&PepperMediaDeviceManager::OnDevicesEnumerated, + AsWeakPtr(), request_id, StreamDeviceInfoArray())); #endif return request_id; @@ -109,11 +106,9 @@ int PepperMediaDeviceManager::OpenDevice(PP_DeviceType_Dev type, PepperMediaDeviceManager::FromPepperDeviceType(type), url::Origin(document_url.GetOrigin())); #else - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&PepperMediaDeviceManager::OnDeviceOpenFailed, - AsWeakPtr(), - request_id)); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&PepperMediaDeviceManager::OnDeviceOpenFailed, + AsWeakPtr(), request_id)); #endif return request_id; @@ -255,4 +250,8 @@ MediaStreamDispatcher* PepperMediaDeviceManager::GetMediaStreamDispatcher() return dispatcher; } +void PepperMediaDeviceManager::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/pepper/pepper_media_device_manager.h b/chromium/content/renderer/pepper/pepper_media_device_manager.h index 90d6dc09dcf..e0343bbd197 100644 --- a/chromium/content/renderer/pepper/pepper_media_device_manager.h +++ b/chromium/content/renderer/pepper/pepper_media_device_manager.h @@ -81,6 +81,9 @@ class PepperMediaDeviceManager private: explicit PepperMediaDeviceManager(RenderFrame* render_frame); + // RenderFrameObserver implementation. + void OnDestruct() override; + // Called by StopEnumerateDevices() after returing to the event loop, to avoid // a reentrancy problem. void StopEnumerateDevicesDelayed(int request_id); diff --git a/chromium/content/renderer/pepper/pepper_platform_audio_output.cc b/chromium/content/renderer/pepper/pepper_platform_audio_output.cc index 1e9c74cc7e5..a8e7c433668 100644 --- a/chromium/content/renderer/pepper/pepper_platform_audio_output.cc +++ b/chromium/content/renderer/pepper/pepper_platform_audio_output.cc @@ -60,6 +60,17 @@ bool PepperPlatformAudioOutput::StopPlayback() { return false; } +bool PepperPlatformAudioOutput::SetVolume(double volume) { + if (ipc_) { + io_task_runner_->PostTask( + FROM_HERE, + base::Bind(&PepperPlatformAudioOutput::SetVolumeOnIOThread, + this, volume)); + return true; + } + return false; +} + void PepperPlatformAudioOutput::ShutDown() { // Called on the main thread to stop all audio callbacks. We must only change // the client on the main thread, and the delegates from the I/O thread. @@ -156,6 +167,12 @@ void PepperPlatformAudioOutput::StartPlaybackOnIOThread() { ipc_->PlayStream(); } +void PepperPlatformAudioOutput::SetVolumeOnIOThread(double volume) { + DCHECK(io_task_runner_->BelongsToCurrentThread()); + if (ipc_) + ipc_->SetVolume(volume); +} + void PepperPlatformAudioOutput::StopPlaybackOnIOThread() { DCHECK(io_task_runner_->BelongsToCurrentThread()); if (ipc_) diff --git a/chromium/content/renderer/pepper/pepper_platform_audio_output.h b/chromium/content/renderer/pepper/pepper_platform_audio_output.h index ea8771d6f90..439dc2b7dc2 100644 --- a/chromium/content/renderer/pepper/pepper_platform_audio_output.h +++ b/chromium/content/renderer/pepper/pepper_platform_audio_output.h @@ -43,6 +43,10 @@ class PepperPlatformAudioOutput // is created or after the stream is closed. bool StopPlayback(); + // Sets the volume. Returns false on error or if called before the stream + // is created or after the stream is closed. + bool SetVolume(double volume); + // Closes the stream. Make sure to call this before the object is // destructed. void ShutDown(); @@ -74,6 +78,7 @@ class PepperPlatformAudioOutput void InitializeOnIOThread(const media::AudioParameters& params); void StartPlaybackOnIOThread(); void StopPlaybackOnIOThread(); + void SetVolumeOnIOThread(double volume); void ShutDownOnIOThread(); // The client to notify when the stream is created. THIS MUST ONLY BE diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc index 8810686bb43..2dfd47b0822 100644 --- a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc @@ -35,6 +35,7 @@ #include "content/renderer/pepper/host_dispatcher_wrapper.h" #include "content/renderer/pepper/host_globals.h" #include "content/renderer/pepper/message_channel.h" +#include "content/renderer/pepper/pepper_audio_controller.h" #include "content/renderer/pepper/pepper_browser_connection.h" #include "content/renderer/pepper/pepper_compositor_host.h" #include "content/renderer/pepper/pepper_file_ref_renderer_host.h" @@ -529,6 +530,7 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl( isolate_(v8::Isolate::GetCurrent()), is_deleted_(false), initialized_(false), + audio_controller_(new PepperAudioController(this)), view_change_weak_ptr_factory_(this), weak_factory_(this) { pp_instance_ = HostGlobals::Get()->AddInstance(this); @@ -585,6 +587,8 @@ PepperPluginInstanceImpl::~PepperPluginInstanceImpl() { if (TrackedCallback::IsPending(lock_mouse_callback_)) lock_mouse_callback_->Abort(); + audio_controller_->OnPepperInstanceDeleted(); + if (render_frame_) render_frame_->PepperInstanceDeleted(this); @@ -684,7 +688,7 @@ void PepperPluginInstanceImpl::Delete() { // Force-unbind any Graphics. In the case of Graphics2D, if the plugin // leaks the graphics 2D, it may actually get cleaned up after our - // destruction, so we need its pointers to be up-to-date. + // destruction, so we need its pointers to be up to date. BindGraphics(pp_instance(), 0); container_ = NULL; } @@ -756,22 +760,63 @@ void PepperPluginInstanceImpl::ScrollRect(int dx, } } -void PepperPluginInstanceImpl::CommitBackingTexture() { +void PepperPluginInstanceImpl::CommitTextureMailbox( + const cc::TextureMailbox& texture_mailbox) { + if (committed_texture_.IsValid() && !IsTextureInUse(committed_texture_)) { + committed_texture_graphics_3d_->ReturnFrontBuffer( + committed_texture_.mailbox(), committed_texture_consumed_sync_token_, + false); + } + + committed_texture_ = texture_mailbox; + committed_texture_graphics_3d_ = bound_graphics_3d_; + committed_texture_consumed_sync_token_ = gpu::SyncToken(); + if (!texture_layer_) { UpdateLayer(true); return; } - gpu::Mailbox mailbox; - gpu::SyncToken sync_token; - bound_graphics_3d_->GetBackingMailbox(&mailbox, &sync_token); - DCHECK(!mailbox.IsZero()); - DCHECK(sync_token.HasData()); - texture_layer_->SetTextureMailboxWithoutReleaseCallback( - cc::TextureMailbox(mailbox, sync_token, GL_TEXTURE_2D)); + PassCommittedTextureToTextureLayer(); texture_layer_->SetNeedsDisplay(); } +void PepperPluginInstanceImpl::PassCommittedTextureToTextureLayer() { + DCHECK(bound_graphics_3d_); + + if (!committed_texture_.IsValid()) + return; + + std::unique_ptr<cc::SingleReleaseCallback> callback( + cc::SingleReleaseCallback::Create(base::Bind( + &PepperPluginInstanceImpl::FinishedConsumingCommittedTexture, + weak_factory_.GetWeakPtr(), committed_texture_, + committed_texture_graphics_3d_))); + + IncrementTextureReferenceCount(committed_texture_); + texture_layer_->SetTextureMailbox(committed_texture_, std::move(callback)); +} + +void PepperPluginInstanceImpl::FinishedConsumingCommittedTexture( + const cc::TextureMailbox& texture_mailbox, + scoped_refptr<PPB_Graphics3D_Impl> graphics_3d, + const gpu::SyncToken& sync_token, + bool is_lost) { + bool removed = DecrementTextureReferenceCount(texture_mailbox); + bool is_committed_texture = + committed_texture_.mailbox() == texture_mailbox.mailbox(); + + if (is_committed_texture && !is_lost) { + committed_texture_consumed_sync_token_ = sync_token; + return; + } + + if (removed && !is_committed_texture) { + graphics_3d->ReturnFrontBuffer(texture_mailbox.mailbox(), sync_token, + is_lost); + } +} + void PepperPluginInstanceImpl::InstanceCrashed() { // Force free all resources and vars. HostGlobals::Get()->InstanceCrashed(pp_instance()); @@ -843,6 +888,14 @@ bool PepperPluginInstanceImpl::Initialize( if (message_channel_) message_channel_->Start(); } + + if (success && + render_frame_ && + render_frame_->render_accessibility() && + LoadPdfInterface()) { + plugin_pdf_interface_->EnableAccessibility(pp_instance()); + } + initialized_ = success; return success; } @@ -1216,8 +1269,7 @@ PP_Var PepperPluginInstanceImpl::GetInstanceObject(v8::Isolate* isolate) { void PepperPluginInstanceImpl::ViewChanged( const gfx::Rect& window, const gfx::Rect& clip, - const gfx::Rect& unobscured, - const std::vector<gfx::Rect>& cut_outs_rects) { + const gfx::Rect& unobscured) { // WebKit can give weird (x,y) positions for empty clip rects (since the // position technically doesn't matter). But we want to make these // consistent since this is given to the plugin, so force everything to 0 @@ -1228,8 +1280,6 @@ void PepperPluginInstanceImpl::ViewChanged( unobscured_rect_ = unobscured; - cut_outs_rects_ = cut_outs_rects; - view_data_.rect = PP_FromGfxRect(window); view_data_.clip_rect = PP_FromGfxRect(clip); view_data_.device_scale = container_->deviceScaleFactor(); @@ -1251,9 +1301,7 @@ void PepperPluginInstanceImpl::ViewChanged( scroll_offset.height()); if (desired_fullscreen_state_ || view_data_.is_fullscreen) { - WebElement element = container_->element(); - WebDocument document = element.document(); - bool is_fullscreen_element = (element == document.fullScreenElement()); + bool is_fullscreen_element = container_->isFullscreenElement(); if (!view_data_.is_fullscreen && desired_fullscreen_state_ && render_frame()->GetRenderWidget()->is_fullscreen_granted() && is_fullscreen_element) { @@ -1424,12 +1472,13 @@ bool PepperPluginInstanceImpl::StartFind(const base::string16& search_text, PP_FromBool(case_sensitive))); } -void PepperPluginInstanceImpl::SelectFindResult(bool forward) { +void PepperPluginInstanceImpl::SelectFindResult(bool forward, int identifier) { // Keep a reference on the stack. See NOTE above. scoped_refptr<PepperPluginInstanceImpl> ref(this); - if (LoadFindInterface()) - plugin_find_interface_->SelectFindResult(pp_instance(), - PP_FromBool(forward)); + if (!LoadFindInterface()) + return; + find_identifier_ = identifier; + plugin_find_interface_->SelectFindResult(pp_instance(), PP_FromBool(forward)); } void PepperPluginInstanceImpl::StopFind() { @@ -1921,9 +1970,9 @@ bool PepperPluginInstanceImpl::SetFullscreen(bool fullscreen) { // so we will tweak plugin's attributes to support the expected behavior. KeepSizeAttributesBeforeFullscreen(); SetSizeAttributesForFullscreen(); - container_->element().requestFullScreen(); + container_->requestFullscreen(); } else { - container_->document().cancelFullScreen(); + container_->cancelFullscreen(); } return true; } @@ -2003,12 +2052,7 @@ void PepperPluginInstanceImpl::UpdateLayer(bool force_creation) { if (!container_) return; - gpu::Mailbox mailbox; - gpu::SyncToken sync_token; - if (bound_graphics_3d_.get()) { - bound_graphics_3d_->GetBackingMailbox(&mailbox, &sync_token); - } - bool want_3d_layer = !mailbox.IsZero() && sync_token.HasData(); + bool want_3d_layer = !!bound_graphics_3d_.get(); bool want_2d_layer = !!bound_graphics_2d_platform_; bool want_texture_layer = want_3d_layer || want_2d_layer; bool want_compositor_layer = !!bound_compositor_; @@ -2047,8 +2091,8 @@ void PepperPluginInstanceImpl::UpdateLayer(bool force_creation) { DCHECK(bound_graphics_3d_.get()); texture_layer_ = cc::TextureLayer::CreateForMailbox(NULL); opaque = bound_graphics_3d_->IsOpaque(); - texture_layer_->SetTextureMailboxWithoutReleaseCallback( - cc::TextureMailbox(mailbox, sync_token, GL_TEXTURE_2D)); + + PassCommittedTextureToTextureLayer(); } else { DCHECK(bound_graphics_2d_platform_); texture_layer_ = cc::TextureLayer::CreateForMailbox(this); @@ -3340,4 +3384,47 @@ void PepperPluginInstanceImpl::ConvertDIPToViewport(gfx::Rect* rect) const { rect->set_height(rect->height() / viewport_to_dip_scale_); } +void PepperPluginInstanceImpl::IncrementTextureReferenceCount( + const cc::TextureMailbox& mailbox) { + auto it = + std::find_if(texture_ref_counts_.begin(), texture_ref_counts_.end(), + [&mailbox](const TextureMailboxRefCount& ref_count) { + return ref_count.first.mailbox() == mailbox.mailbox(); + }); + if (it == texture_ref_counts_.end()) { + texture_ref_counts_.push_back(std::make_pair(mailbox, 1)); + return; + } + + it->second++; +} + +bool PepperPluginInstanceImpl::DecrementTextureReferenceCount( + const cc::TextureMailbox& mailbox) { + auto it = + std::find_if(texture_ref_counts_.begin(), texture_ref_counts_.end(), + [&mailbox](const TextureMailboxRefCount& ref_count) { + return ref_count.first.mailbox() == mailbox.mailbox(); + }); + DCHECK(it != texture_ref_counts_.end()); + + if (it->second == 1) { + texture_ref_counts_.erase(it); + return true; + } + + it->second--; + return false; +} + +bool PepperPluginInstanceImpl::IsTextureInUse( + const cc::TextureMailbox& mailbox) const { + auto it = + std::find_if(texture_ref_counts_.begin(), texture_ref_counts_.end(), + [&mailbox](const TextureMailboxRefCount& ref_count) { + return ref_count.first.mailbox() == mailbox.mailbox(); + }); + return it != texture_ref_counts_.end(); +} + } // namespace content diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.h b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.h index dd53679cc79..f3089f05042 100644 --- a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.h +++ b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.h @@ -24,6 +24,7 @@ #include "cc/layers/content_layer_client.h" #include "cc/layers/layer.h" #include "cc/layers/texture_layer_client.h" +#include "cc/resources/texture_mailbox.h" #include "content/common/content_export.h" #include "content/public/renderer/pepper_plugin_instance.h" #include "content/public/renderer/plugin_instance_throttler.h" @@ -105,6 +106,7 @@ namespace content { class ContentDecryptorDelegate; class FullscreenContainer; class MessageChannel; +class PepperAudioController; class PepperCompositorHost; class PepperGraphics2DHost; class PluginInstanceThrottlerImpl; @@ -197,9 +199,18 @@ class CONTENT_EXPORT PepperPluginInstanceImpl // slow path can also be triggered if there is an overlapping frame. void ScrollRect(int dx, int dy, const gfx::Rect& rect); - // Commit the backing texture to the screen once the side effects some - // rendering up to an offscreen SwapBuffers are visible. - void CommitBackingTexture(); + // Commit the texture mailbox to the screen. + void CommitTextureMailbox(const cc::TextureMailbox& texture_mailbox); + + // Passes the committed texture to |texture_layer_| and marks it as in use. + void PassCommittedTextureToTextureLayer(); + + // Callback when the compositor is finished consuming the committed texture. + void FinishedConsumingCommittedTexture( + const cc::TextureMailbox& texture_mailbox, + scoped_refptr<PPB_Graphics3D_Impl> graphics_3d, + const gpu::SyncToken& sync_token, + bool is_lost); // Called when the out-of-process plugin implementing this instance crashed. void InstanceCrashed(); @@ -219,8 +230,7 @@ class CONTENT_EXPORT PepperPluginInstanceImpl PP_Var GetInstanceObject(v8::Isolate* isolate); void ViewChanged(const gfx::Rect& window, const gfx::Rect& clip, - const gfx::Rect& unobscured, - const std::vector<gfx::Rect>& cut_outs_rects); + const gfx::Rect& unobscured); // Handlers for composition events. bool HandleCompositionStart(const base::string16& text); @@ -259,7 +269,7 @@ class CONTENT_EXPORT PepperPluginInstanceImpl bool StartFind(const base::string16& search_text, bool case_sensitive, int identifier); - void SelectFindResult(bool forward); + void SelectFindResult(bool forward, int identifier); void StopFind(); bool SupportsPrintInterface(); @@ -548,6 +558,10 @@ class CONTENT_EXPORT PepperPluginInstanceImpl void OnThrottleStateChange() override; void OnHiddenForPlaceholder(bool hidden) override; + PepperAudioController& audio_controller() { + return *audio_controller_; + } + private: friend class base::RefCounted<PepperPluginInstanceImpl>; friend class PpapiPluginInstanceTest; @@ -702,6 +716,28 @@ class CONTENT_EXPORT PepperPluginInstanceImpl void ConvertRectToDIP(PP_Rect* rect) const; void ConvertDIPToViewport(gfx::Rect* rect) const; + // Each time CommitTextureMailbox() is called, this instance is given + // ownership + // of a cc::TextureMailbox. This instance always needs to hold on to the most + // recently committed cc::TextureMailbox, since UpdateLayer() might require + // it. + // Since it is possible for a cc::TextureMailbox to be passed to + // texture_layer_ more than once, a reference counting mechanism is necessary + // to ensure that a cc::TextureMailbox isn't returned until all copies of it + // have been released by texture_layer_. + // + // This method should be called each time a cc::TextureMailbox is passed to + // |texture_layer_|. It increments an internal reference count. + void IncrementTextureReferenceCount(const cc::TextureMailbox& mailbox); + + // This method should be called each time |texture_layer_| finishes consuming + // a cc::TextureMailbox. It decrements an internal reference count. Returns + // whether the last reference was removed. + bool DecrementTextureReferenceCount(const cc::TextureMailbox& mailbox); + + // Whether a given cc::TextureMailbox is in use by |texture_layer_|. + bool IsTextureInUse(const cc::TextureMailbox& mailbox) const; + RenderFrameImpl* render_frame_; scoped_refptr<PluginModule> module_; std::unique_ptr<ppapi::PPP_Instance_Combined> instance_interface_; @@ -831,10 +867,6 @@ class CONTENT_EXPORT PepperPluginInstanceImpl // Set to true if this plugin thinks it will always be on top. This allows us // to use a more optimized painting path in some cases. bool always_on_top_; - // Even if |always_on_top_| is true, the plugin is not fully visible if there - // are some cut-out areas (occupied by iframes higher in the stacking order). - // This information is used in the optimized painting path. - std::vector<gfx::Rect> cut_outs_rects_; // Implementation of PPB_FlashFullscreen. @@ -932,8 +964,27 @@ class CONTENT_EXPORT PepperPluginInstanceImpl // The text that is currently selected in the plugin. base::string16 selected_text_; + // The most recently committed texture. This is kept around in case the layer + // needs to be regenerated. + cc::TextureMailbox committed_texture_; + + // The Graphics3D that produced the most recently committed texture. + scoped_refptr<PPB_Graphics3D_Impl> committed_texture_graphics_3d_; + + gpu::SyncToken committed_texture_consumed_sync_token_; + + // Holds the number of references |texture_layer_| has to any given + // cc::TextureMailbox. + // We expect there to be no more than 10 textures in use at a time. A + // std::vector will have better performance than a std::map. + using TextureMailboxRefCount = std::pair<cc::TextureMailbox, int>; + std::vector<TextureMailboxRefCount> texture_ref_counts_; + bool initialized_; + // The controller for all active audios of this pepper instance. + std::unique_ptr<PepperAudioController> audio_controller_; + // We use a weak ptr factory for scheduling DidChangeView events so that we // can tell whether updates are pending and consolidate them. When there's // already a weak ptr pending (HasWeakPtrs is true), code should update the diff --git a/chromium/content/renderer/pepper/pepper_url_loader_host.cc b/chromium/content/renderer/pepper/pepper_url_loader_host.cc index ac34ce9ca66..d8b75dda4aa 100644 --- a/chromium/content/renderer/pepper/pepper_url_loader_host.cc +++ b/chromium/content/renderer/pepper/pepper_url_loader_host.cc @@ -264,7 +264,9 @@ int32_t PepperURLLoaderHost::InternalOnHostMsgOpen( // The requests from the plugins with private permission which can bypass same // origin must skip the ServiceWorker. web_request.setSkipServiceWorker( - host()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE)); + host()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE) + ? blink::WebURLRequest::SkipServiceWorker::All + : blink::WebURLRequest::SkipServiceWorker::None); WebURLLoaderOptions options; if (has_universal_access_) { diff --git a/chromium/content/renderer/pepper/pepper_video_decoder_host.cc b/chromium/content/renderer/pepper/pepper_video_decoder_host.cc index 00fbe5d631b..3ca1c3b1b9f 100644 --- a/chromium/content/renderer/pepper/pepper_video_decoder_host.cc +++ b/chromium/content/renderer/pepper/pepper_video_decoder_host.cc @@ -149,7 +149,10 @@ int32_t PepperVideoDecoderHost::OnHostMsgInitialize( // it is okay to immediately send IPC messages. if (command_buffer->channel()) { decoder_.reset(new media::GpuVideoDecodeAcceleratorHost(command_buffer)); - if (decoder_->Initialize(profile_, this)) { + media::VideoDecodeAccelerator::Config vda_config(profile_); + vda_config.supported_output_formats.assign( + {media::PIXEL_FORMAT_XRGB, media::PIXEL_FORMAT_ARGB}); + if (decoder_->Initialize(vda_config, this)) { initialized_ = true; return PP_OK; } @@ -351,6 +354,7 @@ int32_t PepperVideoDecoderHost::OnHostMsgReset( void PepperVideoDecoderHost::ProvidePictureBuffers( uint32_t requested_num_of_buffers, + media::VideoPixelFormat format, uint32_t textures_per_buffer, const gfx::Size& dimensions, uint32_t texture_target) { diff --git a/chromium/content/renderer/pepper/pepper_video_decoder_host.h b/chromium/content/renderer/pepper/pepper_video_decoder_host.h index 308ba447598..e0f383a651b 100644 --- a/chromium/content/renderer/pepper/pepper_video_decoder_host.h +++ b/chromium/content/renderer/pepper/pepper_video_decoder_host.h @@ -73,6 +73,7 @@ class CONTENT_EXPORT PepperVideoDecoderHost // media::VideoDecodeAccelerator::Client implementation. void ProvidePictureBuffers(uint32_t requested_num_of_buffers, + media::VideoPixelFormat format, uint32_t textures_per_buffer, const gfx::Size& dimensions, uint32_t texture_target) override; diff --git a/chromium/content/renderer/pepper/pepper_video_encoder_host.cc b/chromium/content/renderer/pepper/pepper_video_encoder_host.cc index 8438c0f51d3..0d0997b5047 100644 --- a/chromium/content/renderer/pepper/pepper_video_encoder_host.cc +++ b/chromium/content/renderer/pepper/pepper_video_encoder_host.cc @@ -441,12 +441,14 @@ void PepperVideoEncoderHost::RequireBitstreamBuffers( } void PepperVideoEncoderHost::BitstreamBufferReady(int32_t buffer_id, - size_t payload_size, - bool key_frame) { + size_t payload_size, + bool key_frame, + base::TimeDelta /* timestamp */) { DCHECK(RenderThreadImpl::current()); DCHECK(shm_buffers_[buffer_id]->in_use); shm_buffers_[buffer_id]->in_use = false; + // TODO: Pass timestamp. Tracked in crbug/613984. host()->SendUnsolicitedReply( pp_resource(), PpapiPluginMsg_VideoEncoder_BitstreamBufferReady( @@ -527,10 +529,10 @@ bool PepperVideoEncoderHost::EnsureGpuChannel() { return false; command_buffer_ = gpu::CommandBufferProxyImpl::Create( - std::move(channel), gpu::kNullSurfaceHandle, gfx::Size(), nullptr, + std::move(channel), gpu::kNullSurfaceHandle, nullptr, gpu::GPU_STREAM_DEFAULT, gpu::GpuStreamPriority::NORMAL, gpu::gles2::ContextCreationAttribHelper(), GURL::EmptyGURL(), - gfx::PreferIntegratedGpu, base::ThreadTaskRunnerHandle::Get()); + base::ThreadTaskRunnerHandle::Get()); if (!command_buffer_) { Close(); return false; diff --git a/chromium/content/renderer/pepper/pepper_video_encoder_host.h b/chromium/content/renderer/pepper/pepper_video_encoder_host.h index 53b95069119..d3f8e2a4eb0 100644 --- a/chromium/content/renderer/pepper/pepper_video_encoder_host.h +++ b/chromium/content/renderer/pepper/pepper_video_encoder_host.h @@ -71,7 +71,8 @@ class CONTENT_EXPORT PepperVideoEncoderHost size_t output_buffer_size) override; void BitstreamBufferReady(int32_t bitstream_buffer_id, size_t payload_size, - bool key_frame) override; + bool key_frame, + base::TimeDelta timestamp) override; void NotifyError(media::VideoEncodeAccelerator::Error error) override; // ResourceHost implementation. diff --git a/chromium/content/renderer/pepper/pepper_webplugin_impl.cc b/chromium/content/renderer/pepper/pepper_webplugin_impl.cc index 813820319f5..3949db81188 100644 --- a/chromium/content/renderer/pepper/pepper_webplugin_impl.cc +++ b/chromium/content/renderer/pepper/pepper_webplugin_impl.cc @@ -9,7 +9,9 @@ #include <utility> #include "base/debug/crash_logging.h" -#include "base/message_loop/message_loop.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" #include "content/public/renderer/content_renderer_client.h" #include "content/renderer/pepper/message_channel.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" @@ -155,7 +157,7 @@ void PepperWebPluginImpl::destroy() { instance_ = nullptr; } - base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); } v8::Local<v8::Object> PepperWebPluginImpl::v8ScriptableObject( @@ -199,12 +201,8 @@ void PepperWebPluginImpl::updateGeometry( const WebVector<WebRect>& cut_outs_rects, bool is_visible) { plugin_rect_ = window_rect; - if (instance_ && !instance_->FlashIsFullscreenOrPending()) { - std::vector<gfx::Rect> cut_outs; - for (size_t i = 0; i < cut_outs_rects.size(); ++i) - cut_outs.push_back(cut_outs_rects[i]); - instance_->ViewChanged(plugin_rect_, clip_rect, unobscured_rect, cut_outs); - } + if (instance_ && !instance_->FlashIsFullscreenOrPending()) + instance_->ViewChanged(plugin_rect_, clip_rect, unobscured_rect); } void PepperWebPluginImpl::updateFocus(bool focused, @@ -271,8 +269,8 @@ bool PepperWebPluginImpl::startFind(const blink::WebString& search_text, return instance_->StartFind(search_text, case_sensitive, identifier); } -void PepperWebPluginImpl::selectFindResult(bool forward) { - instance_->SelectFindResult(forward); +void PepperWebPluginImpl::selectFindResult(bool forward, int identifier) { + instance_->SelectFindResult(forward, identifier); } void PepperWebPluginImpl::stopFind() { instance_->StopFind(); } diff --git a/chromium/content/renderer/pepper/pepper_webplugin_impl.h b/chromium/content/renderer/pepper/pepper_webplugin_impl.h index 49a0832c5ae..3de02b80c1a 100644 --- a/chromium/content/renderer/pepper/pepper_webplugin_impl.h +++ b/chromium/content/renderer/pepper/pepper_webplugin_impl.h @@ -70,7 +70,7 @@ class PepperWebPluginImpl : public blink::WebPlugin { bool startFind(const blink::WebString& search_text, bool case_sensitive, int identifier) override; - void selectFindResult(bool forward) override; + void selectFindResult(bool forward, int identifier) override; void stopFind() override; bool supportsPaginatedPrint() override; bool isPrintScalingDisabled() override; diff --git a/chromium/content/renderer/pepper/plugin_power_saver_helper.cc b/chromium/content/renderer/pepper/plugin_power_saver_helper.cc index 36d65e3f8fc..1879b7e9fe2 100644 --- a/chromium/content/renderer/pepper/plugin_power_saver_helper.cc +++ b/chromium/content/renderer/pepper/plugin_power_saver_helper.cc @@ -7,9 +7,11 @@ #include <string> #include "base/command_line.h" -#include "base/message_loop/message_loop.h" +#include "base/location.h" #include "base/metrics/histogram.h" +#include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" +#include "base/threading/thread_task_runner_handle.h" #include "content/common/frame_messages.h" #include "content/public/common/content_switches.h" #include "content/public/renderer/render_frame.h" @@ -66,6 +68,10 @@ bool PluginPowerSaverHelper::OnMessageReceived(const IPC::Message& message) { return handled; } +void PluginPowerSaverHelper::OnDestruct() { + delete this; +} + void PluginPowerSaverHelper::OnUpdatePluginContentOriginWhitelist( const std::set<url::Origin>& origin_whitelist) { origin_whitelist_ = origin_whitelist; @@ -76,8 +82,8 @@ void PluginPowerSaverHelper::OnUpdatePluginContentOriginWhitelist( if (origin_whitelist.count(it->content_origin)) { // Because the unthrottle callback may register another peripheral plugin // and invalidate our iterator, we cannot run it synchronously. - base::MessageLoop::current()->PostTask(FROM_HERE, - it->unthrottle_callback); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + it->unthrottle_callback); it = peripheral_plugins_.erase(it); } else { ++it; diff --git a/chromium/content/renderer/pepper/plugin_power_saver_helper.h b/chromium/content/renderer/pepper/plugin_power_saver_helper.h index 2f3bb442657..0de22ddf3b9 100644 --- a/chromium/content/renderer/pepper/plugin_power_saver_helper.h +++ b/chromium/content/renderer/pepper/plugin_power_saver_helper.h @@ -57,6 +57,7 @@ class CONTENT_EXPORT PluginPowerSaverHelper : public RenderFrameObserver { void DidCommitProvisionalLoad(bool is_new_navigation, bool is_same_page_navigation) override; bool OnMessageReceived(const IPC::Message& message) override; + void OnDestruct() override; void OnUpdatePluginContentOriginWhitelist( const std::set<url::Origin>& origin_whitelist); diff --git a/chromium/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc b/chromium/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc index d701c31b251..35b8388f88c 100644 --- a/chromium/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc +++ b/chromium/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <tuple> + #include "base/macros.h" #include "base/run_loop.h" #include "content/common/frame_messages.h" @@ -64,7 +66,7 @@ TEST_F(PluginPowerSaverHelperTest, TemporaryOriginWhitelist) { FrameHostMsg_PluginContentOriginAllowed::Param params; FrameHostMsg_PluginContentOriginAllowed::Read(msg, ¶ms); EXPECT_TRUE(url::Origin(GURL("http://other.com")) - .IsSameOriginWith(base::get<0>(params))); + .IsSameOriginWith(std::get<0>(params))); } TEST_F(PluginPowerSaverHelperTest, UnthrottleOnExPostFactoWhitelist) { diff --git a/chromium/content/renderer/pepper/ppb_audio_impl.cc b/chromium/content/renderer/pepper/ppb_audio_impl.cc index 98bf7637f4a..43426b5b5fa 100644 --- a/chromium/content/renderer/pepper/ppb_audio_impl.cc +++ b/chromium/content/renderer/pepper/ppb_audio_impl.cc @@ -5,11 +5,11 @@ #include "content/renderer/pepper/ppb_audio_impl.h" #include "base/logging.h" +#include "content/renderer/pepper/pepper_audio_controller.h" #include "content/renderer/pepper/pepper_platform_audio_output.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "content/renderer/pepper/plugin_instance_throttler_impl.h" #include "content/renderer/render_frame_impl.h" -#include "content/renderer/render_view_impl.h" #include "media/audio/audio_output_controller.h" #include "ppapi/c/pp_completion_callback.h" #include "ppapi/c/ppb_audio.h" @@ -44,8 +44,11 @@ PPB_Audio_Impl::PPB_Audio_Impl(PP_Instance instance) PPB_Audio_Impl::~PPB_Audio_Impl() { PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>( PepperPluginInstance::Get(pp_instance())); - if (instance && instance->throttler()) { - instance->throttler()->RemoveObserver(this); + if (instance) { + if (instance->throttler()) { + instance->throttler()->RemoveObserver(this); + } + instance->audio_controller().RemoveInstance(this); } // Calling ShutDown() makes sure StreamCreated cannot be called anymore and @@ -83,6 +86,9 @@ PP_Bool PPB_Audio_Impl::StartPlayback() { return PP_TRUE; } + if (instance) + instance->audio_controller().AddInstance(this); + SetStartPlaybackState(); return PP_FromBool(audio_->StartPlayback()); } @@ -97,6 +103,11 @@ PP_Bool PPB_Audio_Impl::StopPlayback() { StartDeferredPlayback(); } + PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>( + PepperPluginInstance::Get(pp_instance())); + if (instance) + instance->audio_controller().RemoveInstance(this); + if (!playing()) return PP_TRUE; if (!audio_->StopPlayback()) @@ -173,8 +184,17 @@ void PPB_Audio_Impl::StartDeferredPlayback() { DCHECK(playback_throttled_); playback_throttled_ = false; + PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>( + PepperPluginInstance::Get(pp_instance())); + if (instance) + instance->audio_controller().AddInstance(this); + SetStartPlaybackState(); audio_->StartPlayback(); } +void PPB_Audio_Impl::SetVolume(double volume) { + if (audio_) + audio_->SetVolume(volume); +} } // namespace content diff --git a/chromium/content/renderer/pepper/ppb_audio_impl.h b/chromium/content/renderer/pepper/ppb_audio_impl.h index 311dfb9306c..e0618ffb29d 100644 --- a/chromium/content/renderer/pepper/ppb_audio_impl.h +++ b/chromium/content/renderer/pepper/ppb_audio_impl.h @@ -50,6 +50,8 @@ class PPB_Audio_Impl : public ppapi::Resource, int32_t GetSharedMemory(base::SharedMemory** shm, uint32_t* shm_size) override; + void SetVolume(double volume); + private: ~PPB_Audio_Impl() override; diff --git a/chromium/content/renderer/pepper/ppb_graphics_3d_impl.cc b/chromium/content/renderer/pepper/ppb_graphics_3d_impl.cc index a908b6fbe0f..5e0b5f32641 100644 --- a/chromium/content/renderer/pepper/ppb_graphics_3d_impl.cc +++ b/chromium/content/renderer/pepper/ppb_graphics_3d_impl.cc @@ -28,6 +28,7 @@ #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebPluginContainer.h" +#include "third_party/khronos/GLES2/gl2.h" using ppapi::thunk::EnterResourceNoLock; using ppapi::thunk::PPB_Graphics3D_API; @@ -114,6 +115,22 @@ void PPB_Graphics3D_Impl::EnsureWorkVisible() { command_buffer_->EnsureWorkVisible(); } +void PPB_Graphics3D_Impl::TakeFrontBuffer() { + if (!taken_front_buffer_.IsZero()) { + DLOG(ERROR) + << "TakeFrontBuffer should only be called once before DoSwapBuffers"; + return; + } + taken_front_buffer_ = GenerateMailbox(); + command_buffer_->TakeFrontBuffer(taken_front_buffer_); +} + +void PPB_Graphics3D_Impl::ReturnFrontBuffer(const gpu::Mailbox& mailbox, + const gpu::SyncToken& sync_token, + bool is_lost) { + command_buffer_->ReturnFrontBuffer(mailbox, sync_token, is_lost); +} + bool PPB_Graphics3D_Impl::BindToInstance(bool bind) { bound_to_instance_ = bind; return true; @@ -143,8 +160,10 @@ gpu::GpuControl* PPB_Graphics3D_Impl::GetGpuControl() { int32_t PPB_Graphics3D_Impl::DoSwapBuffers(const gpu::SyncToken& sync_token) { DCHECK(command_buffer_); - if (sync_token.HasData()) - sync_token_ = sync_token; + if (taken_front_buffer_.IsZero()) { + DLOG(ERROR) << "TakeFrontBuffer should be called before DoSwapBuffers"; + return PP_ERROR_FAILED; + } if (bound_to_instance_) { // If we are bound to the instance, we need to ask the compositor @@ -154,14 +173,18 @@ int32_t PPB_Graphics3D_Impl::DoSwapBuffers(const gpu::SyncToken& sync_token) { // // Don't need to check for NULL from GetPluginInstance since when we're // bound, we know our instance is valid. - HostGlobals::Get()->GetInstance(pp_instance())->CommitBackingTexture(); + cc::TextureMailbox texture_mailbox(taken_front_buffer_, sync_token, + GL_TEXTURE_2D); + taken_front_buffer_.SetZero(); + HostGlobals::Get() + ->GetInstance(pp_instance()) + ->CommitTextureMailbox(texture_mailbox); commit_pending_ = true; } else { // Wait for the command to complete on the GPU to allow for throttling. command_buffer_->SignalSyncToken( - sync_token_, - base::Bind(&PPB_Graphics3D_Impl::OnSwapBuffers, - weak_ptr_factory_.GetWeakPtr())); + sync_token, base::Bind(&PPB_Graphics3D_Impl::OnSwapBuffers, + weak_ptr_factory_.GetWeakPtr())); } return PP_OK_COMPLETIONPENDING; @@ -202,9 +225,9 @@ bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API* share_context, if (!channel) return false; - gfx::Size surface_size; + gpu::gles2::ContextCreationAttribHelper attrib_helper; std::vector<int32_t> attribs; - gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; + attrib_helper.gpu_preference = gl::PreferDiscreteGpu; // TODO(alokp): Change CommandBufferProxyImpl::Create() // interface to accept width and height in the attrib_list so that // we do not need to filter for width and height here. @@ -213,16 +236,16 @@ bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API* share_context, attr += 2) { switch (attr[0]) { case PP_GRAPHICS3DATTRIB_WIDTH: - surface_size.set_width(attr[1]); + attrib_helper.offscreen_framebuffer_size.set_width(attr[1]); break; case PP_GRAPHICS3DATTRIB_HEIGHT: - surface_size.set_height(attr[1]); + attrib_helper.offscreen_framebuffer_size.set_height(attr[1]); break; case PP_GRAPHICS3DATTRIB_GPU_PREFERENCE: - gpu_preference = + attrib_helper.gpu_preference = (attr[1] == PP_GRAPHICS3DATTRIB_GPU_PREFERENCE_LOW_POWER) - ? gfx::PreferIntegratedGpu - : gfx::PreferDiscreteGpu; + ? gl::PreferIntegratedGpu + : gl::PreferDiscreteGpu; break; case PP_GRAPHICS3DATTRIB_ALPHA_SIZE: has_alpha_ = attr[1] > 0; @@ -235,7 +258,6 @@ bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API* share_context, } attribs.push_back(PP_GRAPHICS3DATTRIB_NONE); } - gpu::gles2::ContextCreationAttribHelper attrib_helper; if (!attrib_helper.Parse(attribs)) return false; @@ -247,10 +269,9 @@ bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API* share_context, } command_buffer_ = gpu::CommandBufferProxyImpl::Create( - std::move(channel), gpu::kNullSurfaceHandle, surface_size, share_buffer, - gpu::GPU_STREAM_DEFAULT, gpu::GpuStreamPriority::NORMAL, - attrib_helper, GURL::EmptyGURL(), gpu_preference, - base::ThreadTaskRunnerHandle::Get()); + std::move(channel), gpu::kNullSurfaceHandle, share_buffer, + gpu::GPU_STREAM_DEFAULT, gpu::GpuStreamPriority::NORMAL, attrib_helper, + GURL::EmptyGURL(), base::ThreadTaskRunnerHandle::Get()); if (!command_buffer_) return false; @@ -263,10 +284,6 @@ bool PPB_Graphics3D_Impl::InitRaw(PPB_Graphics3D_API* share_context, if (command_buffer_id) *command_buffer_id = command_buffer_->GetCommandBufferID(); - mailbox_ = gpu::Mailbox::Generate(); - if (!command_buffer_->ProduceFrontBuffer(mailbox_)) - return false; - return true; } @@ -344,4 +361,14 @@ void PPB_Graphics3D_Impl::SendContextLost() { ppp_graphics_3d->Graphics3DContextLost(this_pp_instance); } +gpu::Mailbox PPB_Graphics3D_Impl::GenerateMailbox() { + if (!mailboxes_to_reuse_.empty()) { + gpu::Mailbox mailbox = mailboxes_to_reuse_.back(); + mailboxes_to_reuse_.pop_back(); + return mailbox; + } + + return gpu::Mailbox::Generate(); +} + } // namespace content diff --git a/chromium/content/renderer/pepper/ppb_graphics_3d_impl.h b/chromium/content/renderer/pepper/ppb_graphics_3d_impl.h index 8216f631b7e..abafd2c4b14 100644 --- a/chromium/content/renderer/pepper/ppb_graphics_3d_impl.h +++ b/chromium/content/renderer/pepper/ppb_graphics_3d_impl.h @@ -47,6 +47,10 @@ class PPB_Graphics3D_Impl : public ppapi::PPB_Graphics3D_Shared, gpu::CommandBuffer::State WaitForGetOffsetInRange(int32_t start, int32_t end) override; void EnsureWorkVisible() override; + void TakeFrontBuffer() override; + void ReturnFrontBuffer(const gpu::Mailbox& mailbox, + const gpu::SyncToken& sync_token, + bool is_lost); // Binds/unbinds the graphics of this context with the associated instance. // Returns true if binding/unbinding is successful. @@ -59,11 +63,6 @@ class PPB_Graphics3D_Impl : public ppapi::PPB_Graphics3D_Shared, // These messages are used to send Flush callbacks to the plugin. void ViewInitiatedPaint(); - void GetBackingMailbox(gpu::Mailbox* mailbox, gpu::SyncToken* sync_token) { - *mailbox = mailbox_; - *sync_token = sync_token_; - } - gpu::CommandBufferProxyImpl* GetCommandBufferProxy(); protected: @@ -92,6 +91,16 @@ class PPB_Graphics3D_Impl : public ppapi::PPB_Graphics3D_Shared, // Notifications sent to plugin. void SendContextLost(); + // Reuses a mailbox if one is available, otherwise makes a new one. + gpu::Mailbox GenerateMailbox(); + + // A front buffer that was recently taken from the command buffer. This should + // be immediately consumed by DoSwapBuffers(). + gpu::Mailbox taken_front_buffer_; + + // Mailboxes that are no longer in use. + std::vector<gpu::Mailbox> mailboxes_to_reuse_; + // True if context is bound to instance. bool bound_to_instance_; // True when waiting for compositor to commit our backing texture. @@ -101,8 +110,6 @@ class PPB_Graphics3D_Impl : public ppapi::PPB_Graphics3D_Shared, bool lost_context_ = false; #endif - gpu::Mailbox mailbox_; - gpu::SyncToken sync_token_; bool has_alpha_; std::unique_ptr<gpu::CommandBufferProxyImpl> command_buffer_; diff --git a/chromium/content/renderer/pepper/ppb_video_decoder_impl.cc b/chromium/content/renderer/pepper/ppb_video_decoder_impl.cc index 0f31ea09a21..360f5d4e3e5 100644 --- a/chromium/content/renderer/pepper/ppb_video_decoder_impl.cc +++ b/chromium/content/renderer/pepper/ppb_video_decoder_impl.cc @@ -239,6 +239,7 @@ void PPB_VideoDecoder_Impl::Destroy() { void PPB_VideoDecoder_Impl::ProvidePictureBuffers( uint32_t requested_num_of_buffers, + media::VideoPixelFormat format, uint32_t textures_per_buffer, const gfx::Size& dimensions, uint32_t texture_target) { diff --git a/chromium/content/renderer/pepper/ppb_video_decoder_impl.h b/chromium/content/renderer/pepper/ppb_video_decoder_impl.h index c0597a23211..635a5ce47e4 100644 --- a/chromium/content/renderer/pepper/ppb_video_decoder_impl.h +++ b/chromium/content/renderer/pepper/ppb_video_decoder_impl.h @@ -45,6 +45,7 @@ class PPB_VideoDecoder_Impl : public ppapi::PPB_VideoDecoder_Shared, // media::VideoDecodeAccelerator::Client implementation. void ProvidePictureBuffers(uint32_t requested_num_of_buffers, + media::VideoPixelFormat format, uint32_t textures_per_buffer, const gfx::Size& dimensions, uint32_t texture_target) override; diff --git a/chromium/content/renderer/pepper/video_encoder_shim.cc b/chromium/content/renderer/pepper/video_encoder_shim.cc index ab466b395da..0887863363b 100644 --- a/chromium/content/renderer/pepper/video_encoder_shim.cc +++ b/chromium/content/renderer/pepper/video_encoder_shim.cc @@ -487,7 +487,8 @@ void VideoEncoderShim::OnBitstreamBufferReady( bool key_frame) { DCHECK(RenderThreadImpl::current()); - host_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame); + host_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame, + frame->timestamp()); } void VideoEncoderShim::OnNotifyError( diff --git a/chromium/content/renderer/presentation/presentation_dispatcher.cc b/chromium/content/renderer/presentation/presentation_dispatcher.cc index bcc2eacc4c4..e9360099ed0 100644 --- a/chromium/content/renderer/presentation/presentation_dispatcher.cc +++ b/chromium/content/renderer/presentation/presentation_dispatcher.cc @@ -8,12 +8,13 @@ #include <utility> #include <vector> +#include "base/bind.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "content/public/common/presentation_constants.h" -#include "content/public/common/service_registry.h" #include "content/public/renderer/render_frame.h" #include "content/renderer/presentation/presentation_connection_client.h" +#include "services/shell/public/cpp/interface_provider.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/modules/presentation/WebPresentationAvailabilityObserver.h" @@ -308,6 +309,10 @@ void PresentationDispatcher::DidCommitProvisionalLoad( std::swap(message_request_queue_, empty); } +void PresentationDispatcher::OnDestruct() { + delete this; +} + void PresentationDispatcher::OnScreenAvailabilityUpdated( const mojo::String& url, bool available) { const std::string& availability_url = url.get(); @@ -450,8 +455,7 @@ void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() { if (presentation_service_.get()) return; - render_frame()->GetServiceRegistry()->ConnectToRemoteService( - mojo::GetProxy(&presentation_service_)); + render_frame()->GetRemoteInterfaces()->GetInterface(&presentation_service_); presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind()); } diff --git a/chromium/content/renderer/presentation/presentation_dispatcher.h b/chromium/content/renderer/presentation/presentation_dispatcher.h index 2aee2c0d710..e5fb81427c1 100644 --- a/chromium/content/renderer/presentation/presentation_dispatcher.h +++ b/chromium/content/renderer/presentation/presentation_dispatcher.h @@ -94,6 +94,7 @@ class CONTENT_EXPORT PresentationDispatcher void DidCommitProvisionalLoad( bool is_new_navigation, bool is_same_page_navigation) override; + void OnDestruct() override; // blink::mojom::PresentationServiceClient void OnScreenAvailabilityNotSupported(const mojo::String& url) override; diff --git a/chromium/content/renderer/push_messaging/push_messaging_dispatcher.cc b/chromium/content/renderer/push_messaging/push_messaging_dispatcher.cc index b865237174a..471024e90a7 100644 --- a/chromium/content/renderer/push_messaging/push_messaging_dispatcher.cc +++ b/chromium/content/renderer/push_messaging/push_messaging_dispatcher.cc @@ -39,6 +39,10 @@ bool PushMessagingDispatcher::OnMessageReceived(const IPC::Message& message) { return handled; } +void PushMessagingDispatcher::OnDestruct() { + delete this; +} + void PushMessagingDispatcher::subscribe( blink::WebServiceWorkerRegistration* service_worker_registration, const blink::WebPushSubscriptionOptions& options, diff --git a/chromium/content/renderer/push_messaging/push_messaging_dispatcher.h b/chromium/content/renderer/push_messaging/push_messaging_dispatcher.h index 5dcbf8bf943..5fb894f6b5c 100644 --- a/chromium/content/renderer/push_messaging/push_messaging_dispatcher.h +++ b/chromium/content/renderer/push_messaging/push_messaging_dispatcher.h @@ -39,8 +39,9 @@ class PushMessagingDispatcher : public RenderFrameObserver, ~PushMessagingDispatcher() override; private: - // RenderFrame::Observer implementation. + // RenderFrameObserver implementation. bool OnMessageReceived(const IPC::Message& message) override; + void OnDestruct() override; // WebPushClient implementation. void subscribe( diff --git a/chromium/content/renderer/raster_worker_pool_unittest.cc b/chromium/content/renderer/raster_worker_pool_unittest.cc deleted file mode 100644 index 73f83dcdf6a..00000000000 --- a/chromium/content/renderer/raster_worker_pool_unittest.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/sequenced_task_runner_test_template.h" -#include "base/test/task_runner_test_template.h" -#include "base/threading/simple_thread.h" -#include "cc/test/task_graph_runner_test_template.h" -#include "content/renderer/raster_worker_pool.h" - -namespace base { -namespace { - -// Number of threads spawned in tests. -const int kNumThreads = 4; - -class RasterWorkerPoolTestDelegate { - public: - RasterWorkerPoolTestDelegate() - : raster_worker_pool_(new content::RasterWorkerPool()) {} - - void StartTaskRunner() { - raster_worker_pool_->Start(kNumThreads); - } - - scoped_refptr<content::RasterWorkerPool> GetTaskRunner() { - return raster_worker_pool_; - } - - void StopTaskRunner() { raster_worker_pool_->FlushForTesting(); } - - ~RasterWorkerPoolTestDelegate() { raster_worker_pool_->Shutdown(); } - - private: - scoped_refptr<content::RasterWorkerPool> raster_worker_pool_; -}; - -INSTANTIATE_TYPED_TEST_CASE_P(RasterWorkerPool, - TaskRunnerTest, - RasterWorkerPoolTestDelegate); - -class RasterWorkerPoolSequencedTestDelegate { - public: - RasterWorkerPoolSequencedTestDelegate() - : raster_worker_pool_(new content::RasterWorkerPool()) {} - - void StartTaskRunner() { - raster_worker_pool_->Start(kNumThreads); - } - - scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() { - return raster_worker_pool_->CreateSequencedTaskRunner(); - } - - void StopTaskRunner() { raster_worker_pool_->FlushForTesting(); } - - ~RasterWorkerPoolSequencedTestDelegate() { raster_worker_pool_->Shutdown(); } - - private: - scoped_refptr<content::RasterWorkerPool> raster_worker_pool_; -}; - -INSTANTIATE_TYPED_TEST_CASE_P(RasterWorkerPool, - SequencedTaskRunnerTest, - RasterWorkerPoolSequencedTestDelegate); - -} // namespace -} // namespace base - -namespace cc { -namespace { - -template <int NumThreads> -class RasterWorkerPoolTaskGraphRunnerTestDelegate { - public: - RasterWorkerPoolTaskGraphRunnerTestDelegate() - : raster_worker_pool_(new content::RasterWorkerPool()) {} - - void StartTaskGraphRunner() { - raster_worker_pool_->Start(NumThreads); - } - - cc::TaskGraphRunner* GetTaskGraphRunner() { - return raster_worker_pool_->GetTaskGraphRunner(); - } - - void StopTaskGraphRunner() { raster_worker_pool_->FlushForTesting(); } - - ~RasterWorkerPoolTaskGraphRunnerTestDelegate() { - raster_worker_pool_->Shutdown(); - } - - private: - scoped_refptr<content::RasterWorkerPool> raster_worker_pool_; -}; - -// Multithreaded tests. -INSTANTIATE_TYPED_TEST_CASE_P(RasterWorkerPool_1_Threads, - TaskGraphRunnerTest, - RasterWorkerPoolTaskGraphRunnerTestDelegate<1>); -INSTANTIATE_TYPED_TEST_CASE_P(RasterWorkerPool_2_Threads, - TaskGraphRunnerTest, - RasterWorkerPoolTaskGraphRunnerTestDelegate<2>); -INSTANTIATE_TYPED_TEST_CASE_P(RasterWorkerPool_3_Threads, - TaskGraphRunnerTest, - RasterWorkerPoolTaskGraphRunnerTestDelegate<3>); -INSTANTIATE_TYPED_TEST_CASE_P(RasterWorkerPool_4_Threads, - TaskGraphRunnerTest, - RasterWorkerPoolTaskGraphRunnerTestDelegate<4>); -INSTANTIATE_TYPED_TEST_CASE_P(RasterWorkerPool_5_Threads, - TaskGraphRunnerTest, - RasterWorkerPoolTaskGraphRunnerTestDelegate<5>); - -// Single threaded tests. -INSTANTIATE_TYPED_TEST_CASE_P(RasterWorkerPool, - SingleThreadTaskGraphRunnerTest, - RasterWorkerPoolTaskGraphRunnerTestDelegate<1>); - -} // namespace -} // namespace cc diff --git a/chromium/content/renderer/render_frame_impl.cc b/chromium/content/renderer/render_frame_impl.cc index 8d049b23fc0..faa00b78063 100644 --- a/chromium/content/renderer/render_frame_impl.cc +++ b/chromium/content/renderer/render_frame_impl.cc @@ -50,6 +50,7 @@ #include "content/child/weburlresponse_extradata_impl.h" #include "content/common/accessibility_messages.h" #include "content/common/clipboard_messages.h" +#include "content/common/content_constants_internal.h" #include "content/common/content_security_policy_header.h" #include "content/common/frame_messages.h" #include "content/common/frame_replication_state.h" @@ -69,8 +70,10 @@ #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/common/context_menu_params.h" +#include "content/public/common/file_chooser_file_info.h" +#include "content/public/common/file_chooser_params.h" #include "content/public/common/isolated_world_ids.h" -#include "content/public/common/mhtml_generation_params.h" +#include "content/public/common/mojo_shell_connection.h" #include "content/public/common/page_state.h" #include "content/public/common/resource_response.h" #include "content/public/common/url_constants.h" @@ -82,7 +85,7 @@ #include "content/public/renderer/navigation_state.h" #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/renderer_ppapi_host.h" -#include "content/renderer/accessibility/renderer_accessibility.h" +#include "content/renderer/accessibility/render_accessibility_impl.h" #include "content/renderer/bluetooth/web_bluetooth_impl.h" #include "content/renderer/browser_plugin/browser_plugin.h" #include "content/renderer/browser_plugin/browser_plugin_manager.h" @@ -110,10 +113,11 @@ #include "content/renderer/media/user_media_client_impl.h" #include "content/renderer/media/web_media_element_source_utils.h" #include "content/renderer/media/webmediaplayer_ms.h" -#include "content/renderer/mojo/service_registry_js_wrapper.h" +#include "content/renderer/mojo/interface_provider_js_wrapper.h" #include "content/renderer/mojo_bindings_controller.h" #include "content/renderer/navigation_state_impl.h" #include "content/renderer/notification_permission_dispatcher.h" +#include "content/renderer/pepper/pepper_audio_controller.h" #include "content/renderer/pepper/plugin_instance_throttler_impl.h" #include "content/renderer/presentation/presentation_dispatcher.h" #include "content/renderer/push_messaging/push_messaging_dispatcher.h" @@ -145,18 +149,22 @@ #include "media/blink/webencryptedmediaclient_impl.h" #include "media/blink/webmediaplayer_impl.h" #include "media/renderers/gpu_video_accelerator_factories.h" -#include "mojo/common/url_type_converters.h" #include "mojo/edk/js/core.h" #include "mojo/edk/js/support.h" #include "net/base/data_url.h" #include "net/base/net_errors.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "net/http/http_util.h" +#include "services/shell/public/cpp/interface_provider.h" +#include "services/shell/public/cpp/interface_registry.h" +#include "storage/common/data_element.h" +#include "third_party/WebKit/public/platform/FilePathConversion.h" #include "third_party/WebKit/public/platform/URLConversion.h" #include "third_party/WebKit/public/platform/WebCachePolicy.h" #include "third_party/WebKit/public/platform/WebData.h" #include "third_party/WebKit/public/platform/WebMediaPlayer.h" #include "third_party/WebKit/public/platform/WebMediaPlayerSource.h" +#include "third_party/WebKit/public/platform/WebPoint.h" #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" #include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -169,6 +177,7 @@ #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFindOptions.h" #include "third_party/WebKit/public/web/WebFrameSerializer.h" +#include "third_party/WebKit/public/web/WebFrameSerializerCacheControlPolicy.h" #include "third_party/WebKit/public/web/WebFrameWidget.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -231,17 +240,17 @@ #endif #if defined(ENABLE_MOJO_CDM) -#include "media/mojo/services/mojo_cdm_factory.h" // nogncheck +#include "media/mojo/clients/mojo_cdm_factory.h" // nogncheck #endif #if defined(ENABLE_MOJO_RENDERER) -#include "media/mojo/services/mojo_renderer_factory.h" // nogncheck +#include "media/mojo/clients/mojo_renderer_factory.h" // nogncheck #else #include "media/renderers/default_renderer_factory.h" #endif #if defined(ENABLE_MOJO_AUDIO_DECODER) || defined(ENABLE_MOJO_VIDEO_DECODER) -#include "media/mojo/services/mojo_decoder_factory.h" // nogncheck +#include "media/mojo/clients/mojo_decoder_factory.h" // nogncheck #endif using blink::WebCachePolicy; @@ -273,6 +282,7 @@ using blink::WebNavigationType; using blink::WebNode; using blink::WebPluginDocument; using blink::WebPluginParams; +using blink::WebPoint; using blink::WebPopupMenuInfo; using blink::WebRange; using blink::WebRect; @@ -301,6 +311,10 @@ using blink::WebFloatPoint; using blink::WebFloatRect; #endif +#define STATIC_ASSERT_ENUM(a, b) \ + static_assert(static_cast<int>(a) == static_cast<int>(b), \ + "mismatching enums: " #a) + namespace content { namespace { @@ -522,10 +536,11 @@ WebURLRequest CreateURLRequestForNavigation( } request.setHTTPMethod(WebString::fromUTF8(common_params.method)); + request.setLoFiState( + static_cast<WebURLRequest::LoFiState>(common_params.lofi_state)); RequestExtraData* extra_data = new RequestExtraData(); extra_data->set_stream_override(std::move(stream_override)); - extra_data->set_lofi_state(common_params.lofi_state); request.setExtraData(extra_data); // Set the ui timestamp for this navigation. Currently the timestamp here is @@ -597,8 +612,9 @@ CommonNavigationParams MakeCommonNavigationParams( return CommonNavigationParams( request->url(), referrer, extra_data->transition_type(), FrameMsg_Navigate_Type::NORMAL, true, should_replace_current_entry, - ui_timestamp, report_type, GURL(), GURL(), extra_data->lofi_state(), - base::TimeTicks::Now(), request->httpMethod().latin1()); + ui_timestamp, report_type, GURL(), GURL(), + static_cast<LoFiState>(request->getLoFiState()),base::TimeTicks::Now(), + request->httpMethod().latin1(), GetRequestBodyForWebURLRequest(*request)); } media::Context3D GetSharedMainThreadContext3D( @@ -648,7 +664,7 @@ RenderFrameImpl::CreateRenderFrameImplFunction g_create_render_frame_impl = nullptr; void OnGotInstanceID(shell::mojom::ConnectResult result, - const std::string& user_id, + mojo::String user_id, uint32_t instance_id) {} WebString ConvertRelativePathToHtmlAttribute(const base::FilePath& path) { @@ -739,6 +755,12 @@ class MHTMLPartsGenerationDelegate return WebString::fromUTF8(content_id); } + blink::WebFrameSerializerCacheControlPolicy cacheControlPolicy() override { + return params_.mhtml_cache_control_policy; + } + + bool useBinaryEncoding() override { return params_.mhtml_binary_encoding; } + private: const FrameMsg_SerializeAsMHTML_Params& params_; std::set<std::string>* digests_of_uris_of_serialized_resources_; @@ -793,6 +815,10 @@ bool IsContentWithCertificateErrorsRelevantToUI( ssl_status.connection_status); } +bool IsHttpPost(const blink::WebURLRequest& request) { + return request.httpMethod().utf8() == "POST"; +} + #if defined(OS_ANDROID) // Returns true if WMPI should be used for playback, false otherwise. // @@ -840,6 +866,14 @@ bool UseMojoCdm() { } // namespace +struct RenderFrameImpl::PendingFileChooser { + PendingFileChooser(const FileChooserParams& p, + blink::WebFileChooserCompletion* c) + : params(p), completion(c) {} + FileChooserParams params; + blink::WebFileChooserCompletion* completion; // MAY BE NULL to skip callback. +}; + // static RenderFrameImpl* RenderFrameImpl::Create(RenderViewImpl* render_view, int32_t routing_id) { @@ -887,9 +921,6 @@ RenderFrameImpl* RenderFrameImpl::CreateMainFrame( render_view->webview()->setMainFrame(web_frame); render_frame->render_widget_ = RenderWidget::CreateForFrame( widget_routing_id, hidden, screen_info, compositor_deps, web_frame); - // TODO(kenrb): Observing shouldn't be necessary when we sort out - // WasShown and WasHidden, separating page-level visibility from - // frame-level visibility. // TODO(avi): This DCHECK is to track cleanup for https://crbug.com/545684 DCHECK_EQ(render_view->GetWidget(), render_frame->render_widget_) << "Main frame is no longer reusing the RenderView as its widget! " @@ -952,8 +983,7 @@ void RenderFrameImpl::CreateFrame( render_frame->InitializeBlameContext(nullptr); render_frame->proxy_routing_id_ = proxy_routing_id; web_frame = blink::WebLocalFrame::createProvisional( - render_frame, proxy->web_frame(), replicated_state.sandbox_flags, - frame_owner_properties); + render_frame, proxy->web_frame(), replicated_state.sandbox_flags); } render_frame->BindToWebFrame(web_frame); CHECK(parent_routing_id != MSG_ROUTING_NONE || !web_frame->parent()); @@ -967,12 +997,8 @@ void RenderFrameImpl::CreateFrame( // TODO(avi): The main frame re-uses the RenderViewImpl as its widget, so // avoid double-registering the frame as an observer. // https://crbug.com/545684 - if (web_frame->parent()) { - // TODO(kenrb): Observing shouldn't be necessary when we sort out - // WasShown and WasHidden, separating page-level visibility from - // frame-level visibility. + if (web_frame->parent()) render_frame->render_widget_->RegisterRenderFrame(render_frame); - } } render_frame->Initialize(); @@ -1037,7 +1063,6 @@ RenderFrameImpl::RenderFrameImpl(const CreateParams& params) in_frame_tree_(false), render_view_(params.render_view->AsWeakPtr()), routing_id_(params.routing_id), - is_detaching_(false), proxy_routing_id_(MSG_ROUTING_NONE), #if defined(ENABLE_PLUGINS) plugin_power_saver_helper_(nullptr), @@ -1064,11 +1089,10 @@ RenderFrameImpl::RenderFrameImpl(const CreateParams& params) devtools_agent_(nullptr), push_messaging_dispatcher_(NULL), presentation_dispatcher_(NULL), - blink_service_registry_(service_registry_.GetWeakPtr()), screen_orientation_dispatcher_(NULL), manifest_manager_(NULL), accessibility_mode_(AccessibilityModeOff), - renderer_accessibility_(NULL), + render_accessibility_(NULL), media_player_delegate_(NULL), is_using_lofi_(false), effective_connection_type_( @@ -1080,7 +1104,19 @@ RenderFrameImpl::RenderFrameImpl(const CreateParams& params) focused_pepper_plugin_(nullptr), pepper_last_mouse_event_target_(nullptr), #endif + frame_binding_(this), weak_factory_(this) { + // We don't have a shell::Connection at this point, so use nullptr. + // TODO(beng): We should fix this, so we can apply policy about which + // interfaces get exposed. + interface_registry_.reset(new shell::InterfaceRegistry(nullptr)); + shell::mojom::InterfaceProviderPtr remote_interfaces; + pending_remote_interface_provider_request_ = GetProxy(&remote_interfaces); + remote_interfaces_.reset(new shell::InterfaceProvider); + remote_interfaces_->Bind(std::move(remote_interfaces)); + blink_service_registry_.reset(new BlinkServiceRegistryImpl( + remote_interfaces_->GetWeakPtr())); + std::pair<RoutingIDFrameMap::iterator, bool> result = g_routing_id_frame_map.Get().insert(std::make_pair(routing_id_, this)); CHECK(result.second) << "Inserting a duplicate item."; @@ -1104,6 +1140,15 @@ RenderFrameImpl::RenderFrameImpl(const CreateParams& params) } RenderFrameImpl::~RenderFrameImpl() { + // If file chooser is still waiting for answer, dispatch empty answer. + while (!file_chooser_completions_.empty()) { + if (file_chooser_completions_.front()->completion) { + file_chooser_completions_.front()->completion->didChooseFile( + WebVector<WebString>()); + } + file_chooser_completions_.pop_front(); + } + FOR_EACH_OBSERVER(RenderFrameObserver, observers_, RenderFrameGone()); FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnDestruct()); @@ -1176,7 +1221,7 @@ void RenderFrameImpl::Initialize() { devtools_agent_ = new DevToolsAgent(this); } - RegisterMojoServices(); + RegisterMojoInterfaces(); // We delay calling this until we have the WebFrame so that any observer or // embedder can call GetWebFrame on any RenderFrame. @@ -1194,7 +1239,7 @@ void RenderFrameImpl::Initialize() { void RenderFrameImpl::InitializeBlameContext(RenderFrameImpl* parent_frame) { DCHECK(!blame_context_); - blame_context_ = new FrameBlameContext(this, parent_frame); + blame_context_ = base::WrapUnique(new FrameBlameContext(this, parent_frame)); blame_context_->Initialize(); } @@ -1392,15 +1437,10 @@ MediaStreamDispatcher* RenderFrameImpl::GetMediaStreamDispatcher() { } bool RenderFrameImpl::Send(IPC::Message* message) { - if (is_detaching_) { - delete message; - return false; - } - return RenderThread::Get()->Send(message); } -#if defined(OS_MACOSX) || defined(OS_ANDROID) +#if defined(USE_EXTERNAL_POPUP_MENU) void RenderFrameImpl::DidHideExternalPopupMenu() { // We need to clear external_popup_menu_ as soon as ExternalPopupMenu::close // is called. Otherwise, createExternalPopupMenu() for new popup will fail. @@ -1447,6 +1487,9 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(FrameMsg_ContextMenuClosed, OnContextMenuClosed) IPC_MESSAGE_HANDLER(FrameMsg_CustomContextMenuAction, OnCustomContextMenuAction) +#if defined(ENABLE_PLUGINS) + IPC_MESSAGE_HANDLER(FrameMsg_SetPepperVolume, OnSetPepperVolume) +#endif //defined(ENABLE_PLUGINS) IPC_MESSAGE_HANDLER(InputMsg_Undo, OnUndo) IPC_MESSAGE_HANDLER(InputMsg_Redo, OnRedo) IPC_MESSAGE_HANDLER(InputMsg_Cut, OnCut) @@ -1463,6 +1506,8 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) { OnMoveRangeSelectionExtent) IPC_MESSAGE_HANDLER(InputMsg_Replace, OnReplace) IPC_MESSAGE_HANDLER(InputMsg_ReplaceMisspelling, OnReplaceMisspelling) + IPC_MESSAGE_HANDLER(FrameMsg_CopyImageAt, OnCopyImageAt) + IPC_MESSAGE_HANDLER(FrameMsg_SaveImageAt, OnSaveImageAt) IPC_MESSAGE_HANDLER(InputMsg_ExtendSelectionAndDelete, OnExtendSelectionAndDelete) IPC_MESSAGE_HANDLER(InputMsg_SetCompositionFromExistingText, @@ -1506,17 +1551,29 @@ bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) { OnGetSerializedHtmlWithLocalLinks) IPC_MESSAGE_HANDLER(FrameMsg_SerializeAsMHTML, OnSerializeAsMHTML) IPC_MESSAGE_HANDLER(FrameMsg_Find, OnFind) + IPC_MESSAGE_HANDLER(FrameMsg_ClearActiveFindMatch, OnClearActiveFindMatch) IPC_MESSAGE_HANDLER(FrameMsg_StopFinding, OnStopFinding) IPC_MESSAGE_HANDLER(FrameMsg_EnableViewSourceMode, OnEnableViewSourceMode) IPC_MESSAGE_HANDLER(FrameMsg_SuppressFurtherDialogs, OnSuppressFurtherDialogs) + IPC_MESSAGE_HANDLER(FrameMsg_RunFileChooserResponse, OnFileChooserResponse) #if defined(OS_ANDROID) - IPC_MESSAGE_HANDLER(InputMsg_ActivateNearestFindResult, + IPC_MESSAGE_HANDLER(FrameMsg_ActivateNearestFindResult, OnActivateNearestFindResult) + IPC_MESSAGE_HANDLER(FrameMsg_GetNearestFindResult, + OnGetNearestFindResult) IPC_MESSAGE_HANDLER(FrameMsg_FindMatchRects, OnFindMatchRects) - IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItems, OnSelectPopupMenuItems) -#elif defined(OS_MACOSX) +#endif + +#if defined(USE_EXTERNAL_POPUP_MENU) +#if defined(OS_MACOSX) IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItem, OnSelectPopupMenuItem) +#else + IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItems, OnSelectPopupMenuItems) +#endif +#endif + +#if defined(OS_MACOSX) IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard, OnCopyToFindPboard) #endif IPC_END_MESSAGE_MAP() @@ -1552,11 +1609,12 @@ void RenderFrameImpl::OnNavigate( std::unique_ptr<StreamOverrideParameters>()); } -void RenderFrameImpl::BindServiceRegistry( - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) { - service_registry_.Bind(std::move(services)); - service_registry_.BindRemoteServiceProvider(std::move(exposed_services)); +void RenderFrameImpl::Bind(mojom::FrameRequest request, + mojom::FrameHostPtr host) { + frame_binding_.Bind(std::move(request)); + frame_host_ = std::move(host); + frame_host_->GetInterfaceProvider( + std::move(pending_remote_interface_provider_request_)); } ManifestManager* RenderFrameImpl::manifest_manager() { @@ -1568,7 +1626,7 @@ void RenderFrameImpl::SetPendingNavigationParams( pending_navigation_params_ = std::move(navigation_params); } -void RenderFrameImpl::OnBeforeUnload() { +void RenderFrameImpl::OnBeforeUnload(bool is_reload) { TRACE_EVENT1("navigation", "RenderFrameImpl::OnBeforeUnload", "id", routing_id_); // TODO(creis): Right now, this is only called on the main frame. Make the @@ -1577,11 +1635,10 @@ void RenderFrameImpl::OnBeforeUnload() { CHECK(!frame_->parent()); base::TimeTicks before_unload_start_time = base::TimeTicks::Now(); - bool proceed = frame_->dispatchBeforeUnloadEvent(); + bool proceed = frame_->dispatchBeforeUnloadEvent(is_reload); base::TimeTicks before_unload_end_time = base::TimeTicks::Now(); - Send(new FrameHostMsg_BeforeUnload_ACK(routing_id_, proceed, - before_unload_start_time, - before_unload_end_time)); + Send(new FrameHostMsg_BeforeUnload_ACK( + routing_id_, proceed, before_unload_start_time, before_unload_end_time)); } void RenderFrameImpl::OnSwapOut( @@ -1626,14 +1683,6 @@ void RenderFrameImpl::OnSwapOut( if (!is_main_frame_) proxy->web_frame()->initializeFromFrame(frame_); - // Let WebKit know that this view is hidden so it can drop resources and - // stop compositing. - // TODO(creis): Support this for subframes as well. - if (is_main_frame_) { - render_view_->webview()->setVisibilityState( - blink::WebPageVisibilityStateHidden, false); - } - RenderViewImpl* render_view = render_view_.get(); bool is_main_frame = is_main_frame_; int routing_id = GetRoutingID(); @@ -1851,6 +1900,14 @@ void RenderFrameImpl::OnReplaceMisspelling(const base::string16& text) { frame_->replaceMisspelledRange(text); } +void RenderFrameImpl::OnCopyImageAt(int x, int y) { + frame_->copyImageAt(WebPoint(x, y)); +} + +void RenderFrameImpl::OnSaveImageAt(int x, int y) { + frame_->saveImageAt(WebPoint(x, y)); +} + void RenderFrameImpl::OnCSSInsertRequest(const std::string& css) { frame_->document().insertStyleSheet(WebString::fromUTF8(css)); } @@ -2031,25 +2088,25 @@ void RenderFrameImpl::OnSetAccessibilityMode(AccessibilityMode new_mode) { if (accessibility_mode_ == new_mode) return; accessibility_mode_ = new_mode; - if (renderer_accessibility_) { + if (render_accessibility_) { // Note: this isn't called automatically by the destructor because // there'd be no point in calling it in frame teardown, only if there's // an accessibility mode change but the frame is persisting. - renderer_accessibility_->DisableAccessibility(); + render_accessibility_->DisableAccessibility(); - delete renderer_accessibility_; - renderer_accessibility_ = NULL; + delete render_accessibility_; + render_accessibility_ = NULL; } if (accessibility_mode_ == AccessibilityModeOff) return; if (accessibility_mode_ & AccessibilityModeFlagFullTree) - renderer_accessibility_ = new RendererAccessibility(this); + render_accessibility_ = new RenderAccessibilityImpl(this); } void RenderFrameImpl::OnSnapshotAccessibilityTree(int callback_id) { AXContentTreeUpdate response; - RendererAccessibility::SnapshotAccessibilityTree(this, &response); + RenderAccessibilityImpl::SnapshotAccessibilityTree(this, &response); Send(new AccessibilityHostMsg_SnapshotResponse( routing_id_, callback_id, response)); } @@ -2214,6 +2271,31 @@ bool RenderFrameImpl::RunJavaScriptMessage(JavaScriptMessageType type, return success; } +bool RenderFrameImpl::ScheduleFileChooser( + const FileChooserParams& params, + blink::WebFileChooserCompletion* completion) { + static const size_t kMaximumPendingFileChooseRequests = 4; + if (file_chooser_completions_.size() > kMaximumPendingFileChooseRequests) { + // This sanity check prevents too many file choose requests from getting + // queued which could DoS the user. Getting these is most likely a + // programming error (there are many ways to DoS the user so it's not + // considered a "real" security check), either in JS requesting many file + // choosers to pop up, or in a plugin. + // + // TODO(brettw): We might possibly want to require a user gesture to open + // a file picker, which will address this issue in a better way. + return false; + } + + file_chooser_completions_.push_back( + base::WrapUnique(new PendingFileChooser(params, completion))); + if (file_chooser_completions_.size() == 1) { + // Actually show the browse dialog when this is the first request. + Send(new FrameHostMsg_RunFileChooser(routing_id_, params)); + } + return true; +} + void RenderFrameImpl::LoadNavigationErrorPage( const WebURLRequest& failed_request, const WebURLError& error, @@ -2258,6 +2340,10 @@ RenderView* RenderFrameImpl::GetRenderView() { return render_view_.get(); } +RenderAccessibility* RenderFrameImpl::GetRenderAccessibility() { + return render_accessibility_; +} + int RenderFrameImpl::GetRoutingID() { return routing_id_; } @@ -2334,8 +2420,12 @@ void RenderFrameImpl::ExecuteJavaScript(const base::string16& javascript) { OnJavaScriptExecuteRequest(javascript, 0, false); } -ServiceRegistry* RenderFrameImpl::GetServiceRegistry() { - return &service_registry_; +shell::InterfaceRegistry* RenderFrameImpl::GetInterfaceRegistry() { + return interface_registry_.get(); +} + +shell::InterfaceProvider* RenderFrameImpl::GetRemoteInterfaces() { + return remote_interfaces_.get(); } #if defined(ENABLE_PLUGINS) @@ -2398,13 +2488,14 @@ void RenderFrameImpl::EnsureMojoBuiltinsAreAvailable( registry->AddBuiltinModule(isolate, mojo::edk::js::Support::kModuleName, mojo::edk::js::Support::GetModule(isolate)); registry->AddBuiltinModule( - isolate, ServiceRegistryJsWrapper::kPerFrameModuleName, - ServiceRegistryJsWrapper::Create(isolate, context, &service_registry_) + isolate, InterfaceProviderJsWrapper::kPerFrameModuleName, + InterfaceProviderJsWrapper::Create( + isolate, context, remote_interfaces_.get()) .ToV8()); registry->AddBuiltinModule( - isolate, ServiceRegistryJsWrapper::kPerProcessModuleName, - ServiceRegistryJsWrapper::Create( - isolate, context, RenderThread::Get()->GetServiceRegistry()) + isolate, InterfaceProviderJsWrapper::kPerProcessModuleName, + InterfaceProviderJsWrapper::Create( + isolate, context, RenderThread::Get()->GetRemoteInterfaces()) .ToV8()); } @@ -2439,6 +2530,13 @@ bool RenderFrameImpl::IsPasting() const { return is_pasting_; } +// mojom::Frame implementation ------------------------------------------------- + +void RenderFrameImpl::GetInterfaceProvider( + shell::mojom::InterfaceProviderRequest request) { + interface_registry_->Bind(std::move(request)); +} + // blink::WebFrameClient implementation ---------------------------------------- blink::WebPlugin* RenderFrameImpl::createPlugin( @@ -2520,7 +2618,9 @@ blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer( &GetSharedMainThreadContext3D, RenderThreadImpl::current()->SharedMainThreadContextProvider()); - scoped_refptr<media::MediaLog> media_log(new RenderMediaLog()); + scoped_refptr<media::MediaLog> media_log(new RenderMediaLog( + blink::WebStringToGURL(frame_->getSecurityOrigin().toString()))); + #if defined(OS_ANDROID) if (UseWebMediaPlayerImpl(url) && !media_surface_manager_) media_surface_manager_ = new RendererSurfaceViewManager(this); @@ -2558,8 +2658,7 @@ blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer( media_renderer_factory.reset(new media::DefaultRendererFactory( media_log, GetDecoderFactory(), base::Bind(&RenderThreadImpl::GetGpuFactories, - base::Unretained(render_thread)), - *render_thread->GetAudioHardwareConfig())); + base::Unretained(render_thread)))); } #endif // defined(ENABLE_MOJO_RENDERER) @@ -2607,7 +2706,7 @@ RenderFrameImpl::createWorkerContentSettingsClientProxy() { WebExternalPopupMenu* RenderFrameImpl::createExternalPopupMenu( const WebPopupMenuInfo& popup_menu_info, WebExternalPopupMenuClient* popup_menu_client) { -#if defined(OS_MACOSX) || defined(OS_ANDROID) +#if defined(USE_EXTERNAL_POPUP_MENU) // An IPC message is sent to the browser to build and display the actual // popup. The user could have time to click a different select by the time // the popup is shown. In that case external_popup_menu_ is non NULL. @@ -2635,7 +2734,7 @@ blink::WebCookieJar* RenderFrameImpl::cookieJar() { blink::BlameContext* RenderFrameImpl::frameBlameContext() { DCHECK(blame_context_); - return blame_context_; + return blame_context_.get(); } blink::WebServiceWorkerProvider* @@ -2658,6 +2757,9 @@ RenderFrameImpl::createServiceWorkerProvider() { } void RenderFrameImpl::didAccessInitialDocument() { + // NOTE: Do not call back into JavaScript here, since this call is made from a + // V8 security check. + // If the request hasn't yet committed, notify the browser process that it is // no longer safe to show the pending URL of the main frame, since a URL spoof // is now possible. (If the request has committed, the browser already knows.) @@ -2738,7 +2840,6 @@ void RenderFrameImpl::frameDetached(blink::WebFrame* frame, DetachType type) { // NOTE: This function is called on the frame that is being detached and not // the parent frame. This is different from createChildFrame() which is // called on the parent frame. - CHECK(!is_detaching_); DCHECK_EQ(frame_, frame); FOR_EACH_OBSERVER(RenderFrameObserver, observers_, FrameDetached()); @@ -2750,10 +2851,6 @@ void RenderFrameImpl::frameDetached(blink::WebFrame* frame, DetachType type) { if (!in_browser_initiated_detach_ && type == DetachType::Remove) Send(new FrameHostMsg_Detach(routing_id_)); - // The |is_detaching_| flag disables Send(). FrameHostMsg_Detach must be - // sent before setting |is_detaching_| to true. - is_detaching_ = true; - // Clean up the associated RenderWidget for the frame, if there is one. if (render_widget_) { render_widget_->UnregisterRenderFrame(this); @@ -2818,8 +2915,9 @@ void RenderFrameImpl::didChangeName(const blink::WebString& name, } } -void RenderFrameImpl::didEnforceStrictMixedContentChecking() { - Send(new FrameHostMsg_EnforceStrictMixedContentChecking(routing_id_)); +void RenderFrameImpl::didEnforceInsecureRequestPolicy( + blink::WebInsecureRequestPolicy policy) { + Send(new FrameHostMsg_EnforceInsecureRequestPolicy(routing_id_, policy)); } void RenderFrameImpl::didUpdateToUniqueOrigin( @@ -2915,13 +3013,13 @@ void RenderFrameImpl::loadURLExternally(const blink::WebURLRequest& request, bool should_replace_current_entry) { Referrer referrer(RenderViewImpl::GetReferrerFromRequest(frame_, request)); if (policy == blink::WebNavigationPolicyDownload) { - render_view_->Send(new ViewHostMsg_DownloadUrl(render_view_->GetRoutingID(), - GetRoutingID(), - request.url(), referrer, - suggested_name)); + Send(new FrameHostMsg_DownloadUrl(render_view_->GetRoutingID(), + GetRoutingID(), request.url(), referrer, + suggested_name)); } else { - OpenURL(request.url(), referrer, policy, should_replace_current_entry, - false); + OpenURL(request.url(), IsHttpPost(request), + GetRequestBodyForWebURLRequest(request), referrer, policy, + should_replace_current_entry, false); } } @@ -3072,9 +3170,8 @@ void RenderFrameImpl::didCreateDataSource(blink::WebLocalFrame* frame, ServiceWorkerNetworkProvider::AttachToDocumentState( DocumentState::FromDataSource(datasource), - ServiceWorkerNetworkProvider::CreateForNavigation( - routing_id_, navigation_state->request_params(), frame, - content_initiated)); + ServiceWorkerNetworkProvider::CreateForNavigation(routing_id_, frame, + content_initiated)); } void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame* frame, @@ -3740,6 +3837,37 @@ bool RenderFrameImpl::runModalBeforeUnloadDialog(bool is_reload) { return success; } +bool RenderFrameImpl::runFileChooser( + const blink::WebFileChooserParams& params, + blink::WebFileChooserCompletion* chooser_completion) { + // Do not open the file dialog in a hidden RenderFrame. + if (IsHidden()) + return false; + + FileChooserParams ipc_params; + if (params.directory) + ipc_params.mode = FileChooserParams::UploadFolder; + else if (params.multiSelect) + ipc_params.mode = FileChooserParams::OpenMultiple; + else if (params.saveAs) + ipc_params.mode = FileChooserParams::Save; + else + ipc_params.mode = FileChooserParams::Open; + ipc_params.title = params.title; + ipc_params.default_file_name = + blink::WebStringToFilePath(params.initialValue).BaseName(); + ipc_params.accept_types.reserve(params.acceptTypes.size()); + for (const auto& type : params.acceptTypes) + ipc_params.accept_types.push_back(type); + ipc_params.need_local_path = params.needLocalPath; +#if defined(OS_ANDROID) + ipc_params.capture = params.useMediaCapture; +#endif + ipc_params.requestor = params.requestor; + + return ScheduleFileChooser(ipc_params, chooser_completion); +} + void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) { ContextMenuParams params = ContextMenuParamsBuilder::Build(data); blink::WebRect position_in_window(params.x, params.y, 0, 0); @@ -3773,6 +3901,15 @@ void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) { Send(new FrameHostMsg_ContextMenu(routing_id_, params)); } +void RenderFrameImpl::saveImageFromDataURL(const blink::WebString& data_url) { + // Note: We should basically send GURL but we use size-limited string instead + // in order to send a larger data url to save a image for <canvas> or <img>. + if (data_url.length() < kMaxLengthOfDataURLString) { + Send(new FrameHostMsg_SaveImageFromDataURL( + render_view_->GetRoutingID(), routing_id_, data_url.utf8())); + } +} + void RenderFrameImpl::willSendRequest( blink::WebLocalFrame* frame, unsigned identifier, @@ -3787,20 +3924,20 @@ void RenderFrameImpl::willSendRequest( // requests). This value will be updated during redirects, consistent with // https://tools.ietf.org/html/draft-west-first-party-cookies-04#section-2.1.1 if (request.firstPartyForCookies().isEmpty()) { - if (request.getFrameType() == blink::WebURLRequest::FrameTypeTopLevel) { + if (request.getFrameType() == blink::WebURLRequest::FrameTypeTopLevel) request.setFirstPartyForCookies(request.url()); - } else { - // TODO(nasko): When the top-level frame is remote, there is no document. - // This is broken and should be fixed to propagate the first party. - WebFrame* top = frame->top(); - if (top->isWebLocalFrame()) { - request.setFirstPartyForCookies( - frame->top()->document().firstPartyForCookies()); - } - } + else + request.setFirstPartyForCookies(frame->document().firstPartyForCookies()); + } - // If we need to set the first party, then we need to set the request's - // initiator as well; it will not be updated during redirects. + // Set the requestor origin to the same origin as the frame's document if it + // hasn't yet been set. + // + // TODO(mkwst): It would be cleaner to adjust blink::ResourceRequest to + // initialize itself with a `nullptr` initiator so that this can be a simple + // `isNull()` check. + if (request.requestorOrigin().isUnique() && + !frame->document().getSecurityOrigin().isUnique()) { request.setRequestorOrigin(frame->document().getSecurityOrigin()); } @@ -3894,15 +4031,18 @@ void RenderFrameImpl::willSendRequest( provider_id = provider->provider_id(); // Explicitly set the SkipServiceWorker flag here if the renderer process // hasn't received SetControllerServiceWorker message. - if (!provider->IsControlledByServiceWorker()) - request.setSkipServiceWorker(true); + if (!provider->IsControlledByServiceWorker() && + request.skipServiceWorker() != + blink::WebURLRequest::SkipServiceWorker::All) + request.setSkipServiceWorker( + blink::WebURLRequest::SkipServiceWorker::Controlling); } WebFrame* parent = frame->parent(); int parent_routing_id = parent ? GetRoutingIdForFrameOrProxy(parent) : -1; RequestExtraData* extra_data = new RequestExtraData(); - extra_data->set_visibility_state(render_view_->visibilityState()); + extra_data->set_visibility_state(visibilityState()); extra_data->set_custom_user_agent(custom_user_agent); extra_data->set_requested_with(requested_with); extra_data->set_render_frame_id(routing_id_); @@ -3921,14 +4061,21 @@ void RenderFrameImpl::willSendRequest( navigation_state->start_params().transferred_request_request_id); extra_data->set_service_worker_provider_id(provider_id); extra_data->set_stream_override(std::move(stream_override)); - if (request.getLoFiState() != WebURLRequest::LoFiUnspecified) - extra_data->set_lofi_state(static_cast<LoFiState>(request.getLoFiState())); - else if (is_main_frame_ && !navigation_state->request_committed()) - extra_data->set_lofi_state(navigation_state->common_params().lofi_state); - else - extra_data->set_lofi_state(is_using_lofi_ ? LOFI_ON : LOFI_OFF); + WebString error; + extra_data->set_initiated_in_secure_context( + frame->document().isSecureContext(error)); request.setExtraData(extra_data); + if (request.getLoFiState() == WebURLRequest::LoFiUnspecified) { + if (is_main_frame_ && !navigation_state->request_committed()) { + request.setLoFiState(static_cast<WebURLRequest::LoFiState>( + navigation_state->common_params().lofi_state)); + } else { + request.setLoFiState( + is_using_lofi_ ? WebURLRequest::LoFiOn : WebURLRequest::LoFiOff); + } + } + // TODO(creis): Update prefetching to work with out-of-process iframes. WebFrame* top_frame = frame->top(); if (top_frame && top_frame->isWebLocalFrame()) { @@ -4113,20 +4260,19 @@ void RenderFrameImpl::willInsertBody(blink::WebLocalFrame* frame) { void RenderFrameImpl::reportFindInPageMatchCount(int request_id, int count, bool final_update) { - int active_match_ordinal = -1; // -1 = don't update active match ordinal - if (!count) - active_match_ordinal = 0; + // -1 here means don't update the active match ordinal. + int active_match_ordinal = count ? -1 : 0; - Send(new FrameHostMsg_Find_Reply(routing_id_, request_id, count, gfx::Rect(), - active_match_ordinal, final_update)); + SendFindReply(request_id, count, active_match_ordinal, gfx::Rect(), + final_update); } void RenderFrameImpl::reportFindInPageSelection( int request_id, int active_match_ordinal, const blink::WebRect& selection_rect) { - Send(new FrameHostMsg_Find_Reply(routing_id_, request_id, -1, selection_rect, - active_match_ordinal, false)); + SendFindReply(request_id, -1 /* match_count */, active_match_ordinal, + selection_rect, false /* final_status_update */); } void RenderFrameImpl::requestStorageQuota( @@ -4278,8 +4424,8 @@ void RenderFrameImpl::handleAccessibilityFindInPageResult( int start_offset, const blink::WebAXObject& end_object, int end_offset) { - if (renderer_accessibility_) { - renderer_accessibility_->HandleAccessibilityFindInPageResult( + if (render_accessibility_) { + render_accessibility_->HandleAccessibilityFindInPageResult( identifier, match_index, start_object, start_offset, end_object, end_offset); } @@ -4300,9 +4446,10 @@ bool RenderFrameImpl::exitFullscreen() { } blink::WebPermissionClient* RenderFrameImpl::permissionClient() { - if (!permission_client_) - permission_client_.reset(new PermissionDispatcher(GetServiceRegistry())); - + if (!permission_client_) { + permission_client_.reset( + new PermissionDispatcher(GetRemoteInterfaces())); + } return permission_client_.get(); } @@ -4338,13 +4485,8 @@ void RenderFrameImpl::unregisterProtocolHandler(const WebString& scheme, } blink::WebBluetooth* RenderFrameImpl::bluetooth() { - // ChildThreadImpl::current() is null in some tests. - if (!bluetooth_ && ChildThreadImpl::current()) { - bluetooth_.reset(new WebBluetoothImpl( - GetServiceRegistry(), ChildThreadImpl::current()->thread_safe_sender(), - routing_id_)); - } - + if (!bluetooth_.get()) + bluetooth_.reset(new WebBluetoothImpl(GetRemoteInterfaces())); return bluetooth_.get(); } @@ -4381,27 +4523,25 @@ void RenderFrameImpl::WasHidden() { for (auto* plugin : active_pepper_instances_) plugin->PageVisibilityChanged(false); #endif // ENABLE_PLUGINS + + if (GetWebFrame()->frameWidget()) { + static_cast<blink::WebFrameWidget*>(GetWebFrame()->frameWidget()) + ->setVisibilityState(visibilityState()); + } } void RenderFrameImpl::WasShown() { - // TODO(kenrb): Need to figure out how to do this better. Should - // VisibilityState remain a page-level concept or move to frames? - // The semantics of 'Show' might have to change here. - // TODO(avi): This DCHECK is to track cleanup for https://crbug.com/545684 - DCHECK(!IsMainFrame() || render_widget_.get() == render_view_.get()) - << "The main render frame is no longer reusing the RenderView as its " - << "RenderWidget!"; - if (render_widget_ && render_widget_->webwidget() && - render_view_.get() != render_widget_.get()) { - static_cast<blink::WebFrameWidget*>(render_widget_->webwidget())-> - setVisibilityState(blink::WebPageVisibilityStateVisible, false); - } FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasShown()); #if defined(ENABLE_PLUGINS) for (auto* plugin : active_pepper_instances_) plugin->PageVisibilityChanged(true); #endif // ENABLE_PLUGINS + + if (GetWebFrame()->frameWidget()) { + static_cast<blink::WebFrameWidget*>(GetWebFrame()->frameWidget()) + ->setVisibilityState(visibilityState()); + } } void RenderFrameImpl::WidgetWillClose() { @@ -4472,8 +4612,7 @@ void RenderFrameImpl::SendDidCommitProvisionalLoad( // RenderFrameProxies in other processes. params.origin = frame->document().getSecurityOrigin(); - params.should_enforce_strict_mixed_content_checking = - frame->shouldEnforceStrictMixedContentChecking(); + params.insecure_request_policy = frame->getInsecureRequestPolicy(); params.has_potentially_trustworthy_unique_origin = frame->document().getSecurityOrigin().isUnique() && @@ -4665,8 +4804,8 @@ void RenderFrameImpl::didChangeLoadProgress(double load_progress) { void RenderFrameImpl::HandleWebAccessibilityEvent( const blink::WebAXObject& obj, blink::WebAXEvent event) { - if (renderer_accessibility_) - renderer_accessibility_->HandleWebAccessibilityEvent(obj, event); + if (render_accessibility_) + render_accessibility_->HandleWebAccessibilityEvent(obj, event); } void RenderFrameImpl::FocusedNodeChanged(const WebNode& node) { @@ -4674,8 +4813,8 @@ void RenderFrameImpl::FocusedNodeChanged(const WebNode& node) { } void RenderFrameImpl::FocusedNodeChangedForAccessibility(const WebNode& node) { - if (renderer_accessibility()) - renderer_accessibility()->AccessibilityFocusedNodeChanged(node); + if (render_accessibility()) + render_accessibility()->AccessibilityFocusedNodeChanged(node); } // PlzNavigate @@ -4793,8 +4932,9 @@ WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation( if (is_content_initiated && IsTopLevelNavigation(frame_) && render_view_->renderer_preferences_ .browser_handles_all_top_level_requests) { - OpenURL(url, referrer, info.defaultPolicy, info.replacesCurrentHistoryItem, - false); + OpenURL(url, IsHttpPost(info.urlRequest), + GetRequestBodyForWebURLRequest(info.urlRequest), referrer, + info.defaultPolicy, info.replacesCurrentHistoryItem, false); return blink::WebNavigationPolicyIgnore; // Suppress the load here. } @@ -4803,8 +4943,9 @@ WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation( // FrameNavigationEntry. If none is found, fall back to the default url. if (SiteIsolationPolicy::UseSubframeNavigationEntries() && info.isHistoryNavigationInNewChildFrame && is_content_initiated) { - OpenURL(url, referrer, info.defaultPolicy, info.replacesCurrentHistoryItem, - true); + OpenURL(url, IsHttpPost(info.urlRequest), + GetRequestBodyForWebURLRequest(info.urlRequest), referrer, + info.defaultPolicy, info.replacesCurrentHistoryItem, true); // Suppress the load in Blink but mark the frame as loading. return blink::WebNavigationPolicyHandledByClient; } @@ -4819,15 +4960,6 @@ WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation( // an extension or app origin, leaving a WebUI page, etc). We only care about // top-level navigations (not iframes). But we sometimes navigate to // about:blank to clear a tab, and we want to still allow that. - // - // Note: this is known to break POST submissions when crossing process - // boundaries until http://crbug.com/101395 is fixed. This is better for - // security than loading a WebUI, extension or app page in the wrong process. - // POST requests don't work because this mechanism does not preserve form - // POST data. We will need to send the request's httpBody data up to the - // browser process, and issue a special POST navigation in WebKit (via - // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl - // for examples of how to send the httpBody data. if (!frame_->parent() && is_content_initiated && !url.SchemeIs(url::kAboutScheme)) { bool send_referrer = false; @@ -4867,7 +4999,9 @@ WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation( } if (should_fork) { - OpenURL(url, send_referrer ? referrer : Referrer(), info.defaultPolicy, + OpenURL(url, IsHttpPost(info.urlRequest), + GetRequestBodyForWebURLRequest(info.urlRequest), + send_referrer ? referrer : Referrer(), info.defaultPolicy, info.replacesCurrentHistoryItem, false); return blink::WebNavigationPolicyIgnore; // Suppress the load here. } @@ -4907,11 +5041,31 @@ WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation( if (is_fork) { // Open the URL via the browser, not via WebKit. - OpenURL(url, Referrer(), info.defaultPolicy, - info.replacesCurrentHistoryItem, false); + OpenURL(url, IsHttpPost(info.urlRequest), + GetRequestBodyForWebURLRequest(info.urlRequest), Referrer(), + info.defaultPolicy, info.replacesCurrentHistoryItem, false); return blink::WebNavigationPolicyIgnore; } + // Execute the BeforeUnload event. If asked not to proceed or the frame is + // destroyed, ignore the navigation. There is no need to execute the + // BeforeUnload event during a redirect, since it was already executed at the + // start of the navigation. + // PlzNavigate: this is not executed when commiting the navigation. + if (info.defaultPolicy == blink::WebNavigationPolicyCurrentTab && + !is_redirect && (!IsBrowserSideNavigationEnabled() || + info.urlRequest.checkForBrowserSideNavigation())) { + // Keep a WeakPtr to this RenderFrameHost to detect if executing the + // BeforeUnload event destriyed this frame. + base::WeakPtr<RenderFrameImpl> weak_self = weak_factory_.GetWeakPtr(); + + if (!frame_->dispatchBeforeUnloadEvent(info.navigationType == + blink::WebNavigationTypeReload) || + !weak_self) { + return blink::WebNavigationPolicyIgnore; + } + } + // PlzNavigate: if the navigation is not synchronous, send it to the browser. // This includes navigations with no request being sent to the network stack. if (IsBrowserSideNavigationEnabled() && @@ -4965,30 +5119,36 @@ void RenderFrameImpl::OnSerializeAsMHTML( DCHECK(!mhtml_boundary.isEmpty()); WebData data; - bool success = true; std::set<std::string> digests_of_uris_of_serialized_resources; MHTMLPartsGenerationDelegate delegate( params, &digests_of_uris_of_serialized_resources); + bool success = true; + // Generate MHTML header if needed. if (IsMainFrame()) { - blink::WebFrameSerializerCacheControlPolicy policy = - static_cast<blink::WebFrameSerializerCacheControlPolicy>( - params.mhtml_cache_control_policy); - success = WebFrameSerializer::generateMHTMLHeader(mhtml_boundary, policy, - GetWebFrame(), &data); - if (success && file.WriteAtCurrentPos(data.data(), data.size()) < 0) { + // |data| can be empty if the main frame should be skipped. If the main + // frame is + // skipped, then the whole archive is bad, so bail to the error condition. + WebData data = WebFrameSerializer::generateMHTMLHeader( + mhtml_boundary, GetWebFrame(), &delegate); + if (data.isEmpty() || + file.WriteAtCurrentPos(data.data(), data.size()) < 0) { success = false; } } - // Generate MHTML parts. + // Generate MHTML parts. Note that if this is not the main frame, then even + // skipping the whole parts generation step is not an error - it simply + // results in an omitted resource in the final file. if (success) { - data = WebFrameSerializer::generateMHTMLParts( - mhtml_boundary, GetWebFrame(), params.mhtml_binary_encoding, &delegate); + // |data| can be empty if the frame should be skipped, but this is OK. + data = WebFrameSerializer::generateMHTMLParts(mhtml_boundary, GetWebFrame(), + &delegate); // TODO(jcivelli): write the chunks in deferred tasks to give a chance to // the message loop to process other events. - if (file.WriteAtCurrentPos(data.data(), data.size()) < 0) { + if (!data.isEmpty() && + file.WriteAtCurrentPos(data.data(), data.size()) < 0) { success = false; } } @@ -5011,13 +5171,6 @@ void RenderFrameImpl::OnSerializeAsMHTML( void RenderFrameImpl::OnFind(int request_id, const base::string16& search_text, const WebFindOptions& options) { - // This should only be received on the main frame, since find-in-page is - // currently orchestrated by the main frame. - if (!is_main_frame_) { - NOTREACHED(); - return; - } - DCHECK(!search_text.empty()); blink::WebPlugin* plugin = GetWebPluginForFind(); @@ -5025,156 +5178,82 @@ void RenderFrameImpl::OnFind(int request_id, if (plugin) { if (options.findNext) { // Just navigate back/forward. - plugin->selectFindResult(options.forward); + plugin->selectFindResult(options.forward, request_id); } else { if (!plugin->startFind(search_text, options.matchCase, request_id)) { // Send "no results". - SendFindReply(request_id, 0, 0, gfx::Rect(), true); + SendFindReply(request_id, 0 /* match_count */, 0 /* ordinal */, + gfx::Rect(), true /* final_status_update */ ); } } return; } - WebLocalFrame* main_frame = GetWebFrame(); - WebLocalFrame* focused_frame = - render_view_->webview()->focusedFrame()->toWebLocalFrame(); - // Start searching in the focused frame. - WebLocalFrame* search_frame = focused_frame; - - // Check for multiple searchable frames. - bool multi_frame = (main_frame->traverseNextLocal(true) != main_frame); - - // If we have multiple frames, we don't want to wrap the search within the - // frame, so we check here if we only have |main_frame| in the chain. - bool wrap_within_frame = !multi_frame; + // Send "no results" if this frame has no visible content. + if (!frame_->hasVisibleContent()) { + SendFindReply(request_id, 0 /* match_count */, 0 /* ordinal */, + gfx::Rect(), true /* final_status_update */ ); + return; + } WebRect selection_rect; - bool result = false; bool active_now = false; // If something is selected when we start searching it means we cannot just // increment the current match ordinal; we need to re-generate it. - WebRange current_selection = focused_frame->selectionRange(); - - do { - result = - search_frame->find(request_id, search_text, options, wrap_within_frame, - &selection_rect, &active_now); - - if (!result) { - // Don't leave text selected as you move to the next frame. - search_frame->executeCommand(WebString::fromUTF8("Unselect")); - - // Find the next frame, but skip the invisible ones. - do { - // What is the next frame to search (we might be going backwards)? Note - // that we specify wrap=true so that search_frame never becomes NULL. - search_frame = options.forward - ? search_frame->traverseNextLocal(true) - : search_frame->traversePreviousLocal(true); - } while (!search_frame->hasVisibleContent() && - search_frame != focused_frame); - - // Make sure selection doesn't affect the search operation in new frame. - search_frame->executeCommand(WebString::fromUTF8("Unselect")); - - // If we have multiple frames and we have wrapped back around to the - // focused frame, we need to search it once more allowing wrap within - // the frame, otherwise it will report 'no match' if the focused frame has - // reported matches, but no frames after the focused_frame contain a - // match for the search word(s). - if (multi_frame && search_frame == focused_frame) { - result = search_frame->find(request_id, search_text, options, - true, // Force wrapping. - &selection_rect, &active_now); - } - } + WebRange current_selection = frame_->selectionRange(); - render_view_->webview()->setFocusedFrame(search_frame); - } while (!result && search_frame != focused_frame); + if (frame_->find(request_id, search_text, options, + false /* wrapWithinFrame */, &selection_rect, &active_now)) { + // Indicate that at least one match has been found. 1 here means possibly + // more matches could be coming. -1 here means that the exact active match + // ordinal is not yet known. + SendFindReply(request_id, 1 /* match_count */, -1 /* ordinal */, + gfx::Rect(), false /* final_status_update */ ); + } if (options.findNext && current_selection.isNull() && active_now) { - // Force the main_frame to report the actual count. - main_frame->increaseMatchCount(0, request_id); - } else { - // If nothing is found, set result to "0 of 0", otherwise, set it to - // "-1 of 1" to indicate that we found at least one item, but we don't know - // yet what is active. - int ordinal = result ? -1 : 0; // -1 here means we might know more later. - int match_count = result ? 1 : 0; // 1 here means possibly more coming. - - // If we find no matches then this will be our last status update. - // Otherwise the scoping effort will send more results. - bool final_status_update = !result; - - SendFindReply(request_id, match_count, ordinal, selection_rect, - final_status_update); - - // Scoping effort begins, starting with the main frame. - search_frame = main_frame; - - main_frame->resetMatchCount(); - - do { - // Cancel all old scoping requests before starting a new one. - search_frame->cancelPendingScopingEffort(); - - // We don't start another scoping effort unless at least one match has - // been found. - if (result) { - // Start new scoping request. If the scoping function determines that it - // needs to scope, it will defer until later. - search_frame->scopeStringMatches(request_id, search_text, options, - true); // reset the tickmarks - } - - // Iterate to the next frame. The frame will not necessarily scope, for - // example if it is not visible. - search_frame = search_frame->traverseNextLocal(true); - } while (search_frame != main_frame); + // Force report of the actual count. + frame_->increaseMatchCount(0, request_id); + return; } + + // Scoping effort begins. + frame_->resetMatchCount(); + + // Cancel all old scoping requests before starting a new one. + frame_->cancelPendingScopingEffort(); + + // Start new scoping request. If the scoping function determines that it + // needs to scope, it will defer until later. + frame_->scopeStringMatches(request_id, + search_text, + options, + true); // reset the tickmarks } -void RenderFrameImpl::OnStopFinding(StopFindAction action) { - // This should only be received on the main frame, since find-in-page is - // currently orchestrated by the main frame. - if (!is_main_frame_) { - NOTREACHED(); - return; - } +void RenderFrameImpl::OnClearActiveFindMatch() { + frame_->executeCommand(WebString::fromUTF8("Unselect")); + frame_->clearActiveFindMatch(); +} - WebView* view = render_view_->webview(); - if (!view) - return; +// Ensure that content::StopFindAction and blink::WebLocalFrame::StopFindAction +// are kept in sync. +STATIC_ASSERT_ENUM(STOP_FIND_ACTION_CLEAR_SELECTION, + WebLocalFrame::StopFindActionClearSelection); +STATIC_ASSERT_ENUM(STOP_FIND_ACTION_KEEP_SELECTION, + WebLocalFrame::StopFindActionKeepSelection); +STATIC_ASSERT_ENUM(STOP_FIND_ACTION_ACTIVATE_SELECTION, + WebLocalFrame::StopFindActionActivateSelection); +void RenderFrameImpl::OnStopFinding(StopFindAction action) { blink::WebPlugin* plugin = GetWebPluginForFind(); if (plugin) { plugin->stopFind(); return; } - bool clear_selection = action == STOP_FIND_ACTION_CLEAR_SELECTION; - if (clear_selection) { - view->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect")); - } - - WebLocalFrame* frame = GetWebFrame(); - while (frame) { - frame->stopFinding(clear_selection); - frame = frame->traverseNextLocal(false); - } - - if (action == STOP_FIND_ACTION_ACTIVATE_SELECTION) { - WebFrame* focused_frame = view->focusedFrame(); - if (focused_frame) { - WebDocument doc = focused_frame->document(); - if (!doc.isNull()) { - WebElement element = doc.focusedElement(); - if (!element.isNull()) - element.simulateClick(); - } - } - } + frame_->stopFinding(static_cast<WebLocalFrame::StopFindAction>(action)); } void RenderFrameImpl::OnEnableViewSourceMode() { @@ -5187,6 +5266,43 @@ void RenderFrameImpl::OnSuppressFurtherDialogs() { suppress_further_dialogs_ = true; } +void RenderFrameImpl::OnFileChooserResponse( + const std::vector<content::FileChooserFileInfo>& files) { + // This could happen if we navigated to a different page before the user + // closed the chooser. + if (file_chooser_completions_.empty()) + return; + + // Convert Chrome's SelectedFileInfo list to WebKit's. + WebVector<blink::WebFileChooserCompletion::SelectedFileInfo> selected_files( + files.size()); + for (size_t i = 0; i < files.size(); ++i) { + blink::WebFileChooserCompletion::SelectedFileInfo selected_file; + selected_file.path = files[i].file_path.AsUTF16Unsafe(); + selected_file.displayName = + base::FilePath(files[i].display_name).AsUTF16Unsafe(); + if (files[i].file_system_url.is_valid()) { + selected_file.fileSystemURL = files[i].file_system_url; + selected_file.length = files[i].length; + selected_file.modificationTime = files[i].modification_time.ToDoubleT(); + selected_file.isDirectory = files[i].is_directory; + } + selected_files[i] = selected_file; + } + + if (file_chooser_completions_.front()->completion) { + file_chooser_completions_.front()->completion->didChooseFile( + selected_files); + } + file_chooser_completions_.pop_front(); + + // If there are more pending file chooser requests, schedule one now. + if (!file_chooser_completions_.empty()) { + Send(new FrameHostMsg_RunFileChooser( + routing_id_, file_chooser_completions_.front()->params)); + } +} + #if defined(OS_ANDROID) void RenderFrameImpl::OnActivateNearestFindResult(int request_id, float x, @@ -5206,6 +5322,14 @@ void RenderFrameImpl::OnActivateNearestFindResult(int request_id, true /* final_update */); } +void RenderFrameImpl::OnGetNearestFindResult(int nfr_request_id, + float x, + float y) { + float distance = frame_->distanceToNearestFindMatch(WebFloatPoint(x, y)); + Send(new FrameHostMsg_GetNearestFindResult_Reply( + routing_id_, nfr_request_id, distance)); +} + void RenderFrameImpl::OnFindMatchRects(int current_version) { std::vector<gfx::RectF> match_rects; @@ -5222,7 +5346,17 @@ void RenderFrameImpl::OnFindMatchRects(int current_version) { Send(new FrameHostMsg_FindMatchRects_Reply(routing_id_, rects_version, match_rects, active_rect)); } +#endif +#if defined(USE_EXTERNAL_POPUP_MENU) +#if defined(OS_MACOSX) +void RenderFrameImpl::OnSelectPopupMenuItem(int selected_index) { + if (external_popup_menu_ == NULL) + return; + external_popup_menu_->DidSelectItem(selected_index); + external_popup_menu_.reset(); +} +#else void RenderFrameImpl::OnSelectPopupMenuItems( bool canceled, const std::vector<int>& selected_indices) { @@ -5236,22 +5370,21 @@ void RenderFrameImpl::OnSelectPopupMenuItems( external_popup_menu_->DidSelectItems(canceled, selected_indices); external_popup_menu_.reset(); } -#elif defined(OS_MACOSX) -void RenderFrameImpl::OnSelectPopupMenuItem(int selected_index) { - if (external_popup_menu_ == NULL) - return; - external_popup_menu_->DidSelectItem(selected_index); - external_popup_menu_.reset(); -} +#endif #endif -void RenderFrameImpl::OpenURL(const GURL& url, - const Referrer& referrer, - WebNavigationPolicy policy, - bool should_replace_current_entry, - bool is_history_navigation_in_new_child) { +void RenderFrameImpl::OpenURL( + const GURL& url, + bool uses_post, + const scoped_refptr<ResourceRequestBodyImpl>& resource_request_body, + const Referrer& referrer, + WebNavigationPolicy policy, + bool should_replace_current_entry, + bool is_history_navigation_in_new_child) { FrameHostMsg_OpenURL_Params params; params.url = url; + params.uses_post = uses_post; + params.resource_request_body = resource_request_body; params.referrer = referrer; params.disposition = RenderViewImpl::NavigationPolicyToDisposition(policy); @@ -5349,6 +5482,12 @@ void RenderFrameImpl::NavigateInternal( WebURLRequest request = CreateURLRequestForNavigation(common_params, std::move(stream_params), frame_->isViewSourceModeEnabled()); + request.setFrameType(IsTopLevelNavigation(frame_) + ? blink::WebURLRequest::FrameTypeTopLevel + : blink::WebURLRequest::FrameTypeNested); + + if (IsBrowserSideNavigationEnabled() && common_params.post_data) + request.setHTTPBody(GetWebHTTPBodyForRequestBody(common_params.post_data)); // Used to determine whether this frame is actually loading a request as part // of a history navigation. @@ -5439,18 +5578,10 @@ void RenderFrameImpl::NavigateInternal( } } - if (common_params.method == "POST" && !browser_side_navigation) { - // Set post data. - WebHTTPBody http_body; - http_body.initialize(); - const char* data = nullptr; - if (start_params.browser_initiated_post_data.size()) { - data = reinterpret_cast<const char*>( - &start_params.browser_initiated_post_data.front()); - } - http_body.appendData( - WebData(data, start_params.browser_initiated_post_data.size())); - request.setHTTPBody(http_body); + if (common_params.method == "POST" && !browser_side_navigation && + common_params.post_data) { + request.setHTTPBody( + GetWebHTTPBodyForRequestBody(common_params.post_data)); } // A session history navigation should have been accompanied by state. @@ -5474,12 +5605,11 @@ void RenderFrameImpl::NavigateInternal( // Perform a navigation to a data url if needed. // Note: the base URL might be invalid, so also check the data URL string. - if (!common_params.base_url_for_data_url.is_empty() || + bool should_load_data_url = !common_params.base_url_for_data_url.is_empty(); #if defined(OS_ANDROID) - !request_params.data_url_as_string.empty() || + should_load_data_url |= !request_params.data_url_as_string.empty(); #endif - (browser_side_navigation && - common_params.url.SchemeIs(url::kDataScheme))) { + if (should_load_data_url) { LoadDataURL(common_params, request_params, frame_, load_type, item_for_history_navigation, history_load_type, is_client_redirect); @@ -5605,11 +5735,12 @@ WebMediaPlayer* RenderFrameImpl::CreateWebMediaPlayerForMediaStream( scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner = render_thread->compositor_task_runner(); if (!compositor_task_runner.get()) - compositor_task_runner = base::MessageLoop::current()->task_runner(); + compositor_task_runner = base::ThreadTaskRunnerHandle::Get(); return new WebMediaPlayerMS( frame_, client, GetWebMediaPlayerDelegate()->AsWeakPtr(), - new RenderMediaLog(), CreateRendererFactory(), compositor_task_runner, + new RenderMediaLog(blink::WebStringToGURL(security_origin.toString())), + CreateRendererFactory(), compositor_task_runner, render_thread->GetMediaThreadTaskRunner(), render_thread->GetWorkerTaskRunner(), render_thread->GetGpuFactories(), sink_id, security_origin); @@ -5660,7 +5791,6 @@ void RenderFrameImpl::BeginNavigation(blink::WebURLRequest* request, bool is_client_redirect) { CHECK(IsBrowserSideNavigationEnabled()); DCHECK(request); - // TODO(clamy): Execute the beforeunload event. // Note: At this stage, the goal is to apply all the modifications the // renderer wants to make to the request, and then send it to the browser, so @@ -5708,9 +5838,9 @@ void RenderFrameImpl::BeginNavigation(blink::WebURLRequest* request, BeginNavigationParams(GetWebURLRequestHeaders(*request), GetLoadFlagsForWebURLRequest(*request), request->hasUserGesture(), - request->skipServiceWorker(), - GetRequestContextTypeForWebURLRequest(*request)), - GetRequestBodyForWebURLRequest(*request))); + request->skipServiceWorker() != + blink::WebURLRequest::SkipServiceWorker::None, + GetRequestContextTypeForWebURLRequest(*request)))); } void RenderFrameImpl::LoadDataURL( @@ -6028,23 +6158,23 @@ media::DecoderFactory* RenderFrameImpl::GetDecoderFactory() { return decoder_factory_.get(); } -void RenderFrameImpl::RegisterMojoServices() { +void RenderFrameImpl::RegisterMojoInterfaces() { // Only main frame have ImageDownloader service. if (!frame_->parent()) { - GetServiceRegistry()->AddService(base::Bind( + GetInterfaceRegistry()->AddInterface(base::Bind( &ImageDownloaderImpl::CreateMojoService, base::Unretained(this))); } } template <typename Interface> void RenderFrameImpl::GetInterface(mojo::InterfaceRequest<Interface> request) { - GetServiceRegistry()->ConnectToRemoteService(std::move(request)); + GetRemoteInterfaces()->GetInterface(std::move(request)); } shell::mojom::InterfaceProviderPtr RenderFrameImpl::ConnectToApplication( const GURL& url) { if (!connector_) - GetServiceRegistry()->ConnectToRemoteService(mojo::GetProxy(&connector_)); + GetRemoteInterfaces()->GetInterface(&connector_); shell::mojom::InterfaceProviderPtr interface_provider; shell::mojom::IdentityPtr target(shell::mojom::Identity::New()); target->name = url.spec(); @@ -6074,13 +6204,28 @@ void RenderFrameImpl::checkIfAudioSinkExistsAndIsAuthorized( } blink::ServiceRegistry* RenderFrameImpl::serviceRegistry() { - return &blink_service_registry_; + return blink_service_registry_.get(); } -blink::WebPlugin* RenderFrameImpl::GetWebPluginForFind() { - if (!is_main_frame_) - return nullptr; +blink::WebPageVisibilityState RenderFrameImpl::visibilityState() const { + RenderFrameImpl* local_root = + RenderFrameImpl::FromWebFrame(frame_->localRoot()); + blink::WebPageVisibilityState current_state = + local_root->render_widget_->is_hidden() + ? blink::WebPageVisibilityStateHidden + : blink::WebPageVisibilityStateVisible; + blink::WebPageVisibilityState override_state = current_state; + if (GetContentClient()->renderer()->ShouldOverridePageVisibilityState( + this, &override_state)) + return override_state; + return current_state; +} +blink::WebPageVisibilityState RenderFrameImpl::GetVisibilityState() const { + return visibilityState(); +} + +blink::WebPlugin* RenderFrameImpl::GetWebPluginForFind() { if (frame_->document().isPluginDocument()) return frame_->document().to<WebPluginDocument>().plugin(); @@ -6097,8 +6242,15 @@ void RenderFrameImpl::SendFindReply(int request_id, int ordinal, const WebRect& selection_rect, bool final_status_update) { - Send(new FrameHostMsg_Find_Reply(routing_id_, request_id, match_count, - selection_rect, ordinal, + if (final_status_update && !ordinal) + frame_->executeCommand(WebString::fromUTF8("Unselect")); + DCHECK(ordinal >= -1); + + Send(new FrameHostMsg_Find_Reply(routing_id_, + request_id, + match_count, + selection_rect, + ordinal, final_status_update)); } @@ -6137,6 +6289,22 @@ void RenderFrameImpl::PepperFocusChanged(PepperPluginInstanceImpl* instance, GetRenderWidget()->UpdateSelectionBounds(); } +void RenderFrameImpl::PepperStartsPlayback(PepperPluginInstanceImpl* instance) { + // TODO(zqzhang): send PepperStartsPlayback message to the browser. + // See https://crbug.com/619084 +} + +void RenderFrameImpl::PepperStopsPlayback(PepperPluginInstanceImpl* instance) { + // TODO(zqzhang): send PepperStopsPlayback message to the browser. + // See https://crbug.com/619084 +} + +void RenderFrameImpl::OnSetPepperVolume(int32_t pp_instance, double volume) { + PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>( + PepperPluginInstance::Get(pp_instance)); + if (instance) + instance->audio_controller().SetVolume(volume); +} #endif // ENABLE_PLUGINS void RenderFrameImpl::RenderWidgetSetFocus(bool enable) { diff --git a/chromium/content/renderer/render_frame_impl.h b/chromium/content/renderer/render_frame_impl.h index c424e0a6002..f3d5f6f9efa 100644 --- a/chromium/content/renderer/render_frame_impl.h +++ b/chromium/content/renderer/render_frame_impl.h @@ -17,13 +17,14 @@ #include "base/id_map.h" #include "base/macros.h" #include "base/memory/linked_ptr.h" +#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/process/process_handle.h" #include "build/build_config.h" #include "content/common/accessibility_mode_enums.h" +#include "content/common/frame.mojom.h" #include "content/common/frame_message_enums.h" -#include "content/common/mojo/service_registry_impl.h" #include "content/public/common/console_message_level.h" #include "content/public/common/javascript_message_type.h" #include "content/public/common/referrer.h" @@ -36,12 +37,14 @@ #include "ipc/ipc_platform_file.h" #include "media/blink/webmediaplayer_delegate.h" #include "media/blink/webmediaplayer_params.h" +#include "mojo/public/cpp/bindings/binding.h" #include "services/shell/public/interfaces/connector.mojom.h" #include "services/shell/public/interfaces/interface_provider.mojom.h" #include "third_party/WebKit/public/platform/WebEffectiveConnectionType.h" #include "third_party/WebKit/public/platform/WebFocusType.h" #include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h" #include "third_party/WebKit/public/platform/WebMediaPlayer.h" +#include "third_party/WebKit/public/platform/WebPageVisibilityState.h" #include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerClient.h" #include "third_party/WebKit/public/web/WebAXObject.h" #include "third_party/WebKit/public/web/WebDataSource.h" @@ -108,8 +111,9 @@ class UrlIndex; class WebEncryptedMediaClientImpl; } -namespace mojo { -class ServiceProvider; +namespace shell { +class InterfaceRegistry; +class InterfaceProvider; } namespace url { @@ -136,7 +140,7 @@ class PepperPluginInstanceImpl; class PermissionDispatcher; class PresentationDispatcher; class PushMessagingDispatcher; -class RendererAccessibility; +class RenderAccessibilityImpl; class RendererCdmManager; class RendererMediaPlayerManager; class RendererMediaSessionManager; @@ -146,11 +150,14 @@ class RenderFrameObserver; class RenderViewImpl; class RenderWidget; class RenderWidgetFullscreenPepper; +class ResourceRequestBodyImpl; class ScreenOrientationDispatcher; class UserMediaClientImpl; class WakeLockDispatcher; struct CommonNavigationParams; struct CustomContextMenuContext; +struct FileChooserFileInfo; +struct FileChooserParams; struct FrameReplicationState; struct NavigationParams; struct RequestNavigationParams; @@ -160,6 +167,7 @@ struct StreamOverrideParameters; class CONTENT_EXPORT RenderFrameImpl : public RenderFrame, + NON_EXPORTED_BASE(mojom::Frame), NON_EXPORTED_BASE(public blink::WebFrameClient), NON_EXPORTED_BASE(public blink::WebFrameSerializerClient) { public: @@ -279,8 +287,8 @@ class CONTENT_EXPORT RenderFrameImpl return accessibility_mode_; } - RendererAccessibility* renderer_accessibility() { - return renderer_accessibility_; + RenderAccessibilityImpl* render_accessibility() { + return render_accessibility_; } void HandleWebAccessibilityEvent(const blink::WebAXObject& obj, @@ -291,7 +299,7 @@ class CONTENT_EXPORT RenderFrameImpl void FocusedNodeChanged(const blink::WebNode& node); // TODO(dmazzoni): the only reason this is here is to plumb it through to - // RendererAccessibility. It should use the RenderFrameObserver method, once + // RenderAccessibilityImpl. It should use the RenderFrameObserver method, once // blink has a separate accessibility tree per frame. void FocusedNodeChangedForAccessibility(const blink::WebNode& node); @@ -367,7 +375,7 @@ class CONTENT_EXPORT RenderFrameImpl // NULL. MediaStreamDispatcher* GetMediaStreamDispatcher(); -#if defined(OS_MACOSX) || defined(OS_ANDROID) +#if defined(USE_EXTERNAL_POPUP_MENU) void DidHideExternalPopupMenu(); #endif @@ -379,6 +387,7 @@ class CONTENT_EXPORT RenderFrameImpl // RenderFrame implementation: RenderView* GetRenderView() override; + RenderAccessibility* GetRenderAccessibility() override; int GetRoutingID() override; blink::WebLocalFrame* GetWebFrame() override; WebPreferences& GetWebkitPreferences() override; @@ -395,7 +404,8 @@ class CONTENT_EXPORT RenderFrameImpl void ExecuteJavaScript(const base::string16& javascript) override; bool IsMainFrame() override; bool IsHidden() override; - ServiceRegistry* GetServiceRegistry() override; + shell::InterfaceRegistry* GetInterfaceRegistry() override; + shell::InterfaceProvider* GetRemoteInterfaces() override; #if defined(ENABLE_PLUGINS) void RegisterPeripheralPlugin( const url::Origin& content_origin, @@ -418,6 +428,11 @@ class CONTENT_EXPORT RenderFrameImpl const std::string& message) override; bool IsUsingLoFi() const override; bool IsPasting() const override; + blink::WebPageVisibilityState GetVisibilityState() const override; + + // mojom::Frame implementation: + void GetInterfaceProvider( + shell::mojom::InterfaceProviderRequest request) override; // blink::WebFrameClient implementation: blink::WebPlugin* createPlugin(blink::WebLocalFrame* frame, @@ -454,7 +469,8 @@ class CONTENT_EXPORT RenderFrameImpl void willClose(blink::WebFrame* frame) override; void didChangeName(const blink::WebString& name, const blink::WebString& unique_name) override; - void didEnforceStrictMixedContentChecking() override; + void didEnforceInsecureRequestPolicy( + blink::WebInsecureRequestPolicy policy) override; void didUpdateToUniqueOrigin( bool is_potentially_trustworthy_unique_origin) override; void didChangeSandboxFlags(blink::WebFrame* child_frame, @@ -539,7 +555,11 @@ class CONTENT_EXPORT RenderFrameImpl const blink::WebString& default_value, blink::WebString* actual_value) override; bool runModalBeforeUnloadDialog(bool is_reload) override; + bool runFileChooser( + const blink::WebFileChooserParams& params, + blink::WebFileChooserCompletion* chooser_completion) override; void showContextMenu(const blink::WebContextMenuData& data) override; + void saveImageFromDataURL(const blink::WebString& data_url) override; void willSendRequest(blink::WebLocalFrame* frame, unsigned identifier, blink::WebURLRequest& request, @@ -618,6 +638,7 @@ class CONTENT_EXPORT RenderFrameImpl const blink::WebSecurityOrigin& security_origin, blink::WebSetSinkIdCallbacks* web_callbacks) override; blink::ServiceRegistry* serviceRegistry() override; + blink::WebPageVisibilityState visibilityState() const override; // WebFrameSerializerClient implementation: void didSerializeDataForFrame( @@ -625,9 +646,8 @@ class CONTENT_EXPORT RenderFrameImpl blink::WebFrameSerializerClient::FrameSerializationStatus status) override; - // Binds this render frame's service registry. - void BindServiceRegistry(shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services); + // Binds to the FrameHost in the browser. + void Bind(mojom::FrameRequest frame, mojom::FrameHostPtr frame_host); ManifestManager* manifest_manager(); @@ -670,6 +690,10 @@ class CONTENT_EXPORT RenderFrameImpl // Notification that the given plugin is focused or unfocused. void PepperFocusChanged(PepperPluginInstanceImpl* instance, bool focused); + + void PepperStartsPlayback(PepperPluginInstanceImpl* instance); + void PepperStopsPlayback(PepperPluginInstanceImpl* instance); + void OnSetPepperVolume(int32_t pp_instance, double volume); #endif // ENABLE_PLUGINS protected: @@ -678,13 +702,13 @@ class CONTENT_EXPORT RenderFrameImpl private: friend class RenderFrameImplTest; friend class RenderFrameObserver; - friend class RendererAccessibilityTest; + friend class RenderAccessibilityImplTest; friend class TestRenderFrame; FRIEND_TEST_ALL_PREFIXES(ExternalPopupMenuDisplayNoneTest, SelectItem); FRIEND_TEST_ALL_PREFIXES(ExternalPopupMenuRemoveTest, RemoveOnChange); FRIEND_TEST_ALL_PREFIXES(ExternalPopupMenuTest, NormalCase); FRIEND_TEST_ALL_PREFIXES(ExternalPopupMenuTest, ShowPopupThenNavigate); - FRIEND_TEST_ALL_PREFIXES(RendererAccessibilityTest, + FRIEND_TEST_ALL_PREFIXES(RenderAccessibilityImplTest, AccessibilityMessagesQueueWhileSwappedOut); // A wrapper class used as the callback for JavaScript executed @@ -741,7 +765,7 @@ class CONTENT_EXPORT RenderFrameImpl void OnNavigate(const CommonNavigationParams& common_params, const StartNavigationParams& start_params, const RequestNavigationParams& request_params); - void OnBeforeUnload(); + void OnBeforeUnload(bool is_reload); void OnSwapOut(int proxy_routing_id, bool is_loading, const FrameReplicationState& replicated_frame_state); @@ -765,6 +789,8 @@ class CONTENT_EXPORT RenderFrameImpl void OnMoveRangeSelectionExtent(const gfx::Point& point); void OnReplace(const base::string16& text); void OnReplaceMisspelling(const base::string16& text); + void OnCopyImageAt(int x, int y); + void OnSaveImageAt(int x, int y); void OnCSSInsertRequest(const std::string& css); void OnAddMessageToConsole(ConsoleMessageLevel level, const std::string& message); @@ -816,16 +842,28 @@ class CONTENT_EXPORT RenderFrameImpl void OnFind(int request_id, const base::string16& search_text, const blink::WebFindOptions& options); + void OnClearActiveFindMatch(); void OnStopFinding(StopFindAction action); void OnEnableViewSourceMode(); void OnSuppressFurtherDialogs(); + void OnFileChooserResponse( + const std::vector<content::FileChooserFileInfo>& files); #if defined(OS_ANDROID) void OnActivateNearestFindResult(int request_id, float x, float y); + void OnGetNearestFindResult(int request_id, float x, float y); void OnFindMatchRects(int current_version); +#endif + +#if defined(USE_EXTERNAL_POPUP_MENU) +#if defined(OS_MACOSX) + void OnSelectPopupMenuItem(int selected_index); +#else void OnSelectPopupMenuItems(bool canceled, const std::vector<int>& selected_indices); -#elif defined(OS_MACOSX) - void OnSelectPopupMenuItem(int selected_index); +#endif +#endif + +#if defined(OS_MACOSX) void OnCopyToFindPboard(); #endif @@ -833,11 +871,14 @@ class CONTENT_EXPORT RenderFrameImpl // |is_history_navigation_in_new_child| is true, the browser process should // look for a matching FrameNavigationEntry in the last committed entry to use // instead of |url|. - void OpenURL(const GURL& url, - const Referrer& referrer, - blink::WebNavigationPolicy policy, - bool should_replace_current_entry, - bool is_history_navigation_in_new_child); + void OpenURL( + const GURL& url, + bool uses_post, + const scoped_refptr<ResourceRequestBodyImpl>& resource_request_body, + const Referrer& referrer, + blink::WebNavigationPolicy policy, + bool should_replace_current_entry, + bool is_history_navigation_in_new_child); // Performs a navigation in the frame. This provides a unified function for // the current code path and the browser-side navigation path (in @@ -881,6 +922,15 @@ class CONTENT_EXPORT RenderFrameImpl const GURL& frame_url, base::string16* result); + // Adds the given file chooser request to the file_chooser_completion_ queue + // (see that var for more) and requests the chooser be displayed if there are + // no other waiting items in the queue. + // + // Returns true if the chooser was successfully scheduled. False means we + // didn't schedule anything. + bool ScheduleFileChooser(const FileChooserParams& params, + blink::WebFileChooserCompletion* completion); + // Loads the appropriate error page for the specified failure into the frame. void LoadNavigationErrorPage(const blink::WebURLRequest& failed_request, const blink::WebURLError& error, @@ -978,7 +1028,7 @@ class CONTENT_EXPORT RenderFrameImpl media::CdmFactory* GetCdmFactory(); media::DecoderFactory* GetDecoderFactory(); - void RegisterMojoServices(); + void RegisterMojoInterfaces(); // Connect to an interface provided by the service registry. template <typename Interface> @@ -1038,8 +1088,6 @@ class CONTENT_EXPORT RenderFrameImpl base::WeakPtr<RenderViewImpl> render_view_; int routing_id_; - bool is_detaching_; - // If this frame was created to replace a proxy, this will store the routing // id of the proxy to replace at commit-time, at which time it will be // cleared. @@ -1172,8 +1220,11 @@ class CONTENT_EXPORT RenderFrameImpl // initialized. PresentationDispatcher* presentation_dispatcher_; - ServiceRegistryImpl service_registry_; - BlinkServiceRegistryImpl blink_service_registry_; + std::unique_ptr<shell::InterfaceRegistry> interface_registry_; + std::unique_ptr<shell::InterfaceProvider> remote_interfaces_; + std::unique_ptr<BlinkServiceRegistryImpl> blink_service_registry_; + shell::mojom::InterfaceProviderRequest + pending_remote_interface_provider_request_; // The shell proxy used to connect to Mojo applications. shell::mojom::ConnectorPtr connector_; @@ -1191,7 +1242,7 @@ class CONTENT_EXPORT RenderFrameImpl // Only valid if |accessibility_mode_| is anything other than // AccessibilityModeOff. - RendererAccessibility* renderer_accessibility_; + RenderAccessibilityImpl* render_accessibility_; std::unique_ptr<PermissionDispatcher> permission_client_; @@ -1217,12 +1268,19 @@ class CONTENT_EXPORT RenderFrameImpl // stack that interferes with swapping out. bool suppress_further_dialogs_; -#if defined(OS_MACOSX) || defined(OS_ANDROID) + // The current and pending file chooser completion objects. If the queue is + // nonempty, the first item represents the currently running file chooser + // callback, and the remaining elements are the other file chooser completion + // still waiting to be run (in order). + struct PendingFileChooser; + std::deque<std::unique_ptr<PendingFileChooser>> file_chooser_completions_; + +#if defined(USE_EXTERNAL_POPUP_MENU) // The external popup for the currently showing select popup. std::unique_ptr<ExternalPopupMenu> external_popup_menu_; #endif - FrameBlameContext* blame_context_; // Not owned. + std::unique_ptr<FrameBlameContext> blame_context_; // Plugins ------------------------------------------------------------------- #if defined(ENABLE_PLUGINS) @@ -1239,6 +1297,9 @@ class CONTENT_EXPORT RenderFrameImpl PepperPluginInstanceImpl* pepper_last_mouse_event_target_; #endif + mojo::Binding<mojom::Frame> frame_binding_; + mojom::FrameHostPtr frame_host_; + base::WeakPtrFactory<RenderFrameImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(RenderFrameImpl); diff --git a/chromium/content/renderer/render_frame_impl_browsertest.cc b/chromium/content/renderer/render_frame_impl_browsertest.cc index 2a853c16903..61fd6b341e9 100644 --- a/chromium/content/renderer/render_frame_impl_browsertest.cc +++ b/chromium/content/renderer/render_frame_impl_browsertest.cc @@ -19,11 +19,14 @@ #include "content/test/fake_compositor_dependencies.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebEffectiveConnectionType.h" +#include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "third_party/WebKit/public/web/WebFrameOwnerProperties.h" #include "third_party/WebKit/public/web/WebHistoryItem.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +using blink::WebString; + namespace { const int32_t kSubframeRouteId = 20; const int32_t kSubframeWidgetRouteId = 21; @@ -108,8 +111,10 @@ class RenderFrameTestObserver : public RenderFrameObserver { ~RenderFrameTestObserver() override {} + // RenderFrameObserver implementation. void WasShown() override { visible_ = true; } void WasHidden() override { visible_ = false; } + void OnDestruct() override { delete this; } bool visible() { return visible_; } @@ -292,4 +297,50 @@ TEST_F(RenderFrameImplTest, EffectiveConnectionType) { } } +TEST_F(RenderFrameImplTest, SaveImageFromDataURL) { + const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching( + FrameHostMsg_SaveImageFromDataURL::ID); + EXPECT_FALSE(msg1); + render_thread_->sink().ClearMessages(); + + const std::string image_data_url = + "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="; + + frame()->saveImageFromDataURL(WebString::fromUTF8(image_data_url)); + ProcessPendingMessages(); + const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching( + FrameHostMsg_SaveImageFromDataURL::ID); + EXPECT_TRUE(msg2); + + FrameHostMsg_SaveImageFromDataURL::Param param1; + FrameHostMsg_SaveImageFromDataURL::Read(msg2, ¶m1); + EXPECT_EQ(std::get<2>(param1), image_data_url); + + ProcessPendingMessages(); + render_thread_->sink().ClearMessages(); + + const std::string large_data_url(1024 * 1024 * 20 - 1, 'd'); + + frame()->saveImageFromDataURL(WebString::fromUTF8(large_data_url)); + ProcessPendingMessages(); + const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching( + FrameHostMsg_SaveImageFromDataURL::ID); + EXPECT_TRUE(msg3); + + FrameHostMsg_SaveImageFromDataURL::Param param2; + FrameHostMsg_SaveImageFromDataURL::Read(msg3, ¶m2); + EXPECT_EQ(std::get<2>(param2), large_data_url); + + ProcessPendingMessages(); + render_thread_->sink().ClearMessages(); + + const std::string exceeded_data_url(1024 * 1024 * 20 + 1, 'd'); + + frame()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url)); + ProcessPendingMessages(); + const IPC::Message* msg4 = render_thread_->sink().GetFirstMessageMatching( + FrameHostMsg_SaveImageFromDataURL::ID); + EXPECT_FALSE(msg4); +} + } // namespace diff --git a/chromium/content/renderer/render_frame_proxy.cc b/chromium/content/renderer/render_frame_proxy.cc index 868412155c7..74bcd08f83f 100644 --- a/chromium/content/renderer/render_frame_proxy.cc +++ b/chromium/content/renderer/render_frame_proxy.cc @@ -10,6 +10,7 @@ #include "base/command_line.h" #include "base/lazy_instance.h" +#include "content/child/web_url_request_util.h" #include "content/child/webmessageportchannel_impl.h" #include "content/common/content_security_policy_header.h" #include "content/common/frame_messages.h" @@ -212,8 +213,7 @@ void RenderFrameProxy::SetReplicatedState(const FrameReplicationState& state) { web_frame_->setReplicatedSandboxFlags(state.sandbox_flags); web_frame_->setReplicatedName(blink::WebString::fromUTF8(state.name), blink::WebString::fromUTF8(state.unique_name)); - web_frame_->setReplicatedShouldEnforceStrictMixedContentChecking( - state.should_enforce_strict_mixed_content_checking); + web_frame_->setReplicatedInsecureRequestPolicy(state.insecure_request_policy); web_frame_->setReplicatedPotentiallyTrustworthyUniqueOrigin( state.has_potentially_trustworthy_unique_origin); @@ -267,11 +267,14 @@ bool RenderFrameProxy::OnMessageReceived(const IPC::Message& msg) { OnAddContentSecurityPolicy) IPC_MESSAGE_HANDLER(FrameMsg_ResetContentSecurityPolicy, OnResetContentSecurityPolicy) - IPC_MESSAGE_HANDLER(FrameMsg_EnforceStrictMixedContentChecking, - OnEnforceStrictMixedContentChecking) + IPC_MESSAGE_HANDLER(FrameMsg_EnforceInsecureRequestPolicy, + OnEnforceInsecureRequestPolicy) + IPC_MESSAGE_HANDLER(FrameMsg_SetFrameOwnerProperties, + OnSetFrameOwnerProperties) IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateOrigin, OnDidUpdateOrigin) IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetPageFocus) IPC_MESSAGE_HANDLER(FrameMsg_SetFocusedFrame, OnSetFocusedFrame) + IPC_MESSAGE_HANDLER(FrameMsg_WillEnterFullscreen, OnWillEnterFullscreen) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -348,10 +351,14 @@ void RenderFrameProxy::OnResetContentSecurityPolicy() { web_frame_->resetReplicatedContentSecurityPolicy(); } -void RenderFrameProxy::OnEnforceStrictMixedContentChecking( - bool should_enforce) { - web_frame_->setReplicatedShouldEnforceStrictMixedContentChecking( - should_enforce); +void RenderFrameProxy::OnEnforceInsecureRequestPolicy( + blink::WebInsecureRequestPolicy policy) { + web_frame_->setReplicatedInsecureRequestPolicy(policy); +} + +void RenderFrameProxy::OnSetFrameOwnerProperties( + const blink::WebFrameOwnerProperties& properties) { + web_frame_->setFrameOwnerProperties(properties); } void RenderFrameProxy::OnDidUpdateOrigin( @@ -372,6 +379,10 @@ void RenderFrameProxy::OnSetFocusedFrame() { render_view_->webview()->focusDocumentView(web_frame_); } +void RenderFrameProxy::OnWillEnterFullscreen() { + web_frame_->willEnterFullScreen(); +} + void RenderFrameProxy::frameDetached(DetachType type) { if (type == DetachType::Remove && web_frame_->parent()) { web_frame_->parent()->removeChild(web_frame_); @@ -436,6 +447,8 @@ void RenderFrameProxy::navigate(const blink::WebURLRequest& request, bool should_replace_current_entry) { FrameHostMsg_OpenURL_Params params; params.url = request.url(); + params.uses_post = request.httpMethod().utf8() == "POST"; + params.resource_request_body = GetRequestBodyForWebURLRequest(request); params.referrer = Referrer( blink::WebStringToGURL( request.httpHeaderField(blink::WebString::fromUTF8("Referer"))), diff --git a/chromium/content/renderer/render_frame_proxy.h b/chromium/content/renderer/render_frame_proxy.h index 638037b69d4..950e25dacd5 100644 --- a/chromium/content/renderer/render_frame_proxy.h +++ b/chromium/content/renderer/render_frame_proxy.h @@ -11,6 +11,7 @@ #include "ipc/ipc_listener.h" #include "ipc/ipc_sender.h" #include "third_party/WebKit/public/platform/WebFocusType.h" +#include "third_party/WebKit/public/platform/WebInsecureRequestPolicy.h" #include "third_party/WebKit/public/web/WebRemoteFrame.h" #include "third_party/WebKit/public/web/WebRemoteFrameClient.h" #include "url/origin.h" @@ -24,7 +25,7 @@ struct WebRect; } namespace cc { -struct SurfaceId; +class SurfaceId; struct SurfaceSequence; } @@ -168,11 +169,14 @@ class CONTENT_EXPORT RenderFrameProxy void OnDidUpdateName(const std::string& name, const std::string& unique_name); void OnAddContentSecurityPolicy(const ContentSecurityPolicyHeader& header); void OnResetContentSecurityPolicy(); - void OnEnforceStrictMixedContentChecking(bool should_enforce); + void OnEnforceInsecureRequestPolicy(blink::WebInsecureRequestPolicy policy); + void OnSetFrameOwnerProperties( + const blink::WebFrameOwnerProperties& properties); void OnDidUpdateOrigin(const url::Origin& origin, bool is_potentially_trustworthy_unique_origin); void OnSetPageFocus(bool is_focused); void OnSetFocusedFrame(); + void OnWillEnterFullscreen(); // The routing ID by which this RenderFrameProxy is known. const int routing_id_; diff --git a/chromium/content/renderer/render_thread_impl.cc b/chromium/content/renderer/render_thread_impl.cc index b729a8ca44e..a43b39dd21d 100644 --- a/chromium/content/renderer/render_thread_impl.cc +++ b/chromium/content/renderer/render_thread_impl.cc @@ -41,6 +41,8 @@ #include "cc/base/switches.h" #include "cc/blink/web_external_bitmap_impl.h" #include "cc/blink/web_layer_impl.h" +#include "cc/output/output_surface.h" +#include "cc/output/vulkan_in_process_context_provider.h" #include "cc/raster/task_graph_runner.h" #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_settings.h" @@ -65,15 +67,14 @@ #include "content/child/runtime_features.h" #include "content/child/thread_safe_sender.h" #include "content/child/web_database_observer_impl.h" +#include "content/child/websocket_message_filter.h" #include "content/child/worker_thread_registry.h" #include "content/common/child_process_messages.h" #include "content/common/content_constants_internal.h" -#include "content/common/database_messages.h" #include "content/common/dom_storage/dom_storage_messages.h" #include "content/common/frame_messages.h" #include "content/common/gpu/client/context_provider_command_buffer.h" #include "content/common/gpu_process_launch_causes.h" -#include "content/common/render_frame_setup.mojom.h" #include "content/common/render_process_messages.h" #include "content/common/resource_messages.h" #include "content/common/service_worker/embedded_worker_setup.mojom.h" @@ -87,10 +88,10 @@ #include "content/public/renderer/content_renderer_client.h" #include "content/public/renderer/render_thread_observer.h" #include "content/public/renderer/render_view_visitor.h" -#include "content/renderer/bluetooth/bluetooth_message_filter.h" #include "content/renderer/browser_plugin/browser_plugin_manager.h" #include "content/renderer/cache_storage/cache_storage_dispatcher.h" #include "content/renderer/cache_storage/cache_storage_message_filter.h" +#include "content/renderer/categorized_worker_pool.h" #include "content/renderer/devtools/devtools_agent_filter.h" #include "content/renderer/devtools/v8_sampling_profiler.h" #include "content/renderer/dom_storage/dom_storage_dispatcher.h" @@ -99,6 +100,7 @@ #include "content/renderer/gpu/compositor_external_begin_frame_source.h" #include "content/renderer/gpu/compositor_forwarding_message_filter.h" #include "content/renderer/gpu/compositor_output_surface.h" +#include "content/renderer/gpu/frame_swap_message_queue.h" #include "content/renderer/input/input_event_filter.h" #include "content/renderer/input/input_handler_manager.h" #include "content/renderer/input/main_thread_input_event_filter.h" @@ -114,7 +116,6 @@ #include "content/renderer/media/video_capture_message_filter.h" #include "content/renderer/net_info_helper.h" #include "content/renderer/p2p/socket_dispatcher.h" -#include "content/renderer/raster_worker_pool.h" #include "content/renderer/render_frame_proxy.h" #include "content/renderer/render_process_impl.h" #include "content/renderer/render_view_impl.h" @@ -130,8 +131,8 @@ #include "gpu/ipc/client/command_buffer_proxy_impl.h" #include "gpu/ipc/client/gpu_channel_host.h" #include "ipc/ipc_channel_handle.h" +#include "ipc/ipc_channel_mojo.h" #include "ipc/ipc_platform_file.h" -#include "ipc/mojo/ipc_channel_mojo.h" #include "media/base/audio_hardware_config.h" #include "media/base/media.h" #include "media/renderers/gpu_video_accelerator_factories.h" @@ -151,7 +152,7 @@ #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebKit.h" -#include "third_party/WebKit/public/web/WebMemoryPressureListener.h" +#include "third_party/WebKit/public/web/WebMemoryCoordinator.h" #include "third_party/WebKit/public/web/WebNetworkStateNotifier.h" #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" #include "third_party/WebKit/public/web/WebScriptController.h" @@ -164,8 +165,8 @@ #if defined(OS_ANDROID) #include <cpu-features.h> -#include "content/renderer/android/synchronous_compositor_external_begin_frame_source.h" #include "content/renderer/android/synchronous_compositor_filter.h" +#include "content/renderer/android/synchronous_compositor_output_surface.h" #include "content/renderer/media/android/renderer_demuxer_android.h" #include "content/renderer/media/android/stream_texture_factory.h" #include "media/base/android/media_codec_util.h" @@ -197,11 +198,17 @@ #include "v8/src/third_party/vtune/v8-vtune.h" #endif -#if defined(MOJO_SHELL_CLIENT) +#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA) +#include "components/mus/common/gpu_service.h" #include "content/public/common/mojo_shell_connection.h" +#include "content/renderer/mus/render_widget_mus_connection.h" #include "content/renderer/mus/render_widget_window_tree_client_factory.h" #endif +#if defined(ENABLE_IPC_FUZZER) +#include "content/common/external_ipc_dumper.h" +#endif + using base::ThreadRestrictions; using blink::WebDocument; using blink::WebFrame; @@ -236,6 +243,9 @@ const double kThrottledResourceRequestFlushPeriodS = 1. / 60.; // allocation that exceeds this limit. const size_t kImageCacheSingleAllocationByteLimit = 64 * 1024 * 1024; +// Unique identifier for each output surface created. +uint32_t g_next_output_surface_id = 1; + // Keep the global RenderThreadImpl in a TLS slot so it is impossible to access // incorrectly from the wrong thread. base::LazyInstance<base::ThreadLocalPointer<RenderThreadImpl> > @@ -252,6 +262,20 @@ static_assert(static_cast<v8::MemoryPressureLevel>( base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) == v8::MemoryPressureLevel::kCritical, "critical level not align"); +// WebMemoryPressureLevel should correspond to base::MemoryPressureListener. +static_assert(static_cast<blink::WebMemoryPressureLevel>( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) == + blink::WebMemoryPressureLevelNone, + "blink::WebMemoryPressureLevelNone not align"); +static_assert(static_cast<blink::WebMemoryPressureLevel>( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) == + blink::WebMemoryPressureLevelModerate, + "blink::WebMemoryPressureLevelModerate not align"); +static_assert(static_cast<blink::WebMemoryPressureLevel>( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) == + blink::WebMemoryPressureLevelCritical, + "blink::WebMemoryPressureLevelCritical not align"); + class WebThreadForCompositor : public WebThreadImplForWorkerScheduler { public: explicit WebThreadForCompositor(base::Thread::Options options) @@ -313,16 +337,16 @@ void NotifyTimezoneChangeOnThisThread() { v8::Date::DateTimeConfigurationChangeNotification(isolate); } -class RenderFrameSetupImpl : public mojom::RenderFrameSetup { +class FrameFactoryImpl : public mojom::FrameFactory { public: - explicit RenderFrameSetupImpl( - mojo::InterfaceRequest<mojom::RenderFrameSetup> request) + explicit FrameFactoryImpl(mojom::FrameFactoryRequest request) : routing_id_highmark_(-1), binding_(this, std::move(request)) {} - void ExchangeInterfaceProviders( - int32_t frame_routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) override { + private: + // mojom::FrameFactory: + void CreateFrame(int32_t frame_routing_id, + mojom::FrameRequest frame_request, + mojom::FrameHostPtr frame_host) override { // TODO(morrita): This is for investigating http://crbug.com/415059 and // should be removed once it is fixed. CHECK_LT(routing_id_highmark_, frame_routing_id); @@ -333,28 +357,26 @@ class RenderFrameSetupImpl : public mojom::RenderFrameSetup { // created due to a race between the message and a ViewMsg_New IPC that // triggers creation of the RenderFrame we want. if (!frame) { - RenderThreadImpl::current()->RegisterPendingRenderFrameConnect( - frame_routing_id, std::move(services), std::move(exposed_services)); + RenderThreadImpl::current()->RegisterPendingFrameCreate( + frame_routing_id, std::move(frame_request), std::move(frame_host)); return; } - frame->BindServiceRegistry(std::move(services), - std::move(exposed_services)); + frame->Bind(std::move(frame_request), std::move(frame_host)); } private: int32_t routing_id_highmark_; - mojo::StrongBinding<mojom::RenderFrameSetup> binding_; + mojo::StrongBinding<mojom::FrameFactory> binding_; }; -void CreateRenderFrameSetup( - mojo::InterfaceRequest<mojom::RenderFrameSetup> request) { - new RenderFrameSetupImpl(std::move(request)); +void CreateFrameFactory(mojom::FrameFactoryRequest request) { + new FrameFactoryImpl(std::move(request)); } void SetupEmbeddedWorkerOnWorkerThread( - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtrInfo exposed_services) { + shell::mojom::InterfaceProviderRequest request, + shell::mojom::InterfaceProviderPtrInfo remote_interfaces) { ServiceWorkerContextClient* client = ServiceWorkerContextClient::ThreadSpecificInstance(); // It is possible for client to be null if for some reason the worker died @@ -362,8 +384,8 @@ void SetupEmbeddedWorkerOnWorkerThread( // nothing and let mojo close the connection. if (!client) return; - client->BindServiceRegistry(std::move(services), - mojo::MakeProxy(std::move(exposed_services))); + client->BindInterfaceProviders(std::move(request), + mojo::MakeProxy(std::move(remote_interfaces))); } class EmbeddedWorkerSetupImpl : public mojom::EmbeddedWorkerSetup { @@ -374,12 +396,12 @@ class EmbeddedWorkerSetupImpl : public mojom::EmbeddedWorkerSetup { void ExchangeInterfaceProviders( int32_t thread_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) override { + shell::mojom::InterfaceProviderRequest request, + shell::mojom::InterfaceProviderPtr remote_interfaces) override { WorkerThreadRegistry::Instance()->GetTaskRunnerFor(thread_id)->PostTask( FROM_HERE, - base::Bind(&SetupEmbeddedWorkerOnWorkerThread, base::Passed(&services), - base::Passed(exposed_services.PassInterface()))); + base::Bind(&SetupEmbeddedWorkerOnWorkerThread, base::Passed(&request), + base::Passed(remote_interfaces.PassInterface()))); } private: @@ -430,8 +452,7 @@ scoped_refptr<ContextProviderCommandBuffer> CreateOffscreenContext( std::move(gpu_channel_host), stream_id, stream_priority, gpu::kNullSurfaceHandle, GURL("chrome://gpu/RenderThreadImpl::CreateOffscreenContext"), - gfx::PreferIntegratedGpu, automatic_flushes, support_locking, limits, - attributes, nullptr, type)); + automatic_flushes, support_locking, limits, attributes, nullptr, type)); } } // namespace @@ -582,9 +603,11 @@ RenderThreadImpl::RenderThreadImpl( std::unique_ptr<scheduler::RendererScheduler> scheduler, scoped_refptr<base::SingleThreadTaskRunner>& resource_task_queue) : ChildThreadImpl(Options::Builder() - .InBrowserProcess(params).UseMojoChannel(true).Build()), + .InBrowserProcess(params) + .UseMojoChannel(true) + .Build()), renderer_scheduler_(std::move(scheduler)), - raster_worker_pool_(new RasterWorkerPool()) { + categorized_worker_pool_(new CategorizedWorkerPool()) { Init(resource_task_queue); } @@ -596,7 +619,7 @@ RenderThreadImpl::RenderThreadImpl( : ChildThreadImpl(Options::Builder().UseMojoChannel(true).Build()), renderer_scheduler_(std::move(scheduler)), main_message_loop_(std::move(main_message_loop)), - raster_worker_pool_(new RasterWorkerPool()) { + categorized_worker_pool_(new CategorizedWorkerPool()) { scoped_refptr<base::SingleThreadTaskRunner> test_task_counter; Init(test_task_counter); } @@ -609,7 +632,7 @@ void RenderThreadImpl::Init( base::PlatformThread::CurrentId(), kTraceEventRendererMainThreadSortIndex); -#if defined(OS_MACOSX) || (defined(OS_ANDROID) && !defined(USE_AURA)) +#if defined(USE_EXTERNAL_POPUP_MENU) // On Mac and Android Java UI, the select popups are rendered by the browser. blink::WebView::setUseExternalPopupMenus(true); #endif @@ -627,7 +650,6 @@ void RenderThreadImpl::Init( hidden_widget_count_ = 0; idle_notification_delay_in_ms_ = kInitialIdleHandlerDelayMs; idle_notifications_to_skip_ = 0; - layout_test_mode_ = false; appcache_dispatcher_.reset( new AppCacheDispatcher(Get(), new AppCacheFrontendImpl())); @@ -648,7 +670,7 @@ void RenderThreadImpl::Init( media_stream_center_ = NULL; - blob_message_filter_ = new BlobMessageFilter(); + blob_message_filter_ = new BlobMessageFilter(GetFileThreadMessageLoopProxy()); AddFilter(blob_message_filter_.get()); db_message_filter_ = new DBMessageFilter(); AddFilter(db_message_filter_.get()); @@ -690,9 +712,6 @@ void RenderThreadImpl::Init( midi_message_filter_ = new MidiMessageFilter(GetIOMessageLoopProxy()); AddFilter(midi_message_filter_.get()); - bluetooth_message_filter_ = new BluetoothMessageFilter(thread_safe_sender()); - AddFilter(bluetooth_message_filter_->GetFilter()); - AddFilter((new IndexedDBMessageFilter(thread_safe_sender()))->GetFilter()); AddFilter((new CacheStorageMessageFilter(thread_safe_sender()))->GetFilter()); @@ -708,6 +727,16 @@ void RenderThreadImpl::Init( const base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); +#if defined(ENABLE_IPC_FUZZER) + if (command_line.HasSwitch(switches::kIpcDumpDirectory)) { + base::FilePath dump_directory = + command_line.GetSwitchValuePath(switches::kIpcDumpDirectory); + IPC::ChannelProxy::OutgoingMessageFilter* filter = + LoadExternalIPCDumper(dump_directory); + GetChannel()->set_outgoing_message_filter(filter); + } +#endif + cc::SetClientNameForMetrics("Renderer"); is_threaded_animation_enabled_ = @@ -800,7 +829,7 @@ void RenderThreadImpl::Init( // image decode tasks. are_image_decode_tasks_enabled_ = true; - raster_worker_pool_->Start(num_raster_threads); + categorized_worker_pool_->Start(num_raster_threads); // TODO(boliu): In single process, browser main loop should set up the // discardable memory manager, and should skip this if kSingleProcess. @@ -808,19 +837,22 @@ void RenderThreadImpl::Init( base::DiscardableMemoryAllocator::SetInstance( ChildThreadImpl::discardable_shared_memory_manager()); - service_registry()->AddService(base::Bind(CreateRenderFrameSetup)); - service_registry()->AddService(base::Bind(CreateEmbeddedWorkerSetup)); + GetContentClient()->renderer()->ExposeInterfacesToBrowser( + GetInterfaceRegistry()); -#if defined(MOJO_SHELL_CLIENT) + GetInterfaceRegistry()->AddInterface(base::Bind(CreateFrameFactory)); + GetInterfaceRegistry()->AddInterface(base::Bind(CreateEmbeddedWorkerSetup)); + +#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA) // We may not have a MojoShellConnection object in tests that directly // instantiate a RenderThreadImpl. - if (MojoShellConnection::Get() && + if (MojoShellConnection::GetForProcess() && base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kUseMusInRenderer)) CreateRenderWidgetWindowTreeClientFactory(); #endif - service_registry()->ConnectToRemoteService( + GetRemoteInterfaces()->GetInterface( mojo::GetProxy(&storage_partition_service_)); is_renderer_suspended_ = false; @@ -896,7 +928,7 @@ void RenderThreadImpl::Shutdown() { RemoveFilter(audio_message_filter_.get()); audio_message_filter_ = NULL; - raster_worker_pool_->Shutdown(); + categorized_worker_pool_->Shutdown(); main_input_callback_.Cancel(); input_handler_manager_.reset(); @@ -930,6 +962,7 @@ void RenderThreadImpl::Shutdown() { // Shut down the message loop and the renderer scheduler before shutting down // Blink. This prevents a scenario where a pending task in the message loop // accesses Blink objects after Blink shuts down. + renderer_scheduler_->SetRAILModeObserver(nullptr); renderer_scheduler_->Shutdown(); if (main_message_loop_) main_message_loop_->RunUntilIdle(); @@ -1009,24 +1042,17 @@ RenderThreadImpl::GetIOMessageLoopProxy() { void RenderThreadImpl::AddRoute(int32_t routing_id, IPC::Listener* listener) { ChildThreadImpl::GetRouter()->AddRoute(routing_id, listener); - PendingRenderFrameConnectMap::iterator it = - pending_render_frame_connects_.find(routing_id); - if (it == pending_render_frame_connects_.end()) + auto it = pending_frame_creates_.find(routing_id); + if (it == pending_frame_creates_.end()) return; RenderFrameImpl* frame = RenderFrameImpl::FromRoutingID(routing_id); if (!frame) return; - scoped_refptr<PendingRenderFrameConnect> connection(it->second); - shell::mojom::InterfaceProviderRequest services( - std::move(connection->services())); - shell::mojom::InterfaceProviderPtr exposed_services( - std::move(connection->exposed_services())); - exposed_services.set_connection_error_handler(mojo::Closure()); - pending_render_frame_connects_.erase(it); - - frame->BindServiceRegistry(std::move(services), std::move(exposed_services)); + scoped_refptr<PendingFrameCreate> create(it->second); + frame->Bind(it->second->TakeFrameRequest(), it->second->TakeFrameHost()); + pending_frame_creates_.erase(it); } void RenderThreadImpl::RemoveRoute(int32_t routing_id) { @@ -1050,15 +1076,15 @@ void RenderThreadImpl::RemoveEmbeddedWorkerRoute(int32_t routing_id) { } } -void RenderThreadImpl::RegisterPendingRenderFrameConnect( +void RenderThreadImpl::RegisterPendingFrameCreate( int routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) { - std::pair<PendingRenderFrameConnectMap::iterator, bool> result = - pending_render_frame_connects_.insert(std::make_pair( + mojom::FrameRequest frame_request, + mojom::FrameHostPtr frame_host) { + std::pair<PendingFrameCreateMap::iterator, bool> result = + pending_frame_creates_.insert(std::make_pair( routing_id, - make_scoped_refptr(new PendingRenderFrameConnect( - routing_id, std::move(services), std::move(exposed_services))))); + make_scoped_refptr(new PendingFrameCreate( + routing_id, std::move(frame_request), std::move(frame_host))))); CHECK(result.second) << "Inserting a duplicate item."; } @@ -1105,7 +1131,6 @@ void RenderThreadImpl::InitializeCompositorThread() { FROM_HERE, base::Bind(base::IgnoreResult(&ThreadRestrictions::SetIOAllowed), false)); - InputHandlerManagerClient* input_handler_manager_client = nullptr; SynchronousInputHandlerProxyClient* synchronous_input_handler_proxy_client = nullptr; #if defined(OS_ANDROID) @@ -1113,22 +1138,17 @@ void RenderThreadImpl::InitializeCompositorThread() { sync_compositor_message_filter_ = new SynchronousCompositorFilter(compositor_task_runner_); AddFilter(sync_compositor_message_filter_.get()); - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kSyncInputForSyncCompositor)) { - input_handler_manager_client = sync_compositor_message_filter_.get(); - } synchronous_input_handler_proxy_client = sync_compositor_message_filter_.get(); } #endif - if (!input_handler_manager_client) { - scoped_refptr<InputEventFilter> compositor_input_event_filter( - new InputEventFilter(main_input_callback_.callback(), - main_thread_compositor_task_runner_, - compositor_task_runner_)); - input_handler_manager_client = compositor_input_event_filter.get(); - input_event_filter_ = compositor_input_event_filter; - } + scoped_refptr<InputEventFilter> compositor_input_event_filter( + new InputEventFilter(main_input_callback_.callback(), + main_thread_compositor_task_runner_, + compositor_task_runner_)); + InputHandlerManagerClient* input_handler_manager_client = + compositor_input_event_filter.get(); + input_event_filter_ = compositor_input_event_filter; input_handler_manager_.reset(new InputHandlerManager( compositor_task_runner_, input_handler_manager_client, synchronous_input_handler_proxy_client, renderer_scheduler_.get())); @@ -1150,12 +1170,13 @@ void RenderThreadImpl::InitializeWebKit( blink_platform_impl_.reset(new RendererBlinkPlatformImpl( renderer_scheduler_.get(), - static_cast<ServiceRegistryImpl*>(service_registry())->GetWeakPtr())); + GetRemoteInterfaces()->GetWeakPtr())); blink::initialize(blink_platform_impl_.get()); v8::Isolate* isolate = blink::mainThreadIsolate(); isolate->SetCreateHistogramFunction(CreateHistogram); isolate->SetAddHistogramSampleFunction(AddHistogramSample); + renderer_scheduler_->SetRAILModeObserver(this); main_thread_compositor_task_runner_ = renderer_scheduler_->CompositorTaskRunner(); @@ -1184,6 +1205,9 @@ void RenderThreadImpl::InitializeWebKit( resource_task_queue2); resource_dispatcher()->SetMainThreadTaskRunner(resource_task_queue2); + websocket_message_filter()->SetLoadingTaskRunner( + renderer_scheduler_->LoadingTaskRunner()); + if (!command_line.HasSwitch(switches::kDisableThreadedCompositing) && !command_line.HasSwitch(switches::kUseRemoteCompositing)) InitializeCompositorThread(); @@ -1266,6 +1290,10 @@ void RenderThreadImpl::RegisterSchemes() { // chrome-devtools: WebString devtools_scheme(base::ASCIIToUTF16(kChromeDevToolsScheme)); WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(devtools_scheme); + + // view-source: + WebString view_source_scheme(base::ASCIIToUTF16(kViewSourceScheme)); + WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(view_source_scheme); } void RenderThreadImpl::NotifyTimezoneChange() { @@ -1499,7 +1527,7 @@ bool RenderThreadImpl::EnableStreamTextureCopy() { AudioRendererMixerManager* RenderThreadImpl::GetAudioRendererMixerManager() { if (!audio_renderer_mixer_manager_) { - audio_renderer_mixer_manager_.reset(new AudioRendererMixerManager()); + audio_renderer_mixer_manager_ = AudioRendererMixerManager::Create(); } return audio_renderer_mixer_manager_.get(); @@ -1531,11 +1559,6 @@ void RenderThreadImpl::PreCacheFontCharacters(const LOGFONT& log_font, #endif // OS_WIN -ServiceRegistry* RenderThreadImpl::GetServiceRegistry() { - DCHECK(service_registry()); - return service_registry(); -} - bool RenderThreadImpl::IsGpuRasterizationForced() { return is_gpu_rasterization_forced_; } @@ -1600,12 +1623,6 @@ scheduler::RendererScheduler* RenderThreadImpl::GetRendererScheduler() { std::unique_ptr<cc::BeginFrameSource> RenderThreadImpl::CreateExternalBeginFrameSource(int routing_id) { -#if defined(OS_ANDROID) - if (sync_compositor_message_filter_) { - return base::WrapUnique(new SynchronousCompositorExternalBeginFrameSource( - routing_id, sync_compositor_message_filter_.get())); - } -#endif return base::WrapUnique(new CompositorExternalBeginFrameSource( compositor_message_filter_.get(), sync_message_filter(), routing_id)); } @@ -1616,7 +1633,7 @@ RenderThreadImpl::GetImageSerializationProcessor() { } cc::TaskGraphRunner* RenderThreadImpl::GetTaskGraphRunner() { - return raster_worker_pool_->GetTaskGraphRunner(); + return categorized_worker_pool_->GetTaskGraphRunner(); } bool RenderThreadImpl::AreImageDecodeTasksEnabled() { @@ -1627,6 +1644,11 @@ bool RenderThreadImpl::IsThreadedAnimationEnabled() { return is_threaded_animation_enabled_; } +void RenderThreadImpl::OnRAILModeChanged(v8::RAILMode rail_mode) { + blink::mainThreadIsolate()->SetRAILMode(rail_mode); + blink::setRAILModeOnWorkerThreadIsolates(rail_mode); +} + bool RenderThreadImpl::IsMainThread() { return !!current(); } @@ -1789,6 +1811,123 @@ scoped_refptr<gpu::GpuChannelHost> RenderThreadImpl::EstablishGpuChannelSync( return gpu_channel_; } +std::unique_ptr<cc::OutputSurface> +RenderThreadImpl::CreateCompositorOutputSurface( + bool use_software, + int routing_id, + scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue, + const GURL& url) { + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + if (command_line.HasSwitch(switches::kDisableGpuCompositing)) + use_software = true; + +#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA) + auto shell_connection = MojoShellConnection::GetForProcess(); + if (shell_connection && !use_software && + command_line.HasSwitch(switches::kUseMusInRenderer)) { + mus::GpuService::Initialize(shell_connection->GetConnector()); + RenderWidgetMusConnection* connection = + RenderWidgetMusConnection::GetOrCreate(routing_id); + return connection->CreateOutputSurface(); + } +#endif + + uint32_t output_surface_id = g_next_output_surface_id++; + + if (command_line.HasSwitch(switches::kEnableVulkan)) { + scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider = + cc::VulkanInProcessContextProvider::Create(); + if (vulkan_context_provider) { + DCHECK(!layout_test_mode()); + return base::WrapUnique(new CompositorOutputSurface( + routing_id, output_surface_id, std::move(vulkan_context_provider), + std::move(frame_swap_message_queue))); + } + } + + // Create a gpu process channel and verify we want to use GPU compositing + // before creating any context providers. + scoped_refptr<gpu::GpuChannelHost> gpu_channel_host; + if (!use_software) { + gpu_channel_host = EstablishGpuChannelSync( + CAUSE_FOR_GPU_LAUNCH_RENDERER_VERIFY_GPU_COMPOSITING); + if (!gpu_channel_host) { + // Cause the compositor to wait and try again. + return nullptr; + } + // We may get a valid channel, but with a software renderer. In that case, + // disable GPU compositing. + if (gpu_channel_host->gpu_info().software_rendering) + use_software = true; + } + + if (use_software) { + DCHECK(!layout_test_mode()); + return base::WrapUnique(new CompositorOutputSurface( + routing_id, output_surface_id, nullptr, nullptr, + std::move(frame_swap_message_queue))); + } + + scoped_refptr<ContextProviderCommandBuffer> worker_context_provider = + SharedCompositorWorkerContextProvider(); + if (!worker_context_provider) { + // Cause the compositor to wait and try again. + return nullptr; + } + + // The renderer compositor context doesn't do a lot of stuff, so we don't + // expect it to need a lot of space for commands or transfer. Raster and + // uploads happen on the worker context instead. + gpu::SharedMemoryLimits limits = gpu::SharedMemoryLimits::ForMailboxContext(); + + // This is for an offscreen context for the compositor. So the default + // framebuffer doesn't need alpha, depth, stencil, antialiasing. + gpu::gles2::ContextCreationAttribHelper attributes; + attributes.alpha_size = -1; + attributes.depth_size = 0; + attributes.stencil_size = 0; + attributes.samples = 0; + attributes.sample_buffers = 0; + attributes.bind_generates_resource = false; + attributes.lose_context_when_out_of_memory = true; + + constexpr bool automatic_flushes = false; + constexpr bool support_locking = false; + + // The compositor context shares resources with the worker context unless + // the worker is async. + ContextProviderCommandBuffer* share_context = worker_context_provider.get(); + if (IsAsyncWorkerContextEnabled()) + share_context = nullptr; + + scoped_refptr<ContextProviderCommandBuffer> context_provider( + new ContextProviderCommandBuffer( + gpu_channel_host, gpu::GPU_STREAM_DEFAULT, + gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle, url, + automatic_flushes, support_locking, limits, attributes, share_context, + command_buffer_metrics::RENDER_COMPOSITOR_CONTEXT)); + + if (layout_test_deps_) { + return layout_test_deps_->CreateOutputSurface( + std::move(gpu_channel_host), std::move(context_provider), + std::move(worker_context_provider), this); + } + +#if defined(OS_ANDROID) + if (sync_compositor_message_filter_) { + return base::WrapUnique(new SynchronousCompositorOutputSurface( + std::move(context_provider), std::move(worker_context_provider), + routing_id, output_surface_id, sync_compositor_message_filter_.get(), + std::move(frame_swap_message_queue))); + } +#endif + + return base::WrapUnique(new CompositorOutputSurface( + routing_id, output_surface_id, std::move(context_provider), + std::move(worker_context_provider), std::move(frame_swap_message_queue))); +} + blink::WebMediaStreamCenter* RenderThreadImpl::CreateMediaStreamCenter( blink::WebMediaStreamCenterClient* client) { #if defined(ENABLE_WEBRTC) @@ -1906,7 +2045,7 @@ void RenderThreadImpl::OnMemoryPressure( // Do not call into blink if it is not initialized. if (blink_platform_impl_) { - blink::WebMemoryPressureListener::onMemoryPressure( + blink::WebMemoryCoordinator::onMemoryPressure( static_cast<blink::WebMemoryPressureLevel>(memory_pressure_level)); if (memory_pressure_level == @@ -1945,7 +2084,7 @@ RenderThreadImpl::GetMediaThreadTaskRunner() { } base::TaskRunner* RenderThreadImpl::GetWorkerTaskRunner() { - return raster_worker_pool_.get(); + return categorized_worker_pool_.get(); } scoped_refptr<ContextProviderCommandBuffer> @@ -2049,29 +2188,27 @@ void RenderThreadImpl::ReleaseFreeMemory() { blink::decommitFreeableMemory(); } -RenderThreadImpl::PendingRenderFrameConnect::PendingRenderFrameConnect( +RenderThreadImpl::PendingFrameCreate::PendingFrameCreate( int routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) + mojom::FrameRequest frame_request, + mojom::FrameHostPtr frame_host) : routing_id_(routing_id), - services_(std::move(services)), - exposed_services_(std::move(exposed_services)) { - // The RenderFrame may be deleted before the ExchangeInterfaceProviders - // message is received. In that case, the RenderFrameHost should close the - // connection, which is detected by setting an error handler on - // |exposed_services_|. - exposed_services_.set_connection_error_handler(base::Bind( - &RenderThreadImpl::PendingRenderFrameConnect::OnConnectionError, + frame_request_(std::move(frame_request)), + frame_host_(std::move(frame_host)) { + // The RenderFrame may be deleted before the CreateFrame message is received. + // In that case, the RenderFrameHost should cancel the create, which is + // detected by setting an error handler on |frame_host_|. + frame_host_.set_connection_error_handler(base::Bind( + &RenderThreadImpl::PendingFrameCreate::OnConnectionError, base::Unretained(this))); } -RenderThreadImpl::PendingRenderFrameConnect::~PendingRenderFrameConnect() { +RenderThreadImpl::PendingFrameCreate::~PendingFrameCreate() { } -void RenderThreadImpl::PendingRenderFrameConnect::OnConnectionError() { +void RenderThreadImpl::PendingFrameCreate::OnConnectionError() { size_t erased = - RenderThreadImpl::current()->pending_render_frame_connects_.erase( - routing_id_); + RenderThreadImpl::current()->pending_frame_creates_.erase(routing_id_); DCHECK_EQ(1u, erased); } diff --git a/chromium/content/renderer/render_thread_impl.h b/chromium/content/renderer/render_thread_impl.h index 486efe0dbfe..1f26f30d512 100644 --- a/chromium/content/renderer/render_thread_impl.h +++ b/chromium/content/renderer/render_thread_impl.h @@ -22,13 +22,16 @@ #include "base/threading/thread_checker.h" #include "base/timer/timer.h" #include "build/build_config.h" +#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/child/child_thread_impl.h" #include "content/common/content_export.h" +#include "content/common/frame.mojom.h" #include "content/common/frame_replication_state.h" #include "content/common/gpu_process_launch_causes.h" #include "content/common/storage_partition_service.mojom.h" #include "content/public/renderer/render_thread.h" #include "content/renderer/gpu/compositor_dependencies.h" +#include "content/renderer/layout_test_dependencies.h" #include "gpu/ipc/client/gpu_channel_host.h" #include "net/base/network_change_notifier.h" #include "third_party/WebKit/public/platform/WebConnectionType.h" @@ -59,6 +62,7 @@ class Thread; namespace cc { class ContextProvider; class ImageSerializationProcessor; +class OutputSurface; class TaskGraphRunner; } @@ -76,7 +80,6 @@ class GpuVideoAcceleratorFactories; } namespace scheduler { -class RendererScheduler; class WebThreadBase; } @@ -92,7 +95,6 @@ class AudioInputMessageFilter; class AudioMessageFilter; class AudioRendererMixerManager; class BlobMessageFilter; -class BluetoothMessageFilter; class BrowserPluginManager; class CacheStorageDispatcher; class CompositorForwardingMessageFilter; @@ -101,6 +103,7 @@ class DBMessageFilter; class DevToolsAgentFilter; class DomStorageDispatcher; class EmbeddedWorkerDispatcher; +class FrameSwapMessageQueue; class IndexedDBDispatcher; class InputHandlerManager; class MediaStreamCenter; @@ -110,7 +113,7 @@ class NetInfoDispatcher; class P2PSocketDispatcher; class PeerConnectionDependencyFactory; class PeerConnectionTracker; -class RasterWorkerPool; +class CategorizedWorkerPool; class RenderThreadObserver; class RendererBlinkPlatformImpl; class RendererDemuxerAndroid; @@ -144,6 +147,7 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread, public ChildThreadImpl, public gpu::GpuChannelHostFactory, + public scheduler::RendererScheduler::RAILModeObserver, NON_EXPORTED_BASE(public CompositorDependencies) { public: static RenderThreadImpl* Create(const InProcessChildThreadParams& params); @@ -191,7 +195,6 @@ class CONTENT_EXPORT RenderThreadImpl int PostTaskToAllWebWorkers(const base::Closure& closure) override; bool ResolveProxy(const GURL& url, std::string* proxy_list) override; base::WaitableEvent* GetShutdownEvent() override; - ServiceRegistry* GetServiceRegistry() override; // CompositorDependencies implementation. bool IsGpuRasterizationForced() override; @@ -218,20 +221,28 @@ class CONTENT_EXPORT RenderThreadImpl bool AreImageDecodeTasksEnabled() override; bool IsThreadedAnimationEnabled() override; + // scheduler::RendererScheduler::RAILModeObserver implementation. + void OnRAILModeChanged(v8::RAILMode rail_mode) override; + // Synchronously establish a channel to the GPU plugin if not previously // established or if it has been lost (for example if the GPU plugin crashed). // If there is a pending asynchronous request, it will be completed by the // time this routine returns. scoped_refptr<gpu::GpuChannelHost> EstablishGpuChannelSync(CauseForGpuLaunch); + std::unique_ptr<cc::OutputSurface> CreateCompositorOutputSurface( + bool use_software, + int routing_id, + scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue, + const GURL& url); + // True if we are running layout tests. This currently disables forwarding // various status messages to the console, skips network error pages, and // short circuits size update and focus events. - bool layout_test_mode() const { - return layout_test_mode_; - } - void set_layout_test_mode(bool layout_test_mode) { - layout_test_mode_ = layout_test_mode; + bool layout_test_mode() const { return !!layout_test_deps_; } + void set_layout_test_dependencies( + std::unique_ptr<LayoutTestDependencies> deps) { + layout_test_deps_ = std::move(deps); } RendererBlinkPlatformImpl* blink_platform_impl() const { @@ -437,10 +448,9 @@ class CONTENT_EXPORT RenderThreadImpl void AddEmbeddedWorkerRoute(int32_t routing_id, IPC::Listener* listener); void RemoveEmbeddedWorkerRoute(int32_t routing_id); - void RegisterPendingRenderFrameConnect( - int routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services); + void RegisterPendingFrameCreate(int routing_id, + mojom::FrameRequest frame, + mojom::FrameHostPtr host); mojom::StoragePartitionService* GetStoragePartitionService(); @@ -576,8 +586,8 @@ class CONTENT_EXPORT RenderThreadImpl bool webkit_shared_timer_suspended_; - // The following flag is used to control layout test specific behavior. - bool layout_test_mode_; + // Used to control layout test specific behavior. + std::unique_ptr<LayoutTestDependencies> layout_test_deps_; // Timer that periodically calls IdleHandler. base::RepeatingTimer idle_timer_; @@ -614,7 +624,7 @@ class CONTENT_EXPORT RenderThreadImpl scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_; // Pool of workers used for raster operations (e.g., tile rasterization). - scoped_refptr<RasterWorkerPool> raster_worker_pool_; + scoped_refptr<CategorizedWorkerPool> categorized_worker_pool_; base::CancelableCallback<void(const IPC::Message&)> main_input_callback_; scoped_refptr<IPC::MessageFilter> input_event_filter_; @@ -626,8 +636,6 @@ class CONTENT_EXPORT RenderThreadImpl scoped_refptr<StreamTextureFactory> stream_texture_factory_; #endif - scoped_refptr<BluetoothMessageFilter> bluetooth_message_filter_; - scoped_refptr<ContextProviderCommandBuffer> shared_main_thread_contexts_; base::ObserverList<RenderThreadObserver> observers_; @@ -666,36 +674,34 @@ class CONTENT_EXPORT RenderThreadImpl bool are_image_decode_tasks_enabled_; bool is_threaded_animation_enabled_; - class PendingRenderFrameConnect - : public base::RefCounted<PendingRenderFrameConnect> { + class PendingFrameCreate : public base::RefCounted<PendingFrameCreate> { public: - PendingRenderFrameConnect( - int routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services); - - shell::mojom::InterfaceProviderRequest& services() { return services_; } - - shell::mojom::InterfaceProviderPtr& exposed_services() { - return exposed_services_; + PendingFrameCreate(int routing_id, + mojom::FrameRequest frame_request, + mojom::FrameHostPtr frame_host); + + mojom::FrameRequest TakeFrameRequest() { return std::move(frame_request_); } + mojom::FrameHostPtr TakeFrameHost() { + frame_host_.set_connection_error_handler(base::Closure()); + return std::move(frame_host_); } private: - friend class base::RefCounted<PendingRenderFrameConnect>; + friend class base::RefCounted<PendingFrameCreate>; - ~PendingRenderFrameConnect(); + ~PendingFrameCreate(); // Mojo error handler. void OnConnectionError(); int routing_id_; - shell::mojom::InterfaceProviderRequest services_; - shell::mojom::InterfaceProviderPtr exposed_services_; + mojom::FrameRequest frame_request_; + mojom::FrameHostPtr frame_host_; }; - typedef std::map<int, scoped_refptr<PendingRenderFrameConnect>> - PendingRenderFrameConnectMap; - PendingRenderFrameConnectMap pending_render_frame_connects_; + using PendingFrameCreateMap = + std::map<int, scoped_refptr<PendingFrameCreate>>; + PendingFrameCreateMap pending_frame_creates_; mojom::StoragePartitionServicePtr storage_partition_service_; diff --git a/chromium/content/renderer/render_view_browsertest.cc b/chromium/content/renderer/render_view_browsertest.cc index 98c0ad33f9c..57747020cd7 100644 --- a/chromium/content/renderer/render_view_browsertest.cc +++ b/chromium/content/renderer/render_view_browsertest.cc @@ -4,6 +4,7 @@ #include <stddef.h> #include <stdint.h> +#include <tuple> #include "base/bind.h" #include "base/callback.h" @@ -45,7 +46,7 @@ #include "content/public/test/frame_load_waiter.h" #include "content/public/test/render_view_test.h" #include "content/public/test/test_utils.h" -#include "content/renderer/accessibility/renderer_accessibility.h" +#include "content/renderer/accessibility/render_accessibility_impl.h" #include "content/renderer/devtools/devtools_agent.h" #include "content/renderer/gpu/render_widget_compositor.h" #include "content/renderer/history_controller.h" @@ -546,54 +547,6 @@ TEST_F(RenderViewImplTest, RenderFrameClearedAfterClose) { new_view->Release(); } -TEST_F(RenderViewImplTest, SaveImageFromDataURL) { - const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching( - ViewHostMsg_SaveImageFromDataURL::ID); - EXPECT_FALSE(msg1); - render_thread_->sink().ClearMessages(); - - const std::string image_data_url = - "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="; - - view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url)); - ProcessPendingMessages(); - const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching( - ViewHostMsg_SaveImageFromDataURL::ID); - EXPECT_TRUE(msg2); - - ViewHostMsg_SaveImageFromDataURL::Param param1; - ViewHostMsg_SaveImageFromDataURL::Read(msg2, ¶m1); - EXPECT_EQ(base::get<2>(param1).length(), image_data_url.length()); - EXPECT_EQ(base::get<2>(param1), image_data_url); - - ProcessPendingMessages(); - render_thread_->sink().ClearMessages(); - - const std::string large_data_url(1024 * 1024 * 20 - 1, 'd'); - - view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url)); - ProcessPendingMessages(); - const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching( - ViewHostMsg_SaveImageFromDataURL::ID); - EXPECT_TRUE(msg3); - - ViewHostMsg_SaveImageFromDataURL::Param param2; - ViewHostMsg_SaveImageFromDataURL::Read(msg3, ¶m2); - EXPECT_EQ(base::get<2>(param2).length(), large_data_url.length()); - EXPECT_EQ(base::get<2>(param2), large_data_url); - - ProcessPendingMessages(); - render_thread_->sink().ClearMessages(); - - const std::string exceeded_data_url(1024 * 1024 * 20 + 1, 'd'); - - view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url)); - ProcessPendingMessages(); - const IPC::Message* msg4 = render_thread_->sink().GetFirstMessageMatching( - ViewHostMsg_SaveImageFromDataURL::ID); - EXPECT_FALSE(msg4); -} - // Test that we get form state change notifications when input fields change. TEST_F(RenderViewImplTest, OnNavStateChanged) { view()->set_send_content_state_immediately(true); @@ -633,11 +586,11 @@ TEST_F(RenderViewImplTest, OnNavigationHttpPost) { request_params.page_id = -1; // Set up post data. - const unsigned char* raw_data = reinterpret_cast<const unsigned char*>( - "post \0\ndata"); - const unsigned int length = 11; - const std::vector<unsigned char> post_data(raw_data, raw_data + length); - start_params.browser_initiated_post_data = post_data; + const char raw_data[] = "post \0\ndata"; + const size_t length = arraysize(raw_data); + scoped_refptr<ResourceRequestBodyImpl> post_data(new ResourceRequestBodyImpl); + post_data->AppendBytes(raw_data, length); + common_params.post_data = post_data; frame()->Navigate(common_params, start_params, request_params); ProcessPendingMessages(); @@ -650,12 +603,12 @@ TEST_F(RenderViewImplTest, OnNavigationHttpPost) { FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params; FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg, &host_nav_params); - EXPECT_EQ("POST", base::get<0>(host_nav_params).method); + EXPECT_EQ("POST", std::get<0>(host_nav_params).method); // Check post data sent to browser matches - EXPECT_TRUE(base::get<0>(host_nav_params).page_state.IsValid()); + EXPECT_TRUE(std::get<0>(host_nav_params).page_state.IsValid()); std::unique_ptr<HistoryEntry> entry = - PageStateToHistoryEntry(base::get<0>(host_nav_params).page_state); + PageStateToHistoryEntry(std::get<0>(host_nav_params).page_state); blink::WebHTTPBody body = entry->root().httpBody(); blink::WebHTTPBody::Element element; bool successful = body.elementAt(0, element); @@ -697,7 +650,7 @@ TEST_F(RenderViewImplTest, OnBrowserNavigationUpdatePageID) { FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params; FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg, &host_nav_params); - EXPECT_TRUE(base::get<0>(host_nav_params).page_state.IsValid()); + EXPECT_TRUE(std::get<0>(host_nav_params).page_state.IsValid()); const IPC::Message* frame_page_id_msg = render_thread_->sink().GetUniqueMessageMatching( @@ -707,7 +660,7 @@ TEST_F(RenderViewImplTest, OnBrowserNavigationUpdatePageID) { FrameHostMsg_DidAssignPageId::Param host_page_id_params; FrameHostMsg_DidAssignPageId::Read(frame_page_id_msg, &host_page_id_params); - EXPECT_EQ(base::get<0>(host_page_id_params), view_page_id()); + EXPECT_EQ(std::get<0>(host_page_id_params), view_page_id()); } #if defined(OS_ANDROID) @@ -734,7 +687,7 @@ TEST_F(RenderViewImplTest, OnNavigationLoadDataWithBaseURL) { // Check post data sent to browser matches. FrameHostMsg_UpdateTitle::Param title_params; EXPECT_TRUE(FrameHostMsg_UpdateTitle::Read(frame_title_msg, &title_params)); - EXPECT_EQ(base::ASCIIToUTF16("Data page"), base::get<0>(title_params)); + EXPECT_EQ(base::ASCIIToUTF16("Data page"), std::get<0>(title_params)); } #endif @@ -1044,8 +997,8 @@ TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) { ASSERT_TRUE(msg_A); ViewHostMsg_UpdateState::Param param; ViewHostMsg_UpdateState::Read(msg_A, ¶m); - int page_id_A = base::get<0>(param); - PageState state_A = base::get<1>(param); + int page_id_A = std::get<0>(param); + PageState state_A = std::get<1>(param); EXPECT_EQ(1, page_id_A); render_thread_->sink().ClearMessages(); @@ -1058,8 +1011,8 @@ TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) { ViewHostMsg_UpdateState::ID); ASSERT_TRUE(msg_B); ViewHostMsg_UpdateState::Read(msg_B, ¶m); - int page_id_B = base::get<0>(param); - PageState state_B = base::get<1>(param); + int page_id_B = std::get<0>(param); + PageState state_B = std::get<1>(param); EXPECT_EQ(2, page_id_B); EXPECT_NE(state_A, state_B); render_thread_->sink().ClearMessages(); @@ -1073,8 +1026,8 @@ TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) { ViewHostMsg_UpdateState::ID); ASSERT_TRUE(msg_C); ViewHostMsg_UpdateState::Read(msg_C, ¶m); - int page_id_C = base::get<0>(param); - PageState state_C = base::get<1>(param); + int page_id_C = std::get<0>(param); + PageState state_C = std::get<1>(param); EXPECT_EQ(3, page_id_C); EXPECT_NE(state_B, state_C); render_thread_->sink().ClearMessages(); @@ -1128,8 +1081,8 @@ TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) { ViewHostMsg_UpdateState::ID); ASSERT_TRUE(msg); ViewHostMsg_UpdateState::Read(msg, ¶m); - int page_id = base::get<0>(param); - PageState state = base::get<1>(param); + int page_id = std::get<0>(param); + PageState state = std::get<1>(param); EXPECT_EQ(page_id_C, page_id); EXPECT_NE(state_A, state); EXPECT_NE(state_B, state); @@ -1202,7 +1155,7 @@ TEST_F(RenderViewImplTest, OnImeTypeChanged) { EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type()); ViewHostMsg_TextInputStateChanged::Param params; ViewHostMsg_TextInputStateChanged::Read(msg, ¶ms); - TextInputState p = base::get<0>(params); + TextInputState p = std::get<0>(params); ui::TextInputType type = p.type; ui::TextInputMode input_mode = p.mode; bool can_compose_inline = p.can_compose_inline; @@ -1222,7 +1175,7 @@ TEST_F(RenderViewImplTest, OnImeTypeChanged) { EXPECT_TRUE(msg != NULL); EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type()); ViewHostMsg_TextInputStateChanged::Read(msg, ¶ms); - p = base::get<0>(params); + p = std::get<0>(params); type = p.type; input_mode = p.mode; EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, type); @@ -1247,7 +1200,7 @@ TEST_F(RenderViewImplTest, OnImeTypeChanged) { EXPECT_TRUE(msg != NULL); EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type()); ViewHostMsg_TextInputStateChanged::Read(msg, ¶ms); - p = base::get<0>(params); + p = std::get<0>(params); type = p.type; input_mode = p.mode; EXPECT_EQ(test_case->expected_mode, input_mode); @@ -2007,7 +1960,7 @@ TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) { ViewHostMsg_FocusedNodeChanged::Param params; ViewHostMsg_FocusedNodeChanged::Read(msg1, ¶ms); - EXPECT_TRUE(base::get<0>(params)); + EXPECT_TRUE(std::get<0>(params)); render_thread_->sink().ClearMessages(); ExecuteJavaScriptForTests("document.getElementById('test2').focus();"); @@ -2015,7 +1968,7 @@ TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) { ViewHostMsg_FocusedNodeChanged::ID); EXPECT_TRUE(msg2); ViewHostMsg_FocusedNodeChanged::Read(msg2, ¶ms); - EXPECT_TRUE(base::get<0>(params)); + EXPECT_TRUE(std::get<0>(params)); render_thread_->sink().ClearMessages(); view()->webview()->clearFocusedElement(); @@ -2023,7 +1976,7 @@ TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) { ViewHostMsg_FocusedNodeChanged::ID); EXPECT_TRUE(msg3); ViewHostMsg_FocusedNodeChanged::Read(msg3, ¶ms); - EXPECT_FALSE(base::get<0>(params)); + EXPECT_FALSE(std::get<0>(params)); render_thread_->sink().ClearMessages(); } @@ -2071,19 +2024,19 @@ TEST_F(RenderViewImplTest, ServiceWorkerNetworkProviderSetup) { TEST_F(RenderViewImplTest, OnSetAccessibilityMode) { ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode()); - ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility()); + ASSERT_FALSE(frame()->render_accessibility()); frame()->SetAccessibilityMode(AccessibilityModeTreeOnly); ASSERT_EQ(AccessibilityModeTreeOnly, frame()->accessibility_mode()); - ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility()); + ASSERT_TRUE(frame()->render_accessibility()); frame()->SetAccessibilityMode(AccessibilityModeOff); ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode()); - ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility()); + ASSERT_FALSE(frame()->render_accessibility()); frame()->SetAccessibilityMode(AccessibilityModeComplete); ASSERT_EQ(AccessibilityModeComplete, frame()->accessibility_mode()); - ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility()); + ASSERT_TRUE(frame()->render_accessibility()); } // Sanity check for the Navigation Timing API |navigationStart| override. We @@ -2123,7 +2076,7 @@ TEST_F(RenderViewImplTest, RendererNavigationStartTransmittedToBrowser) { FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params; FrameHostMsg_DidStartProvisionalLoad::Read(frame_navigate_msg, &host_nav_params); - base::TimeTicks transmitted_start = base::get<1>(host_nav_params); + base::TimeTicks transmitted_start = std::get<1>(host_nav_params); EXPECT_FALSE(transmitted_start.is_null()); EXPECT_LT(lower_bound_navigation_start, transmitted_start); } @@ -2147,7 +2100,7 @@ TEST_F(RenderViewImplTest, BrowserNavigationStartNotUsedForReload) { FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params = ProcessAndReadIPC<FrameHostMsg_DidStartProvisionalLoad>(); // The true timestamp is later than the browser initiated one. - EXPECT_PRED2(TimeTicksGT, base::get<1>(host_nav_params), + EXPECT_PRED2(TimeTicksGT, std::get<1>(host_nav_params), common_params.navigation_start); } @@ -2169,7 +2122,7 @@ TEST_F(RenderViewImplTest, BrowserNavigationStartNotUsedForHistoryNavigation) { StartNavigationParams(), RequestNavigationParams()); FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params = ProcessAndReadIPC<FrameHostMsg_DidStartProvisionalLoad>(); - EXPECT_PRED2(TimeTicksGT, base::get<1>(host_nav_params), + EXPECT_PRED2(TimeTicksGT, std::get<1>(host_nav_params), common_params_back.navigation_start); render_thread_->sink().ClearMessages(); @@ -2182,7 +2135,7 @@ TEST_F(RenderViewImplTest, BrowserNavigationStartNotUsedForHistoryNavigation) { StartNavigationParams(), RequestNavigationParams()); FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params2 = ProcessAndReadIPC<FrameHostMsg_DidStartProvisionalLoad>(); - EXPECT_PRED2(TimeTicksGT, base::get<1>(host_nav_params2), + EXPECT_PRED2(TimeTicksGT, std::get<1>(host_nav_params2), common_params_forward.navigation_start); } @@ -2197,7 +2150,7 @@ TEST_F(RenderViewImplTest, BrowserNavigationStartSuccessfullyTransmitted) { FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params = ProcessAndReadIPC<FrameHostMsg_DidStartProvisionalLoad>(); - EXPECT_EQ(base::get<1>(host_nav_params), common_params.navigation_start); + EXPECT_EQ(std::get<1>(host_nav_params), common_params.navigation_start); } TEST_F(RenderViewImplTest, PreferredSizeZoomed) { diff --git a/chromium/content/renderer/render_view_impl.cc b/chromium/content/renderer/render_view_impl.cc index c6c6a4991ce..be61076b8df 100644 --- a/chromium/content/renderer/render_view_impl.cc +++ b/chromium/content/renderer/render_view_impl.cc @@ -19,17 +19,20 @@ #include "base/i18n/rtl.h" #include "base/json/json_writer.h" #include "base/lazy_instance.h" +#include "base/location.h" #include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" #include "base/process/kill.h" #include "base/process/process.h" +#include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" @@ -42,15 +45,12 @@ #include "content/child/webmessageportchannel_impl.h" #include "content/common/content_constants_internal.h" #include "content/common/content_switches_internal.h" -#include "content/common/database_messages.h" #include "content/common/dom_storage/dom_storage_types.h" #include "content/common/drag_messages.h" #include "content/common/frame_messages.h" #include "content/common/frame_replication_state.h" -#include "content/common/input/input_event_utils.h" #include "content/common/input_messages.h" #include "content/common/page_messages.h" -#include "content/common/pepper_messages.h" #include "content/common/site_isolation_policy.h" #include "content/common/ssl_status_serialization.h" #include "content/common/view_messages.h" @@ -60,8 +60,6 @@ #include "content/public/common/content_switches.h" #include "content/public/common/drop_data.h" #include "content/public/common/favicon_url.h" -#include "content/public/common/file_chooser_file_info.h" -#include "content/public/common/file_chooser_params.h" #include "content/public/common/page_importance_signals.h" #include "content/public/common/page_state.h" #include "content/public/common/page_zoom.h" @@ -92,7 +90,6 @@ #include "content/renderer/render_frame_proxy.h" #include "content/renderer/render_process.h" #include "content/renderer/render_thread_impl.h" -#include "content/renderer/render_view_mouse_lock_dispatcher.h" #include "content/renderer/render_widget_fullscreen_pepper.h" #include "content/renderer/renderer_webapplicationcachehost_impl.h" #include "content/renderer/resizing_mode_selector.h" @@ -392,39 +389,55 @@ static void ConvertToFaviconSizes( /////////////////////////////////////////////////////////////////////////////// -struct RenderViewImpl::PendingFileChooser { - PendingFileChooser(const FileChooserParams& p, WebFileChooserCompletion* c) - : params(p), - completion(c) { - } - FileChooserParams params; - WebFileChooserCompletion* completion; // MAY BE NULL to skip callback. -}; - namespace { -class WebWidgetLockTarget : public MouseLockDispatcher::LockTarget { - public: - explicit WebWidgetLockTarget(blink::WebWidget* webwidget) - : webwidget_(webwidget) {} - - void OnLockMouseACK(bool succeeded) override { - if (succeeded) - webwidget_->didAcquirePointerLock(); - else - webwidget_->didNotAcquirePointerLock(); - } +WebDragData DropMetaDataToWebDragData( + const std::vector<DropData::Metadata>& drop_meta_data) { + std::vector<WebDragData::Item> item_list; + for (const auto& meta_data_item : drop_meta_data) { + if (meta_data_item.kind == DropData::Kind::STRING) { + WebDragData::Item item; + item.storageType = WebDragData::Item::StorageTypeString; + item.stringType = meta_data_item.mime_type; + // Have to pass a dummy URL here instead of an empty URL because the + // DropData received by browser_plugins goes through a round trip: + // DropData::MetaData --> WebDragData-->DropData. In the end, DropData + // will contain an empty URL (which means no URL is dragged) if the URL in + // WebDragData is empty. + if (base::EqualsASCII(meta_data_item.mime_type, + ui::Clipboard::kMimeTypeURIList)) { + item.stringData = WebString::fromUTF8("about:dragdrop-placeholder"); + } + item_list.push_back(item); + continue; + } - void OnMouseLockLost() override { webwidget_->didLosePointerLock(); } + // TODO(hush): crbug.com/584789. Blink needs to support creating a file with + // just the mimetype. This is needed to drag files to WebView on Android + // platform. + if ((meta_data_item.kind == DropData::Kind::FILENAME) && + !meta_data_item.filename.empty()) { + WebDragData::Item item; + item.storageType = WebDragData::Item::StorageTypeFilename; + item.filenameData = meta_data_item.filename.AsUTF16Unsafe(); + item_list.push_back(item); + continue; + } - bool HandleMouseLockedInputEvent(const blink::WebMouseEvent& event) override { - // The WebWidget handles mouse lock in WebKit's handleInputEvent(). - return false; + if (meta_data_item.kind == DropData::Kind::FILESYSTEMFILE) { + WebDragData::Item item; + item.storageType = WebDragData::Item::StorageTypeFileSystemFile; + item.fileSystemURL = meta_data_item.file_system_url; + item_list.push_back(item); + continue; + } } - private: - blink::WebWidget* webwidget_; -}; + WebDragData result; + result.initialize(); + result.setItems(item_list); + return result; +} WebDragData DropDataToWebDragData(const DropData& drop_data) { std::vector<WebDragData::Item> item_list; @@ -442,8 +455,6 @@ WebDragData DropDataToWebDragData(const DropData& drop_data) { item_list.push_back(item); } - // TODO(dcheng): Do we need to distinguish between null and empty URLs? Is it - // meaningful to write an empty URL to the clipboard? if (!drop_data.url.is_empty()) { WebDragData::Item item; item.storageType = WebDragData::Item::StorageTypeString; @@ -606,14 +617,19 @@ GetV8CacheStrategiesForCacheStorage() { *base::CommandLine::ForCurrentProcess(); std::string v8_cache_strategies = command_line.GetSwitchValueASCII( switches::kV8CacheStrategiesForCacheStorage); - if (v8_cache_strategies.empty()) + if (v8_cache_strategies.empty()) { v8_cache_strategies = base::FieldTrialList::FindFullName("V8CacheStrategiesForCacheStorage"); - if (v8_cache_strategies == "none") { + } + + if (base::StartsWith(v8_cache_strategies, "none", + base::CompareCase::SENSITIVE)) { return WebSettings::V8CacheStrategiesForCacheStorage::None; - } else if (v8_cache_strategies == "normal") { + } else if (base::StartsWith(v8_cache_strategies, "normal", + base::CompareCase::SENSITIVE)) { return WebSettings::V8CacheStrategiesForCacheStorage::Normal; - } else if (v8_cache_strategies == "aggressive") { + } else if (base::StartsWith(v8_cache_strategies, "aggressive", + base::CompareCase::SENSITIVE)) { return WebSettings::V8CacheStrategiesForCacheStorage::Aggressive; } else { return WebSettings::V8CacheStrategiesForCacheStorage::Default; @@ -654,7 +670,6 @@ RenderViewImpl::RenderViewImpl(CompositorDependencies* compositor_deps, main_render_frame_(nullptr), frame_widget_(nullptr), speech_recognition_dispatcher_(NULL), - mouse_lock_dispatcher_(NULL), #if defined(OS_ANDROID) expected_content_intent_id_(0), #endif @@ -679,9 +694,10 @@ void RenderViewImpl::Initialize(const ViewMsg_New_Params& params, // Ensure we start with a valid next_page_id_ from the browser. DCHECK_GE(next_page_id_, 0); - webview_ = WebView::create(this); - webwidget_ = webview_->widget(); - webwidget_mouse_lock_target_.reset(new WebWidgetLockTarget(webwidget_)); + webview_ = + WebView::create(this, is_hidden() ? blink::WebPageVisibilityStateHidden + : blink::WebPageVisibilityStateVisible); + RenderWidget::DoInit(MSG_ROUTING_NONE, webview_->widget(), nullptr); g_view_map.Get().insert(std::make_pair(webview(), this)); g_routing_id_view_map.Get().insert(std::make_pair(GetRoutingID(), this)); @@ -709,6 +725,7 @@ void RenderViewImpl::Initialize(const ViewMsg_New_Params& params, command_line.HasSwitch(switches::kRootLayerScrolls)); webview()->setShowFPSCounter( command_line.HasSwitch(cc::switches::kShowFPSCounter)); + webview()->setDeviceColorProfile(params.image_decode_color_profile); ApplyWebPreferencesInternal(webkit_preferences_, webview(), compositor_deps_); @@ -767,17 +784,6 @@ void RenderViewImpl::Initialize(const ViewMsg_New_Params& params, content_detectors_.push_back(base::WrapUnique(new EmailDetector())); #endif - RenderThread::Get()->AddRoute(GetRoutingID(), this); - // Take a reference on behalf of the RenderThread. This will be balanced - // when we receive ViewMsg_Close in the RenderWidget (which RenderView - // inherits from). - AddRef(); - if (RenderThreadImpl::current()) { - RenderThreadImpl::current()->WidgetCreated(); - if (is_hidden_) - RenderThreadImpl::current()->WidgetHidden(); - } - // If this is a popup, we must wait for the CreatingNew_ACK message before // completing initialization. Otherwise, we can finish it now. if (opener_id_ == MSG_ROUTING_NONE) @@ -809,10 +815,6 @@ void RenderViewImpl::Initialize(const ViewMsg_New_Params& params, new TextInputClientObserver(this); #endif // defined(OS_MACOSX) - // The next group of objects all implement RenderViewObserver, so are deleted - // along with the RenderView automatically. - mouse_lock_dispatcher_ = new RenderViewMouseLockDispatcher(this); - // We don't use HistoryController in OOPIF-enabled modes. if (!SiteIsolationPolicy::UseSubframeNavigationEntries()) history_controller_.reset(new HistoryController(this)); @@ -845,18 +847,9 @@ RenderViewImpl::~RenderViewImpl() { ++it) delete it->second; - // If file chooser is still waiting for answer, dispatch empty answer. - while (!file_chooser_completions_.empty()) { - if (file_chooser_completions_.front()->completion) { - file_chooser_completions_.front()->completion->didChooseFile( - WebVector<WebString>()); - } - file_chooser_completions_.pop_front(); - } - #if defined(OS_ANDROID) - // The date/time picker client is both a scoped_ptr member of this class and - // a RenderViewObserver. Reset it to prevent double deletion. + // The date/time picker client is both a std::unique_ptr member of this class + // and a RenderViewObserver. Reset it to prevent double deletion. date_time_picker_client_.reset(); #endif @@ -1123,8 +1116,12 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs, prefs.report_screen_size_in_physical_pixels_quirk); settings->setShouldReuseGlobalForUnownedMainFrame( prefs.resue_global_for_unowned_main_frame); + settings->setProgressBarCompletion( + static_cast<WebSettings::ProgressBarCompletion>( + prefs.progress_bar_completion)); settings->setPreferHiddenVolumeControls(true); - settings->setShrinksViewportContentToFit(true); + WebRuntimeFeatures::enableAutoplayMutedVideos( + prefs.autoplay_muted_videos_enabled); #endif settings->setAutoplayExperimentMode( @@ -1132,6 +1129,8 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs, settings->setViewportEnabled(prefs.viewport_enabled); settings->setViewportMetaEnabled(prefs.viewport_meta_enabled); + settings->setShrinksViewportContentToFit( + prefs.shrinks_viewport_contents_to_fit); settings->setViewportStyle( static_cast<blink::WebViewportStyle>(prefs.viewport_style)); @@ -1144,13 +1143,13 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs, settings->setUseSolidColorScrollbars(prefs.use_solid_color_scrollbars); settings->setShowContextMenuOnMouseUp(prefs.context_menu_on_mouse_up); + settings->setAlwaysShowContextMenuOnTouch( + prefs.always_show_context_menu_on_touch); #if defined(OS_MACOSX) settings->setDoubleTapToZoomEnabled(true); web_view->setMaximumLegibleScale(prefs.default_maximum_page_scale_factor); #endif - - settings->setWheelGesturesEnabled(UseGestureBasedWheelScrolling()); } /*static*/ @@ -1288,8 +1287,6 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) { OnScrollFocusedEditableNodeIntoRect) IPC_MESSAGE_HANDLER(InputMsg_SetEditCommandsForNextKeyEvent, OnSetEditCommandsForNextKeyEvent) - IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt) - IPC_MESSAGE_HANDLER(ViewMsg_SaveImageAt, OnSaveImageAt) IPC_MESSAGE_HANDLER(ViewMsg_SetPageScale, OnSetPageScale) IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom) IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForLoadingURL, @@ -1310,7 +1307,6 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences) IPC_MESSAGE_HANDLER(ViewMsg_EnumerateDirectoryResponse, OnEnumerateDirectoryResponse) - IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse) IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage) IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged) IPC_MESSAGE_HANDLER(ViewMsg_MoveOrResizeStarted, OnMoveOrResizeStarted) @@ -1339,6 +1335,9 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(PageMsg_UpdateWindowScreenRect, OnUpdateWindowScreenRect) IPC_MESSAGE_HANDLER(PageMsg_SetZoomLevel, OnSetZoomLevel) + IPC_MESSAGE_HANDLER(PageMsg_WasHidden, OnPageWasHidden) + IPC_MESSAGE_HANDLER(PageMsg_WasShown, OnPageWasShown) + #if defined(OS_ANDROID) IPC_MESSAGE_HANDLER(ViewMsg_UpdateTopControlsState, OnUpdateTopControlsState) @@ -1367,14 +1366,6 @@ void RenderViewImpl::OnSelectWordAroundCaret() { input_handler_->set_handling_input_event(false); } -void RenderViewImpl::OnCopyImageAt(int x, int y) { - webview()->copyImageAt(WebPoint(x, y)); -} - -void RenderViewImpl::OnSaveImageAt(int x, int y) { - webview()->saveImageAt(WebPoint(x, y)); -} - void RenderViewImpl::OnUpdateTargetURLAck() { // Check if there is a targeturl waiting to be sent. if (target_url_status_ == TARGET_PENDING) @@ -1409,15 +1400,12 @@ void RenderViewImpl::OnScrollFocusedEditableNodeIntoRect( return; } - blink::WebElement element = GetFocusedElement(); - bool will_animate = false; - if (!element.isNull() && element.isEditable()) { - rect_for_scrolled_focused_editable_node_ = rect; - has_scrolled_focused_editable_node_into_rect_ = true; - will_animate = webview()->scrollFocusedNodeIntoRect(rect); - } + if (!webview()->scrollFocusedEditableElementIntoRect(rect)) + return; - if (!will_animate) + rect_for_scrolled_focused_editable_node_ = rect; + has_scrolled_focused_editable_node_into_rect_ = true; + if (!compositor()->hasPendingPageScaleAnimation()) GetWidget()->FocusChangeComplete(); } @@ -1624,14 +1612,6 @@ void RenderViewImpl::printPage(WebLocalFrame* frame) { PrintPage(frame, input_handler().handling_input_event())); } -void RenderViewImpl::saveImageFromDataURL(const blink::WebString& data_url) { - // Note: We should basically send GURL but we use size-limited string instead - // in order to send a larger data url to save a image for <canvas> or <img>. - if (data_url.length() < kMaxLengthOfDataURLString) - Send(new ViewHostMsg_SaveImageFromDataURL( - GetRoutingID(), GetMainRenderFrame()->GetRoutingID(), data_url.utf8())); -} - bool RenderViewImpl::enumerateChosenDirectory( const WebString& path, WebFileChooserCompletion* chooser_completion) { @@ -1704,36 +1684,6 @@ bool RenderViewImpl::handleCurrentKeyboardEvent() { return did_execute_command; } -bool RenderViewImpl::runFileChooser( - const blink::WebFileChooserParams& params, - WebFileChooserCompletion* chooser_completion) { - // Do not open the file dialog in a hidden RenderView. - if (is_hidden()) - return false; - FileChooserParams ipc_params; - if (params.directory) - ipc_params.mode = FileChooserParams::UploadFolder; - else if (params.multiSelect) - ipc_params.mode = FileChooserParams::OpenMultiple; - else if (params.saveAs) - ipc_params.mode = FileChooserParams::Save; - else - ipc_params.mode = FileChooserParams::Open; - ipc_params.title = params.title; - ipc_params.default_file_name = - blink::WebStringToFilePath(params.initialValue).BaseName(); - ipc_params.accept_types.reserve(params.acceptTypes.size()); - for (size_t i = 0; i < params.acceptTypes.size(); ++i) - ipc_params.accept_types.push_back(params.acceptTypes[i]); - ipc_params.need_local_path = params.needLocalPath; -#if defined(OS_ANDROID) - ipc_params.capture = params.useMediaCapture; -#endif - ipc_params.requestor = params.requestor; - - return ScheduleFileChooser(ipc_params, chooser_completion); -} - void RenderViewImpl::SetValidationMessageDirection( base::string16* wrapped_main_text, blink::WebTextDirection main_text_hint, @@ -1994,19 +1944,6 @@ void RenderViewImpl::show(WebNavigationPolicy policy) { SetPendingWindowRect(initial_rect_); } -bool RenderViewImpl::requestPointerLock() { - return mouse_lock_dispatcher_->LockMouse(webwidget_mouse_lock_target_.get()); -} - -void RenderViewImpl::requestPointerUnlock() { - mouse_lock_dispatcher_->UnlockMouse(webwidget_mouse_lock_target_.get()); -} - -bool RenderViewImpl::isPointerLocked() { - return mouse_lock_dispatcher_->IsMouseLockedTo( - webwidget_mouse_lock_target_.get()); -} - void RenderViewImpl::onMouseDown(const WebNode& mouse_down_node) { FOR_EACH_OBSERVER( RenderViewObserver, observers_, OnMouseDown(mouse_down_node)); @@ -2062,8 +1999,7 @@ void RenderViewImpl::initializeLayerTreeView() { if (input_handler_manager) { input_handler_manager->AddInputHandler( GetRoutingID(), rwc->GetInputHandler(), AsWeakPtr(), - webkit_preferences_.enable_scroll_animator, - UseGestureBasedWheelScrolling()); + webkit_preferences_.enable_scroll_animator); has_added_input_handler_ = true; } } @@ -2320,10 +2256,6 @@ bool RenderViewImpl::GetContentStateImmediately() const { return send_content_state_immediately_; } -blink::WebPageVisibilityState RenderViewImpl::GetVisibilityState() const { - return visibilityState(); -} - void RenderViewImpl::DidStartLoading() { main_render_frame_->didStartLoading(true); } @@ -2332,19 +2264,6 @@ void RenderViewImpl::DidStopLoading() { main_render_frame_->didStopLoading(); } -blink::WebElement RenderViewImpl::GetFocusedElement() const { - if (!webview()) - return WebElement(); - WebFrame* focused_frame = webview()->focusedFrame(); - if (focused_frame) { - WebDocument doc = focused_frame->document(); - if (!doc.isNull()) - return doc.focusedElement(); - } - - return WebElement(); -} - void RenderViewImpl::OnSetPageScale(float page_scale_factor) { if (!webview()) return; @@ -2444,17 +2363,15 @@ void RenderViewImpl::OnAllowBindings(int enabled_bindings_flags) { main_render_frame_->MaybeEnableMojoBindings(); } -void RenderViewImpl::OnDragTargetDragEnter(const DropData& drop_data, - const gfx::Point& client_point, - const gfx::Point& screen_point, - WebDragOperationsMask ops, - int key_modifiers) { +void RenderViewImpl::OnDragTargetDragEnter( + const std::vector<DropData::Metadata>& drop_meta_data, + const gfx::Point& client_point, + const gfx::Point& screen_point, + WebDragOperationsMask ops, + int key_modifiers) { WebDragOperation operation = webview()->dragTargetDragEnter( - DropDataToWebDragData(drop_data), - ConvertWindowPointToViewport(client_point), - screen_point, - ops, - key_modifiers); + DropMetaDataToWebDragData(drop_meta_data), client_point, screen_point, + ops, key_modifiers); Send(new DragHostMsg_UpdateDragCursor(GetRoutingID(), operation)); } @@ -2476,11 +2393,12 @@ void RenderViewImpl::OnDragTargetDragLeave() { webview()->dragTargetDragLeave(); } -void RenderViewImpl::OnDragTargetDrop(const gfx::Point& client_point, +void RenderViewImpl::OnDragTargetDrop(const DropData& drop_data, + const gfx::Point& client_point, const gfx::Point& screen_point, int key_modifiers) { - webview()->dragTargetDrop( - ConvertWindowPointToViewport(client_point), screen_point, key_modifiers); + webview()->dragTargetDrop(DropDataToWebDragData(drop_data), client_point, + screen_point, key_modifiers); } void RenderViewImpl::OnDragSourceEnded(const gfx::Point& client_point, @@ -2513,42 +2431,6 @@ void RenderViewImpl::OnEnumerateDirectoryResponse( enumeration_completions_.erase(id); } -void RenderViewImpl::OnFileChooserResponse( - const std::vector<content::FileChooserFileInfo>& files) { - // This could happen if we navigated to a different page before the user - // closed the chooser. - if (file_chooser_completions_.empty()) - return; - - // Convert Chrome's SelectedFileInfo list to WebKit's. - WebVector<WebFileChooserCompletion::SelectedFileInfo> selected_files( - files.size()); - for (size_t i = 0; i < files.size(); ++i) { - WebFileChooserCompletion::SelectedFileInfo selected_file; - selected_file.path = files[i].file_path.AsUTF16Unsafe(); - selected_file.displayName = - base::FilePath(files[i].display_name).AsUTF16Unsafe(); - if (files[i].file_system_url.is_valid()) { - selected_file.fileSystemURL = files[i].file_system_url; - selected_file.length = files[i].length; - selected_file.modificationTime = files[i].modification_time.ToDoubleT(); - selected_file.isDirectory = files[i].is_directory; - } - selected_files[i] = selected_file; - } - - if (file_chooser_completions_.front()->completion) - file_chooser_completions_.front()->completion->didChooseFile( - selected_files); - file_chooser_completions_.pop_front(); - - // If there are more pending file chooser requests, schedule one now. - if (!file_chooser_completions_.empty()) { - Send(new ViewHostMsg_RunFileChooser( - GetRoutingID(), file_chooser_completions_.front()->params)); - } -} - void RenderViewImpl::OnEnableAutoResize(const gfx::Size& min_size, const gfx::Size& max_size) { DCHECK(disable_scrollbars_size_limit_.IsEmpty()); @@ -2698,7 +2580,8 @@ void RenderViewImpl::OnResize(const ResizeParams& params) { TRACE_EVENT0("renderer", "RenderViewImpl::OnResize"); if (webview()) { webview()->hidePopups(); - if (send_preferred_size_changes_) { + if (send_preferred_size_changes_ && + webview()->mainFrame()->isWebLocalFrame()) { webview()->mainFrame()->setCanHaveScrollbars( ShouldDisplayScrollbars(params.new_size.width(), params.new_size.height())); @@ -2800,9 +2683,7 @@ void RenderViewImpl::Close() { RenderThread::Get()->Send(new ViewHostMsg_Close_ACK(GetRoutingID())); } -void RenderViewImpl::OnWasHidden() { - RenderWidget::OnWasHidden(); - +void RenderViewImpl::OnPageWasHidden() { #if defined(OS_ANDROID) && defined(ENABLE_WEBRTC) RenderThreadImpl::current()->video_capture_impl_manager()-> SuspendDevices(true); @@ -2810,21 +2691,30 @@ void RenderViewImpl::OnWasHidden() { speech_recognition_dispatcher_->AbortAllRecognitions(); #endif - if (webview()) - webview()->setVisibilityState(visibilityState(), false); + if (webview()) { + // TODO(lfg): It's not correct to defer the page visibility to the main + // frame. Currently, this is done because the main frame may override the + // visibility of the page when prerendering. In order to fix this, + // prerendering must be made aware of OOPIFs. https://crbug.com/440544 + blink::WebPageVisibilityState visibilityState = + GetMainRenderFrame() ? GetMainRenderFrame()->visibilityState() + : blink::WebPageVisibilityStateHidden; + webview()->setVisibilityState(visibilityState, false); + } } -void RenderViewImpl::OnWasShown(bool needs_repainting, - const ui::LatencyInfo& latency_info) { - RenderWidget::OnWasShown(needs_repainting, latency_info); - +void RenderViewImpl::OnPageWasShown() { #if defined(OS_ANDROID) && defined(ENABLE_WEBRTC) RenderThreadImpl::current()->video_capture_impl_manager()-> SuspendDevices(false); #endif - if (webview()) - webview()->setVisibilityState(visibilityState(), false); + if (webview()) { + blink::WebPageVisibilityState visibilityState = + GetMainRenderFrame() ? GetMainRenderFrame()->visibilityState() + : blink::WebPageVisibilityStateVisible; + webview()->setVisibilityState(visibilityState, false); + } } GURL RenderViewImpl::GetURLForGraphicsContext3D() { @@ -3026,31 +2916,6 @@ void RenderViewImpl::SetScreenMetricsEmulationParameters( } } -bool RenderViewImpl::ScheduleFileChooser( - const FileChooserParams& params, - WebFileChooserCompletion* completion) { - static const size_t kMaximumPendingFileChooseRequests = 4; - if (file_chooser_completions_.size() > kMaximumPendingFileChooseRequests) { - // This sanity check prevents too many file choose requests from getting - // queued which could DoS the user. Getting these is most likely a - // programming error (there are many ways to DoS the user so it's not - // considered a "real" security check), either in JS requesting many file - // choosers to pop up, or in a plugin. - // - // TODO(brettw) we might possibly want to require a user gesture to open - // a file picker, which will address this issue in a better way. - return false; - } - - file_chooser_completions_.push_back( - base::WrapUnique(new PendingFileChooser(params, completion))); - if (file_chooser_completions_.size() == 1) { - // Actually show the browse dialog when this is the first request. - Send(new ViewHostMsg_RunFileChooser(GetRoutingID(), params)); - } - return true; -} - blink::WebSpeechRecognizer* RenderViewImpl::speechRecognizer() { if (!speech_recognition_dispatcher_) speech_recognition_dispatcher_ = new SpeechRecognitionDispatcher(this); @@ -3100,19 +2965,6 @@ double RenderViewImpl::zoomFactorToZoomLevel(double factor) const { return ZoomFactorToZoomLevel(factor); } -blink::WebPageVisibilityState RenderViewImpl::visibilityState() const { - blink::WebPageVisibilityState current_state = is_hidden() ? - blink::WebPageVisibilityStateHidden : - blink::WebPageVisibilityStateVisible; - blink::WebPageVisibilityState override_state = current_state; - // TODO(jam): move this method to WebFrameClient. - if (GetContentClient()->renderer()-> - ShouldOverridePageVisibilityState(main_render_frame_, - &override_state)) - return override_state; - return current_state; -} - void RenderViewImpl::draggableRegionsChanged() { FOR_EACH_OBSERVER( RenderViewObserver, @@ -3153,7 +3005,7 @@ WebContentDetectionResult RenderViewImpl::detectContentAround( void RenderViewImpl::scheduleContentIntent(const WebURL& intent, bool is_main_frame) { // Introduce a short delay so that the user can notice the content. - base::MessageLoop::current()->PostDelayedTask( + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::Bind(&RenderViewImpl::LaunchAndroidContentIntent, AsWeakPtr(), intent, expected_content_intent_id_, is_main_frame), diff --git a/chromium/content/renderer/render_view_impl.h b/chromium/content/renderer/render_view_impl.h index 8d292c2c9d1..1ebdb174b2e 100644 --- a/chromium/content/renderer/render_view_impl.h +++ b/chromium/content/renderer/render_view_impl.h @@ -33,19 +33,18 @@ #include "content/common/navigation_gesture.h" #include "content/common/page_message_enums.h" #include "content/common/view_message_enums.h" +#include "content/public/common/drop_data.h" #include "content/public/common/page_zoom.h" #include "content/public/common/referrer.h" #include "content/public/common/renderer_preferences.h" #include "content/public/common/top_controls_state.h" #include "content/public/common/web_preferences.h" #include "content/public/renderer/render_view.h" -#include "content/renderer/mouse_lock_dispatcher.h" #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_widget.h" #include "content/renderer/render_widget_owner_delegate.h" #include "content/renderer/stats_collection_observer.h" #include "ipc/ipc_platform_file.h" -#include "third_party/WebKit/public/platform/WebPageVisibilityState.h" #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" #include "third_party/WebKit/public/web/WebAXObject.h" #include "third_party/WebKit/public/web/WebConsoleMessage.h" @@ -121,7 +120,6 @@ namespace content { class HistoryController; class HistoryEntry; -class MouseLockDispatcher; class PageState; class RenderViewImplTest; class RenderViewObserver; @@ -130,7 +128,6 @@ class RendererDateTimePicker; class RendererWebColorChooserImpl; class SpeechRecognitionDispatcher; class WebPluginDelegateProxy; -struct DropData; struct FaviconURL; struct FileChooserParams; struct FileChooserFileInfo; @@ -194,10 +191,6 @@ class CONTENT_EXPORT RenderViewImpl send_content_state_immediately_ = value; } - MouseLockDispatcher* mouse_lock_dispatcher() { - return mouse_lock_dispatcher_; - } - HistoryController* history_controller() { return history_controller_.get(); } @@ -293,9 +286,6 @@ class CONTENT_EXPORT RenderViewImpl // Most methods are handled by RenderWidget. void didFocus() override; void show(blink::WebNavigationPolicy policy) override; - bool requestPointerLock() override; - void requestPointerUnlock() override; - bool isPointerLocked() override; void didHandleGestureEvent(const blink::WebGestureEvent& event, bool event_cancelled) override; void onMouseDown(const blink::WebNode& mouse_down_node) override; @@ -347,12 +337,8 @@ class CONTENT_EXPORT RenderViewImpl bool enumerateChosenDirectory( const blink::WebString& path, blink::WebFileChooserCompletion* chooser_completion) override; - void saveImageFromDataURL(const blink::WebString& data_url) override; void didCancelCompositionOnSelectionChange() override; bool handleCurrentKeyboardEvent() override; - bool runFileChooser( - const blink::WebFileChooserParams& params, - blink::WebFileChooserCompletion* chooser_completion) override; void SetValidationMessageDirection(base::string16* main_text, blink::WebTextDirection main_text_hint, base::string16* sub_text, @@ -395,7 +381,6 @@ class CONTENT_EXPORT RenderViewImpl void pageScaleFactorChanged() override; virtual double zoomLevelToZoomFactor(double zoom_level) const; virtual double zoomFactorToZoomLevel(double factor) const; - blink::WebPageVisibilityState visibilityState() const override; void draggableRegionsChanged() override; void pageImportanceSignalsChanged() override; @@ -428,7 +413,6 @@ class CONTENT_EXPORT RenderViewImpl bool ShouldDisplayScrollbars(int width, int height) const override; int GetEnabledBindings() const override; bool GetContentStateImmediately() const override; - blink::WebPageVisibilityState GetVisibilityState() const override; void DidStartLoading() override; void DidStopLoading() override; void Repaint(const gfx::Size& size) override; @@ -461,9 +445,6 @@ class CONTENT_EXPORT RenderViewImpl void Close() override; void OnResize(const ResizeParams& params) override; void OnSetFocus(bool enable) override; - void OnWasHidden() override; - void OnWasShown(bool needs_repainting, - const ui::LatencyInfo& latency_info) override; GURL GetURLForGraphicsContext3D() override; void OnImeSetComposition( const base::string16& text, @@ -620,8 +601,6 @@ class CONTENT_EXPORT RenderViewImpl void OnShowContextMenu(ui::MenuSourceType source_type, const gfx::Point& location); - void OnCopyImageAt(int x, int y); - void OnSaveImageAt(int x, int y); void OnDeterminePageLanguage(); void OnDisableScrollbarsForSmallWindows( const gfx::Size& disable_scrollbars_size_limit); @@ -629,14 +608,17 @@ class CONTENT_EXPORT RenderViewImpl const gfx::Point& screen_point, blink::WebDragOperation drag_operation); void OnDragSourceSystemDragEnded(); - void OnDragTargetDrop(const gfx::Point& client_pt, + void OnDragTargetDrop(const DropData& drop_data, + const gfx::Point& client_pt, const gfx::Point& screen_pt, int key_modifiers); - void OnDragTargetDragEnter(const DropData& drop_data, - const gfx::Point& client_pt, - const gfx::Point& screen_pt, - blink::WebDragOperationsMask operations_allowed, - int key_modifiers); + // Real data that is dragged is not included at DragEnter time. + void OnDragTargetDragEnter( + const std::vector<DropData::Metadata>& drop_meta_data, + const gfx::Point& client_pt, + const gfx::Point& screen_pt, + blink::WebDragOperationsMask operations_allowed, + int key_modifiers); void OnDragTargetDragLeave(); void OnDragTargetDragOver(const gfx::Point& client_pt, const gfx::Point& screen_pt, @@ -647,8 +629,6 @@ class CONTENT_EXPORT RenderViewImpl void OnDisableAutoResize(const gfx::Size& new_size); void OnEnumerateDirectoryResponse(int id, const std::vector<base::FilePath>& paths); - void OnFileChooserResponse( - const std::vector<content::FileChooserFileInfo>& files); void OnMediaPlayerActionAt(const gfx::Point& location, const blink::WebMediaPlayerAction& action); void OnPluginActionAt(const gfx::Point& location, @@ -686,6 +666,8 @@ class CONTENT_EXPORT RenderViewImpl // Page message handlers ----------------------------------------------------- void OnUpdateWindowScreenRect(gfx::Rect window_screen_rect); void OnSetZoomLevel(PageMsg_SetZoomLevel_Command command, double zoom_level); + void OnPageWasHidden(); + void OnPageWasShown(); // Adding a new message handler? Please add it in alphabetical order above // and put it in the same position in the .cc file. @@ -694,9 +676,6 @@ class CONTENT_EXPORT RenderViewImpl // Check whether the preferred size has changed. void CheckPreferredSize(); - // Gets the currently focused element, if any. - blink::WebElement GetFocusedElement() const; - #if defined(OS_ANDROID) // Launch an Android content intent with the given URL. void LaunchAndroidContentIntent(const GURL& intent_url, @@ -904,9 +883,6 @@ class CONTENT_EXPORT RenderViewImpl // initialized. SpeechRecognitionDispatcher* speech_recognition_dispatcher_; - // Mouse Lock dispatcher attached to this view. - MouseLockDispatcher* mouse_lock_dispatcher_; - std::unique_ptr<HistoryController> history_controller_; #if defined(OS_ANDROID) @@ -926,13 +902,6 @@ class CONTENT_EXPORT RenderViewImpl // Misc ---------------------------------------------------------------------- - // The current and pending file chooser completion objects. If the queue is - // nonempty, the first item represents the currently running file chooser - // callback, and the remaining elements are the other file chooser completion - // still waiting to be run (in order). - struct PendingFileChooser; - std::deque<std::unique_ptr<PendingFileChooser>> file_chooser_completions_; - // The current directory enumeration callback std::map<int, blink::WebFileChooserCompletion*> enumeration_completions_; int enumeration_completion_id_; @@ -950,9 +919,6 @@ class CONTENT_EXPORT RenderViewImpl // is fine. base::ObserverList<RenderViewObserver> observers_; - // Wraps the |webwidget_| as a MouseLockDispatcher::LockTarget interface. - std::unique_ptr<MouseLockDispatcher::LockTarget> webwidget_mouse_lock_target_; - // This field stores drag/drop related info for the event that is currently // being handled. If the current event results in starting a drag/drop // session, this info is sent to the browser along with other drag/drop info. diff --git a/chromium/content/renderer/render_view_mouse_lock_dispatcher.h b/chromium/content/renderer/render_view_mouse_lock_dispatcher.h deleted file mode 100644 index 984a40e0984..00000000000 --- a/chromium/content/renderer/render_view_mouse_lock_dispatcher.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_RENDER_VIEW_MOUSE_LOCK_DISPATCHER_H_ -#define CONTENT_RENDERER_RENDER_VIEW_MOUSE_LOCK_DISPATCHER_H_ - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "content/public/renderer/render_view_observer.h" -#include "content/renderer/mouse_lock_dispatcher.h" - -namespace content { -class RenderViewImpl; - -// RenderViewMouseLockDispatcher is owned by RenderViewImpl. -class RenderViewMouseLockDispatcher : public MouseLockDispatcher, - public RenderViewObserver { - public: - explicit RenderViewMouseLockDispatcher(RenderViewImpl* render_view_impl); - ~RenderViewMouseLockDispatcher() override; - - private: - // MouseLockDispatcher implementation. - void SendLockMouseRequest(bool unlocked_by_target) override; - void SendUnlockMouseRequest() override; - - // RenderView::Observer implementation. - bool OnMessageReceived(const IPC::Message& message) override; - - void OnLockMouseACK(bool succeeded); - - RenderViewImpl* render_view_impl_; - - DISALLOW_COPY_AND_ASSIGN(RenderViewMouseLockDispatcher); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_RENDER_VIEW_MOUSE_LOCK_DISPATCHER_H_ diff --git a/chromium/content/renderer/render_widget.cc b/chromium/content/renderer/render_widget.cc index 66a8ecc0355..129ed07f6eb 100644 --- a/chromium/content/renderer/render_widget.cc +++ b/chromium/content/renderer/render_widget.cc @@ -23,17 +23,11 @@ #include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event_synthetic_delay.h" #include "build/build_config.h" -#include "cc/base/switches.h" -#include "cc/debug/benchmark_instrumentation.h" #include "cc/output/output_surface.h" -#include "cc/output/vulkan_in_process_context_provider.h" #include "cc/scheduler/begin_frame_source.h" -#include "cc/trees/layer_tree_host.h" #include "components/scheduler/renderer/render_widget_scheduling_state.h" #include "components/scheduler/renderer/renderer_scheduler.h" #include "content/common/content_switches_internal.h" -#include "content/common/gpu/client/context_provider_command_buffer.h" -#include "content/common/gpu_process_launch_causes.h" #include "content/common/input/synthetic_gesture_packet.h" #include "content/common/input/web_input_event_traits.h" #include "content/common/input_messages.h" @@ -46,10 +40,7 @@ #include "content/renderer/cursor_utils.h" #include "content/renderer/devtools/render_widget_screen_metrics_emulator.h" #include "content/renderer/external_popup_menu.h" -#include "content/renderer/gpu/compositor_output_surface.h" -#include "content/renderer/gpu/delegated_compositor_output_surface.h" #include "content/renderer/gpu/frame_swap_message_queue.h" -#include "content/renderer/gpu/mailbox_output_surface.h" #include "content/renderer/gpu/queue_message_swap_promise.h" #include "content/renderer/gpu/render_widget_compositor.h" #include "content/renderer/ime_event_guard.h" @@ -63,7 +54,6 @@ #include "content/renderer/render_widget_owner_delegate.h" #include "content/renderer/renderer_blink_platform_impl.h" #include "content/renderer/resizing_mode_selector.h" -#include "gpu/command_buffer/client/shared_memory_limits.h" #include "ipc/ipc_sync_message.h" #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/public/platform/WebCursorInfo.h" @@ -93,8 +83,6 @@ #if defined(OS_ANDROID) #include <android/keycodes.h> -#include "content/renderer/android/synchronous_compositor_filter.h" -#include "content/renderer/android/synchronous_compositor_output_surface.h" #endif #if defined(OS_POSIX) @@ -140,6 +128,29 @@ namespace { typedef std::map<std::string, ui::TextInputMode> TextInputModeMap; +class WebWidgetLockTarget : public content::MouseLockDispatcher::LockTarget { + public: + explicit WebWidgetLockTarget(blink::WebWidget* webwidget) + : webwidget_(webwidget) {} + + void OnLockMouseACK(bool succeeded) override { + if (succeeded) + webwidget_->didAcquirePointerLock(); + else + webwidget_->didNotAcquirePointerLock(); + } + + void OnMouseLockLost() override { webwidget_->didLosePointerLock(); } + + bool HandleMouseLockedInputEvent(const blink::WebMouseEvent& event) override { + // The WebWidget handles mouse lock in Blink's handleInputEvent(). + return false; + } + + private: + blink::WebWidget* webwidget_; +}; + class TextInputModeMapSingleton { public: static TextInputModeMapSingleton* GetInstance() { @@ -189,7 +200,7 @@ content::RenderWidgetInputHandlerDelegate* GetRenderWidgetInputHandlerDelegate( content::RenderWidget* widget) { #if defined(MOJO_SHELL_CLIENT) const base::CommandLine& cmdline = *base::CommandLine::ForCurrentProcess(); - if (content::MojoShellConnection::Get() && + if (content::MojoShellConnection::GetForProcess() && cmdline.HasSwitch(switches::kUseMusInRenderer)) { return content::RenderWidgetMusConnection::GetOrCreate( widget->routing_id()); @@ -239,7 +250,6 @@ RenderWidget::RenderWidget(CompositorDependencies* compositor_deps, pending_window_rect_count_(0), screen_info_(screen_info), device_scale_factor_(screen_info_.deviceScaleFactor), - next_output_surface_id_(0), #if defined(OS_ANDROID) text_field_is_dirty_(false), #endif @@ -374,6 +384,8 @@ bool RenderWidget::DoInit(int32_t opener_id, opener_id_ = opener_id; webwidget_ = web_widget; + webwidget_mouse_lock_target_.reset(new WebWidgetLockTarget(webwidget_)); + mouse_lock_dispatcher_.reset(new RenderWidgetMouseLockDispatcher(this)); bool result = true; if (create_widget_message) @@ -435,7 +447,7 @@ gfx::Rect RenderWidget::AdjustValidationMessageAnchor(const gfx::Rect& anchor) { return anchor; } -#if defined(OS_MACOSX) || defined(OS_ANDROID) +#if defined(USE_EXTERNAL_POPUP_MENU) void RenderWidget::SetExternalPopupOriginAdjustmentsForEmulation( ExternalPopupMenu* popup, RenderWidgetScreenMetricsEmulator* emulator) { @@ -450,6 +462,10 @@ void RenderWidget::OnShowHostContextMenu(ContextMenuParams* params) { } bool RenderWidget::OnMessageReceived(const IPC::Message& message) { + if (mouse_lock_dispatcher_ && + mouse_lock_dispatcher_->OnMessageReceived(message)) + return true; + bool handled = true; IPC_BEGIN_MESSAGE_MAP(RenderWidget, message) IPC_MESSAGE_HANDLER(InputMsg_HandleInputEvent, OnHandleInputEvent) @@ -467,7 +483,6 @@ bool RenderWidget::OnMessageReceived(const IPC::Message& message) { OnEnableDeviceEmulation) IPC_MESSAGE_HANDLER(ViewMsg_DisableDeviceEmulation, OnDisableDeviceEmulation) - IPC_MESSAGE_HANDLER(ViewMsg_ColorProfile, OnColorProfile) IPC_MESSAGE_HANDLER(ViewMsg_ChangeResizeRect, OnChangeResizeRect) IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden) IPC_MESSAGE_HANDLER(ViewMsg_WasShown, OnWasShown) @@ -596,10 +611,6 @@ void RenderWidget::OnDisableDeviceEmulation() { screen_metrics_emulator_.reset(); } -void RenderWidget::OnColorProfile(const std::vector<char>& color_profile) { - SetDeviceColorProfile(color_profile); -} - void RenderWidget::OnChangeResizeRect(const gfx::Rect& resizer_rect) { if (resizer_rect_ == resizer_rect) return; @@ -704,119 +715,9 @@ std::unique_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface( // For widgets that are never visible, we don't start the compositor, so we // never get a request for a cc::OutputSurface. DCHECK(!compositor_never_visible_); - - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - bool use_software = fallback; - if (command_line.HasSwitch(switches::kDisableGpuCompositing)) - use_software = true; - -#if defined(MOJO_SHELL_CLIENT) - if (MojoShellConnection::Get() && !use_software && - command_line.HasSwitch(switches::kUseMusInRenderer)) { - RenderWidgetMusConnection* connection = - RenderWidgetMusConnection::GetOrCreate(routing_id()); - return connection->CreateOutputSurface(); - } -#endif - - uint32_t output_surface_id = next_output_surface_id_++; - - if (command_line.HasSwitch(switches::kEnableVulkan)) { - scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider = - cc::VulkanInProcessContextProvider::Create(); - if (vulkan_context_provider) { - return base::WrapUnique(new DelegatedCompositorOutputSurface( - routing_id(), output_surface_id, nullptr, nullptr, - vulkan_context_provider, frame_swap_message_queue_)); - } - } - - // Create a gpu process channel and verify we want to use GPU compositing - // before creating any context providers. - scoped_refptr<gpu::GpuChannelHost> gpu_channel_host; - if (!use_software) { - gpu_channel_host = RenderThreadImpl::current()->EstablishGpuChannelSync( - CAUSE_FOR_GPU_LAUNCH_RENDERER_VERIFY_GPU_COMPOSITING); - if (!gpu_channel_host) { - // Cause the compositor to wait and try again. - return nullptr; - } - // We may get a valid channel, but with a software renderer. In that case, - // disable GPU compositing. - if (gpu_channel_host->gpu_info().software_rendering) - use_software = true; - } - - if (use_software) { - return base::WrapUnique(new DelegatedCompositorOutputSurface( - routing_id(), output_surface_id, nullptr, nullptr, nullptr, - frame_swap_message_queue_)); - } - - scoped_refptr<ContextProviderCommandBuffer> worker_context_provider = - RenderThreadImpl::current()->SharedCompositorWorkerContextProvider(); - if (!worker_context_provider) { - // Cause the compositor to wait and try again. - return nullptr; - } - - // The renderer compositor context doesn't do a lot of stuff, so we don't - // expect it to need a lot of space for commands or transfer. Raster and - // uploads happen on the worker context instead. - gpu::SharedMemoryLimits limits = gpu::SharedMemoryLimits::ForMailboxContext(); - - // This is for an offscreen context for the compositor. So the default - // framebuffer doesn't need alpha, depth, stencil, antialiasing. - gpu::gles2::ContextCreationAttribHelper attributes; - attributes.alpha_size = -1; - attributes.depth_size = 0; - attributes.stencil_size = 0; - attributes.samples = 0; - attributes.sample_buffers = 0; - attributes.bind_generates_resource = false; - attributes.lose_context_when_out_of_memory = true; - - constexpr bool automatic_flushes = false; - constexpr bool support_locking = false; - - // The compositor context shares resources with the worker context unless - // the worker is async. - ContextProviderCommandBuffer* share_context = worker_context_provider.get(); - if (compositor_deps_->IsAsyncWorkerContextEnabled()) - share_context = nullptr; - - scoped_refptr<ContextProviderCommandBuffer> context_provider( - new ContextProviderCommandBuffer( - std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT, - gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle, - GetURLForGraphicsContext3D(), gfx::PreferIntegratedGpu, - automatic_flushes, support_locking, limits, attributes, share_context, - command_buffer_metrics::RENDER_COMPOSITOR_CONTEXT)); - -#if defined(OS_ANDROID) - if (RenderThreadImpl::current()->sync_compositor_message_filter()) { - return base::WrapUnique(new SynchronousCompositorOutputSurface( - context_provider, worker_context_provider, routing_id(), - output_surface_id, - RenderThreadImpl::current()->sync_compositor_message_filter(), - frame_swap_message_queue_)); - } -#endif - - // Composite-to-mailbox is currently used for layout tests in order to cause - // them to draw inside in the renderer to do the readback there. This should - // no longer be the case when crbug.com/311404 is fixed. - if (RenderThreadImpl::current()->layout_test_mode()) { - return base::WrapUnique(new MailboxOutputSurface( - routing_id(), output_surface_id, std::move(context_provider), - std::move(worker_context_provider), frame_swap_message_queue_, - cc::RGBA_8888)); - } - - return base::WrapUnique(new DelegatedCompositorOutputSurface( - routing_id(), output_surface_id, std::move(context_provider), - std::move(worker_context_provider), nullptr, frame_swap_message_queue_)); + return RenderThreadImpl::current()->CreateCompositorOutputSurface( + fallback, routing_id_, frame_swap_message_queue_, + GetURLForGraphicsContext3D()); } std::unique_ptr<cc::BeginFrameSource> @@ -915,13 +816,6 @@ void RenderWidget::WillBeginCompositorFrame() { WillBeginCompositorFrame()); } -void RenderWidget::ReportFixedRasterScaleUseCounters( - bool has_blurry_content, - bool has_potential_performance_regression) { - webwidget_->reportFixedRasterScaleUseCounters( - has_blurry_content, has_potential_performance_regression); -} - /////////////////////////////////////////////////////////////////////////////// // RenderWidgetInputHandlerDelegate @@ -937,27 +831,6 @@ bool RenderWidget::HasTouchEventHandlersAt(const gfx::Point& point) const { return true; } -void RenderWidget::ObserveWheelEventAndResult( - const blink::WebMouseWheelEvent& wheel_event, - const gfx::Vector2dF& wheel_unused_delta, - bool event_processed) { - if (!compositor_deps_->IsElasticOverscrollEnabled()) - return; - - cc::InputHandlerScrollResult scroll_result; - scroll_result.did_scroll = event_processed; - scroll_result.did_overscroll_root = !wheel_unused_delta.IsZero(); - scroll_result.unused_scroll_delta = wheel_unused_delta; - - RenderThreadImpl* render_thread = RenderThreadImpl::current(); - InputHandlerManager* input_handler_manager = - render_thread ? render_thread->input_handler_manager() : NULL; - if (input_handler_manager) { - input_handler_manager->ObserveWheelEventAndResultOnMainThread( - routing_id_, wheel_event, scroll_result); - } -} - void RenderWidget::ObserveGestureEventAndResult( const blink::WebGestureEvent& gesture_event, const gfx::Vector2dF& unused_delta, @@ -2099,4 +1972,17 @@ float RenderWidget::GetOriginalDeviceScaleFactor() const { device_scale_factor_; } +bool RenderWidget::requestPointerLock() { + return mouse_lock_dispatcher_->LockMouse(webwidget_mouse_lock_target_.get()); +} + +void RenderWidget::requestPointerUnlock() { + mouse_lock_dispatcher_->UnlockMouse(webwidget_mouse_lock_target_.get()); +} + +bool RenderWidget::isPointerLocked() { + return mouse_lock_dispatcher_->IsMouseLockedTo( + webwidget_mouse_lock_target_.get()); +} + } // namespace content diff --git a/chromium/content/renderer/render_widget.h b/chromium/content/renderer/render_widget.h index 181222d7c44..8cb0010653d 100644 --- a/chromium/content/renderer/render_widget.h +++ b/chromium/content/renderer/render_widget.h @@ -27,6 +27,8 @@ #include "content/renderer/input/render_widget_input_handler.h" #include "content/renderer/input/render_widget_input_handler_delegate.h" #include "content/renderer/message_delivery_policy.h" +#include "content/renderer/mouse_lock_dispatcher.h" +#include "content/renderer/render_widget_mouse_lock_dispatcher.h" #include "ipc/ipc_listener.h" #include "ipc/ipc_sender.h" #include "third_party/WebKit/public/platform/WebDisplayMode.h" @@ -39,7 +41,6 @@ #include "third_party/WebKit/public/web/WebTouchAction.h" #include "third_party/WebKit/public/web/WebWidget.h" #include "third_party/WebKit/public/web/WebWidgetClient.h" -#include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/ime/text_input_mode.h" #include "ui/base/ime/text_input_type.h" #include "ui/base/ui_base_types.h" @@ -202,16 +203,10 @@ class CONTENT_EXPORT RenderWidget void RequestScheduleAnimation() override; void UpdateVisualState() override; void WillBeginCompositorFrame() override; - void ReportFixedRasterScaleUseCounters( - bool has_blurry_content, - bool has_potential_performance_regression) override; // RenderWidgetInputHandlerDelegate void FocusChangeComplete() override; bool HasTouchEventHandlersAt(const gfx::Point& point) const override; - void ObserveWheelEventAndResult(const blink::WebMouseWheelEvent& wheel_event, - const gfx::Vector2dF& wheel_unused_delta, - bool event_processed) override; void ObserveGestureEventAndResult(const blink::WebGestureEvent& gesture_event, const gfx::Vector2dF& unused_delta, bool event_processed) override; @@ -262,6 +257,9 @@ class CONTENT_EXPORT RenderWidget void showImeIfNeeded() override; void convertViewportToWindow(blink::WebRect* rect) override; void convertWindowToViewport(blink::WebFloatRect* rect) override; + bool requestPointerLock() override; + void requestPointerUnlock() override; + bool isPointerLocked() override; // Override point to obtain that the current input method state and caret // position. @@ -346,9 +344,6 @@ class CONTENT_EXPORT RenderWidget // the new value will be sent to the browser process. void UpdateSelectionBounds(); - // Called by the compositor to forward a proto that represents serialized - // compositor state. - virtual void GetSelectionBounds(gfx::Rect* start, gfx::Rect* end); void OnShowHostContextMenu(ContextMenuParams* params); @@ -366,6 +361,10 @@ class CONTENT_EXPORT RenderWidget // Indicates whether this widget has focus. bool has_focus() const { return has_focus_; } + MouseLockDispatcher* mouse_lock_dispatcher() { + return mouse_lock_dispatcher_.get(); + } + protected: // Friend RefCounted so that the dtor can be non-public. Using this class // without ref-counting is an error. @@ -424,7 +423,7 @@ class CONTENT_EXPORT RenderWidget // Used to force the size of a window when running layout tests. void SetWindowRectSynchronously(const gfx::Rect& new_window_rect); -#if defined(OS_MACOSX) || defined(OS_ANDROID) +#if defined(USE_EXTERNAL_POPUP_MENU) void SetExternalPopupOriginAdjustmentsForEmulation( ExternalPopupMenu* popup, RenderWidgetScreenMetricsEmulator* emulator); @@ -442,7 +441,6 @@ class CONTENT_EXPORT RenderWidget virtual void OnResize(const ResizeParams& params); void OnEnableDeviceEmulation(const blink::WebDeviceEmulationParams& params); void OnDisableDeviceEmulation(); - void OnColorProfile(const std::vector<char>& color_profile); void OnChangeResizeRect(const gfx::Rect& resizer_rect); virtual void OnWasHidden(); virtual void OnWasShown(bool needs_repainting, @@ -717,8 +715,6 @@ class CONTENT_EXPORT RenderWidget std::queue<SyntheticGestureCompletionCallback> pending_synthetic_gesture_callbacks_; - uint32_t next_output_surface_id_; - #if defined(OS_ANDROID) // Indicates value in the focused text field is in dirty state, i.e. modified // by script etc., not by user input. @@ -760,6 +756,12 @@ class CONTENT_EXPORT RenderWidget std::unique_ptr<scheduler::RenderWidgetSchedulingState> render_widget_scheduling_state_; + // Mouse Lock dispatcher attached to this view. + std::unique_ptr<RenderWidgetMouseLockDispatcher> mouse_lock_dispatcher_; + + // Wraps the |webwidget_| as a MouseLockDispatcher::LockTarget interface. + std::unique_ptr<MouseLockDispatcher::LockTarget> webwidget_mouse_lock_target_; + private: // When emulated, this returns original device scale factor. float GetOriginalDeviceScaleFactor() const; diff --git a/chromium/content/renderer/render_widget_fullscreen_pepper.cc b/chromium/content/renderer/render_widget_fullscreen_pepper.cc index 30a6372c082..10df6034b8f 100644 --- a/chromium/content/renderer/render_widget_fullscreen_pepper.cc +++ b/chromium/content/renderer/render_widget_fullscreen_pepper.cc @@ -145,8 +145,7 @@ class PepperWidget : public WebWidget { size_ = size; WebRect plugin_rect(0, 0, size_.width, size_.height); - widget_->plugin()->ViewChanged(plugin_rect, plugin_rect, plugin_rect, - std::vector<gfx::Rect>()); + widget_->plugin()->ViewChanged(plugin_rect, plugin_rect, plugin_rect); widget_->Invalidate(); } diff --git a/chromium/content/renderer/render_view_mouse_lock_dispatcher.cc b/chromium/content/renderer/render_widget_mouse_lock_dispatcher.cc index bdd747b044e..970bef08fd6 100644 --- a/chromium/content/renderer/render_view_mouse_lock_dispatcher.cc +++ b/chromium/content/renderer/render_widget_mouse_lock_dispatcher.cc @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/render_view_mouse_lock_dispatcher.h" +#include "content/renderer/render_widget_mouse_lock_dispatcher.h" #include "content/common/view_messages.h" #include "content/renderer/render_view_impl.h" +#include "ipc/ipc_message.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" #include "third_party/WebKit/public/web/WebView.h" @@ -15,31 +16,29 @@ using blink::WebUserGestureIndicator; namespace content { -RenderViewMouseLockDispatcher::RenderViewMouseLockDispatcher( - RenderViewImpl* render_view_impl) - : RenderViewObserver(render_view_impl), - render_view_impl_(render_view_impl) { -} +RenderWidgetMouseLockDispatcher::RenderWidgetMouseLockDispatcher( + RenderWidget* render_widget) + : render_widget_(render_widget) {} -RenderViewMouseLockDispatcher::~RenderViewMouseLockDispatcher() { -} +RenderWidgetMouseLockDispatcher::~RenderWidgetMouseLockDispatcher() {} -void RenderViewMouseLockDispatcher::SendLockMouseRequest( +void RenderWidgetMouseLockDispatcher::SendLockMouseRequest( bool unlocked_by_target) { bool user_gesture = WebUserGestureIndicator::isProcessingUserGesture(); - Send(new ViewHostMsg_LockMouse(routing_id(), user_gesture, unlocked_by_target, - false)); + render_widget_->Send(new ViewHostMsg_LockMouse( + render_widget_->routing_id(), user_gesture, unlocked_by_target, false)); } -void RenderViewMouseLockDispatcher::SendUnlockMouseRequest() { - Send(new ViewHostMsg_UnlockMouse(routing_id())); +void RenderWidgetMouseLockDispatcher::SendUnlockMouseRequest() { + render_widget_->Send( + new ViewHostMsg_UnlockMouse(render_widget_->routing_id())); } -bool RenderViewMouseLockDispatcher::OnMessageReceived( +bool RenderWidgetMouseLockDispatcher::OnMessageReceived( const IPC::Message& message) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP(RenderViewMouseLockDispatcher, message) + IPC_BEGIN_MESSAGE_MAP(RenderWidgetMouseLockDispatcher, message) IPC_MESSAGE_HANDLER(ViewMsg_LockMouse_ACK, OnLockMouseACK) IPC_MESSAGE_FORWARD(ViewMsg_MouseLockLost, static_cast<MouseLockDispatcher*>(this), @@ -49,7 +48,7 @@ bool RenderViewMouseLockDispatcher::OnMessageReceived( return handled; } -void RenderViewMouseLockDispatcher::OnLockMouseACK(bool succeeded) { +void RenderWidgetMouseLockDispatcher::OnLockMouseACK(bool succeeded) { // Notify the base class. MouseLockDispatcher::OnLockMouseACK(succeeded); @@ -59,8 +58,8 @@ void RenderViewMouseLockDispatcher::OnLockMouseACK(bool succeeded) { // Mouse Capture is implicitly given for the duration of a drag event, and // sends all mouse events to the initial target of the drag. // If Lock is entered it supercedes any in progress Capture. - if (succeeded && render_view_impl_->GetWidget()->webwidget()) - render_view_impl_->GetWidget()->webwidget()->mouseCaptureLost(); + if (succeeded && render_widget_->webwidget()) + render_widget_->webwidget()->mouseCaptureLost(); } } // namespace content diff --git a/chromium/content/renderer/render_widget_mouse_lock_dispatcher.h b/chromium/content/renderer/render_widget_mouse_lock_dispatcher.h new file mode 100644 index 00000000000..ed5ecee0259 --- /dev/null +++ b/chromium/content/renderer/render_widget_mouse_lock_dispatcher.h @@ -0,0 +1,42 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_RENDER_WIDGET_MOUSE_LOCK_DISPATCHER_H_ +#define CONTENT_RENDERER_RENDER_WIDGET_MOUSE_LOCK_DISPATCHER_H_ + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "content/renderer/mouse_lock_dispatcher.h" + +namespace IPC { +class Message; +} + +namespace content { + +class RenderWidget; + +// RenderWidgetMouseLockDispatcher is owned by RenderWidget. +class RenderWidgetMouseLockDispatcher : public MouseLockDispatcher { + public: + explicit RenderWidgetMouseLockDispatcher(RenderWidget* render_widget); + ~RenderWidgetMouseLockDispatcher() override; + + bool OnMessageReceived(const IPC::Message& message); + + private: + // MouseLockDispatcher implementation. + void SendLockMouseRequest(bool unlocked_by_target) override; + void SendUnlockMouseRequest() override; + + void OnLockMouseACK(bool succeeded); + + RenderWidget* render_widget_; + + DISALLOW_COPY_AND_ASSIGN(RenderWidgetMouseLockDispatcher); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_RENDER_WIDGET_MOUSE_LOCK_DISPATCHER_H_ diff --git a/chromium/content/renderer/render_widget_unittest.cc b/chromium/content/renderer/render_widget_unittest.cc index 91b687f20d9..9b7ac2ea586 100644 --- a/chromium/content/renderer/render_widget_unittest.cc +++ b/chromium/content/renderer/render_widget_unittest.cc @@ -4,6 +4,7 @@ #include "content/renderer/render_widget.h" +#include <tuple> #include <vector> #include "base/macros.h" @@ -167,7 +168,7 @@ TEST_F(RenderWidgetUnittest, TouchHitTestSinglePoint) { EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); InputHostMsg_HandleInputEvent_ACK::Param params; InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); - InputEventAckState ack_state = base::get<0>(params).state; + InputEventAckState ack_state = std::get<0>(params).state; EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, ack_state); widget()->sink()->ClearMessages(); @@ -185,7 +186,7 @@ TEST_F(RenderWidgetUnittest, TouchHitTestSinglePoint) { message = widget()->sink()->GetMessageAt(0); EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); - ack_state = base::get<0>(params).state; + ack_state = std::get<0>(params).state; EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_state); widget()->sink()->ClearMessages(); } @@ -212,7 +213,7 @@ TEST_F(RenderWidgetUnittest, TouchHitTestMultiplePoints) { EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); InputHostMsg_HandleInputEvent_ACK::Param params; InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); - InputEventAckState ack_state = base::get<0>(params).state; + InputEventAckState ack_state = std::get<0>(params).state; EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, ack_state); widget()->sink()->ClearMessages(); @@ -223,7 +224,7 @@ TEST_F(RenderWidgetUnittest, TouchHitTestMultiplePoints) { message = widget()->sink()->GetMessageAt(0); EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); - ack_state = base::get<0>(params).state; + ack_state = std::get<0>(params).state; EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_state); widget()->sink()->ClearMessages(); } @@ -248,7 +249,7 @@ TEST_F(RenderWidgetUnittest, EventOverscroll) { ASSERT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type()); InputHostMsg_HandleInputEvent_ACK::Param params; InputHostMsg_HandleInputEvent_ACK::Read(message, ¶ms); - const InputEventAck& ack = base::get<0>(params); + const InputEventAck& ack = std::get<0>(params); ASSERT_EQ(ack.type, scroll.type); ASSERT_TRUE(ack.overscroll); EXPECT_EQ(gfx::Vector2dF(0, 10), ack.overscroll->accumulated_overscroll); @@ -269,7 +270,7 @@ TEST_F(RenderWidgetUnittest, FlingOverscroll) { ASSERT_EQ(InputHostMsg_DidOverscroll::ID, message->type()); InputHostMsg_DidOverscroll::Param params; InputHostMsg_DidOverscroll::Read(message, ¶ms); - const DidOverscrollParams& overscroll = base::get<0>(params); + const DidOverscrollParams& overscroll = std::get<0>(params); EXPECT_EQ(gfx::Vector2dF(10, 5), overscroll.latest_overscroll_delta); EXPECT_EQ(gfx::Vector2dF(5, 5), overscroll.accumulated_overscroll); EXPECT_EQ(gfx::PointF(1, 1), overscroll.causal_event_viewport_point); diff --git a/chromium/content/renderer/renderer.sb b/chromium/content/renderer/renderer.sb index 8c0f569abcc..7afdf86b297 100644 --- a/chromium/content/renderer/renderer.sb +++ b/chromium/content/renderer/renderer.sb @@ -34,18 +34,6 @@ (allow file-read-metadata (regex #"^/(private/)?etc$")) -; https://crbug.com/508935 -; TODO(tkent): Remove this section when we drop 'results' attribute support. -; https://crbug.com/590117 -(if (param-true? elcap-or-later) - (allow file-read* - (literal "/usr/lib/libcrypto.0.9.8.dylib") - (literal "/usr/lib/libcsfde.dylib") - (literal "/usr/lib/libcurl.4.dylib") - (literal "/usr/lib/libCoreStorage.dylib") - (literal "/usr/lib/libsasl2.2.dylib") - (literal "/usr/lib/libutil.dylib"))) - ; https://crbug.com/605840 ; file-read-metadata /System/Library/LinguisticData/en/US/hyphenation.dat ; for CFStringIsHyphenationAvailableForLocale and CFStringGetHyphenationLocationBeforeIndex diff --git a/chromium/content/renderer/renderer_blink_platform_impl.cc b/chromium/content/renderer/renderer_blink_platform_impl.cc index 478cf8161ce..a3878139660 100644 --- a/chromium/content/renderer/renderer_blink_platform_impl.cc +++ b/chromium/content/renderer/renderer_blink_platform_impl.cc @@ -8,6 +8,7 @@ #include "base/command_line.h" #include "base/files/file_path.h" +#include "base/guid.h" #include "base/lazy_instance.h" #include "base/location.h" #include "base/logging.h" @@ -43,10 +44,8 @@ #include "content/common/frame_messages.h" #include "content/common/gpu/client/context_provider_command_buffer.h" #include "content/common/gpu_process_launch_causes.h" -#include "content/common/mime_registry_messages.h" #include "content/common/render_process_messages.h" #include "content/public/common/content_switches.h" -#include "content/public/common/service_registry.h" #include "content/public/common/webplugininfo.h" #include "content/public/renderer/content_renderer_client.h" #include "content/public/renderer/media_stream_utils.h" @@ -61,6 +60,7 @@ #include "content/renderer/gamepad_shared_memory_reader.h" #include "content/renderer/media/audio_decoder.h" #include "content/renderer/media/canvas_capture_handler.h" +#include "content/renderer/media/html_audio_element_capturer_source.h" #include "content/renderer/media/html_video_element_capturer_source.h" #include "content/renderer/media/image_capture_frame_grabber.h" #include "content/renderer/media/media_recorder_handler.h" @@ -84,6 +84,7 @@ #include "media/base/mime_util.h" #include "media/blink/webcontentdecryptionmodule_impl.h" #include "media/filters/stream_parser_factory.h" +#include "mojo/common/common_type_converters.h" #include "storage/common/database/database_identifier.h" #include "storage/common/quota/quota_types.h" #include "third_party/WebKit/public/platform/BlameContext.h" @@ -99,9 +100,9 @@ #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebVector.h" +#include "third_party/WebKit/public/platform/mime_registry.mojom.h" #include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionListener.h" #include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationListener.h" -#include "ui/gfx/color_profile.h" #include "url/gurl.h" #if defined(OS_MACOSX) @@ -192,6 +193,9 @@ class RendererBlinkPlatformImpl::MimeRegistry const blink::WebString& codecs) override; blink::WebString mimeTypeForExtension( const blink::WebString& file_extension) override; + + private: + blink::mojom::MimeRegistryPtr mime_registry_; }; class RendererBlinkPlatformImpl::FileUtilities : public WebFileUtilitiesImpl { @@ -238,7 +242,7 @@ class RendererBlinkPlatformImpl::SandboxSupport RendererBlinkPlatformImpl::RendererBlinkPlatformImpl( scheduler::RendererScheduler* renderer_scheduler, - base::WeakPtr<ServiceRegistry> service_registry) + base::WeakPtr<shell::InterfaceProvider> remote_interfaces) : BlinkPlatformImpl(renderer_scheduler->DefaultTaskRunner()), main_thread_(renderer_scheduler->CreateMainThread()), clipboard_delegate_(new RendererClipboardDelegate), @@ -250,7 +254,8 @@ RendererBlinkPlatformImpl::RendererBlinkPlatformImpl( loading_task_runner_(renderer_scheduler->LoadingTaskRunner()), web_scrollbar_behavior_(new WebScrollbarBehaviorImpl), renderer_scheduler_(renderer_scheduler), - blink_service_registry_(new BlinkServiceRegistryImpl(service_registry)) { + blink_service_registry_( + new BlinkServiceRegistryImpl(remote_interfaces)) { #if !defined(OS_ANDROID) && !defined(OS_WIN) if (g_sandbox_enabled && sandboxEnabled()) { sandbox_support_.reset(new RendererBlinkPlatformImpl::SandboxSupport); @@ -511,11 +516,15 @@ WebString RendererBlinkPlatformImpl::MimeRegistry::mimeTypeForExtension( const WebString& file_extension) { // The sandbox restricts our access to the registry, so we need to proxy // these calls over to the browser process. - std::string mime_type; - RenderThread::Get()->Send( - new MimeRegistryMsg_GetMimeTypeFromExtension( - blink::WebStringToFilePath(file_extension).value(), &mime_type)); - return base::ASCIIToUTF16(mime_type); + if (!mime_registry_) + RenderThread::Get()->GetRemoteInterfaces()->GetInterface(&mime_registry_); + + mojo::String mime_type; + if (!mime_registry_->GetMimeTypeFromExtension( + mojo::String::From(base::string16(file_extension)), &mime_type)) { + return WebString(); + } + return base::ASCIIToUTF16(mime_type.get()); } //------------------------------------------------------------------------------ @@ -639,11 +648,8 @@ long long RendererBlinkPlatformImpl::databaseGetFileSize( long long RendererBlinkPlatformImpl::databaseGetSpaceAvailableForOrigin( const blink::WebSecurityOrigin& origin) { - // TODO(jsbell): Pass url::Origin over IPC instead of database - // identifier/GURL. https://crbug.com/591482 - return DatabaseUtil::DatabaseGetSpaceAvailable(WebString::fromUTF8( - storage::GetIdentifierFromOrigin(WebSecurityOriginToGURL(origin))), - sync_message_filter_.get()); + return DatabaseUtil::DatabaseGetSpaceAvailable(origin, + sync_message_filter_.get()); } bool RendererBlinkPlatformImpl::databaseSetFileSize( @@ -836,27 +842,6 @@ blink::WebString RendererBlinkPlatformImpl::signedPublicKeyAndChallengeString( //------------------------------------------------------------------------------ -void RendererBlinkPlatformImpl::screenColorProfile( - WebVector<char>* to_profile) { -#if defined(OS_WIN) - // On Windows screen color profile is only available in the browser. - std::vector<char> profile; - // This Send() can be called from any impl-side thread. Use a thread - // safe send to avoid crashing trying to access RenderThread::Get(), - // which is not accessible from arbitrary threads. - thread_safe_sender_->Send( - new RenderProcessHostMsg_GetMonitorColorProfile(&profile)); - *to_profile = profile; -#else - // On other platforms, the primary monitor color profile can be read - // directly. - gfx::ColorProfile profile; - *to_profile = profile.profile(); -#endif -} - -//------------------------------------------------------------------------------ - blink::WebScrollbarBehavior* RendererBlinkPlatformImpl::scrollbarBehavior() { return web_scrollbar_behavior_.get(); } @@ -975,6 +960,33 @@ void RendererBlinkPlatformImpl::createHTMLVideoElementCapturer( #endif } +void RendererBlinkPlatformImpl::createHTMLAudioElementCapturer( + WebMediaStream* web_media_stream, + WebMediaPlayer* web_media_player) { + DCHECK(web_media_stream); + DCHECK(web_media_player); + + blink::WebMediaStreamSource web_media_stream_source; + blink::WebMediaStreamTrack web_media_stream_track; + const WebString track_id = WebString::fromUTF8(base::GenerateGUID()); + + web_media_stream_source.initialize(track_id, + blink::WebMediaStreamSource::TypeAudio, + track_id, + false /* is_remote */); + web_media_stream_track.initialize(web_media_stream_source); + + MediaStreamAudioSource* const media_stream_source = + HtmlAudioElementCapturerSource::CreateFromWebMediaPlayerImpl( + web_media_player); + + // Takes ownership of |media_stream_source|. + web_media_stream_source.setExtraData(media_stream_source); + + media_stream_source->ConnectToTrack(web_media_stream_track); + web_media_stream->addTrack(web_media_stream_track); +} + //------------------------------------------------------------------------------ WebImageCaptureFrameGrabber* @@ -1072,6 +1084,8 @@ RendererBlinkPlatformImpl::createOffscreenGraphicsContext3DProvider( attributes.samples = 0; attributes.sample_buffers = 0; attributes.bind_generates_resource = false; + // Prefer discrete GPU for WebGL. + attributes.gpu_preference = gl::PreferDiscreteGpu; attributes.fail_if_major_perf_caveat = web_attributes.failIfMajorPerformanceCaveat; @@ -1084,15 +1098,13 @@ RendererBlinkPlatformImpl::createOffscreenGraphicsContext3DProvider( constexpr bool automatic_flushes = true; constexpr bool support_locking = false; - // Prefer discrete GPU for WebGL. - constexpr gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; scoped_refptr<ContextProviderCommandBuffer> provider( new ContextProviderCommandBuffer( std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT, gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle, - GURL(top_document_web_url), gpu_preference, automatic_flushes, - support_locking, gpu::SharedMemoryLimits(), attributes, share_context, + GURL(top_document_web_url), automatic_flushes, support_locking, + gpu::SharedMemoryLimits(), attributes, share_context, command_buffer_metrics::OFFSCREEN_CONTEXT_FOR_WEBGL)); return new WebGraphicsContext3DProviderImpl(std::move(provider)); } diff --git a/chromium/content/renderer/renderer_blink_platform_impl.h b/chromium/content/renderer/renderer_blink_platform_impl.h index 85b8fb8bab4..ac345facef6 100644 --- a/chromium/content/renderer/renderer_blink_platform_impl.h +++ b/chromium/content/renderer/renderer_blink_platform_impl.h @@ -48,6 +48,10 @@ class RendererScheduler; class WebThreadImplForRendererScheduler; } +namespace shell { +class InterfaceProvider; +} + namespace content { class BlinkServiceRegistryImpl; class DeviceLightEventPump; @@ -58,7 +62,6 @@ class PlatformEventObserverBase; class QuotaMessageFilter; class RendererClipboardDelegate; class RenderView; -class ServiceRegistry; class ThreadSafeSender; class WebClipboardImpl; class WebDatabaseObserverImpl; @@ -66,8 +69,9 @@ class WebFileSystemImpl; class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { public: - RendererBlinkPlatformImpl(scheduler::RendererScheduler* renderer_scheduler, - base::WeakPtr<ServiceRegistry> service_registry); + RendererBlinkPlatformImpl( + scheduler::RendererScheduler* renderer_scheduler, + base::WeakPtr<shell::InterfaceProvider> remote_interfaces); ~RendererBlinkPlatformImpl() override; // Shutdown must be called just prior to shutting down blink. @@ -129,7 +133,6 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { void getPluginList(bool refresh, blink::WebPluginListBuilder* builder) override; blink::WebPublicSuffixList* publicSuffixList() override; - void screenColorProfile(blink::WebVector<char>* to_profile) override; blink::WebScrollbarBehavior* scrollbarBehavior() override; blink::WebIDBFactory* idbFactory() override; blink::WebServiceWorkerCacheStorage* cacheStorage( @@ -177,6 +180,9 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { void createHTMLVideoElementCapturer( blink::WebMediaStream* web_media_stream, blink::WebMediaPlayer* web_media_player) override; + void createHTMLAudioElementCapturer( + blink::WebMediaStream* web_media_stream, + blink::WebMediaPlayer* web_media_player) override; blink::WebImageCaptureFrameGrabber* createImageCaptureFrameGrabber() override; blink::WebGraphicsContext3DProvider* createOffscreenGraphicsContext3DProvider( const blink::Platform::ContextAttributes& attributes, diff --git a/chromium/content/renderer/renderer_main.cc b/chromium/content/renderer/renderer_main.cc index a00d117ce0c..149c18f8c68 100644 --- a/chromium/content/renderer/renderer_main.cc +++ b/chromium/content/renderer/renderer_main.cc @@ -52,7 +52,7 @@ #endif #if defined(ENABLE_WEBRTC) -#include "third_party/libjingle/overrides/init_webrtc.h" +#include "third_party/webrtc_overrides/init_webrtc.h" #endif #if defined(USE_OZONE) @@ -91,8 +91,6 @@ int RendererMain(const MainFunctionParams& parameters) { const base::CommandLine& parsed_command_line = parameters.command_line; - MojoShellConnectionImpl::Create(); - #if defined(OS_MACOSX) base::mac::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool; #endif // OS_MACOSX @@ -200,8 +198,6 @@ int RendererMain(const MainFunctionParams& parameters) { TRACE_EVENT_ASYNC_END0("toplevel", "RendererMain.START_MSG_LOOP", 0); } - MojoShellConnectionImpl::Destroy(); - #if defined(LEAK_SANITIZER) // Run leak detection before RenderProcessImpl goes out of scope. This helps // ignore shutdown-only leaks. diff --git a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.cc b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.cc index f0060ef0b21..5f2071d3779 100644 --- a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.cc +++ b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.cc @@ -31,6 +31,10 @@ bool ScreenOrientationDispatcher::OnMessageReceived( return handled; } +void ScreenOrientationDispatcher::OnDestruct() { + delete this; +} + void ScreenOrientationDispatcher::OnLockSuccess(int request_id) { blink::WebLockOrientationCallback* callback = pending_callbacks_.Lookup(request_id); diff --git a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.h b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.h index 4eadeb191fe..9d108d27668 100644 --- a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.h +++ b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher.h @@ -34,6 +34,7 @@ class CONTENT_EXPORT ScreenOrientationDispatcher : // RenderFrameObserver implementation. bool OnMessageReceived(const IPC::Message& message) override; + void OnDestruct() override; // blink::WebScreenOrientationClient implementation. void lockOrientation(blink::WebScreenOrientationLockType orientation, diff --git a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc index 4d9cf0226d2..b5f7bebf0ef 100644 --- a/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc +++ b/chromium/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc @@ -6,6 +6,7 @@ #include <list> #include <memory> +#include <tuple> #include "base/logging.h" #include "content/common/screen_orientation_messages.h" @@ -72,9 +73,9 @@ class ScreenOrientationDispatcherTest : public testing::Test { ScreenOrientationHostMsg_LockRequest::ID); EXPECT_TRUE(msg != NULL); - base::Tuple<blink::WebScreenOrientationLockType, int> params; + std::tuple<blink::WebScreenOrientationLockType, int> params; ScreenOrientationHostMsg_LockRequest::Read(msg, ¶ms); - return base::get<1>(params); + return std::get<1>(params); } IPC::TestSink& sink() { diff --git a/chromium/content/renderer/service_worker/service_worker_context_client.cc b/chromium/content/renderer/service_worker/service_worker_context_client.cc index 6a5cd56673c..c765667871b 100644 --- a/chromium/content/renderer/service_worker/service_worker_context_client.cc +++ b/chromium/content/renderer/service_worker/service_worker_context_client.cc @@ -29,7 +29,6 @@ #include "content/child/webmessageportchannel_impl.h" #include "content/common/devtools_messages.h" #include "content/common/message_port_messages.h" -#include "content/common/mojo/service_registry_impl.h" #include "content/common/service_worker/embedded_worker_messages.h" #include "content/common/service_worker/service_worker_messages.h" #include "content/public/common/push_event_payload.h" @@ -43,6 +42,7 @@ #include "content/renderer/service_worker/service_worker_type_util.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_macros.h" +#include "mojo/public/cpp/bindings/interface_request.h" #include "third_party/WebKit/public/platform/URLConversion.h" #include "third_party/WebKit/public/platform/WebMessagePortChannel.h" #include "third_party/WebKit/public/platform/WebReferrerPolicy.h" @@ -99,6 +99,9 @@ class WebServiceWorkerNetworkProviderImpl std::unique_ptr<RequestExtraData> extra_data(new RequestExtraData); extra_data->set_service_worker_provider_id(provider->provider_id()); extra_data->set_originated_from_service_worker(true); + // Service workers are only available in secure contexts, so all requests + // are initiated in a secure context. + extra_data->set_initiated_in_secure_context(true); request.setExtraData(extra_data.release()); } }; @@ -171,11 +174,13 @@ struct ServiceWorkerContextClient::WorkerContextData { using SkipWaitingCallbacksMap = IDMap<blink::WebServiceWorkerSkipWaitingCallbacks, IDMapOwnPointer>; using SyncEventCallbacksMap = - IDMap<const mojo::Callback<void(blink::mojom::ServiceWorkerEventStatus)>, + IDMap<const base::Callback<void(blink::mojom::ServiceWorkerEventStatus)>, IDMapOwnPointer>; explicit WorkerContextData(ServiceWorkerContextClient* owner) - : weak_factory(owner), proxy_weak_factory(owner->proxy_) {} + : interface_registry(nullptr), + weak_factory(owner), + proxy_weak_factory(owner->proxy_) {} ~WorkerContextData() { DCHECK(thread_checker.CalledOnValidThread()); @@ -196,7 +201,8 @@ struct ServiceWorkerContextClient::WorkerContextData { // Pending callbacks for Background Sync Events SyncEventCallbacksMap sync_event_callbacks; - ServiceRegistryImpl service_registry; + shell::InterfaceRegistry interface_registry; + shell::InterfaceProvider remote_interfaces; base::ThreadChecker thread_checker; base::WeakPtrFactory<ServiceWorkerContextClient> weak_factory; @@ -272,12 +278,11 @@ void ServiceWorkerContextClient::OnMessageReceived( DCHECK(handled); } -void ServiceWorkerContextClient::BindServiceRegistry( - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) { - context_->service_registry.Bind(std::move(services)); - context_->service_registry.BindRemoteServiceProvider( - std::move(exposed_services)); +void ServiceWorkerContextClient::BindInterfaceProviders( + shell::mojom::InterfaceProviderRequest request, + shell::mojom::InterfaceProviderPtr remote_interfaces) { + context_->interface_registry.Bind(std::move(request)); + context_->remote_interfaces.Bind(std::move(remote_interfaces)); } blink::WebURL ServiceWorkerContextClient::scope() const { @@ -375,8 +380,8 @@ void ServiceWorkerContextClient::workerContextStarted( DCHECK_NE(registration_info.registration_id, kInvalidServiceWorkerRegistrationId); - // Register Mojo services. - context_->service_registry.ServiceRegistry::AddService( + // Register Mojo interfaces. + context_->interface_registry.AddInterface( base::Bind(&BackgroundSyncClientImpl::Create)); SetRegistrationInServiceWorkerGlobalScope(registration_info, version_attrs); @@ -408,7 +413,8 @@ void ServiceWorkerContextClient::didInitializeWorkerContext( v8::Local<v8::Context> context) { GetContentClient() ->renderer() - ->DidInitializeServiceWorkerContextOnWorkerThread(context, script_url_); + ->DidInitializeServiceWorkerContextOnWorkerThread( + context, embedded_worker_id_, script_url_); } void ServiceWorkerContextClient::willDestroyWorkerContext( @@ -427,7 +433,7 @@ void ServiceWorkerContextClient::willDestroyWorkerContext( g_worker_client_tls.Pointer()->Set(NULL); GetContentClient()->renderer()->WillDestroyServiceWorkerContextOnWorkerThread( - context, script_url_); + context, embedded_worker_id_, script_url_); } void ServiceWorkerContextClient::workerContextDestroyed() { @@ -501,21 +507,23 @@ void ServiceWorkerContextClient::didHandleInstallEvent( int request_id, blink::WebServiceWorkerEventResult result) { Send(new ServiceWorkerHostMsg_InstallEventFinished( - GetRoutingID(), request_id, result)); + GetRoutingID(), request_id, result, proxy_->hasFetchEventHandler())); } -void ServiceWorkerContextClient::didHandleFetchEvent(int request_id) { - Send(new ServiceWorkerHostMsg_FetchEventFinished( - GetRoutingID(), request_id, - SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, +void ServiceWorkerContextClient::respondToFetchEvent(int response_id) { + Send(new ServiceWorkerHostMsg_FetchEventResponse( + GetRoutingID(), response_id, SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, ServiceWorkerResponse())); } -void ServiceWorkerContextClient::didHandleFetchEvent( - int request_id, +void ServiceWorkerContextClient::respondToFetchEvent( + int response_id, const blink::WebServiceWorkerResponse& web_response) { ServiceWorkerHeaderMap headers; GetServiceWorkerHeaderMapFromWebResponse(web_response, &headers); + ServiceWorkerHeaderList cors_exposed_header_names; + GetCorsExposedHeaderNamesFromWebResponse(web_response, + &cors_exposed_header_names); ServiceWorkerResponse response( web_response.url(), web_response.status(), web_response.statusText().utf8(), web_response.responseType(), headers, @@ -523,13 +531,19 @@ void ServiceWorkerContextClient::didHandleFetchEvent( web_response.streamURL(), web_response.error(), base::Time::FromInternalValue(web_response.responseTime()), !web_response.cacheStorageCacheName().isNull(), - web_response.cacheStorageCacheName().utf8()); - Send(new ServiceWorkerHostMsg_FetchEventFinished( - GetRoutingID(), request_id, - SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, + web_response.cacheStorageCacheName().utf8(), cors_exposed_header_names); + Send(new ServiceWorkerHostMsg_FetchEventResponse( + GetRoutingID(), response_id, SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, response)); } +void ServiceWorkerContextClient::didHandleFetchEvent( + int event_finish_id, + blink::WebServiceWorkerEventResult result) { + Send(new ServiceWorkerHostMsg_FetchEventFinished(GetRoutingID(), + event_finish_id, result)); +} + void ServiceWorkerContextClient::didHandleNotificationClickEvent( int request_id, blink::WebServiceWorkerEventResult result) { @@ -580,7 +594,8 @@ ServiceWorkerContextClient::createServiceWorkerNetworkProvider( provider_context_ = provider->context(); // Tell the network provider about which version to load. - provider->SetServiceWorkerVersionId(service_worker_version_id_); + provider->SetServiceWorkerVersionId(service_worker_version_id_, + embedded_worker_id_); // The provider is kept around for the lifetime of the DataSource // and ownership is transferred to the DataSource. @@ -758,7 +773,8 @@ void ServiceWorkerContextClient::OnInstallEvent(int request_id) { } void ServiceWorkerContextClient::OnFetchEvent( - int request_id, + int response_id, + int event_finish_id, const ServiceWorkerFetchRequest& request) { blink::WebServiceWorkerRequest webRequest; TRACE_EVENT0("ServiceWorker", @@ -789,9 +805,9 @@ void ServiceWorkerContextClient::OnFetchEvent( webRequest.setClientId(blink::WebString::fromUTF8(request.client_id)); webRequest.setIsReload(request.is_reload); if (request.fetch_type == ServiceWorkerFetchType::FOREIGN_FETCH) { - proxy_->dispatchForeignFetchEvent(request_id, webRequest); + proxy_->dispatchForeignFetchEvent(response_id, event_finish_id, webRequest); } else { - proxy_->dispatchFetchEvent(request_id, webRequest); + proxy_->dispatchFetchEvent(response_id, event_finish_id, webRequest); } } diff --git a/chromium/content/renderer/service_worker/service_worker_context_client.h b/chromium/content/renderer/service_worker/service_worker_context_client.h index 48b4dbd5178..a009d30c492 100644 --- a/chromium/content/renderer/service_worker/service_worker_context_client.h +++ b/chromium/content/renderer/service_worker/service_worker_context_client.h @@ -13,6 +13,7 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/id_map.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -64,7 +65,7 @@ class ServiceWorkerContextClient : public blink::WebServiceWorkerContextClient { public: using SyncCallback = - mojo::Callback<void(blink::mojom::ServiceWorkerEventStatus)>; + base::Callback<void(blink::mojom::ServiceWorkerEventStatus)>; // Returns a thread-specific client instance. This does NOT create a // new instance. @@ -82,11 +83,10 @@ class ServiceWorkerContextClient int embedded_worker_id, const IPC::Message& message); - // Called some time after the worker has started. Attempts to use the - // ServiceRegistry to connect to services before this method is called are - // queued up and will resolve after this method is called. - void BindServiceRegistry(shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services); + // Called some time after the worker has started. + void BindInterfaceProviders( + shell::mojom::InterfaceProviderRequest request, + shell::mojom::InterfaceProviderPtr remote_interfaces); // WebServiceWorkerContextClient overrides. blink::WebURL scope() const override; @@ -136,10 +136,12 @@ class ServiceWorkerContextClient void didHandleInstallEvent( int request_id, blink::WebServiceWorkerEventResult result) override; - void didHandleFetchEvent(int request_id) override; - void didHandleFetchEvent( - int request_id, + void respondToFetchEvent(int response_id) override; + void respondToFetchEvent( + int response_id, const blink::WebServiceWorkerResponse& response) override; + void didHandleFetchEvent(int event_finish_id, + blink::WebServiceWorkerEventResult result) override; void didHandleNotificationClickEvent( int request_id, blink::WebServiceWorkerEventResult result) override; @@ -199,7 +201,9 @@ class ServiceWorkerContextClient int request_id, const ServiceWorkerMsg_ExtendableMessageEvent_Params& params); void OnInstallEvent(int request_id); - void OnFetchEvent(int request_id, const ServiceWorkerFetchRequest& request); + void OnFetchEvent(int response_id, + int event_finish_id, + const ServiceWorkerFetchRequest& request); void OnNotificationClickEvent( int request_id, int64_t persistent_notification_id, diff --git a/chromium/content/renderer/service_worker/service_worker_type_util.cc b/chromium/content/renderer/service_worker/service_worker_type_util.cc index 9eb9f9c6c53..35769afd267 100644 --- a/chromium/content/renderer/service_worker/service_worker_type_util.cc +++ b/chromium/content/renderer/service_worker/service_worker_type_util.cc @@ -61,4 +61,14 @@ void GetServiceWorkerHeaderMapFromWebResponse( web_response.visitHTTPHeaderFields(MakeHeaderVisitor(headers).get()); } +void GetCorsExposedHeaderNamesFromWebResponse( + const blink::WebServiceWorkerResponse& web_response, + ServiceWorkerHeaderList* result) { + blink::WebVector<blink::WebString> headers = + web_response.corsExposedHeaderNames(); + result->resize(headers.size()); + std::transform(headers.begin(), headers.end(), result->begin(), + [](const blink::WebString& s) { return s.latin1(); }); +} + } // namespace content diff --git a/chromium/content/renderer/service_worker/service_worker_type_util.h b/chromium/content/renderer/service_worker/service_worker_type_util.h index 439231fdebd..f1cfa84e7a3 100644 --- a/chromium/content/renderer/service_worker/service_worker_type_util.h +++ b/chromium/content/renderer/service_worker/service_worker_type_util.h @@ -22,6 +22,10 @@ void GetServiceWorkerHeaderMapFromWebResponse( const blink::WebServiceWorkerResponse& web_response, ServiceWorkerHeaderMap* headers); +void GetCorsExposedHeaderNamesFromWebResponse( + const blink::WebServiceWorkerResponse& web_response, + ServiceWorkerHeaderList* result); + } // namespace content #endif // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TYPE_UTIL_H_ diff --git a/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.cc index 4b7509754fc..1b58b4f59dd 100644 --- a/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.cc +++ b/chromium/content/renderer/shared_worker/embedded_shared_worker_stub.cc @@ -18,6 +18,7 @@ #include "content/child/shared_worker_devtools_agent.h" #include "content/child/webmessageportchannel_impl.h" #include "content/common/worker_messages.h" +#include "content/public/common/origin_util.h" #include "content/renderer/devtools/devtools_agent.h" #include "content/renderer/render_thread_impl.h" #include "content/renderer/shared_worker/embedded_shared_worker_content_settings_client_proxy.h" @@ -72,6 +73,7 @@ class DataSourceExtraData public: DataSourceExtraData() {} ~DataSourceExtraData() override {} + bool is_secure_context = false; }; // Called on the main thread only and blink owns it. @@ -86,13 +88,19 @@ class WebServiceWorkerNetworkProviderImpl GetNetworkProviderFromDataSource(data_source); std::unique_ptr<RequestExtraData> extra_data(new RequestExtraData); extra_data->set_service_worker_provider_id(provider->provider_id()); + extra_data->set_initiated_in_secure_context( + static_cast<DataSourceExtraData*>(data_source->getExtraData()) + ->is_secure_context); request.setExtraData(extra_data.release()); // Explicitly set the SkipServiceWorker flag for subresources here if the // renderer process hasn't received SetControllerServiceWorker message. if (request.getRequestContext() != blink::WebURLRequest::RequestContextSharedWorker && - !provider->IsControlledByServiceWorker()) { - request.setSkipServiceWorker(true); + !provider->IsControlledByServiceWorker() && + request.skipServiceWorker() != + blink::WebURLRequest::SkipServiceWorker::All) { + request.setSkipServiceWorker( + blink::WebURLRequest::SkipServiceWorker::Controlling); } } @@ -248,6 +256,7 @@ EmbeddedSharedWorkerStub::createServiceWorkerNetworkProvider( // The provider is kept around for the lifetime of the DataSource // and ownership is transferred to the DataSource. DataSourceExtraData* extra_data = new DataSourceExtraData(); + extra_data->is_secure_context = IsOriginSecure(url_); data_source->setExtraData(extra_data); ServiceWorkerNetworkProvider::AttachToDocumentState(extra_data, std::move(provider)); diff --git a/chromium/content/renderer/shared_worker_repository.cc b/chromium/content/renderer/shared_worker_repository.cc index 607e044fe27..466a79b6877 100644 --- a/chromium/content/renderer/shared_worker_repository.cc +++ b/chromium/content/renderer/shared_worker_repository.cc @@ -59,4 +59,8 @@ void SharedWorkerRepository::documentDetached(DocumentID document) { } } +void SharedWorkerRepository::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/shared_worker_repository.h b/chromium/content/renderer/shared_worker_repository.h index 93ac628c379..8714f3af39d 100644 --- a/chromium/content/renderer/shared_worker_repository.h +++ b/chromium/content/renderer/shared_worker_repository.h @@ -37,6 +37,9 @@ class SharedWorkerRepository : public RenderFrameObserver, void documentDetached(DocumentID document_id) override; private: + // RenderFrameObserver implementation. + void OnDestruct() override; + std::set<DocumentID> documents_with_workers_; DISALLOW_COPY_AND_ASSIGN(SharedWorkerRepository); diff --git a/chromium/content/renderer/speech_recognition_dispatcher.cc b/chromium/content/renderer/speech_recognition_dispatcher.cc index 585b61cd8da..e707f4105df 100644 --- a/chromium/content/renderer/speech_recognition_dispatcher.cc +++ b/chromium/content/renderer/speech_recognition_dispatcher.cc @@ -66,6 +66,10 @@ bool SpeechRecognitionDispatcher::OnMessageReceived( return handled; } +void SpeechRecognitionDispatcher::OnDestruct() { + delete this; +} + void SpeechRecognitionDispatcher::start( const WebSpeechRecognitionHandle& handle, const WebSpeechRecognitionParams& params, diff --git a/chromium/content/renderer/speech_recognition_dispatcher.h b/chromium/content/renderer/speech_recognition_dispatcher.h index bde0bdf0f33..d0cddc075ea 100644 --- a/chromium/content/renderer/speech_recognition_dispatcher.h +++ b/chromium/content/renderer/speech_recognition_dispatcher.h @@ -45,6 +45,7 @@ class SpeechRecognitionDispatcher : public RenderViewObserver, private: // RenderViewObserver implementation. bool OnMessageReceived(const IPC::Message& message) override; + void OnDestruct() override; // blink::WebSpeechRecognizer implementation. void start(const blink::WebSpeechRecognitionHandle&, diff --git a/chromium/content/renderer/stats_collection_observer.cc b/chromium/content/renderer/stats_collection_observer.cc index 4c4b911ec8c..f2c45bf461c 100644 --- a/chromium/content/renderer/stats_collection_observer.cc +++ b/chromium/content/renderer/stats_collection_observer.cc @@ -30,4 +30,8 @@ void StatsCollectionObserver::DidStopLoading() { impl->RemoveObserver(this); } +void StatsCollectionObserver::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/stats_collection_observer.h b/chromium/content/renderer/stats_collection_observer.h index 5a17dfe6933..e1b73233120 100644 --- a/chromium/content/renderer/stats_collection_observer.h +++ b/chromium/content/renderer/stats_collection_observer.h @@ -30,6 +30,9 @@ class StatsCollectionObserver : public RenderViewObserver { const base::Time& load_stop_time() { return stop_time_; } private: + // RenderViewObserver implementation. + void OnDestruct() override; + base::Time start_time_; base::Time stop_time_; diff --git a/chromium/content/renderer/text_input_client_observer.cc b/chromium/content/renderer/text_input_client_observer.cc index e3b8bd7a377..3c953eebaad 100644 --- a/chromium/content/renderer/text_input_client_observer.cc +++ b/chromium/content/renderer/text_input_client_observer.cc @@ -48,6 +48,10 @@ bool TextInputClientObserver::OnMessageReceived(const IPC::Message& message) { return handled; } +void TextInputClientObserver::OnDestruct() { + delete this; +} + blink::WebView* TextInputClientObserver::webview() { return render_view()->GetWebView(); } diff --git a/chromium/content/renderer/text_input_client_observer.h b/chromium/content/renderer/text_input_client_observer.h index c41b670ce22..2c538a61c2b 100644 --- a/chromium/content/renderer/text_input_client_observer.h +++ b/chromium/content/renderer/text_input_client_observer.h @@ -31,6 +31,9 @@ class TextInputClientObserver : public RenderViewObserver { bool OnMessageReceived(const IPC::Message& message) override; private: + // RenderViewObserver implementation. + void OnDestruct() override; + // Returns the WebView of the RenderView. blink::WebView* webview(); diff --git a/chromium/content/renderer/visual_state_browsertest.cc b/chromium/content/renderer/visual_state_browsertest.cc index 26d9a6ddd26..2a8b49bff8f 100644 --- a/chromium/content/renderer/visual_state_browsertest.cc +++ b/chromium/content/renderer/visual_state_browsertest.cc @@ -50,6 +50,9 @@ class CommitObserver : public RenderViewObserver { int GetCommitCount() { return commit_count_; } private: + // RenderViewObserver implementation. + void OnDestruct() override { delete this; } + std::set<base::Closure*> quit_closures_; int commit_count_; }; diff --git a/chromium/content/renderer/web_ui_extension.cc b/chromium/content/renderer/web_ui_extension.cc index 0751e6ee68b..a793b4e215b 100644 --- a/chromium/content/renderer/web_ui_extension.cc +++ b/chromium/content/renderer/web_ui_extension.cc @@ -5,6 +5,7 @@ #include "content/renderer/web_ui_extension.h" #include <memory> +#include <utility> #include "base/values.h" #include "content/common/view_messages.h" @@ -108,13 +109,9 @@ void WebUIExtension::Send(gin::Arguments* args) { } std::unique_ptr<V8ValueConverter> converter(V8ValueConverter::create()); - - base::Value* value = - converter->FromV8Value(obj, frame->mainWorldScriptContext()); - base::ListValue* list = NULL; - value->GetAsList(&list); - DCHECK(list); - content.reset(list); + content = base::ListValue::From( + converter->FromV8Value(obj, frame->mainWorldScriptContext())); + DCHECK(content); } // Send the message up to the browser. diff --git a/chromium/content/renderer/web_ui_extension_data.cc b/chromium/content/renderer/web_ui_extension_data.cc index 80d570fd9a1..43cf15ec347 100644 --- a/chromium/content/renderer/web_ui_extension_data.cc +++ b/chromium/content/renderer/web_ui_extension_data.cc @@ -39,4 +39,8 @@ void WebUIExtensionData::OnSetWebUIProperty(const std::string& name, variable_map_[name] = value; } +void WebUIExtensionData::OnDestruct() { + delete this; +} + } // namespace content diff --git a/chromium/content/renderer/web_ui_extension_data.h b/chromium/content/renderer/web_ui_extension_data.h index 8bbac72a5b8..566faed6c4d 100644 --- a/chromium/content/renderer/web_ui_extension_data.h +++ b/chromium/content/renderer/web_ui_extension_data.h @@ -28,6 +28,7 @@ class WebUIExtensionData private: // RenderViewObserver implementation. bool OnMessageReceived(const IPC::Message& message) override; + void OnDestruct() override; void OnSetWebUIProperty(const std::string& name, const std::string& value); |