diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js | 679 |
1 files changed, 679 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js b/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js new file mode 100644 index 000000000..f4c99fbec --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js @@ -0,0 +1,679 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2015 Apple 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. + */ + +WebInspector.RemoteObject = class RemoteObject +{ + constructor(target, objectId, type, subtype, value, description, size, classPrototype, className, preview) + { + console.assert(type); + console.assert(!preview || preview instanceof WebInspector.ObjectPreview); + console.assert(!target || target instanceof WebInspector.Target); + + this._target = target || WebInspector.mainTarget; + this._type = type; + this._subtype = subtype; + + if (objectId) { + // Object, Function, or Symbol. + console.assert(!subtype || typeof subtype === "string"); + console.assert(!description || typeof description === "string"); + console.assert(!value); + + this._objectId = objectId; + this._description = description || ""; + this._hasChildren = type !== "symbol"; + this._size = size; + this._classPrototype = classPrototype; + this._preview = preview; + + if (subtype === "class") { + this._functionDescription = this._description; + this._description = "class " + className; + } + } else { + // Primitive or null. + console.assert(type !== "object" || value === null); + console.assert(!preview); + + this._description = description || (value + ""); + this._hasChildren = false; + this._value = value; + } + } + + // Static + + static createFakeRemoteObject() + { + return new WebInspector.RemoteObject(undefined, WebInspector.RemoteObject.FakeRemoteObjectId, "object"); + } + + static fromPrimitiveValue(value) + { + return new WebInspector.RemoteObject(undefined, undefined, typeof value, undefined, value, undefined, undefined, undefined, undefined); + } + + static fromPayload(payload, target) + { + console.assert(typeof payload === "object", "Remote object payload should only be an object"); + + if (payload.subtype === "array") { + // COMPATIBILITY (iOS 8): Runtime.RemoteObject did not have size property, + // instead it was tacked onto the end of the description, like "Array[#]". + var match = payload.description.match(/\[(\d+)\]$/); + if (match) { + payload.size = parseInt(match[1]); + payload.description = payload.description.replace(/\[\d+\]$/, ""); + } + } + + if (payload.classPrototype) + payload.classPrototype = WebInspector.RemoteObject.fromPayload(payload.classPrototype, target); + + if (payload.preview) { + // COMPATIBILITY (iOS 8): iOS 7 and 8 did not have type/subtype/description on + // Runtime.ObjectPreview. Copy them over from the RemoteObject. + if (!payload.preview.type) { + payload.preview.type = payload.type; + payload.preview.subtype = payload.subtype; + payload.preview.description = payload.description; + payload.preview.size = payload.size; + } + + payload.preview = WebInspector.ObjectPreview.fromPayload(payload.preview); + } + + return new WebInspector.RemoteObject(target, payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.size, payload.classPrototype, payload.className, payload.preview); + } + + static createCallArgument(valueOrObject) + { + if (valueOrObject instanceof WebInspector.RemoteObject) { + if (valueOrObject.objectId) + return {objectId: valueOrObject.objectId}; + return {value: valueOrObject.value}; + } + + return {value: valueOrObject}; + } + + static resolveNode(node, objectGroup, callback) + { + DOMAgent.resolveNode(node.id, objectGroup, function(error, object) { + if (!callback) + return; + + if (error || !object) + callback(null); + else + callback(WebInspector.RemoteObject.fromPayload(object, WebInspector.mainTarget)); + }); + } + + static type(remoteObject) + { + if (remoteObject === null) + return "null"; + + var type = typeof remoteObject; + if (type !== "object" && type !== "function") + return type; + + return remoteObject.type; + } + + // Public + + get target() + { + return this._target; + } + + get objectId() + { + return this._objectId; + } + + get type() + { + return this._type; + } + + get subtype() + { + return this._subtype; + } + + get description() + { + return this._description; + } + + get functionDescription() + { + console.assert(this.type === "function"); + + return this._functionDescription || this._description; + } + + get hasChildren() + { + return this._hasChildren; + } + + get value() + { + return this._value; + } + + get size() + { + return this._size || 0; + } + + get classPrototype() + { + return this._classPrototype; + } + + get preview() + { + return this._preview; + } + + hasSize() + { + return this.isArray() || this.isCollectionType(); + } + + hasValue() + { + return "_value" in this; + } + + getOwnPropertyDescriptors(callback) + { + this._getPropertyDescriptors(true, callback); + } + + getAllPropertyDescriptors(callback) + { + this._getPropertyDescriptors(false, callback); + } + + getDisplayablePropertyDescriptors(callback) + { + if (!this._objectId || this._isSymbol() || this._isFakeObject()) { + callback([]); + return; + } + + // COMPATIBILITY (iOS 8): RuntimeAgent.getDisplayableProperties did not exist. + // Here we do our best to reimplement it by getting all properties and reducing them down. + if (!RuntimeAgent.getDisplayableProperties) { + this._target.RuntimeAgent.getProperties(this._objectId, function(error, allProperties) { + var ownOrGetterPropertiesList = []; + if (allProperties) { + for (var property of allProperties) { + if (property.isOwn || property.name === "__proto__") { + // Own property or getter property in prototype chain. + ownOrGetterPropertiesList.push(property); + } else if (property.value && property.name !== property.name.toUpperCase()) { + var type = property.value.type; + if (type && type !== "function" && property.name !== "constructor") { + // Possible native binding getter property converted to a value. Also, no CONSTANT name style and not "constructor". + // There is no way of knowing if this is native or not, so just go with it. + ownOrGetterPropertiesList.push(property); + } + } + } + } + + this._getPropertyDescriptorsResolver(callback, error, ownOrGetterPropertiesList); + }.bind(this)); + return; + } + + this._target.RuntimeAgent.getDisplayableProperties(this._objectId, true, this._getPropertyDescriptorsResolver.bind(this, callback)); + } + + // FIXME: Phase out these deprecated functions. They return DeprecatedRemoteObjectProperty instead of PropertyDescriptors. + deprecatedGetOwnProperties(callback) + { + this._deprecatedGetProperties(true, callback); + } + + deprecatedGetAllProperties(callback) + { + this._deprecatedGetProperties(false, callback); + } + + deprecatedGetDisplayableProperties(callback) + { + if (!this._objectId || this._isSymbol() || this._isFakeObject()) { + callback([]); + return; + } + + // COMPATIBILITY (iOS 8): RuntimeAgent.getProperties did not support ownerAndGetterProperties. + // Here we do our best to reimplement it by getting all properties and reducing them down. + if (!RuntimeAgent.getDisplayableProperties) { + this._target.RuntimeAgent.getProperties(this._objectId, function(error, allProperties) { + var ownOrGetterPropertiesList = []; + if (allProperties) { + for (var property of allProperties) { + if (property.isOwn || property.get || property.name === "__proto__") { + // Own property or getter property in prototype chain. + ownOrGetterPropertiesList.push(property); + } else if (property.value && property.name !== property.name.toUpperCase()) { + var type = property.value.type; + if (type && type !== "function" && property.name !== "constructor") { + // Possible native binding getter property converted to a value. Also, no CONSTANT name style and not "constructor". + ownOrGetterPropertiesList.push(property); + } + } + } + } + + this._deprecatedGetPropertiesResolver(callback, error, ownOrGetterPropertiesList); + }.bind(this)); + return; + } + + this._target.RuntimeAgent.getDisplayableProperties(this._objectId, this._deprecatedGetPropertiesResolver.bind(this, callback)); + } + + setPropertyValue(name, value, callback) + { + if (!this._objectId || this._isSymbol() || this._isFakeObject()) { + callback("Can't set a property of non-object."); + return; + } + + // FIXME: It doesn't look like setPropertyValue is used yet. This will need to be tested when it is again (editable ObjectTrees). + this._target.RuntimeAgent.evaluate.invoke({expression: appendWebInspectorSourceURL(value), doNotPauseOnExceptionsAndMuteConsole: true}, evaluatedCallback.bind(this), this._target.RuntimeAgent); + + function evaluatedCallback(error, result, wasThrown) + { + if (error || wasThrown) { + callback(error || result.description); + return; + } + + function setPropertyValue(propertyName, propertyValue) + { + this[propertyName] = propertyValue; + } + + delete result.description; // Optimize on traffic. + + this._target.RuntimeAgent.callFunctionOn(this._objectId, appendWebInspectorSourceURL(setPropertyValue.toString()), [{value: name}, result], true, undefined, propertySetCallback.bind(this)); + + if (result._objectId) + this._target.RuntimeAgent.releaseObject(result._objectId); + } + + function propertySetCallback(error, result, wasThrown) + { + if (error || wasThrown) { + callback(error || result.description); + return; + } + + callback(); + } + } + + isUndefined() + { + return this._type === "undefined"; + } + + isNode() + { + return this._subtype === "node"; + } + + isArray() + { + return this._subtype === "array"; + } + + isClass() + { + return this._subtype === "class"; + } + + isCollectionType() + { + return this._subtype === "map" || this._subtype === "set" || this._subtype === "weakmap" || this._subtype === "weakset"; + } + + isWeakCollection() + { + return this._subtype === "weakmap" || this._subtype === "weakset"; + } + + getCollectionEntries(start, numberToFetch, callback) + { + start = typeof start === "number" ? start : 0; + numberToFetch = typeof numberToFetch === "number" ? numberToFetch : 100; + + console.assert(start >= 0); + console.assert(numberToFetch >= 0); + console.assert(this.isCollectionType()); + + // WeakMaps and WeakSets are not ordered. We should never send a non-zero start. + console.assert((this._subtype === "weakmap" && start === 0) || this._subtype !== "weakmap"); + console.assert((this._subtype === "weakset" && start === 0) || this._subtype !== "weakset"); + + let objectGroup = this.isWeakCollection() ? this._weakCollectionObjectGroup() : ""; + + this._target.RuntimeAgent.getCollectionEntries(this._objectId, objectGroup, start, numberToFetch, (error, entries) => { + entries = entries.map((x) => WebInspector.CollectionEntry.fromPayload(x, this._target)); + callback(entries); + }); + } + + releaseWeakCollectionEntries() + { + console.assert(this.isWeakCollection()); + + this._target.RuntimeAgent.releaseObjectGroup(this._weakCollectionObjectGroup()); + } + + pushNodeToFrontend(callback) + { + if (this._objectId) + WebInspector.domTreeManager.pushNodeToFrontend(this._objectId, callback); + else + callback(0); + } + + getProperty(propertyName, callback) + { + function inspectedPage_object_getProperty(property) { + return this[property]; + } + + this.callFunction(inspectedPage_object_getProperty, [propertyName], true, callback); + } + + callFunction(functionDeclaration, args, generatePreview, callback) + { + function mycallback(error, result, wasThrown) + { + result = result ? WebInspector.RemoteObject.fromPayload(result, this._target) : null; + + if (callback && typeof callback === "function") + callback(error, result, wasThrown); + } + + if (args) + args = args.map(WebInspector.RemoteObject.createCallArgument); + + this._target.RuntimeAgent.callFunctionOn(this._objectId, appendWebInspectorSourceURL(functionDeclaration.toString()), args, true, undefined, !!generatePreview, mycallback.bind(this)); + } + + callFunctionJSON(functionDeclaration, args, callback) + { + function mycallback(error, result, wasThrown) + { + callback((error || wasThrown) ? null : result.value); + } + + this._target.RuntimeAgent.callFunctionOn(this._objectId, appendWebInspectorSourceURL(functionDeclaration.toString()), args, true, true, mycallback); + } + + invokeGetter(getterRemoteObject, callback) + { + console.assert(getterRemoteObject instanceof WebInspector.RemoteObject); + + function backendInvokeGetter(getter) + { + return getter ? getter.call(this) : undefined; + } + + this.callFunction(backendInvokeGetter, [getterRemoteObject], true, callback); + } + + getOwnPropertyDescriptor(propertyName, callback) + { + function backendGetOwnPropertyDescriptor(propertyName) + { + return this[propertyName]; + } + + function wrappedCallback(error, result, wasThrown) + { + if (error || wasThrown || !(result instanceof WebInspector.RemoteObject)) { + callback(null); + return; + } + + var fakeDescriptor = {name: propertyName, value: result, writable: true, configurable: true, enumerable: false}; + var fakePropertyDescriptor = new WebInspector.PropertyDescriptor(fakeDescriptor, null, true, false, false, false); + callback(fakePropertyDescriptor); + } + + // FIXME: Implement a real RuntimeAgent.getOwnPropertyDescriptor? + this.callFunction(backendGetOwnPropertyDescriptor, [propertyName], false, wrappedCallback.bind(this)); + } + + release() + { + if (this._objectId && !this._isFakeObject()) + this._target.RuntimeAgent.releaseObject(this._objectId); + } + + arrayLength() + { + if (this._subtype !== "array") + return 0; + + var matches = this._description.match(/\[([0-9]+)\]/); + if (!matches) + return 0; + + return parseInt(matches[1], 10); + } + + asCallArgument() + { + return WebInspector.RemoteObject.createCallArgument(this); + } + + findFunctionSourceCodeLocation() + { + var result = new WebInspector.WrappedPromise; + + if (!this._isFunction() || !this._objectId) { + result.resolve(WebInspector.RemoteObject.SourceCodeLocationPromise.MissingObjectId); + return result.promise; + } + + this._target.DebuggerAgent.getFunctionDetails(this._objectId, (error, response) => { + if (error) { + result.reject(error); + return; + } + + var location = response.location; + var sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId, this._target); + + if (!sourceCode || (!WebInspector.isDebugUIEnabled() && isWebKitInternalScript(sourceCode.sourceURL))) { + result.resolve(WebInspector.RemoteObject.SourceCodeLocationPromise.NoSourceFound); + return; + } + + var sourceCodeLocation = sourceCode.createSourceCodeLocation(location.lineNumber, location.columnNumber || 0); + result.resolve(sourceCodeLocation); + }); + + return result.promise; + } + + // Private + + _isFakeObject() + { + return this._objectId === WebInspector.RemoteObject.FakeRemoteObjectId; + } + + _isSymbol() + { + return this._type === "symbol"; + } + + _isFunction() + { + return this._type === "function"; + } + + _weakCollectionObjectGroup() + { + return JSON.stringify(this._objectId) + "-" + this._subtype; + } + + _getPropertyDescriptors(ownProperties, callback) + { + if (!this._objectId || this._isSymbol() || this._isFakeObject()) { + callback([]); + return; + } + + this._target.RuntimeAgent.getProperties(this._objectId, ownProperties, true, this._getPropertyDescriptorsResolver.bind(this, callback)); + } + + getOwnPropertyDescriptorsAsObject(callback) + { + this.getOwnPropertyDescriptors(function(properties) { + var propertiesResult = {}; + var internalPropertiesResult = {}; + for (var propertyDescriptor of properties) { + var object = propertyDescriptor.isInternalProperty ? internalPropertiesResult : propertiesResult; + object[propertyDescriptor.name] = propertyDescriptor; + } + callback(propertiesResult, internalPropertiesResult); + }); + } + + _getPropertyDescriptorsResolver(callback, error, properties, internalProperties) + { + if (error) { + callback(null); + return; + } + + let descriptors = properties.map((payload) => { + return WebInspector.PropertyDescriptor.fromPayload(payload, false, this._target); + }); + + if (internalProperties) { + descriptors = descriptors.concat(internalProperties.map((payload) => { + return WebInspector.PropertyDescriptor.fromPayload(payload, true, this._target); + })); + } + + callback(descriptors); + } + + // FIXME: Phase out these deprecated functions. They return DeprecatedRemoteObjectProperty instead of PropertyDescriptors. + _deprecatedGetProperties(ownProperties, callback) + { + if (!this._objectId || this._isSymbol() || this._isFakeObject()) { + callback([]); + return; + } + + this._target.RuntimeAgent.getProperties(this._objectId, ownProperties, this._deprecatedGetPropertiesResolver.bind(this, callback)); + } + + _deprecatedGetPropertiesResolver(callback, error, properties, internalProperties) + { + if (error) { + callback(null); + return; + } + + if (internalProperties) { + properties = properties.concat(internalProperties.map(function(descriptor) { + descriptor.writable = false; + descriptor.configurable = false; + descriptor.enumerable = false; + descriptor.isOwn = true; + return descriptor; + })); + } + + var result = []; + for (var i = 0; properties && i < properties.length; ++i) { + var property = properties[i]; + if (property.get || property.set) { + if (property.get) + result.push(new WebInspector.DeprecatedRemoteObjectProperty("get " + property.name, WebInspector.RemoteObject.fromPayload(property.get, this._target), property)); + if (property.set) + result.push(new WebInspector.DeprecatedRemoteObjectProperty("set " + property.name, WebInspector.RemoteObject.fromPayload(property.set, this._target), property)); + } else + result.push(new WebInspector.DeprecatedRemoteObjectProperty(property.name, WebInspector.RemoteObject.fromPayload(property.value, this._target), property)); + } + + callback(result); + } +}; + +WebInspector.RemoteObject.FakeRemoteObjectId = "fake-remote-object"; + +WebInspector.RemoteObject.SourceCodeLocationPromise = { + NoSourceFound: "remote-object-source-code-location-promise-no-source-found", + MissingObjectId: "remote-object-source-code-location-promise-missing-object-id" +}; + +// FIXME: Phase out this deprecated class. +WebInspector.DeprecatedRemoteObjectProperty = class DeprecatedRemoteObjectProperty +{ + constructor(name, value, descriptor) + { + this.name = name; + this.value = value; + this.enumerable = descriptor ? !!descriptor.enumerable : true; + this.writable = descriptor ? !!descriptor.writable : true; + if (descriptor && descriptor.wasThrown) + this.wasThrown = true; + } + + // Static + + fromPrimitiveValue(name, value) + { + return new WebInspector.DeprecatedRemoteObjectProperty(name, WebInspector.RemoteObject.fromPrimitiveValue(value)); + } +}; |