| Index: Source/core/inspector/InjectedScriptCanvasModuleSource.js
 | 
| diff --git a/Source/core/inspector/InjectedScriptCanvasModuleSource.js b/Source/core/inspector/InjectedScriptCanvasModuleSource.js
 | 
| deleted file mode 100644
 | 
| index eb1d1ec99fb70c81d976494f72e15a782141a5cc..0000000000000000000000000000000000000000
 | 
| --- a/Source/core/inspector/InjectedScriptCanvasModuleSource.js
 | 
| +++ /dev/null
 | 
| @@ -1,4587 +0,0 @@
 | 
| -/*
 | 
| - * 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.
 | 
| - */
 | 
| -
 | 
| -/**
 | 
| - * FIXME: ES5 strict mode check is suppressed due to multiple uses of arguments.callee.
 | 
| - * @fileoverview
 | 
| - * @suppress {es5Strict}
 | 
| - */
 | 
| -
 | 
| -/**
 | 
| - * @param {InjectedScriptHostClass} InjectedScriptHost
 | 
| - * @param {Window} inspectedWindow
 | 
| - * @param {number} injectedScriptId
 | 
| - * @param {!InjectedScript} injectedScript
 | 
| - */
 | 
| -(function (InjectedScriptHost, inspectedWindow, injectedScriptId, injectedScript) {
 | 
| -
 | 
| -var TypeUtils = {
 | 
| -    /**
 | 
| -     * http://www.khronos.org/registry/typedarray/specs/latest/#7
 | 
| -     * @const
 | 
| -     * @type {!Array.<function(new:ArrayBufferView, (!ArrayBuffer|!ArrayBufferView), number=, number=)>}
 | 
| -     */
 | 
| -    _typedArrayClasses: (function(typeNames) {
 | 
| -        var result = [];
 | 
| -        for (var i = 0, n = typeNames.length; i < n; ++i) {
 | 
| -            if (inspectedWindow[typeNames[i]])
 | 
| -                result.push(inspectedWindow[typeNames[i]]);
 | 
| -        }
 | 
| -        return result;
 | 
| -    })(["Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array"]),
 | 
| -
 | 
| -    /**
 | 
| -     * @const
 | 
| -     * @type {!Array.<string>}
 | 
| -     */
 | 
| -    _supportedPropertyPrefixes: ["webkit"],
 | 
| -
 | 
| -    /**
 | 
| -     * @param {*} array
 | 
| -     * @return {function(new:ArrayBufferView, (!ArrayBuffer|!ArrayBufferView), number=, number=)|null}
 | 
| -     */
 | 
| -    typedArrayClass: function(array)
 | 
| -    {
 | 
| -        var classes = TypeUtils._typedArrayClasses;
 | 
| -        for (var i = 0, n = classes.length; i < n; ++i) {
 | 
| -            if (array instanceof classes[i])
 | 
| -                return classes[i];
 | 
| -        }
 | 
| -        return null;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {*} obj
 | 
| -     * @return {*}
 | 
| -     */
 | 
| -    clone: function(obj)
 | 
| -    {
 | 
| -        if (!obj)
 | 
| -            return obj;
 | 
| -
 | 
| -        var type = typeof obj;
 | 
| -        if (type !== "object" && type !== "function")
 | 
| -            return obj;
 | 
| -
 | 
| -        // Handle Array and ArrayBuffer instances.
 | 
| -        if (typeof obj.slice === "function") {
 | 
| -            console.assert(obj instanceof Array || obj instanceof ArrayBuffer);
 | 
| -            return obj.slice(0);
 | 
| -        }
 | 
| -
 | 
| -        var typedArrayClass = TypeUtils.typedArrayClass(obj);
 | 
| -        if (typedArrayClass)
 | 
| -            return new typedArrayClass(/** @type {!ArrayBufferView} */ (obj));
 | 
| -
 | 
| -        if (obj instanceof HTMLImageElement) {
 | 
| -            var img = /** @type {!HTMLImageElement} */ (obj);
 | 
| -            // Special case for Images with Blob URIs: cloneNode will fail if the Blob URI has already been revoked.
 | 
| -            // FIXME: Maybe this is a bug in WebKit core?
 | 
| -            if (/^blob:/.test(img.src))
 | 
| -                return TypeUtils.cloneIntoCanvas(img);
 | 
| -            return img.cloneNode(true);
 | 
| -        }
 | 
| -
 | 
| -        if (obj instanceof HTMLCanvasElement)
 | 
| -            return TypeUtils.cloneIntoCanvas(obj);
 | 
| -
 | 
| -        if (obj instanceof HTMLVideoElement)
 | 
| -            return TypeUtils.cloneIntoCanvas(obj, obj.videoWidth, obj.videoHeight);
 | 
| -
 | 
| -        if (obj instanceof ImageData) {
 | 
| -            var context = TypeUtils._dummyCanvas2dContext();
 | 
| -            // FIXME: suppress type checks due to outdated builtin externs for createImageData.
 | 
| -            var result = (/** @type {?} */ (context)).createImageData(obj);
 | 
| -            for (var i = 0, n = obj.data.length; i < n; ++i)
 | 
| -              result.data[i] = obj.data[i];
 | 
| -            return result;
 | 
| -        }
 | 
| -
 | 
| -        // Try to convert to a primitive value via valueOf().
 | 
| -        if (typeof obj.valueOf === "function") {
 | 
| -            var value = obj.valueOf();
 | 
| -            var valueType = typeof value;
 | 
| -            if (valueType !== "object" && valueType !== "function")
 | 
| -                return value;
 | 
| -        }
 | 
| -
 | 
| -        console.error("ASSERT_NOT_REACHED: failed to clone object: ", obj);
 | 
| -        return obj;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!HTMLImageElement|!HTMLCanvasElement|!HTMLVideoElement} obj
 | 
| -     * @param {number=} width
 | 
| -     * @param {number=} height
 | 
| -     * @return {!HTMLCanvasElement}
 | 
| -     */
 | 
| -    cloneIntoCanvas: function(obj, width, height)
 | 
| -    {
 | 
| -        var canvas = /** @type {!HTMLCanvasElement} */ (inspectedWindow.document.createElement("canvas"));
 | 
| -        canvas.width = width || +obj.width;
 | 
| -        canvas.height = height || +obj.height;
 | 
| -        var context = /** @type {!CanvasRenderingContext2D} */ (Resource.wrappedObject(canvas.getContext("2d")));
 | 
| -        context.drawImage(obj, 0, 0);
 | 
| -        return canvas;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {?Object=} obj
 | 
| -     * @return {?Object}
 | 
| -     */
 | 
| -    cloneObject: function(obj)
 | 
| -    {
 | 
| -        if (!obj)
 | 
| -            return null;
 | 
| -        var result = {};
 | 
| -        for (var key in obj)
 | 
| -            result[key] = obj[key];
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Array.<string>} names
 | 
| -     * @return {!Object.<string, boolean>}
 | 
| -     */
 | 
| -    createPrefixedPropertyNamesSet: function(names)
 | 
| -    {
 | 
| -        var result = Object.create(null);
 | 
| -        for (var i = 0, name; name = names[i]; ++i) {
 | 
| -            result[name] = true;
 | 
| -            var suffix = name.substr(0, 1).toUpperCase() + name.substr(1);
 | 
| -            for (var j = 0, prefix; prefix = TypeUtils._supportedPropertyPrefixes[j]; ++j)
 | 
| -                result[prefix + suffix] = true;
 | 
| -        }
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    now: function()
 | 
| -    {
 | 
| -        try {
 | 
| -            return inspectedWindow.performance.now();
 | 
| -        } catch(e) {
 | 
| -            try {
 | 
| -                return Date.now();
 | 
| -            } catch(ex) {
 | 
| -            }
 | 
| -        }
 | 
| -        return 0;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {string} property
 | 
| -     * @param {!Object} obj
 | 
| -     * @return {boolean}
 | 
| -     */
 | 
| -    isEnumPropertyName: function(property, obj)
 | 
| -    {
 | 
| -        return (/^[A-Z][A-Z0-9_]+$/.test(property) && typeof obj[property] === "number");
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!CanvasRenderingContext2D}
 | 
| -     */
 | 
| -    _dummyCanvas2dContext: function()
 | 
| -    {
 | 
| -        var context = TypeUtils._dummyCanvas2dContextInstance;
 | 
| -        if (!context) {
 | 
| -            var canvas = /** @type {!HTMLCanvasElement} */ (inspectedWindow.document.createElement("canvas"));
 | 
| -            context = /** @type {!CanvasRenderingContext2D} */ (Resource.wrappedObject(canvas.getContext("2d")));
 | 
| -            TypeUtils._dummyCanvas2dContextInstance = context;
 | 
| -        }
 | 
| -        return context;
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/** @typedef {{name:string, valueIsEnum:(boolean|undefined), value:*, values:(!Array.<!TypeUtils.InternalResourceStateDescriptor>|undefined), isArray:(boolean|undefined)}} */
 | 
| -TypeUtils.InternalResourceStateDescriptor;
 | 
| -
 | 
| -/**
 | 
| - * @interface
 | 
| - */
 | 
| -function StackTrace()
 | 
| -{
 | 
| -}
 | 
| -
 | 
| -StackTrace.prototype = {
 | 
| -    /**
 | 
| -     * @param {number} index
 | 
| -     * @return {{sourceURL: string, lineNumber: number, columnNumber: number}|undefined}
 | 
| -     */
 | 
| -    callFrame: function(index)
 | 
| -    {
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @param {number=} stackTraceLimit
 | 
| - * @param {?Function=} topMostFunctionToIgnore
 | 
| - * @return {?StackTrace}
 | 
| - */
 | 
| -StackTrace.create = function(stackTraceLimit, topMostFunctionToIgnore)
 | 
| -{
 | 
| -    if (typeof Error.captureStackTrace === "function")
 | 
| -        return new StackTraceV8(stackTraceLimit, topMostFunctionToIgnore || arguments.callee);
 | 
| -    // FIXME: Support JSC, and maybe other browsers.
 | 
| -    return null;
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @implements {StackTrace}
 | 
| - * @param {number=} stackTraceLimit
 | 
| - * @param {?Function=} topMostFunctionToIgnore
 | 
| - * @see http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
 | 
| - */
 | 
| -function StackTraceV8(stackTraceLimit, topMostFunctionToIgnore)
 | 
| -{
 | 
| -    var oldPrepareStackTrace = Error.prepareStackTrace;
 | 
| -    var oldStackTraceLimit = Error.stackTraceLimit;
 | 
| -    if (typeof stackTraceLimit === "number")
 | 
| -        Error.stackTraceLimit = stackTraceLimit;
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Object} error
 | 
| -     * @param {!Array.<!CallSite>} structuredStackTrace
 | 
| -     * @return {!Array.<{sourceURL: string, lineNumber: number, columnNumber: number}>}
 | 
| -     */
 | 
| -    Error.prepareStackTrace = function(error, structuredStackTrace)
 | 
| -    {
 | 
| -        return structuredStackTrace.map(function(callSite) {
 | 
| -            return {
 | 
| -                sourceURL: callSite.getFileName(),
 | 
| -                lineNumber: callSite.getLineNumber(),
 | 
| -                columnNumber: callSite.getColumnNumber()
 | 
| -            };
 | 
| -        });
 | 
| -    }
 | 
| -
 | 
| -    var holder = /** @type {{stack: !Array.<{sourceURL: string, lineNumber: number, columnNumber: number}>}} */ ({});
 | 
| -    Error.captureStackTrace(holder, topMostFunctionToIgnore || arguments.callee);
 | 
| -    this._stackTrace = holder.stack;
 | 
| -
 | 
| -    Error.stackTraceLimit = oldStackTraceLimit;
 | 
| -    Error.prepareStackTrace = oldPrepareStackTrace;
 | 
| -}
 | 
| -
 | 
| -StackTraceV8.prototype = {
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {number} index
 | 
| -     * @return {{sourceURL: string, lineNumber: number, columnNumber: number}|undefined}
 | 
| -     */
 | 
| -    callFrame: function(index)
 | 
| -    {
 | 
| -        return this._stackTrace[index];
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @template T
 | 
| - */
 | 
| -function Cache()
 | 
| -{
 | 
| -    this.reset();
 | 
| -}
 | 
| -
 | 
| -Cache.prototype = {
 | 
| -    /**
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    size: function()
 | 
| -    {
 | 
| -        return this._size;
 | 
| -    },
 | 
| -
 | 
| -    reset: function()
 | 
| -    {
 | 
| -        /** @type {!Object.<number, !T>} */
 | 
| -        this._items = Object.create(null);
 | 
| -        /** @type {number} */
 | 
| -        this._size = 0;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} key
 | 
| -     * @return {boolean}
 | 
| -     */
 | 
| -    has: function(key)
 | 
| -    {
 | 
| -        return key in this._items;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} key
 | 
| -     * @return {T|undefined}
 | 
| -     */
 | 
| -    get: function(key)
 | 
| -    {
 | 
| -        return this._items[key];
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} key
 | 
| -     * @param {!T} item
 | 
| -     */
 | 
| -    put: function(key, item)
 | 
| -    {
 | 
| -        if (!this.has(key))
 | 
| -            ++this._size;
 | 
| -        this._items[key] = item;
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @param {?Resource|!Object} thisObject
 | 
| - * @param {string} functionName
 | 
| - * @param {!Array|!Arguments} args
 | 
| - * @param {!Resource|*=} result
 | 
| - * @param {?StackTrace=} stackTrace
 | 
| - */
 | 
| -function Call(thisObject, functionName, args, result, stackTrace)
 | 
| -{
 | 
| -    this._thisObject = thisObject;
 | 
| -    this._functionName = functionName;
 | 
| -    this._args = Array.prototype.slice.call(args, 0);
 | 
| -    this._result = result;
 | 
| -    this._stackTrace = stackTrace || null;
 | 
| -
 | 
| -    if (!this._functionName)
 | 
| -        console.assert(this._args.length === 2 && typeof this._args[0] === "string");
 | 
| -}
 | 
| -
 | 
| -Call.prototype = {
 | 
| -    /**
 | 
| -     * @return {?Resource}
 | 
| -     */
 | 
| -    resource: function()
 | 
| -    {
 | 
| -        return Resource.forObject(this._thisObject);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    functionName: function()
 | 
| -    {
 | 
| -        return this._functionName;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {boolean}
 | 
| -     */
 | 
| -    isPropertySetter: function()
 | 
| -    {
 | 
| -        return !this._functionName;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Array}
 | 
| -     */
 | 
| -    args: function()
 | 
| -    {
 | 
| -        return this._args;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {*}
 | 
| -     */
 | 
| -    result: function()
 | 
| -    {
 | 
| -        return this._result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?StackTrace}
 | 
| -     */
 | 
| -    stackTrace: function()
 | 
| -    {
 | 
| -        return this._stackTrace;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {?StackTrace} stackTrace
 | 
| -     */
 | 
| -    setStackTrace: function(stackTrace)
 | 
| -    {
 | 
| -        this._stackTrace = stackTrace;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {*} result
 | 
| -     */
 | 
| -    setResult: function(result)
 | 
| -    {
 | 
| -        this._result = result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {string} name
 | 
| -     * @param {?Object} attachment
 | 
| -     */
 | 
| -    setAttachment: function(name, attachment)
 | 
| -    {
 | 
| -        if (attachment) {
 | 
| -            /** @type {?Object.<string, !Object>|undefined} */
 | 
| -            this._attachments = this._attachments || Object.create(null);
 | 
| -            this._attachments[name] = attachment;
 | 
| -        } else if (this._attachments) {
 | 
| -            delete this._attachments[name];
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {string} name
 | 
| -     * @return {?Object}
 | 
| -     */
 | 
| -    attachment: function(name)
 | 
| -    {
 | 
| -        return this._attachments ? (this._attachments[name] || null) : null;
 | 
| -    },
 | 
| -
 | 
| -    freeze: function()
 | 
| -    {
 | 
| -        if (this._freezed)
 | 
| -            return;
 | 
| -        this._freezed = true;
 | 
| -        for (var i = 0, n = this._args.length; i < n; ++i) {
 | 
| -            // FIXME: freeze the Resources also!
 | 
| -            if (!Resource.forObject(this._args[i]))
 | 
| -                this._args[i] = TypeUtils.clone(this._args[i]);
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Cache.<!ReplayableResource>} cache
 | 
| -     * @return {!ReplayableCall}
 | 
| -     */
 | 
| -    toReplayable: function(cache)
 | 
| -    {
 | 
| -        this.freeze();
 | 
| -        var thisObject = /** @type {!ReplayableResource} */ (Resource.toReplayable(this._thisObject, cache));
 | 
| -        var result = Resource.toReplayable(this._result, cache);
 | 
| -        var args = this._args.map(function(obj) {
 | 
| -            return Resource.toReplayable(obj, cache);
 | 
| -        });
 | 
| -        var attachments = TypeUtils.cloneObject(this._attachments);
 | 
| -        return new ReplayableCall(thisObject, this._functionName, args, result, this._stackTrace, attachments);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!ReplayableCall} replayableCall
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     * @return {!Call}
 | 
| -     */
 | 
| -    replay: function(replayableCall, cache)
 | 
| -    {
 | 
| -        var replayableResult = replayableCall.result();
 | 
| -        if (replayableResult instanceof ReplayableResource && !cache.has(replayableResult.id())) {
 | 
| -            var resource = replayableResult.replay(cache);
 | 
| -            console.assert(resource.calls().length > 0, "Expected create* call for the Resource");
 | 
| -            return resource.calls()[0];
 | 
| -        }
 | 
| -
 | 
| -        var replayObject = ReplayableResource.replay(replayableCall.replayableResource(), cache);
 | 
| -        var replayArgs = replayableCall.args().map(function(obj) {
 | 
| -            return ReplayableResource.replay(obj, cache);
 | 
| -        });
 | 
| -        var replayResult = undefined;
 | 
| -
 | 
| -        if (replayableCall.isPropertySetter())
 | 
| -            replayObject[replayArgs[0]] = replayArgs[1];
 | 
| -        else {
 | 
| -            var replayFunction = replayObject[replayableCall.functionName()];
 | 
| -            console.assert(typeof replayFunction === "function", "Expected a function to replay");
 | 
| -            replayResult = replayFunction.apply(replayObject, replayArgs);
 | 
| -
 | 
| -            if (replayableResult instanceof ReplayableResource) {
 | 
| -                var resource = replayableResult.replay(cache);
 | 
| -                if (!resource.wrappedObject())
 | 
| -                    resource.setWrappedObject(replayResult);
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        this._thisObject = replayObject;
 | 
| -        this._functionName = replayableCall.functionName();
 | 
| -        this._args = replayArgs;
 | 
| -        this._result = replayResult;
 | 
| -        this._stackTrace = replayableCall.stackTrace();
 | 
| -        this._freezed = true;
 | 
| -        var attachments = replayableCall.attachments();
 | 
| -        this._attachments = attachments ? TypeUtils.cloneObject(attachments) : null;
 | 
| -        return this;
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @param {!ReplayableResource} thisObject
 | 
| - * @param {string} functionName
 | 
| - * @param {!Array.<!ReplayableResource|*>} args
 | 
| - * @param {!ReplayableResource|*} result
 | 
| - * @param {?StackTrace} stackTrace
 | 
| - * @param {?Object.<string, !Object>} attachments
 | 
| - */
 | 
| -function ReplayableCall(thisObject, functionName, args, result, stackTrace, attachments)
 | 
| -{
 | 
| -    this._thisObject = thisObject;
 | 
| -    this._functionName = functionName;
 | 
| -    this._args = args;
 | 
| -    this._result = result;
 | 
| -    this._stackTrace = stackTrace;
 | 
| -    if (attachments)
 | 
| -        this._attachments = attachments;
 | 
| -}
 | 
| -
 | 
| -ReplayableCall.prototype = {
 | 
| -    /**
 | 
| -     * @return {!ReplayableResource}
 | 
| -     */
 | 
| -    replayableResource: function()
 | 
| -    {
 | 
| -        return this._thisObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    functionName: function()
 | 
| -    {
 | 
| -        return this._functionName;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {boolean}
 | 
| -     */
 | 
| -    isPropertySetter: function()
 | 
| -    {
 | 
| -        return !this._functionName;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    propertyName: function()
 | 
| -    {
 | 
| -        console.assert(this.isPropertySetter());
 | 
| -        return /** @type {string} */ (this._args[0]);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {*}
 | 
| -     */
 | 
| -    propertyValue: function()
 | 
| -    {
 | 
| -        console.assert(this.isPropertySetter());
 | 
| -        return this._args[1];
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Array.<!ReplayableResource|*>}
 | 
| -     */
 | 
| -    args: function()
 | 
| -    {
 | 
| -        return this._args;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!ReplayableResource|*}
 | 
| -     */
 | 
| -    result: function()
 | 
| -    {
 | 
| -        return this._result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?StackTrace}
 | 
| -     */
 | 
| -    stackTrace: function()
 | 
| -    {
 | 
| -        return this._stackTrace;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?Object.<string, !Object>}
 | 
| -     */
 | 
| -    attachments: function()
 | 
| -    {
 | 
| -        return this._attachments || null;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {string} name
 | 
| -     * @return {!Object}
 | 
| -     */
 | 
| -    attachment: function(name)
 | 
| -    {
 | 
| -        return this._attachments && this._attachments[name];
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     * @return {!Call}
 | 
| -     */
 | 
| -    replay: function(cache)
 | 
| -    {
 | 
| -        var call = /** @type {!Call} */ (Object.create(Call.prototype));
 | 
| -        return call.replay(this, cache);
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function Resource(wrappedObject, name)
 | 
| -{
 | 
| -    /** @type {number} */
 | 
| -    this._id = ++Resource._uniqueId;
 | 
| -    /** @type {string} */
 | 
| -    this._name = name || "Resource";
 | 
| -    /** @type {number} */
 | 
| -    this._kindId = Resource._uniqueKindIds[this._name] = (Resource._uniqueKindIds[this._name] || 0) + 1;
 | 
| -    /** @type {?ResourceTrackingManager} */
 | 
| -    this._resourceManager = null;
 | 
| -    /** @type {!Array.<!Call>} */
 | 
| -    this._calls = [];
 | 
| -    /**
 | 
| -     * This is to prevent GC from collecting associated resources.
 | 
| -     * Otherwise, for example in WebGL, subsequent calls to gl.getParameter()
 | 
| -     * may return a recently created instance that is no longer bound to a
 | 
| -     * Resource object (thus, no history to replay it later).
 | 
| -     *
 | 
| -     * @type {!Object.<string, !Resource>}
 | 
| -     */
 | 
| -    this._boundResources = Object.create(null);
 | 
| -    this.setWrappedObject(wrappedObject);
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @type {number}
 | 
| - */
 | 
| -Resource._uniqueId = 0;
 | 
| -
 | 
| -/**
 | 
| - * @type {!Object.<string, number>}
 | 
| - */
 | 
| -Resource._uniqueKindIds = {};
 | 
| -
 | 
| -/**
 | 
| - * @param {*} obj
 | 
| - * @return {?Resource}
 | 
| - */
 | 
| -Resource.forObject = function(obj)
 | 
| -{
 | 
| -    if (!obj)
 | 
| -        return null;
 | 
| -    if (obj instanceof Resource)
 | 
| -        return obj;
 | 
| -    if (typeof obj === "object")
 | 
| -        return obj["__resourceObject"];
 | 
| -    return null;
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @param {!Resource|*} obj
 | 
| - * @return {*}
 | 
| - */
 | 
| -Resource.wrappedObject = function(obj)
 | 
| -{
 | 
| -    var resource = Resource.forObject(obj);
 | 
| -    return resource ? resource.wrappedObject() : obj;
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @param {!Resource|*} obj
 | 
| - * @param {!Cache.<!ReplayableResource>} cache
 | 
| - * @return {!ReplayableResource|*}
 | 
| - */
 | 
| -Resource.toReplayable = function(obj, cache)
 | 
| -{
 | 
| -    var resource = Resource.forObject(obj);
 | 
| -    return resource ? resource.toReplayable(cache) : obj;
 | 
| -}
 | 
| -
 | 
| -Resource.prototype = {
 | 
| -    /**
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    id: function()
 | 
| -    {
 | 
| -        return this._id;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    name: function()
 | 
| -    {
 | 
| -        return this._name;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    description: function()
 | 
| -    {
 | 
| -        return this._name + "@" + this._kindId;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Object}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Object} value
 | 
| -     */
 | 
| -    setWrappedObject: function(value)
 | 
| -    {
 | 
| -        console.assert(value, "wrappedObject should not be NULL");
 | 
| -        console.assert(!(value instanceof Resource), "Binding a Resource object to another Resource object?");
 | 
| -        this._wrappedObject = value;
 | 
| -        this._bindObjectToResource(value);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Object}
 | 
| -     */
 | 
| -    proxyObject: function()
 | 
| -    {
 | 
| -        if (!this._proxyObject)
 | 
| -            this._proxyObject = this._wrapObject();
 | 
| -        return this._proxyObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?ResourceTrackingManager}
 | 
| -     */
 | 
| -    manager: function()
 | 
| -    {
 | 
| -        return this._resourceManager;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!ResourceTrackingManager} value
 | 
| -     */
 | 
| -    setManager: function(value)
 | 
| -    {
 | 
| -        this._resourceManager = value;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Array.<!Call>}
 | 
| -     */
 | 
| -    calls: function()
 | 
| -    {
 | 
| -        return this._calls;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?ContextResource}
 | 
| -     */
 | 
| -    contextResource: function()
 | 
| -    {
 | 
| -        if (this instanceof ContextResource)
 | 
| -            return /** @type {!ContextResource} */ (this);
 | 
| -
 | 
| -        if (this._calculatingContextResource)
 | 
| -            return null;
 | 
| -
 | 
| -        this._calculatingContextResource = true;
 | 
| -        var result = null;
 | 
| -        for (var i = 0, n = this._calls.length; i < n; ++i) {
 | 
| -            result = this._calls[i].resource().contextResource();
 | 
| -            if (result)
 | 
| -                break;
 | 
| -        }
 | 
| -        delete this._calculatingContextResource;
 | 
| -        console.assert(result, "Failed to find context resource for " + this._name + "@" + this._kindId);
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        var result = [];
 | 
| -        var proxyObject = this.proxyObject();
 | 
| -        if (!proxyObject)
 | 
| -            return result;
 | 
| -        var statePropertyNames = this._proxyStatePropertyNames || [];
 | 
| -        for (var i = 0, n = statePropertyNames.length; i < n; ++i) {
 | 
| -            var pname = statePropertyNames[i];
 | 
| -            result.push({ name: pname, value: proxyObject[pname] });
 | 
| -        }
 | 
| -        result.push({ name: "context", value: this.contextResource() });
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    toDataURL: function()
 | 
| -    {
 | 
| -        return "";
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Cache.<!ReplayableResource>} cache
 | 
| -     * @return {!ReplayableResource}
 | 
| -     */
 | 
| -    toReplayable: function(cache)
 | 
| -    {
 | 
| -        var result = cache.get(this._id);
 | 
| -        if (result)
 | 
| -            return result;
 | 
| -        var data = {
 | 
| -            id: this._id,
 | 
| -            name: this._name,
 | 
| -            kindId: this._kindId
 | 
| -        };
 | 
| -        result = new ReplayableResource(this, data);
 | 
| -        cache.put(this._id, result); // Put into the cache early to avoid loops.
 | 
| -        data.calls = this._calls.map(function(call) {
 | 
| -            return call.toReplayable(cache);
 | 
| -        });
 | 
| -        this._populateReplayableData(data, cache);
 | 
| -        var contextResource = this.contextResource();
 | 
| -        if (contextResource !== this)
 | 
| -            data.contextResource = Resource.toReplayable(contextResource, cache);
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!ReplayableResource>} cache
 | 
| -     */
 | 
| -    _populateReplayableData: function(data, cache)
 | 
| -    {
 | 
| -        // Do nothing. Should be overridden by subclasses.
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     * @return {!Resource}
 | 
| -     */
 | 
| -    replay: function(data, cache)
 | 
| -    {
 | 
| -        var resource = cache.get(data.id);
 | 
| -        if (resource)
 | 
| -            return resource;
 | 
| -        this._id = data.id;
 | 
| -        this._name = data.name;
 | 
| -        this._kindId = data.kindId;
 | 
| -        this._resourceManager = null;
 | 
| -        this._calls = [];
 | 
| -        this._boundResources = Object.create(null);
 | 
| -        this._wrappedObject = null;
 | 
| -        cache.put(data.id, this); // Put into the cache early to avoid loops.
 | 
| -        this._doReplayCalls(data, cache);
 | 
| -        console.assert(this._wrappedObject, "Resource should be reconstructed!");
 | 
| -        return this;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     */
 | 
| -    _doReplayCalls: function(data, cache)
 | 
| -    {
 | 
| -        for (var i = 0, n = data.calls.length; i < n; ++i)
 | 
| -            this._calls.push(data.calls[i].replay(cache));
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall: function(call)
 | 
| -    {
 | 
| -        call.freeze();
 | 
| -        this._calls.push(call);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    onCallReplayed: function(call)
 | 
| -    {
 | 
| -        // Ignore by default.
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Object} object
 | 
| -     */
 | 
| -    _bindObjectToResource: function(object)
 | 
| -    {
 | 
| -        Object.defineProperty(object, "__resourceObject", {
 | 
| -            value: this,
 | 
| -            writable: false,
 | 
| -            enumerable: false,
 | 
| -            configurable: true
 | 
| -        });
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {string} key
 | 
| -     * @param {*} obj
 | 
| -     */
 | 
| -    _registerBoundResource: function(key, obj)
 | 
| -    {
 | 
| -        var resource = Resource.forObject(obj);
 | 
| -        if (resource)
 | 
| -            this._boundResources[key] = resource;
 | 
| -        else
 | 
| -            delete this._boundResources[key];
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?Object}
 | 
| -     */
 | 
| -    _wrapObject: function()
 | 
| -    {
 | 
| -        var wrappedObject = this.wrappedObject();
 | 
| -        if (!wrappedObject)
 | 
| -            return null;
 | 
| -        var proxy = Object.create(wrappedObject.__proto__); // In order to emulate "instanceof".
 | 
| -
 | 
| -        var customWrapFunctions = this._customWrapFunctions();
 | 
| -        /** @type {!Array.<string>} */
 | 
| -        this._proxyStatePropertyNames = [];
 | 
| -
 | 
| -        /**
 | 
| -         * @param {string} property
 | 
| -         * @this {Resource}
 | 
| -         */
 | 
| -        function processProperty(property)
 | 
| -        {
 | 
| -            if (typeof wrappedObject[property] === "function") {
 | 
| -                var customWrapFunction = customWrapFunctions[property];
 | 
| -                if (customWrapFunction)
 | 
| -                    proxy[property] = this._wrapCustomFunction(this, wrappedObject, wrappedObject[property], property, customWrapFunction);
 | 
| -                else
 | 
| -                    proxy[property] = this._wrapFunction(this, wrappedObject, wrappedObject[property], property);
 | 
| -            } else if (TypeUtils.isEnumPropertyName(property, wrappedObject)) {
 | 
| -                // Fast access to enums and constants.
 | 
| -                proxy[property] = wrappedObject[property];
 | 
| -            } else {
 | 
| -                this._proxyStatePropertyNames.push(property);
 | 
| -                Object.defineProperty(proxy, property, {
 | 
| -                    get: function()
 | 
| -                    {
 | 
| -                        var obj = wrappedObject[property];
 | 
| -                        var resource = Resource.forObject(obj);
 | 
| -                        return resource ? resource : obj;
 | 
| -                    },
 | 
| -                    set: this._wrapPropertySetter(this, wrappedObject, property),
 | 
| -                    enumerable: true
 | 
| -                });
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        var isEmpty = true;
 | 
| -        for (var property in wrappedObject) {
 | 
| -            isEmpty = false;
 | 
| -            processProperty.call(this, property);
 | 
| -        }
 | 
| -        if (isEmpty)
 | 
| -            return wrappedObject; // Nothing to proxy.
 | 
| -
 | 
| -        this._bindObjectToResource(proxy);
 | 
| -        return proxy;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Resource} resource
 | 
| -     * @param {!Object} originalObject
 | 
| -     * @param {!Function} originalFunction
 | 
| -     * @param {string} functionName
 | 
| -     * @param {!Function} customWrapFunction
 | 
| -     * @return {!Function}
 | 
| -     */
 | 
| -    _wrapCustomFunction: function(resource, originalObject, originalFunction, functionName, customWrapFunction)
 | 
| -    {
 | 
| -        return function()
 | 
| -        {
 | 
| -            var manager = resource.manager();
 | 
| -            var isCapturing = manager && manager.capturing();
 | 
| -            if (isCapturing)
 | 
| -                manager.captureArguments(resource, arguments);
 | 
| -            var wrapFunction = new Resource.WrapFunction(originalObject, originalFunction, functionName, arguments);
 | 
| -            customWrapFunction.apply(wrapFunction, arguments);
 | 
| -            if (isCapturing) {
 | 
| -                var call = wrapFunction.call();
 | 
| -                call.setStackTrace(StackTrace.create(1, arguments.callee));
 | 
| -                manager.captureCall(call);
 | 
| -            }
 | 
| -            return wrapFunction.result();
 | 
| -        };
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Resource} resource
 | 
| -     * @param {!Object} originalObject
 | 
| -     * @param {!Function} originalFunction
 | 
| -     * @param {string} functionName
 | 
| -     * @return {!Function}
 | 
| -     */
 | 
| -    _wrapFunction: function(resource, originalObject, originalFunction, functionName)
 | 
| -    {
 | 
| -        return function()
 | 
| -        {
 | 
| -            var manager = resource.manager();
 | 
| -            if (!manager || !manager.capturing())
 | 
| -                return originalFunction.apply(originalObject, arguments);
 | 
| -            manager.captureArguments(resource, arguments);
 | 
| -            var result = originalFunction.apply(originalObject, arguments);
 | 
| -            var stackTrace = StackTrace.create(1, arguments.callee);
 | 
| -            var call = new Call(resource, functionName, arguments, result, stackTrace);
 | 
| -            manager.captureCall(call);
 | 
| -            return result;
 | 
| -        };
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Resource} resource
 | 
| -     * @param {!Object} originalObject
 | 
| -     * @param {string} propertyName
 | 
| -     * @return {function(*)}
 | 
| -     */
 | 
| -    _wrapPropertySetter: function(resource, originalObject, propertyName)
 | 
| -    {
 | 
| -        return function(value)
 | 
| -        {
 | 
| -            resource._registerBoundResource(propertyName, value);
 | 
| -            var manager = resource.manager();
 | 
| -            if (!manager || !manager.capturing()) {
 | 
| -                originalObject[propertyName] = Resource.wrappedObject(value);
 | 
| -                return;
 | 
| -            }
 | 
| -            var args = [propertyName, value];
 | 
| -            manager.captureArguments(resource, args);
 | 
| -            originalObject[propertyName] = Resource.wrappedObject(value);
 | 
| -            var stackTrace = StackTrace.create(1, arguments.callee);
 | 
| -            var call = new Call(resource, "", args, undefined, stackTrace);
 | 
| -            manager.captureCall(call);
 | 
| -        };
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Object.<string, !Function>}
 | 
| -     */
 | 
| -    _customWrapFunctions: function()
 | 
| -    {
 | 
| -        return Object.create(null); // May be overridden by subclasses.
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @param {!Object} originalObject
 | 
| - * @param {!Function} originalFunction
 | 
| - * @param {string} functionName
 | 
| - * @param {!Array|!Arguments} args
 | 
| - */
 | 
| -Resource.WrapFunction = function(originalObject, originalFunction, functionName, args)
 | 
| -{
 | 
| -    this._originalObject = originalObject;
 | 
| -    this._originalFunction = originalFunction;
 | 
| -    this._functionName = functionName;
 | 
| -    this._args = args;
 | 
| -    this._resource = Resource.forObject(originalObject);
 | 
| -    console.assert(this._resource, "Expected a wrapped call on a Resource object.");
 | 
| -}
 | 
| -
 | 
| -Resource.WrapFunction.prototype = {
 | 
| -    /**
 | 
| -     * @return {*}
 | 
| -     */
 | 
| -    result: function()
 | 
| -    {
 | 
| -        if (!this._executed) {
 | 
| -            this._executed = true;
 | 
| -            this._result = this._originalFunction.apply(this._originalObject, this._args);
 | 
| -        }
 | 
| -        return this._result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Call}
 | 
| -     */
 | 
| -    call: function()
 | 
| -    {
 | 
| -        if (!this._call)
 | 
| -            this._call = new Call(this._resource, this._functionName, this._args, this.result());
 | 
| -        return this._call;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {*} result
 | 
| -     */
 | 
| -    overrideResult: function(result)
 | 
| -    {
 | 
| -        var call = this.call();
 | 
| -        call.setResult(result);
 | 
| -        this._result = result;
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @param {function(new:Resource, !Object, string)} resourceConstructor
 | 
| - * @param {string} resourceName
 | 
| - * @return {function(this:Resource.WrapFunction)}
 | 
| - */
 | 
| -Resource.WrapFunction.resourceFactoryMethod = function(resourceConstructor, resourceName)
 | 
| -{
 | 
| -    return /** @this {Resource.WrapFunction} */ function()
 | 
| -    {
 | 
| -        var wrappedObject = /** @type {?Object} */ (this.result());
 | 
| -        if (!wrappedObject)
 | 
| -            return;
 | 
| -        var resource = new resourceConstructor(wrappedObject, resourceName);
 | 
| -        var manager = this._resource.manager();
 | 
| -        if (manager)
 | 
| -            manager.registerResource(resource);
 | 
| -        this.overrideResult(resource.proxyObject());
 | 
| -        resource.pushCall(this.call());
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @param {!Resource} originalResource
 | 
| - * @param {!Object} data
 | 
| - */
 | 
| -function ReplayableResource(originalResource, data)
 | 
| -{
 | 
| -    this._proto = originalResource.__proto__;
 | 
| -    this._data = data;
 | 
| -}
 | 
| -
 | 
| -ReplayableResource.prototype = {
 | 
| -    /**
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    id: function()
 | 
| -    {
 | 
| -        return this._data.id;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    name: function()
 | 
| -    {
 | 
| -        return this._data.name;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    description: function()
 | 
| -    {
 | 
| -        return this._data.name + "@" + this._data.kindId;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!ReplayableResource}
 | 
| -     */
 | 
| -    contextResource: function()
 | 
| -    {
 | 
| -        return this._data.contextResource || this;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     * @return {!Resource}
 | 
| -     */
 | 
| -    replay: function(cache)
 | 
| -    {
 | 
| -        var result = /** @type {!Resource} */ (Object.create(this._proto));
 | 
| -        result = result.replay(this._data, cache)
 | 
| -        console.assert(result.__proto__ === this._proto, "Wrong type of a replay result");
 | 
| -        return result;
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @param {!ReplayableResource|*} obj
 | 
| - * @param {!Cache.<!Resource>} cache
 | 
| - * @return {*}
 | 
| - */
 | 
| -ReplayableResource.replay = function(obj, cache)
 | 
| -{
 | 
| -    return (obj instanceof ReplayableResource) ? obj.replay(cache).wrappedObject() : obj;
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {Resource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function ContextResource(wrappedObject, name)
 | 
| -{
 | 
| -    Resource.call(this, wrappedObject, name);
 | 
| -}
 | 
| -
 | 
| -ContextResource.prototype = {
 | 
| -    __proto__: Resource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {Resource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function LogEverythingResource(wrappedObject, name)
 | 
| -{
 | 
| -    Resource.call(this, wrappedObject, name);
 | 
| -}
 | 
| -
 | 
| -LogEverythingResource.prototype = {
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Object.<string, !Function>}
 | 
| -     */
 | 
| -    _customWrapFunctions: function()
 | 
| -    {
 | 
| -        var wrapFunctions = Object.create(null);
 | 
| -        var wrappedObject = this.wrappedObject();
 | 
| -        if (wrappedObject) {
 | 
| -            for (var property in wrappedObject) {
 | 
| -                /** @this {Resource.WrapFunction} */
 | 
| -                wrapFunctions[property] = function()
 | 
| -                {
 | 
| -                    this._resource.pushCall(this.call());
 | 
| -                }
 | 
| -            }
 | 
| -        }
 | 
| -        return wrapFunctions;
 | 
| -    },
 | 
| -
 | 
| -    __proto__: Resource.prototype
 | 
| -}
 | 
| -
 | 
| -////////////////////////////////////////////////////////////////////////////////
 | 
| -// WebGL
 | 
| -////////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {Resource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function WebGLBoundResource(wrappedObject, name)
 | 
| -{
 | 
| -    Resource.call(this, wrappedObject, name);
 | 
| -    /** @type {!Object.<string, *>} */
 | 
| -    this._state = {};
 | 
| -}
 | 
| -
 | 
| -WebGLBoundResource.prototype = {
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!ReplayableResource>} cache
 | 
| -     */
 | 
| -    _populateReplayableData: function(data, cache)
 | 
| -    {
 | 
| -        var state = this._state;
 | 
| -        data.state = {};
 | 
| -        Object.keys(state).forEach(function(parameter) {
 | 
| -            data.state[parameter] = Resource.toReplayable(state[parameter], cache);
 | 
| -        });
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     */
 | 
| -    _doReplayCalls: function(data, cache)
 | 
| -    {
 | 
| -        var gl = this._replayContextResource(data, cache).wrappedObject();
 | 
| -
 | 
| -        /** @type {!Object.<string, !Array.<string>>} */
 | 
| -        var bindingsData = {
 | 
| -            TEXTURE_2D: ["bindTexture", "TEXTURE_BINDING_2D"],
 | 
| -            TEXTURE_CUBE_MAP: ["bindTexture", "TEXTURE_BINDING_CUBE_MAP"],
 | 
| -            ARRAY_BUFFER: ["bindBuffer", "ARRAY_BUFFER_BINDING"],
 | 
| -            ELEMENT_ARRAY_BUFFER: ["bindBuffer", "ELEMENT_ARRAY_BUFFER_BINDING"],
 | 
| -            FRAMEBUFFER: ["bindFramebuffer", "FRAMEBUFFER_BINDING"],
 | 
| -            RENDERBUFFER: ["bindRenderbuffer", "RENDERBUFFER_BINDING"]
 | 
| -        };
 | 
| -        var originalBindings = {};
 | 
| -        Object.keys(bindingsData).forEach(function(bindingTarget) {
 | 
| -            var bindingParameter = bindingsData[bindingTarget][1];
 | 
| -            originalBindings[bindingTarget] = gl.getParameter(gl[bindingParameter]);
 | 
| -        });
 | 
| -
 | 
| -        var state = {};
 | 
| -        Object.keys(data.state).forEach(function(parameter) {
 | 
| -            state[parameter] = ReplayableResource.replay(data.state[parameter], cache);
 | 
| -        });
 | 
| -        this._state = state;
 | 
| -        Resource.prototype._doReplayCalls.call(this, data, cache);
 | 
| -
 | 
| -        Object.keys(bindingsData).forEach(function(bindingTarget) {
 | 
| -            var bindMethodName = bindingsData[bindingTarget][0];
 | 
| -            gl[bindMethodName].call(gl, gl[bindingTarget], originalBindings[bindingTarget]);
 | 
| -        });
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     * @return {?WebGLRenderingContextResource}
 | 
| -     */
 | 
| -    _replayContextResource: function(data, cache)
 | 
| -    {
 | 
| -        var calls = /** @type {!Array.<!ReplayableCall>} */ (data.calls);
 | 
| -        for (var i = 0, n = calls.length; i < n; ++i) {
 | 
| -            var resource = ReplayableResource.replay(calls[i].replayableResource(), cache);
 | 
| -            var contextResource = WebGLRenderingContextResource.forObject(resource);
 | 
| -            if (contextResource)
 | 
| -                return contextResource;
 | 
| -        }
 | 
| -        return null;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} target
 | 
| -     * @param {string} bindMethodName
 | 
| -     */
 | 
| -    pushBinding: function(target, bindMethodName)
 | 
| -    {
 | 
| -        if (this._state.bindTarget !== target) {
 | 
| -            this._state.bindTarget = target;
 | 
| -            this.pushCall(new Call(WebGLRenderingContextResource.forObject(this), bindMethodName, [target, this]));
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    __proto__: Resource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {WebGLBoundResource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function WebGLTextureResource(wrappedObject, name)
 | 
| -{
 | 
| -    WebGLBoundResource.call(this, wrappedObject, name);
 | 
| -}
 | 
| -
 | 
| -WebGLTextureResource.prototype = {
 | 
| -    /**
 | 
| -     * @override (overrides @return type)
 | 
| -     * @return {!WebGLTexture}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        var result = [];
 | 
| -        var glResource = WebGLRenderingContextResource.forObject(this);
 | 
| -        var gl = glResource.wrappedObject();
 | 
| -        var texture = this.wrappedObject();
 | 
| -        if (!gl || !texture)
 | 
| -            return result;
 | 
| -        result.push({ name: "isTexture", value: gl.isTexture(texture) });
 | 
| -        result.push({ name: "context", value: this.contextResource() });
 | 
| -
 | 
| -        var target = this._state.bindTarget;
 | 
| -        if (typeof target !== "number")
 | 
| -            return result;
 | 
| -
 | 
| -        var bindingParameter;
 | 
| -        switch (target) {
 | 
| -        case gl.TEXTURE_2D:
 | 
| -            bindingParameter = gl.TEXTURE_BINDING_2D;
 | 
| -            break;
 | 
| -        case gl.TEXTURE_CUBE_MAP:
 | 
| -            bindingParameter = gl.TEXTURE_BINDING_CUBE_MAP;
 | 
| -            break;
 | 
| -        default:
 | 
| -            console.error("ASSERT_NOT_REACHED: unknown texture target " + target);
 | 
| -            return result;
 | 
| -        }
 | 
| -        result.push({ name: "target", value: target, valueIsEnum: true });
 | 
| -
 | 
| -        var oldTexture = /** @type {!WebGLTexture} */ (gl.getParameter(bindingParameter));
 | 
| -        if (oldTexture !== texture)
 | 
| -            gl.bindTexture(target, texture);
 | 
| -
 | 
| -        var textureParameters = [
 | 
| -            "TEXTURE_MAG_FILTER",
 | 
| -            "TEXTURE_MIN_FILTER",
 | 
| -            "TEXTURE_WRAP_S",
 | 
| -            "TEXTURE_WRAP_T",
 | 
| -            "TEXTURE_MAX_ANISOTROPY_EXT" // EXT_texture_filter_anisotropic extension
 | 
| -        ];
 | 
| -        glResource.queryStateValues(gl.getTexParameter, target, textureParameters, result);
 | 
| -
 | 
| -        if (oldTexture !== texture)
 | 
| -            gl.bindTexture(target, oldTexture);
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     */
 | 
| -    _doReplayCalls: function(data, cache)
 | 
| -    {
 | 
| -        var gl = this._replayContextResource(data, cache).wrappedObject();
 | 
| -
 | 
| -        var state = {};
 | 
| -        WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) {
 | 
| -            state[parameter] = gl.getParameter(gl[parameter]);
 | 
| -        });
 | 
| -
 | 
| -        WebGLBoundResource.prototype._doReplayCalls.call(this, data, cache);
 | 
| -
 | 
| -        WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) {
 | 
| -            gl.pixelStorei(gl[parameter], state[parameter]);
 | 
| -        });
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall: function(call)
 | 
| -    {
 | 
| -        var gl = WebGLRenderingContextResource.forObject(call.resource()).wrappedObject();
 | 
| -        WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) {
 | 
| -            var value = gl.getParameter(gl[parameter]);
 | 
| -            if (this._state[parameter] !== value) {
 | 
| -                this._state[parameter] = value;
 | 
| -                var pixelStoreCall = new Call(gl, "pixelStorei", [gl[parameter], value]);
 | 
| -                WebGLBoundResource.prototype.pushCall.call(this, pixelStoreCall);
 | 
| -            }
 | 
| -        }, this);
 | 
| -
 | 
| -        // FIXME: remove any older calls that no longer contribute to the resource state.
 | 
| -        // FIXME: optimize memory usage: maybe it's more efficient to store one texImage2D call instead of many texSubImage2D.
 | 
| -        WebGLBoundResource.prototype.pushCall.call(this, call);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * Handles: texParameteri, texParameterf
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall_texParameter: function(call)
 | 
| -    {
 | 
| -        var args = call.args();
 | 
| -        var pname = args[1];
 | 
| -        var param = args[2];
 | 
| -        if (this._state[pname] !== param) {
 | 
| -            this._state[pname] = param;
 | 
| -            WebGLBoundResource.prototype.pushCall.call(this, call);
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * Handles: copyTexImage2D, copyTexSubImage2D
 | 
| -     * copyTexImage2D and copyTexSubImage2D define a texture image with pixels from the current framebuffer.
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall_copyTexImage2D: function(call)
 | 
| -    {
 | 
| -        var glResource = WebGLRenderingContextResource.forObject(call.resource());
 | 
| -        var gl = glResource.wrappedObject();
 | 
| -        var framebufferResource = /** @type {!WebGLFramebufferResource} */ (glResource.currentBinding(gl.FRAMEBUFFER));
 | 
| -        if (framebufferResource)
 | 
| -            this.pushCall(new Call(glResource, "bindFramebuffer", [gl.FRAMEBUFFER, framebufferResource]));
 | 
| -        else {
 | 
| -            // FIXME: Implement this case.
 | 
| -            console.error("ASSERT_NOT_REACHED: Could not properly process a gl." + call.functionName() + " call while the DRAWING BUFFER is bound.");
 | 
| -        }
 | 
| -        this.pushCall(call);
 | 
| -    },
 | 
| -
 | 
| -    __proto__: WebGLBoundResource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {Resource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function WebGLProgramResource(wrappedObject, name)
 | 
| -{
 | 
| -    Resource.call(this, wrappedObject, name);
 | 
| -}
 | 
| -
 | 
| -WebGLProgramResource.prototype = {
 | 
| -    /**
 | 
| -     * @override (overrides @return type)
 | 
| -     * @return {!WebGLProgram}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        /**
 | 
| -         * @param {!Object} obj
 | 
| -         * @param {!Array.<!TypeUtils.InternalResourceStateDescriptor>} output
 | 
| -         */
 | 
| -        function convertToStateDescriptors(obj, output)
 | 
| -        {
 | 
| -            for (var pname in obj)
 | 
| -                output.push({ name: pname, value: obj[pname], valueIsEnum: (pname === "type") });
 | 
| -        }
 | 
| -
 | 
| -        var result = [];
 | 
| -        var program = this.wrappedObject();
 | 
| -        if (!program)
 | 
| -            return result;
 | 
| -        var glResource = WebGLRenderingContextResource.forObject(this);
 | 
| -        var gl = glResource.wrappedObject();
 | 
| -        var programParameters = ["DELETE_STATUS", "LINK_STATUS", "VALIDATE_STATUS"];
 | 
| -        glResource.queryStateValues(gl.getProgramParameter, program, programParameters, result);
 | 
| -        result.push({ name: "getProgramInfoLog", value: gl.getProgramInfoLog(program) });
 | 
| -        result.push({ name: "isProgram", value: gl.isProgram(program) });
 | 
| -        result.push({ name: "context", value: this.contextResource() });
 | 
| -
 | 
| -        // ATTACHED_SHADERS
 | 
| -        var callFormatter = CallFormatter.forResource(this);
 | 
| -        var shaders = gl.getAttachedShaders(program) || [];
 | 
| -        var shaderDescriptors = [];
 | 
| -        for (var i = 0, n = shaders.length; i < n; ++i) {
 | 
| -            var shaderResource = Resource.forObject(shaders[i]);
 | 
| -            var pname = callFormatter.enumNameForValue(shaderResource.type());
 | 
| -            shaderDescriptors.push({ name: pname, value: shaderResource });
 | 
| -        }
 | 
| -        result.push({ name: "ATTACHED_SHADERS", values: shaderDescriptors, isArray: true });
 | 
| -
 | 
| -        // ACTIVE_UNIFORMS
 | 
| -        var uniformDescriptors = [];
 | 
| -        var uniforms = this._activeUniforms(true);
 | 
| -        for (var i = 0, n = uniforms.length; i < n; ++i) {
 | 
| -            var pname = "" + i;
 | 
| -            var values = [];
 | 
| -            convertToStateDescriptors(uniforms[i], values);
 | 
| -            uniformDescriptors.push({ name: pname, values: values });
 | 
| -        }
 | 
| -        result.push({ name: "ACTIVE_UNIFORMS", values: uniformDescriptors, isArray: true });
 | 
| -
 | 
| -        // ACTIVE_ATTRIBUTES
 | 
| -        var attributesCount = /** @type {number} */ (gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES));
 | 
| -        var attributeDescriptors = [];
 | 
| -        for (var i = 0; i < attributesCount; ++i) {
 | 
| -            var activeInfo = gl.getActiveAttrib(program, i);
 | 
| -            if (!activeInfo)
 | 
| -                continue;
 | 
| -            var pname = "" + i;
 | 
| -            var values = [];
 | 
| -            convertToStateDescriptors(activeInfo, values);
 | 
| -            attributeDescriptors.push({ name: pname, values: values });
 | 
| -        }
 | 
| -        result.push({ name: "ACTIVE_ATTRIBUTES", values: attributeDescriptors, isArray: true });
 | 
| -
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {boolean=} includeAllInfo
 | 
| -     * @return {!Array.<{name:string, type:number, value:*, size:(number|undefined)}>}
 | 
| -     */
 | 
| -    _activeUniforms: function(includeAllInfo)
 | 
| -    {
 | 
| -        var uniforms = [];
 | 
| -        var program = this.wrappedObject();
 | 
| -        if (!program)
 | 
| -            return uniforms;
 | 
| -
 | 
| -        var gl = WebGLRenderingContextResource.forObject(this).wrappedObject();
 | 
| -        var uniformsCount = /** @type {number} */ (gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS));
 | 
| -        for (var i = 0; i < uniformsCount; ++i) {
 | 
| -            var activeInfo = gl.getActiveUniform(program, i);
 | 
| -            if (!activeInfo)
 | 
| -                continue;
 | 
| -            var uniformLocation = gl.getUniformLocation(program, activeInfo.name);
 | 
| -            if (!uniformLocation)
 | 
| -                continue;
 | 
| -            var value = gl.getUniform(program, uniformLocation);
 | 
| -            var item = Object.create(null);
 | 
| -            item.name = activeInfo.name;
 | 
| -            item.type = activeInfo.type;
 | 
| -            item.value = value;
 | 
| -            if (includeAllInfo)
 | 
| -                item.size = activeInfo.size;
 | 
| -            uniforms.push(item);
 | 
| -        }
 | 
| -        return uniforms;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!ReplayableResource>} cache
 | 
| -     */
 | 
| -    _populateReplayableData: function(data, cache)
 | 
| -    {
 | 
| -        var glResource = WebGLRenderingContextResource.forObject(this);
 | 
| -        var originalErrors = glResource.getAllErrors();
 | 
| -        data.uniforms = this._activeUniforms();
 | 
| -        glResource.restoreErrors(originalErrors);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     */
 | 
| -    _doReplayCalls: function(data, cache)
 | 
| -    {
 | 
| -        Resource.prototype._doReplayCalls.call(this, data, cache);
 | 
| -        var gl = WebGLRenderingContextResource.forObject(this).wrappedObject();
 | 
| -        var program = this.wrappedObject();
 | 
| -
 | 
| -        var originalProgram = /** @type {!WebGLProgram} */ (gl.getParameter(gl.CURRENT_PROGRAM));
 | 
| -        var currentProgram = originalProgram;
 | 
| -
 | 
| -        data.uniforms.forEach(function(uniform) {
 | 
| -            var uniformLocation = gl.getUniformLocation(program, uniform.name);
 | 
| -            if (!uniformLocation)
 | 
| -                return;
 | 
| -            if (currentProgram !== program) {
 | 
| -                currentProgram = program;
 | 
| -                gl.useProgram(program);
 | 
| -            }
 | 
| -            var methodName = this._uniformMethodNameByType(gl, uniform.type);
 | 
| -            if (methodName.indexOf("Matrix") === -1)
 | 
| -                gl[methodName].call(gl, uniformLocation, uniform.value);
 | 
| -            else
 | 
| -                gl[methodName].call(gl, uniformLocation, false, uniform.value);
 | 
| -        }.bind(this));
 | 
| -
 | 
| -        if (currentProgram !== originalProgram)
 | 
| -            gl.useProgram(originalProgram);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!WebGLRenderingContext} gl
 | 
| -     * @param {number} type
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    _uniformMethodNameByType: function(gl, type)
 | 
| -    {
 | 
| -        var uniformMethodNames = WebGLProgramResource._uniformMethodNames;
 | 
| -        if (!uniformMethodNames) {
 | 
| -            uniformMethodNames = {};
 | 
| -            uniformMethodNames[gl.FLOAT] = "uniform1f";
 | 
| -            uniformMethodNames[gl.FLOAT_VEC2] = "uniform2fv";
 | 
| -            uniformMethodNames[gl.FLOAT_VEC3] = "uniform3fv";
 | 
| -            uniformMethodNames[gl.FLOAT_VEC4] = "uniform4fv";
 | 
| -            uniformMethodNames[gl.INT] = "uniform1i";
 | 
| -            uniformMethodNames[gl.BOOL] = "uniform1i";
 | 
| -            uniformMethodNames[gl.SAMPLER_2D] = "uniform1i";
 | 
| -            uniformMethodNames[gl.SAMPLER_CUBE] = "uniform1i";
 | 
| -            uniformMethodNames[gl.INT_VEC2] = "uniform2iv";
 | 
| -            uniformMethodNames[gl.BOOL_VEC2] = "uniform2iv";
 | 
| -            uniformMethodNames[gl.INT_VEC3] = "uniform3iv";
 | 
| -            uniformMethodNames[gl.BOOL_VEC3] = "uniform3iv";
 | 
| -            uniformMethodNames[gl.INT_VEC4] = "uniform4iv";
 | 
| -            uniformMethodNames[gl.BOOL_VEC4] = "uniform4iv";
 | 
| -            uniformMethodNames[gl.FLOAT_MAT2] = "uniformMatrix2fv";
 | 
| -            uniformMethodNames[gl.FLOAT_MAT3] = "uniformMatrix3fv";
 | 
| -            uniformMethodNames[gl.FLOAT_MAT4] = "uniformMatrix4fv";
 | 
| -            WebGLProgramResource._uniformMethodNames = uniformMethodNames;
 | 
| -        }
 | 
| -        console.assert(uniformMethodNames[type], "Unknown uniform type " + type);
 | 
| -        return uniformMethodNames[type];
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall: function(call)
 | 
| -    {
 | 
| -        // FIXME: remove any older calls that no longer contribute to the resource state.
 | 
| -        // FIXME: handle multiple attachShader && detachShader.
 | 
| -        Resource.prototype.pushCall.call(this, call);
 | 
| -    },
 | 
| -
 | 
| -    __proto__: Resource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {Resource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function WebGLShaderResource(wrappedObject, name)
 | 
| -{
 | 
| -    Resource.call(this, wrappedObject, name);
 | 
| -}
 | 
| -
 | 
| -WebGLShaderResource.prototype = {
 | 
| -    /**
 | 
| -     * @override (overrides @return type)
 | 
| -     * @return {!WebGLShader}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    type: function()
 | 
| -    {
 | 
| -        var call = this._calls[0];
 | 
| -        if (call && call.functionName() === "createShader")
 | 
| -            return call.args()[0];
 | 
| -        console.error("ASSERT_NOT_REACHED: Failed to restore shader type from the log.", call);
 | 
| -        return 0;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        var result = [];
 | 
| -        var shader = this.wrappedObject();
 | 
| -        if (!shader)
 | 
| -            return result;
 | 
| -        var glResource = WebGLRenderingContextResource.forObject(this);
 | 
| -        var gl = glResource.wrappedObject();
 | 
| -        var shaderParameters = ["SHADER_TYPE", "DELETE_STATUS", "COMPILE_STATUS"];
 | 
| -        glResource.queryStateValues(gl.getShaderParameter, shader, shaderParameters, result);
 | 
| -        result.push({ name: "getShaderInfoLog", value: gl.getShaderInfoLog(shader) });
 | 
| -        result.push({ name: "getShaderSource", value: gl.getShaderSource(shader) });
 | 
| -        result.push({ name: "isShader", value: gl.isShader(shader) });
 | 
| -        result.push({ name: "context", value: this.contextResource() });
 | 
| -
 | 
| -        // getShaderPrecisionFormat
 | 
| -        var shaderType = this.type();
 | 
| -        var precisionValues = [];
 | 
| -        var precisionParameters = ["LOW_FLOAT", "MEDIUM_FLOAT", "HIGH_FLOAT", "LOW_INT", "MEDIUM_INT", "HIGH_INT"];
 | 
| -        for (var i = 0, pname; pname = precisionParameters[i]; ++i)
 | 
| -            precisionValues.push({ name: pname, value: gl.getShaderPrecisionFormat(shaderType, gl[pname]) });
 | 
| -        result.push({ name: "getShaderPrecisionFormat", values: precisionValues });
 | 
| -
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall: function(call)
 | 
| -    {
 | 
| -        // FIXME: remove any older calls that no longer contribute to the resource state.
 | 
| -        // FIXME: handle multiple shaderSource calls.
 | 
| -        Resource.prototype.pushCall.call(this, call);
 | 
| -    },
 | 
| -
 | 
| -    __proto__: Resource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {WebGLBoundResource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function WebGLBufferResource(wrappedObject, name)
 | 
| -{
 | 
| -    WebGLBoundResource.call(this, wrappedObject, name);
 | 
| -}
 | 
| -
 | 
| -WebGLBufferResource.prototype = {
 | 
| -    /**
 | 
| -     * @override (overrides @return type)
 | 
| -     * @return {!WebGLBuffer}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?ArrayBufferView}
 | 
| -     */
 | 
| -    cachedBufferData: function()
 | 
| -    {
 | 
| -        /**
 | 
| -         * Creates a view to a given buffer, does NOT copy the buffer.
 | 
| -         * @param {!ArrayBuffer|!ArrayBufferView} buffer
 | 
| -         * @return {!Uint8Array}
 | 
| -         */
 | 
| -        function createUint8ArrayBufferView(buffer)
 | 
| -        {
 | 
| -            return buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
 | 
| -        }
 | 
| -
 | 
| -        if (!this._cachedBufferData) {
 | 
| -            for (var i = this._calls.length - 1; i >= 0; --i) {
 | 
| -                var call = this._calls[i];
 | 
| -                if (call.functionName() === "bufferData") {
 | 
| -                    var sizeOrData = /** @type {number|!ArrayBuffer|!ArrayBufferView} */ (call.args()[1]);
 | 
| -                    if (typeof sizeOrData === "number")
 | 
| -                        this._cachedBufferData = new ArrayBuffer(sizeOrData);
 | 
| -                    else
 | 
| -                        this._cachedBufferData = sizeOrData;
 | 
| -                    this._lastBufferSubDataIndex = i + 1;
 | 
| -                    break;
 | 
| -                }
 | 
| -            }
 | 
| -            if (!this._cachedBufferData)
 | 
| -                return null;
 | 
| -        }
 | 
| -
 | 
| -        // Apply any "bufferSubData" calls that have not been applied yet.
 | 
| -        var bufferDataView;
 | 
| -        while (this._lastBufferSubDataIndex < this._calls.length) {
 | 
| -            var call = this._calls[this._lastBufferSubDataIndex++];
 | 
| -            if (call.functionName() !== "bufferSubData")
 | 
| -                continue;
 | 
| -            var offset = /** @type {number} */ (call.args()[1]);
 | 
| -            var data = /** @type {!ArrayBuffer|!ArrayBufferView} */ (call.args()[2]);
 | 
| -            var view = createUint8ArrayBufferView(data);
 | 
| -            if (!bufferDataView)
 | 
| -                bufferDataView = createUint8ArrayBufferView(this._cachedBufferData);
 | 
| -            bufferDataView.set(view, offset);
 | 
| -
 | 
| -            var isFullReplacement = (offset === 0 && bufferDataView.length === view.length);
 | 
| -            if (this._cachedBufferData instanceof ArrayBuffer) {
 | 
| -                // The buffer data has no type yet. Try to guess from the "bufferSubData" call.
 | 
| -                var typedArrayClass = TypeUtils.typedArrayClass(data);
 | 
| -                if (typedArrayClass)
 | 
| -                    this._cachedBufferData = new typedArrayClass(this._cachedBufferData); // Does not copy the buffer.
 | 
| -            } else if (isFullReplacement) {
 | 
| -                var typedArrayClass = TypeUtils.typedArrayClass(data);
 | 
| -                if (typedArrayClass) {
 | 
| -                    var typedArrayData = /** @type {!ArrayBufferView} */ (data);
 | 
| -                    this._cachedBufferData = new typedArrayClass(this._cachedBufferData.buffer, this._cachedBufferData.byteOffset, typedArrayData.length); // Does not copy the buffer.
 | 
| -                }
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        if (this._cachedBufferData instanceof ArrayBuffer) {
 | 
| -            // If we failed to guess the data type yet, use Uint8Array.
 | 
| -            return new Uint8Array(this._cachedBufferData);
 | 
| -        }
 | 
| -        return this._cachedBufferData;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        var result = [];
 | 
| -        var glResource = WebGLRenderingContextResource.forObject(this);
 | 
| -        var gl = glResource.wrappedObject();
 | 
| -        var buffer = this.wrappedObject();
 | 
| -        if (!gl || !buffer)
 | 
| -            return result;
 | 
| -        result.push({ name: "isBuffer", value: gl.isBuffer(buffer) });
 | 
| -        result.push({ name: "context", value: this.contextResource() });
 | 
| -
 | 
| -        var target = this._state.bindTarget;
 | 
| -        if (typeof target !== "number")
 | 
| -            return result;
 | 
| -
 | 
| -        var bindingParameter;
 | 
| -        switch (target) {
 | 
| -        case gl.ARRAY_BUFFER:
 | 
| -            bindingParameter = gl.ARRAY_BUFFER_BINDING;
 | 
| -            break;
 | 
| -        case gl.ELEMENT_ARRAY_BUFFER:
 | 
| -            bindingParameter = gl.ELEMENT_ARRAY_BUFFER_BINDING;
 | 
| -            break;
 | 
| -        default:
 | 
| -            console.error("ASSERT_NOT_REACHED: unknown buffer target " + target);
 | 
| -            return result;
 | 
| -        }
 | 
| -        result.push({ name: "target", value: target, valueIsEnum: true });
 | 
| -
 | 
| -        var oldBuffer = /** @type {!WebGLBuffer} */ (gl.getParameter(bindingParameter));
 | 
| -        if (oldBuffer !== buffer)
 | 
| -            gl.bindBuffer(target, buffer);
 | 
| -
 | 
| -        var bufferParameters = ["BUFFER_SIZE", "BUFFER_USAGE"];
 | 
| -        glResource.queryStateValues(gl.getBufferParameter, target, bufferParameters, result);
 | 
| -
 | 
| -        if (oldBuffer !== buffer)
 | 
| -            gl.bindBuffer(target, oldBuffer);
 | 
| -
 | 
| -        try {
 | 
| -            var data = this.cachedBufferData();
 | 
| -            if (data)
 | 
| -                result.push({ name: "bufferData", value: data });
 | 
| -        } catch (e) {
 | 
| -            console.error("Exception while restoring bufferData", e);
 | 
| -        }
 | 
| -
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall_bufferData: function(call)
 | 
| -    {
 | 
| -        // FIXME: remove any older calls that no longer contribute to the resource state.
 | 
| -        delete this._cachedBufferData;
 | 
| -        delete this._lastBufferSubDataIndex;
 | 
| -        WebGLBoundResource.prototype.pushCall.call(this, call);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall_bufferSubData: function(call)
 | 
| -    {
 | 
| -        // FIXME: Optimize memory for bufferSubData.
 | 
| -        WebGLBoundResource.prototype.pushCall.call(this, call);
 | 
| -    },
 | 
| -
 | 
| -    __proto__: WebGLBoundResource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {WebGLBoundResource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function WebGLFramebufferResource(wrappedObject, name)
 | 
| -{
 | 
| -    WebGLBoundResource.call(this, wrappedObject, name);
 | 
| -}
 | 
| -
 | 
| -WebGLFramebufferResource.prototype = {
 | 
| -    /**
 | 
| -     * @override (overrides @return type)
 | 
| -     * @return {!WebGLFramebuffer}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        var result = [];
 | 
| -        var framebuffer = this.wrappedObject();
 | 
| -        if (!framebuffer)
 | 
| -            return result;
 | 
| -        var gl = WebGLRenderingContextResource.forObject(this).wrappedObject();
 | 
| -
 | 
| -        var oldFramebuffer = /** @type {!WebGLFramebuffer} */ (gl.getParameter(gl.FRAMEBUFFER_BINDING));
 | 
| -        if (oldFramebuffer !== framebuffer)
 | 
| -            gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
 | 
| -
 | 
| -        var attachmentParameters = ["COLOR_ATTACHMENT0", "DEPTH_ATTACHMENT", "STENCIL_ATTACHMENT"];
 | 
| -        var framebufferParameters = ["FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE", "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME", "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL", "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE"];
 | 
| -        for (var i = 0, attachment; attachment = attachmentParameters[i]; ++i) {
 | 
| -            var values = [];
 | 
| -            for (var j = 0, pname; pname = framebufferParameters[j]; ++j) {
 | 
| -                var value = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl[attachment], gl[pname]);
 | 
| -                value = Resource.forObject(value) || value;
 | 
| -                values.push({ name: pname, value: value, valueIsEnum: WebGLRenderingContextResource.GetResultIsEnum[pname] });
 | 
| -            }
 | 
| -            result.push({ name: attachment, values: values });
 | 
| -        }
 | 
| -        result.push({ name: "isFramebuffer", value: gl.isFramebuffer(framebuffer) });
 | 
| -        result.push({ name: "context", value: this.contextResource() });
 | 
| -
 | 
| -        if (oldFramebuffer !== framebuffer)
 | 
| -            gl.bindFramebuffer(gl.FRAMEBUFFER, oldFramebuffer);
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall: function(call)
 | 
| -    {
 | 
| -        // FIXME: remove any older calls that no longer contribute to the resource state.
 | 
| -        WebGLBoundResource.prototype.pushCall.call(this, call);
 | 
| -    },
 | 
| -
 | 
| -    __proto__: WebGLBoundResource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {WebGLBoundResource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function WebGLRenderbufferResource(wrappedObject, name)
 | 
| -{
 | 
| -    WebGLBoundResource.call(this, wrappedObject, name);
 | 
| -}
 | 
| -
 | 
| -WebGLRenderbufferResource.prototype = {
 | 
| -    /**
 | 
| -     * @override (overrides @return type)
 | 
| -     * @return {!WebGLRenderbuffer}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        var result = [];
 | 
| -        var renderbuffer = this.wrappedObject();
 | 
| -        if (!renderbuffer)
 | 
| -            return result;
 | 
| -        var glResource = WebGLRenderingContextResource.forObject(this);
 | 
| -        var gl = glResource.wrappedObject();
 | 
| -
 | 
| -        var oldRenderbuffer = /** @type {!WebGLRenderbuffer} */ (gl.getParameter(gl.RENDERBUFFER_BINDING));
 | 
| -        if (oldRenderbuffer !== renderbuffer)
 | 
| -            gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
 | 
| -
 | 
| -        var renderbufferParameters = ["RENDERBUFFER_WIDTH", "RENDERBUFFER_HEIGHT", "RENDERBUFFER_INTERNAL_FORMAT", "RENDERBUFFER_RED_SIZE", "RENDERBUFFER_GREEN_SIZE", "RENDERBUFFER_BLUE_SIZE", "RENDERBUFFER_ALPHA_SIZE", "RENDERBUFFER_DEPTH_SIZE", "RENDERBUFFER_STENCIL_SIZE"];
 | 
| -        glResource.queryStateValues(gl.getRenderbufferParameter, gl.RENDERBUFFER, renderbufferParameters, result);
 | 
| -        result.push({ name: "isRenderbuffer", value: gl.isRenderbuffer(renderbuffer) });
 | 
| -        result.push({ name: "context", value: this.contextResource() });
 | 
| -
 | 
| -        if (oldRenderbuffer !== renderbuffer)
 | 
| -            gl.bindRenderbuffer(gl.RENDERBUFFER, oldRenderbuffer);
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall: function(call)
 | 
| -    {
 | 
| -        // FIXME: remove any older calls that no longer contribute to the resource state.
 | 
| -        WebGLBoundResource.prototype.pushCall.call(this, call);
 | 
| -    },
 | 
| -
 | 
| -    __proto__: WebGLBoundResource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {Resource}
 | 
| - * @param {!Object} wrappedObject
 | 
| - * @param {string} name
 | 
| - */
 | 
| -function WebGLUniformLocationResource(wrappedObject, name)
 | 
| -{
 | 
| -    Resource.call(this, wrappedObject, name);
 | 
| -}
 | 
| -
 | 
| -WebGLUniformLocationResource.prototype = {
 | 
| -    /**
 | 
| -     * @override (overrides @return type)
 | 
| -     * @return {!WebGLUniformLocation}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?WebGLProgramResource}
 | 
| -     */
 | 
| -    program: function()
 | 
| -    {
 | 
| -        var call = this._calls[0];
 | 
| -        if (call && call.functionName() === "getUniformLocation")
 | 
| -            return /** @type {!WebGLProgramResource} */ (Resource.forObject(call.args()[0]));
 | 
| -        console.error("ASSERT_NOT_REACHED: Failed to restore WebGLUniformLocation from the log.", call);
 | 
| -        return null;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    name: function()
 | 
| -    {
 | 
| -        var call = this._calls[0];
 | 
| -        if (call && call.functionName() === "getUniformLocation")
 | 
| -            return call.args()[1];
 | 
| -        console.error("ASSERT_NOT_REACHED: Failed to restore WebGLUniformLocation from the log.", call);
 | 
| -        return "";
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        var result = [];
 | 
| -        var location = this.wrappedObject();
 | 
| -        if (!location)
 | 
| -            return result;
 | 
| -        var programResource = this.program();
 | 
| -        var program = programResource && programResource.wrappedObject();
 | 
| -        if (!program)
 | 
| -            return result;
 | 
| -        var gl = WebGLRenderingContextResource.forObject(this).wrappedObject();
 | 
| -        var uniformValue = gl.getUniform(program, location);
 | 
| -        var name = this.name();
 | 
| -        result.push({ name: "name", value: name });
 | 
| -        result.push({ name: "program", value: programResource });
 | 
| -        result.push({ name: "value", value: uniformValue });
 | 
| -        result.push({ name: "context", value: this.contextResource() });
 | 
| -
 | 
| -        if (typeof this._type !== "number") {
 | 
| -            var altName = name + "[0]";
 | 
| -            var uniformsCount = /** @type {number} */ (gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS));
 | 
| -            for (var i = 0; i < uniformsCount; ++i) {
 | 
| -                var activeInfo = gl.getActiveUniform(program, i);
 | 
| -                if (!activeInfo)
 | 
| -                    continue;
 | 
| -                if (activeInfo.name === name || activeInfo.name === altName) {
 | 
| -                    this._type = activeInfo.type;
 | 
| -                    this._size = activeInfo.size;
 | 
| -                    if (activeInfo.name === name)
 | 
| -                        break;
 | 
| -                }
 | 
| -            }
 | 
| -        }
 | 
| -        if (typeof this._type === "number")
 | 
| -            result.push({ name: "type", value: this._type, valueIsEnum: true });
 | 
| -        if (typeof this._size === "number")
 | 
| -            result.push({ name: "size", value: this._size });
 | 
| -
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!ReplayableResource>} cache
 | 
| -     */
 | 
| -    _populateReplayableData: function(data, cache)
 | 
| -    {
 | 
| -        data.type = this._type;
 | 
| -        data.size = this._size;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     */
 | 
| -    _doReplayCalls: function(data, cache)
 | 
| -    {
 | 
| -        this._type = data.type;
 | 
| -        this._size = data.size;
 | 
| -        Resource.prototype._doReplayCalls.call(this, data, cache);
 | 
| -    },
 | 
| -
 | 
| -    __proto__: Resource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {ContextResource}
 | 
| - * @param {!WebGLRenderingContext} glContext
 | 
| - */
 | 
| -function WebGLRenderingContextResource(glContext)
 | 
| -{
 | 
| -    ContextResource.call(this, glContext, "WebGLRenderingContext");
 | 
| -    /** @type {?Object.<number, boolean>} */
 | 
| -    this._customErrors = null;
 | 
| -    /** @type {!Object.<string, string>} */
 | 
| -    this._extensions = {};
 | 
| -    /** @type {!Object.<string, number>} */
 | 
| -    this._extensionEnums = {};
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @const
 | 
| - * @type {!Array.<string>}
 | 
| - */
 | 
| -WebGLRenderingContextResource.GLCapabilities = [
 | 
| -    "BLEND",
 | 
| -    "CULL_FACE",
 | 
| -    "DEPTH_TEST",
 | 
| -    "DITHER",
 | 
| -    "POLYGON_OFFSET_FILL",
 | 
| -    "SAMPLE_ALPHA_TO_COVERAGE",
 | 
| -    "SAMPLE_COVERAGE",
 | 
| -    "SCISSOR_TEST",
 | 
| -    "STENCIL_TEST"
 | 
| -];
 | 
| -
 | 
| -/**
 | 
| - * @const
 | 
| - * @type {!Array.<string>}
 | 
| - */
 | 
| -WebGLRenderingContextResource.PixelStoreParameters = [
 | 
| -    "PACK_ALIGNMENT",
 | 
| -    "UNPACK_ALIGNMENT",
 | 
| -    "UNPACK_COLORSPACE_CONVERSION_WEBGL",
 | 
| -    "UNPACK_FLIP_Y_WEBGL",
 | 
| -    "UNPACK_PREMULTIPLY_ALPHA_WEBGL"
 | 
| -];
 | 
| -
 | 
| -/**
 | 
| - * @const
 | 
| - * @type {!Array.<string>}
 | 
| - */
 | 
| -WebGLRenderingContextResource.StateParameters = [
 | 
| -    "ACTIVE_TEXTURE",
 | 
| -    "ARRAY_BUFFER_BINDING",
 | 
| -    "BLEND_COLOR",
 | 
| -    "BLEND_DST_ALPHA",
 | 
| -    "BLEND_DST_RGB",
 | 
| -    "BLEND_EQUATION_ALPHA",
 | 
| -    "BLEND_EQUATION_RGB",
 | 
| -    "BLEND_SRC_ALPHA",
 | 
| -    "BLEND_SRC_RGB",
 | 
| -    "COLOR_CLEAR_VALUE",
 | 
| -    "COLOR_WRITEMASK",
 | 
| -    "CULL_FACE_MODE",
 | 
| -    "CURRENT_PROGRAM",
 | 
| -    "DEPTH_CLEAR_VALUE",
 | 
| -    "DEPTH_FUNC",
 | 
| -    "DEPTH_RANGE",
 | 
| -    "DEPTH_WRITEMASK",
 | 
| -    "ELEMENT_ARRAY_BUFFER_BINDING",
 | 
| -    "FRAGMENT_SHADER_DERIVATIVE_HINT_OES", // OES_standard_derivatives extension
 | 
| -    "FRAMEBUFFER_BINDING",
 | 
| -    "FRONT_FACE",
 | 
| -    "GENERATE_MIPMAP_HINT",
 | 
| -    "LINE_WIDTH",
 | 
| -    "PACK_ALIGNMENT",
 | 
| -    "POLYGON_OFFSET_FACTOR",
 | 
| -    "POLYGON_OFFSET_UNITS",
 | 
| -    "RENDERBUFFER_BINDING",
 | 
| -    "SAMPLE_COVERAGE_INVERT",
 | 
| -    "SAMPLE_COVERAGE_VALUE",
 | 
| -    "SCISSOR_BOX",
 | 
| -    "STENCIL_BACK_FAIL",
 | 
| -    "STENCIL_BACK_FUNC",
 | 
| -    "STENCIL_BACK_PASS_DEPTH_FAIL",
 | 
| -    "STENCIL_BACK_PASS_DEPTH_PASS",
 | 
| -    "STENCIL_BACK_REF",
 | 
| -    "STENCIL_BACK_VALUE_MASK",
 | 
| -    "STENCIL_BACK_WRITEMASK",
 | 
| -    "STENCIL_CLEAR_VALUE",
 | 
| -    "STENCIL_FAIL",
 | 
| -    "STENCIL_FUNC",
 | 
| -    "STENCIL_PASS_DEPTH_FAIL",
 | 
| -    "STENCIL_PASS_DEPTH_PASS",
 | 
| -    "STENCIL_REF",
 | 
| -    "STENCIL_VALUE_MASK",
 | 
| -    "STENCIL_WRITEMASK",
 | 
| -    "UNPACK_ALIGNMENT",
 | 
| -    "UNPACK_COLORSPACE_CONVERSION_WEBGL",
 | 
| -    "UNPACK_FLIP_Y_WEBGL",
 | 
| -    "UNPACK_PREMULTIPLY_ALPHA_WEBGL",
 | 
| -    "VERTEX_ARRAY_BINDING_OES", // OES_vertex_array_object extension
 | 
| -    "VIEWPORT"
 | 
| -];
 | 
| -
 | 
| -/**
 | 
| - * True for those enums that return also an enum via a getter API method (e.g. getParameter, getShaderParameter, etc.).
 | 
| - * @const
 | 
| - * @type {!Object.<string, boolean>}
 | 
| - */
 | 
| -WebGLRenderingContextResource.GetResultIsEnum = TypeUtils.createPrefixedPropertyNamesSet([
 | 
| -    // gl.getParameter()
 | 
| -    "ACTIVE_TEXTURE",
 | 
| -    "BLEND_DST_ALPHA",
 | 
| -    "BLEND_DST_RGB",
 | 
| -    "BLEND_EQUATION_ALPHA",
 | 
| -    "BLEND_EQUATION_RGB",
 | 
| -    "BLEND_SRC_ALPHA",
 | 
| -    "BLEND_SRC_RGB",
 | 
| -    "CULL_FACE_MODE",
 | 
| -    "DEPTH_FUNC",
 | 
| -    "FRONT_FACE",
 | 
| -    "GENERATE_MIPMAP_HINT",
 | 
| -    "FRAGMENT_SHADER_DERIVATIVE_HINT_OES",
 | 
| -    "STENCIL_BACK_FAIL",
 | 
| -    "STENCIL_BACK_FUNC",
 | 
| -    "STENCIL_BACK_PASS_DEPTH_FAIL",
 | 
| -    "STENCIL_BACK_PASS_DEPTH_PASS",
 | 
| -    "STENCIL_FAIL",
 | 
| -    "STENCIL_FUNC",
 | 
| -    "STENCIL_PASS_DEPTH_FAIL",
 | 
| -    "STENCIL_PASS_DEPTH_PASS",
 | 
| -    "UNPACK_COLORSPACE_CONVERSION_WEBGL",
 | 
| -    // gl.getBufferParameter()
 | 
| -    "BUFFER_USAGE",
 | 
| -    // gl.getFramebufferAttachmentParameter()
 | 
| -    "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE",
 | 
| -    // gl.getRenderbufferParameter()
 | 
| -    "RENDERBUFFER_INTERNAL_FORMAT",
 | 
| -    // gl.getTexParameter()
 | 
| -    "TEXTURE_MAG_FILTER",
 | 
| -    "TEXTURE_MIN_FILTER",
 | 
| -    "TEXTURE_WRAP_S",
 | 
| -    "TEXTURE_WRAP_T",
 | 
| -    // gl.getShaderParameter()
 | 
| -    "SHADER_TYPE",
 | 
| -    // gl.getVertexAttrib()
 | 
| -    "VERTEX_ATTRIB_ARRAY_TYPE"
 | 
| -]);
 | 
| -
 | 
| -/**
 | 
| - * @const
 | 
| - * @type {!Object.<string, boolean>}
 | 
| - */
 | 
| -WebGLRenderingContextResource.DrawingMethods = TypeUtils.createPrefixedPropertyNamesSet([
 | 
| -    "clear",
 | 
| -    "drawArrays",
 | 
| -    "drawElements"
 | 
| -]);
 | 
| -
 | 
| -/**
 | 
| - * @param {*} obj
 | 
| - * @return {?WebGLRenderingContextResource}
 | 
| - */
 | 
| -WebGLRenderingContextResource.forObject = function(obj)
 | 
| -{
 | 
| -    var resource = Resource.forObject(obj);
 | 
| -    if (!resource)
 | 
| -        return null;
 | 
| -    resource = resource.contextResource();
 | 
| -    return (resource instanceof WebGLRenderingContextResource) ? resource : null;
 | 
| -}
 | 
| -
 | 
| -WebGLRenderingContextResource.prototype = {
 | 
| -    /**
 | 
| -     * @override (overrides @return type)
 | 
| -     * @return {!WebGLRenderingContext}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    toDataURL: function()
 | 
| -    {
 | 
| -        return this.wrappedObject().canvas.toDataURL();
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Array.<number>}
 | 
| -     */
 | 
| -    getAllErrors: function()
 | 
| -    {
 | 
| -        var errors = [];
 | 
| -        var gl = this.wrappedObject();
 | 
| -        if (gl) {
 | 
| -            while (true) {
 | 
| -                var error = gl.getError();
 | 
| -                if (error === gl.NO_ERROR)
 | 
| -                    break;
 | 
| -                this.clearError(error);
 | 
| -                errors.push(error);
 | 
| -            }
 | 
| -        }
 | 
| -        if (this._customErrors) {
 | 
| -            for (var key in this._customErrors) {
 | 
| -                var error = Number(key);
 | 
| -                errors.push(error);
 | 
| -            }
 | 
| -            delete this._customErrors;
 | 
| -        }
 | 
| -        return errors;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Array.<number>} errors
 | 
| -     */
 | 
| -    restoreErrors: function(errors)
 | 
| -    {
 | 
| -        var gl = this.wrappedObject();
 | 
| -        if (gl) {
 | 
| -            var wasError = false;
 | 
| -            while (gl.getError() !== gl.NO_ERROR)
 | 
| -                wasError = true;
 | 
| -            console.assert(!wasError, "Error(s) while capturing current WebGL state.");
 | 
| -        }
 | 
| -        if (!errors.length)
 | 
| -            delete this._customErrors;
 | 
| -        else {
 | 
| -            this._customErrors = {};
 | 
| -            for (var i = 0, n = errors.length; i < n; ++i)
 | 
| -                this._customErrors[errors[i]] = true;
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} error
 | 
| -     */
 | 
| -    clearError: function(error)
 | 
| -    {
 | 
| -        if (this._customErrors)
 | 
| -            delete this._customErrors[error];
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    nextError: function()
 | 
| -    {
 | 
| -        if (this._customErrors) {
 | 
| -            for (var key in this._customErrors) {
 | 
| -                var error = Number(key);
 | 
| -                delete this._customErrors[error];
 | 
| -                return error;
 | 
| -            }
 | 
| -        }
 | 
| -        delete this._customErrors;
 | 
| -        var gl = this.wrappedObject();
 | 
| -        return gl ? gl.NO_ERROR : 0;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {string} name
 | 
| -     * @param {?Object} obj
 | 
| -     */
 | 
| -    registerWebGLExtension: function(name, obj)
 | 
| -    {
 | 
| -        // FIXME: Wrap OES_vertex_array_object extension.
 | 
| -        var lowerName = name.toLowerCase();
 | 
| -        if (obj && !this._extensions[lowerName]) {
 | 
| -            this._extensions[lowerName] = name;
 | 
| -            for (var property in obj) {
 | 
| -                if (TypeUtils.isEnumPropertyName(property, obj))
 | 
| -                    this._extensionEnums[property] = /** @type {number} */ (obj[property]);
 | 
| -            }
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {string} name
 | 
| -     * @return {number|undefined}
 | 
| -     */
 | 
| -    _enumValueForName: function(name)
 | 
| -    {
 | 
| -        if (typeof this._extensionEnums[name] === "number")
 | 
| -            return this._extensionEnums[name];
 | 
| -        var gl = this.wrappedObject();
 | 
| -        return (typeof gl[name] === "number" ? gl[name] : undefined);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {function(this:WebGLRenderingContext, T, number):*} func
 | 
| -     * @param {T} targetOrWebGLObject
 | 
| -     * @param {!Array.<string>} pnames
 | 
| -     * @param {!Array.<!TypeUtils.InternalResourceStateDescriptor>} output
 | 
| -     * @template T
 | 
| -     */
 | 
| -    queryStateValues: function(func, targetOrWebGLObject, pnames, output)
 | 
| -    {
 | 
| -        var gl = this.wrappedObject();
 | 
| -        for (var i = 0, pname; pname = pnames[i]; ++i) {
 | 
| -            var enumValue = this._enumValueForName(pname);
 | 
| -            if (typeof enumValue !== "number")
 | 
| -                continue;
 | 
| -            var value = func.call(gl, targetOrWebGLObject, enumValue);
 | 
| -            value = Resource.forObject(value) || value;
 | 
| -            output.push({ name: pname, value: value, valueIsEnum: WebGLRenderingContextResource.GetResultIsEnum[pname] });
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        /**
 | 
| -         * @param {!Object} obj
 | 
| -         * @param {!Array.<!TypeUtils.InternalResourceStateDescriptor>} output
 | 
| -         */
 | 
| -        function convertToStateDescriptors(obj, output)
 | 
| -        {
 | 
| -            for (var pname in obj)
 | 
| -                output.push({ name: pname, value: obj[pname], valueIsEnum: WebGLRenderingContextResource.GetResultIsEnum[pname] });
 | 
| -        }
 | 
| -
 | 
| -        var gl = this.wrappedObject();
 | 
| -        var glState = this._internalCurrentState(null);
 | 
| -
 | 
| -        // VERTEX_ATTRIB_ARRAYS
 | 
| -        var vertexAttribStates = [];
 | 
| -        for (var i = 0, n = glState.VERTEX_ATTRIB_ARRAYS.length; i < n; ++i) {
 | 
| -            var pname = "" + i;
 | 
| -            var values = [];
 | 
| -            convertToStateDescriptors(glState.VERTEX_ATTRIB_ARRAYS[i], values);
 | 
| -            vertexAttribStates.push({ name: pname, values: values });
 | 
| -        }
 | 
| -        delete glState.VERTEX_ATTRIB_ARRAYS;
 | 
| -
 | 
| -        // TEXTURE_UNITS
 | 
| -        var textureUnits = [];
 | 
| -        for (var i = 0, n = glState.TEXTURE_UNITS.length; i < n; ++i) {
 | 
| -            var pname = "TEXTURE" + i;
 | 
| -            var values = [];
 | 
| -            convertToStateDescriptors(glState.TEXTURE_UNITS[i], values);
 | 
| -            textureUnits.push({ name: pname, values: values });
 | 
| -        }
 | 
| -        delete glState.TEXTURE_UNITS;
 | 
| -
 | 
| -        var result = [];
 | 
| -        convertToStateDescriptors(glState, result);
 | 
| -        result.push({ name: "VERTEX_ATTRIB_ARRAYS", values: vertexAttribStates, isArray: true });
 | 
| -        result.push({ name: "TEXTURE_UNITS", values: textureUnits, isArray: true });
 | 
| -
 | 
| -        var textureBindingParameters = ["TEXTURE_BINDING_2D", "TEXTURE_BINDING_CUBE_MAP"];
 | 
| -        for (var i = 0, pname; pname = textureBindingParameters[i]; ++i) {
 | 
| -            var value = gl.getParameter(gl[pname]);
 | 
| -            value = Resource.forObject(value) || value;
 | 
| -            result.push({ name: pname, value: value });
 | 
| -        }
 | 
| -
 | 
| -        // ENABLED_EXTENSIONS
 | 
| -        var enabledExtensions = [];
 | 
| -        for (var lowerName in this._extensions) {
 | 
| -            var pname = this._extensions[lowerName];
 | 
| -            var value = gl.getExtension(pname);
 | 
| -            value = Resource.forObject(value) || value;
 | 
| -            enabledExtensions.push({ name: pname, value: value });
 | 
| -        }
 | 
| -        result.push({ name: "ENABLED_EXTENSIONS", values: enabledExtensions, isArray: true });
 | 
| -
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {?Cache.<!ReplayableResource>} cache
 | 
| -     * @return {!Object.<string, *>}
 | 
| -     */
 | 
| -    _internalCurrentState: function(cache)
 | 
| -    {
 | 
| -        /**
 | 
| -         * @param {!Resource|*} obj
 | 
| -         * @return {!Resource|!ReplayableResource|*}
 | 
| -         */
 | 
| -        function maybeToReplayable(obj)
 | 
| -        {
 | 
| -            return cache ? Resource.toReplayable(obj, cache) : (Resource.forObject(obj) || obj);
 | 
| -        }
 | 
| -
 | 
| -        var gl = this.wrappedObject();
 | 
| -        var originalErrors = this.getAllErrors();
 | 
| -
 | 
| -        // Take a full GL state snapshot.
 | 
| -        var glState = Object.create(null);
 | 
| -        WebGLRenderingContextResource.GLCapabilities.forEach(function(parameter) {
 | 
| -            glState[parameter] = gl.isEnabled(gl[parameter]);
 | 
| -        });
 | 
| -        for (var i = 0, pname; pname = WebGLRenderingContextResource.StateParameters[i]; ++i) {
 | 
| -            var enumValue = this._enumValueForName(pname);
 | 
| -            if (typeof enumValue === "number")
 | 
| -                glState[pname] = maybeToReplayable(gl.getParameter(enumValue));
 | 
| -        }
 | 
| -
 | 
| -        // VERTEX_ATTRIB_ARRAYS
 | 
| -        var maxVertexAttribs = /** @type {number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
 | 
| -        var vertexAttribParameters = [
 | 
| -            "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING",
 | 
| -            "VERTEX_ATTRIB_ARRAY_ENABLED",
 | 
| -            "VERTEX_ATTRIB_ARRAY_SIZE",
 | 
| -            "VERTEX_ATTRIB_ARRAY_STRIDE",
 | 
| -            "VERTEX_ATTRIB_ARRAY_TYPE",
 | 
| -            "VERTEX_ATTRIB_ARRAY_NORMALIZED",
 | 
| -            "CURRENT_VERTEX_ATTRIB",
 | 
| -            "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE" // ANGLE_instanced_arrays extension
 | 
| -        ];
 | 
| -        var vertexAttribStates = [];
 | 
| -        for (var index = 0; index < maxVertexAttribs; ++index) {
 | 
| -            var state = Object.create(null);
 | 
| -            for (var i = 0, pname; pname = vertexAttribParameters[i]; ++i) {
 | 
| -                var enumValue = this._enumValueForName(pname);
 | 
| -                if (typeof enumValue === "number")
 | 
| -                    state[pname] = maybeToReplayable(gl.getVertexAttrib(index, enumValue));
 | 
| -            }
 | 
| -            state.VERTEX_ATTRIB_ARRAY_POINTER = gl.getVertexAttribOffset(index, gl.VERTEX_ATTRIB_ARRAY_POINTER);
 | 
| -            vertexAttribStates.push(state);
 | 
| -        }
 | 
| -        glState.VERTEX_ATTRIB_ARRAYS = vertexAttribStates;
 | 
| -
 | 
| -        // TEXTURE_UNITS
 | 
| -        var savedActiveTexture = /** @type {number} */ (gl.getParameter(gl.ACTIVE_TEXTURE));
 | 
| -        var maxTextureImageUnits = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS));
 | 
| -        var textureUnits = [];
 | 
| -        for (var i = 0; i < maxTextureImageUnits; ++i) {
 | 
| -            gl.activeTexture(gl.TEXTURE0 + i);
 | 
| -            var state = Object.create(null);
 | 
| -            state.TEXTURE_2D = maybeToReplayable(gl.getParameter(gl.TEXTURE_BINDING_2D));
 | 
| -            state.TEXTURE_CUBE_MAP = maybeToReplayable(gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP));
 | 
| -            textureUnits.push(state);
 | 
| -        }
 | 
| -        glState.TEXTURE_UNITS = textureUnits;
 | 
| -        gl.activeTexture(savedActiveTexture);
 | 
| -
 | 
| -        this.restoreErrors(originalErrors);
 | 
| -        return glState;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!ReplayableResource>} cache
 | 
| -     */
 | 
| -    _populateReplayableData: function(data, cache)
 | 
| -    {
 | 
| -        var gl = this.wrappedObject();
 | 
| -        data.originalCanvas = gl.canvas;
 | 
| -        data.originalContextAttributes = gl.getContextAttributes();
 | 
| -        data.extensions = TypeUtils.cloneObject(this._extensions);
 | 
| -        data.extensionEnums = TypeUtils.cloneObject(this._extensionEnums);
 | 
| -        data.glState = this._internalCurrentState(cache);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     */
 | 
| -    _doReplayCalls: function(data, cache)
 | 
| -    {
 | 
| -        this._customErrors = null;
 | 
| -        this._extensions = TypeUtils.cloneObject(data.extensions) || {};
 | 
| -        this._extensionEnums = TypeUtils.cloneObject(data.extensionEnums) || {};
 | 
| -
 | 
| -        var canvas = data.originalCanvas.cloneNode(true);
 | 
| -        var replayContext = null;
 | 
| -        var contextIds = ["experimental-webgl", "webkit-3d", "3d"];
 | 
| -        for (var i = 0, contextId; contextId = contextIds[i]; ++i) {
 | 
| -            replayContext = canvas.getContext(contextId, data.originalContextAttributes);
 | 
| -            if (replayContext)
 | 
| -                break;
 | 
| -        }
 | 
| -
 | 
| -        console.assert(replayContext, "Failed to create a WebGLRenderingContext for the replay.");
 | 
| -
 | 
| -        var gl = /** @type {!WebGLRenderingContext} */ (Resource.wrappedObject(replayContext));
 | 
| -        this.setWrappedObject(gl);
 | 
| -
 | 
| -        // Enable corresponding WebGL extensions.
 | 
| -        for (var name in this._extensions)
 | 
| -            gl.getExtension(name);
 | 
| -
 | 
| -        var glState = data.glState;
 | 
| -        gl.bindFramebuffer(gl.FRAMEBUFFER, /** @type {!WebGLFramebuffer} */ (ReplayableResource.replay(glState.FRAMEBUFFER_BINDING, cache)));
 | 
| -        gl.bindRenderbuffer(gl.RENDERBUFFER, /** @type {!WebGLRenderbuffer} */ (ReplayableResource.replay(glState.RENDERBUFFER_BINDING, cache)));
 | 
| -
 | 
| -        // Enable or disable server-side GL capabilities.
 | 
| -        WebGLRenderingContextResource.GLCapabilities.forEach(function(parameter) {
 | 
| -            console.assert(parameter in glState);
 | 
| -            if (glState[parameter])
 | 
| -                gl.enable(gl[parameter]);
 | 
| -            else
 | 
| -                gl.disable(gl[parameter]);
 | 
| -        });
 | 
| -
 | 
| -        gl.blendColor(glState.BLEND_COLOR[0], glState.BLEND_COLOR[1], glState.BLEND_COLOR[2], glState.BLEND_COLOR[3]);
 | 
| -        gl.blendEquationSeparate(glState.BLEND_EQUATION_RGB, glState.BLEND_EQUATION_ALPHA);
 | 
| -        gl.blendFuncSeparate(glState.BLEND_SRC_RGB, glState.BLEND_DST_RGB, glState.BLEND_SRC_ALPHA, glState.BLEND_DST_ALPHA);
 | 
| -        gl.clearColor(glState.COLOR_CLEAR_VALUE[0], glState.COLOR_CLEAR_VALUE[1], glState.COLOR_CLEAR_VALUE[2], glState.COLOR_CLEAR_VALUE[3]);
 | 
| -        gl.clearDepth(glState.DEPTH_CLEAR_VALUE);
 | 
| -        gl.clearStencil(glState.STENCIL_CLEAR_VALUE);
 | 
| -        gl.colorMask(glState.COLOR_WRITEMASK[0], glState.COLOR_WRITEMASK[1], glState.COLOR_WRITEMASK[2], glState.COLOR_WRITEMASK[3]);
 | 
| -        gl.cullFace(glState.CULL_FACE_MODE);
 | 
| -        gl.depthFunc(glState.DEPTH_FUNC);
 | 
| -        gl.depthMask(glState.DEPTH_WRITEMASK);
 | 
| -        gl.depthRange(glState.DEPTH_RANGE[0], glState.DEPTH_RANGE[1]);
 | 
| -        gl.frontFace(glState.FRONT_FACE);
 | 
| -        gl.hint(gl.GENERATE_MIPMAP_HINT, glState.GENERATE_MIPMAP_HINT);
 | 
| -        gl.lineWidth(glState.LINE_WIDTH);
 | 
| -
 | 
| -        var enumValue = this._enumValueForName("FRAGMENT_SHADER_DERIVATIVE_HINT_OES");
 | 
| -        if (typeof enumValue === "number")
 | 
| -            gl.hint(enumValue, glState.FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
 | 
| -
 | 
| -        WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) {
 | 
| -            gl.pixelStorei(gl[parameter], glState[parameter]);
 | 
| -        });
 | 
| -
 | 
| -        gl.polygonOffset(glState.POLYGON_OFFSET_FACTOR, glState.POLYGON_OFFSET_UNITS);
 | 
| -        gl.sampleCoverage(glState.SAMPLE_COVERAGE_VALUE, glState.SAMPLE_COVERAGE_INVERT);
 | 
| -        gl.stencilFuncSeparate(gl.FRONT, glState.STENCIL_FUNC, glState.STENCIL_REF, glState.STENCIL_VALUE_MASK);
 | 
| -        gl.stencilFuncSeparate(gl.BACK, glState.STENCIL_BACK_FUNC, glState.STENCIL_BACK_REF, glState.STENCIL_BACK_VALUE_MASK);
 | 
| -        gl.stencilOpSeparate(gl.FRONT, glState.STENCIL_FAIL, glState.STENCIL_PASS_DEPTH_FAIL, glState.STENCIL_PASS_DEPTH_PASS);
 | 
| -        gl.stencilOpSeparate(gl.BACK, glState.STENCIL_BACK_FAIL, glState.STENCIL_BACK_PASS_DEPTH_FAIL, glState.STENCIL_BACK_PASS_DEPTH_PASS);
 | 
| -        gl.stencilMaskSeparate(gl.FRONT, glState.STENCIL_WRITEMASK);
 | 
| -        gl.stencilMaskSeparate(gl.BACK, glState.STENCIL_BACK_WRITEMASK);
 | 
| -
 | 
| -        gl.scissor(glState.SCISSOR_BOX[0], glState.SCISSOR_BOX[1], glState.SCISSOR_BOX[2], glState.SCISSOR_BOX[3]);
 | 
| -        gl.viewport(glState.VIEWPORT[0], glState.VIEWPORT[1], glState.VIEWPORT[2], glState.VIEWPORT[3]);
 | 
| -
 | 
| -        gl.useProgram(/** @type {!WebGLProgram} */ (ReplayableResource.replay(glState.CURRENT_PROGRAM, cache)));
 | 
| -
 | 
| -        // VERTEX_ATTRIB_ARRAYS
 | 
| -        var maxVertexAttribs = /** @type {number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
 | 
| -        for (var i = 0; i < maxVertexAttribs; ++i) {
 | 
| -            var state = glState.VERTEX_ATTRIB_ARRAYS[i] || {};
 | 
| -            if (state.VERTEX_ATTRIB_ARRAY_ENABLED)
 | 
| -                gl.enableVertexAttribArray(i);
 | 
| -            else
 | 
| -                gl.disableVertexAttribArray(i);
 | 
| -            if (state.CURRENT_VERTEX_ATTRIB)
 | 
| -                gl.vertexAttrib4fv(i, state.CURRENT_VERTEX_ATTRIB);
 | 
| -            var buffer = /** @type {!WebGLBuffer} */ (ReplayableResource.replay(state.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, cache));
 | 
| -            if (buffer) {
 | 
| -                gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
 | 
| -                gl.vertexAttribPointer(i, state.VERTEX_ATTRIB_ARRAY_SIZE, state.VERTEX_ATTRIB_ARRAY_TYPE, state.VERTEX_ATTRIB_ARRAY_NORMALIZED, state.VERTEX_ATTRIB_ARRAY_STRIDE, state.VERTEX_ATTRIB_ARRAY_POINTER);
 | 
| -            }
 | 
| -        }
 | 
| -        gl.bindBuffer(gl.ARRAY_BUFFER, /** @type {!WebGLBuffer} */ (ReplayableResource.replay(glState.ARRAY_BUFFER_BINDING, cache)));
 | 
| -        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, /** @type {!WebGLBuffer} */ (ReplayableResource.replay(glState.ELEMENT_ARRAY_BUFFER_BINDING, cache)));
 | 
| -
 | 
| -        // TEXTURE_UNITS
 | 
| -        var maxTextureImageUnits = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS));
 | 
| -        for (var i = 0; i < maxTextureImageUnits; ++i) {
 | 
| -            gl.activeTexture(gl.TEXTURE0 + i);
 | 
| -            var state = glState.TEXTURE_UNITS[i] || {};
 | 
| -            gl.bindTexture(gl.TEXTURE_2D, /** @type {!WebGLTexture} */ (ReplayableResource.replay(state.TEXTURE_2D, cache)));
 | 
| -            gl.bindTexture(gl.TEXTURE_CUBE_MAP, /** @type {!WebGLTexture} */ (ReplayableResource.replay(state.TEXTURE_CUBE_MAP, cache)));
 | 
| -        }
 | 
| -        gl.activeTexture(glState.ACTIVE_TEXTURE);
 | 
| -
 | 
| -        ContextResource.prototype._doReplayCalls.call(this, data, cache);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Object|number} target
 | 
| -     * @return {?Resource}
 | 
| -     */
 | 
| -    currentBinding: function(target)
 | 
| -    {
 | 
| -        var resource = Resource.forObject(target);
 | 
| -        if (resource)
 | 
| -            return resource;
 | 
| -        var gl = this.wrappedObject();
 | 
| -        var bindingParameter;
 | 
| -        var bindMethodName;
 | 
| -        target = +target; // Explicitly convert to a number.
 | 
| -        var bindMethodTarget = target;
 | 
| -        switch (target) {
 | 
| -        case gl.ARRAY_BUFFER:
 | 
| -            bindingParameter = gl.ARRAY_BUFFER_BINDING;
 | 
| -            bindMethodName = "bindBuffer";
 | 
| -            break;
 | 
| -        case gl.ELEMENT_ARRAY_BUFFER:
 | 
| -            bindingParameter = gl.ELEMENT_ARRAY_BUFFER_BINDING;
 | 
| -            bindMethodName = "bindBuffer";
 | 
| -            break;
 | 
| -        case gl.TEXTURE_2D:
 | 
| -            bindingParameter = gl.TEXTURE_BINDING_2D;
 | 
| -            bindMethodName = "bindTexture";
 | 
| -            break;
 | 
| -        case gl.TEXTURE_CUBE_MAP:
 | 
| -        case gl.TEXTURE_CUBE_MAP_POSITIVE_X:
 | 
| -        case gl.TEXTURE_CUBE_MAP_NEGATIVE_X:
 | 
| -        case gl.TEXTURE_CUBE_MAP_POSITIVE_Y:
 | 
| -        case gl.TEXTURE_CUBE_MAP_NEGATIVE_Y:
 | 
| -        case gl.TEXTURE_CUBE_MAP_POSITIVE_Z:
 | 
| -        case gl.TEXTURE_CUBE_MAP_NEGATIVE_Z:
 | 
| -            bindingParameter = gl.TEXTURE_BINDING_CUBE_MAP;
 | 
| -            bindMethodTarget = gl.TEXTURE_CUBE_MAP;
 | 
| -            bindMethodName = "bindTexture";
 | 
| -            break;
 | 
| -        case gl.FRAMEBUFFER:
 | 
| -            bindingParameter = gl.FRAMEBUFFER_BINDING;
 | 
| -            bindMethodName = "bindFramebuffer";
 | 
| -            break;
 | 
| -        case gl.RENDERBUFFER:
 | 
| -            bindingParameter = gl.RENDERBUFFER_BINDING;
 | 
| -            bindMethodName = "bindRenderbuffer";
 | 
| -            break;
 | 
| -        default:
 | 
| -            console.error("ASSERT_NOT_REACHED: unknown binding target " + target);
 | 
| -            return null;
 | 
| -        }
 | 
| -        resource = Resource.forObject(gl.getParameter(bindingParameter));
 | 
| -        if (resource)
 | 
| -            resource.pushBinding(bindMethodTarget, bindMethodName);
 | 
| -        return resource;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    onCallReplayed: function(call)
 | 
| -    {
 | 
| -        var functionName = call.functionName();
 | 
| -        var args = call.args();
 | 
| -        switch (functionName) {
 | 
| -        case "bindBuffer":
 | 
| -        case "bindFramebuffer":
 | 
| -        case "bindRenderbuffer":
 | 
| -        case "bindTexture":
 | 
| -            // Update BINDING state for Resources in the replay world.
 | 
| -            var resource = Resource.forObject(args[1]);
 | 
| -            if (resource)
 | 
| -                resource.pushBinding(args[0], functionName);
 | 
| -            break;
 | 
| -        case "getExtension":
 | 
| -            this.registerWebGLExtension(args[0], /** @type {!Object} */ (call.result()));
 | 
| -            break;
 | 
| -        case "bufferData":
 | 
| -            var resource = /** @type {!WebGLBufferResource} */ (this.currentBinding(args[0]));
 | 
| -            if (resource)
 | 
| -                resource.pushCall_bufferData(call);
 | 
| -            break;
 | 
| -        case "bufferSubData":
 | 
| -            var resource = /** @type {!WebGLBufferResource} */ (this.currentBinding(args[0]));
 | 
| -            if (resource)
 | 
| -                resource.pushCall_bufferSubData(call);
 | 
| -            break;
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Object.<string, !Function>}
 | 
| -     */
 | 
| -    _customWrapFunctions: function()
 | 
| -    {
 | 
| -        var wrapFunctions = WebGLRenderingContextResource._wrapFunctions;
 | 
| -        if (!wrapFunctions) {
 | 
| -            wrapFunctions = Object.create(null);
 | 
| -
 | 
| -            wrapFunctions["createBuffer"] = Resource.WrapFunction.resourceFactoryMethod(WebGLBufferResource, "WebGLBuffer");
 | 
| -            wrapFunctions["createShader"] = Resource.WrapFunction.resourceFactoryMethod(WebGLShaderResource, "WebGLShader");
 | 
| -            wrapFunctions["createProgram"] = Resource.WrapFunction.resourceFactoryMethod(WebGLProgramResource, "WebGLProgram");
 | 
| -            wrapFunctions["createTexture"] = Resource.WrapFunction.resourceFactoryMethod(WebGLTextureResource, "WebGLTexture");
 | 
| -            wrapFunctions["createFramebuffer"] = Resource.WrapFunction.resourceFactoryMethod(WebGLFramebufferResource, "WebGLFramebuffer");
 | 
| -            wrapFunctions["createRenderbuffer"] = Resource.WrapFunction.resourceFactoryMethod(WebGLRenderbufferResource, "WebGLRenderbuffer");
 | 
| -            wrapFunctions["getUniformLocation"] = Resource.WrapFunction.resourceFactoryMethod(WebGLUniformLocationResource, "WebGLUniformLocation");
 | 
| -
 | 
| -            stateModifyingWrapFunction("bindAttribLocation");
 | 
| -            stateModifyingWrapFunction("compileShader");
 | 
| -            stateModifyingWrapFunction("detachShader");
 | 
| -            stateModifyingWrapFunction("linkProgram");
 | 
| -            stateModifyingWrapFunction("shaderSource");
 | 
| -            stateModifyingWrapFunction("bufferData", WebGLBufferResource.prototype.pushCall_bufferData);
 | 
| -            stateModifyingWrapFunction("bufferSubData", WebGLBufferResource.prototype.pushCall_bufferSubData);
 | 
| -            stateModifyingWrapFunction("compressedTexImage2D");
 | 
| -            stateModifyingWrapFunction("compressedTexSubImage2D");
 | 
| -            stateModifyingWrapFunction("copyTexImage2D", WebGLTextureResource.prototype.pushCall_copyTexImage2D);
 | 
| -            stateModifyingWrapFunction("copyTexSubImage2D", WebGLTextureResource.prototype.pushCall_copyTexImage2D);
 | 
| -            stateModifyingWrapFunction("generateMipmap");
 | 
| -            stateModifyingWrapFunction("texImage2D");
 | 
| -            stateModifyingWrapFunction("texSubImage2D");
 | 
| -            stateModifyingWrapFunction("texParameterf", WebGLTextureResource.prototype.pushCall_texParameter);
 | 
| -            stateModifyingWrapFunction("texParameteri", WebGLTextureResource.prototype.pushCall_texParameter);
 | 
| -            stateModifyingWrapFunction("renderbufferStorage");
 | 
| -
 | 
| -            /** @this {Resource.WrapFunction} */
 | 
| -            wrapFunctions["getError"] = function()
 | 
| -            {
 | 
| -                var gl = /** @type {!WebGLRenderingContext} */ (this._originalObject);
 | 
| -                var error = this.result();
 | 
| -                if (error !== gl.NO_ERROR)
 | 
| -                    this._resource.clearError(error);
 | 
| -                else {
 | 
| -                    error = this._resource.nextError();
 | 
| -                    if (error !== gl.NO_ERROR)
 | 
| -                        this.overrideResult(error);
 | 
| -                }
 | 
| -            }
 | 
| -
 | 
| -            /**
 | 
| -             * @param {string} name
 | 
| -             * @this {Resource.WrapFunction}
 | 
| -             */
 | 
| -            wrapFunctions["getExtension"] = function(name)
 | 
| -            {
 | 
| -                this._resource.registerWebGLExtension(name, this.result());
 | 
| -            }
 | 
| -
 | 
| -            //
 | 
| -            // Register bound WebGL resources.
 | 
| -            //
 | 
| -
 | 
| -            /**
 | 
| -             * @param {!WebGLProgram} program
 | 
| -             * @param {!WebGLShader} shader
 | 
| -             * @this {Resource.WrapFunction}
 | 
| -             */
 | 
| -            wrapFunctions["attachShader"] = function(program, shader)
 | 
| -            {
 | 
| -                var resource = this._resource.currentBinding(program);
 | 
| -                if (resource) {
 | 
| -                    resource.pushCall(this.call());
 | 
| -                    var shaderResource = /** @type {!WebGLShaderResource} */ (Resource.forObject(shader));
 | 
| -                    if (shaderResource) {
 | 
| -                        var shaderType = shaderResource.type();
 | 
| -                        resource._registerBoundResource("__attachShader_" + shaderType, shaderResource);
 | 
| -                    }
 | 
| -                }
 | 
| -            }
 | 
| -            /**
 | 
| -             * @param {number} target
 | 
| -             * @param {number} attachment
 | 
| -             * @param {number} objectTarget
 | 
| -             * @param {!WebGLRenderbuffer|!WebGLTexture} obj
 | 
| -             * @this {Resource.WrapFunction}
 | 
| -             */
 | 
| -            wrapFunctions["framebufferRenderbuffer"] = wrapFunctions["framebufferTexture2D"] = function(target, attachment, objectTarget, obj)
 | 
| -            {
 | 
| -                var resource = this._resource.currentBinding(target);
 | 
| -                if (resource) {
 | 
| -                    resource.pushCall(this.call());
 | 
| -                    resource._registerBoundResource("__framebufferAttachmentObjectName", obj);
 | 
| -                }
 | 
| -            }
 | 
| -            /**
 | 
| -             * @param {number} target
 | 
| -             * @param {!Object} obj
 | 
| -             * @this {Resource.WrapFunction}
 | 
| -             */
 | 
| -            wrapFunctions["bindBuffer"] = wrapFunctions["bindFramebuffer"] = wrapFunctions["bindRenderbuffer"] = function(target, obj)
 | 
| -            {
 | 
| -                this._resource.currentBinding(target); // To call WebGLBoundResource.prototype.pushBinding().
 | 
| -                this._resource._registerBoundResource("__bindBuffer_" + target, obj);
 | 
| -            }
 | 
| -            /**
 | 
| -             * @param {number} target
 | 
| -             * @param {!WebGLTexture} obj
 | 
| -             * @this {Resource.WrapFunction}
 | 
| -             */
 | 
| -            wrapFunctions["bindTexture"] = function(target, obj)
 | 
| -            {
 | 
| -                this._resource.currentBinding(target); // To call WebGLBoundResource.prototype.pushBinding().
 | 
| -                var gl = /** @type {!WebGLRenderingContext} */ (this._originalObject);
 | 
| -                var currentTextureBinding = /** @type {number} */ (gl.getParameter(gl.ACTIVE_TEXTURE));
 | 
| -                this._resource._registerBoundResource("__bindTexture_" + target + "_" + currentTextureBinding, obj);
 | 
| -            }
 | 
| -            /**
 | 
| -             * @param {!WebGLProgram} program
 | 
| -             * @this {Resource.WrapFunction}
 | 
| -             */
 | 
| -            wrapFunctions["useProgram"] = function(program)
 | 
| -            {
 | 
| -                this._resource._registerBoundResource("__useProgram", program);
 | 
| -            }
 | 
| -            /**
 | 
| -             * @param {number} index
 | 
| -             * @this {Resource.WrapFunction}
 | 
| -             */
 | 
| -            wrapFunctions["vertexAttribPointer"] = function(index)
 | 
| -            {
 | 
| -                var gl = /** @type {!WebGLRenderingContext} */ (this._originalObject);
 | 
| -                this._resource._registerBoundResource("__vertexAttribPointer_" + index, gl.getParameter(gl.ARRAY_BUFFER_BINDING));
 | 
| -            }
 | 
| -
 | 
| -            WebGLRenderingContextResource._wrapFunctions = wrapFunctions;
 | 
| -        }
 | 
| -
 | 
| -        /**
 | 
| -         * @param {string} methodName
 | 
| -         * @param {function(this:Resource, !Call)=} pushCallFunc
 | 
| -         */
 | 
| -        function stateModifyingWrapFunction(methodName, pushCallFunc)
 | 
| -        {
 | 
| -            if (pushCallFunc) {
 | 
| -                /**
 | 
| -                 * @param {!Object|number} target
 | 
| -                 * @this {Resource.WrapFunction}
 | 
| -                 */
 | 
| -                wrapFunctions[methodName] = function(target)
 | 
| -                {
 | 
| -                    var resource = this._resource.currentBinding(target);
 | 
| -                    if (resource)
 | 
| -                        pushCallFunc.call(resource, this.call());
 | 
| -                }
 | 
| -            } else {
 | 
| -                /**
 | 
| -                 * @param {!Object|number} target
 | 
| -                 * @this {Resource.WrapFunction}
 | 
| -                 */
 | 
| -                wrapFunctions[methodName] = function(target)
 | 
| -                {
 | 
| -                    var resource = this._resource.currentBinding(target);
 | 
| -                    if (resource)
 | 
| -                        resource.pushCall(this.call());
 | 
| -                }
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        return wrapFunctions;
 | 
| -    },
 | 
| -
 | 
| -    __proto__: ContextResource.prototype
 | 
| -}
 | 
| -
 | 
| -////////////////////////////////////////////////////////////////////////////////
 | 
| -// 2D Canvas
 | 
| -////////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {ContextResource}
 | 
| - * @param {!CanvasRenderingContext2D} context
 | 
| - */
 | 
| -function CanvasRenderingContext2DResource(context)
 | 
| -{
 | 
| -    ContextResource.call(this, context, "CanvasRenderingContext2D");
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @const
 | 
| - * @type {!Array.<string>}
 | 
| - */
 | 
| -CanvasRenderingContext2DResource.AttributeProperties = [
 | 
| -    "strokeStyle",
 | 
| -    "fillStyle",
 | 
| -    "globalAlpha",
 | 
| -    "lineWidth",
 | 
| -    "lineCap",
 | 
| -    "lineJoin",
 | 
| -    "miterLimit",
 | 
| -    "shadowOffsetX",
 | 
| -    "shadowOffsetY",
 | 
| -    "shadowBlur",
 | 
| -    "shadowColor",
 | 
| -    "globalCompositeOperation",
 | 
| -    "font",
 | 
| -    "textAlign",
 | 
| -    "textBaseline",
 | 
| -    "lineDashOffset",
 | 
| -    "imageSmoothingEnabled",
 | 
| -    "webkitLineDash",
 | 
| -    "webkitLineDashOffset"
 | 
| -];
 | 
| -
 | 
| -/**
 | 
| - * @const
 | 
| - * @type {!Array.<string>}
 | 
| - */
 | 
| -CanvasRenderingContext2DResource.PathMethods = [
 | 
| -    "beginPath",
 | 
| -    "moveTo",
 | 
| -    "closePath",
 | 
| -    "lineTo",
 | 
| -    "quadraticCurveTo",
 | 
| -    "bezierCurveTo",
 | 
| -    "arcTo",
 | 
| -    "arc",
 | 
| -    "rect",
 | 
| -    "ellipse"
 | 
| -];
 | 
| -
 | 
| -/**
 | 
| - * @const
 | 
| - * @type {!Array.<string>}
 | 
| - */
 | 
| -CanvasRenderingContext2DResource.TransformationMatrixMethods = [
 | 
| -    "scale",
 | 
| -    "rotate",
 | 
| -    "translate",
 | 
| -    "transform",
 | 
| -    "setTransform",
 | 
| -    "resetTransform"
 | 
| -];
 | 
| -
 | 
| -/**
 | 
| - * @const
 | 
| - * @type {!Object.<string, boolean>}
 | 
| - */
 | 
| -CanvasRenderingContext2DResource.DrawingMethods = TypeUtils.createPrefixedPropertyNamesSet([
 | 
| -    "clearRect",
 | 
| -    "drawImage",
 | 
| -    "drawImageFromRect",
 | 
| -    "drawCustomFocusRing",
 | 
| -    "drawFocusIfNeeded",
 | 
| -    "fill",
 | 
| -    "fillRect",
 | 
| -    "fillText",
 | 
| -    "putImageData",
 | 
| -    "putImageDataHD",
 | 
| -    "stroke",
 | 
| -    "strokeRect",
 | 
| -    "strokeText"
 | 
| -]);
 | 
| -
 | 
| -CanvasRenderingContext2DResource.prototype = {
 | 
| -    /**
 | 
| -     * @override (overrides @return type)
 | 
| -     * @return {!CanvasRenderingContext2D}
 | 
| -     */
 | 
| -    wrappedObject: function()
 | 
| -    {
 | 
| -        return this._wrappedObject;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {string}
 | 
| -     */
 | 
| -    toDataURL: function()
 | 
| -    {
 | 
| -        return this.wrappedObject().canvas.toDataURL();
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Array.<!TypeUtils.InternalResourceStateDescriptor>}
 | 
| -     */
 | 
| -    currentState: function()
 | 
| -    {
 | 
| -        var result = [];
 | 
| -        var state = this._internalCurrentState(null);
 | 
| -        for (var pname in state)
 | 
| -            result.push({ name: pname, value: state[pname] });
 | 
| -        result.push({ name: "context", value: this.contextResource() });
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {?Cache.<!ReplayableResource>} cache
 | 
| -     * @return {!Object.<string, *>}
 | 
| -     */
 | 
| -    _internalCurrentState: function(cache)
 | 
| -    {
 | 
| -        /**
 | 
| -         * @param {!Resource|*} obj
 | 
| -         * @return {!Resource|!ReplayableResource|*}
 | 
| -         */
 | 
| -        function maybeToReplayable(obj)
 | 
| -        {
 | 
| -            return cache ? Resource.toReplayable(obj, cache) : (Resource.forObject(obj) || obj);
 | 
| -        }
 | 
| -
 | 
| -        var ctx = this.wrappedObject();
 | 
| -        var state = Object.create(null);
 | 
| -        CanvasRenderingContext2DResource.AttributeProperties.forEach(function(attribute) {
 | 
| -            if (attribute in ctx)
 | 
| -                state[attribute] = maybeToReplayable(ctx[attribute]);
 | 
| -        });
 | 
| -        if (ctx.getLineDash)
 | 
| -            state.lineDash = ctx.getLineDash();
 | 
| -        return state;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {?Object.<string, *>} state
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     */
 | 
| -    _applyAttributesState: function(state, cache)
 | 
| -    {
 | 
| -        if (!state)
 | 
| -            return;
 | 
| -        var ctx = this.wrappedObject();
 | 
| -        for (var attribute in state) {
 | 
| -            if (attribute === "lineDash") {
 | 
| -                if (ctx.setLineDash)
 | 
| -                    ctx.setLineDash(/** @type {!Array.<number>} */ (state[attribute]));
 | 
| -            } else
 | 
| -                ctx[attribute] = ReplayableResource.replay(state[attribute], cache);
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!ReplayableResource>} cache
 | 
| -     */
 | 
| -    _populateReplayableData: function(data, cache)
 | 
| -    {
 | 
| -        var ctx = this.wrappedObject();
 | 
| -        // FIXME: Convert resources in the state (CanvasGradient, CanvasPattern) to Replayable.
 | 
| -        data.currentAttributes = this._internalCurrentState(null);
 | 
| -        data.originalCanvasCloned = TypeUtils.cloneIntoCanvas(/** @type {!HTMLCanvasElement} */ (ctx.canvas));
 | 
| -        if (ctx.getContextAttributes)
 | 
| -            data.originalContextAttributes = ctx.getContextAttributes();
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!Object} data
 | 
| -     * @param {!Cache.<!Resource>} cache
 | 
| -     */
 | 
| -    _doReplayCalls: function(data, cache)
 | 
| -    {
 | 
| -        var canvas = TypeUtils.cloneIntoCanvas(data.originalCanvasCloned);
 | 
| -        var ctx = /** @type {!CanvasRenderingContext2D} */ (Resource.wrappedObject(canvas.getContext("2d", data.originalContextAttributes)));
 | 
| -        this.setWrappedObject(ctx);
 | 
| -
 | 
| -        for (var i = 0, n = data.calls.length; i < n; ++i) {
 | 
| -            var replayableCall = /** @type {!ReplayableCall} */ (data.calls[i]);
 | 
| -            if (replayableCall.functionName() === "save")
 | 
| -                this._applyAttributesState(replayableCall.attachment("canvas2dAttributesState"), cache);
 | 
| -            this._calls.push(replayableCall.replay(cache));
 | 
| -        }
 | 
| -        this._applyAttributesState(data.currentAttributes, cache);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall_setOrResetTransform: function(call)
 | 
| -    {
 | 
| -        var saveCallIndex = this._lastIndexOfMatchingSaveCall();
 | 
| -        var index = this._lastIndexOfAnyCall(CanvasRenderingContext2DResource.PathMethods);
 | 
| -        index = Math.max(index, saveCallIndex);
 | 
| -        if (this._removeCallsFromLog(CanvasRenderingContext2DResource.TransformationMatrixMethods, index + 1))
 | 
| -            this._removeAllObsoleteCallsFromLog();
 | 
| -        this.pushCall(call);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall_beginPath: function(call)
 | 
| -    {
 | 
| -        var index = this._lastIndexOfAnyCall(["clip"]);
 | 
| -        if (this._removeCallsFromLog(CanvasRenderingContext2DResource.PathMethods, index + 1))
 | 
| -            this._removeAllObsoleteCallsFromLog();
 | 
| -        this.pushCall(call);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall_save: function(call)
 | 
| -    {
 | 
| -        // FIXME: Convert resources in the state (CanvasGradient, CanvasPattern) to Replayable.
 | 
| -        call.setAttachment("canvas2dAttributesState", this._internalCurrentState(null));
 | 
| -        this.pushCall(call);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    pushCall_restore: function(call)
 | 
| -    {
 | 
| -        var lastIndexOfSave = this._lastIndexOfMatchingSaveCall();
 | 
| -        if (lastIndexOfSave === -1)
 | 
| -            return;
 | 
| -        this._calls[lastIndexOfSave].setAttachment("canvas2dAttributesState", null); // No longer needed, free memory.
 | 
| -
 | 
| -        var modified = false;
 | 
| -        if (this._removeCallsFromLog(["clip"], lastIndexOfSave + 1))
 | 
| -            modified = true;
 | 
| -
 | 
| -        var lastIndexOfAnyPathMethod = this._lastIndexOfAnyCall(CanvasRenderingContext2DResource.PathMethods);
 | 
| -        var index = Math.max(lastIndexOfSave, lastIndexOfAnyPathMethod);
 | 
| -        if (this._removeCallsFromLog(CanvasRenderingContext2DResource.TransformationMatrixMethods, index + 1))
 | 
| -            modified = true;
 | 
| -
 | 
| -        if (modified)
 | 
| -            this._removeAllObsoleteCallsFromLog();
 | 
| -
 | 
| -        var lastCall = this._calls[this._calls.length - 1];
 | 
| -        if (lastCall && lastCall.functionName() === "save")
 | 
| -            this._calls.pop();
 | 
| -        else
 | 
| -            this.pushCall(call);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number=} fromIndex
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    _lastIndexOfMatchingSaveCall: function(fromIndex)
 | 
| -    {
 | 
| -        if (typeof fromIndex !== "number")
 | 
| -            fromIndex = this._calls.length - 1;
 | 
| -        else
 | 
| -            fromIndex = Math.min(fromIndex, this._calls.length - 1);
 | 
| -        var stackDepth = 1;
 | 
| -        for (var i = fromIndex; i >= 0; --i) {
 | 
| -            var functionName = this._calls[i].functionName();
 | 
| -            if (functionName === "restore")
 | 
| -                ++stackDepth;
 | 
| -            else if (functionName === "save") {
 | 
| -                --stackDepth;
 | 
| -                if (!stackDepth)
 | 
| -                    return i;
 | 
| -            }
 | 
| -        }
 | 
| -        return -1;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Array.<string>} functionNames
 | 
| -     * @param {number=} fromIndex
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    _lastIndexOfAnyCall: function(functionNames, fromIndex)
 | 
| -    {
 | 
| -        if (typeof fromIndex !== "number")
 | 
| -            fromIndex = this._calls.length - 1;
 | 
| -        else
 | 
| -            fromIndex = Math.min(fromIndex, this._calls.length - 1);
 | 
| -        for (var i = fromIndex; i >= 0; --i) {
 | 
| -            if (functionNames.indexOf(this._calls[i].functionName()) !== -1)
 | 
| -                return i;
 | 
| -        }
 | 
| -        return -1;
 | 
| -    },
 | 
| -
 | 
| -    _removeAllObsoleteCallsFromLog: function()
 | 
| -    {
 | 
| -        // Remove all PATH methods between clip() and beginPath() calls.
 | 
| -        var lastIndexOfBeginPath = this._lastIndexOfAnyCall(["beginPath"]);
 | 
| -        while (lastIndexOfBeginPath !== -1) {
 | 
| -            var index = this._lastIndexOfAnyCall(["clip"], lastIndexOfBeginPath - 1);
 | 
| -            this._removeCallsFromLog(CanvasRenderingContext2DResource.PathMethods, index + 1, lastIndexOfBeginPath);
 | 
| -            lastIndexOfBeginPath = this._lastIndexOfAnyCall(["beginPath"], index - 1);
 | 
| -        }
 | 
| -
 | 
| -        // Remove all TRASFORMATION MATRIX methods before restore(), setTransform() or resetTransform() but after any PATH or corresponding save() method.
 | 
| -        var lastRestore = this._lastIndexOfAnyCall(["restore", "setTransform", "resetTransform"]);
 | 
| -        while (lastRestore !== -1) {
 | 
| -            var saveCallIndex = this._lastIndexOfMatchingSaveCall(lastRestore - 1);
 | 
| -            var index = this._lastIndexOfAnyCall(CanvasRenderingContext2DResource.PathMethods, lastRestore - 1);
 | 
| -            index = Math.max(index, saveCallIndex);
 | 
| -            this._removeCallsFromLog(CanvasRenderingContext2DResource.TransformationMatrixMethods, index + 1, lastRestore);
 | 
| -            lastRestore = this._lastIndexOfAnyCall(["restore", "setTransform", "resetTransform"], index - 1);
 | 
| -        }
 | 
| -
 | 
| -        // Remove all save-restore consecutive pairs.
 | 
| -        var restoreCalls = 0;
 | 
| -        for (var i = this._calls.length - 1; i >= 0; --i) {
 | 
| -            var functionName = this._calls[i].functionName();
 | 
| -            if (functionName === "restore") {
 | 
| -                ++restoreCalls;
 | 
| -                continue;
 | 
| -            }
 | 
| -            if (functionName === "save" && restoreCalls > 0) {
 | 
| -                var saveCallIndex = i;
 | 
| -                for (var j = i - 1; j >= 0 && i - j < restoreCalls; --j) {
 | 
| -                    if (this._calls[j].functionName() === "save")
 | 
| -                        saveCallIndex = j;
 | 
| -                    else
 | 
| -                        break;
 | 
| -                }
 | 
| -                this._calls.splice(saveCallIndex, (i - saveCallIndex + 1) * 2);
 | 
| -                i = saveCallIndex;
 | 
| -            }
 | 
| -            restoreCalls = 0;
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Array.<string>} functionNames
 | 
| -     * @param {number} fromIndex
 | 
| -     * @param {number=} toIndex
 | 
| -     * @return {boolean}
 | 
| -     */
 | 
| -    _removeCallsFromLog: function(functionNames, fromIndex, toIndex)
 | 
| -    {
 | 
| -        var oldLength = this._calls.length;
 | 
| -        if (typeof toIndex !== "number")
 | 
| -            toIndex = oldLength;
 | 
| -        else
 | 
| -            toIndex = Math.min(toIndex, oldLength);
 | 
| -        var newIndex = Math.min(fromIndex, oldLength);
 | 
| -        for (var i = newIndex; i < toIndex; ++i) {
 | 
| -            var call = this._calls[i];
 | 
| -            if (functionNames.indexOf(call.functionName()) === -1)
 | 
| -                this._calls[newIndex++] = call;
 | 
| -        }
 | 
| -        if (newIndex >= toIndex)
 | 
| -            return false;
 | 
| -        this._calls.splice(newIndex, toIndex - newIndex);
 | 
| -        return true;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @return {!Object.<string, !Function>}
 | 
| -     */
 | 
| -    _customWrapFunctions: function()
 | 
| -    {
 | 
| -        var wrapFunctions = CanvasRenderingContext2DResource._wrapFunctions;
 | 
| -        if (!wrapFunctions) {
 | 
| -            wrapFunctions = Object.create(null);
 | 
| -
 | 
| -            wrapFunctions["createLinearGradient"] = Resource.WrapFunction.resourceFactoryMethod(LogEverythingResource, "CanvasGradient");
 | 
| -            wrapFunctions["createRadialGradient"] = Resource.WrapFunction.resourceFactoryMethod(LogEverythingResource, "CanvasGradient");
 | 
| -            wrapFunctions["createPattern"] = Resource.WrapFunction.resourceFactoryMethod(LogEverythingResource, "CanvasPattern");
 | 
| -
 | 
| -            for (var i = 0, methodName; methodName = CanvasRenderingContext2DResource.TransformationMatrixMethods[i]; ++i)
 | 
| -                stateModifyingWrapFunction(methodName, (methodName === "setTransform" || methodName === "resetTransform") ? this.pushCall_setOrResetTransform : undefined);
 | 
| -            for (var i = 0, methodName; methodName = CanvasRenderingContext2DResource.PathMethods[i]; ++i)
 | 
| -                stateModifyingWrapFunction(methodName, methodName === "beginPath" ? this.pushCall_beginPath : undefined);
 | 
| -
 | 
| -            stateModifyingWrapFunction("save", this.pushCall_save);
 | 
| -            stateModifyingWrapFunction("restore", this.pushCall_restore);
 | 
| -            stateModifyingWrapFunction("clip");
 | 
| -
 | 
| -            CanvasRenderingContext2DResource._wrapFunctions = wrapFunctions;
 | 
| -        }
 | 
| -
 | 
| -        /**
 | 
| -         * @param {string} methodName
 | 
| -         * @param {function(this:Resource, !Call)=} func
 | 
| -         */
 | 
| -        function stateModifyingWrapFunction(methodName, func)
 | 
| -        {
 | 
| -            if (func) {
 | 
| -                /** @this {Resource.WrapFunction} */
 | 
| -                wrapFunctions[methodName] = function()
 | 
| -                {
 | 
| -                    func.call(this._resource, this.call());
 | 
| -                }
 | 
| -            } else {
 | 
| -                /** @this {Resource.WrapFunction} */
 | 
| -                wrapFunctions[methodName] = function()
 | 
| -                {
 | 
| -                    this._resource.pushCall(this.call());
 | 
| -                }
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        return wrapFunctions;
 | 
| -    },
 | 
| -
 | 
| -    __proto__: ContextResource.prototype
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @param {!Object.<string, boolean>=} drawingMethodNames
 | 
| - */
 | 
| -function CallFormatter(drawingMethodNames)
 | 
| -{
 | 
| -    this._drawingMethodNames = drawingMethodNames || Object.create(null);
 | 
| -}
 | 
| -
 | 
| -CallFormatter.prototype = {
 | 
| -    /**
 | 
| -     * @param {!ReplayableCall} replayableCall
 | 
| -     * @param {string=} objectGroup
 | 
| -     * @return {!Object}
 | 
| -     */
 | 
| -    formatCall: function(replayableCall, objectGroup)
 | 
| -    {
 | 
| -        var result = {};
 | 
| -        var functionName = replayableCall.functionName();
 | 
| -        if (functionName) {
 | 
| -            result.functionName = functionName;
 | 
| -            result.arguments = [];
 | 
| -            var args = replayableCall.args();
 | 
| -            for (var i = 0, n = args.length; i < n; ++i)
 | 
| -                result.arguments.push(this.formatValue(args[i], objectGroup));
 | 
| -            if (replayableCall.result() !== undefined)
 | 
| -                result.result = this.formatValue(replayableCall.result(), objectGroup);
 | 
| -            if (this._drawingMethodNames[functionName])
 | 
| -                result.isDrawingCall = true;
 | 
| -        } else {
 | 
| -            result.property = replayableCall.propertyName();
 | 
| -            result.value = this.formatValue(replayableCall.propertyValue(), objectGroup);
 | 
| -        }
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {*} value
 | 
| -     * @param {string=} objectGroup
 | 
| -     * @return {!CanvasAgent.CallArgument}
 | 
| -     */
 | 
| -    formatValue: function(value, objectGroup)
 | 
| -    {
 | 
| -        if (value instanceof Resource || value instanceof ReplayableResource) {
 | 
| -            return {
 | 
| -                description: value.description(),
 | 
| -                resourceId: CallFormatter.makeStringResourceId(value.id())
 | 
| -            };
 | 
| -        }
 | 
| -
 | 
| -        var doNotBind = !objectGroup;
 | 
| -        var remoteObject = injectedScript.wrapObjectForModule(value, objectGroup || "", doNotBind);
 | 
| -        var description = remoteObject.description || ("" + value);
 | 
| -
 | 
| -        var result = {
 | 
| -            description: description,
 | 
| -            type: /** @type {!CanvasAgent.CallArgumentType} */ (remoteObject.type)
 | 
| -        };
 | 
| -        if (remoteObject.subtype)
 | 
| -            result.subtype = /** @type {!CanvasAgent.CallArgumentSubtype} */ (remoteObject.subtype);
 | 
| -        if (remoteObject.objectId && !doNotBind)
 | 
| -            result.remoteObject = remoteObject;
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {string} name
 | 
| -     * @return {?string}
 | 
| -     */
 | 
| -    enumValueForName: function(name)
 | 
| -    {
 | 
| -        return null;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} value
 | 
| -     * @param {!Array.<string>=} options
 | 
| -     * @return {?string}
 | 
| -     */
 | 
| -    enumNameForValue: function(value, options)
 | 
| -    {
 | 
| -        return null;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Array.<!TypeUtils.InternalResourceStateDescriptor>} descriptors
 | 
| -     * @param {string=} objectGroup
 | 
| -     * @return {!Array.<!CanvasAgent.ResourceStateDescriptor>}
 | 
| -     */
 | 
| -    formatResourceStateDescriptors: function(descriptors, objectGroup)
 | 
| -    {
 | 
| -        var result = [];
 | 
| -        for (var i = 0, n = descriptors.length; i < n; ++i) {
 | 
| -            var d = descriptors[i];
 | 
| -            var item;
 | 
| -            if (d.values)
 | 
| -                item = { name: d.name, values: this.formatResourceStateDescriptors(d.values, objectGroup) };
 | 
| -            else {
 | 
| -                item = { name: d.name, value: this.formatValue(d.value, objectGroup) };
 | 
| -                if (d.valueIsEnum && typeof d.value === "number") {
 | 
| -                    var enumName = this.enumNameForValue(d.value);
 | 
| -                    if (enumName)
 | 
| -                        item.value.enumName = enumName;
 | 
| -                }
 | 
| -            }
 | 
| -            var enumValue = this.enumValueForName(d.name);
 | 
| -            if (enumValue)
 | 
| -                item.enumValueForName = enumValue;
 | 
| -            if (d.isArray)
 | 
| -                item.isArray = true;
 | 
| -            result.push(item);
 | 
| -        }
 | 
| -        return result;
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @const
 | 
| - * @type {!Object.<string, !CallFormatter>}
 | 
| - */
 | 
| -CallFormatter._formatters = {};
 | 
| -
 | 
| -/**
 | 
| - * @param {string} resourceName
 | 
| - * @param {!CallFormatter} callFormatter
 | 
| - */
 | 
| -CallFormatter.register = function(resourceName, callFormatter)
 | 
| -{
 | 
| -    CallFormatter._formatters[resourceName] = callFormatter;
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @param {!Resource|!ReplayableResource} resource
 | 
| - * @return {!CallFormatter}
 | 
| - */
 | 
| -CallFormatter.forResource = function(resource)
 | 
| -{
 | 
| -    var formatter = CallFormatter._formatters[resource.name()];
 | 
| -    if (!formatter) {
 | 
| -        var contextResource = resource.contextResource();
 | 
| -        formatter = (contextResource && CallFormatter._formatters[contextResource.name()]) || new CallFormatter();
 | 
| -    }
 | 
| -    return formatter;
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @param {number} resourceId
 | 
| - * @return {!CanvasAgent.ResourceId}
 | 
| - */
 | 
| -CallFormatter.makeStringResourceId = function(resourceId)
 | 
| -{
 | 
| -    return "{\"injectedScriptId\":" + injectedScriptId + ",\"resourceId\":" + resourceId + "}";
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @extends {CallFormatter}
 | 
| - * @param {!Object.<string, boolean>} drawingMethodNames
 | 
| - */
 | 
| -function WebGLCallFormatter(drawingMethodNames)
 | 
| -{
 | 
| -    CallFormatter.call(this, drawingMethodNames);
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * NOTE: The code below is generated from the IDL file by the script:
 | 
| - * /devtools/scripts/check_injected_webgl_calls_info.py
 | 
| - *
 | 
| - * @type {!Array.<{aname: string, enum: (!Array.<number>|undefined), bitfield: (!Array.<number>|undefined), returnType: string, hints: (!Array.<string>|undefined)}>}
 | 
| - */
 | 
| -WebGLCallFormatter.EnumsInfo = [
 | 
| -    {"aname": "activeTexture", "enum": [0]},
 | 
| -    {"aname": "bindBuffer", "enum": [0]},
 | 
| -    {"aname": "bindFramebuffer", "enum": [0]},
 | 
| -    {"aname": "bindRenderbuffer", "enum": [0]},
 | 
| -    {"aname": "bindTexture", "enum": [0]},
 | 
| -    {"aname": "blendEquation", "enum": [0]},
 | 
| -    {"aname": "blendEquationSeparate", "enum": [0, 1]},
 | 
| -    {"aname": "blendFunc", "enum": [0, 1], "hints": ["ZERO", "ONE"]},
 | 
| -    {"aname": "blendFuncSeparate", "enum": [0, 1, 2, 3], "hints": ["ZERO", "ONE"]},
 | 
| -    {"aname": "bufferData", "enum": [0, 2]},
 | 
| -    {"aname": "bufferSubData", "enum": [0]},
 | 
| -    {"aname": "checkFramebufferStatus", "enum": [0], "returnType": "enum"},
 | 
| -    {"aname": "clear", "bitfield": [0]},
 | 
| -    {"aname": "compressedTexImage2D", "enum": [0, 2]},
 | 
| -    {"aname": "compressedTexSubImage2D", "enum": [0, 6]},
 | 
| -    {"aname": "copyTexImage2D", "enum": [0, 2]},
 | 
| -    {"aname": "copyTexSubImage2D", "enum": [0]},
 | 
| -    {"aname": "createShader", "enum": [0]},
 | 
| -    {"aname": "cullFace", "enum": [0]},
 | 
| -    {"aname": "depthFunc", "enum": [0]},
 | 
| -    {"aname": "disable", "enum": [0]},
 | 
| -    {"aname": "drawArrays", "enum": [0], "hints": ["POINTS", "LINES"]},
 | 
| -    {"aname": "drawElements", "enum": [0, 2], "hints": ["POINTS", "LINES"]},
 | 
| -    {"aname": "enable", "enum": [0]},
 | 
| -    {"aname": "framebufferRenderbuffer", "enum": [0, 1, 2]},
 | 
| -    {"aname": "framebufferTexture2D", "enum": [0, 1, 2]},
 | 
| -    {"aname": "frontFace", "enum": [0]},
 | 
| -    {"aname": "generateMipmap", "enum": [0]},
 | 
| -    {"aname": "getBufferParameter", "enum": [0, 1]},
 | 
| -    {"aname": "getError", "hints": ["NO_ERROR"], "returnType": "enum"},
 | 
| -    {"aname": "getFramebufferAttachmentParameter", "enum": [0, 1, 2]},
 | 
| -    {"aname": "getParameter", "enum": [0]},
 | 
| -    {"aname": "getProgramParameter", "enum": [1]},
 | 
| -    {"aname": "getRenderbufferParameter", "enum": [0, 1]},
 | 
| -    {"aname": "getShaderParameter", "enum": [1]},
 | 
| -    {"aname": "getShaderPrecisionFormat", "enum": [0, 1]},
 | 
| -    {"aname": "getTexParameter", "enum": [0, 1], "returnType": "enum"},
 | 
| -    {"aname": "getVertexAttrib", "enum": [1]},
 | 
| -    {"aname": "getVertexAttribOffset", "enum": [1]},
 | 
| -    {"aname": "hint", "enum": [0, 1]},
 | 
| -    {"aname": "isEnabled", "enum": [0]},
 | 
| -    {"aname": "pixelStorei", "enum": [0]},
 | 
| -    {"aname": "readPixels", "enum": [4, 5]},
 | 
| -    {"aname": "renderbufferStorage", "enum": [0, 1]},
 | 
| -    {"aname": "stencilFunc", "enum": [0]},
 | 
| -    {"aname": "stencilFuncSeparate", "enum": [0, 1]},
 | 
| -    {"aname": "stencilMaskSeparate", "enum": [0]},
 | 
| -    {"aname": "stencilOp", "enum": [0, 1, 2], "hints": ["ZERO", "ONE"]},
 | 
| -    {"aname": "stencilOpSeparate", "enum": [0, 1, 2, 3], "hints": ["ZERO", "ONE"]},
 | 
| -    {"aname": "texParameterf", "enum": [0, 1, 2]},
 | 
| -    {"aname": "texParameteri", "enum": [0, 1, 2]},
 | 
| -    {"aname": "texImage2D", "enum": [0, 2, 6, 7]},
 | 
| -    {"aname": "texImage2D", "enum": [0, 2, 3, 4]},
 | 
| -    {"aname": "texSubImage2D", "enum": [0, 6, 7]},
 | 
| -    {"aname": "texSubImage2D", "enum": [0, 4, 5]},
 | 
| -    {"aname": "vertexAttribPointer", "enum": [2]}
 | 
| -];
 | 
| -
 | 
| -WebGLCallFormatter.prototype = {
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {!ReplayableCall} replayableCall
 | 
| -     * @param {string=} objectGroup
 | 
| -     * @return {!Object}
 | 
| -     */
 | 
| -    formatCall: function(replayableCall, objectGroup)
 | 
| -    {
 | 
| -        var result = CallFormatter.prototype.formatCall.call(this, replayableCall, objectGroup);
 | 
| -        if (!result.functionName)
 | 
| -            return result;
 | 
| -        var enumsInfo = this._findEnumsInfo(replayableCall);
 | 
| -        if (!enumsInfo)
 | 
| -            return result;
 | 
| -        var enumArgsIndexes = enumsInfo["enum"] || [];
 | 
| -        for (var i = 0, n = enumArgsIndexes.length; i < n; ++i) {
 | 
| -            var index = enumArgsIndexes[i];
 | 
| -            var callArgument = result.arguments[index];
 | 
| -            this._formatEnumValue(callArgument, enumsInfo["hints"]);
 | 
| -        }
 | 
| -        var bitfieldArgsIndexes = enumsInfo["bitfield"] || [];
 | 
| -        for (var i = 0, n = bitfieldArgsIndexes.length; i < n; ++i) {
 | 
| -            var index = bitfieldArgsIndexes[i];
 | 
| -            var callArgument = result.arguments[index];
 | 
| -            this._formatEnumBitmaskValue(callArgument, enumsInfo["hints"]);
 | 
| -        }
 | 
| -        if (enumsInfo.returnType === "enum")
 | 
| -            this._formatEnumValue(result.result, enumsInfo["hints"]);
 | 
| -        else if (enumsInfo.returnType === "bitfield")
 | 
| -            this._formatEnumBitmaskValue(result.result, enumsInfo["hints"]);
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {string} name
 | 
| -     * @return {?string}
 | 
| -     */
 | 
| -    enumValueForName: function(name)
 | 
| -    {
 | 
| -        this._initialize();
 | 
| -        if (name in this._enumNameToValue)
 | 
| -            return "" + this._enumNameToValue[name];
 | 
| -        return null;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @override
 | 
| -     * @param {number} value
 | 
| -     * @param {!Array.<string>=} options
 | 
| -     * @return {?string}
 | 
| -     */
 | 
| -    enumNameForValue: function(value, options)
 | 
| -    {
 | 
| -        this._initialize();
 | 
| -        options = options || [];
 | 
| -        for (var i = 0, n = options.length; i < n; ++i) {
 | 
| -            if (this._enumNameToValue[options[i]] === value)
 | 
| -                return options[i];
 | 
| -        }
 | 
| -        var names = this._enumValueToNames[value];
 | 
| -        if (!names || names.length !== 1)
 | 
| -            return null;
 | 
| -        return names[0];
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!ReplayableCall} replayableCall
 | 
| -     * @return {?Object}
 | 
| -     */
 | 
| -    _findEnumsInfo: function(replayableCall)
 | 
| -    {
 | 
| -        function findMaxArgumentIndex(enumsInfo)
 | 
| -        {
 | 
| -            var result = -1;
 | 
| -            var enumArgsIndexes = enumsInfo["enum"] || [];
 | 
| -            for (var i = 0, n = enumArgsIndexes.length; i < n; ++i)
 | 
| -                result = Math.max(result, enumArgsIndexes[i]);
 | 
| -            var bitfieldArgsIndexes = enumsInfo["bitfield"] || [];
 | 
| -            for (var i = 0, n = bitfieldArgsIndexes.length; i < n; ++i)
 | 
| -                result = Math.max(result, bitfieldArgsIndexes[i]);
 | 
| -            return result;
 | 
| -        }
 | 
| -
 | 
| -        var result = null;
 | 
| -        for (var i = 0, enumsInfo; enumsInfo = WebGLCallFormatter.EnumsInfo[i]; ++i) {
 | 
| -            if (enumsInfo["aname"] !== replayableCall.functionName())
 | 
| -                continue;
 | 
| -            var argsCount = replayableCall.args().length;
 | 
| -            var maxArgumentIndex = findMaxArgumentIndex(enumsInfo);
 | 
| -            if (maxArgumentIndex >= argsCount)
 | 
| -                continue;
 | 
| -            // To resolve ambiguity (see texImage2D, texSubImage2D) choose description with max argument indexes.
 | 
| -            if (!result || findMaxArgumentIndex(result) < maxArgumentIndex)
 | 
| -                result = enumsInfo;
 | 
| -        }
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {?CanvasAgent.CallArgument|undefined} callArgument
 | 
| -     * @param {!Array.<string>=} options
 | 
| -     */
 | 
| -    _formatEnumValue: function(callArgument, options)
 | 
| -    {
 | 
| -        if (!callArgument || isNaN(callArgument.description))
 | 
| -            return;
 | 
| -        this._initialize();
 | 
| -        var value = +callArgument.description;
 | 
| -        var enumName = this.enumNameForValue(value, options);
 | 
| -        if (enumName)
 | 
| -            callArgument.enumName = enumName;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {?CanvasAgent.CallArgument|undefined} callArgument
 | 
| -     * @param {!Array.<string>=} options
 | 
| -     */
 | 
| -    _formatEnumBitmaskValue: function(callArgument, options)
 | 
| -    {
 | 
| -        if (!callArgument || isNaN(callArgument.description))
 | 
| -            return;
 | 
| -        this._initialize();
 | 
| -        var value = +callArgument.description;
 | 
| -        options = options || [];
 | 
| -        /** @type {!Array.<string>} */
 | 
| -        var result = [];
 | 
| -        for (var i = 0, n = options.length; i < n; ++i) {
 | 
| -            var bitValue = this._enumNameToValue[options[i]] || 0;
 | 
| -            if (value & bitValue) {
 | 
| -                result.push(options[i]);
 | 
| -                value &= ~bitValue;
 | 
| -            }
 | 
| -        }
 | 
| -        while (value) {
 | 
| -            var nextValue = value & (value - 1);
 | 
| -            var bitValue = value ^ nextValue;
 | 
| -            var names = this._enumValueToNames[bitValue];
 | 
| -            if (!names || names.length !== 1) {
 | 
| -                console.warn("Ambiguous WebGL enum names for value " + bitValue + ": " + names);
 | 
| -                return;
 | 
| -            }
 | 
| -            result.push(names[0]);
 | 
| -            value = nextValue;
 | 
| -        }
 | 
| -        result.sort();
 | 
| -        callArgument.enumName = result.join(" | ");
 | 
| -    },
 | 
| -
 | 
| -    _initialize: function()
 | 
| -    {
 | 
| -        if (this._enumNameToValue)
 | 
| -            return;
 | 
| -
 | 
| -        /** @type {!Object.<string, number>} */
 | 
| -        this._enumNameToValue = Object.create(null);
 | 
| -        /** @type {!Object.<number, !Array.<string>>} */
 | 
| -        this._enumValueToNames = Object.create(null);
 | 
| -
 | 
| -        /**
 | 
| -         * @param {?Object} obj
 | 
| -         * @this WebGLCallFormatter
 | 
| -         */
 | 
| -        function iterateWebGLEnums(obj)
 | 
| -        {
 | 
| -            if (!obj)
 | 
| -                return;
 | 
| -            for (var property in obj) {
 | 
| -                if (TypeUtils.isEnumPropertyName(property, obj)) {
 | 
| -                    var value = /** @type {number} */ (obj[property]);
 | 
| -                    this._enumNameToValue[property] = value;
 | 
| -                    var names = this._enumValueToNames[value];
 | 
| -                    if (names) {
 | 
| -                        if (names.indexOf(property) === -1)
 | 
| -                            names.push(property);
 | 
| -                    } else
 | 
| -                        this._enumValueToNames[value] = [property];
 | 
| -                }
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        /**
 | 
| -         * @param {!Array.<string>} values
 | 
| -         * @return {string}
 | 
| -         */
 | 
| -        function commonSubstring(values)
 | 
| -        {
 | 
| -            var length = values.length;
 | 
| -            for (var i = 0; i < length; ++i) {
 | 
| -                for (var j = 0; j < length; ++j) {
 | 
| -                    if (values[j].indexOf(values[i]) === -1)
 | 
| -                        break;
 | 
| -                }
 | 
| -                if (j === length)
 | 
| -                    return values[i];
 | 
| -            }
 | 
| -            return "";
 | 
| -        }
 | 
| -
 | 
| -        var gl = this._createUninstrumentedWebGLRenderingContext();
 | 
| -        iterateWebGLEnums.call(this, gl);
 | 
| -
 | 
| -        var extensions = gl.getSupportedExtensions() || [];
 | 
| -        for (var i = 0, n = extensions.length; i < n; ++i)
 | 
| -            iterateWebGLEnums.call(this, gl.getExtension(extensions[i]));
 | 
| -
 | 
| -        // Sort to get rid of ambiguity.
 | 
| -        for (var value in this._enumValueToNames) {
 | 
| -            var numericValue = Number(value);
 | 
| -            var names = this._enumValueToNames[numericValue];
 | 
| -            if (names.length > 1) {
 | 
| -                // Choose one enum name if possible. For example:
 | 
| -                //   [BLEND_EQUATION, BLEND_EQUATION_RGB] => BLEND_EQUATION
 | 
| -                //   [COLOR_ATTACHMENT0, COLOR_ATTACHMENT0_WEBGL] => COLOR_ATTACHMENT0
 | 
| -                var common = commonSubstring(names);
 | 
| -                if (common)
 | 
| -                    this._enumValueToNames[numericValue] = [common];
 | 
| -                else
 | 
| -                    this._enumValueToNames[numericValue] = names.sort();
 | 
| -            }
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?WebGLRenderingContext}
 | 
| -     */
 | 
| -    _createUninstrumentedWebGLRenderingContext: function()
 | 
| -    {
 | 
| -        var canvas = /** @type {!HTMLCanvasElement} */ (inspectedWindow.document.createElement("canvas"));
 | 
| -        var contextIds = ["experimental-webgl", "webkit-3d", "3d"];
 | 
| -        for (var i = 0, contextId; contextId = contextIds[i]; ++i) {
 | 
| -            var context = canvas.getContext(contextId);
 | 
| -            if (context)
 | 
| -                return /** @type {!WebGLRenderingContext} */ (Resource.wrappedObject(context));
 | 
| -        }
 | 
| -        return null;
 | 
| -    },
 | 
| -
 | 
| -    __proto__: CallFormatter.prototype
 | 
| -}
 | 
| -
 | 
| -CallFormatter.register("CanvasRenderingContext2D", new CallFormatter(CanvasRenderingContext2DResource.DrawingMethods));
 | 
| -CallFormatter.register("WebGLRenderingContext", new WebGLCallFormatter(WebGLRenderingContextResource.DrawingMethods));
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - */
 | 
| -function TraceLog()
 | 
| -{
 | 
| -    /** @type {!Array.<!ReplayableCall>} */
 | 
| -    this._replayableCalls = [];
 | 
| -    /** @type {!Cache.<!ReplayableResource>} */
 | 
| -    this._replayablesCache = new Cache();
 | 
| -    /** @type {!Object.<number, boolean>} */
 | 
| -    this._frameEndCallIndexes = {};
 | 
| -    /** @type {!Object.<number, boolean>} */
 | 
| -    this._resourcesCreatedInThisTraceLog = {};
 | 
| -}
 | 
| -
 | 
| -TraceLog.prototype = {
 | 
| -    /**
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    size: function()
 | 
| -    {
 | 
| -        return this._replayableCalls.length;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!Array.<!ReplayableCall>}
 | 
| -     */
 | 
| -    replayableCalls: function()
 | 
| -    {
 | 
| -        return this._replayableCalls;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} id
 | 
| -     * @return {!ReplayableResource|undefined}
 | 
| -     */
 | 
| -    replayableResource: function(id)
 | 
| -    {
 | 
| -        return this._replayablesCache.get(id);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} resourceId
 | 
| -     * @return {boolean}
 | 
| -     */
 | 
| -    createdInThisTraceLog: function(resourceId)
 | 
| -    {
 | 
| -        return !!this._resourcesCreatedInThisTraceLog[resourceId];
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Resource} resource
 | 
| -     */
 | 
| -    captureResource: function(resource)
 | 
| -    {
 | 
| -        resource.toReplayable(this._replayablesCache);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    addCall: function(call)
 | 
| -    {
 | 
| -        var resource = Resource.forObject(call.result());
 | 
| -        if (resource && !this._replayablesCache.has(resource.id()))
 | 
| -            this._resourcesCreatedInThisTraceLog[resource.id()] = true;
 | 
| -        this._replayableCalls.push(call.toReplayable(this._replayablesCache));
 | 
| -    },
 | 
| -
 | 
| -    addFrameEndMark: function()
 | 
| -    {
 | 
| -        var index = this._replayableCalls.length - 1;
 | 
| -        if (index >= 0)
 | 
| -            this._frameEndCallIndexes[index] = true;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} index
 | 
| -     * @return {boolean}
 | 
| -     */
 | 
| -    isFrameEndCallAt: function(index)
 | 
| -    {
 | 
| -        return !!this._frameEndCallIndexes[index];
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @param {!TraceLog} traceLog
 | 
| - */
 | 
| -function TraceLogPlayer(traceLog)
 | 
| -{
 | 
| -    /** @type {!TraceLog} */
 | 
| -    this._traceLog = traceLog;
 | 
| -    /** @type {number} */
 | 
| -    this._nextReplayStep = 0;
 | 
| -    /** @type {!Cache.<!Resource>} */
 | 
| -    this._replayWorldCache = new Cache();
 | 
| -}
 | 
| -
 | 
| -TraceLogPlayer.prototype = {
 | 
| -    /**
 | 
| -     * @return {!TraceLog}
 | 
| -     */
 | 
| -    traceLog: function()
 | 
| -    {
 | 
| -        return this._traceLog;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} id
 | 
| -     * @return {!Resource|undefined}
 | 
| -     */
 | 
| -    replayWorldResource: function(id)
 | 
| -    {
 | 
| -        return this._replayWorldCache.get(id);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {number}
 | 
| -     */
 | 
| -    nextReplayStep: function()
 | 
| -    {
 | 
| -        return this._nextReplayStep;
 | 
| -    },
 | 
| -
 | 
| -    reset: function()
 | 
| -    {
 | 
| -        this._nextReplayStep = 0;
 | 
| -        this._replayWorldCache.reset();
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} stepNum
 | 
| -     * @return {{replayTime:number, lastCall:(!Call)}}
 | 
| -     */
 | 
| -    stepTo: function(stepNum)
 | 
| -    {
 | 
| -        stepNum = Math.min(stepNum, this._traceLog.size() - 1);
 | 
| -        console.assert(stepNum >= 0);
 | 
| -        if (this._nextReplayStep > stepNum)
 | 
| -            this.reset();
 | 
| -
 | 
| -        // Replay the calls' arguments first to warm-up, before measuring the actual replay time.
 | 
| -        this._replayCallArguments(stepNum);
 | 
| -
 | 
| -        var replayableCalls = this._traceLog.replayableCalls();
 | 
| -        var replayedCalls = [];
 | 
| -        replayedCalls.length = stepNum - this._nextReplayStep + 1;
 | 
| -
 | 
| -        var beforeTime = TypeUtils.now();
 | 
| -        for (var i = 0; this._nextReplayStep <= stepNum; ++this._nextReplayStep, ++i)
 | 
| -            replayedCalls[i] = replayableCalls[this._nextReplayStep].replay(this._replayWorldCache);
 | 
| -        var replayTime = Math.max(0, TypeUtils.now() - beforeTime);
 | 
| -
 | 
| -        for (var i = 0, call; call = replayedCalls[i]; ++i)
 | 
| -            call.resource().onCallReplayed(call);
 | 
| -
 | 
| -        return {
 | 
| -            replayTime: replayTime,
 | 
| -            lastCall: replayedCalls[replayedCalls.length - 1]
 | 
| -        };
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} stepNum
 | 
| -     */
 | 
| -    _replayCallArguments: function(stepNum)
 | 
| -    {
 | 
| -        /**
 | 
| -         * @param {*} obj
 | 
| -         * @this {TraceLogPlayer}
 | 
| -         */
 | 
| -        function replayIfNotCreatedInThisTraceLog(obj)
 | 
| -        {
 | 
| -            if (!(obj instanceof ReplayableResource))
 | 
| -                return;
 | 
| -            var replayableResource = /** @type {!ReplayableResource} */ (obj);
 | 
| -            if (!this._traceLog.createdInThisTraceLog(replayableResource.id()))
 | 
| -                replayableResource.replay(this._replayWorldCache)
 | 
| -        }
 | 
| -        var replayableCalls = this._traceLog.replayableCalls();
 | 
| -        for (var i = this._nextReplayStep; i <= stepNum; ++i) {
 | 
| -            replayIfNotCreatedInThisTraceLog.call(this, replayableCalls[i].replayableResource());
 | 
| -            replayIfNotCreatedInThisTraceLog.call(this, replayableCalls[i].result());
 | 
| -            replayableCalls[i].args().forEach(replayIfNotCreatedInThisTraceLog.bind(this));
 | 
| -        }
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - */
 | 
| -function ResourceTrackingManager()
 | 
| -{
 | 
| -    this._capturing = false;
 | 
| -    this._stopCapturingOnFrameEnd = false;
 | 
| -    this._lastTraceLog = null;
 | 
| -}
 | 
| -
 | 
| -ResourceTrackingManager.prototype = {
 | 
| -    /**
 | 
| -     * @return {boolean}
 | 
| -     */
 | 
| -    capturing: function()
 | 
| -    {
 | 
| -        return this._capturing;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {?TraceLog}
 | 
| -     */
 | 
| -    lastTraceLog: function()
 | 
| -    {
 | 
| -        return this._lastTraceLog;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Resource} resource
 | 
| -     */
 | 
| -    registerResource: function(resource)
 | 
| -    {
 | 
| -        resource.setManager(this);
 | 
| -    },
 | 
| -
 | 
| -    startCapturing: function()
 | 
| -    {
 | 
| -        if (!this._capturing)
 | 
| -            this._lastTraceLog = new TraceLog();
 | 
| -        this._capturing = true;
 | 
| -        this._stopCapturingOnFrameEnd = false;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!TraceLog=} traceLog
 | 
| -     */
 | 
| -    stopCapturing: function(traceLog)
 | 
| -    {
 | 
| -        if (traceLog && this._lastTraceLog !== traceLog)
 | 
| -            return;
 | 
| -        this._capturing = false;
 | 
| -        this._stopCapturingOnFrameEnd = false;
 | 
| -        if (this._lastTraceLog)
 | 
| -            this._lastTraceLog.addFrameEndMark();
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!TraceLog} traceLog
 | 
| -     */
 | 
| -    dropTraceLog: function(traceLog)
 | 
| -    {
 | 
| -        this.stopCapturing(traceLog);
 | 
| -        if (this._lastTraceLog === traceLog)
 | 
| -            this._lastTraceLog = null;
 | 
| -    },
 | 
| -
 | 
| -    captureFrame: function()
 | 
| -    {
 | 
| -        this._lastTraceLog = new TraceLog();
 | 
| -        this._capturing = true;
 | 
| -        this._stopCapturingOnFrameEnd = true;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Resource} resource
 | 
| -     * @param {!Array|!Arguments} args
 | 
| -     */
 | 
| -    captureArguments: function(resource, args)
 | 
| -    {
 | 
| -        if (!this._capturing)
 | 
| -            return;
 | 
| -        this._lastTraceLog.captureResource(resource);
 | 
| -        for (var i = 0, n = args.length; i < n; ++i) {
 | 
| -            var res = Resource.forObject(args[i]);
 | 
| -            if (res)
 | 
| -                this._lastTraceLog.captureResource(res);
 | 
| -        }
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!Call} call
 | 
| -     */
 | 
| -    captureCall: function(call)
 | 
| -    {
 | 
| -        if (!this._capturing)
 | 
| -            return;
 | 
| -        this._lastTraceLog.addCall(call);
 | 
| -    },
 | 
| -
 | 
| -    markFrameEnd: function()
 | 
| -    {
 | 
| -        if (!this._lastTraceLog)
 | 
| -            return;
 | 
| -        this._lastTraceLog.addFrameEndMark();
 | 
| -        if (this._stopCapturingOnFrameEnd && this._lastTraceLog.size())
 | 
| -            this.stopCapturing(this._lastTraceLog);
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - */
 | 
| -var InjectedCanvasModule = function()
 | 
| -{
 | 
| -    /** @type {!ResourceTrackingManager} */
 | 
| -    this._manager = new ResourceTrackingManager();
 | 
| -    /** @type {number} */
 | 
| -    this._lastTraceLogId = 0;
 | 
| -    /** @type {!Object.<string, !TraceLog>} */
 | 
| -    this._traceLogs = {};
 | 
| -    /** @type {!Object.<string, !TraceLogPlayer>} */
 | 
| -    this._traceLogPlayers = {};
 | 
| -}
 | 
| -
 | 
| -InjectedCanvasModule.prototype = {
 | 
| -    /**
 | 
| -     * @param {!WebGLRenderingContext} glContext
 | 
| -     * @return {!Object}
 | 
| -     */
 | 
| -    wrapWebGLContext: function(glContext)
 | 
| -    {
 | 
| -        var resource = Resource.forObject(glContext) || new WebGLRenderingContextResource(glContext);
 | 
| -        this._manager.registerResource(resource);
 | 
| -        return resource.proxyObject();
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!CanvasRenderingContext2D} context
 | 
| -     * @return {!Object}
 | 
| -     */
 | 
| -    wrapCanvas2DContext: function(context)
 | 
| -    {
 | 
| -        var resource = Resource.forObject(context) || new CanvasRenderingContext2DResource(context);
 | 
| -        this._manager.registerResource(resource);
 | 
| -        return resource.proxyObject();
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!CanvasAgent.TraceLogId}
 | 
| -     */
 | 
| -    captureFrame: function()
 | 
| -    {
 | 
| -        return this._callStartCapturingFunction(this._manager.captureFrame);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!CanvasAgent.TraceLogId}
 | 
| -     */
 | 
| -    startCapturing: function()
 | 
| -    {
 | 
| -        return this._callStartCapturingFunction(this._manager.startCapturing);
 | 
| -    },
 | 
| -
 | 
| -    markFrameEnd: function()
 | 
| -    {
 | 
| -        this._manager.markFrameEnd();
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {function(this:ResourceTrackingManager)} func
 | 
| -     * @return {!CanvasAgent.TraceLogId}
 | 
| -     */
 | 
| -    _callStartCapturingFunction: function(func)
 | 
| -    {
 | 
| -        var oldTraceLog = this._manager.lastTraceLog();
 | 
| -        func.call(this._manager);
 | 
| -        var traceLog = /** @type {!TraceLog} */ (this._manager.lastTraceLog());
 | 
| -        if (traceLog === oldTraceLog) {
 | 
| -            for (var id in this._traceLogs) {
 | 
| -                if (this._traceLogs[id] === traceLog)
 | 
| -                    return id;
 | 
| -            }
 | 
| -        }
 | 
| -        var id = this._makeTraceLogId();
 | 
| -        this._traceLogs[id] = traceLog;
 | 
| -        return id;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!CanvasAgent.TraceLogId} id
 | 
| -     */
 | 
| -    stopCapturing: function(id)
 | 
| -    {
 | 
| -        var traceLog = this._traceLogs[id];
 | 
| -        if (traceLog)
 | 
| -            this._manager.stopCapturing(traceLog);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!CanvasAgent.TraceLogId} id
 | 
| -     */
 | 
| -    dropTraceLog: function(id)
 | 
| -    {
 | 
| -        var traceLog = this._traceLogs[id];
 | 
| -        if (traceLog)
 | 
| -            this._manager.dropTraceLog(traceLog);
 | 
| -        delete this._traceLogs[id];
 | 
| -        delete this._traceLogPlayers[id];
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!CanvasAgent.TraceLogId} id
 | 
| -     * @param {number=} startOffset
 | 
| -     * @param {number=} maxLength
 | 
| -     * @return {!CanvasAgent.TraceLog|string}
 | 
| -     */
 | 
| -    traceLog: function(id, startOffset, maxLength)
 | 
| -    {
 | 
| -        var traceLog = this._traceLogs[id];
 | 
| -        if (!traceLog)
 | 
| -            return "Error: Trace log with the given ID not found.";
 | 
| -
 | 
| -        // Ensure last call ends a frame.
 | 
| -        traceLog.addFrameEndMark();
 | 
| -
 | 
| -        var replayableCalls = traceLog.replayableCalls();
 | 
| -        if (typeof startOffset !== "number")
 | 
| -            startOffset = 0;
 | 
| -        if (typeof maxLength !== "number")
 | 
| -            maxLength = replayableCalls.length;
 | 
| -
 | 
| -        var fromIndex = Math.max(0, startOffset);
 | 
| -        var toIndex = Math.min(replayableCalls.length - 1, fromIndex + maxLength - 1);
 | 
| -
 | 
| -        var alive = this._manager.capturing() && this._manager.lastTraceLog() === traceLog;
 | 
| -        var result = {
 | 
| -            id: id,
 | 
| -            /** @type {!Array.<!CanvasAgent.Call>} */
 | 
| -            calls: [],
 | 
| -            /** @type {!Array.<!CanvasAgent.CallArgument>} */
 | 
| -            contexts: [],
 | 
| -            alive: alive,
 | 
| -            startOffset: fromIndex,
 | 
| -            totalAvailableCalls: replayableCalls.length
 | 
| -        };
 | 
| -        /** @type {!Object.<string, boolean>} */
 | 
| -        var contextIds = {};
 | 
| -        for (var i = fromIndex; i <= toIndex; ++i) {
 | 
| -            var call = replayableCalls[i];
 | 
| -            var resource = call.replayableResource();
 | 
| -            var contextResource = resource.contextResource();
 | 
| -            var stackTrace = call.stackTrace();
 | 
| -            var callFrame = stackTrace ? stackTrace.callFrame(0) || {} : {};
 | 
| -            var item = CallFormatter.forResource(resource).formatCall(call);
 | 
| -            item.contextId = CallFormatter.makeStringResourceId(contextResource.id());
 | 
| -            item.sourceURL = callFrame.sourceURL;
 | 
| -            item.lineNumber = callFrame.lineNumber;
 | 
| -            item.columnNumber = callFrame.columnNumber;
 | 
| -            item.isFrameEndCall = traceLog.isFrameEndCallAt(i);
 | 
| -            result.calls.push(item);
 | 
| -            if (!contextIds[item.contextId]) {
 | 
| -                contextIds[item.contextId] = true;
 | 
| -                result.contexts.push(CallFormatter.forResource(resource).formatValue(contextResource));
 | 
| -            }
 | 
| -        }
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!CanvasAgent.TraceLogId} traceLogId
 | 
| -     * @param {number} stepNo
 | 
| -     * @return {{resourceState: !CanvasAgent.ResourceState, replayTime: number}|string}
 | 
| -     */
 | 
| -    replayTraceLog: function(traceLogId, stepNo)
 | 
| -    {
 | 
| -        var traceLog = this._traceLogs[traceLogId];
 | 
| -        if (!traceLog)
 | 
| -            return "Error: Trace log with the given ID not found.";
 | 
| -        this._traceLogPlayers[traceLogId] = this._traceLogPlayers[traceLogId] || new TraceLogPlayer(traceLog);
 | 
| -
 | 
| -        var replayResult = this._traceLogPlayers[traceLogId].stepTo(stepNo);
 | 
| -        var resource = replayResult.lastCall.resource();
 | 
| -        var dataURL = resource.toDataURL();
 | 
| -        if (!dataURL) {
 | 
| -            resource = resource.contextResource();
 | 
| -            dataURL = resource.toDataURL();
 | 
| -        }
 | 
| -        return {
 | 
| -            resourceState: this._makeResourceState(resource.id(), traceLogId, resource, dataURL),
 | 
| -            replayTime: replayResult.replayTime
 | 
| -        };
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!CanvasAgent.TraceLogId} traceLogId
 | 
| -     * @param {!CanvasAgent.ResourceId} stringResourceId
 | 
| -     * @return {!CanvasAgent.ResourceState|string}
 | 
| -     */
 | 
| -    resourceState: function(traceLogId, stringResourceId)
 | 
| -    {
 | 
| -        var traceLog = this._traceLogs[traceLogId];
 | 
| -        if (!traceLog)
 | 
| -            return "Error: Trace log with the given ID not found.";
 | 
| -
 | 
| -        var parsedStringId1 = this._parseStringId(traceLogId);
 | 
| -        var parsedStringId2 = this._parseStringId(stringResourceId);
 | 
| -        if (parsedStringId1.injectedScriptId !== parsedStringId2.injectedScriptId)
 | 
| -            return "Error: Both IDs must point to the same injected script.";
 | 
| -
 | 
| -        var resourceId = parsedStringId2.resourceId;
 | 
| -        if (!resourceId)
 | 
| -            return "Error: Wrong resource ID: " + stringResourceId;
 | 
| -
 | 
| -        var traceLogPlayer = this._traceLogPlayers[traceLogId];
 | 
| -        var resource = traceLogPlayer && traceLogPlayer.replayWorldResource(resourceId);
 | 
| -        return this._makeResourceState(resourceId, traceLogId, resource);
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {!CanvasAgent.TraceLogId} traceLogId
 | 
| -     * @param {number} callIndex
 | 
| -     * @param {number} argumentIndex
 | 
| -     * @param {string} objectGroup
 | 
| -     * @return {{result:(!RuntimeAgent.RemoteObject|undefined), resourceState:(!CanvasAgent.ResourceState|undefined)}|string}
 | 
| -     */
 | 
| -    evaluateTraceLogCallArgument: function(traceLogId, callIndex, argumentIndex, objectGroup)
 | 
| -    {
 | 
| -        var traceLog = this._traceLogs[traceLogId];
 | 
| -        if (!traceLog)
 | 
| -            return "Error: Trace log with the given ID not found.";
 | 
| -
 | 
| -        var replayableCall = traceLog.replayableCalls()[callIndex];
 | 
| -        if (!replayableCall)
 | 
| -            return "Error: No call found at index " + callIndex;
 | 
| -
 | 
| -        var value;
 | 
| -        if (replayableCall.isPropertySetter())
 | 
| -            value = replayableCall.propertyValue();
 | 
| -        else if (argumentIndex === -1)
 | 
| -            value = replayableCall.result();
 | 
| -        else {
 | 
| -            var args = replayableCall.args();
 | 
| -            if (argumentIndex < 0 || argumentIndex >= args.length)
 | 
| -                return "Error: No argument found at index " + argumentIndex + " for call at index " + callIndex;
 | 
| -            value = args[argumentIndex];
 | 
| -        }
 | 
| -
 | 
| -        if (value instanceof ReplayableResource) {
 | 
| -            var traceLogPlayer = this._traceLogPlayers[traceLogId];
 | 
| -            var resource = traceLogPlayer && traceLogPlayer.replayWorldResource(value.id());
 | 
| -            var resourceState = this._makeResourceState(value.id(), traceLogId, resource);
 | 
| -            return { resourceState: resourceState };
 | 
| -        }
 | 
| -
 | 
| -        var remoteObject = injectedScript.wrapObjectForModule(value, objectGroup);
 | 
| -        return { result: remoteObject };
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @return {!CanvasAgent.TraceLogId}
 | 
| -     */
 | 
| -    _makeTraceLogId: function()
 | 
| -    {
 | 
| -        return "{\"injectedScriptId\":" + injectedScriptId + ",\"traceLogId\":" + (++this._lastTraceLogId) + "}";
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {number} resourceId
 | 
| -     * @param {!CanvasAgent.TraceLogId} traceLogId
 | 
| -     * @param {?Resource=} resource
 | 
| -     * @param {string=} overrideImageURL
 | 
| -     * @return {!CanvasAgent.ResourceState}
 | 
| -     */
 | 
| -    _makeResourceState: function(resourceId, traceLogId, resource, overrideImageURL)
 | 
| -    {
 | 
| -        var result = {
 | 
| -            id: CallFormatter.makeStringResourceId(resourceId),
 | 
| -            traceLogId: traceLogId
 | 
| -        };
 | 
| -        if (resource) {
 | 
| -            result.imageURL = overrideImageURL || resource.toDataURL();
 | 
| -            result.descriptors = CallFormatter.forResource(resource).formatResourceStateDescriptors(resource.currentState(), traceLogId);
 | 
| -        }
 | 
| -        return result;
 | 
| -    },
 | 
| -
 | 
| -    /**
 | 
| -     * @param {string} stringId
 | 
| -     * @return {{injectedScriptId: number, traceLogId: ?number, resourceId: ?number}}
 | 
| -     */
 | 
| -    _parseStringId: function(stringId)
 | 
| -    {
 | 
| -        return /** @type {?} */ (InjectedScriptHost.eval("(" + stringId + ")"));
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -var injectedCanvasModule = new InjectedCanvasModule();
 | 
| -return injectedCanvasModule;
 | 
| -
 | 
| -})
 | 
| 
 |