Index: third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp |
diff --git a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp |
index 6e8d06fd799194b31fe90c23cb3e2487e8e493b8..5ba98053d559fc5cf55d204f85166632be4a2796 100644 |
--- a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp |
+++ b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp |
@@ -9,6 +9,9 @@ |
#include "bindings/core/v8/V8Binding.h" |
#include "bindings/core/v8/V8DOMException.h" |
#include "bindings/core/v8/V8DOMTokenList.h" |
+#include "bindings/core/v8/V8Event.h" |
+#include "bindings/core/v8/V8EventListener.h" |
+#include "bindings/core/v8/V8EventListenerList.h" |
#include "bindings/core/v8/V8HTMLAllCollection.h" |
#include "bindings/core/v8/V8HTMLCollection.h" |
#include "bindings/core/v8/V8Node.h" |
@@ -117,6 +120,150 @@ bool ThreadDebugger::isInspectableHeapObject(v8::Local<v8::Object> object) |
return true; |
} |
+static void returnDataCallback(const v8::FunctionCallbackInfo<v8::Value>& info) |
+{ |
+ info.GetReturnValue().Set(info.Data()); |
+} |
+ |
+void ThreadDebugger::createFunctionProperty(v8::Local<v8::Context> context, v8::Local<v8::Object> object, const char* name, v8::FunctionCallback callback, const char* description) |
+{ |
+ v8::Local<v8::String> funcName = v8String(context->GetIsolate(), name); |
+ v8::Local<v8::Function> func; |
+ if (!v8::Function::New(context, callback, v8::External::New(context->GetIsolate(), this)).ToLocal(&func)) |
+ return; |
+ func->SetName(funcName); |
+ v8::Local<v8::String> returnValue = v8String(context->GetIsolate(), description); |
+ v8::Local<v8::Function> toStringFunction; |
+ if (v8::Function::New(context, returnDataCallback, returnValue).ToLocal(&toStringFunction)) |
+ func->Set(v8String(context->GetIsolate(), "toString"), toStringFunction); |
+ if (!object->Set(context, funcName, func).FromMaybe(false)) |
+ return; |
+} |
+ |
+bool ThreadDebugger::isCommandLineAPIMethod(const String& name) |
+{ |
+ DEFINE_STATIC_LOCAL(HashSet<String>, methods, ()); |
+ if (methods.size() == 0) { |
+ const char* members[] = { "monitorEvents", "unmonitorEvents" }; |
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(members); ++i) |
+ methods.add(members[i]); |
+ } |
+ return methods.find(name) != methods.end() || V8Debugger::isCommandLineAPIMethod(name); |
+} |
+ |
+void ThreadDebugger::installAdditionalCommandLineAPI(v8::Local<v8::Context> context, v8::Local<v8::Object> object) |
+{ |
+ createFunctionProperty(context, object, "monitorEvents", ThreadDebugger::monitorEventsCallback, "function monitorEvents(object, [types]) { [Command Line API] }"); |
+ createFunctionProperty(context, object, "unmonitorEvents", ThreadDebugger::unmonitorEventsCallback, "function unmonitorEvents(object, [types]) { [Command Line API] }"); |
+} |
+ |
+static Vector<String> normalizeEventTypes(const v8::FunctionCallbackInfo<v8::Value>& info) |
+{ |
+ Vector<String> types; |
+ if (info.Length() > 1 && info[1]->IsString()) |
+ types.append(toCoreString(info[1].As<v8::String>())); |
+ if (info.Length() > 1 && info[1]->IsArray()) { |
+ v8::Local<v8::Array> typesArray = v8::Local<v8::Array>::Cast(info[1]); |
+ for (size_t i = 0; i < typesArray->Length(); ++i) { |
+ v8::Local<v8::Value> typeValue; |
+ if (!typesArray->Get(info.GetIsolate()->GetCurrentContext(), i).ToLocal(&typeValue) || !typeValue->IsString()) |
+ continue; |
+ types.append(toCoreString(v8::Local<v8::String>::Cast(typeValue))); |
+ } |
+ } |
+ if (info.Length() == 1) |
+ types.appendVector(Vector<String>({ "mouse", "key", "touch", "pointer", "control", "load", "unload", "abort", "error", "select", "input", "change", "submit", "reset", "focus", "blur", "resize", "scroll", "search", "devicemotion", "deviceorientation" })); |
+ |
+ Vector<String> outputTypes; |
+ for (size_t i = 0; i < types.size(); ++i) { |
+ if (types[i] == "mouse") |
+ outputTypes.appendVector(Vector<String>({ "click", "dblclick", "mousedown", "mouseeenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup", "mouseleave", "mousewheel" })); |
+ else if (types[i] == "key") |
+ outputTypes.appendVector(Vector<String>({ "keydown", "keyup", "keypress", "textInput" })); |
+ else if (types[i] == "touch") |
+ outputTypes.appendVector(Vector<String>({ "touchstart", "touchmove", "touchend", "touchcancel" })); |
+ else if (types[i] == "pointer") |
+ outputTypes.appendVector(Vector<String>({ "pointerover", "pointerout", "pointerenter", "pointerleave", "pointerdown", "pointerup", "pointermove", "pointercancel", "gotpointercapture", "lostpointercapture" })); |
+ else if (types[i] == "control") |
+ outputTypes.appendVector(Vector<String>({ "resize", "scroll", "zoom", "focus", "blur", "select", "input", "change", "submit", "reset" })); |
+ else |
+ outputTypes.append(types[i]); |
+ } |
+ return outputTypes; |
+} |
+ |
+void ThreadDebugger::logCallback(const v8::FunctionCallbackInfo<v8::Value>& info) |
+{ |
+ if (info.Length() < 1) |
+ return; |
+ ThreadDebugger* debugger = static_cast<ThreadDebugger*>(v8::Local<v8::External>::Cast(info.Data())->Value()); |
+ DCHECK(debugger); |
+ Event* event = V8Event::toImplWithTypeCheck(info.GetIsolate(), info[0]); |
+ if (!event) |
+ return; |
+ |
+ v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); |
+ ScriptState* scriptState = ScriptState::from(context); |
+ DCHECK(scriptState->contextIsValid()); |
+ Vector<ScriptValue> arguments = Vector<ScriptValue>({ |
+ ScriptValue(scriptState, v8String(info.GetIsolate(), event->type())), |
+ ScriptValue(scriptState, info[0]) |
+ }); |
+ |
+ ConsoleMessage* consoleMessage = ConsoleMessage::create(ConsoleAPIMessageSource, LogMessageLevel, event->type()); |
+ consoleMessage->setType(LogMessageType); |
+ consoleMessage->setScriptState(scriptState); |
+ consoleMessage->setScriptArguments(ScriptArguments::create(scriptState, arguments)); |
+ debugger->reportMessageToConsole(context, consoleMessage); |
+} |
+ |
+v8::Local<v8::Function> ThreadDebugger::eventLogFunction() |
+{ |
+ if (m_eventLogFunction.IsEmpty()) |
+ m_eventLogFunction.Reset(m_isolate, v8::Function::New(m_isolate, logCallback, v8::External::New(m_isolate, this))); |
+ return m_eventLogFunction.Get(m_isolate); |
+} |
+ |
+static EventTarget* firstArgumentAsEventTarget(const v8::FunctionCallbackInfo<v8::Value>& info) |
+{ |
+ if (info.Length() < 1) |
+ return nullptr; |
+ if (EventTarget* target = V8EventTarget::toImplWithTypeCheck(info.GetIsolate(), info[0])) |
+ return target; |
+ return toDOMWindow(info.GetIsolate(), info[0]); |
+} |
+ |
+void ThreadDebugger::setMonitorEventsCallback(const v8::FunctionCallbackInfo<v8::Value>& info, bool enabled) |
+{ |
+ EventTarget* eventTarget = firstArgumentAsEventTarget(info); |
+ if (!eventTarget) |
+ return; |
+ Vector<String> types = normalizeEventTypes(info); |
+ ThreadDebugger* debugger = static_cast<ThreadDebugger*>(v8::Local<v8::External>::Cast(info.Data())->Value()); |
+ DCHECK(debugger); |
+ EventListener* eventListener = V8EventListenerList::getEventListener(ScriptState::current(info.GetIsolate()), debugger->eventLogFunction(), false, enabled ? ListenerFindOrCreate : ListenerFindOnly); |
+ if (!eventListener) |
+ return; |
+ for (size_t i = 0; i < types.size(); ++i) { |
+ if (enabled) |
+ eventTarget->addEventListener(AtomicString(types[i]), eventListener, false); |
+ else |
+ eventTarget->removeEventListener(AtomicString(types[i]), eventListener, false); |
+ } |
+} |
+ |
+// static |
+void ThreadDebugger::monitorEventsCallback(const v8::FunctionCallbackInfo<v8::Value>& info) |
+{ |
+ setMonitorEventsCallback(info, true); |
+} |
+ |
+// static |
+void ThreadDebugger::unmonitorEventsCallback(const v8::FunctionCallbackInfo<v8::Value>& info) |
+{ |
+ setMonitorEventsCallback(info, false); |
+} |
+ |
void ThreadDebugger::reportMessageToConsole(v8::Local<v8::Context> context, MessageType type, MessageLevel level, const String16& message, const v8::FunctionCallbackInfo<v8::Value>* arguments, unsigned skipArgumentCount) |
{ |
ScriptState* scriptState = ScriptState::from(context); |