Wire up more of the DebuggerAgent

The debugger can now correctly break on exceptions
and show the corresponding line in the inspector.

It correctly understands which scripts are internal
to sky and does not pause during them.

There is still a ton to make work here
(including stacktraces which I have not tested),
but basic functionality seems to work.

The current implementation is not smart enough to
unpause the inspector when the frontend disconnects.

BUG=434510,434513
R=abarth@chromium.org

Review URL: https://codereview.chromium.org/727593004
This commit is contained in:
Eric Seidel 2014-11-18 15:05:05 -08:00
parent 39fb57b20b
commit 593c8f8de3
64 changed files with 9035 additions and 32 deletions

View File

@ -0,0 +1,548 @@
/*
* Copyright (C) 2010 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.
*/
(function () {
var DebuggerScript = {};
DebuggerScript.PauseOnExceptionsState = {
DontPauseOnExceptions: 0,
PauseOnAllExceptions: 1,
PauseOnUncaughtExceptions: 2
};
DebuggerScript.ScopeInfoDetails = {
AllScopes: 0,
FastAsyncScopes: 1,
NoScopes: 2
};
DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.DontPauseOnExceptions;
Debug.clearBreakOnException();
Debug.clearBreakOnUncaughtException();
DebuggerScript.getAfterCompileScript = function(eventData)
{
return DebuggerScript._formatScript(eventData.script_.script_);
}
DebuggerScript.getWorkerScripts = function()
{
var result = [];
var scripts = Debug.scripts();
for (var i = 0; i < scripts.length; ++i) {
var script = scripts[i];
// Workers don't share same V8 heap now so there is no need to complicate stuff with
// the context id like we do to discriminate between scripts from different pages.
// However we need to filter out v8 native scripts.
if (script.context_data && script.context_data === "worker")
result.push(DebuggerScript._formatScript(script));
}
return result;
}
DebuggerScript.getFunctionScopes = function(fun)
{
var mirror = MakeMirror(fun);
var count = mirror.scopeCount();
if (count == 0)
return null;
var result = [];
for (var i = 0; i < count; i++) {
var scopeDetails = mirror.scope(i).details();
result[i] = {
type: scopeDetails.type(),
object: DebuggerScript._buildScopeObject(scopeDetails.type(), scopeDetails.object())
};
}
return result;
}
DebuggerScript.getCollectionEntries = function(object)
{
var mirror = MakeMirror(object, true /* transient */);
if (mirror.isMap())
return mirror.entries();
if (mirror.isSet()) {
var result = [];
var values = mirror.values();
for (var i = 0; i < values.length; ++i)
result.push({ value: values[i] });
return result;
}
}
DebuggerScript.getInternalProperties = function(value)
{
var properties = ObjectMirror.GetInternalProperties(value);
var result = [];
for (var i = 0; i < properties.length; i++) {
var mirror = properties[i];
result.push({
name: mirror.name(),
value: mirror.value().value()
});
}
return result;
}
DebuggerScript.setFunctionVariableValue = function(functionValue, scopeIndex, variableName, newValue)
{
var mirror = MakeMirror(functionValue);
if (!mirror.isFunction())
throw new Error("Function value has incorrect type");
return DebuggerScript._setScopeVariableValue(mirror, scopeIndex, variableName, newValue);
}
DebuggerScript._setScopeVariableValue = function(scopeHolder, scopeIndex, variableName, newValue)
{
var scopeMirror = scopeHolder.scope(scopeIndex);
if (!scopeMirror)
throw new Error("Incorrect scope index");
scopeMirror.setVariableValue(variableName, newValue);
return undefined;
}
DebuggerScript.getScripts = function(contextData)
{
var result = [];
if (!contextData)
return result;
var comma = contextData.indexOf(",");
if (comma === -1)
return result;
// Context data is a string in the following format:
// ("page"|"injected")","<page id>
var idSuffix = contextData.substring(comma); // including the comma
var scripts = Debug.scripts();
for (var i = 0; i < scripts.length; ++i) {
var script = scripts[i];
if (script.context_data && script.context_data.lastIndexOf(idSuffix) != -1)
result.push(DebuggerScript._formatScript(script));
}
return result;
}
DebuggerScript._formatScript = function(script)
{
var lineEnds = script.line_ends;
var lineCount = lineEnds.length;
var endLine = script.line_offset + lineCount - 1;
var endColumn;
// V8 will not count last line if script source ends with \n.
if (script.source[script.source.length - 1] === '\n') {
endLine += 1;
endColumn = 0;
} else {
if (lineCount === 1)
endColumn = script.source.length + script.column_offset;
else
endColumn = script.source.length - (lineEnds[lineCount - 2] + 1);
}
return {
id: script.id,
name: script.nameOrSourceURL(),
sourceURL: script.source_url,
sourceMappingURL: script.source_mapping_url,
source: script.source,
startLine: script.line_offset,
startColumn: script.column_offset,
endLine: endLine,
endColumn: endColumn,
isContentScript: !!script.context_data && script.context_data.indexOf("injected") == 0
};
}
DebuggerScript.setBreakpoint = function(execState, info)
{
var positionAlignment = info.interstatementLocation ? Debug.BreakPositionAlignment.BreakPosition : Debug.BreakPositionAlignment.Statement;
var breakId = Debug.setScriptBreakPointById(info.sourceID, info.lineNumber, info.columnNumber, info.condition, undefined, positionAlignment);
var locations = Debug.findBreakPointActualLocations(breakId);
if (!locations.length)
return undefined;
info.lineNumber = locations[0].line;
info.columnNumber = locations[0].column;
return breakId.toString();
}
DebuggerScript.removeBreakpoint = function(execState, info)
{
Debug.findBreakPoint(info.breakpointId, true);
}
DebuggerScript.pauseOnExceptionsState = function()
{
return DebuggerScript._pauseOnExceptionsState;
}
DebuggerScript.setPauseOnExceptionsState = function(newState)
{
DebuggerScript._pauseOnExceptionsState = newState;
if (DebuggerScript.PauseOnExceptionsState.PauseOnAllExceptions === newState)
Debug.setBreakOnException();
else
Debug.clearBreakOnException();
if (DebuggerScript.PauseOnExceptionsState.PauseOnUncaughtExceptions === newState)
Debug.setBreakOnUncaughtException();
else
Debug.clearBreakOnUncaughtException();
}
DebuggerScript.frameCount = function(execState)
{
return execState.frameCount();
}
DebuggerScript.currentCallFrame = function(execState, data)
{
var maximumLimit = data >> 2;
var scopeDetailsLevel = data & 3;
var frameCount = execState.frameCount();
if (maximumLimit && maximumLimit < frameCount)
frameCount = maximumLimit;
var topFrame = undefined;
for (var i = frameCount - 1; i >= 0; i--) {
var frameMirror = execState.frame(i);
topFrame = DebuggerScript._frameMirrorToJSCallFrame(frameMirror, topFrame, scopeDetailsLevel);
}
return topFrame;
}
DebuggerScript.currentCallFrameByIndex = function(execState, index)
{
if (index < 0)
return undefined;
var frameCount = execState.frameCount();
if (index >= frameCount)
return undefined;
return DebuggerScript._frameMirrorToJSCallFrame(execState.frame(index), undefined, DebuggerScript.ScopeInfoDetails.NoScopes);
}
DebuggerScript.stepIntoStatement = function(execState)
{
execState.prepareStep(Debug.StepAction.StepIn, 1);
}
DebuggerScript.stepOverStatement = function(execState, callFrame)
{
execState.prepareStep(Debug.StepAction.StepNext, 1);
}
DebuggerScript.stepOutOfFunction = function(execState, callFrame)
{
execState.prepareStep(Debug.StepAction.StepOut, 1);
}
// Returns array in form:
// [ 0, <v8_result_report> ] in case of success
// or [ 1, <general_error_message>, <compiler_message>, <line_number>, <column_number> ] in case of compile error, numbers are 1-based.
// or throws exception with message.
DebuggerScript.liveEditScriptSource = function(scriptId, newSource, preview)
{
var scripts = Debug.scripts();
var scriptToEdit = null;
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].id == scriptId) {
scriptToEdit = scripts[i];
break;
}
}
if (!scriptToEdit)
throw("Script not found");
var changeLog = [];
try {
var result = Debug.LiveEdit.SetScriptSource(scriptToEdit, newSource, preview, changeLog);
return [0, result];
} catch (e) {
if (e instanceof Debug.LiveEdit.Failure && "details" in e) {
var details = e.details;
if (details.type === "liveedit_compile_error") {
var startPosition = details.position.start;
return [1, String(e), String(details.syntaxErrorMessage), Number(startPosition.line), Number(startPosition.column)];
}
}
throw e;
}
}
DebuggerScript.clearBreakpoints = function(execState, info)
{
Debug.clearAllBreakPoints();
}
DebuggerScript.setBreakpointsActivated = function(execState, info)
{
Debug.debuggerFlags().breakPointsActive.setValue(info.enabled);
}
DebuggerScript.getScriptSource = function(eventData)
{
return eventData.script().source();
}
DebuggerScript.setScriptSource = function(eventData, source)
{
if (eventData.script().data() === "injected-script")
return;
eventData.script().setSource(source);
}
DebuggerScript.getScriptName = function(eventData)
{
return eventData.script().script_.nameOrSourceURL();
}
DebuggerScript.getBreakpointNumbers = function(eventData)
{
var breakpoints = eventData.breakPointsHit();
var numbers = [];
if (!breakpoints)
return numbers;
for (var i = 0; i < breakpoints.length; i++) {
var breakpoint = breakpoints[i];
var scriptBreakPoint = breakpoint.script_break_point();
numbers.push(scriptBreakPoint ? scriptBreakPoint.number() : breakpoint.number());
}
return numbers;
}
DebuggerScript.isEvalCompilation = function(eventData)
{
var script = eventData.script();
return (script.compilationType() === Debug.ScriptCompilationType.Eval);
}
// NOTE: This function is performance critical, as it can be run on every
// statement that generates an async event (like addEventListener) to support
// asynchronous call stacks. Thus, when possible, initialize the data lazily.
DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame, scopeDetailsLevel)
{
// Stuff that can not be initialized lazily (i.e. valid while paused with a valid break_id).
// The frameMirror and scopeMirror can be accessed only while paused on the debugger.
var frameDetails = frameMirror.details();
var funcObject = frameDetails.func();
var sourcePosition = frameDetails.sourcePosition();
var thisObject = frameDetails.receiver();
var isAtReturn = !!frameDetails.isAtReturn();
var returnValue = isAtReturn ? frameDetails.returnValue() : undefined;
var scopeMirrors = (scopeDetailsLevel === DebuggerScript.ScopeInfoDetails.NoScopes ? [] : frameMirror.allScopes(scopeDetailsLevel === DebuggerScript.ScopeInfoDetails.FastAsyncScopes));
var scopeTypes = new Array(scopeMirrors.length);
var scopeObjects = new Array(scopeMirrors.length);
for (var i = 0; i < scopeMirrors.length; ++i) {
var scopeDetails = scopeMirrors[i].details();
scopeTypes[i] = scopeDetails.type();
scopeObjects[i] = scopeDetails.object();
}
// Calculated lazily.
var scopeChain;
var funcMirror;
var location;
function lazyScopeChain()
{
if (!scopeChain) {
scopeChain = [];
for (var i = 0; i < scopeObjects.length; ++i)
scopeChain.push(DebuggerScript._buildScopeObject(scopeTypes[i], scopeObjects[i]));
scopeObjects = null; // Free for GC.
}
return scopeChain;
}
function ensureFuncMirror()
{
if (!funcMirror) {
funcMirror = MakeMirror(funcObject);
if (!funcMirror.isFunction())
funcMirror = new UnresolvedFunctionMirror(funcObject);
}
return funcMirror;
}
function ensureLocation()
{
if (!location) {
var script = ensureFuncMirror().script();
if (script)
location = script.locationFromPosition(sourcePosition, true);
if (!location)
location = { line: 0, column: 0 };
}
return location;
}
function line()
{
return ensureLocation().line;
}
function column()
{
return ensureLocation().column;
}
function sourceID()
{
var script = ensureFuncMirror().script();
return script && script.id();
}
function scriptName()
{
var script = ensureFuncMirror().script();
return script && script.name();
}
function functionName()
{
var func = ensureFuncMirror();
if (!func.resolved())
return undefined;
var displayName;
var valueMirror = func.property("displayName").value();
if (valueMirror && valueMirror.isString())
displayName = valueMirror.value();
return displayName || func.name() || func.inferredName();
}
function evaluate(expression)
{
return frameMirror.evaluate(expression, false).value();
}
function restart()
{
return Debug.LiveEdit.RestartFrame(frameMirror);
}
function setVariableValue(scopeNumber, variableName, newValue)
{
return DebuggerScript._setScopeVariableValue(frameMirror, scopeNumber, variableName, newValue);
}
function stepInPositions()
{
var stepInPositionsV8 = frameMirror.stepInPositions();
var stepInPositionsProtocol;
if (stepInPositionsV8) {
stepInPositionsProtocol = [];
var script = ensureFuncMirror().script();
if (script) {
var scriptId = String(script.id());
for (var i = 0; i < stepInPositionsV8.length; i++) {
var item = {
scriptId: scriptId,
lineNumber: stepInPositionsV8[i].position.line,
columnNumber: stepInPositionsV8[i].position.column
};
stepInPositionsProtocol.push(item);
}
}
}
return JSON.stringify(stepInPositionsProtocol);
}
return {
"sourceID": sourceID,
"line": line,
"column": column,
"scriptName": scriptName,
"functionName": functionName,
"thisObject": thisObject,
"scopeChain": lazyScopeChain,
"scopeType": scopeTypes,
"evaluate": evaluate,
"caller": callerFrame,
"restart": restart,
"setVariableValue": setVariableValue,
"stepInPositions": stepInPositions,
"isAtReturn": isAtReturn,
"returnValue": returnValue
};
}
DebuggerScript._buildScopeObject = function(scopeType, scopeObject)
{
var result;
switch (scopeType) {
case ScopeType.Local:
case ScopeType.Closure:
case ScopeType.Catch:
// For transient objects we create a "persistent" copy that contains
// the same properties.
// Reset scope object prototype to null so that the proto properties
// don't appear in the local scope section.
result = { __proto__: null };
var properties = MakeMirror(scopeObject, true /* transient */).properties();
for (var j = 0; j < properties.length; j++) {
var name = properties[j].name();
if (name.charAt(0) === ".")
continue; // Skip internal variables like ".arguments"
result[name] = properties[j].value_;
}
break;
case ScopeType.Global:
case ScopeType.With:
result = scopeObject;
break;
case ScopeType.Block:
// Unsupported yet. Mustn't be reachable.
break;
}
return result;
}
DebuggerScript.getPromiseDetails = function(eventData)
{
return {
"promise": eventData.promise().value(),
"parentPromise": eventData.parentPromise().value(),
"status": eventData.status()
};
}
// We never resolve Mirror by its handle so to avoid memory leaks caused by Mirrors in the cache we disable it.
ToggleMirrorCache(false);
return DebuggerScript;
})();

View File

@ -0,0 +1,325 @@
/*
* Copyright (c) 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 "config.h"
#include "bindings/core/v8/PageScriptDebugServer.h"
#include "bindings/core/v8/DOMWrapperWorld.h"
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptSourceCode.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "bindings/core/v8/V8Window.h"
#include "bindings/core/v8/WindowProxy.h"
#include "core/dom/ExecutionContext.h"
#include "core/frame/FrameConsole.h"
#include "core/frame/FrameHost.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/UseCounter.h"
#include "core/inspector/InspectorTraceEvents.h"
#include "core/inspector/ScriptDebugListener.h"
#include "core/page/Page.h"
#include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/StdLibExtras.h"
#include "wtf/TemporaryChange.h"
#include "wtf/text/StringBuilder.h"
#include "gin/modules/console.h"
#include "gin/converter.h"
namespace blink {
static LocalFrame* retrieveFrameWithGlobalObjectCheck(v8::Handle<v8::Context> context)
{
if (context.IsEmpty())
return 0;
// FIXME: This is a temporary hack for crbug.com/345014.
// Currently it's possible that V8 can trigger Debugger::ProcessDebugEvent for a context
// that is being initialized (i.e., inside Context::New() of the context).
// We should fix the V8 side so that it won't trigger the event for a half-baked context
// because there is no way in the embedder side to check if the context is half-baked or not.
if (isMainThread() && DOMWrapperWorld::windowIsBeingInitialized())
return 0;
v8::Handle<v8::Value> global = V8Window::findInstanceInPrototypeChain(context->Global(), context->GetIsolate());
if (global.IsEmpty())
return 0;
return toFrameIfNotDetached(context);
}
void PageScriptDebugServer::setPreprocessorSource(const String& preprocessorSource)
{
if (preprocessorSource.isEmpty())
m_preprocessorSourceCode.clear();
else
m_preprocessorSourceCode = adoptPtr(new ScriptSourceCode(preprocessorSource));
m_scriptPreprocessor.clear();
}
PageScriptDebugServer& PageScriptDebugServer::shared()
{
DEFINE_STATIC_LOCAL(PageScriptDebugServer, server, ());
return server;
}
v8::Isolate* PageScriptDebugServer::s_mainThreadIsolate = 0;
void PageScriptDebugServer::setMainThreadIsolate(v8::Isolate* isolate)
{
s_mainThreadIsolate = isolate;
}
PageScriptDebugServer::PageScriptDebugServer()
: ScriptDebugServer(s_mainThreadIsolate)
, m_pausedPage(0)
{
}
PageScriptDebugServer::~PageScriptDebugServer()
{
}
void PageScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page)
{
ScriptController& scriptController = page->mainFrame()->script();
v8::HandleScope scope(m_isolate);
if (!m_listenersMap.size()) {
v8::Debug::SetDebugEventListener(&PageScriptDebugServer::v8DebugEventCallback, v8::External::New(m_isolate, this));
ensureDebuggerScriptCompiled();
}
v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
v8::Context::Scope contextScope(debuggerContext);
v8::Local<v8::Value> console = gin::Console::GetModule(m_isolate);
debuggerContext->Global()->Set(gin::StringToV8(m_isolate, "console"), console);
v8::Local<v8::Object> debuggerScript = m_debuggerScript.newLocal(m_isolate);
ASSERT(!debuggerScript->IsUndefined());
m_listenersMap.set(page, listener);
WindowProxy* windowProxy = scriptController.existingWindowProxy(DOMWrapperWorld::mainWorld());
if (!windowProxy || !windowProxy->isContextInitialized())
return;
v8::Local<v8::Context> context = windowProxy->context();
v8::Handle<v8::Function> getScriptsFunction = v8::Local<v8::Function>::Cast(debuggerScript->Get(v8AtomicString(m_isolate, "getScripts")));
v8::Handle<v8::Value> argv[] = { context->GetEmbedderData(0) };
v8::Handle<v8::Value> value = V8ScriptRunner::callInternalFunction(getScriptsFunction, debuggerScript, WTF_ARRAY_LENGTH(argv), argv, m_isolate);
if (value.IsEmpty())
return;
ASSERT(!value->IsUndefined() && value->IsArray());
v8::Handle<v8::Array> scriptsArray = v8::Handle<v8::Array>::Cast(value);
for (unsigned i = 0; i < scriptsArray->Length(); ++i)
dispatchDidParseSource(listener, v8::Handle<v8::Object>::Cast(scriptsArray->Get(v8::Integer::New(m_isolate, i))), CompileSuccess);
}
void PageScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page)
{
if (!m_listenersMap.contains(page))
return;
if (m_pausedPage == page)
continueProgram();
m_listenersMap.remove(page);
if (m_listenersMap.isEmpty()) {
discardDebuggerScript();
v8::Debug::SetDebugEventListener(0);
// FIXME: Remove all breakpoints set by the agent.
}
}
void PageScriptDebugServer::interruptAndRun(PassOwnPtr<Task> task)
{
ScriptDebugServer::interruptAndRun(task, s_mainThreadIsolate);
}
void PageScriptDebugServer::setClientMessageLoop(PassOwnPtr<ClientMessageLoop> clientMessageLoop)
{
m_clientMessageLoop = clientMessageLoop;
}
void PageScriptDebugServer::compileScript(ScriptState* scriptState, const String& expression, const String& sourceURL, String* scriptId, String* exceptionDetailsText, int* lineNumber, int* columnNumber, RefPtr<ScriptCallStack>* stackTrace)
{
ExecutionContext* executionContext = scriptState->executionContext();
RefPtr<LocalFrame> protect = executionContext->executingWindow()->frame();
ScriptDebugServer::compileScript(scriptState, expression, sourceURL, scriptId, exceptionDetailsText, lineNumber, columnNumber, stackTrace);
if (!scriptId->isNull())
m_compiledScriptURLs.set(*scriptId, sourceURL);
}
void PageScriptDebugServer::clearCompiledScripts()
{
ScriptDebugServer::clearCompiledScripts();
m_compiledScriptURLs.clear();
}
void PageScriptDebugServer::runScript(ScriptState* scriptState, const String& scriptId, ScriptValue* result, bool* wasThrown, String* exceptionDetailsText, int* lineNumber, int* columnNumber, RefPtr<ScriptCallStack>* stackTrace)
{
String sourceURL = m_compiledScriptURLs.take(scriptId);
ExecutionContext* executionContext = scriptState->executionContext();
LocalFrame* frame = executionContext->executingWindow()->frame();
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "EvaluateScript", "data", InspectorEvaluateScriptEvent::data(frame, sourceURL, TextPosition::minimumPosition().m_line.oneBasedInt()));
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", TRACE_EVENT_SCOPE_PROCESS, "stack", InspectorCallStackEvent::currentCallStack());
RefPtr<LocalFrame> protect = frame;
ScriptDebugServer::runScript(scriptState, scriptId, result, wasThrown, exceptionDetailsText, lineNumber, columnNumber, stackTrace);
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", TRACE_EVENT_SCOPE_PROCESS, "data", InspectorUpdateCountersEvent::data());
}
ScriptDebugListener* PageScriptDebugServer::getDebugListenerForContext(v8::Handle<v8::Context> context)
{
v8::HandleScope scope(m_isolate);
LocalFrame* frame = retrieveFrameWithGlobalObjectCheck(context);
if (!frame)
return 0;
return m_listenersMap.get(frame->page());
}
void PageScriptDebugServer::runMessageLoopOnPause(v8::Handle<v8::Context> context)
{
v8::HandleScope scope(m_isolate);
LocalFrame* frame = retrieveFrameWithGlobalObjectCheck(context);
m_pausedPage = frame->page();
// Wait for continue or step command.
m_clientMessageLoop->run(m_pausedPage);
// The listener may have been removed in the nested loop.
if (ScriptDebugListener* listener = m_listenersMap.get(m_pausedPage))
listener->didContinue();
m_pausedPage = 0;
}
void PageScriptDebugServer::quitMessageLoopOnPause()
{
m_clientMessageLoop->quitNow();
}
void PageScriptDebugServer::preprocessBeforeCompile(const v8::Debug::EventDetails& eventDetails)
{
v8::Handle<v8::Context> eventContext = eventDetails.GetEventContext();
LocalFrame* frame = retrieveFrameWithGlobalObjectCheck(eventContext);
if (!frame)
return;
if (!canPreprocess(frame))
return;
v8::Handle<v8::Object> eventData = eventDetails.GetEventData();
v8::Local<v8::Context> debugContext = v8::Debug::GetDebugContext();
v8::Context::Scope contextScope(debugContext);
v8::TryCatch tryCatch;
// <script> tag source and attribute value source are preprocessed before we enter V8.
// Avoid preprocessing any internal scripts by processing only eval source in this V8 event handler.
v8::Handle<v8::Value> argvEventData[] = { eventData };
v8::Handle<v8::Value> v8Value = callDebuggerMethod("isEvalCompilation", WTF_ARRAY_LENGTH(argvEventData), argvEventData);
if (v8Value.IsEmpty() || !v8Value->ToBoolean()->Value())
return;
// The name and source are in the JS event data.
String scriptName = toCoreStringWithUndefinedOrNullCheck(callDebuggerMethod("getScriptName", WTF_ARRAY_LENGTH(argvEventData), argvEventData));
String script = toCoreStringWithUndefinedOrNullCheck(callDebuggerMethod("getScriptSource", WTF_ARRAY_LENGTH(argvEventData), argvEventData));
String preprocessedSource = m_scriptPreprocessor->preprocessSourceCode(script, scriptName);
v8::Handle<v8::Value> argvPreprocessedScript[] = { eventData, v8String(debugContext->GetIsolate(), preprocessedSource) };
callDebuggerMethod("setScriptSource", WTF_ARRAY_LENGTH(argvPreprocessedScript), argvPreprocessedScript);
}
static bool isCreatingPreprocessor = false;
bool PageScriptDebugServer::canPreprocess(LocalFrame* frame)
{
ASSERT(frame);
if (!m_preprocessorSourceCode || !frame->page() || isCreatingPreprocessor)
return false;
// We delay the creation of the preprocessor until just before the first JS from the
// Web page to ensure that the debugger's console initialization code has completed.
if (!m_scriptPreprocessor) {
TemporaryChange<bool> isPreprocessing(isCreatingPreprocessor, true);
m_scriptPreprocessor = adoptPtr(new ScriptPreprocessor(*m_preprocessorSourceCode.get(), frame));
}
if (m_scriptPreprocessor->isValid())
return true;
m_scriptPreprocessor.clear();
// Don't retry the compile if we fail one time.
m_preprocessorSourceCode.clear();
return false;
}
// Source to Source processing iff debugger enabled and it has loaded a preprocessor.
PassOwnPtr<ScriptSourceCode> PageScriptDebugServer::preprocess(LocalFrame* frame, const ScriptSourceCode& sourceCode)
{
if (!canPreprocess(frame))
return PassOwnPtr<ScriptSourceCode>();
String preprocessedSource = m_scriptPreprocessor->preprocessSourceCode(sourceCode.source(), sourceCode.url());
return adoptPtr(new ScriptSourceCode(preprocessedSource, sourceCode.url()));
}
String PageScriptDebugServer::preprocessEventListener(LocalFrame* frame, const String& source, const String& url, const String& functionName)
{
if (!canPreprocess(frame))
return source;
return m_scriptPreprocessor->preprocessSourceCode(source, url, functionName);
}
void PageScriptDebugServer::clearPreprocessor()
{
m_scriptPreprocessor.clear();
}
void PageScriptDebugServer::muteWarningsAndDeprecations()
{
FrameConsole::mute();
UseCounter::muteForInspector();
}
void PageScriptDebugServer::unmuteWarningsAndDeprecations()
{
FrameConsole::unmute();
UseCounter::unmuteForInspector();
}
} // namespace blink

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 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.
*/
#ifndef PageScriptDebugServer_h
#define PageScriptDebugServer_h
#include "bindings/core/v8/ScriptDebugServer.h"
#include "bindings/core/v8/ScriptPreprocessor.h"
#include "wtf/Forward.h"
#include "wtf/RefCounted.h"
#include <v8.h>
namespace blink {
class Page;
class ScriptController;
class ScriptPreprocessor;
class ScriptSourceCode;
class PageScriptDebugServer final : public ScriptDebugServer {
WTF_MAKE_NONCOPYABLE(PageScriptDebugServer);
public:
static PageScriptDebugServer& shared();
static void setMainThreadIsolate(v8::Isolate*);
void addListener(ScriptDebugListener*, Page*);
void removeListener(ScriptDebugListener*, Page*);
static void interruptAndRun(PassOwnPtr<Task>);
class ClientMessageLoop {
public:
virtual ~ClientMessageLoop() { }
virtual void run(Page*) = 0;
virtual void quitNow() = 0;
};
void setClientMessageLoop(PassOwnPtr<ClientMessageLoop>);
virtual void compileScript(ScriptState*, const String& expression, const String& sourceURL, String* scriptId, String* exceptionDetailsText, int* lineNumber, int* columnNumber, RefPtr<ScriptCallStack>* stackTrace) override;
virtual void clearCompiledScripts() override;
virtual void runScript(ScriptState*, const String& scriptId, ScriptValue* result, bool* wasThrown, String* exceptionDetailsText, int* lineNumber, int* columnNumber, RefPtr<ScriptCallStack>* stackTrace) override;
virtual void setPreprocessorSource(const String&) override;
virtual void preprocessBeforeCompile(const v8::Debug::EventDetails&) override;
virtual PassOwnPtr<ScriptSourceCode> preprocess(LocalFrame*, const ScriptSourceCode&) override;
virtual String preprocessEventListener(LocalFrame*, const String& source, const String& url, const String& functionName) override;
virtual void clearPreprocessor() override;
virtual void muteWarningsAndDeprecations() override;
virtual void unmuteWarningsAndDeprecations() override;
private:
PageScriptDebugServer();
virtual ~PageScriptDebugServer();
virtual ScriptDebugListener* getDebugListenerForContext(v8::Handle<v8::Context>) override;
virtual void runMessageLoopOnPause(v8::Handle<v8::Context>) override;
virtual void quitMessageLoopOnPause() override;
typedef HashMap<Page*, ScriptDebugListener*> ListenersMap;
ListenersMap m_listenersMap;
OwnPtr<ClientMessageLoop> m_clientMessageLoop;
Page* m_pausedPage;
HashMap<String, String> m_compiledScriptURLs;
OwnPtr<ScriptSourceCode> m_preprocessorSourceCode;
OwnPtr<ScriptPreprocessor> m_scriptPreprocessor;
bool canPreprocess(LocalFrame*);
static v8::Isolate* s_mainThreadIsolate;
};
} // namespace blink
#endif // PageScriptDebugServer_h

View File

@ -580,7 +580,7 @@ void ScriptDebugServer::ensureDebuggerScriptCompiled()
v8::HandleScope scope(m_isolate);
v8::Context::Scope contextScope(v8::Debug::GetDebugContext());
const blink::WebData& debuggerScriptSourceResource = blink::Platform::current()->loadResource("DebuggerScriptSource.js");
const blink::WebData& debuggerScriptSourceResource = blink::Platform::current()->loadResource("DebuggerScript.js");
v8::Handle<v8::String> source = v8String(m_isolate, String(debuggerScriptSourceResource.data(), debuggerScriptSourceResource.size()));
v8::Local<v8::Value> value = V8ScriptRunner::compileAndRunInternalScript(source, m_isolate);
ASSERT(!value.IsEmpty());

View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 2004, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008 Collabora Ltd.
* Copyright (C) 2011 Peter Varga (pvarga@webkit.org), University of Szeged
* Copyright (C) 2013 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:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
#include "bindings/core/v8/ScriptRegexp.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8PerIsolateData.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "platform/ScriptForbiddenScope.h"
namespace blink {
ScriptRegexp::ScriptRegexp(const String& pattern, TextCaseSensitivity caseSensitivity, MultilineMode multilineMode)
{
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(V8PerIsolateData::from(isolate)->ensureScriptRegexpContext());
v8::TryCatch tryCatch;
unsigned flags = v8::RegExp::kNone;
if (caseSensitivity == TextCaseInsensitive)
flags |= v8::RegExp::kIgnoreCase;
if (multilineMode == MultilineEnabled)
flags |= v8::RegExp::kMultiline;
v8::Local<v8::RegExp> regex = v8::RegExp::New(v8String(isolate, pattern), static_cast<v8::RegExp::Flags>(flags));
// If the regex failed to compile we'll get an empty handle.
if (!regex.IsEmpty())
m_regex.set(isolate, regex);
}
int ScriptRegexp::match(const String& string, int startFrom, int* matchLength) const
{
if (matchLength)
*matchLength = 0;
if (m_regex.isEmpty() || string.isNull())
return -1;
// v8 strings are limited to int.
if (string.length() > INT_MAX)
return -1;
ScriptForbiddenScope::AllowUserAgentScript allowScript;
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
v8::Context::Scope contextScope(V8PerIsolateData::from(isolate)->ensureScriptRegexpContext());
v8::TryCatch tryCatch;
v8::Local<v8::RegExp> regex = m_regex.newLocal(isolate);
v8::Local<v8::Function> exec = regex->Get(v8AtomicString(isolate, "exec")).As<v8::Function>();
v8::Handle<v8::Value> argv[] = { v8String(isolate, string.substring(startFrom)) };
v8::Local<v8::Value> returnValue = V8ScriptRunner::callInternalFunction(exec, regex, WTF_ARRAY_LENGTH(argv), argv, isolate);
if (tryCatch.HasCaught())
return -1;
// RegExp#exec returns null if there's no match, otherwise it returns an
// Array of strings with the first being the whole match string and others
// being subgroups. The Array also has some random properties tacked on like
// "index" which is the offset of the match.
//
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec
ASSERT(!returnValue.IsEmpty());
if (!returnValue->IsArray())
return -1;
v8::Local<v8::Array> result = returnValue.As<v8::Array>();
int matchOffset = result->Get(v8AtomicString(isolate, "index"))->ToInt32()->Value();
if (matchLength) {
v8::Local<v8::String> match = result->Get(0).As<v8::String>();
*matchLength = match->Length();
}
return matchOffset + startFrom;
}
} // namespace blink

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2003, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2013 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:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
*/
#ifndef ScriptRegexp_h
#define ScriptRegexp_h
#include "bindings/core/v8/ScopedPersistent.h"
#include "wtf/Noncopyable.h"
#include "wtf/text/WTFString.h"
#include <v8.h>
namespace blink {
enum MultilineMode {
MultilineDisabled,
MultilineEnabled
};
class ScriptRegexp {
WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(ScriptRegexp);
public:
ScriptRegexp(const String&, TextCaseSensitivity, MultilineMode = MultilineDisabled);
int match(const String&, int startFrom = 0, int* matchLength = 0) const;
bool isValid() const { return !m_regex.isEmpty(); }
private:
ScopedPersistent<v8::RegExp> m_regex;
};
} // namespace blink
#endif // ScriptRegexp_h

View File

@ -86,6 +86,8 @@ V8PerIsolateData::V8PerIsolateData()
V8PerIsolateData::~V8PerIsolateData()
{
if (m_scriptRegexpScriptState)
m_scriptRegexpScriptState->disposePerContextData();
if (isMainThread())
mainThreadPerIsolateData = 0;
}
@ -156,6 +158,15 @@ void V8PerIsolateData::setDOMTemplate(void* domTemplateKey, v8::Handle<v8::Funct
currentDOMTemplateMap().add(domTemplateKey, v8::Eternal<v8::FunctionTemplate>(isolate(), v8::Local<v8::FunctionTemplate>(templ)));
}
v8::Local<v8::Context> V8PerIsolateData::ensureScriptRegexpContext()
{
if (!m_scriptRegexpScriptState) {
v8::Local<v8::Context> context(v8::Context::New(isolate()));
m_scriptRegexpScriptState = ScriptState::create(context, DOMWrapperWorld::create());
}
return m_scriptRegexpScriptState->context();
}
bool V8PerIsolateData::hasInstance(const WrapperTypeInfo* info, v8::Handle<v8::Value> value)
{
return hasInstance(info, value, m_domTemplateMapForMainWorld)

View File

@ -94,6 +94,8 @@ public:
bool hasInstance(const WrapperTypeInfo*, v8::Handle<v8::Value>);
v8::Handle<v8::Object> findInstanceInPrototypeChain(const WrapperTypeInfo*, v8::Handle<v8::Value>);
v8::Local<v8::Context> ensureScriptRegexpContext();
const char* previousSamplingState() const { return m_previousSamplingState; }
void setPreviousSamplingState(const char* name) { m_previousSamplingState = name; }
@ -113,6 +115,7 @@ private:
OwnPtr<StringCache> m_stringCache;
OwnPtr<V8HiddenValue> m_hiddenValue;
ScopedPersistent<v8::Value> m_liveRoot;
RefPtr<ScriptState> m_scriptRegexpScriptState;
const char* m_previousSamplingState;

View File

@ -0,0 +1,429 @@
/*
* Copyright (C) 2007-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 "config.h"
#include "bindings/core/v8/V8InjectedScriptHost.h"
#include "bindings/core/v8/BindingSecurity.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptDebugServer.h"
#include "bindings/core/v8/ScriptValue.h"
#include "bindings/core/v8/V8AbstractEventListener.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8DOMTokenList.h"
#include "bindings/core/v8/V8EventTarget.h"
#include "bindings/core/v8/V8Node.h"
#include "bindings/core/v8/V8NodeList.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "bindings/core/v8/custom/V8Float32ArrayCustom.h"
#include "bindings/core/v8/custom/V8Float64ArrayCustom.h"
#include "bindings/core/v8/custom/V8Int16ArrayCustom.h"
#include "bindings/core/v8/custom/V8Int32ArrayCustom.h"
#include "bindings/core/v8/custom/V8Int8ArrayCustom.h"
#include "bindings/core/v8/custom/V8Uint16ArrayCustom.h"
#include "bindings/core/v8/custom/V8Uint32ArrayCustom.h"
#include "bindings/core/v8/custom/V8Uint8ArrayCustom.h"
#include "bindings/core/v8/custom/V8Uint8ClampedArrayCustom.h"
#include "core/events/EventTarget.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/inspector/InjectedScript.h"
#include "core/inspector/InjectedScriptHost.h"
#include "core/inspector/JavaScriptCallFrame.h"
#include "platform/JSONValues.h"
namespace blink {
Node* InjectedScriptHost::scriptValueAsNode(ScriptState* scriptState, ScriptValue value)
{
ScriptState::Scope scope(scriptState);
if (!value.isObject() || value.isNull())
return 0;
return V8Node::toNative(v8::Handle<v8::Object>::Cast(value.v8Value()));
}
ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* scriptState, Node* node)
{
ScriptState::Scope scope(scriptState);
v8::Isolate* isolate = scriptState->isolate();
ExceptionState exceptionState(ExceptionState::ExecutionContext, "nodeAsScriptValue", "InjectedScriptHost", scriptState->context()->Global(), isolate);
return ScriptValue(scriptState, toV8(node, scriptState->context()->Global(), isolate));
}
void V8InjectedScriptHost::inspectedObjectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
if (info.Length() < 1)
return;
if (!info[0]->IsInt32()) {
V8ThrowException::throwTypeError("argument has to be an integer", info.GetIsolate());
return;
}
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
InjectedScriptHost::InspectableObject* object = host->inspectedObject(info[0]->ToInt32()->Value());
v8SetReturnValue(info, object->get(ScriptState::current(info.GetIsolate())).v8Value());
}
static v8::Handle<v8::String> functionDisplayName(v8::Handle<v8::Function> function)
{
v8::Handle<v8::Value> value = function->GetDisplayName();
if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length())
return v8::Handle<v8::String>::Cast(value);
value = function->GetName();
if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length())
return v8::Handle<v8::String>::Cast(value);
value = function->GetInferredName();
if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length())
return v8::Handle<v8::String>::Cast(value);
return v8::Handle<v8::String>();
}
void V8InjectedScriptHost::internalConstructorNameMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
if (info.Length() < 1 || !info[0]->IsObject())
return;
v8::Local<v8::Object> object = info[0]->ToObject();
v8::Local<v8::String> result = object->GetConstructorName();
if (!result.IsEmpty() && toCoreStringWithUndefinedOrNullCheck(result) == "Object") {
v8::Local<v8::String> constructorSymbol = v8AtomicString(info.GetIsolate(), "constructor");
if (object->HasRealNamedProperty(constructorSymbol) && !object->HasRealNamedCallbackProperty(constructorSymbol)) {
v8::TryCatch tryCatch;
v8::Local<v8::Value> constructor = object->GetRealNamedProperty(constructorSymbol);
if (!constructor.IsEmpty() && constructor->IsFunction()) {
v8::Local<v8::String> constructorName = functionDisplayName(v8::Handle<v8::Function>::Cast(constructor));
if (!constructorName.IsEmpty() && !tryCatch.HasCaught())
result = constructorName;
}
}
}
v8SetReturnValue(info, result);
}
void V8InjectedScriptHost::isHTMLAllCollectionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
// FIXME(sky): remove
v8SetReturnValue(info, false);
}
void V8InjectedScriptHost::subtypeMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
if (info.Length() < 1)
return;
v8::Isolate* isolate = info.GetIsolate();
v8::Handle<v8::Value> value = info[0];
if (value->IsArray() || value->IsTypedArray() || value->IsArgumentsObject()) {
v8SetReturnValue(info, v8AtomicString(isolate, "array"));
return;
}
if (value->IsDate()) {
v8SetReturnValue(info, v8AtomicString(isolate, "date"));
return;
}
if (value->IsRegExp()) {
v8SetReturnValue(info, v8AtomicString(isolate, "regexp"));
return;
}
if (value->IsMap() || value->IsWeakMap()) {
v8SetReturnValue(info, v8AtomicString(isolate, "map"));
return;
}
if (value->IsSet() || value->IsWeakSet()) {
v8SetReturnValue(info, v8AtomicString(isolate, "set"));
return;
}
if (V8Node::hasInstance(value, isolate)) {
v8SetReturnValue(info, v8AtomicString(isolate, "node"));
return;
}
if (V8NodeList::hasInstance(value, isolate)
|| V8DOMTokenList::hasInstance(value, isolate)) {
v8SetReturnValue(info, v8AtomicString(isolate, "array"));
return;
}
}
void V8InjectedScriptHost::functionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
if (info.Length() < 1 || !info[0]->IsFunction())
return;
v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(info[0]);
int lineNumber = function->GetScriptLineNumber();
int columnNumber = function->GetScriptColumnNumber();
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Object> location = v8::Object::New(isolate);
location->Set(v8AtomicString(isolate, "lineNumber"), v8::Integer::New(isolate, lineNumber));
location->Set(v8AtomicString(isolate, "columnNumber"), v8::Integer::New(isolate, columnNumber));
location->Set(v8AtomicString(isolate, "scriptId"), v8::Integer::New(isolate, function->ScriptId())->ToString());
v8::Local<v8::Object> result = v8::Object::New(isolate);
result->Set(v8AtomicString(isolate, "location"), location);
v8::Handle<v8::String> name = functionDisplayName(function);
result->Set(v8AtomicString(isolate, "functionName"), name.IsEmpty() ? v8AtomicString(isolate, "") : name);
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
ScriptDebugServer& debugServer = host->scriptDebugServer();
v8::Handle<v8::Value> scopes = debugServer.functionScopes(function);
if (!scopes.IsEmpty() && scopes->IsArray())
result->Set(v8AtomicString(isolate, "rawScopes"), scopes);
v8SetReturnValue(info, result);
}
void V8InjectedScriptHost::collectionEntriesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
if (info.Length() < 1 || !info[0]->IsObject())
return;
v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(info[0]);
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
ScriptDebugServer& debugServer = host->scriptDebugServer();
v8SetReturnValue(info, debugServer.collectionEntries(object));
}
void V8InjectedScriptHost::getInternalPropertiesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
if (info.Length() < 1 || !info[0]->IsObject())
return;
v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(info[0]);
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
ScriptDebugServer& debugServer = host->scriptDebugServer();
v8SetReturnValue(info, debugServer.getInternalProperties(object));
}
void V8InjectedScriptHost::getEventListenersMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
// FIXME(sky): remove
}
void V8InjectedScriptHost::inspectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
if (info.Length() < 2)
return;
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
ScriptState* scriptState = ScriptState::current(info.GetIsolate());
ScriptValue object(scriptState, info[0]);
ScriptValue hints(scriptState, info[1]);
host->inspectImpl(object.toJSONValue(scriptState), hints.toJSONValue(scriptState));
}
void V8InjectedScriptHost::evalMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
v8::Isolate* isolate = info.GetIsolate();
if (info.Length() < 1) {
isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected.")));
return;
}
v8::Handle<v8::String> expression = info[0]->ToString();
if (expression.IsEmpty()) {
isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "The argument must be a string.")));
return;
}
ASSERT(isolate->InContext());
v8::TryCatch tryCatch;
v8::Handle<v8::Value> result = V8ScriptRunner::compileAndRunInternalScript(expression, info.GetIsolate());
if (tryCatch.HasCaught()) {
v8SetReturnValue(info, tryCatch.ReThrow());
return;
}
v8SetReturnValue(info, result);
}
void V8InjectedScriptHost::evaluateWithExceptionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
v8::Isolate* isolate = info.GetIsolate();
if (info.Length() < 1) {
isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected.")));
return;
}
v8::Handle<v8::String> expression = info[0]->ToString();
if (expression.IsEmpty()) {
isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "The argument must be a string.")));
return;
}
ASSERT(isolate->InContext());
v8::TryCatch tryCatch;
v8::Handle<v8::Value> result = V8ScriptRunner::compileAndRunInternalScript(expression, info.GetIsolate());
v8::Local<v8::Object> wrappedResult = v8::Object::New(isolate);
if (tryCatch.HasCaught()) {
wrappedResult->Set(v8::String::NewFromUtf8(isolate, "result"), tryCatch.Exception());
wrappedResult->Set(v8::String::NewFromUtf8(isolate, "exceptionDetails"), JavaScriptCallFrame::createExceptionDetails(tryCatch.Message(), isolate));
} else {
wrappedResult->Set(v8::String::NewFromUtf8(isolate, "result"), result);
wrappedResult->Set(v8::String::NewFromUtf8(isolate, "exceptionDetails"), v8::Undefined(isolate));
}
v8SetReturnValue(info, wrappedResult);
}
void V8InjectedScriptHost::setFunctionVariableValueMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
v8::Handle<v8::Value> functionValue = info[0];
int scopeIndex = info[1]->Int32Value();
String variableName = toCoreStringWithUndefinedOrNullCheck(info[2]);
v8::Handle<v8::Value> newValue = info[3];
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
ScriptDebugServer& debugServer = host->scriptDebugServer();
v8SetReturnValue(info, debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue));
}
static bool getFunctionLocation(const v8::FunctionCallbackInfo<v8::Value>& info, String* scriptId, int* lineNumber, int* columnNumber)
{
if (info.Length() < 1)
return false;
v8::Handle<v8::Value> fn = info[0];
if (!fn->IsFunction())
return false;
v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(fn);
*lineNumber = function->GetScriptLineNumber();
*columnNumber = function->GetScriptColumnNumber();
if (*lineNumber == v8::Function::kLineOffsetNotFound || *columnNumber == v8::Function::kLineOffsetNotFound)
return false;
*scriptId = String::number(function->ScriptId());
return true;
}
void V8InjectedScriptHost::debugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
String scriptId;
int lineNumber;
int columnNumber;
if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
return;
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
host->debugFunction(scriptId, lineNumber, columnNumber);
}
void V8InjectedScriptHost::undebugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
String scriptId;
int lineNumber;
int columnNumber;
if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
return;
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
host->undebugFunction(scriptId, lineNumber, columnNumber);
}
void V8InjectedScriptHost::monitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
String scriptId;
int lineNumber;
int columnNumber;
if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
return;
v8::Handle<v8::Value> name;
if (info.Length() > 0 && info[0]->IsFunction()) {
v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(info[0]);
name = function->GetName();
if (!name->IsString() || !v8::Handle<v8::String>::Cast(name)->Length())
name = function->GetInferredName();
}
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
host->monitorFunction(scriptId, lineNumber, columnNumber, toCoreStringWithUndefinedOrNullCheck(name));
}
void V8InjectedScriptHost::unmonitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
String scriptId;
int lineNumber;
int columnNumber;
if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
return;
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
host->unmonitorFunction(scriptId, lineNumber, columnNumber);
}
void V8InjectedScriptHost::callFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
if (info.Length() < 2 || info.Length() > 3 || !info[0]->IsFunction()) {
ASSERT_NOT_REACHED();
return;
}
v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(info[0]);
v8::Handle<v8::Value> receiver = info[1];
if (info.Length() < 3 || info[2]->IsUndefined()) {
v8::Local<v8::Value> result = function->Call(receiver, 0, 0);
v8SetReturnValue(info, result);
return;
}
if (!info[2]->IsArray()) {
ASSERT_NOT_REACHED();
return;
}
v8::Handle<v8::Array> arguments = v8::Handle<v8::Array>::Cast(info[2]);
size_t argc = arguments->Length();
OwnPtr<v8::Handle<v8::Value>[]> argv = adoptArrayPtr(new v8::Handle<v8::Value>[argc]);
for (size_t i = 0; i < argc; ++i)
argv[i] = arguments->Get(i);
v8::Local<v8::Value> result = function->Call(receiver, argc, argv.get());
v8SetReturnValue(info, result);
}
void V8InjectedScriptHost::suppressWarningsAndCallFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
ScriptDebugServer& debugServer = host->scriptDebugServer();
debugServer.muteWarningsAndDeprecations();
callFunctionMethodCustom(info);
debugServer.unmuteWarningsAndDeprecations();
}
} // namespace blink

View File

@ -0,0 +1,118 @@
/*
* Copyright (C) 2012 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 "config.h"
#include "core/inspector/InjectedScriptManager.h"
#include "bindings/core/v8/BindingSecurity.h"
#include "bindings/core/v8/ScopedPersistent.h"
#include "bindings/core/v8/ScriptDebugServer.h"
#include "bindings/core/v8/ScriptValue.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8InjectedScriptHost.h"
#include "bindings/core/v8/V8ObjectConstructor.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "bindings/core/v8/V8Window.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/inspector/InjectedScriptHost.h"
#include "wtf/RefPtr.h"
namespace blink {
InjectedScriptManager::CallbackData* InjectedScriptManager::createCallbackData(InjectedScriptManager* injectedScriptManager)
{
OwnPtr<InjectedScriptManager::CallbackData> callbackData = adoptPtr(new InjectedScriptManager::CallbackData());
InjectedScriptManager::CallbackData* callbackDataPtr = callbackData.get();
callbackData->injectedScriptManager = injectedScriptManager;
m_callbackDataSet.add(callbackData.release());
return callbackDataPtr;
}
void InjectedScriptManager::removeCallbackData(InjectedScriptManager::CallbackData* callbackData)
{
ASSERT(m_callbackDataSet.contains(callbackData));
m_callbackDataSet.remove(callbackData);
}
static v8::Local<v8::Object> createInjectedScriptHostV8Wrapper(PassRefPtr<InjectedScriptHost> host, InjectedScriptManager* injectedScriptManager, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
ASSERT(host);
v8::Handle<v8::Object> wrapper = V8DOMWrapper::createWrapper(creationContext, &V8InjectedScriptHost::wrapperTypeInfo, V8InjectedScriptHost::toScriptWrappableBase(host.get()), isolate);
if (UNLIKELY(wrapper.IsEmpty()))
return wrapper;
// Create a weak reference to the v8 wrapper of InspectorBackend to deref
// InspectorBackend when the wrapper is garbage collected.
InjectedScriptManager::CallbackData* callbackData = injectedScriptManager->createCallbackData(injectedScriptManager);
callbackData->host = host.get();
callbackData->handle.set(isolate, wrapper);
callbackData->handle.setWeak(callbackData, &InjectedScriptManager::setWeakCallback);
V8DOMWrapper::setNativeInfo(wrapper, &V8InjectedScriptHost::wrapperTypeInfo, V8InjectedScriptHost::toScriptWrappableBase(host.get()));
ASSERT(V8DOMWrapper::isDOMWrapper(wrapper));
return wrapper;
}
ScriptValue InjectedScriptManager::createInjectedScript(const String& scriptSource, ScriptState* inspectedScriptState, int id)
{
v8::Isolate* isolate = inspectedScriptState->isolate();
ScriptState::Scope scope(inspectedScriptState);
// Call custom code to create InjectedScripHost wrapper specific for the context
// instead of calling toV8() that would create the
// wrapper in the current context.
// FIXME: make it possible to use generic bindings factory for InjectedScriptHost.
v8::Local<v8::Object> scriptHostWrapper = createInjectedScriptHostV8Wrapper(m_injectedScriptHost, this, inspectedScriptState->context()->Global(), inspectedScriptState->isolate());
if (scriptHostWrapper.IsEmpty())
return ScriptValue();
// Inject javascript into the context. The compiled script is supposed to evaluate into
// a single anonymous function(it's anonymous to avoid cluttering the global object with
// inspector's stuff) the function is called a few lines below with InjectedScriptHost wrapper,
// injected script id and explicit reference to the inspected global object. The function is expected
// to create and configure InjectedScript instance that is going to be used by the inspector.
v8::Local<v8::Value> value = V8ScriptRunner::compileAndRunInternalScript(v8String(isolate, scriptSource), isolate);
ASSERT(!value.IsEmpty());
ASSERT(value->IsFunction());
v8::Local<v8::Object> windowGlobal = inspectedScriptState->context()->Global();
v8::Handle<v8::Value> info[] = { scriptHostWrapper, windowGlobal, v8::Number::New(inspectedScriptState->isolate(), id) };
v8::Local<v8::Value> injectedScriptValue = V8ScriptRunner::callInternalFunction(v8::Local<v8::Function>::Cast(value), windowGlobal, WTF_ARRAY_LENGTH(info), info, inspectedScriptState->isolate());
return ScriptValue(inspectedScriptState, injectedScriptValue);
}
void InjectedScriptManager::setWeakCallback(const v8::WeakCallbackData<v8::Object, InjectedScriptManager::CallbackData>& data)
{
InjectedScriptManager::CallbackData* callbackData = data.GetParameter();
callbackData->injectedScriptManager->removeCallbackData(callbackData);
}
} // namespace blink

View File

@ -26,6 +26,8 @@
'V8HTMLCanvasElementCustom.cpp',
'V8HTMLElementCustom.cpp',
'V8ImageDataCustom.cpp',
'V8InjectedScriptHostCustom.cpp',
'V8InjectedScriptManager.cpp',
'V8Int16ArrayCustom.h',
'V8Int32ArrayCustom.h',
'V8Int8ArrayCustom.h',

View File

@ -69,6 +69,8 @@
'ScriptPromiseProperty.h',
'ScriptPromisePropertyBase.cpp',
'ScriptPromisePropertyBase.h',
'ScriptRegexp.cpp',
'ScriptRegexp.h',
'ScriptSourceCode.h',
'ScriptState.cpp',
'ScriptState.h',
@ -127,6 +129,8 @@
'WindowProxy.cpp',
'WindowProxy.h',
'WrapperTypeInfo.h',
'PageScriptDebugServer.h',
'PageScriptDebugServer.cpp',
],
},
}

View File

@ -12,19 +12,21 @@ rel_sky_core_gen_dir = rebase_path(sky_core_output_dir, root_build_dir)
source_set("libraries") {
public_deps = [
"//base:base",
"//base",
"//gin",
"//gpu/command_buffer/client:gles2_c_lib",
"//mojo/application",
"//mojo/common",
"//mojo/public/c/system:for_shared_library",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/utility",
"//mojo/public/cpp/system",
"//mojo/public/cpp/utility",
"//mojo/public/interfaces/application",
"//mojo/services/public/cpp/view_manager",
"//mojo/services/public/interfaces/navigation",
"//skia",
"//sky/engine/wtf",
"//sky/services/inspector:bindings",
"//third_party/angle:translator",
"//third_party/iccjpeg",
"//third_party/libpng",
@ -104,6 +106,11 @@ source_set("core_generated") {
# Additional .cpp files from the make_core_generated rules.
"$sky_core_output_dir/CSSGrammar.cpp",
# Additional .cpp files from the inspector_protocol_sources list.
"$sky_core_output_dir/InspectorFrontend.cpp",
"$sky_core_output_dir/InspectorBackendDispatcher.cpp",
"$sky_core_output_dir/InspectorTypeBuilder.cpp",
]
configs += [

View File

@ -1032,22 +1032,49 @@ sky_core_files = [
"html/VoidCallback.h",
"Init.cpp",
"Init.h",
"inspector/AsyncCallStackTracker.cpp",
"inspector/AsyncCallStackTracker.h",
"inspector/BindingVisitors.h",
"inspector/ConsoleAPITypes.h",
"inspector/ConsoleMessage.cpp",
"inspector/ConsoleMessage.h",
"inspector/ConsoleMessageStorage.cpp",
"inspector/ConsoleMessageStorage.h",
"inspector/ContentSearchUtils.cpp",
"inspector/ContentSearchUtils.h",
"inspector/IdentifiersFactory.cpp",
"inspector/IdentifiersFactory.h",
"inspector/InjectedScript.cpp",
"inspector/InjectedScript.h",
"inspector/InjectedScriptBase.cpp",
"inspector/InjectedScriptBase.h",
"inspector/InjectedScriptHost.cpp",
"inspector/InjectedScriptHost.h",
"inspector/InjectedScriptManager.cpp",
"inspector/InjectedScriptManager.h",
"inspector/inspector_backend_mojo.cc",
"inspector/inspector_backend_mojo.h",
"inspector/InspectorBaseAgent.cpp",
"inspector/InspectorBaseAgent.h",
"inspector/InspectorCounters.cpp",
"inspector/InspectorCounters.h",
"inspector/InspectorDebuggerAgent.cpp",
"inspector/InspectorDebuggerAgent.h",
"inspector/InspectorFrontendChannel.h",
"inspector/InspectorNodeIds.cpp",
"inspector/InspectorNodeIds.h",
"inspector/InspectorState.cpp",
"inspector/InspectorState.h",
"inspector/InspectorTraceEvents.cpp",
"inspector/InspectorTraceEvents.h",
"inspector/JavaScriptCallFrame.cpp",
"inspector/JavaScriptCallFrame.h",
"inspector/JSONParser.cpp",
"inspector/JSONParser.h",
"inspector/PageDebuggerAgent.cpp",
"inspector/PageDebuggerAgent.h",
"inspector/PromiseTracker.cpp",
"inspector/PromiseTracker.h",
"inspector/ScriptArguments.cpp",
"inspector/ScriptArguments.h",
"inspector/ScriptAsyncCallStack.cpp",
@ -1467,6 +1494,7 @@ core_idl_files = get_path_info([
"html/TextMetrics.idl",
"html/VoidCallback.idl",
"inspector/JavaScriptCallFrame.idl",
"inspector/InjectedScriptHost.idl",
], "abspath")
# Files for which bindings (.cpp and .h files) will be generated

View File

@ -0,0 +1,401 @@
/*
* Copyright (C) 2013 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 "config.h"
#include "core/inspector/AsyncCallStackTracker.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8RecursionScope.h"
#include "core/dom/ExecutionContext.h"
// #include "core/dom/ExecutionContextTask.h"
#include "core/events/Event.h"
#include "core/events/EventTarget.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/StringHash.h"
#include <v8.h>
namespace {
static const char setTimeoutName[] = "setTimeout";
static const char setIntervalName[] = "setInterval";
static const char requestAnimationFrameName[] = "requestAnimationFrame";
static const char enqueueMutationRecordName[] = "Mutation";
}
namespace blink {
void AsyncCallStackTracker::ExecutionContextData::contextDestroyed()
{
ASSERT(executionContext());
OwnPtr<ExecutionContextData> self = m_tracker->m_executionContextDataMap.take(executionContext());
ASSERT_UNUSED(self, self == this);
ContextLifecycleObserver::contextDestroyed();
}
int AsyncCallStackTracker::ExecutionContextData::circularSequentialID()
{
++m_circularSequentialID;
if (m_circularSequentialID <= 0)
m_circularSequentialID = 1;
return m_circularSequentialID;
}
AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const String& description, const ScriptValue& callFrames)
: m_description(description)
, m_callFrames(callFrames)
{
}
AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack()
{
}
AsyncCallStackTracker::AsyncCallStackTracker()
: m_maxAsyncCallStackDepth(0)
, m_nestedAsyncCallCount(0)
{
}
void AsyncCallStackTracker::setAsyncCallStackDepth(int depth)
{
if (depth <= 0) {
m_maxAsyncCallStackDepth = 0;
clear();
} else {
m_maxAsyncCallStackDepth = depth;
}
}
const AsyncCallStackTracker::AsyncCallChain* AsyncCallStackTracker::currentAsyncCallChain() const
{
if (m_currentAsyncCallChain)
ensureMaxAsyncCallChainDepth(m_currentAsyncCallChain.get(), m_maxAsyncCallStackDepth);
return m_currentAsyncCallChain.get();
}
void AsyncCallStackTracker::didInstallTimer(ExecutionContext* context, int timerId, bool singleShot, const ScriptValue& callFrames)
{
ASSERT(context);
ASSERT(isEnabled());
if (!validateCallFrames(callFrames))
return;
ASSERT(timerId > 0);
ExecutionContextData* data = createContextDataIfNeeded(context);
data->m_timerCallChains.set(timerId, createAsyncCallChain(singleShot ? setTimeoutName : setIntervalName, callFrames));
if (!singleShot)
data->m_intervalTimerIds.add(timerId);
}
void AsyncCallStackTracker::didRemoveTimer(ExecutionContext* context, int timerId)
{
ASSERT(context);
ASSERT(isEnabled());
if (timerId <= 0)
return;
ExecutionContextData* data = m_executionContextDataMap.get(context);
if (!data)
return;
data->m_intervalTimerIds.remove(timerId);
data->m_timerCallChains.remove(timerId);
}
void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId)
{
ASSERT(context);
ASSERT(isEnabled());
ASSERT(timerId > 0);
ASSERT(!m_currentAsyncCallChain);
if (ExecutionContextData* data = m_executionContextDataMap.get(context)) {
if (data->m_intervalTimerIds.contains(timerId))
setCurrentAsyncCallChain(context, data->m_timerCallChains.get(timerId));
else
setCurrentAsyncCallChain(context, data->m_timerCallChains.take(timerId));
} else {
setCurrentAsyncCallChain(context, nullptr);
}
}
void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames)
{
ASSERT(context);
ASSERT(isEnabled());
if (!validateCallFrames(callFrames))
return;
ASSERT(callbackId > 0);
ExecutionContextData* data = createContextDataIfNeeded(context);
data->m_animationFrameCallChains.set(callbackId, createAsyncCallChain(requestAnimationFrameName, callFrames));
}
void AsyncCallStackTracker::didCancelAnimationFrame(ExecutionContext* context, int callbackId)
{
ASSERT(context);
ASSERT(isEnabled());
if (callbackId <= 0)
return;
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
data->m_animationFrameCallChains.remove(callbackId);
}
void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, int callbackId)
{
ASSERT(context);
ASSERT(isEnabled());
ASSERT(callbackId > 0);
ASSERT(!m_currentAsyncCallChain);
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
setCurrentAsyncCallChain(context, data->m_animationFrameCallChains.take(callbackId));
else
setCurrentAsyncCallChain(context, nullptr);
}
void AsyncCallStackTracker::didEnqueueEvent(EventTarget* eventTarget, Event* event, const ScriptValue& callFrames)
{
ASSERT(eventTarget->executionContext());
ASSERT(isEnabled());
if (!validateCallFrames(callFrames))
return;
ExecutionContextData* data = createContextDataIfNeeded(eventTarget->executionContext());
data->m_eventCallChains.set(event, createAsyncCallChain(event->type(), callFrames));
}
void AsyncCallStackTracker::didRemoveEvent(EventTarget* eventTarget, Event* event)
{
ASSERT(eventTarget->executionContext());
ASSERT(isEnabled());
if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->executionContext()))
data->m_eventCallChains.remove(event);
}
void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, Event* event, EventListener* listener, bool useCapture)
{
ASSERT(eventTarget->executionContext());
ASSERT(isEnabled());
ExecutionContext* context = eventTarget->executionContext();
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
setCurrentAsyncCallChain(context, data->m_eventCallChains.get(event));
else
setCurrentAsyncCallChain(context, nullptr);
}
void AsyncCallStackTracker::didEnqueueMutationRecord(ExecutionContext* context, MutationObserver* observer, const ScriptValue& callFrames)
{
ASSERT(context);
ASSERT(isEnabled());
if (!validateCallFrames(callFrames))
return;
ExecutionContextData* data = createContextDataIfNeeded(context);
data->m_mutationObserverCallChains.set(observer, createAsyncCallChain(enqueueMutationRecordName, callFrames));
}
bool AsyncCallStackTracker::hasEnqueuedMutationRecord(ExecutionContext* context, MutationObserver* observer)
{
ASSERT(context);
ASSERT(isEnabled());
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
return data->m_mutationObserverCallChains.contains(observer);
return false;
}
void AsyncCallStackTracker::didClearAllMutationRecords(ExecutionContext* context, MutationObserver* observer)
{
ASSERT(context);
ASSERT(isEnabled());
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
data->m_mutationObserverCallChains.remove(observer);
}
void AsyncCallStackTracker::willDeliverMutationRecords(ExecutionContext* context, MutationObserver* observer)
{
ASSERT(context);
ASSERT(isEnabled());
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
setCurrentAsyncCallChain(context, data->m_mutationObserverCallChains.take(observer));
else
setCurrentAsyncCallChain(context, nullptr);
}
// void AsyncCallStackTracker::didPostExecutionContextTask(ExecutionContext* context, ExecutionContextTask* task, const ScriptValue& callFrames)
// {
// ASSERT(context);
// ASSERT(isEnabled());
// if (!validateCallFrames(callFrames))
// return;
// ExecutionContextData* data = createContextDataIfNeeded(context);
// data->m_executionContextTaskCallChains.set(task, createAsyncCallChain(task->taskNameForInstrumentation(), callFrames));
// }
// void AsyncCallStackTracker::didKillAllExecutionContextTasks(ExecutionContext* context)
// {
// ASSERT(context);
// ASSERT(isEnabled());
// if (ExecutionContextData* data = m_executionContextDataMap.get(context))
// data->m_executionContextTaskCallChains.clear();
// }
// void AsyncCallStackTracker::willPerformExecutionContextTask(ExecutionContext* context, ExecutionContextTask* task)
// {
// ASSERT(context);
// ASSERT(isEnabled());
// if (ExecutionContextData* data = m_executionContextDataMap.get(context))
// setCurrentAsyncCallChain(context, data->m_executionContextTaskCallChains.take(task));
// else
// setCurrentAsyncCallChain(context, nullptr);
// }
static String makeV8AsyncTaskUniqueId(const String& eventName, int id)
{
StringBuilder builder;
builder.append(eventName);
builder.appendNumber(id);
return builder.toString();
}
void AsyncCallStackTracker::didEnqueueV8AsyncTask(ExecutionContext* context, const String& eventName, int id, const ScriptValue& callFrames)
{
ASSERT(context);
ASSERT(isEnabled());
if (!validateCallFrames(callFrames))
return;
ExecutionContextData* data = createContextDataIfNeeded(context);
data->m_v8AsyncTaskCallChains.set(makeV8AsyncTaskUniqueId(eventName, id), createAsyncCallChain(eventName, callFrames));
}
void AsyncCallStackTracker::willHandleV8AsyncTask(ExecutionContext* context, const String& eventName, int id)
{
ASSERT(context);
ASSERT(isEnabled());
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
setCurrentAsyncCallChain(context, data->m_v8AsyncTaskCallChains.take(makeV8AsyncTaskUniqueId(eventName, id)));
else
setCurrentAsyncCallChain(context, nullptr);
}
int AsyncCallStackTracker::traceAsyncOperationStarting(ExecutionContext* context, const String& operationName, const ScriptValue& callFrames)
{
ASSERT(context);
ASSERT(isEnabled());
if (!validateCallFrames(callFrames))
return 0;
ExecutionContextData* data = createContextDataIfNeeded(context);
int id = data->circularSequentialID();
while (data->m_asyncOperationCallChains.contains(id))
id = data->circularSequentialID();
data->m_asyncOperationCallChains.set(id, createAsyncCallChain(operationName, callFrames));
return id;
}
void AsyncCallStackTracker::traceAsyncOperationCompleted(ExecutionContext* context, int operationId)
{
ASSERT(context);
ASSERT(isEnabled());
if (operationId <= 0)
return;
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
data->m_asyncOperationCallChains.remove(operationId);
}
void AsyncCallStackTracker::traceAsyncCallbackStarting(ExecutionContext* context, int operationId)
{
ASSERT(context);
ASSERT(isEnabled());
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
setCurrentAsyncCallChain(context, operationId > 0 ? data->m_asyncOperationCallChains.get(operationId) : nullptr);
else
setCurrentAsyncCallChain(context, nullptr);
}
void AsyncCallStackTracker::didFireAsyncCall()
{
clearCurrentAsyncCallChain();
}
PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createAsyncCallChain(const String& description, const ScriptValue& callFrames)
{
if (callFrames.isEmpty()) {
ASSERT(m_currentAsyncCallChain);
return m_currentAsyncCallChain; // Propogate async call stack chain.
}
RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncCallStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTracker::AsyncCallChain());
ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1);
chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallStack(description, callFrames)));
return chain.release();
}
void AsyncCallStackTracker::setCurrentAsyncCallChain(ExecutionContext* context, PassRefPtr<AsyncCallChain> chain)
{
if (chain && !V8RecursionScope::recursionLevel(toIsolate(context))) {
// Current AsyncCallChain corresponds to the bottommost JS call frame.
m_currentAsyncCallChain = chain;
m_nestedAsyncCallCount = 1;
} else {
if (m_currentAsyncCallChain)
++m_nestedAsyncCallCount;
}
}
void AsyncCallStackTracker::clearCurrentAsyncCallChain()
{
if (!m_nestedAsyncCallCount)
return;
--m_nestedAsyncCallCount;
if (!m_nestedAsyncCallCount)
m_currentAsyncCallChain.clear();
}
void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth)
{
while (chain->m_callStacks.size() > maxDepth)
chain->m_callStacks.removeLast();
}
bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames)
{
return !callFrames.isEmpty() || m_currentAsyncCallChain;
}
AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContextDataIfNeeded(ExecutionContext* context)
{
ExecutionContextData* data = m_executionContextDataMap.get(context);
if (!data) {
data = m_executionContextDataMap.set(context, adoptPtr(new AsyncCallStackTracker::ExecutionContextData(this, context)))
.storedValue->value.get();
}
return data;
}
void AsyncCallStackTracker::clear()
{
m_currentAsyncCallChain.clear();
m_nestedAsyncCallCount = 0;
m_executionContextDataMap.clear();
}
} // namespace blink

View File

@ -0,0 +1,161 @@
/*
* Copyright (C) 2013 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.
*/
#ifndef AsyncCallStackTracker_h
#define AsyncCallStackTracker_h
#include "bindings/core/v8/ScriptValue.h"
#include "core/dom/ContextLifecycleObserver.h"
#include "wtf/Deque.h"
#include "wtf/HashMap.h"
#include "wtf/HashSet.h"
#include "wtf/Noncopyable.h"
#include "wtf/PassRefPtr.h"
#include "wtf/RefPtr.h"
namespace blink {
class Event;
class EventListener;
class EventTarget;
class ExecutionContext;
class MutationObserver;
class AsyncCallStackTracker final {
WTF_MAKE_NONCOPYABLE(AsyncCallStackTracker);
public:
class AsyncCallStack final : public RefCounted<AsyncCallStack> {
public:
AsyncCallStack(const String&, const ScriptValue&);
~AsyncCallStack();
String description() const { return m_description; }
ScriptValue callFrames() const { return m_callFrames; }
private:
String m_description;
ScriptValue m_callFrames;
};
typedef Deque<RefPtr<AsyncCallStack>, 4> AsyncCallStackVector;
class AsyncCallChain final : public RefCounted<AsyncCallChain> {
public:
AsyncCallChain() { }
AsyncCallChain(const AsyncCallChain& t) : m_callStacks(t.m_callStacks) { }
AsyncCallStackVector callStacks() const { return m_callStacks; }
private:
friend class AsyncCallStackTracker;
AsyncCallStackVector m_callStacks;
};
class ExecutionContextData final : public ContextLifecycleObserver {
WTF_MAKE_FAST_ALLOCATED;
public:
ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* executionContext)
: ContextLifecycleObserver(executionContext)
, m_circularSequentialID(0)
, m_tracker(tracker)
{
}
virtual void contextDestroyed() override;
int circularSequentialID();
private:
int m_circularSequentialID;
public:
RawPtr<AsyncCallStackTracker> m_tracker;
HashSet<int> m_intervalTimerIds;
HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains;
HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains;
HashMap<RawPtr<Event>, RefPtr<AsyncCallChain> > m_eventCallChains;
HashMap<RawPtr<MutationObserver>, RefPtr<AsyncCallChain> > m_mutationObserverCallChains;
//HashMap<ExecutionContextTask*, RefPtr<AsyncCallChain> > m_executionContextTaskCallChains;
HashMap<String, RefPtr<AsyncCallChain> > m_v8AsyncTaskCallChains;
HashMap<int, RefPtr<AsyncCallChain> > m_asyncOperationCallChains;
};
AsyncCallStackTracker();
bool isEnabled() const { return m_maxAsyncCallStackDepth; }
void setAsyncCallStackDepth(int);
const AsyncCallChain* currentAsyncCallChain() const;
void didInstallTimer(ExecutionContext*, int timerId, bool singleShot, const ScriptValue& callFrames);
void didRemoveTimer(ExecutionContext*, int timerId);
void willFireTimer(ExecutionContext*, int timerId);
void didRequestAnimationFrame(ExecutionContext*, int callbackId, const ScriptValue& callFrames);
void didCancelAnimationFrame(ExecutionContext*, int callbackId);
void willFireAnimationFrame(ExecutionContext*, int callbackId);
void didEnqueueEvent(EventTarget*, Event*, const ScriptValue& callFrames);
void didRemoveEvent(EventTarget*, Event*);
void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture);
void didEnqueueMutationRecord(ExecutionContext*, MutationObserver*, const ScriptValue& callFrames);
bool hasEnqueuedMutationRecord(ExecutionContext*, MutationObserver*);
void didClearAllMutationRecords(ExecutionContext*, MutationObserver*);
void willDeliverMutationRecords(ExecutionContext*, MutationObserver*);
// void didPostExecutionContextTask(ExecutionContext*, ExecutionContextTask*, const ScriptValue& callFrames);
// void didKillAllExecutionContextTasks(ExecutionContext*);
// void willPerformExecutionContextTask(ExecutionContext*, ExecutionContextTask*);
void didEnqueueV8AsyncTask(ExecutionContext*, const String& eventName, int id, const ScriptValue& callFrames);
void willHandleV8AsyncTask(ExecutionContext*, const String& eventName, int id);
int traceAsyncOperationStarting(ExecutionContext*, const String& operationName, const ScriptValue& callFrames);
void traceAsyncOperationCompleted(ExecutionContext*, int operationId);
void traceAsyncCallbackStarting(ExecutionContext*, int operationId);
void didFireAsyncCall();
void clear();
private:
PassRefPtr<AsyncCallChain> createAsyncCallChain(const String& description, const ScriptValue& callFrames);
void setCurrentAsyncCallChain(ExecutionContext*, PassRefPtr<AsyncCallChain>);
void clearCurrentAsyncCallChain();
static void ensureMaxAsyncCallChainDepth(AsyncCallChain*, unsigned);
bool validateCallFrames(const ScriptValue& callFrames);
ExecutionContextData* createContextDataIfNeeded(ExecutionContext*);
unsigned m_maxAsyncCallStackDepth;
RefPtr<AsyncCallChain> m_currentAsyncCallChain;
unsigned m_nestedAsyncCallCount;
typedef HashMap<RawPtr<ExecutionContext>, OwnPtr<ExecutionContextData> > ExecutionContextDataMap;
ExecutionContextDataMap m_executionContextDataMap;
};
} // namespace blink
#endif // !defined(AsyncCallStackTracker_h)

View File

@ -0,0 +1,188 @@
/*
* Copyright (C) 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS 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 GOOGLE INC.
* OR ITS 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 "config.h"
#include "core/inspector/ContentSearchUtils.h"
#include "bindings/core/v8/ScriptRegexp.h"
#include "wtf/Vector.h"
#include "wtf/text/StringBuilder.h"
namespace blink {
namespace ContentSearchUtils {
namespace {
// This should be kept the same as the one in front-end/utilities.js
static const char regexSpecialCharacters[] = "[](){}+-*.,?\\^$|";
}
static String createSearchRegexSource(const String& text)
{
StringBuilder result;
String specials(regexSpecialCharacters);
for (unsigned i = 0; i < text.length(); i++) {
if (specials.find(text[i]) != kNotFound)
result.append('\\');
result.append(text[i]);
}
return result.toString();
}
static Vector<pair<int, String> > getScriptRegexpMatchesByLines(const ScriptRegexp* regex, const String& text)
{
Vector<pair<int, String> > result;
if (text.isEmpty())
return result;
OwnPtr<Vector<unsigned> > endings(lineEndings(text));
unsigned size = endings->size();
unsigned start = 0;
for (unsigned lineNumber = 0; lineNumber < size; ++lineNumber) {
unsigned lineEnd = endings->at(lineNumber);
String line = text.substring(start, lineEnd - start);
if (line.endsWith('\r'))
line = line.left(line.length() - 1);
int matchLength;
if (regex->match(line, 0, &matchLength) != -1)
result.append(pair<int, String>(lineNumber, line));
start = lineEnd + 1;
}
return result;
}
static PassRefPtr<TypeBuilder::Page::SearchMatch> buildObjectForSearchMatch(int lineNumber, const String& lineContent)
{
return TypeBuilder::Page::SearchMatch::create()
.setLineNumber(lineNumber)
.setLineContent(lineContent)
.release();
}
PassOwnPtr<ScriptRegexp> createSearchRegex(const String& query, bool caseSensitive, bool isRegex)
{
String regexSource = isRegex ? query : createSearchRegexSource(query);
return adoptPtr(new ScriptRegexp(regexSource, caseSensitive ? TextCaseSensitive : TextCaseInsensitive));
}
PassRefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex)
{
RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > result = TypeBuilder::Array<TypeBuilder::Page::SearchMatch>::create();
OwnPtr<ScriptRegexp> regex = ContentSearchUtils::createSearchRegex(query, caseSensitive, isRegex);
Vector<pair<int, String> > matches = getScriptRegexpMatchesByLines(regex.get(), text);
for (Vector<pair<int, String> >::const_iterator it = matches.begin(); it != matches.end(); ++it)
result->addItem(buildObjectForSearchMatch(it->first, it->second));
return result;
}
static String findMagicComment(const String& content, const String& name, MagicCommentType commentType, bool* deprecated = 0)
{
ASSERT(name.find("=") == kNotFound);
if (deprecated)
*deprecated = false;
unsigned length = content.length();
unsigned nameLength = name.length();
size_t pos = length;
size_t equalSignPos = 0;
size_t closingCommentPos = 0;
while (true) {
pos = content.reverseFind(name, pos);
if (pos == kNotFound)
return String();
// Check for a /\/[\/*][@#][ \t]/ regexp (length of 4) before found name.
if (pos < 4)
return String();
pos -= 4;
if (content[pos] != '/')
continue;
if ((content[pos + 1] != '/' || commentType != JavaScriptMagicComment)
&& (content[pos + 1] != '*' || commentType != CSSMagicComment))
continue;
if (content[pos + 2] != '#' && content[pos + 2] != '@')
continue;
if (content[pos + 3] != ' ' && content[pos + 3] != '\t')
continue;
equalSignPos = pos + 4 + nameLength;
if (equalSignPos < length && content[equalSignPos] != '=')
continue;
if (commentType == CSSMagicComment) {
closingCommentPos = content.find("*/", equalSignPos + 1);
if (closingCommentPos == kNotFound)
return String();
}
break;
}
if (deprecated && content[pos + 2] == '@')
*deprecated = true;
ASSERT(equalSignPos);
ASSERT(commentType != CSSMagicComment || closingCommentPos);
size_t urlPos = equalSignPos + 1;
String match = commentType == CSSMagicComment
? content.substring(urlPos, closingCommentPos - urlPos)
: content.substring(urlPos);
size_t newLine = match.find("\n");
if (newLine != kNotFound)
match = match.substring(0, newLine);
match = match.stripWhiteSpace();
String disallowedChars("\"' \t");
for (unsigned i = 0; i < match.length(); ++i) {
if (disallowedChars.find(match[i]) != kNotFound)
return "";
}
return match;
}
String findSourceURL(const String& content, MagicCommentType commentType, bool* deprecated)
{
return findMagicComment(content, "sourceURL", commentType, deprecated);
}
String findSourceMapURL(const String& content, MagicCommentType commentType, bool* deprecated)
{
return findMagicComment(content, "sourceMappingURL", commentType, deprecated);
}
} // namespace ContentSearchUtils
} // namespace blink

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS 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 GOOGLE INC.
* OR ITS 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.
*/
#ifndef ContentSearchUtils_h
#define ContentSearchUtils_h
#include "core/InspectorTypeBuilder.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/text/TextPosition.h"
#include "wtf/text/WTFString.h"
namespace blink {
class ScriptRegexp;
namespace ContentSearchUtils {
enum MagicCommentType {
JavaScriptMagicComment,
CSSMagicComment
};
PassOwnPtr<ScriptRegexp> createSearchRegex(const String& query, bool caseSensitive, bool isRegex);
PassRefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex);
String findSourceURL(const String& content, MagicCommentType, bool* deprecated);
String findSourceMapURL(const String& content, MagicCommentType, bool* deprecated);
} // namespace ContentSearchUtils
} // namespace blink
#endif // !defined(ContentSearchUtils_h)

View File

@ -0,0 +1,341 @@
/*
* Copyright (C) 2012 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 "config.h"
#include "core/inspector/InjectedScript.h"
#include "bindings/core/v8/ScriptFunctionCall.h"
#include "core/inspector/InjectedScriptHost.h"
#include "platform/JSONValues.h"
#include "wtf/text/WTFString.h"
using blink::TypeBuilder::Array;
using blink::TypeBuilder::Debugger::CallFrame;
using blink::TypeBuilder::Debugger::CollectionEntry;
using blink::TypeBuilder::Debugger::FunctionDetails;
using blink::TypeBuilder::Runtime::PropertyDescriptor;
using blink::TypeBuilder::Runtime::InternalPropertyDescriptor;
using blink::TypeBuilder::Runtime::RemoteObject;
namespace blink {
InjectedScript::InjectedScript()
: InjectedScriptBase("InjectedScript")
{
}
InjectedScript::InjectedScript(ScriptValue injectedScriptObject)
: InjectedScriptBase("InjectedScript", injectedScriptObject)
{
}
void InjectedScript::evaluate(ErrorString* errorString, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* exceptionDetails)
{
ScriptFunctionCall function(injectedScriptObject(), "evaluate");
function.appendArgument(expression);
function.appendArgument(objectGroup);
function.appendArgument(includeCommandLineAPI);
function.appendArgument(returnByValue);
function.appendArgument(generatePreview);
makeEvalCall(errorString, function, result, wasThrown, exceptionDetails);
}
void InjectedScript::callFunctionOn(ErrorString* errorString, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown)
{
ScriptFunctionCall function(injectedScriptObject(), "callFunctionOn");
function.appendArgument(objectId);
function.appendArgument(expression);
function.appendArgument(arguments);
function.appendArgument(returnByValue);
function.appendArgument(generatePreview);
makeEvalCall(errorString, function, result, wasThrown);
}
void InjectedScript::evaluateOnCallFrame(ErrorString* errorString, const ScriptValue& callFrames, const Vector<ScriptValue>& asyncCallStacks, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* exceptionDetails)
{
ScriptFunctionCall function(injectedScriptObject(), "evaluateOnCallFrame");
function.appendArgument(callFrames);
function.appendArgument(asyncCallStacks);
function.appendArgument(callFrameId);
function.appendArgument(expression);
function.appendArgument(objectGroup);
function.appendArgument(includeCommandLineAPI);
function.appendArgument(returnByValue);
function.appendArgument(generatePreview);
makeEvalCall(errorString, function, result, wasThrown, exceptionDetails);
}
void InjectedScript::restartFrame(ErrorString* errorString, const ScriptValue& callFrames, const String& callFrameId, RefPtr<JSONObject>* result)
{
ScriptFunctionCall function(injectedScriptObject(), "restartFrame");
function.appendArgument(callFrames);
function.appendArgument(callFrameId);
RefPtr<JSONValue> resultValue;
makeCall(function, &resultValue);
if (resultValue) {
if (resultValue->type() == JSONValue::TypeString) {
resultValue->asString(errorString);
return;
}
if (resultValue->type() == JSONValue::TypeObject) {
*result = resultValue->asObject();
return;
}
}
*errorString = "Internal error";
}
void InjectedScript::getStepInPositions(ErrorString* errorString, const ScriptValue& callFrames, const String& callFrameId, RefPtr<Array<TypeBuilder::Debugger::Location> >& positions)
{
ScriptFunctionCall function(injectedScriptObject(), "getStepInPositions");
function.appendArgument(callFrames);
function.appendArgument(callFrameId);
RefPtr<JSONValue> resultValue;
makeCall(function, &resultValue);
if (resultValue) {
if (resultValue->type() == JSONValue::TypeString) {
resultValue->asString(errorString);
return;
}
if (resultValue->type() == JSONValue::TypeArray) {
positions = Array<TypeBuilder::Debugger::Location>::runtimeCast(resultValue);
return;
}
}
*errorString = "Internal error";
}
void InjectedScript::setVariableValue(ErrorString* errorString, const ScriptValue& callFrames, const String* callFrameIdOpt, const String* functionObjectIdOpt, int scopeNumber, const String& variableName, const String& newValueStr)
{
ScriptFunctionCall function(injectedScriptObject(), "setVariableValue");
if (callFrameIdOpt) {
function.appendArgument(callFrames);
function.appendArgument(*callFrameIdOpt);
} else {
function.appendArgument(false);
function.appendArgument(false);
}
if (functionObjectIdOpt)
function.appendArgument(*functionObjectIdOpt);
else
function.appendArgument(false);
function.appendArgument(scopeNumber);
function.appendArgument(variableName);
function.appendArgument(newValueStr);
RefPtr<JSONValue> resultValue;
makeCall(function, &resultValue);
if (!resultValue) {
*errorString = "Internal error";
return;
}
if (resultValue->type() == JSONValue::TypeString) {
resultValue->asString(errorString);
return;
}
// Normal return.
}
void InjectedScript::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<FunctionDetails>* result)
{
ScriptFunctionCall function(injectedScriptObject(), "getFunctionDetails");
function.appendArgument(functionId);
RefPtr<JSONValue> resultValue;
makeCall(function, &resultValue);
if (!resultValue || resultValue->type() != JSONValue::TypeObject) {
if (!resultValue->asString(errorString))
*errorString = "Internal error";
return;
}
*result = FunctionDetails::runtimeCast(resultValue);
}
void InjectedScript::getCollectionEntries(ErrorString* errorString, const String& objectId, RefPtr<Array<CollectionEntry> >* result)
{
ScriptFunctionCall function(injectedScriptObject(), "getCollectionEntries");
function.appendArgument(objectId);
RefPtr<JSONValue> resultValue;
makeCall(function, &resultValue);
if (!resultValue || resultValue->type() != JSONValue::TypeArray) {
if (!resultValue->asString(errorString))
*errorString = "Internal error";
return;
}
*result = Array<CollectionEntry>::runtimeCast(resultValue);
}
void InjectedScript::getProperties(ErrorString* errorString, const String& objectId, bool ownProperties, bool accessorPropertiesOnly, RefPtr<Array<PropertyDescriptor> >* properties)
{
ScriptFunctionCall function(injectedScriptObject(), "getProperties");
function.appendArgument(objectId);
function.appendArgument(ownProperties);
function.appendArgument(accessorPropertiesOnly);
RefPtr<JSONValue> result;
makeCall(function, &result);
if (!result || result->type() != JSONValue::TypeArray) {
*errorString = "Internal error";
return;
}
*properties = Array<PropertyDescriptor>::runtimeCast(result);
}
void InjectedScript::getInternalProperties(ErrorString* errorString, const String& objectId, RefPtr<Array<InternalPropertyDescriptor> >* properties)
{
ScriptFunctionCall function(injectedScriptObject(), "getInternalProperties");
function.appendArgument(objectId);
RefPtr<JSONValue> result;
makeCall(function, &result);
if (!result || result->type() != JSONValue::TypeArray) {
*errorString = "Internal error";
return;
}
RefPtr<Array<InternalPropertyDescriptor> > array = Array<InternalPropertyDescriptor>::runtimeCast(result);
if (array->length() > 0)
*properties = array;
}
Node* InjectedScript::nodeForObjectId(const String& objectId)
{
if (isEmpty())
return 0;
ScriptFunctionCall function(injectedScriptObject(), "nodeForObjectId");
function.appendArgument(objectId);
bool hadException = false;
ScriptValue resultValue = callFunctionWithEvalEnabled(function, hadException);
ASSERT(!hadException);
return InjectedScriptHost::scriptValueAsNode(scriptState(), resultValue);
}
void InjectedScript::releaseObject(const String& objectId)
{
ScriptFunctionCall function(injectedScriptObject(), "releaseObject");
function.appendArgument(objectId);
RefPtr<JSONValue> result;
makeCall(function, &result);
}
PassRefPtr<Array<CallFrame> > InjectedScript::wrapCallFrames(const ScriptValue& callFrames, int asyncOrdinal)
{
ASSERT(!isEmpty());
ScriptFunctionCall function(injectedScriptObject(), "wrapCallFrames");
function.appendArgument(callFrames);
function.appendArgument(asyncOrdinal);
bool hadException = false;
ScriptValue callFramesValue = callFunctionWithEvalEnabled(function, hadException);
ASSERT(!hadException);
RefPtr<JSONValue> result = callFramesValue.toJSONValue(scriptState());
if (result && result->type() == JSONValue::TypeArray)
return Array<CallFrame>::runtimeCast(result);
return Array<CallFrame>::create();
}
PassRefPtr<TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapObject(const ScriptValue& value, const String& groupName, bool generatePreview) const
{
ASSERT(!isEmpty());
ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapObject");
wrapFunction.appendArgument(value);
wrapFunction.appendArgument(groupName);
wrapFunction.appendArgument(true);
wrapFunction.appendArgument(generatePreview);
bool hadException = false;
ScriptValue r = callFunctionWithEvalEnabled(wrapFunction, hadException);
if (hadException)
return nullptr;
RefPtr<JSONObject> rawResult = r.toJSONValue(scriptState())->asObject();
return TypeBuilder::Runtime::RemoteObject::runtimeCast(rawResult);
}
PassRefPtr<TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapTable(const ScriptValue& table, const ScriptValue& columns) const
{
ASSERT(!isEmpty());
ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapTable");
wrapFunction.appendArgument(true);
wrapFunction.appendArgument(table);
if (columns.isEmpty())
wrapFunction.appendArgument(false);
else
wrapFunction.appendArgument(columns);
bool hadException = false;
ScriptValue r = callFunctionWithEvalEnabled(wrapFunction, hadException);
if (hadException)
return nullptr;
RefPtr<JSONObject> rawResult = r.toJSONValue(scriptState())->asObject();
return TypeBuilder::Runtime::RemoteObject::runtimeCast(rawResult);
}
PassRefPtr<TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapNode(Node* node, const String& groupName)
{
return wrapObject(nodeAsScriptValue(node), groupName);
}
ScriptValue InjectedScript::findObjectById(const String& objectId) const
{
ASSERT(!isEmpty());
ScriptFunctionCall function(injectedScriptObject(), "findObjectById");
function.appendArgument(objectId);
bool hadException = false;
ScriptValue resultValue = callFunctionWithEvalEnabled(function, hadException);
ASSERT(!hadException);
return resultValue;
}
void InjectedScript::inspectNode(Node* node)
{
ASSERT(!isEmpty());
ScriptFunctionCall function(injectedScriptObject(), "inspectNode");
function.appendArgument(nodeAsScriptValue(node));
RefPtr<JSONValue> result;
makeCall(function, &result);
}
void InjectedScript::releaseObjectGroup(const String& objectGroup)
{
ASSERT(!isEmpty());
ScriptFunctionCall releaseFunction(injectedScriptObject(), "releaseObjectGroup");
releaseFunction.appendArgument(objectGroup);
bool hadException = false;
callFunctionWithEvalEnabled(releaseFunction, hadException);
ASSERT(!hadException);
}
ScriptValue InjectedScript::nodeAsScriptValue(Node* node)
{
return InjectedScriptHost::nodeAsScriptValue(scriptState(), node);
}
} // namespace blink

View File

@ -0,0 +1,116 @@
/*
* Copyright (C) 2012 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.
*/
#ifndef InjectedScript_h
#define InjectedScript_h
#include "bindings/core/v8/ScriptValue.h"
#include "core/InspectorTypeBuilder.h"
#include "core/inspector/InjectedScriptBase.h"
#include "core/inspector/InjectedScriptManager.h"
#include "core/inspector/ScriptArguments.h"
#include "wtf/Forward.h"
#include "wtf/Vector.h"
namespace blink {
class InjectedScriptModule;
class Node;
class SerializedScriptValue;
class InjectedScript final : public InjectedScriptBase {
public:
InjectedScript();
virtual ~InjectedScript() { }
void evaluate(
ErrorString*,
const String& expression,
const String& objectGroup,
bool includeCommandLineAPI,
bool returnByValue,
bool generatePreview,
RefPtr<TypeBuilder::Runtime::RemoteObject>* result,
TypeBuilder::OptOutput<bool>* wasThrown,
RefPtr<TypeBuilder::Debugger::ExceptionDetails>*);
void callFunctionOn(
ErrorString*,
const String& objectId,
const String& expression,
const String& arguments,
bool returnByValue,
bool generatePreview,
RefPtr<TypeBuilder::Runtime::RemoteObject>* result,
TypeBuilder::OptOutput<bool>* wasThrown);
void evaluateOnCallFrame(
ErrorString*,
const ScriptValue& callFrames,
const Vector<ScriptValue>& asyncCallStacks,
const String& callFrameId,
const String& expression,
const String& objectGroup,
bool includeCommandLineAPI,
bool returnByValue,
bool generatePreview,
RefPtr<TypeBuilder::Runtime::RemoteObject>* result,
TypeBuilder::OptOutput<bool>* wasThrown,
RefPtr<TypeBuilder::Debugger::ExceptionDetails>*);
void restartFrame(ErrorString*, const ScriptValue& callFrames, const String& callFrameId, RefPtr<JSONObject>* result);
void getStepInPositions(ErrorString*, const ScriptValue& callFrames, const String& callFrameId, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::Location> >& positions);
void setVariableValue(ErrorString*, const ScriptValue& callFrames, const String* callFrameIdOpt, const String* functionObjectIdOpt, int scopeNumber, const String& variableName, const String& newValueStr);
void getFunctionDetails(ErrorString*, const String& functionId, RefPtr<TypeBuilder::Debugger::FunctionDetails>* result);
void getCollectionEntries(ErrorString*, const String& objectId, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CollectionEntry> >* result);
void getProperties(ErrorString*, const String& objectId, bool ownProperties, bool accessorPropertiesOnly, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::PropertyDescriptor> >* result);
void getInternalProperties(ErrorString*, const String& objectId, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::InternalPropertyDescriptor> >* result);
Node* nodeForObjectId(const String& objectId);
void releaseObject(const String& objectId);
PassRefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame> > wrapCallFrames(const ScriptValue&, int asyncOrdinal);
PassRefPtr<TypeBuilder::Runtime::RemoteObject> wrapObject(const ScriptValue&, const String& groupName, bool generatePreview = false) const;
PassRefPtr<TypeBuilder::Runtime::RemoteObject> wrapTable(const ScriptValue& table, const ScriptValue& columns) const;
PassRefPtr<TypeBuilder::Runtime::RemoteObject> wrapNode(Node*, const String& groupName);
ScriptValue findObjectById(const String& objectId) const;
void inspectNode(Node*);
void releaseObjectGroup(const String&);
private:
friend class InjectedScriptModule;
friend InjectedScript InjectedScriptManager::injectedScriptFor(ScriptState*);
explicit InjectedScript(ScriptValue);
ScriptValue nodeAsScriptValue(Node*);
};
} // namespace blink
#endif

View File

@ -0,0 +1,192 @@
/*
* Copyright (C) 2012 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 "config.h"
#include "core/inspector/InjectedScriptBase.h"
#include "bindings/core/v8/ScriptFunctionCall.h"
#include "core/inspector/InspectorTraceEvents.h"
#include "platform/JSONValues.h"
#include "wtf/text/WTFString.h"
using blink::TypeBuilder::Array;
using blink::TypeBuilder::Runtime::RemoteObject;
namespace blink {
static PassRefPtr<TypeBuilder::Debugger::ExceptionDetails> toExceptionDetails(PassRefPtr<JSONObject> object)
{
String text;
if (!object->getString("text", &text))
return nullptr;
RefPtr<TypeBuilder::Debugger::ExceptionDetails> exceptionDetails = TypeBuilder::Debugger::ExceptionDetails::create().setText(text);
String url;
if (object->getString("url", &url))
exceptionDetails->setUrl(url);
int line = 0;
if (object->getNumber("line", &line))
exceptionDetails->setLine(line);
int column = 0;
if (object->getNumber("column", &column))
exceptionDetails->setColumn(column);
RefPtr<JSONArray> stackTrace = object->getArray("stackTrace");
if (stackTrace && stackTrace->length() > 0) {
RefPtr<TypeBuilder::Array<TypeBuilder::Console::CallFrame> > frames = TypeBuilder::Array<TypeBuilder::Console::CallFrame>::create();
for (unsigned i = 0; i < stackTrace->length(); ++i) {
RefPtr<JSONObject> stackFrame = stackTrace->get(i)->asObject();
int lineNumber = 0;
stackFrame->getNumber("lineNumber", &lineNumber);
int column = 0;
stackFrame->getNumber("column", &column);
int scriptId = 0;
stackFrame->getNumber("scriptId", &scriptId);
String sourceURL;
stackFrame->getString("scriptNameOrSourceURL", &sourceURL);
String functionName;
stackFrame->getString("functionName", &functionName);
RefPtr<TypeBuilder::Console::CallFrame> callFrame = TypeBuilder::Console::CallFrame::create()
.setFunctionName(functionName)
.setScriptId(String::number(scriptId))
.setUrl(sourceURL)
.setLineNumber(lineNumber)
.setColumnNumber(column);
frames->addItem(callFrame.release());
}
exceptionDetails->setStackTrace(frames.release());
}
return exceptionDetails.release();
}
InjectedScriptBase::InjectedScriptBase(const String& name)
: m_name(name)
{
}
InjectedScriptBase::InjectedScriptBase(const String& name, ScriptValue injectedScriptObject)
: m_name(name)
, m_injectedScriptObject(injectedScriptObject)
{
}
void InjectedScriptBase::initialize(ScriptValue injectedScriptObject)
{
m_injectedScriptObject = injectedScriptObject;
}
const ScriptValue& InjectedScriptBase::injectedScriptObject() const
{
return m_injectedScriptObject;
}
ScriptValue InjectedScriptBase::callFunctionWithEvalEnabled(ScriptFunctionCall& function, bool& hadException) const
{
ASSERT(!isEmpty());
ExecutionContext* executionContext = m_injectedScriptObject.scriptState()->executionContext();
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "FunctionCall", "data", InspectorFunctionCallEvent::data(executionContext, 0, name(), 1));
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", TRACE_EVENT_SCOPE_PROCESS, "stack", InspectorCallStackEvent::currentCallStack());
ScriptState* scriptState = m_injectedScriptObject.scriptState();
bool evalIsDisabled = false;
if (scriptState) {
evalIsDisabled = !scriptState->evalEnabled();
// Temporarily enable allow evals for inspector.
if (evalIsDisabled)
scriptState->setEvalEnabled(true);
}
ScriptValue resultValue = function.call(hadException);
if (evalIsDisabled)
scriptState->setEvalEnabled(false);
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", TRACE_EVENT_SCOPE_PROCESS, "data", InspectorUpdateCountersEvent::data());
return resultValue;
}
void InjectedScriptBase::makeCall(ScriptFunctionCall& function, RefPtr<JSONValue>* result)
{
if (isEmpty()) {
*result = JSONValue::null();
return;
}
bool hadException = false;
ScriptValue resultValue = callFunctionWithEvalEnabled(function, hadException);
ASSERT(!hadException);
if (!hadException) {
*result = resultValue.toJSONValue(m_injectedScriptObject.scriptState());
if (!*result)
*result = JSONString::create(String::format("Object has too long reference chain(must not be longer than %d)", JSONValue::maxDepth));
} else {
*result = JSONString::create("Exception while making a call.");
}
}
void InjectedScriptBase::makeEvalCall(ErrorString* errorString, ScriptFunctionCall& function, RefPtr<TypeBuilder::Runtime::RemoteObject>* objectResult, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* exceptionDetails)
{
RefPtr<JSONValue> result;
makeCall(function, &result);
if (!result) {
*errorString = "Internal error: result value is empty";
return;
}
if (result->type() == JSONValue::TypeString) {
result->asString(errorString);
ASSERT(errorString->length());
return;
}
RefPtr<JSONObject> resultPair = result->asObject();
if (!resultPair) {
*errorString = "Internal error: result is not an Object";
return;
}
RefPtr<JSONObject> resultObj = resultPair->getObject("result");
bool wasThrownVal = false;
if (!resultObj || !resultPair->getBoolean("wasThrown", &wasThrownVal)) {
*errorString = "Internal error: result is not a pair of value and wasThrown flag";
return;
}
if (wasThrownVal) {
RefPtr<JSONObject> objectExceptionDetails = resultPair->getObject("exceptionDetails");
if (objectExceptionDetails)
*exceptionDetails = toExceptionDetails(objectExceptionDetails.release());
}
*objectResult = TypeBuilder::Runtime::RemoteObject::runtimeCast(resultObj);
*wasThrown = wasThrownVal;
}
} // namespace blink

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2012 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.
*/
#ifndef InjectedScriptBase_h
#define InjectedScriptBase_h
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/ScriptValue.h"
#include "core/InspectorTypeBuilder.h"
#include "wtf/Forward.h"
namespace blink {
class JSONValue;
class ScriptFunctionCall;
typedef String ErrorString;
class InjectedScriptBase {
public:
virtual ~InjectedScriptBase() { }
const String& name() const { return m_name; }
bool isEmpty() const { return m_injectedScriptObject.isEmpty(); }
ScriptState* scriptState() const
{
ASSERT(!isEmpty());
return m_injectedScriptObject.scriptState();
}
protected:
explicit InjectedScriptBase(const String& name);
InjectedScriptBase(const String& name, ScriptValue);
void initialize(ScriptValue);
const ScriptValue& injectedScriptObject() const;
ScriptValue callFunctionWithEvalEnabled(ScriptFunctionCall&, bool& hadException) const;
void makeCall(ScriptFunctionCall&, RefPtr<JSONValue>* result);
void makeEvalCall(ErrorString*, ScriptFunctionCall&, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* = 0);
private:
String m_name;
ScriptValue m_injectedScriptObject;
};
} // namespace blink
#endif

View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
* Copyright (C) 2010 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h"
#include "core/inspector/InjectedScriptHost.h"
#include "core/inspector/InspectorDebuggerAgent.h"
#include "core/inspector/InstrumentingAgents.h"
#include "platform/JSONValues.h"
#include "wtf/RefPtr.h"
#include "wtf/text/StringBuilder.h"
namespace blink {
PassRefPtr<InjectedScriptHost> InjectedScriptHost::create()
{
return adoptRef(new InjectedScriptHost());
}
InjectedScriptHost::InjectedScriptHost()
: m_instrumentingAgents(nullptr)
, m_scriptDebugServer(0)
{
m_defaultInspectableObject = adoptPtr(new InspectableObject());
}
InjectedScriptHost::~InjectedScriptHost()
{
}
void InjectedScriptHost::disconnect()
{
m_instrumentingAgents = nullptr;
m_scriptDebugServer = 0;
}
void InjectedScriptHost::inspectImpl(PassRefPtr<JSONValue> object, PassRefPtr<JSONValue> hints)
{
// FIXME(sky)
}
void InjectedScriptHost::getEventListenersImpl(EventTarget* target, Vector<EventListenerInfo>& listenersArray)
{
// FIXME(sky)
}
void InjectedScriptHost::clearConsoleMessages()
{
// FIXME(sky)
}
ScriptValue InjectedScriptHost::InspectableObject::get(ScriptState*)
{
return ScriptValue();
};
void InjectedScriptHost::addInspectedObject(PassOwnPtr<InjectedScriptHost::InspectableObject> object)
{
m_inspectedObjects.prepend(object);
while (m_inspectedObjects.size() > 5)
m_inspectedObjects.removeLast();
}
void InjectedScriptHost::clearInspectedObjects()
{
m_inspectedObjects.clear();
}
InjectedScriptHost::InspectableObject* InjectedScriptHost::inspectedObject(unsigned num)
{
if (num >= m_inspectedObjects.size())
return m_defaultInspectableObject.get();
return m_inspectedObjects[num].get();
}
void InjectedScriptHost::debugFunction(const String& scriptId, int lineNumber, int columnNumber)
{
if (InspectorDebuggerAgent* debuggerAgent = m_instrumentingAgents ? m_instrumentingAgents->inspectorDebuggerAgent() : 0)
debuggerAgent->setBreakpoint(scriptId, lineNumber, columnNumber, InspectorDebuggerAgent::DebugCommandBreakpointSource);
}
void InjectedScriptHost::undebugFunction(const String& scriptId, int lineNumber, int columnNumber)
{
if (InspectorDebuggerAgent* debuggerAgent = m_instrumentingAgents ? m_instrumentingAgents->inspectorDebuggerAgent() : 0)
debuggerAgent->removeBreakpoint(scriptId, lineNumber, columnNumber, InspectorDebuggerAgent::DebugCommandBreakpointSource);
}
void InjectedScriptHost::monitorFunction(const String& scriptId, int lineNumber, int columnNumber, const String& functionName)
{
StringBuilder builder;
builder.appendLiteral("console.log(\"function ");
if (functionName.isEmpty())
builder.appendLiteral("(anonymous function)");
else
builder.append(functionName);
builder.appendLiteral(" called\" + (arguments.length > 0 ? \" with arguments: \" + Array.prototype.join.call(arguments, \", \") : \"\")) && false");
if (InspectorDebuggerAgent* debuggerAgent = m_instrumentingAgents ? m_instrumentingAgents->inspectorDebuggerAgent() : 0)
debuggerAgent->setBreakpoint(scriptId, lineNumber, columnNumber, InspectorDebuggerAgent::MonitorCommandBreakpointSource, builder.toString());
}
void InjectedScriptHost::unmonitorFunction(const String& scriptId, int lineNumber, int columnNumber)
{
if (InspectorDebuggerAgent* debuggerAgent = m_instrumentingAgents ? m_instrumentingAgents->inspectorDebuggerAgent() : 0)
debuggerAgent->removeBreakpoint(scriptId, lineNumber, columnNumber, InspectorDebuggerAgent::MonitorCommandBreakpointSource);
}
} // namespace blink

View File

@ -0,0 +1,108 @@
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
* Copyright (C) 2009 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
*/
#ifndef InjectedScriptHost_h
#define InjectedScriptHost_h
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/ScriptWrappable.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/RefCounted.h"
#include "wtf/Vector.h"
#include "wtf/text/WTFString.h"
namespace blink {
class Database;
class EventTarget;
class InjectedScript;
class InstrumentingAgents;
class JSONValue;
class Node;
class ScriptDebugServer;
class ScriptValue;
class Storage;
struct EventListenerInfo;
// SECURITY NOTE: Although the InjectedScriptHost is intended for use solely by the inspector,
// a reference to the InjectedScriptHost may be leaked to the page being inspected. Thus, the
// InjectedScriptHost must never implemment methods that have more power over the page than the
// page already has itself (e.g. origin restriction bypasses).
class InjectedScriptHost : public RefCounted<InjectedScriptHost>, public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
static PassRefPtr<InjectedScriptHost> create();
~InjectedScriptHost();
void init(InstrumentingAgents* instrumentingAgents, ScriptDebugServer* scriptDebugServer)
{
m_instrumentingAgents = instrumentingAgents;
m_scriptDebugServer = scriptDebugServer;
}
static Node* scriptValueAsNode(ScriptState*, ScriptValue);
static ScriptValue nodeAsScriptValue(ScriptState*, Node*);
void disconnect();
class InspectableObject {
WTF_MAKE_FAST_ALLOCATED;
public:
virtual ScriptValue get(ScriptState*);
virtual ~InspectableObject() { }
};
void addInspectedObject(PassOwnPtr<InspectableObject>);
void clearInspectedObjects();
InspectableObject* inspectedObject(unsigned num);
void inspectImpl(PassRefPtr<JSONValue> objectToInspect, PassRefPtr<JSONValue> hints);
void getEventListenersImpl(EventTarget*, Vector<EventListenerInfo>& listenersArray);
void clearConsoleMessages();
void debugFunction(const String& scriptId, int lineNumber, int columnNumber);
void undebugFunction(const String& scriptId, int lineNumber, int columnNumber);
void monitorFunction(const String& scriptId, int lineNumber, int columnNumber, const String& functionName);
void unmonitorFunction(const String& scriptId, int lineNumber, int columnNumber);
ScriptDebugServer& scriptDebugServer() { return *m_scriptDebugServer; }
private:
InjectedScriptHost();
RawPtr<InstrumentingAgents> m_instrumentingAgents;
ScriptDebugServer* m_scriptDebugServer;
Vector<OwnPtr<InspectableObject> > m_inspectedObjects;
OwnPtr<InspectableObject> m_defaultInspectableObject;
};
} // namespace blink
#endif // InjectedScriptHost_h

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
* Copyright (C) 2010 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.
*/
[
NoInterfaceObject
] interface InjectedScriptHost {
[NotEnumerable, Unforgeable] void clearConsoleMessages();
[NotEnumerable, Unforgeable, Custom] void inspect(any objectId, any hints);
[NotEnumerable, Unforgeable, Custom] any inspectedObject(long num);
[NotEnumerable, Unforgeable, Custom] any internalConstructorName(any obj);
[NotEnumerable, Unforgeable, Custom] boolean isHTMLAllCollection(any obj);
[NotEnumerable, Unforgeable, Custom] DOMString subtype(any obj);
[NotEnumerable, Unforgeable, Custom] any functionDetails(any obj);
[NotEnumerable, Unforgeable, Custom] any[] collectionEntries(any obj);
[NotEnumerable, Unforgeable, Custom] any[] getInternalProperties(any obj);
[NotEnumerable, Unforgeable, Custom] EventListener[] getEventListeners(EventTarget target);
[NotEnumerable, Unforgeable, Custom] any eval(DOMString text);
[NotEnumerable, Unforgeable, Custom] any evaluateWithExceptionDetails(DOMString text);
[NotEnumerable, Unforgeable, Custom] void debugFunction(any fn);
[NotEnumerable, Unforgeable, Custom] void undebugFunction(any fn);
[NotEnumerable, Unforgeable, Custom] void monitorFunction(any fn);
[NotEnumerable, Unforgeable, Custom] void unmonitorFunction(any fn);
[NotEnumerable, Unforgeable, Custom] any callFunction(any fn, any receiver, any[] argv);
[NotEnumerable, Unforgeable, Custom] any suppressWarningsAndCallFunction(any fn, any receiver, any[] argv);
// Only declarative scope (local, with and catch) is accepted. Returns undefined.
[NotEnumerable, Unforgeable, Custom] any setFunctionVariableValue(any functionObject, long scopeIndex, DOMString variableName, any newValue);
};

View File

@ -0,0 +1,171 @@
/*
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
* Copyright (C) 2012 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h"
#include "core/inspector/InjectedScriptManager.h"
#include "bindings/core/v8/ScriptValue.h"
#include "core/inspector/InjectedScript.h"
#include "core/inspector/InjectedScriptHost.h"
#include "core/inspector/JSONParser.h"
#include "platform/JSONValues.h"
#include "public/platform/Platform.h"
#include "public/platform/WebData.h"
#include "wtf/PassOwnPtr.h"
namespace blink {
PassOwnPtr<InjectedScriptManager> InjectedScriptManager::createForPage()
{
return adoptPtr(new InjectedScriptManager);
}
InjectedScriptManager::InjectedScriptManager()
: m_nextInjectedScriptId(1)
, m_injectedScriptHost(InjectedScriptHost::create())
{
}
InjectedScriptManager::~InjectedScriptManager()
{
}
void InjectedScriptManager::disconnect()
{
m_injectedScriptHost->disconnect();
m_injectedScriptHost.clear();
}
InjectedScriptHost* InjectedScriptManager::injectedScriptHost()
{
return m_injectedScriptHost.get();
}
InjectedScript InjectedScriptManager::injectedScriptForId(int id)
{
IdToInjectedScriptMap::iterator it = m_idToInjectedScript.find(id);
if (it != m_idToInjectedScript.end())
return it->value;
for (ScriptStateToId::iterator it = m_scriptStateToId.begin(); it != m_scriptStateToId.end(); ++it) {
if (it->value == id)
return injectedScriptFor(it->key.get());
}
return InjectedScript();
}
int InjectedScriptManager::injectedScriptIdFor(ScriptState* scriptState)
{
ScriptStateToId::iterator it = m_scriptStateToId.find(scriptState);
if (it != m_scriptStateToId.end())
return it->value;
int id = m_nextInjectedScriptId++;
m_scriptStateToId.set(scriptState, id);
return id;
}
InjectedScript InjectedScriptManager::injectedScriptForObjectId(const String& objectId)
{
RefPtr<JSONValue> parsedObjectId = parseJSON(objectId);
if (parsedObjectId && parsedObjectId->type() == JSONValue::TypeObject) {
long injectedScriptId = 0;
bool success = parsedObjectId->asObject()->getNumber("injectedScriptId", &injectedScriptId);
if (success)
return m_idToInjectedScript.get(injectedScriptId);
}
return InjectedScript();
}
void InjectedScriptManager::discardInjectedScripts()
{
m_idToInjectedScript.clear();
m_scriptStateToId.clear();
}
void InjectedScriptManager::discardInjectedScriptsFor(LocalDOMWindow* window)
{
if (m_scriptStateToId.isEmpty())
return;
Vector<long> idsToRemove;
IdToInjectedScriptMap::iterator end = m_idToInjectedScript.end();
for (IdToInjectedScriptMap::iterator it = m_idToInjectedScript.begin(); it != end; ++it) {
ScriptState* scriptState = it->value.scriptState();
if (window != scriptState->domWindow())
continue;
m_scriptStateToId.remove(scriptState);
idsToRemove.append(it->key);
}
m_idToInjectedScript.removeAll(idsToRemove);
// Now remove script states that have id but no injected script.
Vector<ScriptState*> scriptStatesToRemove;
for (ScriptStateToId::iterator it = m_scriptStateToId.begin(); it != m_scriptStateToId.end(); ++it) {
ScriptState* scriptState = it->key.get();
if (window == scriptState->domWindow())
scriptStatesToRemove.append(scriptState);
}
m_scriptStateToId.removeAll(scriptStatesToRemove);
}
void InjectedScriptManager::releaseObjectGroup(const String& objectGroup)
{
Vector<int> keys;
keys.appendRange(m_idToInjectedScript.keys().begin(), m_idToInjectedScript.keys().end());
for (Vector<int>::iterator k = keys.begin(); k != keys.end(); ++k) {
IdToInjectedScriptMap::iterator s = m_idToInjectedScript.find(*k);
if (s != m_idToInjectedScript.end())
s->value.releaseObjectGroup(objectGroup); // m_idToInjectedScript may change here.
}
}
String InjectedScriptManager::injectedScriptSource()
{
const blink::WebData& injectedScriptSourceResource = blink::Platform::current()->loadResource("InjectedScriptSource.js");
return String(injectedScriptSourceResource.data(), injectedScriptSourceResource.size());
}
InjectedScript InjectedScriptManager::injectedScriptFor(ScriptState* inspectedScriptState)
{
ScriptStateToId::iterator it = m_scriptStateToId.find(inspectedScriptState);
if (it != m_scriptStateToId.end()) {
IdToInjectedScriptMap::iterator it1 = m_idToInjectedScript.find(it->value);
if (it1 != m_idToInjectedScript.end())
return it1->value;
}
int id = injectedScriptIdFor(inspectedScriptState);
ScriptValue injectedScriptValue = createInjectedScript(injectedScriptSource(), inspectedScriptState, id);
InjectedScript result(injectedScriptValue);
m_idToInjectedScript.set(id, result);
return result;
}
} // namespace blink

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
* Copyright (C) 2012 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
*/
#ifndef InjectedScriptManager_h
#define InjectedScriptManager_h
#include "bindings/core/v8/ScriptState.h"
#include "wtf/Forward.h"
#include "wtf/HashMap.h"
#include "wtf/HashSet.h"
#include "wtf/text/WTFString.h"
#include <v8.h>
namespace blink {
class LocalDOMWindow;
class InjectedScript;
class InjectedScriptHost;
class ScriptValue;
class InjectedScriptManager {
WTF_MAKE_NONCOPYABLE(InjectedScriptManager);
WTF_MAKE_FAST_ALLOCATED;
public:
struct CallbackData {
ScopedPersistent<v8::Object> handle;
RefPtr<InjectedScriptHost> host;
InjectedScriptManager* injectedScriptManager;
};
static PassOwnPtr<InjectedScriptManager> createForPage();
~InjectedScriptManager();
void disconnect();
InjectedScriptHost* injectedScriptHost();
InjectedScript injectedScriptFor(ScriptState*);
InjectedScript injectedScriptForId(int);
int injectedScriptIdFor(ScriptState*);
InjectedScript injectedScriptForObjectId(const String& objectId);
void discardInjectedScripts();
void discardInjectedScriptsFor(LocalDOMWindow*);
void releaseObjectGroup(const String& objectGroup);
static void setWeakCallback(const v8::WeakCallbackData<v8::Object, CallbackData>&);
CallbackData* createCallbackData(InjectedScriptManager*);
void removeCallbackData(CallbackData*);
private:
explicit InjectedScriptManager();
String injectedScriptSource();
ScriptValue createInjectedScript(const String& source, ScriptState*, int id);
int m_nextInjectedScriptId;
typedef HashMap<int, InjectedScript> IdToInjectedScriptMap;
IdToInjectedScriptMap m_idToInjectedScript;
RefPtr<InjectedScriptHost> m_injectedScriptHost;
typedef HashMap<RefPtr<ScriptState>, int> ScriptStateToId;
ScriptStateToId m_scriptStateToId;
HashSet<OwnPtr<CallbackData> > m_callbackDataSet;
};
} // namespace blink
#endif // !defined(InjectedScriptManager_h)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 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 "config.h"
#include "core/inspector/InspectorBaseAgent.h"
#include "core/inspector/InspectorState.h"
#include "wtf/PassOwnPtr.h"
namespace blink {
InspectorAgent::InspectorAgent(const String& name)
: m_name(name)
{
}
InspectorAgent::~InspectorAgent()
{
}
void InspectorAgent::init(InstrumentingAgents* agents,
InspectorState* inspectorState)
{
m_instrumentingAgents = agents;
m_state = inspectorState;
virtualInit();
}
} // namespace blink

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 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.
*/
#ifndef InspectorBaseAgent_h
#define InspectorBaseAgent_h
#include "core/InspectorBackendDispatcher.h"
#include "platform/heap/Handle.h"
#include "wtf/Forward.h"
#include "wtf/Vector.h"
#include "wtf/text/WTFString.h"
namespace blink {
class InspectorFrontend;
class InspectorCompositeState;
class InspectorState;
class InstrumentingAgents;
class InspectorAgent {
public:
explicit InspectorAgent(const String&);
virtual ~InspectorAgent();
void init(InstrumentingAgents* agents, InspectorState* inspectorState);
virtual void setFrontend(InspectorFrontend*) { }
virtual void clearFrontend() { }
virtual void restore() { }
virtual void discardAgent() { }
virtual void didCommitLoadForMainFrame() { }
virtual void flushPendingFrontendMessages() { }
private:
virtual void virtualInit() { }
String name() { return m_name; }
protected:
RawPtr<InstrumentingAgents> m_instrumentingAgents;
RawPtr<InspectorState> m_state;
private:
String m_name;
};
template<typename T>
class InspectorBaseAgent : public InspectorAgent {
public:
virtual ~InspectorBaseAgent() { }
protected:
explicit InspectorBaseAgent(const String& name) : InspectorAgent(name)
{
}
};
inline bool asBool(const bool* const b)
{
return b ? *b : false;
}
} // namespace blink
#endif // !defined(InspectorBaseAgent_h)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,275 @@
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
* 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
*/
#ifndef InspectorDebuggerAgent_h
#define InspectorDebuggerAgent_h
#include "bindings/core/v8/ScriptState.h"
#include "core/InspectorFrontend.h"
#include "core/frame/ConsoleTypes.h"
#include "core/inspector/AsyncCallStackTracker.h"
#include "core/inspector/ConsoleAPITypes.h"
#include "core/inspector/InjectedScript.h"
#include "core/inspector/InspectorBaseAgent.h"
#include "core/inspector/PromiseTracker.h"
#include "core/inspector/ScriptBreakpoint.h"
#include "core/inspector/ScriptDebugListener.h"
#include "wtf/Forward.h"
#include "wtf/HashMap.h"
#include "wtf/PassRefPtr.h"
#include "wtf/Vector.h"
#include "wtf/text/StringHash.h"
namespace blink {
class ConsoleMessage;
class Document;
class Event;
class EventListener;
class EventTarget;
class FormData;
class HTTPHeaderMap;
class InjectedScriptManager;
class InspectorFrontend;
class InstrumentingAgents;
class JavaScriptCallFrame;
class JSONObject;
class KURL;
class MutationObserver;
class ScriptArguments;
class ScriptAsyncCallStack;
class ScriptCallStack;
class ScriptDebugServer;
class ScriptRegexp;
class ScriptSourceCode;
class ScriptValue;
class ThreadableLoaderClient;
class XMLHttpRequest;
typedef String ErrorString;
class InspectorDebuggerAgent : public InspectorBaseAgent<InspectorDebuggerAgent>, public ScriptDebugListener, public InspectorBackendDispatcher::DebuggerCommandHandler {
WTF_MAKE_NONCOPYABLE(InspectorDebuggerAgent);
WTF_MAKE_FAST_ALLOCATED;
public:
enum BreakpointSource {
UserBreakpointSource,
DebugCommandBreakpointSource,
MonitorCommandBreakpointSource
};
static const char backtraceObjectGroup[];
virtual ~InspectorDebuggerAgent();
virtual void canSetScriptSource(ErrorString*, bool* result) override final { *result = true; }
virtual void virtualInit() override final;
virtual void setFrontend(InspectorFrontend*) override final;
virtual void clearFrontend() override final;
virtual void restore() override final;
bool isPaused();
bool runningNestedMessageLoop();
void addMessageToConsole(ConsoleMessage*);
String preprocessEventListener(LocalFrame*, const String& source, const String& url, const String& functionName);
PassOwnPtr<ScriptSourceCode> preprocess(LocalFrame*, const ScriptSourceCode&);
// Part of the protocol.
virtual void enable(ErrorString*) override final;
virtual void disable(ErrorString*) override final;
virtual void setBreakpointsActive(ErrorString*, bool active) override final;
virtual void setSkipAllPauses(ErrorString*, bool skipped, const bool* untilReload) override final;
virtual void setBreakpointByUrl(ErrorString*, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const String* optionalCondition, const bool* isAntiBreakpoint, TypeBuilder::Debugger::BreakpointId*, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::Location> >& locations) override final;
virtual void setBreakpoint(ErrorString*, const RefPtr<JSONObject>& location, const String* optionalCondition, TypeBuilder::Debugger::BreakpointId*, RefPtr<TypeBuilder::Debugger::Location>& actualLocation) override final;
virtual void removeBreakpoint(ErrorString*, const String& breakpointId) override final;
virtual void continueToLocation(ErrorString*, const RefPtr<JSONObject>& location, const bool* interstateLocationOpt) override final;
virtual void getStepInPositions(ErrorString*, const String& callFrameId, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::Location> >& positions) override final;
virtual void getBacktrace(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame> >&, RefPtr<TypeBuilder::Debugger::StackTrace>&) override final;
virtual void searchInContent(ErrorString*, const String& scriptId, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> >&) override final;
virtual void setScriptSource(ErrorString*, RefPtr<TypeBuilder::Debugger::SetScriptSourceError>&, const String& scriptId, const String& newContent, const bool* preview, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame> >& newCallFrames, RefPtr<JSONObject>& result, RefPtr<TypeBuilder::Debugger::StackTrace>& asyncStackTrace) override final;
virtual void restartFrame(ErrorString*, const String& callFrameId, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame> >& newCallFrames, RefPtr<JSONObject>& result, RefPtr<TypeBuilder::Debugger::StackTrace>& asyncStackTrace) override final;
virtual void getScriptSource(ErrorString*, const String& scriptId, String* scriptSource) override final;
virtual void getFunctionDetails(ErrorString*, const String& functionId, RefPtr<TypeBuilder::Debugger::FunctionDetails>&) override final;
virtual void getCollectionEntries(ErrorString*, const String& objectId, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CollectionEntry> >&) override final;
virtual void pause(ErrorString*) override final;
virtual void resume(ErrorString*) override final;
virtual void stepOver(ErrorString*) override final;
virtual void stepInto(ErrorString*) override final;
virtual void stepOut(ErrorString*) override final;
virtual void setPauseOnExceptions(ErrorString*, const String& pauseState) override final;
virtual void evaluateOnCallFrame(ErrorString*,
const String& callFrameId,
const String& expression,
const String* objectGroup,
const bool* includeCommandLineAPI,
const bool* doNotPauseOnExceptionsAndMuteConsole,
const bool* returnByValue,
const bool* generatePreview,
RefPtr<TypeBuilder::Runtime::RemoteObject>& result,
TypeBuilder::OptOutput<bool>* wasThrown,
RefPtr<TypeBuilder::Debugger::ExceptionDetails>&) override final;
virtual void compileScript(ErrorString*, const String& expression, const String& sourceURL, const int* executionContextId, TypeBuilder::OptOutput<TypeBuilder::Debugger::ScriptId>*, RefPtr<TypeBuilder::Debugger::ExceptionDetails>&) override;
virtual void runScript(ErrorString*, const TypeBuilder::Debugger::ScriptId&, const int* executionContextId, const String* objectGroup, const bool* doNotPauseOnExceptionsAndMuteConsole, RefPtr<TypeBuilder::Runtime::RemoteObject>& result, RefPtr<TypeBuilder::Debugger::ExceptionDetails>&) override;
virtual void setOverlayMessage(ErrorString*, const String*) override;
virtual void setVariableValue(ErrorString*, int in_scopeNumber, const String& in_variableName, const RefPtr<JSONObject>& in_newValue, const String* in_callFrame, const String* in_functionObjectId) override final;
virtual void skipStackFrames(ErrorString*, const String* pattern) override final;
virtual void setAsyncCallStackDepth(ErrorString*, int depth) override final;
void schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data);
void didInstallTimer(ExecutionContext*, int timerId, int timeout, bool singleShot);
void didRemoveTimer(ExecutionContext*, int timerId);
bool willFireTimer(ExecutionContext*, int timerId);
void didFireTimer();
void didRequestAnimationFrame(Document*, int callbackId);
void didCancelAnimationFrame(Document*, int callbackId);
bool willFireAnimationFrame(Document*, int callbackId);
void didFireAnimationFrame();
void didEnqueueEvent(EventTarget*, Event*);
void didRemoveEvent(EventTarget*, Event*);
void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture);
void didHandleEvent();
void didEnqueueMutationRecord(ExecutionContext*, MutationObserver*);
void didClearAllMutationRecords(ExecutionContext*, MutationObserver*);
void willDeliverMutationRecords(ExecutionContext*, MutationObserver*);
void didDeliverMutationRecords();
// void didPostExecutionContextTask(ExecutionContext*, ExecutionContextTask*);
// void didKillAllExecutionContextTasks(ExecutionContext*);
// void willPerformExecutionContextTask(ExecutionContext*, ExecutionContextTask*);
// void didPerformExecutionContextTask();
int traceAsyncOperationStarting(ExecutionContext*, const String& operationName, int prevOperationId = 0);
void traceAsyncOperationCompleted(ExecutionContext*, int operationId);
void traceAsyncOperationCompletedCallbackStarting(ExecutionContext*, int operationId);
void traceAsyncCallbackStarting(ExecutionContext*, int operationId);
void traceAsyncCallbackCompleted();
bool canBreakProgram();
void breakProgram(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data);
void scriptExecutionBlockedByCSP(const String& directiveText);
class Listener {
public:
virtual ~Listener() { }
virtual void debuggerWasEnabled() = 0;
virtual void debuggerWasDisabled() = 0;
virtual void stepInto() = 0;
virtual void didPause() = 0;
};
void setListener(Listener* listener) { m_listener = listener; }
bool enabled();
virtual ScriptDebugServer& scriptDebugServer() = 0;
void setBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource, const String& condition = String());
void removeBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource);
PassRefPtr<ScriptAsyncCallStack> currentAsyncStackTraceForConsole();
protected:
explicit InspectorDebuggerAgent(InjectedScriptManager*);
virtual void startListeningScriptDebugServer() = 0;
virtual void stopListeningScriptDebugServer() = 0;
virtual void muteConsole() = 0;
virtual void unmuteConsole() = 0;
InjectedScriptManager* injectedScriptManager() { return m_injectedScriptManager; }
virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId) = 0;
virtual void enable();
virtual void disable();
virtual SkipPauseRequest didPause(ScriptState*, const ScriptValue& callFrames, const ScriptValue& exception, const Vector<String>& hitBreakpoints) override final;
virtual void didContinue() override final;
void reset();
void pageDidCommitLoad();
private:
bool shouldSkipInspectorInternals();
SkipPauseRequest shouldSkipExceptionPause();
SkipPauseRequest shouldSkipStepPause();
bool isTopCallFrameInFramework();
void cancelPauseOnNextStatement();
void addMessageToConsole(MessageSource, MessageType);
PassRefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame> > currentCallFrames();
PassRefPtr<TypeBuilder::Debugger::StackTrace> currentAsyncStackTrace();
virtual void didParseSource(const String& scriptId, const Script&, CompileResult) override final;
virtual void didReceiveV8AsyncTaskEvent(ExecutionContext*, const String& eventType, const String& eventName, int id) override final;
virtual void didReceiveV8PromiseEvent(ScriptState*, v8::Handle<v8::Object> promise, v8::Handle<v8::Value> parentPromise, int status) override final;
void setPauseOnExceptionsImpl(ErrorString*, int);
PassRefPtr<TypeBuilder::Debugger::Location> resolveBreakpoint(const String& breakpointId, const String& scriptId, const ScriptBreakpoint&, BreakpointSource);
void removeBreakpoint(const String& breakpointId);
void clear();
bool assertPaused(ErrorString*);
void clearBreakDetails();
String sourceMapURLForScript(const Script&, CompileResult);
PassRefPtr<JavaScriptCallFrame> topCallFrameSkipUnknownSources();
String scriptURL(JavaScriptCallFrame*);
AsyncCallStackTracker& asyncCallStackTracker() { return *m_asyncCallStackTracker; };
typedef HashMap<String, Script> ScriptsMap;
typedef HashMap<String, Vector<String> > BreakpointIdToDebugServerBreakpointIdsMap;
typedef HashMap<String, std::pair<String, BreakpointSource> > DebugServerBreakpointToBreakpointIdAndSourceMap;
RawPtr<InjectedScriptManager> m_injectedScriptManager;
InspectorFrontend::Debugger* m_frontend;
RefPtr<ScriptState> m_pausedScriptState;
ScriptValue m_currentCallStack;
ScriptsMap m_scripts;
BreakpointIdToDebugServerBreakpointIdsMap m_breakpointIdToDebugServerBreakpointIds;
DebugServerBreakpointToBreakpointIdAndSourceMap m_serverBreakpoints;
String m_continueToLocationBreakpointId;
InspectorFrontend::Debugger::Reason::Enum m_breakReason;
RefPtr<JSONObject> m_breakAuxData;
bool m_javaScriptPauseScheduled;
bool m_debuggerStepScheduled;
bool m_steppingFromFramework;
bool m_pausingOnNativeEvent;
RawPtr<Listener> m_listener;
int m_skippedStepInCount;
int m_minFrameCountForSkip;
bool m_skipAllPauses;
OwnPtr<ScriptRegexp> m_cachedSkipStackRegExp;
OwnPtr<AsyncCallStackTracker> m_asyncCallStackTracker;
PromiseTracker m_promiseTracker;
};
} // namespace blink
#endif // !defined(InspectorDebuggerAgent_h)

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 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:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
*/
#ifndef InspectorFrontendChannel_h
#define InspectorFrontendChannel_h
#include "platform/JSONValues.h"
#include "wtf/Forward.h"
namespace blink {
class InspectorFrontendChannel {
public:
virtual ~InspectorFrontendChannel() { }
virtual void sendMessageToFrontend(PassRefPtr<JSONObject> message) = 0;
virtual void flush() = 0;
};
} // namespace blink
#endif // !defined(InspectorFrontendChannel_h)

View File

@ -0,0 +1,171 @@
/*
* Copyright (C) 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") 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 GOOGLE AND ITS 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 APPLE OR ITS 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 "config.h"
#include "core/inspector/InspectorState.h"
// #include "core/inspector/InspectorStateClient.h"
#include "core/inspector/JSONParser.h"
#include "wtf/PassOwnPtr.h"
namespace blink {
InspectorState::InspectorState(InspectorStateUpdateListener* listener, PassRefPtr<JSONObject> properties)
: m_listener(listener)
, m_properties(properties)
{
}
void InspectorState::updateCookie()
{
if (m_listener)
m_listener->inspectorStateUpdated();
}
void InspectorState::setFromCookie(PassRefPtr<JSONObject> properties)
{
m_properties = properties;
}
void InspectorState::setValue(const String& propertyName, PassRefPtr<JSONValue> value)
{
m_properties->setValue(propertyName, value);
updateCookie();
}
void InspectorState::remove(const String& propertyName)
{
m_properties->remove(propertyName);
updateCookie();
}
bool InspectorState::getBoolean(const String& propertyName)
{
JSONObject::iterator it = m_properties->find(propertyName);
bool value = false;
if (it != m_properties->end())
it->value->asBoolean(&value);
return value;
}
String InspectorState::getString(const String& propertyName)
{
JSONObject::iterator it = m_properties->find(propertyName);
String value;
if (it != m_properties->end())
it->value->asString(&value);
return value;
}
long InspectorState::getLong(const String& propertyName)
{
return getLong(propertyName, 0);
}
long InspectorState::getLong(const String& propertyName, long defaultValue)
{
JSONObject::iterator it = m_properties->find(propertyName);
long value = defaultValue;
if (it != m_properties->end())
it->value->asNumber(&value);
return value;
}
double InspectorState::getDouble(const String& propertyName)
{
return getDouble(propertyName, 0);
}
double InspectorState::getDouble(const String& propertyName, double defaultValue)
{
JSONObject::iterator it = m_properties->find(propertyName);
double value = defaultValue;
if (it != m_properties->end())
it->value->asNumber(&value);
return value;
}
PassRefPtr<JSONObject> InspectorState::getObject(const String& propertyName)
{
JSONObject::iterator it = m_properties->find(propertyName);
if (it == m_properties->end()) {
m_properties->setObject(propertyName, JSONObject::create());
it = m_properties->find(propertyName);
}
return it->value->asObject();
}
InspectorState* InspectorCompositeState::createAgentState(const String& agentName)
{
ASSERT(m_stateObject->find(agentName) == m_stateObject->end());
ASSERT(m_inspectorStateMap.find(agentName) == m_inspectorStateMap.end());
RefPtr<JSONObject> stateProperties = JSONObject::create();
m_stateObject->setObject(agentName, stateProperties);
OwnPtr<InspectorState> statePtr = adoptPtr(new InspectorState(this, stateProperties));
InspectorState* state = statePtr.get();
m_inspectorStateMap.add(agentName, statePtr.release());
return state;
}
void InspectorCompositeState::loadFromCookie(const String& inspectorCompositeStateCookie)
{
RefPtr<JSONValue> cookie = parseJSON(inspectorCompositeStateCookie);
if (cookie)
m_stateObject = cookie->asObject();
if (!m_stateObject)
m_stateObject = JSONObject::create();
InspectorStateMap::iterator end = m_inspectorStateMap.end();
for (InspectorStateMap::iterator it = m_inspectorStateMap.begin(); it != end; ++it) {
RefPtr<JSONObject> agentStateObject = m_stateObject->getObject(it->key);
if (!agentStateObject) {
agentStateObject = JSONObject::create();
m_stateObject->setObject(it->key, agentStateObject);
}
it->value->setFromCookie(agentStateObject);
}
}
void InspectorCompositeState::mute()
{
m_isMuted = true;
}
void InspectorCompositeState::unmute()
{
m_isMuted = false;
}
void InspectorCompositeState::inspectorStateUpdated()
{
// FIXME(Sky): tell clients?
}
} // namespace blink

View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 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.
*/
#ifndef InspectorState_h
#define InspectorState_h
#include "platform/JSONValues.h"
#include "platform/heap/Handle.h"
#include "wtf/HashMap.h"
#include "wtf/text/WTFString.h"
namespace blink {
class InspectorStateClient;
class InspectorStateUpdateListener {
public:
virtual ~InspectorStateUpdateListener() { }
virtual void inspectorStateUpdated() = 0;
};
class InspectorState final {
WTF_MAKE_FAST_ALLOCATED;
public:
InspectorState(InspectorStateUpdateListener*, PassRefPtr<JSONObject>);
void loadFromCookie(const String& inspectorStateCookie);
void mute();
void unmute();
bool getBoolean(const String& propertyName);
String getString(const String& propertyName);
long getLong(const String& propertyName);
long getLong(const String& propertyName, long defaultValue);
double getDouble(const String& propertyName);
double getDouble(const String& propertyName, double defaultValue);
PassRefPtr<JSONObject> getObject(const String& propertyName);
void setBoolean(const String& propertyName, bool value) { setValue(propertyName, JSONBasicValue::create(value)); }
void setString(const String& propertyName, const String& value) { setValue(propertyName, JSONString::create(value)); }
void setLong(const String& propertyName, long value) { setValue(propertyName, JSONBasicValue::create((double)value)); }
void setDouble(const String& propertyName, double value) { setValue(propertyName, JSONBasicValue::create(value)); }
void setObject(const String& propertyName, PassRefPtr<JSONObject> value) { setValue(propertyName, value); }
void remove(const String&);
private:
void updateCookie();
void setValue(const String& propertyName, PassRefPtr<JSONValue>);
// Gets called from InspectorCompositeState::loadFromCookie().
void setFromCookie(PassRefPtr<JSONObject>);
friend class InspectorCompositeState;
RawPtr<InspectorStateUpdateListener> m_listener;
RefPtr<JSONObject> m_properties;
};
class InspectorCompositeState final : public InspectorStateUpdateListener {
public:
InspectorCompositeState(InspectorStateClient* inspectorClient)
: m_stateObject(JSONObject::create())
, m_isMuted(false)
{
}
virtual ~InspectorCompositeState() { }
void mute();
void unmute();
InspectorState* createAgentState(const String&);
void loadFromCookie(const String&);
private:
typedef HashMap<String, OwnPtr<InspectorState> > InspectorStateMap;
// From InspectorStateUpdateListener.
virtual void inspectorStateUpdated() override;
RefPtr<JSONObject> m_stateObject;
bool m_isMuted;
InspectorStateMap m_inspectorStateMap;
};
} // namespace blink
#endif // !defined(InspectorState_h)

View File

@ -10,6 +10,7 @@
#include "bindings/core/v8/ScriptSourceCode.h"
#include "core/events/Event.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/LocalFrame.h"
#include "core/inspector/IdentifiersFactory.h"
#include "core/inspector/InspectorNodeIds.h"
@ -17,11 +18,11 @@
#include "core/page/Page.h"
#include "core/rendering/RenderImage.h"
#include "core/rendering/RenderObject.h"
#include "platform/JSONValues.h"
#include "platform/TracedValue.h"
#include "platform/graphics/GraphicsLayer.h"
#include "platform/JSONValues.h"
#include "platform/network/ResourceRequest.h"
#include "platform/network/ResourceResponse.h"
#include "platform/TracedValue.h"
#include "platform/weborigin/KURL.h"
#include "wtf/Vector.h"
#include <inttypes.h>
@ -158,7 +159,7 @@ static LocalFrame* frameForExecutionContext(ExecutionContext* context)
{
LocalFrame* frame = 0;
if (context->isDocument())
frame = toDocument(context)->frame();
frame = context->executingWindow()->frame();
return frame;
}

View File

@ -0,0 +1,33 @@
// 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 InstrumentingAgents_h
#define InstrumentingAgents_h
#include "wtf/Noncopyable.h"
namespace blink {
// This is a stub.
// This allows one agent to talk to another.
class InspectorDebuggerAgent;
class InstrumentingAgents {
WTF_MAKE_NONCOPYABLE(InstrumentingAgents);
public:
InstrumentingAgents(InspectorDebuggerAgent* agent) : debug_agent_(agent) {}
InspectorDebuggerAgent* inspectorDebuggerAgent() {
return debug_agent_;
}
private:
InspectorDebuggerAgent* debug_agent_;
};
} // namespace blink
#endif // InstrumentingAgents_h

View File

@ -0,0 +1,478 @@
/*
* Copyright (C) 2010 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 "config.h"
#include "core/inspector/JSONParser.h"
#include "platform/JSONValues.h"
#include "wtf/text/StringBuilder.h"
namespace blink {
namespace {
const int stackLimit = 1000;
enum Token {
ObjectBegin,
ObjectEnd,
ArrayBegin,
ArrayEnd,
StringLiteral,
Number,
BoolTrue,
BoolFalse,
NullToken,
ListSeparator,
ObjectPairSeparator,
InvalidToken,
};
const char* const nullString = "null";
const char* const trueString = "true";
const char* const falseString = "false";
template<typename CharType>
bool parseConstToken(const CharType* start, const CharType* end, const CharType** tokenEnd, const char* token)
{
while (start < end && *token != '\0' && *start++ == *token++) { }
if (*token != '\0')
return false;
*tokenEnd = start;
return true;
}
template<typename CharType>
bool readInt(const CharType* start, const CharType* end, const CharType** tokenEnd, bool canHaveLeadingZeros)
{
if (start == end)
return false;
bool haveLeadingZero = '0' == *start;
int length = 0;
while (start < end && '0' <= *start && *start <= '9') {
++start;
++length;
}
if (!length)
return false;
if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
return false;
*tokenEnd = start;
return true;
}
template<typename CharType>
bool parseNumberToken(const CharType* start, const CharType* end, const CharType** tokenEnd)
{
// We just grab the number here. We validate the size in DecodeNumber.
// According to RFC4627, a valid number is: [minus] int [frac] [exp]
if (start == end)
return false;
CharType c = *start;
if ('-' == c)
++start;
if (!readInt(start, end, &start, false))
return false;
if (start == end) {
*tokenEnd = start;
return true;
}
// Optional fraction part
c = *start;
if ('.' == c) {
++start;
if (!readInt(start, end, &start, true))
return false;
if (start == end) {
*tokenEnd = start;
return true;
}
c = *start;
}
// Optional exponent part
if ('e' == c || 'E' == c) {
++start;
if (start == end)
return false;
c = *start;
if ('-' == c || '+' == c) {
++start;
if (start == end)
return false;
}
if (!readInt(start, end, &start, true))
return false;
}
*tokenEnd = start;
return true;
}
template<typename CharType>
bool readHexDigits(const CharType* start, const CharType* end, const CharType** tokenEnd, int digits)
{
if (end - start < digits)
return false;
for (int i = 0; i < digits; ++i) {
CharType c = *start++;
if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')))
return false;
}
*tokenEnd = start;
return true;
}
template<typename CharType>
bool parseStringToken(const CharType* start, const CharType* end, const CharType** tokenEnd)
{
while (start < end) {
CharType c = *start++;
if ('\\' == c) {
c = *start++;
// Make sure the escaped char is valid.
switch (c) {
case 'x':
if (!readHexDigits(start, end, &start, 2))
return false;
break;
case 'u':
if (!readHexDigits(start, end, &start, 4))
return false;
break;
case '\\':
case '/':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
case '"':
break;
default:
return false;
}
} else if ('"' == c) {
*tokenEnd = start;
return true;
}
}
return false;
}
template<typename CharType>
Token parseToken(const CharType* start, const CharType* end, const CharType** tokenStart, const CharType** tokenEnd)
{
while (start < end && isSpaceOrNewline(*start))
++start;
if (start == end)
return InvalidToken;
*tokenStart = start;
switch (*start) {
case 'n':
if (parseConstToken(start, end, tokenEnd, nullString))
return NullToken;
break;
case 't':
if (parseConstToken(start, end, tokenEnd, trueString))
return BoolTrue;
break;
case 'f':
if (parseConstToken(start, end, tokenEnd, falseString))
return BoolFalse;
break;
case '[':
*tokenEnd = start + 1;
return ArrayBegin;
case ']':
*tokenEnd = start + 1;
return ArrayEnd;
case ',':
*tokenEnd = start + 1;
return ListSeparator;
case '{':
*tokenEnd = start + 1;
return ObjectBegin;
case '}':
*tokenEnd = start + 1;
return ObjectEnd;
case ':':
*tokenEnd = start + 1;
return ObjectPairSeparator;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
if (parseNumberToken(start, end, tokenEnd))
return Number;
break;
case '"':
if (parseStringToken(start + 1, end, tokenEnd))
return StringLiteral;
break;
}
return InvalidToken;
}
template<typename CharType>
inline int hexToInt(CharType c)
{
if ('0' <= c && c <= '9')
return c - '0';
if ('A' <= c && c <= 'F')
return c - 'A' + 10;
if ('a' <= c && c <= 'f')
return c - 'a' + 10;
ASSERT_NOT_REACHED();
return 0;
}
template<typename CharType>
bool decodeString(const CharType* start, const CharType* end, StringBuilder* output)
{
while (start < end) {
UChar c = *start++;
if ('\\' != c) {
output->append(c);
continue;
}
c = *start++;
switch (c) {
case '"':
case '/':
case '\\':
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'v':
c = '\v';
break;
case 'x':
c = (hexToInt(*start) << 4) +
hexToInt(*(start + 1));
start += 2;
break;
case 'u':
c = (hexToInt(*start) << 12) +
(hexToInt(*(start + 1)) << 8) +
(hexToInt(*(start + 2)) << 4) +
hexToInt(*(start + 3));
start += 4;
break;
default:
return false;
}
output->append(c);
}
return true;
}
template<typename CharType>
bool decodeString(const CharType* start, const CharType* end, String* output)
{
if (start == end) {
*output = "";
return true;
}
if (start > end)
return false;
StringBuilder buffer;
buffer.reserveCapacity(end - start);
if (!decodeString(start, end, &buffer))
return false;
*output = buffer.toString();
return true;
}
template<typename CharType>
PassRefPtr<JSONValue> buildValue(const CharType* start, const CharType* end, const CharType** valueTokenEnd, int depth)
{
if (depth > stackLimit)
return nullptr;
RefPtr<JSONValue> result;
const CharType* tokenStart;
const CharType* tokenEnd;
Token token = parseToken(start, end, &tokenStart, &tokenEnd);
switch (token) {
case InvalidToken:
return nullptr;
case NullToken:
result = JSONValue::null();
break;
case BoolTrue:
result = JSONBasicValue::create(true);
break;
case BoolFalse:
result = JSONBasicValue::create(false);
break;
case Number: {
bool ok;
double value = charactersToDouble(tokenStart, tokenEnd - tokenStart, &ok);
if (!ok)
return nullptr;
result = JSONBasicValue::create(value);
break;
}
case StringLiteral: {
String value;
bool ok = decodeString(tokenStart + 1, tokenEnd - 1, &value);
if (!ok)
return nullptr;
result = JSONString::create(value);
break;
}
case ArrayBegin: {
RefPtr<JSONArray> array = JSONArray::create();
start = tokenEnd;
token = parseToken(start, end, &tokenStart, &tokenEnd);
while (token != ArrayEnd) {
RefPtr<JSONValue> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
if (!arrayNode)
return nullptr;
array->pushValue(arrayNode);
// After a list value, we expect a comma or the end of the list.
start = tokenEnd;
token = parseToken(start, end, &tokenStart, &tokenEnd);
if (token == ListSeparator) {
start = tokenEnd;
token = parseToken(start, end, &tokenStart, &tokenEnd);
if (token == ArrayEnd)
return nullptr;
} else if (token != ArrayEnd) {
// Unexpected value after list value. Bail out.
return nullptr;
}
}
if (token != ArrayEnd)
return nullptr;
result = array.release();
break;
}
case ObjectBegin: {
RefPtr<JSONObject> object = JSONObject::create();
start = tokenEnd;
token = parseToken(start, end, &tokenStart, &tokenEnd);
while (token != ObjectEnd) {
if (token != StringLiteral)
return nullptr;
String key;
if (!decodeString(tokenStart + 1, tokenEnd - 1, &key))
return nullptr;
start = tokenEnd;
token = parseToken(start, end, &tokenStart, &tokenEnd);
if (token != ObjectPairSeparator)
return nullptr;
start = tokenEnd;
RefPtr<JSONValue> value = buildValue(start, end, &tokenEnd, depth + 1);
if (!value)
return nullptr;
object->setValue(key, value);
start = tokenEnd;
// After a key/value pair, we expect a comma or the end of the
// object.
token = parseToken(start, end, &tokenStart, &tokenEnd);
if (token == ListSeparator) {
start = tokenEnd;
token = parseToken(start, end, &tokenStart, &tokenEnd);
if (token == ObjectEnd)
return nullptr;
} else if (token != ObjectEnd) {
// Unexpected value after last object value. Bail out.
return nullptr;
}
}
if (token != ObjectEnd)
return nullptr;
result = object.release();
break;
}
default:
// We got a token that's not a value.
return nullptr;
}
*valueTokenEnd = tokenEnd;
return result.release();
}
template<typename CharType>
PassRefPtr<JSONValue> parseJSONInternal(const CharType* start, unsigned length)
{
const CharType* end = start + length;
const CharType *tokenEnd;
RefPtr<JSONValue> value = buildValue(start, end, &tokenEnd, 0);
if (!value || tokenEnd != end)
return nullptr;
return value.release();
}
} // anonymous namespace
PassRefPtr<JSONValue> parseJSON(const String& json)
{
if (json.isEmpty())
return nullptr;
if (json.is8Bit())
return parseJSONInternal(json.characters8(), json.length());
return parseJSONInternal(json.characters16(), json.length());
}
} // namespace blink

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2009 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.
*/
#ifndef JSONParser_h
#define JSONParser_h
#include "wtf/PassRefPtr.h"
#include "wtf/text/WTFString.h"
namespace blink {
class JSONValue;
PassRefPtr<JSONValue> parseJSON(const String& json);
} // namespace blink
#endif // !defined(JSONParser_h)

View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 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 "config.h"
#include "core/inspector/PageDebuggerAgent.h"
#include "bindings/core/v8/DOMWrapperWorld.h"
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptSourceCode.h"
#include "core/frame/FrameConsole.h"
#include "core/frame/LocalFrame.h"
#include "core/page/Page.h"
namespace blink {
PassOwnPtr<PageDebuggerAgent> PageDebuggerAgent::create(PageScriptDebugServer* pageScriptDebugServer, Page* page, InjectedScriptManager* injectedScriptManager)
{
return adoptPtr(new PageDebuggerAgent(pageScriptDebugServer, page, injectedScriptManager));
}
PageDebuggerAgent::PageDebuggerAgent(PageScriptDebugServer* pageScriptDebugServer, Page* page, InjectedScriptManager* injectedScriptManager)
: InspectorDebuggerAgent(injectedScriptManager)
, m_pageScriptDebugServer(pageScriptDebugServer)
, m_page(page)
{
}
PageDebuggerAgent::~PageDebuggerAgent()
{
}
void PageDebuggerAgent::startListeningScriptDebugServer()
{
scriptDebugServer().addListener(this, m_page);
}
void PageDebuggerAgent::stopListeningScriptDebugServer()
{
scriptDebugServer().removeListener(this, m_page);
}
PageScriptDebugServer& PageDebuggerAgent::scriptDebugServer()
{
return *m_pageScriptDebugServer;
}
void PageDebuggerAgent::muteConsole()
{
FrameConsole::mute();
}
void PageDebuggerAgent::unmuteConsole()
{
FrameConsole::unmute();
}
InjectedScript PageDebuggerAgent::injectedScriptForEval(ErrorString* errorString, const int* executionContextId)
{
if (!executionContextId) {
ScriptState* scriptState = ScriptState::forMainWorld(m_page->mainFrame());
return injectedScriptManager()->injectedScriptFor(scriptState);
}
InjectedScript injectedScript = injectedScriptManager()->injectedScriptForId(*executionContextId);
if (injectedScript.isEmpty())
*errorString = "Execution context with given id not found.";
return injectedScript;
}
void PageDebuggerAgent::setOverlayMessage(ErrorString*, const String* message)
{
if (message)
printf("OVERLAY MESSAGE: %s\n", message->ascii().data());
else
printf("OVERLAY REMOVED\n");
}
void PageDebuggerAgent::didClearDocumentOfWindowObject(LocalFrame* frame)
{
reset();
scriptDebugServer().setPreprocessorSource(String());
}
} // namespace blink

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 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.
*/
#ifndef PageDebuggerAgent_h
#define PageDebuggerAgent_h
#include "bindings/core/v8/PageScriptDebugServer.h"
#include "core/inspector/InspectorDebuggerAgent.h"
namespace blink {
class DocumentLoader;
class InspectorPageAgent;
class Page;
class PageScriptDebugServer;
class ScriptSourceCode;
class PageDebuggerAgent final
: public InspectorDebuggerAgent {
WTF_MAKE_NONCOPYABLE(PageDebuggerAgent);
WTF_MAKE_FAST_ALLOCATED;
public:
static PassOwnPtr<PageDebuggerAgent> create(PageScriptDebugServer*, Page*, InjectedScriptManager*);
virtual ~PageDebuggerAgent();
void didClearDocumentOfWindowObject(LocalFrame*);
private:
virtual void startListeningScriptDebugServer() override;
virtual void stopListeningScriptDebugServer() override;
virtual PageScriptDebugServer& scriptDebugServer() override;
virtual void muteConsole() override;
virtual void unmuteConsole() override;
virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId) override;
virtual void setOverlayMessage(ErrorString*, const String*) override;
PageDebuggerAgent(PageScriptDebugServer*, Page*, InjectedScriptManager*);
PageScriptDebugServer* m_pageScriptDebugServer;
Page* m_page;
};
} // namespace blink
#endif // !defined(PageDebuggerAgent_h)

View File

@ -0,0 +1,147 @@
// 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 "config.h"
#include "core/inspector/PromiseTracker.h"
#include "bindings/core/v8/ScopedPersistent.h"
#include "bindings/core/v8/ScriptCallStackFactory.h"
#include "bindings/core/v8/ScriptState.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/WeakPtr.h"
namespace blink {
class PromiseTracker::PromiseData : public RefCounted<PromiseData> {
public:
PromiseData(v8::Isolate* isolate, int promiseHash, v8::Handle<v8::Object> promise)
: m_promiseHash(promiseHash)
, m_promise(isolate, promise)
, m_status(0)
, m_weakPtrFactory(this)
{
}
int promiseHash() const { return m_promiseHash; }
ScopedPersistent<v8::Object>& promise() { return m_promise; }
private:
friend class PromiseTracker;
int m_promiseHash;
ScopedPersistent<v8::Object> m_promise;
ScriptCallFrame m_callFrame;
ScopedPersistent<v8::Object> m_parentPromise;
int m_status;
WeakPtrFactory<PromiseData> m_weakPtrFactory;
};
static int indexOf(PromiseTracker::PromiseDataVector* vector, const ScopedPersistent<v8::Object>& promise)
{
for (size_t index = 0; index < vector->size(); ++index) {
if (vector->at(index)->promise() == promise)
return index;
}
return -1;
}
namespace {
class PromiseDataWrapper {
public:
PromiseDataWrapper(WeakPtr<PromiseTracker::PromiseData> data, PromiseTracker::PromiseDataMap* map)
: m_data(data)
, m_promiseDataMap(map)
{
}
static void didRemovePromise(const v8::WeakCallbackData<v8::Object, PromiseDataWrapper>& data)
{
OwnPtr<PromiseDataWrapper> wrapper = adoptPtr(data.GetParameter());
WeakPtr<PromiseTracker::PromiseData> promiseData = wrapper->m_data;
if (!promiseData)
return;
PromiseTracker::PromiseDataMap* map = wrapper->m_promiseDataMap;
int promiseHash = promiseData->promiseHash();
PromiseTracker::PromiseDataVector* vector = &map->find(promiseHash)->value;
int index = indexOf(vector, promiseData->promise());
ASSERT(index >= 0);
vector->remove(index);
if (vector->size() == 0)
map->remove(promiseHash);
}
private:
WeakPtr<PromiseTracker::PromiseData> m_data;
PromiseTracker::PromiseDataMap* m_promiseDataMap;
};
}
PromiseTracker::PromiseTracker()
: m_isEnabled(false)
{
}
PromiseTracker::~PromiseTracker()
{
}
void PromiseTracker::enable()
{
m_isEnabled = true;
}
void PromiseTracker::disable()
{
m_isEnabled = false;
clear();
}
void PromiseTracker::clear()
{
m_promiseDataMap.clear();
}
void PromiseTracker::didReceiveV8PromiseEvent(ScriptState* scriptState, v8::Handle<v8::Object> promise, v8::Handle<v8::Value> parentPromise, int status)
{
ASSERT(isEnabled());
int promiseHash = promise->GetIdentityHash();
PromiseDataVector* vector;
PromiseDataMap::iterator it = m_promiseDataMap.find(promiseHash);
if (it != m_promiseDataMap.end())
vector = &it->value;
else
vector = &m_promiseDataMap.add(promiseHash, PromiseDataVector()).storedValue->value;
v8::Isolate* isolate = scriptState->isolate();
RefPtr<PromiseData> data;
int index = indexOf(vector, ScopedPersistent<v8::Object>(isolate, promise));
if (index == -1) {
data = adoptRef(new PromiseData(isolate, promiseHash, promise));
OwnPtr<PromiseDataWrapper> wrapper = adoptPtr(new PromiseDataWrapper(data->m_weakPtrFactory.createWeakPtr(), &m_promiseDataMap));
data->m_promise.setWeak(wrapper.leakPtr(), &PromiseDataWrapper::didRemovePromise);
vector->append(data);
} else {
data = vector->at(index);
}
if (!parentPromise.IsEmpty()) {
ASSERT(parentPromise->IsObject());
data->m_parentPromise.set(isolate, parentPromise->ToObject());
} else {
data->m_status = status;
if (!status) {
v8::Handle<v8::StackTrace> stackTrace(v8::StackTrace::CurrentStackTrace(isolate, 1));
RefPtr<ScriptCallStack> stack = createScriptCallStack(stackTrace, 1, isolate);
if (stack->size())
data->m_callFrame = stack->at(0);
}
}
}
} // namespace blink

View File

@ -0,0 +1,44 @@
// 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 PromiseTracker_h
#define PromiseTracker_h
#include "wtf/HashMap.h"
#include "wtf/Noncopyable.h"
#include "wtf/RefPtr.h"
#include "wtf/Vector.h"
#include <v8.h>
namespace blink {
class ScriptState;
class PromiseTracker {
WTF_MAKE_NONCOPYABLE(PromiseTracker);
public:
PromiseTracker();
~PromiseTracker();
bool isEnabled() const { return m_isEnabled; }
void enable();
void disable();
void clear();
void didReceiveV8PromiseEvent(ScriptState*, v8::Handle<v8::Object> promise, v8::Handle<v8::Value> parentPromise, int status);
class PromiseData;
typedef Vector<RefPtr<PromiseData> > PromiseDataVector;
typedef HashMap<int, PromiseDataVector> PromiseDataMap;
private:
bool m_isEnabled;
PromiseDataMap m_promiseDataMap;
};
} // namespace blink
#endif // !defined(PromiseTracker_h)

View File

@ -55,4 +55,15 @@ ScriptCallFrame::~ScriptCallFrame()
{
}
PassRefPtr<TypeBuilder::Console::CallFrame> ScriptCallFrame::buildInspectorObject() const
{
return TypeBuilder::Console::CallFrame::create()
.setFunctionName(m_functionName)
.setScriptId(m_scriptId)
.setUrl(m_scriptName)
.setLineNumber(m_lineNumber)
.setColumnNumber(m_column)
.release();
}
} // namespace blink

View File

@ -31,6 +31,7 @@
#ifndef ScriptCallFrame_h
#define ScriptCallFrame_h
#include "core/InspectorTypeBuilder.h"
#include "wtf/Forward.h"
#include "wtf/text/WTFString.h"
@ -48,6 +49,8 @@ public:
unsigned lineNumber() const { return m_lineNumber; }
unsigned columnNumber() const { return m_column; }
PassRefPtr<TypeBuilder::Console::CallFrame> buildInspectorObject() const;
private:
String m_functionName;
String m_scriptId;

View File

@ -68,4 +68,12 @@ void ScriptCallStack::setAsyncCallStack(PassRefPtr<ScriptAsyncCallStack> asyncCa
m_asyncCallStack = asyncCallStack;
}
PassRefPtr<TypeBuilder::Array<TypeBuilder::Console::CallFrame> > ScriptCallStack::buildInspectorArray() const
{
RefPtr<TypeBuilder::Array<TypeBuilder::Console::CallFrame> > frames = TypeBuilder::Array<TypeBuilder::Console::CallFrame>::create();
for (size_t i = 0; i < m_frames.size(); i++)
frames->addItem(m_frames.at(i).buildInspectorObject());
return frames;
}
} // namespace blink

View File

@ -31,6 +31,7 @@
#ifndef ScriptCallStack_h
#define ScriptCallStack_h
#include "core/InspectorTypeBuilder.h"
#include "core/inspector/ScriptCallFrame.h"
#include "platform/heap/Handle.h"
#include "wtf/Forward.h"
@ -54,6 +55,8 @@ public:
PassRefPtr<ScriptAsyncCallStack> asyncCallStack() const;
void setAsyncCallStack(PassRefPtr<ScriptAsyncCallStack>);
PassRefPtr<TypeBuilder::Array<TypeBuilder::Console::CallFrame> > buildInspectorArray() const;
private:
explicit ScriptCallStack(Vector<ScriptCallFrame>&);

View File

@ -0,0 +1,109 @@
// 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 "config.h"
#include "core/inspector/inspector_backend_mojo.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "bindings/core/v8/PageScriptDebugServer.h"
#include "bindings/core/v8/ScriptController.h"
#include "core/frame/FrameHost.h"
#include "core/inspector/InspectorState.h"
#include "core/inspector/InstrumentingAgents.h"
#include "core/inspector/PageDebuggerAgent.h"
#include "core/InspectorBackendDispatcher.h"
#include "core/page/Page.h"
#include "mojo/public/cpp/application/connect.h"
#include "mojo/public/cpp/application/service_provider_impl.h"
#include "mojo/public/interfaces/application/shell.mojom.h"
#include "platform/JSONValues.h"
#include "public/platform/ServiceProvider.h"
namespace blink {
class MessageLoopAdaptor : public PageScriptDebugServer::ClientMessageLoop {
public:
MessageLoopAdaptor() { }
private:
virtual void run(Page* page)
{
if (run_loop_)
return;
run_loop_.reset(new base::RunLoop());
run_loop_->Run();
}
virtual void quitNow()
{
if (run_loop_)
run_loop_->Quit();
}
scoped_ptr<base::RunLoop> run_loop_;
};
InspectorBackendMojo::InspectorBackendMojo(const FrameHost& frame_host)
: frame_host_(frame_host) {
}
InspectorBackendMojo::~InspectorBackendMojo() {
}
void InspectorBackendMojo::Connect() {
mojo::Shell* shell = frame_host_.services().Shell();
mojo::ServiceProviderPtr inspector_service_provider;
shell->ConnectToApplication("mojo:sky_inspector_server",
GetProxy(&inspector_service_provider));
mojo::ConnectToService(inspector_service_provider.get(), &frontend_);
frontend_.set_client(this);
// Theoretically we should load our state from the inspector cookie.
inspector_state_ = adoptPtr(new InspectorState(nullptr, JSONObject::create()));
old_frontend_ = adoptPtr(new InspectorFrontend(this));
v8::Isolate* isolate = frame_host_.page().mainFrame()->script().isolate();
PageScriptDebugServer::setMainThreadIsolate(isolate);
OwnPtr<MessageLoopAdaptor> message_loop = adoptPtr(new MessageLoopAdaptor);
PageScriptDebugServer::shared().setClientMessageLoop(message_loop.release());
// AgentRegistry used to do this, but we don't need it for one agent.
script_manager_ = InjectedScriptManager::createForPage();
debugger_agent_ = PageDebuggerAgent::create(&PageScriptDebugServer::shared(), &frame_host_.page(), script_manager_.get());
agents_ = adoptPtr(new InstrumentingAgents(debugger_agent_.get()));
debugger_agent_->init(agents_.get(), inspector_state_.get());
debugger_agent_->setFrontend(old_frontend_.get());
dispatcher_ = InspectorBackendDispatcher::create(this);
dispatcher_->registerAgent(debugger_agent_.get());
}
void InspectorBackendMojo::sendMessageToFrontend(
PassRefPtr<JSONObject> message) {
frontend_->SendMessage(message->toJSONString().toUTF8());
}
void InspectorBackendMojo::flush() {
// TODO(eseidel): Unclear if this is needed.
}
void InspectorBackendMojo::OnConnect() {
}
void InspectorBackendMojo::OnDisconnect() {
}
void InspectorBackendMojo::OnMessage(const mojo::String& message) {
String wtf_message = String::fromUTF8(message.To<std::string>());
String command_name;
InspectorBackendDispatcher::getCommandName(wtf_message, &command_name);
// InspectorBackendDispatcher will automatically reply with errors
// if agents are missing, since we only want this backend to care about
// the Debugger agent, we manually filter here.
if (command_name.startsWith("Debugger"))
dispatcher_->dispatch(wtf_message);
}
} // namespace blink

View File

@ -0,0 +1,56 @@
// 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 SKY_ENGINE_INSPECTOR_INSPECTOR_BACKEND_MOJO_H_
#define SKY_ENGINE_INSPECTOR_INSPECTOR_BACKEND_MOJO_H_
#include "base/basictypes.h"
#include "core/inspector/InspectorFrontendChannel.h"
#include "sky/services/inspector/inspector.mojom.h"
namespace blink {
class FrameHost;
class InspectorBackendDispatcher;
class JSONObject;
class PageDebuggerAgent;
class InjectedScriptManager;
class InspectorState;
class InstrumentingAgents;
class InspectorFrontend;
class InspectorBackendMojo : public mojo::InterfaceImpl<sky::InspectorBackend>,
public InspectorFrontendChannel {
public:
explicit InspectorBackendMojo(const FrameHost& frame_host);
~InspectorBackendMojo();
void Connect();
private:
// InspectorBackend:
void OnConnect() override;
void OnDisconnect() override;
void OnMessage(const mojo::String& message) override;
// InspectorFrontendChannel:
void sendMessageToFrontend(PassRefPtr<JSONObject> message) override;
void flush() override;
const FrameHost& frame_host_;
sky::InspectorFrontendPtr frontend_;
OwnPtr<InspectorFrontend> old_frontend_;
RefPtr<InspectorBackendDispatcher> dispatcher_;
OwnPtr<PageDebuggerAgent> debugger_agent_;
OwnPtr<InjectedScriptManager> script_manager_;
OwnPtr<InspectorState> inspector_state_;
OwnPtr<InstrumentingAgents> agents_;
DISALLOW_COPY_AND_ASSIGN(InspectorBackendMojo);
};
} // namespace blink
#endif // SKY_ENGINE_INSPECTOR_INSPECTOR_BACKEND_MOJO_H_

View File

@ -45,6 +45,7 @@ namespace {
class DummyServiceProvider : public blink::ServiceProvider {
public:
mojo::NavigatorHost* NavigatorHost() { return 0; }
mojo::Shell* Shell() { return 0; }
};
}

View File

@ -7,6 +7,7 @@
namespace mojo {
class NavigatorHost;
class Shell;
}
namespace blink {
@ -14,6 +15,7 @@ namespace blink {
class ServiceProvider {
public:
virtual mojo::NavigatorHost* NavigatorHost() = 0;
virtual mojo::Shell* Shell() = 0;
protected:
virtual ~ServiceProvider();

View File

@ -124,6 +124,7 @@ public:
virtual void injectModule(const WebString& path) = 0;
virtual void connectInspectorBackend() = 0;
// Focus ---------------------------------------------------------------

View File

@ -84,6 +84,10 @@ void FrameLoaderClientImpl::documentElementAvailable()
void FrameLoaderClientImpl::didCreateScriptContext(v8::Handle<v8::Context> context, int extensionGroup, int worldId)
{
// FIXME: We shouldn't need separate debugger ids in sky since
// we should have at most one DocumentView per process, no?
m_webFrame->frame()->script().setWorldDebugId(worldId, 1);
if (m_webFrame->client())
m_webFrame->client()->didCreateScriptContext(m_webFrame, context, extensionGroup, worldId);
}

View File

@ -32,7 +32,6 @@
#include "web/WebViewImpl.h"
#include "core/CSSValueKeywords.h"
#include "core/HTMLNames.h"
#include "core/dom/Document.h"
#include "core/dom/DocumentMarkerController.h"
#include "core/dom/NodeRenderingTraversal.h"
@ -41,8 +40,8 @@
#include "core/editing/FrameSelection.h"
#include "core/editing/HTMLInterchange.h"
#include "core/editing/InputMethodController.h"
#include "core/editing/TextIterator.h"
#include "core/editing/markup.h"
#include "core/editing/TextIterator.h"
#include "core/events/KeyboardEvent.h"
#include "core/events/WheelEvent.h"
#include "core/frame/FrameHost.h"
@ -51,6 +50,8 @@
#include "core/frame/Settings.h"
#include "core/html/HTMLImportElement.h"
#include "core/html/ime/InputMethodContext.h"
#include "core/HTMLNames.h"
#include "core/inspector/inspector_backend_mojo.h"
#include "core/loader/FrameLoader.h"
#include "core/loader/UniqueIdentifier.h"
#include "core/page/Chrome.h"
@ -59,9 +60,14 @@
#include "core/page/FocusController.h"
#include "core/page/Page.h"
#include "core/page/TouchDisambiguation.h"
#include "core/rendering/RenderView.h"
#include "core/rendering/compositing/RenderLayerCompositor.h"
#include "core/rendering/RenderView.h"
#include "platform/Cursor.h"
#include "platform/exported/WebActiveGestureAnimation.h"
#include "platform/fonts/FontCache.h"
#include "platform/graphics/Color.h"
#include "platform/graphics/Image.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/KeyboardCodes.h"
#include "platform/Logging.h"
#include "platform/NotImplemented.h"
@ -70,14 +76,9 @@
#include "platform/PlatformMouseEvent.h"
#include "platform/PlatformWheelEvent.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/scroll/Scrollbar.h"
#include "platform/TraceEvent.h"
#include "platform/UserGestureIndicator.h"
#include "platform/exported/WebActiveGestureAnimation.h"
#include "platform/fonts/FontCache.h"
#include "platform/graphics/Color.h"
#include "platform/graphics/Image.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/scroll/Scrollbar.h"
#include "platform/weborigin/SchemeRegistry.h"
#include "public/platform/Platform.h"
#include "public/platform/WebFloatPoint.h"
@ -97,10 +98,10 @@
#include "web/CompositionUnderlineVectorBuilder.h"
#include "web/GraphicsLayerFactoryChromium.h"
#include "web/LinkHighlight.h"
#include "web/painting/ContinuousPainter.h"
#include "web/WebInputEventConversion.h"
#include "web/WebLocalFrameImpl.h"
#include "web/WebSettingsImpl.h"
#include "web/painting/ContinuousPainter.h"
#include "wtf/CurrentTime.h"
#include "wtf/RefPtr.h"
#include "wtf/TemporaryChange.h"
@ -1605,6 +1606,12 @@ void WebViewImpl::injectModule(const WebString& path)
document->documentElement()->appendChild(import.release());
}
void WebViewImpl::connectInspectorBackend()
{
m_inspectorBackend = adoptPtr(new InspectorBackendMojo(page()->frameHost()));
m_inspectorBackend->Connect();
}
void WebViewImpl::setFocusedFrame(WebFrame* frame)
{
if (!frame) {

View File

@ -32,6 +32,7 @@
#define WebViewImpl_h
#include "core/html/ime/InputMethodContext.h"
#include "core/inspector/inspector_backend_mojo.h"
#include "platform/geometry/IntPoint.h"
#include "platform/geometry/IntRect.h"
#include "platform/graphics/GraphicsLayer.h"
@ -117,6 +118,7 @@ public:
// WebView methods:
virtual void setMainFrame(WebFrame*) override;
virtual void injectModule(const WebString&) override;
virtual void connectInspectorBackend() override;
virtual void setSpellCheckClient(WebSpellCheckClient*) override;
virtual WebSettings* settings() override;
virtual WebString pageEncoding() const override;
@ -448,6 +450,8 @@ private:
WebColor m_backgroundColorOverride;
bool m_userGestureObserved;
OwnPtr<InspectorBackendMojo> m_inspectorBackend;
};
// We have no ways to check if the specified WebView is an instance of

View File

@ -16,18 +16,22 @@ function InspectorBackend(frontend) {
this.agents = {
Console: new ConsoleAgent(),
DOM: domAgent,
Page: new PageAgent(),
Page: new PageAgent(this),
Worker: new WorkerAgent(),
Runtime: new RuntimeAgent(this),
CSS: new CSSAgent(domAgent),
IndexedDB: new IndexedDBAgent(),
};
this.missingNames_ = {};
this.unansweredMessages_ = [];
}
InspectorBackend.prototype = Object.create(
inspector.InspectorBackend.stubClass.prototype);
InspectorBackend.prototype.ASYNC_RESPONSE = "ASYNC_RESPONSE";
InspectorBackend.prototype.MESSAGE_TIMEOUT_MS = 30000;
InspectorBackend.prototype.onConnect = function() {
};
@ -41,12 +45,16 @@ InspectorBackend.prototype.logMissing_ = function(name) {
console.log("InspectorBackend missing " + name);
}
InspectorBackend.prototype.dispatch_ = function(descriptor, params) {
InspectorBackend.prototype.dispatch_ = function(descriptor, params, message_id) {
var parsed = descriptor.split('.');
var agentName = parsed[0];
var methodName = parsed[1];
// Debugger is implemented in c++.
if (agentName == "Debugger")
return;
if (!(agentName in this.agents)) {
this.logMissing_(agentName);
return {};
@ -55,12 +63,12 @@ InspectorBackend.prototype.dispatch_ = function(descriptor, params) {
var agent = this.agents[agentName];
if (!(methodName in agent)) {
this.logMissing_(agentName + "." + methodName);
this.logMissing_(descriptor);
return {};
}
try {
return agent[methodName](params);
return agent[methodName](params, message_id);
} catch(ex) {
console.log(descriptor + ": " + ex);
}
@ -68,14 +76,34 @@ InspectorBackend.prototype.dispatch_ = function(descriptor, params) {
InspectorBackend.prototype.onMessage = function(data) {
var message = JSON.parse(data);
var result = this.dispatch_(message.method, message.params);
var result = this.dispatch_(message.method, message.params, message.id);
this.unansweredMessages_.push(message.id);
// FIXME: This magic return value is kinda hacky.
if (result != this.ASYNC_RESPONSE)
this.sendResponse(message.id, result);
else {
window.setTimeout(function(message_id) {
if (this.unansweredMessages_.indexOf(message_id) == -1)
return;
console.log("Error, failed to reply to " + descriptor
+ " message id " + message_id);
}, this.MESSAGE_TIMEOUT_MS, this, message.id);
}
};
InspectorBackend.prototype.sendResponse = function(message_id, result) {
var messageIndex = this.unansweredMessages_.indexOf(message_id);
if (messageIndex != -1)
this.unansweredMessages_.splice(messageIndex, 1);
else
console.log("Error, responding to unknown message id " + message_id);
var response = {
id: message.id,
id: message_id,
};
if (typeof result !== "undefined")
response.result = result;
this.frontend.sendMessage(JSON.stringify(response));
};
}
InspectorBackend.prototype.sendMessage = function(method, params) {
var message = JSON.stringify({

View File

@ -1,5 +1,7 @@
<import src="/sky/framework/xmlhttprequest.sky" as="XMLHttpRequest" />
<script>
function Page() {
function Page(delegate) {
this.delegate_ = delegate;
}
Page.prototype.enable = function() {
@ -17,14 +19,28 @@ Page.prototype.canEmulate = function() {
};
};
Page.prototype.getResourceContent = function(params, message_id) {
var request = new XMLHttpRequest;
request.onload = function() {
var message = {
'content' : request.responseText,
};
this.delegate_.sendResponse(message_id, message);
}.bind(this);
request.open("GET", params.url);
request.send();
return this.delegate_.ASYNC_RESPONSE;
};
Page.prototype.getResourceTree = function() {
// Unclear if this is all needed, but if we don't return something here
// the inspector hits an exception in WebInspector.ResourceTreeModel.
return {
"frameTree": {
"frame": {
"id": 1,
"loaderId": 1,
"id": "1",
"loaderId": "1",
"url": document.URL,
"mimeType": "text/html",
"securityOrigin": document.URL,

View File

@ -115,7 +115,10 @@ Runtime.prototype.evaluate = function(params) {
return makeResult(params, value, wasThrown);
}
Runtime.prototype.getProperties = debug.loggingStub("getProperties");
Runtime.prototype.getProperties = function(params) {
// FIXME: Unclear what this is for.
return [];
}
module.exports = Runtime;
</script>

View File

@ -0,0 +1 @@
Got message!

View File

@ -64,6 +64,8 @@ mojo::Target WebNavigationPolicyToNavigationTarget(
} // namespace
static int s_next_debugger_id = 1;
DocumentView::DocumentView(
mojo::URLResponsePtr response,
mojo::ShellPtr shell,
@ -75,6 +77,7 @@ DocumentView::DocumentView(
view_manager_client_factory_(shell_.get(), this),
inspector_service_factory_(this),
compositor_thread_(compositor_thread),
debugger_id_(s_next_debugger_id++),
weak_factory_(this) {
shell_.set_client(this);
}
@ -191,8 +194,6 @@ void DocumentView::didCreateScriptContext(blink::WebLocalFrame* frame,
v8::Handle<v8::Context> context,
int extensionGroup,
int worldId) {
if (frame != web_view_->mainFrame())
return;
script_runner_.reset(new ScriptRunner(frame, context));
v8::Isolate* isolate = context->GetIsolate();
@ -209,6 +210,10 @@ mojo::NavigatorHost* DocumentView::NavigatorHost() {
return navigator_host_.get();
}
mojo::Shell* DocumentView::Shell() {
return shell_.get();
}
void DocumentView::OnViewBoundsChanged(mojo::View* view,
const mojo::Rect& old_bounds,
const mojo::Rect& new_bounds) {

View File

@ -89,6 +89,7 @@ class DocumentView : public mojo::InterfaceImpl<mojo::Application>,
// Services methods:
mojo::NavigatorHost* NavigatorHost() override;
mojo::Shell* Shell() override;
// ViewManagerDelegate methods:
void OnEmbed(
@ -121,6 +122,7 @@ class DocumentView : public mojo::InterfaceImpl<mojo::Application>,
scoped_ptr<WebLayerTreeViewImpl> web_layer_tree_view_impl_;
scoped_refptr<base::MessageLoopProxy> compositor_thread_;
scoped_ptr<ScriptRunner> script_runner_;
int debugger_id_;
base::WeakPtrFactory<DocumentView> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DocumentView);

View File

@ -7,6 +7,9 @@
#include <cmath>
#include "base/debug/trace_event.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/synchronization/waitable_event.h"
@ -235,4 +238,28 @@ void PlatformImpl::updateTraceEventDuration(
category_group_enabled, name, traceEventHandle);
}
// FIXME(sky): This is a horrible hack and makes sky only work when run
// inside its source tree! crbug.com/434513
blink::WebData PlatformImpl::loadResource(const char* name)
{
base::FilePath root_dir;
PathService::Get(base::DIR_SOURCE_ROOT, &root_dir);
base::FilePath engine_dir = root_dir.AppendASCII("sky").AppendASCII("engine");
base::FilePath v8_dir = engine_dir.AppendASCII("bindings").AppendASCII("core").AppendASCII("v8");
base::FilePath inspector_dir = engine_dir.AppendASCII("core").AppendASCII("inspector");
base::FilePath path;
if (std::string("InjectedScriptSource.js") == name)
path = inspector_dir.AppendASCII(name);
else if (std::string("DebuggerScript.js") == name)
path = v8_dir.AppendASCII(name);
else
CHECK(false);
std::string buffer;
base::ReadFileToString(path, &buffer);
CHECK(!buffer.empty());
return blink::WebData(buffer.data(), buffer.size());
}
} // namespace sky

View File

@ -70,6 +70,8 @@ class PlatformImpl : public blink::Platform {
const char* name,
TraceEventHandle);
virtual blink::WebData loadResource(const char* name);
private:
void SuspendSharedTimer();
void ResumeSharedTimer();

View File

@ -27,16 +27,17 @@ void InspectorServiceImpl::Inject() {
if (!view_)
return;
mojo::ServiceProviderPtr inpector_service_provider;
mojo::ServiceProviderPtr inspector_service_provider;
view_->shell()->ConnectToApplication("mojo:sky_inspector_server",
GetProxy(&inpector_service_provider));
GetProxy(&inspector_service_provider));
InspectorServerPtr inspector;
ConnectToService(inpector_service_provider.get(), &inspector);
mojo::ConnectToService(inspector_service_provider.get(), &inspector);
inspector->Listen(9898, base::Bind(&Ignored));
// Listen drops existing agents/backends, wait before registering new ones.
inspector.WaitForIncomingMethodCall();
view_->web_view()->injectModule("/sky/framework/inspector/inspector.sky");
view_->web_view()->connectInspectorBackend();
}
} // namespace sky