summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js679
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));
+ }
+};