blob: 4484b698c5fafeac8f02c443836f59b0217d07c7 [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @param {InjectedScriptHost} InjectedScriptHost
*/
(function (InjectedScriptHost, inspectedWindow, injectedScriptId) {
/**
* @constructor
*/
var InjectedScript = function()
{
this._lastBoundObjectId = 0;
this._idToWrapperProxy = {};
this._idToRealWebGLContext = {};
this._capturingFrameInfo = null;
}
InjectedScript.prototype = {
wrapWebGLContext: function(glContext)
{
for (var id in this._idToRealWebGLContext) {
if (this._idToRealWebGLContext[id] === glContext)
return this._idToWrapperProxy[id];
}
var proxy = {};
var nameProcessed = {};
nameProcessed.__proto__ = null;
nameProcessed.constructor = true;
function processName(name) {
if (nameProcessed[name])
return;
nameProcessed[name] = true;
if (typeof glContext[name] === "function")
proxy[name] = injectedScript._wrappedFunction.bind(injectedScript, glContext, name);
else
Object.defineProperty(proxy, name, {
get: function()
{
return glContext[name];
},
set: function(value)
{
glContext[name] = value;
}
});
}
for (var o = glContext; o; o = o.__proto__)
Object.getOwnPropertyNames(o).forEach(processName);
// In order to emulate "instanceof".
proxy.__proto__ = glContext.__proto__;
proxy.constructor = glContext.constructor;
var contextId = this._generateObjectId();
this._idToWrapperProxy[contextId] = proxy;
this._idToRealWebGLContext[contextId] = glContext;
InjectedScriptHost.webGLContextCreated(contextId);
return proxy;
},
_generateObjectId: function()
{
var id = ++this._lastBoundObjectId;
var objectId = "{\"injectedScriptId\":" + injectedScriptId + ",\"webGLId\":" + id + "}";
return objectId;
},
captureFrame: function(contextId)
{
this._capturingFrameInfo = {
contextId: contextId,
capturedCallsNum: 0
};
},
_stopCapturing: function(info)
{
if (this._capturingFrameInfo === info)
this._capturingFrameInfo = null;
},
_wrappedFunction: function(glContext, functionName)
{
// Call real WebGL function.
var args = Array.prototype.slice.call(arguments, 2);
var result = glContext[functionName].apply(glContext, args);
if (this._capturingFrameInfo && this._idToRealWebGLContext[this._capturingFrameInfo.contextId] === glContext) {
var capturedCallsNum = ++this._capturingFrameInfo.capturedCallsNum;
if (capturedCallsNum === 1)
this._setZeroTimeouts(this._stopCapturing.bind(this, this._capturingFrameInfo));
InjectedScriptHost.webGLReportFunctionCall(this._capturingFrameInfo.contextId, functionName, "[" + args.join(", ") + "]", result + "");
}
return result;
},
_setZeroTimeouts: function(callback)
{
// We need a fastest async callback, whatever fires first.
// Usually a postMessage should be faster than a setTimeout(0).
var channel = new MessageChannel();
channel.port1.onmessage = callback;
channel.port2.postMessage("");
inspectedWindow.setTimeout(callback, 0);
}
};
var injectedScript = new InjectedScript();
return injectedScript;
})