blob: 6947d9b2ff184f63ca88e82d7612c50a37c77921 [file] [log] [blame]
/*
* Copyright (C) 2010-2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "web/WebDevToolsAgentImpl.h"
#include <v8-inspector.h>
#include <memory>
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "core/CoreProbeSink.h"
#include "core/events/WebInputEventConversion.h"
#include "core/exported/WebSettingsImpl.h"
#include "core/exported/WebViewBase.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/LocalFrameView.h"
#include "core/frame/Settings.h"
#include "core/frame/WebLocalFrameBase.h"
#include "core/inspector/DevToolsEmulator.h"
#include "core/inspector/InspectedFrames.h"
#include "core/inspector/InspectorAnimationAgent.h"
#include "core/inspector/InspectorApplicationCacheAgent.h"
#include "core/inspector/InspectorCSSAgent.h"
#include "core/inspector/InspectorDOMAgent.h"
#include "core/inspector/InspectorDOMDebuggerAgent.h"
#include "core/inspector/InspectorDOMSnapshotAgent.h"
#include "core/inspector/InspectorEmulationAgent.h"
#include "core/inspector/InspectorInputAgent.h"
#include "core/inspector/InspectorLayerTreeAgent.h"
#include "core/inspector/InspectorLogAgent.h"
#include "core/inspector/InspectorMemoryAgent.h"
#include "core/inspector/InspectorNetworkAgent.h"
#include "core/inspector/InspectorPageAgent.h"
#include "core/inspector/InspectorResourceContainer.h"
#include "core/inspector/InspectorResourceContentLoader.h"
#include "core/inspector/InspectorTaskRunner.h"
#include "core/inspector/InspectorTracingAgent.h"
#include "core/inspector/InspectorWorkerAgent.h"
#include "core/inspector/MainThreadDebugger.h"
#include "core/layout/api/LayoutViewItem.h"
#include "core/page/FocusController.h"
#include "core/page/Page.h"
#include "core/probe/CoreProbes.h"
#include "modules/accessibility/InspectorAccessibilityAgent.h"
#include "modules/cachestorage/InspectorCacheStorageAgent.h"
#include "modules/device_orientation/DeviceOrientationInspectorAgent.h"
#include "modules/indexeddb/InspectorIndexedDBAgent.h"
#include "modules/storage/InspectorDOMStorageAgent.h"
#include "modules/webdatabase/InspectorDatabaseAgent.h"
#include "platform/CrossThreadFunctional.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/paint/PaintController.h"
#include "platform/instrumentation/tracing/TraceEvent.h"
#include "platform/wtf/MathExtras.h"
#include "platform/wtf/Noncopyable.h"
#include "platform/wtf/PtrUtil.h"
#include "platform/wtf/text/WTFString.h"
#include "public/platform/Platform.h"
#include "public/platform/WebLayerTreeView.h"
#include "public/platform/WebRect.h"
#include "public/platform/WebString.h"
#include "public/web/WebDevToolsAgentClient.h"
#include "public/web/WebSettings.h"
#include "web/InspectorOverlayAgent.h"
#include "web/WebFrameWidgetImpl.h"
namespace blink {
namespace {
bool IsMainFrame(WebLocalFrameBase* frame) {
// TODO(dgozman): sometimes view->mainFrameImpl() does return null, even
// though |frame| is meant to be main frame. See http://crbug.com/526162.
return frame->ViewImpl() && !frame->Parent();
}
}
class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
public:
~ClientMessageLoopAdapter() override { instance_ = nullptr; }
static void EnsureMainThreadDebuggerCreated(WebDevToolsAgentClient* client) {
if (instance_)
return;
std::unique_ptr<ClientMessageLoopAdapter> instance =
WTF::WrapUnique(new ClientMessageLoopAdapter(
WTF::WrapUnique(client->CreateClientMessageLoop())));
instance_ = instance.get();
MainThreadDebugger::Instance()->SetClientMessageLoop(std::move(instance));
}
static void ContinueProgram() {
// Release render thread if necessary.
if (instance_)
instance_->QuitNow();
}
static void PauseForCreateWindow(WebLocalFrameBase* frame) {
if (instance_)
instance_->RunForCreateWindow(frame);
}
static bool ResumeForCreateWindow() {
return instance_ ? instance_->QuitForCreateWindow() : false;
}
private:
ClientMessageLoopAdapter(
std::unique_ptr<WebDevToolsAgentClient::WebKitClientMessageLoop>
message_loop)
: running_for_debug_break_(false),
running_for_create_window_(false),
message_loop_(std::move(message_loop)) {
DCHECK(message_loop_.get());
}
void Run(LocalFrame* frame) override {
if (running_for_debug_break_)
return;
running_for_debug_break_ = true;
if (!running_for_create_window_)
RunLoop(WebLocalFrameBase::FromFrame(frame));
}
void RunForCreateWindow(WebLocalFrameBase* frame) {
if (running_for_create_window_)
return;
running_for_create_window_ = true;
if (!running_for_debug_break_)
RunLoop(frame);
}
void RunLoop(WebLocalFrameBase* frame) {
// 0. Flush pending frontend messages.
WebDevToolsAgentImpl* agent = frame->DevToolsAgentImpl();
agent->FlushProtocolNotifications();
// 1. Disable input events.
WebFrameWidgetBase::SetIgnoreInputEvents(true);
for (const auto view : WebViewBase::AllInstances())
view->GetChromeClient().NotifyPopupOpeningObservers();
// 2. Notify embedder about pausing.
if (agent->Client())
agent->Client()->WillEnterDebugLoop();
// 3. Disable active objects
WebView::WillEnterModalLoop();
// 4. Process messages until quitNow is called.
message_loop_->Run();
// 5. Resume active objects
WebView::DidExitModalLoop();
WebFrameWidgetBase::SetIgnoreInputEvents(false);
// 7. Notify embedder about resuming.
if (agent->Client())
agent->Client()->DidExitDebugLoop();
}
void QuitNow() override {
if (running_for_debug_break_) {
running_for_debug_break_ = false;
if (!running_for_create_window_)
message_loop_->QuitNow();
}
}
bool QuitForCreateWindow() {
if (running_for_create_window_) {
running_for_create_window_ = false;
if (!running_for_debug_break_)
message_loop_->QuitNow();
return true;
}
return false;
}
void RunIfWaitingForDebugger(LocalFrame* frame) override {
// If we've paused for createWindow, handle it ourselves.
if (QuitForCreateWindow())
return;
// Otherwise, pass to the client (embedded workers do it differently).
WebDevToolsAgentImpl* agent =
WebLocalFrameBase::FromFrame(frame)->DevToolsAgentImpl();
if (agent && agent->Client())
agent->Client()->ResumeStartup();
}
bool running_for_debug_break_;
bool running_for_create_window_;
std::unique_ptr<WebDevToolsAgentClient::WebKitClientMessageLoop>
message_loop_;
static ClientMessageLoopAdapter* instance_;
};
ClientMessageLoopAdapter* ClientMessageLoopAdapter::instance_ = nullptr;
// static
WebDevToolsAgentImpl* WebDevToolsAgentImpl::Create(
WebLocalFrameBase* frame,
WebDevToolsAgentClient* client) {
if (!IsMainFrame(frame)) {
WebDevToolsAgentImpl* agent =
new WebDevToolsAgentImpl(frame, client, false);
if (frame->FrameWidget())
agent->LayerTreeViewChanged(
ToWebFrameWidgetImpl(frame->FrameWidget())->LayerTreeView());
return agent;
}
WebViewBase* view = frame->ViewImpl();
WebDevToolsAgentImpl* agent = new WebDevToolsAgentImpl(frame, client, true);
agent->LayerTreeViewChanged(view->LayerTreeView());
return agent;
}
WebDevToolsAgentImpl::WebDevToolsAgentImpl(
WebLocalFrameBase* web_local_frame_impl,
WebDevToolsAgentClient* client,
bool include_view_agents)
: client_(client),
web_local_frame_impl_(web_local_frame_impl),
probe_sink_(web_local_frame_impl_->GetFrame()->GetProbeSink()),
resource_content_loader_(InspectorResourceContentLoader::Create(
web_local_frame_impl_->GetFrame())),
inspected_frames_(
InspectedFrames::Create(web_local_frame_impl_->GetFrame())),
resource_container_(new InspectorResourceContainer(inspected_frames_)),
trace_events_(new InspectorTraceEvents()),
include_view_agents_(include_view_agents),
layer_tree_id_(0) {
DCHECK(IsMainThread());
DCHECK(web_local_frame_impl_->GetFrame());
probe_sink_->addInspectorTraceEvents(trace_events_);
}
WebDevToolsAgentImpl::~WebDevToolsAgentImpl() {
DCHECK(!client_);
}
DEFINE_TRACE(WebDevToolsAgentImpl) {
visitor->Trace(web_local_frame_impl_);
visitor->Trace(probe_sink_);
visitor->Trace(resource_content_loader_);
visitor->Trace(inspected_frames_);
visitor->Trace(resource_container_);
visitor->Trace(trace_events_);
visitor->Trace(page_agents_);
visitor->Trace(network_agents_);
visitor->Trace(layer_tree_agents_);
visitor->Trace(tracing_agents_);
visitor->Trace(overlay_agents_);
visitor->Trace(sessions_);
}
void WebDevToolsAgentImpl::WillBeDestroyed() {
DCHECK(web_local_frame_impl_->GetFrame());
DCHECK(inspected_frames_->Root()->View());
probe_sink_->removeInspectorTraceEvents(trace_events_);
trace_events_ = nullptr;
Vector<int> session_ids;
for (int session_id : sessions_.Keys())
session_ids.push_back(session_id);
for (int session_id : session_ids)
Detach(session_id);
resource_content_loader_->Dispose();
client_ = nullptr;
}
InspectorSession* WebDevToolsAgentImpl::InitializeSession(int session_id,
const String& host_id,
String* state) {
DCHECK(client_);
ClientMessageLoopAdapter::EnsureMainThreadDebuggerCreated(client_);
MainThreadDebugger* main_thread_debugger = MainThreadDebugger::Instance();
v8::Isolate* isolate = V8PerIsolateData::MainThreadIsolate();
InspectorSession* session = new InspectorSession(
this, probe_sink_.Get(), session_id,
main_thread_debugger->GetV8Inspector(),
main_thread_debugger->ContextGroupId(inspected_frames_->Root()), state);
InspectorDOMAgent* dom_agent = new InspectorDOMAgent(
isolate, inspected_frames_.Get(), session->V8Session());
session->Append(dom_agent);
InspectorLayerTreeAgent* layer_tree_agent =
InspectorLayerTreeAgent::Create(inspected_frames_.Get());
layer_tree_agents_.Set(session_id, layer_tree_agent);
session->Append(layer_tree_agent);
InspectorNetworkAgent* network_agent =
InspectorNetworkAgent::Create(inspected_frames_.Get());
network_agents_.Set(session_id, network_agent);
session->Append(network_agent);
InspectorCSSAgent* css_agent = InspectorCSSAgent::Create(
dom_agent, inspected_frames_.Get(), network_agent,
resource_content_loader_.Get(), resource_container_.Get());
session->Append(css_agent);
session->Append(InspectorDOMSnapshotAgent::Create(inspected_frames_.Get()));
session->Append(new InspectorAnimationAgent(inspected_frames_.Get(),
css_agent, session->V8Session()));
session->Append(InspectorMemoryAgent::Create());
session->Append(
InspectorApplicationCacheAgent::Create(inspected_frames_.Get()));
session->Append(new InspectorIndexedDBAgent(inspected_frames_.Get(),
session->V8Session()));
InspectorWorkerAgent* worker_agent =
new InspectorWorkerAgent(inspected_frames_.Get());
session->Append(worker_agent);
InspectorTracingAgent* tracing_agent = InspectorTracingAgent::Create(
this, worker_agent, inspected_frames_.Get());
tracing_agents_.Set(session_id, tracing_agent);
session->Append(tracing_agent);
session->Append(
new InspectorDOMDebuggerAgent(isolate, dom_agent, session->V8Session()));
session->Append(InspectorInputAgent::Create(inspected_frames_.Get()));
InspectorPageAgent* page_agent = InspectorPageAgent::Create(
inspected_frames_.Get(), this, resource_content_loader_.Get(),
session->V8Session());
page_agents_.Set(session_id, page_agent);
session->Append(page_agent);
session->Append(new InspectorLogAgent(
&inspected_frames_->Root()->GetPage()->GetConsoleMessageStorage(),
inspected_frames_->Root()->GetPerformanceMonitor()));
session->Append(new DeviceOrientationInspectorAgent(inspected_frames_.Get()));
InspectorOverlayAgent* overlay_agent =
new InspectorOverlayAgent(web_local_frame_impl_, inspected_frames_.Get(),
session->V8Session(), dom_agent);
overlay_agents_.Set(session_id, overlay_agent);
session->Append(overlay_agent);
tracing_agent->SetLayerTreeId(layer_tree_id_);
network_agent->SetHostId(host_id);
if (include_view_agents_) {
// TODO(dgozman): we should actually pass the view instead of frame, but
// during remote->local transition we cannot access mainFrameImpl() yet, so
// we have to store the frame which will become the main frame later.
session->Append(
InspectorEmulationAgent::Create(web_local_frame_impl_, this));
// TODO(dgozman): migrate each of the following agents to frame once module
// is ready.
Page* page = web_local_frame_impl_->ViewImpl()->GetPage();
session->Append(InspectorDatabaseAgent::Create(page));
session->Append(new InspectorAccessibilityAgent(page, dom_agent));
session->Append(InspectorDOMStorageAgent::Create(page));
session->Append(InspectorCacheStorageAgent::Create());
}
if (!sessions_.size())
Platform::Current()->CurrentThread()->AddTaskObserver(this);
sessions_.Set(session_id, session);
return session;
}
void WebDevToolsAgentImpl::DestroySession(int session_id) {
overlay_agents_.erase(session_id);
tracing_agents_.erase(session_id);
layer_tree_agents_.erase(session_id);
network_agents_.erase(session_id);
page_agents_.erase(session_id);
auto session_it = sessions_.find(session_id);
DCHECK(session_it != sessions_.end());
session_it->value->Dispose();
sessions_.erase(session_it);
if (!sessions_.size())
Platform::Current()->CurrentThread()->RemoveTaskObserver(this);
}
void WebDevToolsAgentImpl::Attach(const WebString& host_id, int session_id) {
if (!session_id || sessions_.find(session_id) != sessions_.end())
return;
InitializeSession(session_id, host_id, nullptr);
}
void WebDevToolsAgentImpl::Reattach(const WebString& host_id,
int session_id,
const WebString& saved_state) {
if (!session_id || sessions_.find(session_id) != sessions_.end())
return;
String state = saved_state;
InspectorSession* session = InitializeSession(session_id, host_id, &state);
session->Restore();
}
void WebDevToolsAgentImpl::Detach(int session_id) {
if (!session_id || sessions_.find(session_id) == sessions_.end())
return;
DestroySession(session_id);
}
void WebDevToolsAgentImpl::ContinueProgram() {
ClientMessageLoopAdapter::ContinueProgram();
}
void WebDevToolsAgentImpl::DidCommitLoadForLocalFrame(LocalFrame* frame) {
resource_container_->DidCommitLoadForLocalFrame(frame);
resource_content_loader_->DidCommitLoadForLocalFrame(frame);
for (auto& it : sessions_)
it.value->DidCommitLoadForLocalFrame(frame);
}
void WebDevToolsAgentImpl::DidStartProvisionalLoad(LocalFrame* frame) {
if (inspected_frames_->Root() == frame) {
for (auto& it : sessions_)
it.value->V8Session()->resume();
}
}
bool WebDevToolsAgentImpl::ScreencastEnabled() {
for (auto& it : page_agents_) {
if (it.value->ScreencastEnabled())
return true;
}
return false;
}
void WebDevToolsAgentImpl::WillAddPageOverlay(const GraphicsLayer* layer) {
for (auto& it : layer_tree_agents_)
it.value->WillAddPageOverlay(layer);
}
void WebDevToolsAgentImpl::DidRemovePageOverlay(const GraphicsLayer* layer) {
for (auto& it : layer_tree_agents_)
it.value->DidRemovePageOverlay(layer);
}
void WebDevToolsAgentImpl::RootLayerCleared() {
for (auto& it : tracing_agents_)
it.value->RootLayerCleared();
}
void WebDevToolsAgentImpl::LayerTreeViewChanged(
WebLayerTreeView* layer_tree_view) {
layer_tree_id_ = layer_tree_view ? layer_tree_view->LayerTreeId() : 0;
for (auto& it : tracing_agents_)
it.value->SetLayerTreeId(layer_tree_id_);
}
void WebDevToolsAgentImpl::EnableTracing(const String& category_filter) {
if (client_)
client_->EnableTracing(category_filter);
}
void WebDevToolsAgentImpl::DisableTracing() {
if (client_)
client_->DisableTracing();
}
void WebDevToolsAgentImpl::ShowReloadingBlanket() {
for (auto& it : overlay_agents_)
it.value->ShowReloadingBlanket();
}
void WebDevToolsAgentImpl::HideReloadingBlanket() {
for (auto& it : overlay_agents_)
it.value->HideReloadingBlanket();
}
void WebDevToolsAgentImpl::SetCPUThrottlingRate(double rate) {
if (client_)
client_->SetCPUThrottlingRate(rate);
}
void WebDevToolsAgentImpl::DispatchOnInspectorBackend(
int session_id,
int call_id,
const WebString& method,
const WebString& message) {
if (!Attached())
return;
if (WebDevToolsAgent::ShouldInterruptForMethod(method))
MainThreadDebugger::Instance()->TaskRunner()->RunAllTasksDontWait();
else
DispatchMessageFromFrontend(session_id, method, message);
}
void WebDevToolsAgentImpl::DispatchMessageFromFrontend(int session_id,
const String& method,
const String& message) {
if (!session_id)
return;
auto session_it = sessions_.find(session_id);
if (session_it == sessions_.end())
return;
InspectorTaskRunner::IgnoreInterruptsScope scope(
MainThreadDebugger::Instance()->TaskRunner());
session_it->value->DispatchProtocolMessage(method, message);
}
void WebDevToolsAgentImpl::InspectElementAt(
int session_id,
const WebPoint& point_in_root_frame) {
if (!session_id)
return;
auto agent_it = overlay_agents_.find(session_id);
if (agent_it == overlay_agents_.end())
return;
HitTestRequest::HitTestRequestType hit_type =
HitTestRequest::kMove | HitTestRequest::kReadOnly |
HitTestRequest::kAllowChildFrameContent;
HitTestRequest request(hit_type);
WebMouseEvent dummy_event(WebInputEvent::kMouseDown,
WebInputEvent::kNoModifiers,
WTF::MonotonicallyIncreasingTimeMS());
dummy_event.SetPositionInWidget(point_in_root_frame.x, point_in_root_frame.y);
IntPoint transformed_point = FlooredIntPoint(
TransformWebMouseEvent(web_local_frame_impl_->GetFrameView(), dummy_event)
.PositionInRootFrame());
HitTestResult result(
request, web_local_frame_impl_->GetFrameView()->RootFrameToContents(
transformed_point));
web_local_frame_impl_->GetFrame()->ContentLayoutItem().HitTest(result);
Node* node = result.InnerNode();
if (!node && web_local_frame_impl_->GetFrame()->GetDocument())
node = web_local_frame_impl_->GetFrame()->GetDocument()->documentElement();
agent_it->value->Inspect(node);
}
void WebDevToolsAgentImpl::FailedToRequestDevTools() {
ClientMessageLoopAdapter::ResumeForCreateWindow();
}
void WebDevToolsAgentImpl::SendProtocolMessage(int session_id,
int call_id,
const String& response,
const String& state) {
DCHECK(Attached());
if (client_)
client_->SendProtocolMessage(session_id, call_id, response, state);
}
void WebDevToolsAgentImpl::PageLayoutInvalidated(bool resized) {
for (auto& it : overlay_agents_)
it.value->PageLayoutInvalidated(resized);
}
void WebDevToolsAgentImpl::WaitForCreateWindow(LocalFrame* frame) {
if (!Attached())
return;
if (client_ &&
client_->RequestDevToolsForFrame(WebLocalFrameBase::FromFrame(frame)))
ClientMessageLoopAdapter::PauseForCreateWindow(web_local_frame_impl_);
}
WebString WebDevToolsAgentImpl::EvaluateInWebInspectorOverlay(
const WebString& script) {
WebString result;
for (auto& it : overlay_agents_)
result = it.value->EvaluateInOverlayForTest(script);
return result;
}
void WebDevToolsAgentImpl::PaintOverlay() {
for (auto& it : overlay_agents_)
it.value->PaintOverlay();
}
void WebDevToolsAgentImpl::LayoutOverlay() {
for (auto& it : overlay_agents_)
it.value->LayoutOverlay();
}
bool WebDevToolsAgentImpl::HandleInputEvent(const WebInputEvent& event) {
for (auto& it : overlay_agents_) {
if (it.value->HandleInputEvent(event))
return true;
}
return false;
}
bool WebDevToolsAgentImpl::CacheDisabled() {
for (auto& it : network_agents_) {
if (it.value->CacheDisabled())
return true;
}
return false;
}
void WebDevToolsAgentImpl::FlushProtocolNotifications() {
for (auto& it : sessions_)
it.value->flushProtocolNotifications();
}
void WebDevToolsAgentImpl::WillProcessTask() {
if (!Attached())
return;
ThreadDebugger::IdleFinished(V8PerIsolateData::MainThreadIsolate());
}
void WebDevToolsAgentImpl::DidProcessTask() {
if (!Attached())
return;
ThreadDebugger::IdleStarted(V8PerIsolateData::MainThreadIsolate());
FlushProtocolNotifications();
}
void WebDevToolsAgentImpl::RunDebuggerTask(
int session_id,
std::unique_ptr<WebDevToolsAgent::MessageDescriptor> descriptor) {
WebDevToolsAgent* webagent = descriptor->Agent();
if (!webagent)
return;
WebDevToolsAgentImpl* agent_impl =
static_cast<WebDevToolsAgentImpl*>(webagent);
if (agent_impl->Attached())
agent_impl->DispatchMessageFromFrontend(session_id, descriptor->Method(),
descriptor->Message());
}
void WebDevToolsAgent::InterruptAndDispatch(int session_id,
MessageDescriptor* raw_descriptor) {
// rawDescriptor can't be a std::unique_ptr because interruptAndDispatch is a
// WebKit API function.
MainThreadDebugger::InterruptMainThreadAndRun(
CrossThreadBind(WebDevToolsAgentImpl::RunDebuggerTask, session_id,
WTF::Passed(WTF::WrapUnique(raw_descriptor))));
}
bool WebDevToolsAgent::ShouldInterruptForMethod(const WebString& method) {
return method == "Debugger.pause" || method == "Debugger.setBreakpoint" ||
method == "Debugger.setBreakpointByUrl" ||
method == "Debugger.removeBreakpoint" ||
method == "Debugger.setBreakpointsActive";
}
} // namespace blink