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

Unified Diff: content/browser/devtools/protocol/emulation_handler.cc

Issue 2411793008: Adds BeginFrameControl via DevTools.
Patch Set: BFC prototype v2 with allow_latency_opts and waiting for BFOs. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/devtools/protocol/emulation_handler.cc
diff --git a/content/browser/devtools/protocol/emulation_handler.cc b/content/browser/devtools/protocol/emulation_handler.cc
index a2f4cbd8082f9f2add3bce35701c566bbb2a45e0..e8916e4208ca2e6c2ba366ced7b1c17d918e3d80 100644
--- a/content/browser/devtools/protocol/emulation_handler.cc
+++ b/content/browser/devtools/protocol/emulation_handler.cc
@@ -6,15 +6,25 @@
#include <utility>
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "cc/output/begin_frame_args.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "cc/surfaces/surface_manager.h"
+#include "content/browser/compositor/surface_utils.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/browser/web_contents/web_contents_view.h"
#include "content/common/view_messages.h"
#include "content/public/common/url_constants.h"
#include "device/geolocation/geolocation_service_context.h"
#include "device/geolocation/geoposition.h"
+#include "ui/compositor/compositor.h"
namespace content {
namespace devtools {
@@ -56,10 +66,67 @@ ui::GestureProviderConfigType TouchEmulationConfigurationToType(
} // namespace
+class EmulatedBeginFrameSource : public cc::ExternalBeginFrameSource {
+ public:
+ explicit EmulatedBeginFrameSource(cc::ExternalBeginFrameSourceClient* client)
+ : cc::ExternalBeginFrameSource(client) {}
+ ~EmulatedBeginFrameSource() override {}
+
+ void DidFinishFrame(cc::BeginFrameObserver* obs,
+ size_t remaining_frames) override {
+ cc::ExternalBeginFrameSource::DidFinishFrame(obs, remaining_frames);
+ finished_observers_.insert(obs);
+ CheckFinished();
+ }
+
+ void AddObserver(cc::BeginFrameObserver* obs) override {
+ cc::ExternalBeginFrameSource::AddObserver(obs);
+ sorted_observers_.insert(obs);
+ }
+
+ void RemoveObserver(cc::BeginFrameObserver* obs) override {
+ cc::ExternalBeginFrameSource::RemoveObserver(obs);
+ sorted_observers_.erase(obs);
+ finished_observers_.erase(obs);
+ CheckFinished();
+ }
+
+ void SendBeginFrame(const cc::BeginFrameArgs& args) {
+ finished_observers_.clear();
+ OnBeginFrame(args);
+
+ for (cc::BeginFrameObserver* obs : sorted_observers_) {
+ // TODO(eseckler): Need sequence numbers in args to distinguish emulated
+ // args with equal timestamps.
+ if (obs->LastUsedBeginFrameArgs().frame_time != args.frame_time)
+ finished_observers_.insert(obs);
+ }
+ CheckFinished();
+ }
+
+ void WhenFinished(base::Callback<void()> callback) { callback_ = callback; }
+
+ private:
+ void CheckFinished() {
+ if (!base::STLIncludes(finished_observers_, sorted_observers_))
+ return;
+
+ if (callback_)
+ callback_.Run();
+ }
+
+ base::Callback<void()> callback_;
+ std::set<cc::BeginFrameObserver*> sorted_observers_;
+ std::set<cc::BeginFrameObserver*> finished_observers_;
+};
+
EmulationHandler::EmulationHandler()
: touch_emulation_enabled_(false),
device_emulation_enabled_(false),
- host_(nullptr) {
+ begin_frame_source_(nullptr),
+ needs_begin_frame_(false),
+ host_(nullptr),
+ weak_factory_(this) {
}
EmulationHandler::~EmulationHandler() {
@@ -69,16 +136,23 @@ void EmulationHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
if (host_ == host)
return;
+ DisableBeginFrameControl();
+
host_ = host;
UpdateTouchEventEmulationState();
UpdateDeviceEmulationState();
}
+void EmulationHandler::SetClient(std::unique_ptr<Client> client) {
+ client_.swap(client);
+}
+
void EmulationHandler::Detached() {
touch_emulation_enabled_ = false;
device_emulation_enabled_ = false;
UpdateTouchEventEmulationState();
UpdateDeviceEmulationState();
+ DisableBeginFrameControl();
}
Response EmulationHandler::SetGeolocationOverride(
@@ -290,6 +364,142 @@ Response EmulationHandler::SetVirtualTimePolicy(
return Response::FallThrough();
}
+#if defined(USE_AURA)
+Response EmulationHandler::EnableBeginFrameControl() {
+ if (begin_frame_source_)
+ return Response::OK(); // already enabled.
+
+ WebContentsImpl* web_contents = GetWebContents();
+ if (!web_contents)
+ return Response::InternalError("Could not connect to view");
+
+ ui::Compositor* compositor = web_contents->GetView()->GetCompositor();
+ if (!compositor)
+ return Response::InternalError("Could not obtain Compositor for view");
+
+ TRACE_EVENT_INSTANT2("cc", "EnableBeginFrameControl",
+ TRACE_EVENT_SCOPE_THREAD, "WebContents RoutingID",
+ web_contents->GetRoutingID(), "Compositor FrameSinkId",
+ compositor->frame_sink_id().ToString());
+
+ // TODO(eseckler): Support that Display of WebContents may change (and be
+ // destroyed) while BFC is enabled.
+
+ // Replace original BeginFrameSource by our DevTools-controlled one.
+ std::unique_ptr<cc::BeginFrameSource> begin_frame_source =
+ base::MakeUnique<EmulatedBeginFrameSource>(this);
+ begin_frame_source_ =
+ static_cast<EmulatedBeginFrameSource*>(begin_frame_source.get());
+ compositor->SwapBeginFrameSource(&begin_frame_source);
+ original_begin_frame_source_.swap(begin_frame_source);
+
+ return Response::OK();
+}
+
+Response EmulationHandler::DisableBeginFrameControl() {
+ if (!begin_frame_source_)
+ return Response::OK(); // already disabled.
+
+ WebContentsImpl* web_contents = GetWebContents();
+ if (!web_contents)
+ return Response::InternalError("Could not connect to view");
+
+ ui::Compositor* compositor = web_contents->GetView()->GetCompositor();
+ DCHECK(compositor);
+
+ compositor->SwapBeginFrameSource(&original_begin_frame_source_);
+ original_begin_frame_source_.reset();
+ begin_frame_source_ = nullptr;
+ needs_begin_frame_ = false;
+ return Response::OK();
+}
+
+Response EmulationHandler::SendBeginFrame(double interval,
+ const double* frame_time,
+ const double* deadline,
+ std::string* out_frame_id) {
+ if (!begin_frame_source_)
+ return Response::ServerError("BeginFrameControl not enabled");
+
+ RenderWidgetHostImpl* widget_host =
+ host_ ? host_->GetRenderWidgetHost() : nullptr;
+ if (!widget_host)
+ return Response::ServerError("Target does not support SendBeginFrame");
+
+ ui::Compositor* compositor = GetWebContents()->GetView()->GetCompositor();
+ DCHECK(compositor);
+
+ base::TimeTicks frame_time_ticks =
+ frame_time
+ ? base::TimeTicks::Now()
+ : base::TimeTicks() + base::TimeDelta::FromMicroseconds(*frame_time);
+ base::TimeDelta interval_delta = base::TimeDelta::FromMicroseconds(interval);
+ base::TimeTicks deadline_ticks =
+ deadline
+ ? (base::TimeTicks() + base::TimeDelta::FromMicroseconds(*deadline))
+ : (frame_time_ticks + interval_delta);
+ auto args = cc::BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, frame_time_ticks, deadline_ticks, interval_delta,
+ cc::BeginFrameArgs::NORMAL);
+
+ // TODO(eseckler): Expose via DevTools?
+ // Ensure that we give the renderer main thread(s) a chance to answer this
+ // BeginFrame (disables Begin(Main)Frame skipping).
+ args.allow_latency_optimizations = false;
+
+ *out_frame_id = base::GenerateGUID();
+
+ begin_frame_source_->WhenFinished(
+ base::Bind(&EmulationHandler::ClientFrameCommitted,
+ base::Unretained(this), *out_frame_id));
+ begin_frame_source_->SendBeginFrame(args);
+ return Response::OK();
+}
+
+#else
+Response EmulationHandler::EnableBeginFrameControl() {
+ return Response::InternalError("Only supported on Aura.");
+}
+
+Response EmulationHandler::DisableBeginFrameControl() {
+ return Response::InternalError("Only supported on Aura.");
+}
+
+Response EmulationHandler::SendBeginFrame(double interval,
+ const double* frame_time,
+ const double* deadline,
+ std::string* out_frame_id) {
+ return Response::InternalError("Only supported on Aura.");
+}
+#endif
+
+void EmulationHandler::OnNeedsBeginFrames(bool needs_begin_frames) {
+ if (needs_begin_frame_ == needs_begin_frames)
+ return;
+
+ needs_begin_frame_ = needs_begin_frames;
+ ClientSetNeedsBeginFrame(needs_begin_frame_);
+
+ // TODO(eseckler): Figure out if we need to capture needsBeginFrame updates
+ // elsewhere to avoid indicating (sole) presence of browser-level consumers.
+}
+
+void EmulationHandler::ClientSetNeedsBeginFrame(bool needs_begin_frame) {
+ if (!client_ || !begin_frame_source_)
+ return;
+
+ client_->SetNeedsBeginFrame(SetNeedsBeginFrameParams::Create()
+ ->set_needs_begin_frame(needs_begin_frame));
+}
+
+void EmulationHandler::ClientFrameCommitted(const std::string& frame_id) {
+ if (!client_ || !begin_frame_source_)
+ return;
+
+ client_->FrameCommitted(
+ FrameCommittedParams::Create()->set_frame_id(frame_id));
+}
+
WebContentsImpl* EmulationHandler::GetWebContents() {
return host_ ?
static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(host_)) :
« no previous file with comments | « content/browser/devtools/protocol/emulation_handler.h ('k') | content/browser/renderer_host/render_widget_host_view_aura.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698