Example #1
0
void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& script)
{
    // Don't send script content to the front end until it's really needed.
    const bool* isContentScript = script.isContentScript ? &script.isContentScript : 0;
    String sourceMapURL = sourceMapURLForScript(script);
    m_frontend->scriptParsed(scriptId, script.url, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURL);

    m_scripts.set(scriptId, script);

    if (script.url.isEmpty())
        return;

    RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
    for (InspectorObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
        RefPtr<InspectorObject> breakpointObject = it->second->asObject();
        bool isRegex;
        breakpointObject->getBoolean("isRegex", &isRegex);
        String url;
        breakpointObject->getString("url", &url);
        if (!matches(script.url, url, isRegex))
            continue;
        ScriptBreakpoint breakpoint;
        breakpointObject->getNumber("lineNumber", &breakpoint.lineNumber);
        breakpointObject->getNumber("columnNumber", &breakpoint.columnNumber);
        breakpointObject->getString("condition", &breakpoint.condition);
        RefPtr<InspectorObject> location = resolveBreakpoint(it->first, scriptId, breakpoint);
        if (location)
            m_frontend->breakpointResolved(it->first, location);
    }
}
Example #2
0
void InspectorDebuggerAgent::didParseSource(const String& sourceId, const Script& script)
{
    // Don't send script content to the front end until it's really needed.
    m_frontend->scriptParsed(sourceId, script.url, script.startLine, script.startColumn, script.endLine, script.endColumn, script.isContentScript);

    m_scripts.set(sourceId, script);

    if (script.url.isEmpty())
        return;

    RefPtr<InspectorObject> breakpointsCookie = m_inspectorState->getObject(DebuggerAgentState::javaScriptBreakpoints);
    for (InspectorObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
        RefPtr<InspectorObject> breakpointObject = it->second->asObject();
        String breakpointURL;
        breakpointObject->getString("url", &breakpointURL);
        if (breakpointURL != script.url)
            continue;
        ScriptBreakpoint breakpoint;
        breakpointObject->getNumber("lineNumber", &breakpoint.lineNumber);
        breakpointObject->getNumber("columnNumber", &breakpoint.columnNumber);
        breakpointObject->getString("condition", &breakpoint.condition);
        RefPtr<InspectorObject> location = resolveBreakpoint(it->first, sourceId, breakpoint);
        if (location)
            m_frontend->breakpointResolved(it->first, location);
    }
}
void ForensicSetEditingValueEvent::deserialize(PassRefPtr<JSONObject> json){
	RefPtr<JSONObject> guard = json;
	ForensicPageEvent::deserialize(guard);

	bool result = guard->getString("inputElementName", &m_inputElementName);
	ASSERT(result);

	result = guard->getString("value", &m_value);
	ASSERT(result);
}
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);
    int originScriptId = 0;
    object->getNumber("scriptId", &originScriptId);

    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);
            if (i == 0 && scriptId == originScriptId)
                originScriptId = 0;

            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());
    }
    if (originScriptId)
        exceptionDetails->setScriptId(String::number(originScriptId));
    return exceptionDetails.release();
}
void InspectorDebuggerAgent::didParseSource(JSC::SourceID sourceID, const Script& inScript)
{
    Script script = inScript;
    if (script.startLine <= 0 && !script.startColumn)
        script.sourceURL = ContentSearchUtilities::findScriptSourceURL(script.source);
    script.sourceMappingURL = sourceMapURLForScript(script);

    bool hasSourceURL = !script.sourceURL.isEmpty();
    String scriptURL = hasSourceURL ? script.sourceURL : script.url;
    bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr;
    String* sourceMapURLParam = script.sourceMappingURL.isNull() ? nullptr : &script.sourceMappingURL;
    const bool* isContentScript = script.isContentScript ? &script.isContentScript : nullptr;
    String scriptIDStr = String::number(sourceID);
    m_frontendDispatcher->scriptParsed(scriptIDStr, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam);

    m_scripts.set(sourceID, script);

    if (scriptURL.isEmpty())
        return;

    for (auto it = m_javaScriptBreakpoints.begin(), end = m_javaScriptBreakpoints.end(); it != end; ++it) {
        RefPtr<InspectorObject> breakpointObject;
        if (!it->value->asObject(breakpointObject))
            return;

        bool isRegex;
        breakpointObject->getBoolean(ASCIILiteral("isRegex"), isRegex);
        String url;
        breakpointObject->getString(ASCIILiteral("url"), url);
        if (!matches(scriptURL, url, isRegex))
            continue;

        ScriptBreakpoint breakpoint;
        breakpointObject->getInteger(ASCIILiteral("lineNumber"), breakpoint.lineNumber);
        breakpointObject->getInteger(ASCIILiteral("columnNumber"), breakpoint.columnNumber);
        breakpointObject->getString(ASCIILiteral("condition"), breakpoint.condition);
        breakpointObject->getBoolean(ASCIILiteral("autoContinue"), breakpoint.autoContinue);
        ErrorString errorString;
        RefPtr<InspectorArray> actions;
        breakpointObject->getArray(ASCIILiteral("actions"), actions);
        if (!breakpointActionsFromProtocol(errorString, actions, &breakpoint.actions)) {
            ASSERT_NOT_REACHED();
            continue;
        }

        RefPtr<Inspector::Protocol::Debugger::Location> location = resolveBreakpoint(it->key, sourceID, breakpoint);
        if (location)
            m_frontendDispatcher->breakpointResolved(it->key, location);
    }
}
PassOwnPtrWillBeRawPtr<StorageArea> InspectorDOMStorageAgent::findStorageArea(ErrorString* errorString, const RefPtr<JSONObject>& storageId, LocalFrame*& targetFrame)
{
    String securityOrigin;
    bool isLocalStorage = false;
    bool success = storageId->getString("securityOrigin", &securityOrigin);
    if (success)
        success = storageId->getBoolean("isLocalStorage", &isLocalStorage);
    if (!success) {
        if (errorString)
            *errorString = "Invalid storageId format";
        return nullptr;
    }

    LocalFrame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
    if (!frame) {
        if (errorString)
            *errorString = "LocalFrame not found for the given security origin";
        return nullptr;
    }
    targetFrame = frame;

    if (isLocalStorage)
        return StorageNamespace::localStorageArea(frame->document()->securityOrigin());
    return m_pageAgent->page()->sessionStorage()->storageArea(frame->document()->securityOrigin());
}
Example #7
0
PassRefPtr<StorageArea> InspectorDOMStorageAgent::findStorageArea(ErrorString* errorString, const RefPtr<InspectorObject>& storageId, Frame*& targetFrame)
{
    String securityOrigin;
    bool isLocalStorage = false;
    bool success = storageId->getString("securityOrigin", &securityOrigin);
    if (success)
        success = storageId->getBoolean("isLocalStorage", &isLocalStorage);
    if (!success) {
        if (errorString)
            *errorString = "Invalid storageId format";
        return 0;
    }

    Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
    if (!frame) {
        if (errorString)
            *errorString = "Frame not found for the given security origin";
        return 0;
    }
    targetFrame = frame;

    Page* page = m_pageAgent->page();
    if (isLocalStorage)
        return page->group().localStorage()->storageArea(frame->document()->securityOrigin());
    return page->sessionStorage()->storageArea(frame->document()->securityOrigin());
}
void InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets(ErrorString& errorString, const Inspector::InspectorArray& locations, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::TypeDescription>>& typeDescriptions)
{
    static const bool verbose = false;

    typeDescriptions = Inspector::Protocol::Array<Inspector::Protocol::Runtime::TypeDescription>::create();
    if (!m_vm.typeProfiler()) {
        errorString = ASCIILiteral("The VM does not currently have Type Information.");
        return;
    }

    double start = currentTimeMS();
    m_vm.typeProfilerLog()->processLogEntries(ASCIILiteral("User Query"));

    for (size_t i = 0; i < locations.length(); i++) {
        RefPtr<Inspector::InspectorValue> value = locations.get(i);
        RefPtr<InspectorObject> location;
        if (!value->asObject(location)) {
            errorString = ASCIILiteral("Array of TypeLocation objects has an object that does not have type of TypeLocation.");
            return;
        }

        int descriptor;
        String sourceIDAsString;
        int divot;
        location->getInteger(ASCIILiteral("typeInformationDescriptor"), descriptor);
        location->getString(ASCIILiteral("sourceID"), sourceIDAsString);
        location->getInteger(ASCIILiteral("divot"), divot);

        bool okay;
        TypeLocation* typeLocation = m_vm.typeProfiler()->findLocation(divot, sourceIDAsString.toIntPtrStrict(&okay), static_cast<TypeProfilerSearchDescriptor>(descriptor), m_vm);
        ASSERT(okay);

        RefPtr<TypeSet> typeSet;
        if (typeLocation) {
            if (typeLocation->m_globalTypeSet && typeLocation->m_globalVariableID != TypeProfilerNoGlobalIDExists)
                typeSet = typeLocation->m_globalTypeSet;
            else
                typeSet = typeLocation->m_instructionTypeSet;
        }

        bool isValid = typeLocation && typeSet && !typeSet->isEmpty();
        auto description = Inspector::Protocol::Runtime::TypeDescription::create()
            .setIsValid(isValid)
            .release();

        if (isValid) {
            description->setLeastCommonAncestor(typeSet->leastCommonAncestor());
            description->setStructures(typeSet->allStructureRepresentations());
            description->setTypeSet(typeSet->inspectorTypeSet());
            description->setIsTruncated(typeSet->isOverflown());
        }

        typeDescriptions->addItem(WTFMove(description));
    }

    double end = currentTimeMS();
    if (verbose)
        dataLogF("Inspector::getRuntimeTypesForVariablesAtOffsets took %lfms\n", end - start);
}
void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& inScript)
{
    Script script = inScript;
    if (!script.startLine && !script.startColumn)
        script.sourceURL = ContentSearchUtils::findScriptSourceURL(script.source);
    script.sourceMappingURL = sourceMapURLForScript(script);

    bool hasSourceURL = !script.sourceURL.isEmpty();
    String scriptURL = hasSourceURL ? script.sourceURL : script.url;
    bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : 0;
    String* sourceMapURLParam = script.sourceMappingURL.isNull() ? 0 : &script.sourceMappingURL;
    const bool* isContentScript = script.isContentScript ? &script.isContentScript : 0;
    m_frontend->scriptParsed(scriptId, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam);

    m_scripts.set(scriptId, script);

    if (scriptURL.isEmpty())
        return;

    RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
    for (InspectorObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
        RefPtr<InspectorObject> breakpointObject = it->value->asObject();
        bool isRegex;
        breakpointObject->getBoolean("isRegex", &isRegex);
        String url;
        breakpointObject->getString("url", &url);
        if (!matches(scriptURL, url, isRegex))
            continue;
        ScriptBreakpoint breakpoint;
        breakpointObject->getNumber("lineNumber", &breakpoint.lineNumber);
        breakpointObject->getNumber("columnNumber", &breakpoint.columnNumber);
        breakpointObject->getString("condition", &breakpoint.condition);
        breakpointObject->getBoolean("autoContinue", &breakpoint.autoContinue);
        ErrorString errorString;
        RefPtr<InspectorArray> actions = breakpointObject->getArray("actions");
        if (!breakpointActionsFromProtocol(&errorString, actions, &breakpoint.actions)) {
            ASSERT_NOT_REACHED();
            continue;
        }

        RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(it->key, scriptId, breakpoint);
        if (location)
            m_frontend->breakpointResolved(it->key, location);
    }
}
void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& script)
{
    // Don't send script content to the front end until it's really needed.
    const bool* isContentScript = script.isContentScript ? &script.isContentScript : 0;
    String sourceMapURL = sourceMapURLForScript(script);
    String* sourceMapURLParam = sourceMapURL.isNull() ? 0 : &sourceMapURL;
    String sourceURL;
    if (!script.startLine && !script.startColumn) {
        bool deprecated;
        sourceURL = ContentSearchUtils::findSourceURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated);
        // FIXME: add deprecated console message here.
    }
    bool hasSourceURL = !sourceURL.isEmpty();
    String scriptURL = hasSourceURL ? sourceURL : script.url;
    bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : 0;
    m_frontend->scriptParsed(scriptId, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam);

    m_scripts.set(scriptId, script);

    if (scriptURL.isEmpty())
        return;

    RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
    for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
        RefPtr<JSONObject> breakpointObject = it->value->asObject();
        bool isAntibreakpoint;
        breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint);
        if (isAntibreakpoint)
            continue;
        bool isRegex;
        breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex);
        String url;
        breakpointObject->getString(DebuggerAgentState::url, &url);
        if (!matches(scriptURL, url, isRegex))
            continue;
        ScriptBreakpoint breakpoint;
        breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakpoint.lineNumber);
        breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakpoint.columnNumber);
        breakpointObject->getString(DebuggerAgentState::condition, &breakpoint.condition);
        RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(it->key, scriptId, breakpoint, UserBreakpointSource);
        if (location)
            m_frontend->breakpointResolved(it->key, location);
    }
}
bool InspectorDebuggerAgent::breakpointActionsFromProtocol(ErrorString& errorString, RefPtr<InspectorArray>& actions, BreakpointActions* result)
{
    if (!actions)
        return true;

    unsigned actionsLength = actions->length();
    if (!actionsLength)
        return true;

    result->reserveCapacity(actionsLength);
    for (unsigned i = 0; i < actionsLength; ++i) {
        RefPtr<InspectorValue> value = actions->get(i);
        RefPtr<InspectorObject> object;
        if (!value->asObject(object)) {
            errorString = ASCIILiteral("BreakpointAction of incorrect type, expected object");
            return false;
        }

        String typeString;
        if (!object->getString(ASCIILiteral("type"), typeString)) {
            errorString = ASCIILiteral("BreakpointAction had type missing");
            return false;
        }

        ScriptBreakpointActionType type;
        if (!breakpointActionTypeForString(typeString, &type)) {
            errorString = ASCIILiteral("BreakpointAction had unknown type");
            return false;
        }

        // Specifying an identifier is optional. They are used to correlate probe samples
        // in the frontend across multiple backend probe actions and segregate object groups.
        int identifier = 0;
        object->getInteger(ASCIILiteral("id"), identifier);

        String data;
        object->getString(ASCIILiteral("data"), data);

        result->append(ScriptBreakpointAction(type, identifier, data));
    }

    return true;
}
static bool parseLocation(ErrorString* errorString, RefPtr<InspectorObject> location, String* scriptId, int* lineNumber, int* columnNumber)
{
    if (!location->getString("scriptId", scriptId) || !location->getNumber("lineNumber", lineNumber)) {
        // FIXME: replace with input validation.
        *errorString = "scriptId and lineNumber are required.";
        return false;
    }
    *columnNumber = 0;
    location->getNumber("columnNumber", columnNumber);
    return true;
}
void ForensicReceiveDataEvent::deserialize(PassRefPtr<JSONObject> json){
	RefPtr<JSONObject> guard = json;
	ForensicEvent::deserialize(guard);

	String temp;
	bool result = guard->getString("data", &temp);
	ASSERT(result);
	base64Decode(temp, m_data);

	result = guard->getNumber("encodedDataLength", &m_encodedDataLength);
	ASSERT(result);
}
static bool breakpointActionsFromProtocol(ErrorString* errorString, RefPtr<InspectorArray>& actions, Vector<ScriptBreakpointAction>* result)
{
    if (!actions)
        return true;

    unsigned actionsLength = actions->length();
    if (!actionsLength)
        return true;

    result->reserveCapacity(actionsLength);
    for (unsigned i = 0; i < actionsLength; ++i) {
        RefPtr<InspectorValue> value = actions->get(i);
        RefPtr<InspectorObject> object;
        if (!value->asObject(&object)) {
            *errorString = "BreakpointAction of incorrect type, expected object";
            return false;
        }

        String typeString;
        if (!object->getString("type", &typeString)) {
            *errorString = "BreakpointAction had type missing";
            return false;
        }

        ScriptBreakpointActionType type;
        if (!breakpointActionTypeForString(typeString, &type)) {
            *errorString = "BreakpointAction had unknown type";
            return false;
        }

        String data;
        object->getString("data", &data);

        result->append(ScriptBreakpointAction(type, data));
    }

    return true;
}
ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipExceptionPause(RefPtr<JavaScriptCallFrame>& topFrame)
{
    if (m_skipAllPauses)
        return ScriptDebugListener::Continue;

    String topFrameScriptUrl = scriptURL(topFrame.get());
    if (m_cachedSkipStackRegExp && !topFrameScriptUrl.isEmpty() && m_cachedSkipStackRegExp->match(topFrameScriptUrl) != -1)
        return ScriptDebugListener::Continue;

    // Prepare top frame parameters;
    int topFrameLineNumber = topFrame->line();
    int topFrameColumnNumber = topFrame->column();

    // Match against breakpoints.
    if (topFrameScriptUrl.isEmpty())
        return ScriptDebugListener::NoSkip;

    RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
    for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
        RefPtr<JSONObject> breakpointObject = it->value->asObject();
        bool isAntibreakpoint;
        breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint);
        if (!isAntibreakpoint)
            continue;

        int breakLineNumber;
        breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakLineNumber);
        int breakColumnNumber;
        breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakColumnNumber);

        if (breakLineNumber != topFrameLineNumber)
            continue;

        if (breakColumnNumber != -1 && breakColumnNumber != topFrameColumnNumber)
            continue;

        bool isRegex;
        breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex);
        String url;
        breakpointObject->getString(DebuggerAgentState::url, &url);
        if (!matches(topFrameScriptUrl, url, isRegex))
            continue;

        return ScriptDebugListener::Continue;
    }

    return ScriptDebugListener::NoSkip;
}
Example #16
0
void InspectorLayerTreeAgent::loadSnapshot(ErrorString* errorString, const RefPtr<JSONArray>& tiles, String* snapshotId)
{
    if (!tiles->length()) {
        *errorString = "Invalid argument, no tiles provided";
        return;
    }
    Vector<RefPtr<PictureSnapshot::TilePictureStream> > decodedTiles;
    decodedTiles.grow(tiles->length());
    for (size_t i = 0; i < tiles->length(); ++i) {
        RefPtr<JSONObject> item;
        if (!tiles->get(i)->asObject(&item)) {
            *errorString = "Invalid argument, array item is not an object";
            return;
        }
        double x = 0, y = 0;
        String picture;
        if (!item->getNumber("x", &x) || !item->getNumber("y", &y)
            || !item->getString("picture", &picture)) {
            *errorString = "Invalid argument, missing required field";
            return;
        }
        decodedTiles[i] = adoptRef(new PictureSnapshot::TilePictureStream());
        decodedTiles[i]->layerOffset.set(x, y);
        if (!base64Decode(picture, decodedTiles[i]->data)) {
            *errorString = "Invalid base64 encoding";
            return;
        }
    }
    RefPtr<PictureSnapshot> snapshot = PictureSnapshot::load(decodedTiles);
    if (!snapshot) {
        *errorString = "Invalid snapshot format";
        return;
    }
    if (snapshot->isEmpty()) {
        *errorString = "Empty snapshot";
        return;
    }

    *snapshotId = String::number(++s_lastSnapshotId);
    bool newEntry = m_snapshotById.add(*snapshotId, snapshot).isNewEntry;
    ASSERT_UNUSED(newEntry, newEntry);
}
void InspectorInputAgent::dispatchTouchEvent(ErrorString* error, const String& type, const RefPtr<JSONArray>& touchPoints, const int* modifiers, const double* timestamp)
{
    PlatformEvent::Type convertedType;
    if (type == "touchStart") {
        convertedType = PlatformEvent::TouchStart;
    } else if (type == "touchEnd") {
        convertedType = PlatformEvent::TouchEnd;
    } else if (type == "touchMove") {
        convertedType = PlatformEvent::TouchMove;
    } else {
        *error = "Unrecognized type: " + type;
        return;
    }

    unsigned convertedModifiers = modifiers ? *modifiers : 0;

    SyntheticInspectorTouchEvent event(convertedType, convertedModifiers, timestamp ? *timestamp : currentTime());

    int autoId = 0;
    JSONArrayBase::iterator iter;
    for (iter = touchPoints->begin(); iter != touchPoints->end(); ++iter) {
        RefPtr<JSONObject> pointObj;
        String state;
        int x, y, radiusX, radiusY, id;
        double rotationAngle, force;
        (*iter)->asObject(&pointObj);
        if (!pointObj->getString("state", &state)) {
            *error = "TouchPoint missing 'state'";
            return;
        }
        if (!pointObj->getNumber("x", &x)) {
            *error = "TouchPoint missing 'x' coordinate";
            return;
        }
        if (!pointObj->getNumber("y", &y)) {
            *error = "TouchPoint missing 'y' coordinate";
            return;
        }
        if (!pointObj->getNumber("radiusX", &radiusX))
            radiusX = 1;
        if (!pointObj->getNumber("radiusY", &radiusY))
            radiusY = 1;
        if (!pointObj->getNumber("rotationAngle", &rotationAngle))
            rotationAngle = 0.0f;
        if (!pointObj->getNumber("force", &force))
            force = 1.0f;
        if (pointObj->getNumber("id", &id)) {
            if (autoId > 0)
                id = -1;
            autoId = -1;
        } else {
            id = autoId++;
        }
        if (id < 0) {
            *error = "All or none of the provided TouchPoints must supply positive integer ids.";
            return;
        }

        PlatformTouchPoint::State convertedState;
        if (state == "touchPressed") {
            convertedState = PlatformTouchPoint::TouchPressed;
        } else if (state == "touchReleased") {
            convertedState = PlatformTouchPoint::TouchReleased;
        } else if (state == "touchMoved") {
            convertedState = PlatformTouchPoint::TouchMoved;
        } else if (state == "touchStationary") {
            convertedState = PlatformTouchPoint::TouchStationary;
        } else if (state == "touchCancelled") {
            convertedState = PlatformTouchPoint::TouchCancelled;
        } else {
            *error = "Unrecognized state: " + state;
            return;
        }

        // Some platforms may have flipped coordinate systems, but the given coordinates
        // assume the origin is in the top-left of the window. Convert.
        IntPoint convertedPoint, globalPoint;
        ConvertInspectorPoint(m_page, IntPoint(x, y), &convertedPoint, &globalPoint);

        SyntheticInspectorTouchPoint point(id++, convertedState, globalPoint, convertedPoint, radiusX, radiusY, rotationAngle, force);
        event.append(point);
    }

    m_page->deprecatedLocalMainFrame()->eventHandler().handleTouchEvent(event);
}