Bug 689920 - Integrate Tilt with existing Firefox developer tools; r=cedric,msucan,rcampbell

This commit is contained in:
Victor Porof 2011-11-10 12:09:18 +02:00
parent aa57690f35
commit 3cca7b2af8
48 changed files with 9667 additions and 0 deletions

View File

@ -1013,6 +1013,12 @@ pref("devtools.inspector.htmlHeight", 112);
// Enable the style inspector
pref("devtools.styleinspector.enabled", true);
// Enable the Tilt inspector
pref("devtools.tilt.enabled", true);
// Enable the Tilt inspector even if WebGL capabilities are not detected
pref("devtools.tilt.force-enabled", false);
// Enable the rules view
pref("devtools.ruleview.enabled", true);

View File

@ -148,6 +148,8 @@
oncommand="InspectorUI.toggleInspection();"/>
<command id="Inspector:Sidebar"
oncommand="InspectorUI.toggleSidebar();"/>
<command id="Inspector:Tilt"
oncommand="Tilt.initialize();"/>
</commandset>
<broadcasterset id="mainBroadcasterSet">

View File

@ -55,6 +55,7 @@
# David Dahl <ddahl@mozilla.com>
# Patrick Walton <pcwalton@mozilla.com>
# Mihai Sucan <mihai.sucan@gmail.com>
# Victor Porof <vporof@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -179,6 +180,12 @@ XPCOMUtils.defineLazyGetter(this, "InspectorUI", function() {
return new tmp.InspectorUI(window);
});
XPCOMUtils.defineLazyGetter(this, "Tilt", function() {
let tmp = {};
Cu.import("resource:///modules/devtools/Tilt.jsm", tmp);
return new tmp.Tilt(window);
});
let gInitialPages = [
"about:blank",
"about:privatebrowsing",

View File

@ -37,6 +37,7 @@
# Patrick Walton <pcwalton@mozilla.com>
# David Dahl <ddahl@mozilla.com>
# Frank Yan <fyan@mozilla.com>
# Victor Porof <vporof@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -1007,6 +1008,11 @@
flex="1" orient="horizontal"
clicktoscroll="true"/>
<hbox id="inspector-tools">
<toolbarbutton id="inspector-3D-button"
hidden="true"
label="&inspect3DButton.label;"
accesskey="&inspect3DButton.accesskey;"
command="Inspector:Tilt"/>
<toolbarbutton id="inspector-style-button"
label="&inspectStyleButton.label;"
accesskey="&inspectStyleButton.accesskey;"

View File

@ -52,6 +52,7 @@ DIRS = \
sourceeditor \
styleeditor \
styleinspector \
tilt \
scratchpad \
shared \
$(NULL)

View File

@ -928,6 +928,7 @@ InspectorUI.prototype = {
this.chromeDoc.getElementById("inspector-inspect-toolbutton");
this.initTools();
this.chromeWin.Tilt.setup();
if (this.treePanelEnabled) {
this.treePanel = new TreePanel(this.chromeWin, this);
@ -1190,6 +1191,7 @@ InspectorUI.prototype = {
}
this.breadcrumbs.update();
this.chromeWin.Tilt.update(aNode);
this.toolsSelect(aScroll);
},

View File

@ -0,0 +1,53 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Victor Porof <vporof@mozilla.com> (original author)
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ifdef ENABLE_TESTS
DIRS += test
endif
include $(topsrcdir)/config/rules.mk
libs::
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
$(NSINSTALL) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools

View File

@ -0,0 +1,313 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Tilt: A WebGL-based 3D visualization of a webpage.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Victor Porof <vporof@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the LGPL or the GPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
***** END LICENSE BLOCK *****/
/*global Components, Services, TiltGL, TiltUtils, TiltVisualizer */
"use strict";
const Cu = Components.utils;
// Tilt notifications dispatched through the nsIObserverService.
const TILT_NOTIFICATIONS = {
// Fires when Tilt completes the initialization.
INITIALIZED: "tilt-initialized",
// Fires when Tilt is destroyed.
DESTROYED: "tilt-destroyed",
// Fires when Tilt is shown (after a tab-switch).
SHOWN: "tilt-shown",
// Fires when Tilt is hidden (after a tab-switch).
HIDDEN: "tilt-hidden"
};
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/devtools/TiltGL.jsm");
Cu.import("resource:///modules/devtools/TiltUtils.jsm");
Cu.import("resource:///modules/devtools/TiltVisualizer.jsm");
let EXPORTED_SYMBOLS = ["Tilt"];
/**
* Object managing instances of the visualizer.
*
* @param {Window} aWindow
* the chrome window used by each visualizer instance
*/
function Tilt(aWindow)
{
/**
* Save a reference to the top-level window.
*/
this.chromeWindow = aWindow;
/**
* All the instances of TiltVisualizer.
*/
this.visualizers = {};
/**
* Shortcut for accessing notifications strings.
*/
this.NOTIFICATIONS = TILT_NOTIFICATIONS;
}
Tilt.prototype = {
/**
* Initializes a visualizer for the current tab.
*/
initialize: function T_initialize()
{
let id = this.currentWindowId;
// if the visualizer for the current tab is already open, destroy it now
if (this.visualizers[id]) {
this.destroy(id);
return;
}
// create a visualizer instance for the current tab
this.visualizers[id] = new TiltVisualizer({
parentNode: this.chromeWindow.gBrowser.selectedBrowser.parentNode,
contentWindow: this.chromeWindow.gBrowser.selectedBrowser.contentWindow,
requestAnimationFrame: this.chromeWindow.mozRequestAnimationFrame,
inspectorUI: this.chromeWindow.InspectorUI
});
// make sure the visualizer object was initialized properly
if (!this.visualizers[id].isInitialized()) {
this.destroy(id);
return;
}
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.INITIALIZED, null);
},
/**
* Destroys a specific instance of the visualizer.
*
* @param {String} aId
* the identifier of the instance in the visualizers array
*/
destroy: function T_destroy(aId)
{
// if the visualizer is already destroyed, don't do anything
if (!this.visualizers[aId]) {
return;
}
this.visualizers[aId].removeOverlay();
this.visualizers[aId].cleanup();
this.visualizers[aId] = null;
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.DESTROYED, null);
},
/**
* Handles any supplementary post-initialization work, done immediately
* after a TILT_NOTIFICATIONS.INITIALIZED notification.
*/
_whenInitialized: function T__whenInitialized()
{
this._whenShown();
},
/**
* Handles any supplementary post-destruction work, done immediately
* after a TILT_NOTIFICATIONS.DESTROYED notification.
*/
_whenDestroyed: function T__whenDestroyed()
{
this._whenHidden();
},
/**
* Handles any necessary changes done when the Tilt surface is shown,
* after a TILT_NOTIFICATIONS.SHOWN notification.
*/
_whenShown: function T__whenShown()
{
this.tiltButton.checked = true;
},
/**
* Handles any necessary changes done when the Tilt surface is hidden,
* after a TILT_NOTIFICATIONS.HIDDEN notification.
*/
_whenHidden: function T__whenHidden()
{
this.tiltButton.checked = false;
},
/**
* Handles the event fired when a tab is selected.
*/
_onTabSelect: function T__onTabSelect()
{
if (this.visualizers[this.currentWindowId]) {
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.SHOWN, null);
} else {
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.HIDDEN, null);
}
},
/**
* A node was selected in the Inspector.
* Called from InspectorUI.
*
* @param {Element} aNode
* the newly selected node
*/
update: function T_update(aNode) {
let id = this.currentWindowId;
if (this.visualizers[id]) {
this.visualizers[id].presenter.highlightNode(aNode);
}
},
/**
* Add the browser event listeners to handle state changes.
* Called from InspectorUI.
*/
setup: function T_setup()
{
if (this._setupFinished) {
return;
}
// load the preferences from the devtools.tilt branch
TiltVisualizer.Prefs.load();
// hide the button in the Inspector toolbar if Tilt is not enabled
this.tiltButton.hidden = !this.enabled;
// add the necessary observers to handle specific notifications
Services.obs.addObserver(
this._whenInitialized.bind(this), TILT_NOTIFICATIONS.INITIALIZED, false);
Services.obs.addObserver(
this._whenDestroyed.bind(this), TILT_NOTIFICATIONS.DESTROYED, false);
Services.obs.addObserver(
this._whenShown.bind(this), TILT_NOTIFICATIONS.SHOWN, false);
Services.obs.addObserver(
this._whenHidden.bind(this), TILT_NOTIFICATIONS.HIDDEN, false);
Services.obs.addObserver(function(aSubject, aTopic, aWinId) {
this.destroy(aWinId); }.bind(this),
this.chromeWindow.InspectorUI.INSPECTOR_NOTIFICATIONS.DESTROYED, false);
this.chromeWindow.gBrowser.tabContainer.addEventListener("TabSelect",
this._onTabSelect.bind(this), false);
// FIXME: this shouldn't be done here, see bug #705131
let onOpened = function() {
if (this.visualizers[this.currentWindowId]) {
this.chromeWindow.InspectorUI.stopInspecting();
this.inspectButton.disabled = true;
this.highlighterContainer.style.display = "none";
}
}.bind(this);
let onClosed = function() {
this.inspectButton.disabled = false;
this.highlighterContainer.style.display = "";
}.bind(this);
Services.obs.addObserver(onOpened,
this.chromeWindow.InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(onClosed,
this.chromeWindow.InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
Services.obs.addObserver(onOpened,
TILT_NOTIFICATIONS.INITIALIZED, false);
Services.obs.addObserver(onClosed,
TILT_NOTIFICATIONS.DESTROYED, false);
this._setupFinished = true;
},
/**
* Returns true if this tool is enabled.
*/
get enabled()
{
return (TiltVisualizer.Prefs.enabled &&
(TiltVisualizer.Prefs.forceEnabled || TiltGL.isWebGLSupported()));
},
/**
* Gets the ID of the current window object to identify the visualizer.
*/
get currentWindowId()
{
let gBrowser = this.chromeWindow.gBrowser;
return TiltUtils.getWindowId(gBrowser.selectedBrowser.contentWindow);
},
/**
* Gets the Tilt button in the Inspector toolbar.
*/
get tiltButton()
{
return this.chromeWindow.document.getElementById(
"inspector-3D-button");
},
/**
* Gets the Inspect button in the Inspector toolbar.
* FIXME: this shouldn't be needed here, remove after bug #705131
*/
get inspectButton()
{
return this.chromeWindow.document.getElementById(
"inspector-inspect-toolbutton");
},
/**
* Gets the Highlighter contaniner stack.
* FIXME: this shouldn't be needed here, remove after bug #705131
*/
get highlighterContainer()
{
return this.chromeWindow.document.getElementById(
"highlighter-container");
}
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,685 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Tilt: A WebGL-based 3D visualization of a webpage.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Victor Porof <vporof@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the LGPL or the GPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
***** END LICENSE BLOCK *****/
/*global Components, Services, XPCOMUtils */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
let EXPORTED_SYMBOLS = ["TiltUtils"];
/**
* Module containing various helper functions used throughout Tilt.
*/
let TiltUtils = {};
/**
* Various console/prompt output functions required by the engine.
*/
TiltUtils.Output = {
/**
* Logs a message to the console.
*
* @param {String} aMessage
* the message to be logged
*/
log: function TUO_log(aMessage)
{
// get the console service
let consoleService = Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
// log the message
consoleService.logStringMessage(aMessage);
},
/**
* Logs an error to the console.
*
* @param {String} aMessage
* the message to be logged
* @param {Object} aProperties
* and object containing script error initialization details
*/
error: function TUO_error(aMessage, aProperties)
{
// make sure the properties parameter is a valid object
aProperties = aProperties || {};
// get the console service
let consoleService = Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
// get the script error service
let scriptError = Cc["@mozilla.org/scripterror;1"]
.createInstance(Ci.nsIScriptError);
// initialize a script error
scriptError.init(aMessage,
aProperties.sourceName || "",
aProperties.sourceLine || "",
aProperties.lineNumber || 0,
aProperties.columnNumber || 0,
aProperties.flags || 0,
aProperties.category || "");
// log the error
consoleService.logMessage(scriptError);
},
/**
* Shows a modal alert message popup.
*
* @param {String} aTitle
* the title of the popup
* @param {String} aMessage
* the message to be logged
*/
alert: function TUO_alert(aTitle, aMessage)
{
if (!aMessage) {
aMessage = aTitle;
aTitle = "";
}
// get the prompt service
let prompt = Cc["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Ci.nsIPromptService);
// show the alert message
prompt.alert(null, aTitle, aMessage);
}
};
/**
* Helper functions for managing preferences.
*/
TiltUtils.Preferences = {
/**
* Gets a custom Tilt preference.
* If the preference does not exist, undefined is returned. If it does exist,
* but the type is not correctly specified, null is returned.
*
* @param {String} aPref
* the preference name
* @param {String} aType
* either "boolean", "string" or "integer"
*
* @return {Boolean | String | Number} the requested preference
*/
get: function TUP_get(aPref, aType)
{
if (!aPref || !aType) {
return;
}
try {
let prefs = this._branch;
switch(aType) {
case "boolean":
return prefs.getBoolPref(aPref);
case "string":
return prefs.getCharPref(aPref);
case "integer":
return prefs.getIntPref(aPref);
}
return null;
} catch(e) {
// handle any unexpected exceptions
TiltUtils.Output.error(e.message);
return undefined;
}
},
/**
* Sets a custom Tilt preference.
* If the preference already exists, it is overwritten.
*
* @param {String} aPref
* the preference name
* @param {String} aType
* either "boolean", "string" or "integer"
* @param {String} aValue
* a new preference value
*
* @return {Boolean} true if the preference was set successfully
*/
set: function TUP_set(aPref, aType, aValue)
{
if (!aPref || !aType || aValue === undefined || aValue === null) {
return;
}
try {
let prefs = this._branch;
switch(aType) {
case "boolean":
return prefs.setBoolPref(aPref, aValue);
case "string":
return prefs.setCharPref(aPref, aValue);
case "integer":
return prefs.setIntPref(aPref, aValue);
}
} catch(e) {
// handle any unexpected exceptions
TiltUtils.Output.error(e.message);
}
return false;
},
/**
* Creates a custom Tilt preference.
* If the preference already exists, it is left unchanged.
*
* @param {String} aPref
* the preference name
* @param {String} aType
* either "boolean", "string" or "integer"
* @param {String} aValue
* the initial preference value
*
* @return {Boolean} true if the preference was initialized successfully
*/
create: function TUP_create(aPref, aType, aValue)
{
if (!aPref || !aType || aValue === undefined || aValue === null) {
return;
}
try {
let prefs = this._branch;
if (!prefs.prefHasUserValue(aPref)) {
switch(aType) {
case "boolean":
return prefs.setBoolPref(aPref, aValue);
case "string":
return prefs.setCharPref(aPref, aValue);
case "integer":
return prefs.setIntPref(aPref, aValue);
}
}
} catch(e) {
// handle any unexpected exceptions
TiltUtils.Output.error(e.message);
}
return false;
},
/**
* The preferences branch for this extension.
*/
_branch: (function(aBranch) {
return Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService)
.getBranch(aBranch);
}("devtools.tilt."))
};
/**
* Easy way to access the string bundle.
*/
TiltUtils.L10n = {
/**
* The string bundle element.
*/
stringBundle: null,
/**
* Returns a string in the string bundle.
* If the string bundle is not found, null is returned.
*
* @param {String} aName
* the string name in the bundle
*
* @return {String} the equivalent string from the bundle
*/
get: function TUL_get(aName)
{
// check to see if the parent string bundle document element is valid
if (!this.stringBundle || !aName) {
return null;
}
return this.stringBundle.GetStringFromName(aName);
},
/**
* Returns a formatted string using the string bundle.
* If the string bundle is not found, null is returned.
*
* @param {String} aName
* the string name in the bundle
* @param {Array} aArgs
* an array of arguments for the formatted string
*
* @return {String} the equivalent formatted string from the bundle
*/
format: function TUL_format(aName, aArgs)
{
// check to see if the parent string bundle document element is valid
if (!this.stringBundle || !aName || !aArgs) {
return null;
}
return this.stringBundle.formatStringFromName(aName, aArgs, aArgs.length);
}
};
/**
* Utilities for accessing and manipulating a document.
*/
TiltUtils.DOM = {
/**
* Current parent node object used when creating canvas elements.
*/
parentNode: null,
/**
* Helper method, allowing to easily create and manage a canvas element.
* If the width and height params are falsy, they default to the parent node
* client width and height.
*
* @param {Document} aParentNode
* the parent node used to create the canvas
* if not specified, it will be reused from the cache
* @param {Object} aProperties
* optional, object containing some of the following props:
* {Boolean} focusable
* optional, true to make the canvas focusable
* {Boolean} append
* optional, true to append the canvas to the parent node
* {Number} width
* optional, specifies the width of the canvas
* {Number} height
* optional, specifies the height of the canvas
* {String} id
* optional, id for the created canvas element
*
* @return {HTMLCanvasElement} the newly created canvas element
*/
initCanvas: function TUD_initCanvas(aParentNode, aProperties)
{
// check to see if the parent node element is valid
if (!(aParentNode = aParentNode || this.parentNode)) {
return null;
}
// make sure the properties parameter is a valid object
aProperties = aProperties || {};
// cache this parent node so that it can be reused
this.parentNode = aParentNode;
// create the canvas element
let canvas = aParentNode.ownerDocument.
createElementNS("http://www.w3.org/1999/xhtml", "canvas");
let width = aProperties.width || aParentNode.clientWidth;
let height = aProperties.height || aParentNode.clientHeight;
let id = aProperties.id || null;
canvas.setAttribute("style", "min-width: 1px; min-height: 1px;");
canvas.setAttribute("width", width);
canvas.setAttribute("height", height);
canvas.setAttribute("id", id);
// the canvas is unfocusable by default, we may require otherwise
if (aProperties.focusable) {
canvas.setAttribute("tabindex", "1");
canvas.style.outline = "none";
}
// append the canvas element to the current parent node, if specified
if (aProperties.append) {
aParentNode.appendChild(canvas);
}
return canvas;
},
/**
* Gets the full webpage dimensions (width and height).
*
* @param {Window} aContentWindow
* the content window holding the document
*
* @return {Object} an object containing the width and height coords
*/
getContentWindowDimensions: function TUD_getContentWindowDimensions(
aContentWindow)
{
return {
width: aContentWindow.innerWidth + aContentWindow.scrollMaxX,
height: aContentWindow.innerHeight + aContentWindow.scrollMaxY
};
},
/**
* Returns the absolute x, y, width and height coordinates of a node, or null
* if the passed node is not an ELEMENT_NODE.
*
* @param {Element} aNode
* the node which coordinates need to be calculated
* @param {Window} aContentWindow
* optional, the window content holding the the document
*
* @return {Object} an object containing the top, left, width, height coords
*/
getNodeCoordinates: function TUD_getNodeCoordinates(aNode, aContentWindow) {
// make sure the contentWindow parameter is a valid object
aContentWindow = aContentWindow || {};
if (aNode.nodeType !== 1) { // Node.ELEMENT_NODE
return null;
}
let rect = {
top: 0,
left: 0,
width: 0,
height: 0
};
// the preferred way of getting the bounding client rectangle
let clientRect = aNode.getBoundingClientRect();
rect.top = clientRect.top + aContentWindow.pageYOffset;
rect.left = clientRect.left + aContentWindow.pageXOffset;
rect.width = clientRect.width;
rect.height = clientRect.height;
// compute the iframe position and its offset if necessary
let frameRect = this.getFrameOffset(
aNode.ownerDocument.defaultView.frameElement, aContentWindow);
if (frameRect) {
rect.top += frameRect.top;
rect.left += frameRect.left;
}
return rect;
},
/**
* Retuns the parent iframe position and its offset (borders and padding),
* or null if the passed frame is not valid.
*
* @param {Element} aNode
* the iframe which offset need to be calculated
* @param {Window} aContentWindow
* optional, the window content holding the the document
*
* @return {Object} an object containing the top and left coords
*/
getFrameOffset: (function() {
let cache = {};
return function TUD_getFrameOffset(aFrame, aContentWindow) {
// make sure the contentWindow parameter is a valid object
aContentWindow = aContentWindow || {};
if (!aFrame) {
return null;
}
let id = TiltUtils.getWindowId(aFrame.contentWindow) + "," +
aContentWindow.pageXOffset || 0 + "," +
aContentWindow.pageYOffset || 0;
// check the cache to see if this iframe offset wasn't calculated already
if (cache[id] !== undefined) {
return cache[id];
}
let offset = {
top: 0,
left: 0
};
// take the parent iframe bounding rect position into account
let frameRect = aFrame.getBoundingClientRect();
offset.top = frameRect.top;
offset.left = frameRect.left;
// compute the iframe content offset (iframe border + padding)
// bug #626359
let style = aFrame.contentWindow.getComputedStyle(aFrame, null);
if (style) {
offset.top +=
parseInt(style.getPropertyValue("padding-top")) +
parseInt(style.getPropertyValue("border-top-width"));
offset.left +=
parseInt(style.getPropertyValue("padding-left")) +
parseInt(style.getPropertyValue("border-left-width"));
}
return (cache[id] = offset);
};
}()),
/**
* Traverses a document object model & calculates useful info for each node.
*
* @param {Window} aContentWindow
* the window content holding the document
* @param {Object} aProperties
* optional, an object containing the following properties:
* {Object} invisibleElements
* elements which should be ignored
* {Number} minSize
* the minimum dimensions needed for a node to be traversed
* {Number} maxX
* the maximum left position of an element
* {Number} maxY
* the maximum top position of an element
*
* @return {Array} list containing nodes depths, coordinates and local names
*/
traverse: function TUD_traverse(aContentWindow, aProperties)
{
// make sure the properties parameter is a valid object
aProperties = aProperties || {};
let aInvisibleElements = aProperties.invisibleElements || {};
let aMinSize = aProperties.minSize || -1;
let aMaxX = aProperties.maxX || Number.MAX_VALUE;
let aMaxY = aProperties.maxY || Number.MAX_VALUE;
let nodes = aContentWindow.document.childNodes;
let store = { info: [], nodes: [] };
let depth = 0;
while (nodes.length) {
let queue = [];
for (let i = 0, len = nodes.length; i < len; i++) {
let node = nodes[i];
// skip some nodes to avoid visualization meshes that are too bloated
let name = node.localName;
if (!name || aInvisibleElements[name]) {
continue;
}
// get the x, y, width and height coordinates of the node
let coord = this.getNodeCoordinates(node, aContentWindow);
if (!coord) {
continue;
}
// the maximum size slices the traversal where needed
if (coord.left > aMaxX || coord.top > aMaxY) {
continue;
}
// use this node only if it actually has visible dimensions
if (coord.width > aMinSize && coord.height > aMinSize) {
// save the necessary details into a list to be returned later
store.info.push({ depth: depth, coord: coord, name: name });
store.nodes.push(node);
}
// prepare the queue array
Array.prototype.push.apply(queue, name === "iframe" ?
node.contentDocument.childNodes :
node.childNodes);
}
nodes = queue;
depth++;
}
return store;
}
};
/**
* Binds a new owner object to the child functions.
* If the new parent is not specified, it will default to the passed scope.
*
* @param {Object} aScope
* the object from which all functions will be rebound
* @param {String} aRegex
* a regular expression to identify certain functions
* @param {Object} aParent
* the new parent for the object's functions
*/
TiltUtils.bindObjectFunc = function TU_bindObjectFunc(aScope, aRegex, aParent)
{
if (!aScope) {
return;
}
for (let i in aScope) {
try {
if ("function" === typeof aScope[i] && (aRegex ? i.match(aRegex) : 1)) {
aScope[i] = aScope[i].bind(aParent || aScope);
}
} catch(e) {
TiltUtils.Output.error(e);
}
}
};
/**
* Destroys an object and deletes all members.
*
* @param {Object} aScope
* the object from which all children will be destroyed
*/
TiltUtils.destroyObject = function TU_destroyObject(aScope)
{
if (!aScope) {
return;
}
// objects in Tilt usually use a function to handle internal destruction
if ("function" === typeof aScope.finalize) {
aScope.finalize();
}
for (let i in aScope) {
if (aScope.hasOwnProperty(i)) {
delete aScope[i];
}
}
};
/**
* Retrieve the unique ID of a window object.
*
* @param {Window} aWindow
* the window to get the ID from
*
* @return {Number} the window ID
*/
TiltUtils.getWindowId = function TU_getWindowId(aWindow)
{
if (!aWindow) {
return;
}
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
};
/**
* Performs a garbage collection.
*/
TiltUtils.gc = function TU_gc()
{
var browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.garbageCollect();
};
/**
* Clears the cache and sets all the variables to null.
*/
TiltUtils.clearCache = function TU_clearCache()
{
TiltUtils.DOM.parentNode = null;
};
// bind the owner object to the necessary functions
TiltUtils.bindObjectFunc(TiltUtils.Output);
TiltUtils.bindObjectFunc(TiltUtils.Preferences);
TiltUtils.bindObjectFunc(TiltUtils.L10n);
TiltUtils.bindObjectFunc(TiltUtils.DOM);
// set the necessary string bundle
XPCOMUtils.defineLazyGetter(TiltUtils.L10n, "stringBundle", function() {
return Services.strings.createBundle(
"chrome://browser/locale/devtools/tilt.properties");
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
/* -*- Mode: javascript, tab-width: 2, indent-tabs-mode: nil, c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"), you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Tilt: A WebGL-based 3D visualization of a webpage.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Victor Porof <vporof@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the LGPL or the GPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
***** END LICENSE BLOCK *****/
/*global Components, TiltMath */
"use strict";
const Cu = Components.utils;
Cu.import("resource:///modules/devtools/TiltMath.jsm");
let EXPORTED_SYMBOLS = ["TiltVisualizerStyle"];
let rgba = TiltMath.hex2rgba;
/**
* Various colors and style settings used throughout Tilt.
*/
let TiltVisualizerStyle = {
canvas: {
background: "-moz-linear-gradient(top, #454545 0%, #000 100%)",
},
nodes: {
highlight: {
defaultFill: rgba("#555"),
defaultStroke: rgba("#000"),
defaultStrokeWeight: 1
},
html: rgba("#8880"),
body: rgba("#fff0"),
h1: rgba("#e667af"),
h2: rgba("#c667af"),
h3: rgba("#a667af"),
h4: rgba("#8667af"),
h5: rgba("#8647af"),
h6: rgba("#8627af"),
div: rgba("#5dc8cd"),
span: rgba("#67e46f"),
table: rgba("#ff0700"),
tr: rgba("#ff4540"),
td: rgba("#ff7673"),
ul: rgba("#4671d5"),
li: rgba("#6c8cd5"),
p: rgba("#aaa"),
a: rgba("#123eab"),
img: rgba("#ffb473"),
iframe: rgba("#85004b")
}
};

View File

@ -0,0 +1,297 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Tilt: A WebGL-based 3D visualization of a webpage.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Victor Porof <vporof@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the LGPL or the GPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
***** END LICENSE BLOCK *****/
/*global self*/
"use strict";
const SIXTEEN_OVER_255 = 16 / 255;
const ONE_OVER_255 = 1 / 255;
/**
* Given the initialization data (thickness, sizes and information about
* each DOM node) this worker sends back the arrays representing
* vertices, texture coords, colors, indices and all the needed data for
* rendering the DOM visualization mesh.
*
* Used in the TiltVisualization.Presenter object.
*/
self.onmessage = function TWC_onMessage(event)
{
let data = event.data;
let thickness = data.thickness;
let style = data.style;
let texWidth = data.texWidth;
let texHeight = data.texHeight;
let nodesInfo = data.nodesInfo;
// create the arrays used to construct the 3D mesh data
let vertices = [];
let texCoord = [];
let color = [];
let stacksIndices = [];
let wireframeIndices = [];
let meshWidth = 0;
let meshHeight = 0;
// seed the random function to get the same values each time
// we're doing this to avoid ugly z-fighting with overlapping nodes
self.random.seed(0);
// go through all the dom nodes and compute the verts, texcoord etc.
for (let n = 0, i = 0, len = nodesInfo.length; n < len; n++) {
let info = nodesInfo[n];
let depth = info.depth;
let coord = info.coord;
// calculate the stack x, y, z, width and height coordinates
let z = depth * thickness;
let y = coord.top;
let x = coord.left;
let w = coord.width;
let h = coord.height;
// the maximum texture size slices the visualization mesh where needed
if (x + w > texWidth) {
w = texWidth - x;
}
if (y + h > texHeight) {
h = texHeight - y;
}
x += self.random.next();
y += self.random.next();
w -= self.random.next() * 0.1;
h -= self.random.next() * 0.1;
let xpw = x + w;
let yph = y + h;
let zmt = z - thickness;
let xotw = x / texWidth;
let yoth = y / texHeight;
let xpwotw = xpw / texWidth;
let yphoth = yph / texHeight;
// calculate the margin fill color
let fill = style[info.name] || style.highlight.defaultFill;
let r = fill[0];
let g = fill[1];
let b = fill[2];
let g10 = r * 1.1;
let g11 = g * 1.1;
let g12 = b * 1.1;
let g20 = r * 0.6;
let g21 = g * 0.6;
let g22 = b * 0.6;
// compute the vertices
vertices.push(x, y, z, /* front */ // 0
x, yph, z, // 1
xpw, yph, z, // 2
xpw, y, z, // 3
// we don't duplicate vertices for the left and right faces, because
// they can be reused from the bottom and top faces; we do, however,
// duplicate some vertices from front face, because it has custom
// texture coordinates which are not shared by the other faces
x, y, z, /* front */ // 4
x, yph, z, // 5
xpw, yph, z, // 6
xpw, y, z, // 7
x, y, zmt, /* back */ // 8
x, yph, zmt, // 9
xpw, yph, zmt, // 10
xpw, y, zmt); // 11
// compute the texture coordinates
texCoord.push(xotw, yoth,
xotw, yphoth,
xpwotw, yphoth,
xpwotw, yoth,
-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0);
// compute the colors for each vertex in the mesh
color.push(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
g10, g11, g12,
g10, g11, g12,
g10, g11, g12,
g10, g11, g12,
g20, g21, g22,
g20, g21, g22,
g20, g21, g22,
g20, g21, g22);
let ip1 = i + 1;
let ip2 = ip1 + 1;
let ip3 = ip2 + 1;
let ip4 = ip3 + 1;
let ip5 = ip4 + 1;
let ip6 = ip5 + 1;
let ip7 = ip6 + 1;
let ip8 = ip7 + 1;
let ip9 = ip8 + 1;
let ip10 = ip9 + 1;
let ip11 = ip10 + 1;
// compute the stack indices
stacksIndices.unshift(i, ip1, ip2, i, ip2, ip3,
ip8, ip9, ip5, ip8, ip5, ip4,
ip7, ip6, ip10, ip7, ip10, ip11,
ip8, ip4, ip7, ip8, ip7, ip11,
ip5, ip9, ip10, ip5, ip10, ip6);
// compute the wireframe indices
if (depth !== 0) {
wireframeIndices.unshift(i, ip1, ip1, ip2,
ip2, ip3, ip3, i,
ip8, i, ip9, ip1,
ip11, ip3, ip10, ip2);
}
// number of vertex points, used for creating the indices array
i += 12; // a vertex has 3 coords: x, y and z
// set the maximum mesh width and height to calculate the center offset
meshWidth = Math.max(w, meshWidth);
meshHeight = Math.max(h, meshHeight);
}
self.postMessage({
vertices: vertices,
texCoord: texCoord,
color: color,
stacksIndices: stacksIndices,
wireframeIndices: wireframeIndices,
meshWidth: meshWidth,
meshHeight: meshHeight
});
close();
};
/**
* Utility functions for generating random numbers using the Alea algorithm.
*/
self.random = {
/**
* The generator function, automatically created with seed 0.
*/
_generator: null,
/**
* Returns a new random number between [0..1)
*/
next: function RNG_next()
{
return this._generator();
},
/**
* From http://baagoe.com/en/RandomMusings/javascript
* Johannes Baagoe <baagoe@baagoe.com>, 2010
*
* Seeds a random generator function with a set of passed arguments.
*/
seed: function RNG_seed()
{
let s0 = 0;
let s1 = 0;
let s2 = 0;
let c = 1;
if (arguments.length === 0) {
return this.seed(+new Date());
} else {
s0 = this.mash(" ");
s1 = this.mash(" ");
s2 = this.mash(" ");
for (let i = 0, len = arguments.length; i < len; i++) {
s0 -= this.mash(arguments[i]);
if (s0 < 0) {
s0 += 1;
}
s1 -= this.mash(arguments[i]);
if (s1 < 0) {
s1 += 1;
}
s2 -= this.mash(arguments[i]);
if (s2 < 0) {
s2 += 1;
}
}
let random = function() {
let t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
s0 = s1;
s1 = s2;
return (s2 = t - (c = t | 0));
};
random.uint32 = function() {
return random() * 0x100000000; // 2^32
};
random.fract53 = function() {
return random() +
(random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
};
return (this._generator = random);
}
},
/**
* From http://baagoe.com/en/RandomMusings/javascript
* Johannes Baagoe <baagoe@baagoe.com>, 2010
*/
mash: function RNG_mash(data)
{
let h, n = 0xefc8249d;
for (let i = 0, data = data.toString(), len = data.length; i < len; i++) {
n += data.charCodeAt(i);
h = 0.02519603282416938 * n;
n = h >>> 0;
h -= n;
h *= n;
n = h >>> 0;
h -= n;
n += h * 0x100000000; // 2^32
}
return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
}
};

View File

@ -0,0 +1,217 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Tilt: A WebGL-based 3D visualization of a webpage.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Victor Porof <vporof@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the LGPL or the GPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
***** END LICENSE BLOCK *****/
/*global self*/
"use strict";
/**
* This worker handles picking, given a set of vertices and a ray (calculates
* the intersection points and offers back information about the closest hit).
*
* Used in the TiltVisualization.Presenter object.
*/
self.onmessage = function TWP_onMessage(event)
{
let data = event.data;
let thickness = data.thickness;
let vertices = data.vertices;
let ray = data.ray;
let intersection = null;
let hit = [];
// calculates the squared distance between two points
function dsq(p1, p2) {
let xd = p2[0] - p1[0];
let yd = p2[1] - p1[1];
let zd = p2[2] - p1[2];
return xd * xd + yd * yd + zd * zd;
}
// check each stack face in the visualization mesh for intersections with
// the mouse ray (using a ray picking algorithm)
for (let i = 0, len = vertices.length; i < len; i += 36) {
// the front quad
let v0f = [vertices[i], vertices[i + 1], vertices[i + 2]];
let v1f = [vertices[i + 3], vertices[i + 4], vertices[i + 5]];
let v2f = [vertices[i + 6], vertices[i + 7], vertices[i + 8]];
let v3f = [vertices[i + 9], vertices[i + 10], vertices[i + 11]];
// the back quad
let v0b = [v0f[0], v0f[1], v0f[2] - thickness];
let v1b = [v1f[0], v1f[1], v1f[2] - thickness];
let v2b = [v2f[0], v2f[1], v2f[2] - thickness];
let v3b = [v3f[0], v3f[1], v3f[2] - thickness];
// for each triangle in the stack box, check for the intersections
if (self.intersect(v0f, v1f, v2f, ray, hit) || // front left
self.intersect(v0f, v2f, v3f, ray, hit) || // front right
self.intersect(v0b, v1b, v1f, ray, hit) || // left back
self.intersect(v0b, v1f, v0f, ray, hit) || // left front
self.intersect(v3f, v2b, v3b, ray, hit) || // right back
self.intersect(v3f, v2f, v2b, ray, hit) || // right front
self.intersect(v0b, v0f, v3f, ray, hit) || // top left
self.intersect(v0b, v3f, v3b, ray, hit) || // top right
self.intersect(v1f, v1b, v2b, ray, hit) || // bottom left
self.intersect(v1f, v2b, v2f, ray, hit)) { // bottom right
// calculate the distance between the intersection hit point and camera
let d = dsq(hit, ray.origin);
// we're picking the closest stack in the mesh from the camera
if (intersection === null || d < intersection.distance) {
intersection = {
// each mesh stack is composed of 12 vertices, so there's information
// about a node once in 12 * 3 = 36 iterations (to avoid duplication)
index: i / 36,
distance: d
};
}
}
}
self.postMessage(intersection);
close();
};
/**
* Utility function for finding intersections between a ray and a triangle.
*/
self.intersect = (function() {
// creates a new instance of a vector
function create() {
return new Float32Array(3);
}
// performs a vector addition
function add(aVec, aVec2, aDest) {
aDest[0] = aVec[0] + aVec2[0];
aDest[1] = aVec[1] + aVec2[1];
aDest[2] = aVec[2] + aVec2[2];
return aDest;
}
// performs a vector subtraction
function subtract(aVec, aVec2, aDest) {
aDest[0] = aVec[0] - aVec2[0];
aDest[1] = aVec[1] - aVec2[1];
aDest[2] = aVec[2] - aVec2[2];
return aDest;
}
// performs a vector scaling
function scale(aVec, aVal, aDest) {
aDest[0] = aVec[0] * aVal;
aDest[1] = aVec[1] * aVal;
aDest[2] = aVec[2] * aVal;
return aDest;
}
// generates the cross product of two vectors
function cross(aVec, aVec2, aDest) {
let x = aVec[0];
let y = aVec[1];
let z = aVec[2];
let x2 = aVec2[0];
let y2 = aVec2[1];
let z2 = aVec2[2];
aDest[0] = y * z2 - z * y2;
aDest[1] = z * x2 - x * z2;
aDest[2] = x * y2 - y * x2;
return aDest;
}
// calculates the dot product of two vectors
function dot(aVec, aVec2) {
return aVec[0] * aVec2[0] + aVec[1] * aVec2[1] + aVec[2] * aVec2[2];
}
let edge1 = create();
let edge2 = create();
let pvec = create();
let tvec = create();
let qvec = create();
let lvec = create();
// checks for ray-triangle intersections using the Fast Minimum-Storage
// (simplified) algorithm by Tomas Moller and Ben Trumbore
return function intersect(aVert0, aVert1, aVert2, aRay, aDest) {
let dir = aRay.direction;
let orig = aRay.origin;
// find vectors for two edges sharing vert0
subtract(aVert1, aVert0, edge1);
subtract(aVert2, aVert0, edge2);
// begin calculating determinant - also used to calculate the U parameter
cross(dir, edge2, pvec);
// if determinant is near zero, ray lines in plane of triangle
let inv_det = 1 / dot(edge1, pvec);
// calculate distance from vert0 to ray origin
subtract(orig, aVert0, tvec);
// calculate U parameter and test bounds
let u = dot(tvec, pvec) * inv_det;
if (u < 0 || u > 1) {
return false;
}
// prepare to test V parameter
cross(tvec, edge1, qvec);
// calculate V parameter and test bounds
let v = dot(dir, qvec) * inv_det;
if (v < 0 || u + v > 1) {
return false;
}
// calculate T, ray intersects triangle
let t = dot(edge2, qvec) * inv_det;
scale(dir, t, lvec);
add(orig, lvec, aDest);
return true;
};
}());

View File

@ -0,0 +1,80 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Victor Porof <vporof@mozilla.com> (original author)
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/devtools/tilt/test
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
head.js \
browser_tilt_01_lazy_getter.js \
browser_tilt_02_notifications.js \
browser_tilt_03_tab_switch.js \
browser_tilt_04_initialization.js \
browser_tilt_05_destruction.js \
browser_tilt_arcball.js \
browser_tilt_gl01.js \
browser_tilt_gl02.js \
browser_tilt_gl03.js \
browser_tilt_gl04.js \
browser_tilt_gl05.js \
browser_tilt_gl06.js \
browser_tilt_gl07.js \
browser_tilt_gl08.js \
browser_tilt_math01.js \
browser_tilt_math02.js \
browser_tilt_math03.js \
browser_tilt_math04.js \
browser_tilt_math05.js \
browser_tilt_math06.js \
browser_tilt_math07.js \
browser_tilt_utils01.js \
browser_tilt_utils02.js \
browser_tilt_utils03.js \
browser_tilt_utils04.js \
browser_tilt_utils05.js \
browser_tilt_utils06.js \
browser_tilt_visualizer.js \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -0,0 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, Tilt */
"use strict";
function test() {
ok(Tilt,
"The Tilt object wasn't got correctly via defineLazyGetter.");
is(Tilt.chromeWindow, window,
"The top-level window wasn't saved correctly");
ok(Tilt.visualizers,
"The holder object for all the instances of the visualizer doesn't exist.")
ok(Tilt.NOTIFICATIONS,
"The notifications constants weren't referenced correctly.");
}

View File

@ -0,0 +1,97 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, waitForExplicitFinish, finish, executeSoon, gBrowser */
/*global isTiltEnabled, isWebGLSupported, createTab, createTilt, Tilt */
/*global Services, TILT_INITIALIZED, TILT_DESTROYED, TILT_SHOWN, TILT_HIDDEN */
"use strict";
let tab0, tab1;
let testStep = -1;
let tabEvents = "";
function test() {
if (!isTiltEnabled()) {
info("Skipping notifications test because Tilt isn't enabled.");
return;
}
if (!isWebGLSupported()) {
info("Skipping notifications test because WebGL isn't supported.");
return;
}
waitForExplicitFinish();
gBrowser.tabContainer.addEventListener("TabSelect", tabSelect, false);
createNewTab();
}
function createNewTab() {
tab0 = gBrowser.selectedTab;
tab1 = createTab(function() {
Services.obs.addObserver(tab_TILT_INITIALIZED, TILT_INITIALIZED, false);
Services.obs.addObserver(tab_TILT_DESTROYED, TILT_DESTROYED, false);
Services.obs.addObserver(tab_TILT_SHOWN, TILT_SHOWN, false);
Services.obs.addObserver(tab_TILT_HIDDEN, TILT_HIDDEN, false);
createTilt({
onTiltOpen: function()
{
testStep = 0;
tabSelect();
}
});
});
}
function tab_TILT_INITIALIZED() {
tabEvents += "ti;";
}
function tab_TILT_DESTROYED() {
tabEvents += "td;";
}
function tab_TILT_SHOWN() {
tabEvents += "ts;";
}
function tab_TILT_HIDDEN() {
tabEvents += "th;";
}
let testSteps = [
function step0() {
gBrowser.selectedTab = tab0;
},
function step1() {
gBrowser.selectedTab = tab1;
},
function step2() {
Tilt.destroy(Tilt.currentWindowId);
Services.obs.removeObserver(tab_TILT_INITIALIZED, TILT_INITIALIZED, false);
Services.obs.removeObserver(tab_TILT_DESTROYED, TILT_DESTROYED, false);
Services.obs.removeObserver(tab_TILT_SHOWN, TILT_SHOWN, false);
Services.obs.removeObserver(tab_TILT_HIDDEN, TILT_HIDDEN, false);
gBrowser.removeCurrentTab();
},
function step3_cleanup() {
is(tabEvents, "ti;th;ts;td;",
"The notifications weren't fired in the correct order.");
tab0 = null;
tab1 = null;
gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect, false);
finish();
}
];
function tabSelect() {
if (testStep !== -1) {
executeSoon(testSteps[testStep]);
testStep++;
}
}

View File

@ -0,0 +1,119 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, waitForExplicitFinish, finish, executeSoon, gBrowser */
/*global isTiltEnabled, isWebGLSupported, createTab, createTilt, Tilt */
"use strict";
let tab0, tab1, tab2;
let testStep = -1;
function test() {
if (!isTiltEnabled()) {
info("Skipping tab switch test because Tilt isn't enabled.");
return;
}
if (!isWebGLSupported()) {
info("Skipping tab switch test because WebGL isn't supported.");
return;
}
waitForExplicitFinish();
gBrowser.tabContainer.addEventListener("TabSelect", tabSelect, false);
createTab1();
}
function createTab1() {
tab0 = gBrowser.selectedTab;
tab1 = createTab(function() {
createTilt({
onInspectorOpen: function()
{
ok(Tilt.tiltButton.checked === false,
"The toolbar tilt button shouldn't be pressed before Tilt is open.");
},
onTiltOpen: function()
{
createTab2();
}
});
});
}
function createTab2() {
tab2 = createTab(function() {
createTilt({
onInspectorOpen: function()
{
ok(Tilt.tiltButton.checked === false,
"The toolbar tilt button shouldn't be pressed before Tilt is open.");
},
onTiltOpen: function()
{
testStep = 0;
tabSelect();
}
});
});
}
let testSteps = [
function step0() {
ok(Tilt.tiltButton.checked === true,
"The toolbar tilt button should have been pressed at step0 (tab 2).");
gBrowser.selectedTab = tab1;
},
function step1() {
ok(Tilt.tiltButton.checked === true,
"The toolbar tilt button should have been pressed at step1 (tab 1).");
gBrowser.selectedTab = tab0;
},
function step2() {
ok(Tilt.tiltButton.checked === false,
"The toolbar tilt button shouldn't have been pressed at step2 (tab 0).");
gBrowser.selectedTab = tab1;
},
function step3() {
ok(Tilt.tiltButton.checked === true,
"The toolbar tilt button should have been pressed at step3 (tab 1).");
gBrowser.selectedTab = tab2;
},
function step4() {
ok(Tilt.tiltButton.checked === true,
"The toolbar tilt button should have been pressed at step4 (tab 2).");
Tilt.destroy(Tilt.currentWindowId);
gBrowser.removeCurrentTab();
},
function step5() {
ok(Tilt.tiltButton.checked === true,
"The toolbar tilt button should have been pressed at step5 (tab 1).");
Tilt.destroy(Tilt.currentWindowId);
gBrowser.removeCurrentTab();
},
function step6_cleanup() {
ok(Tilt.tiltButton.checked === false,
"The toolbar tilt button shouldn't have been pressed at step6 (tab 0).");
tab1 = null;
tab2 = null;
gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect, false);
finish();
}
];
function tabSelect() {
if (testStep !== -1) {
executeSoon(testSteps[testStep]);
testStep++;
}
}

View File

@ -0,0 +1,56 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, waitForExplicitFinish, finish, gBrowser */
/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
/*global Tilt, TiltUtils, TiltVisualizer */
"use strict";
function test() {
if (!isTiltEnabled()) {
info("Skipping initialization test because Tilt isn't enabled.");
return;
}
if (!isWebGLSupported()) {
info("Skipping initialization test because WebGL isn't supported.");
return;
}
waitForExplicitFinish();
createTab(function() {
let id = TiltUtils.getWindowId(gBrowser.selectedBrowser.contentWindow);
is(id, Tilt.currentWindowId,
"The unique window identifiers should match for the same window.");
createTilt({
onInspectorOpen: function() {
is(Tilt.visualizers[id], null,
"A instance of the visualizer shouldn't be initialized yet.");
is(typeof TiltVisualizer.Prefs.enabled, "boolean",
"The 'enabled' pref should have been loaded by now.");
is(typeof TiltVisualizer.Prefs.forceEnabled, "boolean",
"The 'force-enabled' pref should have been loaded by now.");
},
onTiltOpen: function()
{
ok(Tilt.visualizers[id] instanceof TiltVisualizer,
"A new instance of the visualizer wasn't created properly.");
ok(Tilt.visualizers[id].isInitialized(),
"The new instance of the visualizer wasn't initialized properly.");
},
onTiltClose: function()
{
is(Tilt.visualizers[id], null,
"The current instance of the visualizer wasn't destroyed properly.");
},
onEnd: function()
{
gBrowser.removeCurrentTab();
finish();
}
}, true);
});
}

View File

@ -0,0 +1,41 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, waitForExplicitFinish, finish, gBrowser */
/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
/*global Services, Tilt, TiltUtils, InspectorUI, TILT_DESTROYED */
"use strict";
function test() {
if (!isTiltEnabled()) {
info("Skipping destruction test because Tilt isn't enabled.");
return;
}
if (!isWebGLSupported()) {
info("Skipping destruction test because WebGL isn't supported.");
return;
}
waitForExplicitFinish();
createTab(function() {
createTilt({
onTiltOpen: function()
{
Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
InspectorUI.closeInspectorUI();
}
});
});
}
function cleanup() {
let id = TiltUtils.getWindowId(gBrowser.selectedBrowser.contentWindow);
is(Tilt.visualizers[id], null,
"The current instance of the visualizer wasn't destroyed properly.");
Services.obs.removeObserver(cleanup, TILT_DESTROYED);
gBrowser.removeCurrentTab();
finish();
}

View File

@ -0,0 +1,333 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isApproxVec, vec3, quat4, TiltVisualizer */
"use strict";
function cloneUpdate(update) {
return {
rotation: quat4.create(update.rotation),
translation: vec3.create(update.translation)
};
}
function isExpectedUpdate(update1, update2) {
if (update1.length !== update2.length) {
return false;
}
for (let i = 0, len = update1.length; i < len; i++) {
if (!isApproxVec(update1[i].rotation, update2[i].rotation) ||
!isApproxVec(update1[i].translation, update2[i].translation)) {
return false;
}
}
return true;
}
function test() {
let arcball1 = new TiltVisualizer.Arcball(123, 456);
is(arcball1.width, 123,
"The first arcball width wasn't set correctly.");
is(arcball1.height, 456,
"The first arcball height wasn't set correctly.");
is(arcball1.radius, 123,
"The first arcball radius wasn't implicitly set correctly.");
let arcball2 = new TiltVisualizer.Arcball(987, 654);
is(arcball2.width, 987,
"The second arcball width wasn't set correctly.");
is(arcball2.height, 654,
"The second arcball height wasn't set correctly.");
is(arcball2.radius, 654,
"The second arcball radius wasn't implicitly set correctly.");
let arcball3 = new TiltVisualizer.Arcball(512, 512);
let sphereVec = vec3.create();
arcball3.pointToSphere(123, 456, 256, 512, 512, sphereVec);
ok(isApproxVec(sphereVec, [-0.009765625, 0.390625, 0.9204980731010437]),
"The pointToSphere() function didn't map the coordinates correctly.");
let stack1 = [];
let expect1 = [
{ rotation: [
-0.054038457572460175, 0.015347825363278389,
-0.02533721923828125, -0.9980993270874023],
translation: [0, 0, 0] },
{ rotation: [
-0.09048379212617874, 0.024709727615118027,
-0.04307326674461365, -0.9946591854095459],
translation: [0, 0, 0] },
{ rotation: [
-0.11537143588066101, 0.03063894622027874,
-0.05548851564526558, -0.9912980198860168],
translation: [0, 0, 0] },
{ rotation: [
-0.13250185549259186, 0.03449848294258118,
-0.0641791820526123, -0.9885009527206421],
translation: [0, 0, 0] },
{ rotation: [
-0.14435507357120514, 0.037062086164951324,
-0.07026264816522598, -0.9863321781158447],
translation: [0, 0, 0] },
{ rotation: [
-0.15258607268333435, 0.03879034146666527,
-0.07452107220888138, -0.9847128391265869],
translation: [0, 0, 0] },
{ rotation: [
-0.1583157479763031, 0.03996811807155609,
-0.07750196009874344, -0.9835304617881775],
translation: [0, 0, 0] },
{ rotation: [
-0.16231097280979156, 0.04077700152993202,
-0.07958859205245972, -0.982679009437561],
translation: [0, 0, 0] },
{ rotation: [
-0.16510005295276642, 0.04133564606308937,
-0.08104922622442245, -0.9820714592933655],
translation: [0, 0, 0] },
{ rotation: [
-0.16704875230789185, 0.04172303527593613,
-0.08207167685031891, -0.9816405177116394],
translation: [0, 0, 0] }];
arcball3.mouseDown(10, 10, 1);
arcball3.mouseMove(10, 100);
for (let i1 = 0; i1 < 10; i1++) {
stack1.push(cloneUpdate(arcball3.update()));
}
ok(isExpectedUpdate(stack1, expect1),
"Mouse down & move events didn't create the expected transform. results.");
let stack2 = [];
let expect2 = [
{ rotation: [
-0.1684110015630722, 0.04199237748980522,
-0.0827873945236206, -0.9813361167907715],
translation: [0, 0, 0] },
{ rotation: [
-0.16936375200748444, 0.04218007251620293,
-0.08328840136528015, -0.9811217188835144],
translation: [0, 0, 0] },
{ rotation: [
-0.17003019154071808, 0.04231100529432297,
-0.08363909274339676, -0.9809709787368774],
translation: [0, 0, 0] },
{ rotation: [
-0.17049652338027954, 0.042402446269989014,
-0.0838845893740654, -0.9808651208877563],
translation: [0, 0, 0] },
{ rotation: [
-0.17082282900810242, 0.042466338723897934,
-0.08405643701553345, -0.9807908535003662],
translation: [0, 0, 0] },
{ rotation: [
-0.17105120420455933, 0.04251104220747948,
-0.08417671173810959, -0.9807388186454773],
translation: [0, 0, 0] },
{ rotation: [
-0.17121103405952454, 0.04254228621721268,
-0.08426092565059662, -0.9807023406028748],
translation: [0, 0, 0] },
{ rotation: [
-0.17132291197776794, 0.042564138770103455,
-0.08431987464427948, -0.9806767106056213],
translation: [0, 0, 0] },
{ rotation: [
-0.1714012324810028, 0.04257945716381073,
-0.08436112850904465, -0.9806588888168335],
translation: [0, 0, 0] },
{ rotation: [
-0.17145603895187378, 0.042590171098709106,
-0.08439001441001892, -0.9806463718414307],
translation: [0, 0, 0] }];
arcball3.mouseUp(100, 100);
for (let i2 = 0; i2 < 10; i2++) {
stack2.push(cloneUpdate(arcball3.update()));
}
ok(isExpectedUpdate(stack2, expect2),
"Mouse up events didn't create the expected transformation results.");
let stack3 = [];
let expect3 = [
{ rotation: [
-0.17149439454078674, 0.04259764403104782,
-0.08441022783517838, -0.9806375503540039],
translation: [0, 0, -1] },
{ rotation: [
-0.17152123153209686, 0.04260288551449776,
-0.08442437648773193, -0.980631411075592],
translation: [0, 0, -1.899999976158142] },
{ rotation: [
-0.1715400665998459, 0.04260658100247383,
-0.08443428575992584, -0.9806271195411682],
translation: [0, 0, -2.7100000381469727] },
{ rotation: [
-0.17155319452285767, 0.04260912910103798,
-0.08444121479988098, -0.9806240797042847],
translation: [0, 0, -3.439000129699707] },
{ rotation: [
-0.17156240344047546, 0.042610932141542435,
-0.08444607257843018, -0.9806219935417175],
translation: [0, 0, -4.095099925994873] },
{ rotation: [
-0.1715688556432724, 0.042612191289663315,
-0.08444946259260178, -0.9806205034255981],
translation: [0, 0, -4.685589790344238] },
{ rotation: [
-0.17157337069511414, 0.04261308163404465,
-0.0844518393278122, -0.980619490146637],
translation: [0, 0, -5.217031002044678] },
{ rotation: [
-0.17157652974128723, 0.0426136814057827,
-0.0844535157084465, -0.9806187748908997],
translation: [0, 0, -5.6953277587890625] },
{ rotation: [
-0.17157875001430511, 0.04261413961648941,
-0.08445467799901962, -0.9806182980537415],
translation: [0, 0, -6.125794887542725] },
{ rotation: [
-0.17158031463623047, 0.04261442646384239,
-0.08445550501346588, -0.980617880821228],
translation: [0, 0, -6.5132155418396] }];
arcball3.mouseScroll(10);
for (let i3 = 0; i3 < 10; i3++) {
stack3.push(cloneUpdate(arcball3.update()));
}
ok(isExpectedUpdate(stack3, expect3),
"Mouse scroll events didn't create the expected transformation results.");
let stack4 = [];
let expect4 = [
{ rotation: [
-0.17158135771751404, 0.04261462762951851,
-0.08445606380701065, -0.9806176424026489],
translation: [0, 0, -6.861894130706787] },
{ rotation: [
-0.1715821474790573, 0.04261479899287224,
-0.08445646613836288, -0.9806175231933594],
translation: [0, 0, -7.1757049560546875] },
{ rotation: [
-0.1715826541185379, 0.0426148846745491,
-0.08445674180984497, -0.980617344379425],
translation: [0, 0, -7.458134651184082] },
{ rotation: [
-0.17158304154872894, 0.04261497035622597,
-0.08445693552494049, -0.9806172847747803],
translation: [0, 0, -7.7123212814331055] },
{ rotation: [
-0.17158329486846924, 0.042615000158548355,
-0.08445708453655243, -0.9806172251701355],
translation: [0, 0, -7.941089153289795] },
{ rotation: [
-0.17158347368240356, 0.04261505603790283,
-0.084457166492939, -0.9806172251701355],
translation: [0, 0, -8.146980285644531] },
{ rotation: [
-0.1715836226940155, 0.04261508584022522,
-0.08445724099874496, -0.9806171655654907],
translation: [0, 0, -8.332282066345215] },
{ rotation: [
-0.17158368229866028, 0.04261508584022522,
-0.08445728570222855, -0.980617105960846],
translation: [0, 0, -8.499053955078125] },
{ rotation: [
-0.17158377170562744, 0.04261511191725731,
-0.08445732295513153, -0.980617105960846],
translation: [0, 0, -8.649148941040039] },
{ rotation: [
-0.17158380150794983, 0.04261511191725731,
-0.08445733785629272, -0.980617105960846],
translation: [0, 0, -8.784234046936035] }];
arcball3.keyDown(65);
arcball3.keyDown(68);
arcball3.keyDown(87);
arcball3.keyDown(83);
arcball3.keyDown(37);
arcball3.keyDown(39);
arcball3.keyDown(38);
arcball3.keyDown(40);
for (let i4 = 0; i4 < 10; i4++) {
stack4.push(cloneUpdate(arcball3.update()));
}
ok(isExpectedUpdate(stack4, expect4),
"Key down events didn't create the expected transformation results.");
let stack5 = [];
let expect5 = [
{ rotation: [
-0.1715838462114334, 0.04261511191725731,
-0.08445736765861511, -0.980617105960846],
translation: [0, 0, -8.905810356140137] },
{ rotation: [
-0.1715838462114334, 0.04261511191725731,
-0.08445736765861511, -0.980617105960846],
translation: [0, 0, -9.015229225158691] },
{ rotation: [
-0.1715838462114334, 0.04261511191725731,
-0.08445736765861511, -0.980617105960846],
translation: [0, 0, -9.113706588745117] },
{ rotation: [
-0.1715838611125946, 0.04261511191725731,
-0.0844573825597763, -0.9806170463562012],
translation: [0, 0, -9.202336311340332] },
{ rotation: [
-0.17158392071723938, 0.0426151417195797,
-0.0844573974609375, -0.980617105960846],
translation: [0, 0, -9.282102584838867] },
{ rotation: [
-0.17158392071723938, 0.0426151417195797,
-0.0844573974609375, -0.980617105960846],
translation: [0, 0, -9.35389232635498] },
{ rotation: [
-0.17158392071723938, 0.0426151417195797,
-0.0844573974609375, -0.980617105960846],
translation: [0, 0, -9.418502807617188] },
{ rotation: [
-0.17158392071723938, 0.0426151417195797,
-0.0844573974609375, -0.980617105960846],
translation: [0, 0, -9.476652145385742] },
{ rotation: [
-0.17158392071723938, 0.0426151417195797,
-0.0844573974609375, -0.980617105960846],
translation: [0, 0, -9.528986930847168] },
{ rotation: [
-0.17158392071723938, 0.0426151417195797,
-0.0844573974609375, -0.980617105960846],
translation: [0, 0, -9.576087951660156] }];
arcball3.keyUp(65);
arcball3.keyUp(68);
arcball3.keyUp(87);
arcball3.keyUp(83);
arcball3.keyUp(37);
arcball3.keyUp(39);
arcball3.keyUp(38);
arcball3.keyUp(40);
for (let i5 = 0; i5 < 10; i5++) {
stack5.push(cloneUpdate(arcball3.update()));
}
ok(isExpectedUpdate(stack5, expect5),
"Key up events didn't create the expected transformation results.");
arcball3.resize(123, 456);
is(arcball3.width, 123,
"The arcball width wasn't updated correctly.");
is(arcball3.height, 456,
"The arcball height wasn't updated correctly.");
is(arcball3.radius, 123,
"The arcball radius wasn't implicitly updated correctly.");
}

View File

@ -0,0 +1,158 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, isApproxVec, isWebGLSupported, createCanvas, TiltGL */
/*global WebGLRenderingContext, WebGLProgram */
"use strict";
let isWebGLAvailable;
function onWebGLFail() {
isWebGLAvailable = false;
}
function onWebGLSuccess() {
isWebGLAvailable = true;
}
function test() {
if (!isWebGLSupported()) {
info("Skipping tilt_gl01 because WebGL isn't supported on this hardware.");
return;
}
let canvas = createCanvas();
let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
let gl = renderer.context;
if (!isWebGLAvailable) {
return;
}
ok(renderer,
"The TiltGL.Renderer constructor should have initialized a new object.");
ok(gl instanceof WebGLRenderingContext,
"The renderer context wasn't created correctly from the passed canvas.");
let clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE),
clearDepth = gl.getParameter(gl.DEPTH_CLEAR_VALUE);
is(clearColor[0], 0,
"The default red clear color wasn't set correctly at initialization.");
is(clearColor[1], 0,
"The default green clear color wasn't set correctly at initialization.");
is(clearColor[2], 0,
"The default blue clear color wasn't set correctly at initialization.");
is(clearColor[3], 0,
"The default alpha clear color wasn't set correctly at initialization.");
is(clearDepth, 1,
"The default clear depth wasn't set correctly at initialization.");
is(renderer.width, canvas.width,
"The renderer width wasn't set correctly from the passed canvas.");
is(renderer.height, canvas.height,
"The renderer height wasn't set correctly from the passed canvas.");
ok(renderer.mvMatrix,
"The model view matrix wasn't initialized properly.");
ok(renderer.projMatrix,
"The model view matrix wasn't initialized properly.");
ok(isApproxVec(renderer._fillColor, [1, 1, 1, 1]),
"The default fill color wasn't set correctly.");
ok(isApproxVec(renderer._strokeColor, [0, 0, 0, 1]),
"The default stroke color wasn't set correctly.");
is(renderer._strokeWeightValue, 1,
"The default stroke weight wasn't set correctly.");
ok(renderer._colorShader,
"A default color shader should have been created.");
ok(typeof renderer.Program, "function",
"At init, the renderer should have created a Program constructor.");
ok(typeof renderer.VertexBuffer, "function",
"At init, the renderer should have created a VertexBuffer constructor.");
ok(typeof renderer.IndexBuffer, "function",
"At init, the renderer should have created a IndexBuffer constructor.");
ok(typeof renderer.Texture, "function",
"At init, the renderer should have created a Texture constructor.");
renderer.depthTest(true);
is(gl.getParameter(gl.DEPTH_TEST), true,
"The depth test wasn't enabled when requested.");
renderer.depthTest(false);
is(gl.getParameter(gl.DEPTH_TEST), false,
"The depth test wasn't disabled when requested.");
renderer.stencilTest(true);
is(gl.getParameter(gl.STENCIL_TEST), true,
"The stencil test wasn't enabled when requested.");
renderer.stencilTest(false);
is(gl.getParameter(gl.STENCIL_TEST), false,
"The stencil test wasn't disabled when requested.");
renderer.cullFace("front");
is(gl.getParameter(gl.CULL_FACE), true,
"The cull face wasn't enabled when requested.");
is(gl.getParameter(gl.CULL_FACE_MODE), gl.FRONT,
"The cull face front mode wasn't set correctly.");
renderer.cullFace("back");
is(gl.getParameter(gl.CULL_FACE), true,
"The cull face wasn't enabled when requested.");
is(gl.getParameter(gl.CULL_FACE_MODE), gl.BACK,
"The cull face back mode wasn't set correctly.");
renderer.cullFace("both");
is(gl.getParameter(gl.CULL_FACE), true,
"The cull face wasn't enabled when requested.");
is(gl.getParameter(gl.CULL_FACE_MODE), gl.FRONT_AND_BACK,
"The cull face back mode wasn't set correctly.");
renderer.cullFace(false);
is(gl.getParameter(gl.CULL_FACE), false,
"The cull face wasn't disabled when requested.");
renderer.frontFace("cw");
is(gl.getParameter(gl.FRONT_FACE), gl.CW,
"The front face cw mode wasn't set correctly.");
renderer.frontFace("ccw");
is(gl.getParameter(gl.FRONT_FACE), gl.CCW,
"The front face ccw mode wasn't set correctly.");
renderer.blendMode("alpha");
is(gl.getParameter(gl.BLEND), true,
"The blend mode wasn't enabled when requested.");
is(gl.getParameter(gl.BLEND_SRC_ALPHA), gl.SRC_ALPHA,
"The soruce blend func wasn't set correctly.");
is(gl.getParameter(gl.BLEND_DST_ALPHA), gl.ONE_MINUS_SRC_ALPHA,
"The destination blend func wasn't set correctly.");
renderer.blendMode("add");
is(gl.getParameter(gl.BLEND), true,
"The blend mode wasn't enabled when requested.");
is(gl.getParameter(gl.BLEND_SRC_ALPHA), gl.SRC_ALPHA,
"The soruce blend func wasn't set correctly.");
is(gl.getParameter(gl.BLEND_DST_ALPHA), gl.ONE,
"The destination blend func wasn't set correctly.");
renderer.blendMode(false);
is(gl.getParameter(gl.CULL_FACE), false,
"The blend mode wasn't disabled when requested.");
is(gl.getParameter(gl.CURRENT_PROGRAM), null,
"No program should be initially set in the WebGL context.");
renderer.useColorShader(new renderer.VertexBuffer([1, 2, 3], 3));
ok(gl.getParameter(gl.CURRENT_PROGRAM) instanceof WebGLProgram,
"The correct program hasn't been set in the WebGL context.");
}

View File

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, isApproxVec, isWebGLSupported, createCanvas, TiltGL */
"use strict";
let isWebGLAvailable;
function onWebGLFail() {
isWebGLAvailable = false;
}
function onWebGLSuccess() {
isWebGLAvailable = true;
}
function test() {
if (!isWebGLSupported()) {
info("Skipping tilt_gl02 because WebGL isn't supported on this hardware.");
return;
}
let canvas = createCanvas();
let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
let gl = renderer.context;
if (!isWebGLAvailable) {
return;
}
renderer.fill([1, 0, 0, 1]);
ok(isApproxVec(renderer._fillColor, [1, 0, 0, 1]),
"The fill color wasn't set correctly.");
renderer.stroke([0, 1, 0, 1]);
ok(isApproxVec(renderer._strokeColor, [0, 1, 0, 1]),
"The stroke color wasn't set correctly.");
renderer.strokeWeight(2);
is(renderer._strokeWeightValue, 2,
"The stroke weight wasn't set correctly.");
is(gl.getParameter(gl.LINE_WIDTH), 2,
"The stroke weight wasn't applied correctly.");
}

View File

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, isApproxVec, isWebGLSupported, createCanvas, TiltGL */
"use strict";
let isWebGLAvailable;
function onWebGLFail() {
isWebGLAvailable = false;
}
function onWebGLSuccess() {
isWebGLAvailable = true;
}
function test() {
if (!isWebGLSupported()) {
info("Skipping tilt_gl03 because WebGL isn't supported on this hardware.");
return;
}
let canvas = createCanvas();
let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
let gl = renderer.context;
if (!isWebGLAvailable) {
return;
}
renderer.defaults();
is(gl.getParameter(gl.DEPTH_TEST), true,
"The depth test wasn't set to the correct default value.");
is(gl.getParameter(gl.STENCIL_TEST), false,
"The stencil test wasn't set to the correct default value.");
is(gl.getParameter(gl.CULL_FACE), false,
"The cull face wasn't set to the correct default value.");
is(gl.getParameter(gl.FRONT_FACE), gl.CCW,
"The front face wasn't set to the correct default value.");
is(gl.getParameter(gl.BLEND), true,
"The blend mode wasn't set to the correct default value.");
is(gl.getParameter(gl.BLEND_SRC_ALPHA), gl.SRC_ALPHA,
"The soruce blend func wasn't set to the correct default value.");
is(gl.getParameter(gl.BLEND_DST_ALPHA), gl.ONE_MINUS_SRC_ALPHA,
"The destination blend func wasn't set to the correct default value.");
ok(isApproxVec(renderer._fillColor, [1, 1, 1, 1]),
"The fill color wasn't set to the correct default value.");
ok(isApproxVec(renderer._strokeColor, [0, 0, 0, 1]),
"The stroke color wasn't set to the correct default value.");
is(renderer._strokeWeightValue, 1,
"The stroke weight wasn't set to the correct default value.");
is(gl.getParameter(gl.LINE_WIDTH), 1,
"The stroke weight wasn't applied with the correct default value.");
ok(isApproxVec(renderer.projMatrix, [
1.2071068286895752, 0, 0, 0, 0, -2.4142136573791504, 0, 0, 0, 0,
-1.0202020406723022, -1, -181.06602478027344, 181.06602478027344,
148.14492797851562, 181.06602478027344
]), "The default perspective projection matrix wasn't set correctly.");
ok(isApproxVec(renderer.mvMatrix, [
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
]), "The default model view matrix wasn't set correctly.");
}

View File

@ -0,0 +1,116 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, isApproxVec, isWebGLSupported, createCanvas, TiltGL */
"use strict";
let isWebGLAvailable;
function onWebGLFail() {
isWebGLAvailable = false;
}
function onWebGLSuccess() {
isWebGLAvailable = true;
}
function test() {
if (!isWebGLSupported()) {
info("Skipping tilt_gl04 because WebGL isn't supported on this hardware.");
return;
}
let canvas = createCanvas();
let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
let gl = renderer.context;
if (!isWebGLAvailable) {
return;
}
renderer.perspective();
ok(isApproxVec(renderer.projMatrix, [
1.2071068286895752, 0, 0, 0, 0, -2.4142136573791504, 0, 0, 0, 0,
-1.0202020406723022, -1, -181.06602478027344, 181.06602478027344,
148.14492797851562, 181.06602478027344
]), "The default perspective proj. matrix wasn't calculated correctly.");
ok(isApproxVec(renderer.mvMatrix, [
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
]), "Changing the perpective matrix should reset the modelview by default.");
renderer.ortho();
ok(isApproxVec(renderer.projMatrix, [
0.006666666828095913, 0, 0, 0, 0, -0.013333333656191826, 0, 0, 0, 0, -1,
0, -1, 1, 0, 1
]), "The default ortho proj. matrix wasn't calculated correctly.");
ok(isApproxVec(renderer.mvMatrix, [
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
]), "Changing the ortho matrix should reset the modelview by default.");
renderer.projection(mat4.perspective(45, 1, 0.1, 100));
ok(isApproxVec(renderer.projMatrix, [
2.4142136573791504, 0, 0, 0, 0, 2.4142136573791504, 0, 0, 0, 0,
-1.0020020008087158, -1, 0, 0, -0.20020020008087158, 0
]), "A custom proj. matrix couldn't be set correctly.");
ok(isApproxVec(renderer.mvMatrix, [
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
]), "Setting a custom proj. matrix should reset the model view by default.");
renderer.translate(1, 1, 1);
ok(isApproxVec(renderer.mvMatrix, [
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1
]), "The translation transformation wasn't applied correctly.");
renderer.rotate(0.5, 1, 1, 1);
ok(isApproxVec(renderer.mvMatrix, [
0.9183883666992188, 0.317602276802063, -0.23599065840244293, 0,
-0.23599065840244293, 0.9183883666992188, 0.317602276802063, 0,
0.317602276802063, -0.23599065840244293, 0.9183883666992188, 0, 1, 1, 1, 1
]), "The rotation transformation wasn't applied correctly.");
renderer.rotateX(0.5);
ok(isApproxVec(renderer.mvMatrix, [
0.9183883666992188, 0.317602276802063, -0.23599065840244293, 0,
-0.05483464524149895, 0.6928216814994812, 0.7190210819244385, 0,
0.391862154006958, -0.6474001407623291, 0.6536949872970581, 0, 1, 1, 1, 1
]), "The X rotation transformation wasn't applied correctly.");
renderer.rotateY(0.5);
ok(isApproxVec(renderer.mvMatrix, [
0.6180928945541382, 0.5891023874282837, -0.5204993486404419, 0,
-0.05483464524149895, 0.6928216814994812, 0.7190210819244385, 0,
0.7841902375221252, -0.4158804416656494, 0.4605313837528229, 0, 1, 1, 1, 1
]), "The Y rotation transformation wasn't applied correctly.");
renderer.rotateZ(0.5);
ok(isApproxVec(renderer.mvMatrix, [
0.5161384344100952, 0.8491423726081848, -0.11206408590078354, 0,
-0.3444514572620392, 0.3255774974822998, 0.8805410265922546, 0,
0.7841902375221252, -0.4158804416656494, 0.4605313837528229, 0, 1, 1, 1, 1
]), "The Z rotation transformation wasn't applied correctly.");
renderer.scale(2, 2, 2);
ok(isApproxVec(renderer.mvMatrix, [
1.0322768688201904, 1.6982847452163696, -0.22412817180156708, 0,
-0.6889029145240784, 0.6511549949645996, 1.7610820531845093, 0,
1.5683804750442505, -0.8317608833312988, 0.9210627675056458, 0, 1, 1, 1, 1
]), "The Z rotation transformation wasn't applied correctly.");
renderer.transform(mat4.create());
ok(isApproxVec(renderer.mvMatrix, [
1.0322768688201904, 1.6982847452163696, -0.22412817180156708, 0,
-0.6889029145240784, 0.6511549949645996, 1.7610820531845093, 0,
1.5683804750442505, -0.8317608833312988, 0.9210627675056458, 0, 1, 1, 1, 1
]), "The identity matrix transformation wasn't applied correctly.");
renderer.origin(1, 1, 1);
ok(isApproxVec(renderer.mvMatrix, [
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
]), "The origin wasn't reset to identity correctly.");
}

View File

@ -0,0 +1,42 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, isWebGLSupported, createCanvas, TiltGL */
"use strict";
let isWebGLAvailable;
function onWebGLFail() {
isWebGLAvailable = false;
}
function onWebGLSuccess() {
isWebGLAvailable = true;
}
function test() {
if (!isWebGLSupported()) {
info("Skipping tilt_gl05 because WebGL isn't supported on this hardware.");
return;
}
let canvas = createCanvas();
let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
let gl = renderer.context;
if (!isWebGLAvailable) {
return;
}
let mesh = {
vertices: new renderer.VertexBuffer([1, 2, 3], 3),
indices: new renderer.IndexBuffer([1]),
};
ok(mesh.vertices instanceof TiltGL.VertexBuffer,
"The mesh vertices weren't saved at initialization.");
ok(mesh.indices instanceof TiltGL.IndexBuffer,
"The mesh indices weren't saved at initialization.");
}

View File

@ -0,0 +1,59 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, isWebGLSupported, createCanvas, TiltGL */
"use strict";
let isWebGLAvailable;
function onWebGLFail() {
isWebGLAvailable = false;
}
function onWebGLSuccess() {
isWebGLAvailable = true;
}
function test() {
if (!isWebGLSupported()) {
info("Skipping tilt_gl06 because WebGL isn't supported on this hardware.");
return;
}
let canvas = createCanvas();
let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
let gl = renderer.context;
if (!isWebGLAvailable) {
return;
}
let vb = new renderer.VertexBuffer([1, 2, 3, 4, 5, 6], 3);
ok(vb instanceof TiltGL.VertexBuffer,
"The vertex buffer object wasn't instantiated correctly.");
ok(vb._ref,
"The vertex buffer gl element wasn't created at initialization.");
ok(vb.components,
"The vertex buffer components weren't created at initialization.");
is(vb.itemSize, 3,
"The vertex buffer item size isn't set correctly.");
is(vb.numItems, 2,
"The vertex buffer number of items weren't calculated correctly.");
let ib = new renderer.IndexBuffer([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
ok(ib instanceof TiltGL.IndexBuffer,
"The index buffer object wasn't instantiated correctly.");
ok(ib._ref,
"The index buffer gl element wasn't created at initialization.");
ok(ib.components,
"The index buffer components weren't created at initialization.");
is(ib.itemSize, 1,
"The index buffer item size isn't set correctly.");
is(ib.numItems, 10,
"The index buffer number of items weren't calculated correctly.");
}

View File

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isnot, info, isWebGLSupported, createCanvas, TiltGL */
"use strict";
let isWebGLAvailable;
function onWebGLFail() {
isWebGLAvailable = false;
}
function onWebGLSuccess() {
isWebGLAvailable = true;
}
function test() {
if (!isWebGLSupported()) {
info("Skipping tilt_gl07 because WebGL isn't supported on this hardware.");
return;
}
let canvas = createCanvas();
let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
let gl = renderer.context;
if (!isWebGLAvailable) {
return;
}
let p = new renderer.Program({
vs: TiltGL.ColorShader.vs,
fs: TiltGL.ColorShader.fs,
attributes: ["vertexPosition"],
uniforms: ["mvMatrix", "projMatrix", "fill"]
});
ok(p instanceof TiltGL.Program,
"The program object wasn't instantiated correctly.");
ok(p._ref,
"The program WebGL object wasn't created properly.");
isnot(p._id, -1,
"The program id wasn't set properly.");
ok(p._attributes,
"The program attributes cache wasn't created properly.");
ok(p._uniforms,
"The program uniforms cache wasn't created properly.");
is(typeof p._attributes.vertexPosition, "number",
"The vertexPosition attribute wasn't cached as it should.");
is(typeof p._uniforms.mvMatrix, "object",
"The mvMatrix uniform wasn't cached as it should.");
is(typeof p._uniforms.projMatrix, "object",
"The projMatrix uniform wasn't cached as it should.");
is(typeof p._uniforms.fill, "object",
"The fill uniform wasn't cached as it should.");
}

View File

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isnot, info, isWebGLSupported, createCanvas, TiltGL */
"use strict";
let isWebGLAvailable;
function onWebGLFail() {
isWebGLAvailable = false;
}
function onWebGLSuccess() {
isWebGLAvailable = true;
}
function test() {
if (!isWebGLSupported()) {
info("Skipping tilt_gl08 because WebGL isn't supported on this hardware.");
return;
}
let canvas = createCanvas();
let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
let gl = renderer.context;
if (!isWebGLAvailable) {
return;
}
let t = new renderer.Texture({
source: canvas,
format: "RGB"
});
ok(t instanceof TiltGL.Texture,
"The texture object wasn't instantiated correctly.");
ok(t._ref,
"The texture WebGL object wasn't created properly.");
isnot(t._id, -1,
"The texture id wasn't set properly.");
isnot(t.width, -1,
"The texture width wasn't set properly.");
isnot(t.height, -1,
"The texture height wasn't set properly.");
ok(t.loaded,
"The texture loaded flag wasn't set to true as it should.");
}

View File

@ -0,0 +1,61 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isApprox, isApproxVec, TiltMath */
"use strict";
function test() {
ok(isApprox(TiltMath.radians(30), 0.523598775),
"The radians() function didn't calculate the value correctly.");
ok(isApprox(TiltMath.degrees(0.5), 28.64788975),
"The degrees() function didn't calculate the value correctly.");
ok(isApprox(TiltMath.map(0.5, 0, 1, 0, 100), 50),
"The map() function didn't calculate the value correctly.");
is(TiltMath.isPowerOfTwo(32), true,
"The isPowerOfTwo() function didn't return the expected value.");
is(TiltMath.isPowerOfTwo(33), false,
"The isPowerOfTwo() function didn't return the expected value.");
ok(isApprox(TiltMath.nextPowerOfTwo(31), 32),
"The nextPowerOfTwo() function didn't calculate the 1st value correctly.");
ok(isApprox(TiltMath.nextPowerOfTwo(32), 32),
"The nextPowerOfTwo() function didn't calculate the 2nd value correctly.");
ok(isApprox(TiltMath.nextPowerOfTwo(33), 64),
"The nextPowerOfTwo() function didn't calculate the 3rd value correctly.");
ok(isApprox(TiltMath.clamp(5, 1, 3), 3),
"The clamp() function didn't calculate the 1st value correctly.");
ok(isApprox(TiltMath.clamp(5, 3, 1), 3),
"The clamp() function didn't calculate the 2nd value correctly.");
ok(isApprox(TiltMath.saturate(5), 1),
"The saturate() function didn't calculate the 1st value correctly.");
ok(isApprox(TiltMath.saturate(-5), 0),
"The saturate() function didn't calculate the 2nd value correctly.");
ok(isApproxVec(TiltMath.hex2rgba("#f00"), [1, 0, 0, 1]),
"The hex2rgba() function didn't calculate the 1st rgba values correctly.");
ok(isApproxVec(TiltMath.hex2rgba("#f008"), [1, 0, 0, 0.53]),
"The hex2rgba() function didn't calculate the 2nd rgba values correctly.");
ok(isApproxVec(TiltMath.hex2rgba("#ff0000"), [1, 0, 0, 1]),
"The hex2rgba() function didn't calculate the 3rd rgba values correctly.");
ok(isApproxVec(TiltMath.hex2rgba("#ff0000aa"), [1, 0, 0, 0.66]),
"The hex2rgba() function didn't calculate the 4th rgba values correctly.");
ok(isApproxVec(TiltMath.hex2rgba("rgba(255, 0, 0, 0.5)"), [1, 0, 0, 0.5]),
"The hex2rgba() function didn't calculate the 5th rgba values correctly.");
ok(isApproxVec(TiltMath.hex2rgba("rgb(255, 0, 0)"), [1, 0, 0, 1]),
"The hex2rgba() function didn't calculate the 6th rgba values correctly.");
}

View File

@ -0,0 +1,106 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isApproxVec, vec3, mat4 */
"use strict";
function test() {
let v1 = vec3.create();
ok(v1, "Should have created a vector with vec3.create().");
is(v1.length, 3, "A vec3 should have 3 elements.");
ok(isApproxVec(v1, [0, 0, 0]),
"When created, a vec3 should have the values default to 0.");
vec3.set([1, 2, 3], v1);
ok(isApproxVec(v1, [1, 2, 3]),
"The vec3.set() function didn't set the values correctly.");
vec3.zero(v1);
ok(isApproxVec(v1, [0, 0, 0]),
"The vec3.zero() function didn't set the values correctly.");
let v2 = vec3.create([4, 5, 6]);
ok(isApproxVec(v2, [4, 5, 6]),
"When cloning arrays, a vec3 should have the values copied.");
let v3 = vec3.create(v2);
ok(isApproxVec(v3, [4, 5, 6]),
"When cloning vectors, a vec3 should have the values copied.");
vec3.add(v2, v3);
ok(isApproxVec(v2, [8, 10, 12]),
"The vec3.add() function didn't set the x value correctly.");
vec3.subtract(v2, v3);
ok(isApproxVec(v2, [4, 5, 6]),
"The vec3.subtract() function didn't set the values correctly.");
vec3.negate(v2);
ok(isApproxVec(v2, [-4, -5, -6]),
"The vec3.negate() function didn't set the values correctly.");
vec3.scale(v2, -2);
ok(isApproxVec(v2, [8, 10, 12]),
"The vec3.scale() function didn't set the values correctly.");
vec3.normalize(v1);
ok(isApproxVec(v1, [0, 0, 0]),
"Normalizing a vector with zero length should return [0, 0, 0].");
vec3.normalize(v2);
ok(isApproxVec(v2, [
0.4558423161506653, 0.5698028802871704, 0.6837634444236755
]), "The vec3.normalize() function didn't set the values correctly.");
vec3.cross(v2, v3);
ok(isApproxVec(v2, [
5.960464477539063e-8, -1.1920928955078125e-7, 5.960464477539063e-8
]), "The vec3.cross() function didn't set the values correctly.");
vec3.dot(v2, v3);
ok(isApproxVec(v2, [
5.960464477539063e-8, -1.1920928955078125e-7, 5.960464477539063e-8
]), "The vec3.dot() function didn't set the values correctly.");
ok(isApproxVec([vec3.length(v2)], [1.4600096599955427e-7]),
"The vec3.length() function didn't calculate the value correctly.");
vec3.direction(v2, v3);
ok(isApproxVec(v2, [
-0.4558422863483429, -0.5698028802871704, -0.6837634444236755
]), "The vec3.direction() function didn't set the values correctly.");
vec3.lerp(v2, v3, 0.5);
ok(isApproxVec(v2, [
1.7720788717269897, 2.2150986194610596, 2.65811824798584
]), "The vec3.lerp() function didn't set the values correctly.");
vec3.project([100, 100, 10], [0, 0, 100, 100],
mat4.create(), mat4.perspective(45, 1, 0.1, 100), v1);
ok(isApproxVec(v1, [-1157.10693359375, 1257.10693359375, 0]),
"The vec3.project() function didn't set the values correctly.");
vec3.unproject([100, 100, 1], [0, 0, 100, 100],
mat4.create(), mat4.perspective(45, 1, 0.1, 100), v1);
ok(isApproxVec(v1, [
41.420406341552734, -41.420406341552734, -99.99771118164062
]), "The vec3.project() function didn't set the values correctly.");
let ray = vec3.createRay([10, 10, 0], [100, 100, 1], [0, 0, 100, 100],
mat4.create(), mat4.perspective(45, 1, 0.1, 100));
ok(isApproxVec(ray.origin, [
-0.03313708305358887, 0.03313708305358887, -0.1000000014901161
]), "The vec3.createRay() function didn't create the position correctly.");
ok(isApproxVec(ray.direction, [
0.35788586614428364, -0.35788586614428364, -0.862458934459091
]), "The vec3.createRay() function didn't create the direction correctly.");
is(vec3.str([0, 0, 0]), "[0, 0, 0]",
"The vec3.str() function didn't work properly.");
}

View File

@ -0,0 +1,35 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isApproxVec, mat3 */
"use strict";
function test() {
let m1 = mat3.create();
ok(m1, "Should have created a matrix with mat3.create().");
is(m1.length, 9, "A mat3 should have 9 elements.");
ok(isApproxVec(m1, [1, 0, 0, 0, 1, 0, 0, 0, 1]),
"When created, a mat3 should have the values default to identity.");
mat3.set([1, 2, 3, 4, 5, 6, 7, 8, 9], m1);
ok(isApproxVec(m1, [1, 2, 3, 4, 5, 6, 7, 8, 9]),
"The mat3.set() function didn't set the values correctly.");
mat3.transpose(m1);
ok(isApproxVec(m1, [1, 4, 7, 2, 5, 8, 3, 6, 9]),
"The mat3.transpose() function didn't set the values correctly.");
mat3.identity(m1);
ok(isApproxVec(m1, [1, 0, 0, 0, 1, 0, 0, 0, 1]),
"The mat3.identity() function didn't set the values correctly.");
let m2 = mat3.toMat4(m1);
ok(isApproxVec(m2, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
"The mat3.toMat4() function didn't set the values correctly.");
is(mat3.str([1, 2, 3, 4, 5, 6, 7, 8, 9]), "[1, 2, 3, 4, 5, 6, 7, 8, 9]",
"The mat3.str() function didn't work properly.");
}

View File

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isApprox, isApproxVec, mat4 */
"use strict";
function test() {
let m1 = mat4.create();
ok(m1, "Should have created a matrix with mat4.create().");
is(m1.length, 16, "A mat4 should have 16 elements.");
ok(isApproxVec(m1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
"When created, a mat4 should have the values default to identity.");
mat4.set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], m1);
ok(isApproxVec(m1, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
"The mat4.set() function didn't set the values correctly.");
mat4.transpose(m1);
ok(isApproxVec(m1, [1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]),
"The mat4.transpose() function didn't set the values correctly.");
mat4.identity(m1);
ok(isApproxVec(m1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
"The mat4.identity() function didn't set the values correctly.");
ok(isApprox(mat4.determinant(m1), 1),
"The mat4.determinant() function didn't calculate the value correctly.");
let m2 = mat4.inverse([1, 3, 1, 1, 1, 1, 2, 1, 2, 3, 4, 1, 1, 1, 1, 1]);
ok(isApproxVec(m2, [
-1, -3, 1, 3, 0.5, 0, 0, -0.5, 0, 1, 0, -1, 0.5, 2, -1, -0.5
]), "The mat4.inverse() function didn't calculate the values correctly.");
let m3 = mat4.toRotationMat([
1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]);
ok(isApproxVec(m3, [
1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 0, 0, 0, 1
]), "The mat4.toRotationMat() func. didn't calculate the values correctly.");
let m4 = mat4.toMat3([
1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]);
ok(isApproxVec(m4, [1, 5, 9, 2, 6, 10, 3, 7, 11]),
"The mat4.toMat3() function didn't set the values correctly.");
let m5 = mat4.toInverseMat3([
1, 3, 1, 1, 1, 1, 2, 1, 2, 3, 4, 1, 1, 1, 1, 1]);
ok(isApproxVec(m5, [2, 9, -5, 0, -2, 1, -1, -3, 2]),
"The mat4.toInverseMat3() function didn't set the values correctly.");
}

View File

@ -0,0 +1,103 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isApproxVec, mat4 */
"use strict";
function test() {
let m1 = mat4.create([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let m2 = mat4.create([
0, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]);
mat4.multiply(m1, m2);
ok(isApproxVec(m1, [
275, 302, 329, 356, 304, 336, 368, 400,
332, 368, 404, 440, 360, 400, 440, 480
]), "The mat4.multiply() function didn't set the values correctly.");
let v1 = mat4.multiplyVec3(m1, [1, 2, 3]);
ok(isApproxVec(v1, [2239, 2478, 2717]),
"The mat4.multiplyVec3() function didn't set the values correctly.");
let v2 = mat4.multiplyVec4(m1, [1, 2, 3, 0]);
ok(isApproxVec(v2, [1879, 2078, 2277, 2476]),
"The mat4.multiplyVec4() function didn't set the values correctly.");
mat4.translate(m1, [1, 2, 3]);
ok(isApproxVec(m1, [
275, 302, 329, 356, 304, 336, 368, 400,
332, 368, 404, 440, 2239, 2478, 2717, 2956
]), "The mat4.translate() function didn't set the values correctly.");
mat4.scale(m1, [1, 2, 3]);
ok(isApproxVec(m1, [
275, 302, 329, 356, 608, 672, 736, 800,
996, 1104, 1212, 1320, 2239, 2478, 2717, 2956
]), "The mat4.scale() function didn't set the values correctly.");
mat4.rotate(m1, 0.5, [1, 1, 1]);
ok(isApproxVec(m1, [
210.6123046875, 230.2483367919922, 249.88438415527344, 269.5204162597656,
809.8145751953125, 896.520751953125, 983.2268676757812,
1069.9329833984375, 858.5731201171875, 951.23095703125,
1043.8887939453125, 1136.5465087890625, 2239, 2478, 2717, 2956
]), "The mat4.rotate() function didn't set the values correctly.");
mat4.rotateX(m1, 0.5);
ok(isApproxVec(m1, [
210.6123046875, 230.2483367919922, 249.88438415527344, 269.5204162597656,
1122.301025390625, 1242.8154296875, 1363.3297119140625,
1483.843994140625, 365.2230224609375, 404.96875, 444.71453857421875,
484.460205078125, 2239, 2478, 2717, 2956
]), "The mat4.rotateX() function didn't set the values correctly.");
mat4.rotateY(m1, 0.5);
ok(isApproxVec(m1, [
9.732441902160645, 7.909564018249512, 6.086670875549316,
4.263822555541992, 1122.301025390625, 1242.8154296875, 1363.3297119140625,
1483.843994140625, 421.48626708984375, 465.78045654296875,
510.0746765136719, 554.3687744140625, 2239, 2478, 2717, 2956
]), "The mat4.rotateY() function didn't set the values correctly.");
mat4.rotateZ(m1, 0.5);
ok(isApproxVec(m1, [
546.6007690429688, 602.7787475585938, 658.9566650390625, 715.1345825195312,
980.245849609375, 1086.881103515625, 1193.5162353515625,
1300.1514892578125, 421.48626708984375, 465.78045654296875,
510.0746765136719, 554.3687744140625, 2239, 2478, 2717, 2956
]), "The mat4.rotateZ() function didn't set the values correctly.");
let m3 = mat4.frustum(0, 100, 200, 0, 0.1, 100);
ok(isApproxVec(m3, [
0.0020000000949949026, 0, 0, 0, 0, -0.0010000000474974513, 0, 0, 1, -1,
-1.0020020008087158, -1, 0, 0, -0.20020020008087158, 0
]), "The mat4.frustum() function didn't compute the values correctly.");
let m4 = mat4.perspective(45, 1.6, 0.1, 100);
ok(isApproxVec(m4, [1.5088834762573242, 0, 0, 0, 0, 2.4142136573791504, 0,
0, 0, 0, -1.0020020008087158, -1, 0, 0, -0.20020020008087158, 0
]), "The mat4.frustum() function didn't compute the values correctly.");
let m5 = mat4.ortho(0, 100, 200, 0, -1, 1);
ok(isApproxVec(m5, [
0.019999999552965164, 0, 0, 0, 0, -0.009999999776482582, 0, 0,
0, 0, -1, 0, -1, 1, 0, 1
]), "The mat4.ortho() function didn't compute the values correctly.");
let m6 = mat4.lookAt([1, 2, 3], [4, 5, 6], [0, 1, 0]);
ok(isApproxVec(m6, [
-0.7071067690849304, -0.40824830532073975, -0.5773502588272095, 0, 0,
0.8164966106414795, -0.5773502588272095, 0, 0.7071067690849304,
-0.40824830532073975, -0.5773502588272095, 0, -1.4142135381698608, 0,
3.464101552963257, 1
]), "The mat4.lookAt() function didn't compute the values correctly.");
is(mat4.str([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
"[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]",
"The mat4.str() function didn't work properly.");
}

View File

@ -0,0 +1,44 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isApprox, isApproxVec, quat4 */
"use strict";
function test() {
let q1 = quat4.create();
ok(q1, "Should have created a quaternion with quat4.create().");
is(q1.length, 4, "A quat4 should have 4 elements.");
ok(isApproxVec(q1, [0, 0, 0, 1]),
"When created, a vec3 should have the values default to identity.");
quat4.set([1, 2, 3, 4], q1);
ok(isApproxVec(q1, [1, 2, 3, 4]),
"The quat4.set() function didn't set the values correctly.");
quat4.identity(q1);
ok(isApproxVec(q1, [0, 0, 0, 1]),
"The quat4.identity() function didn't set the values correctly.");
quat4.set([5, 6, 7, 8], q1);
ok(isApproxVec(q1, [5, 6, 7, 8]),
"The quat4.set() function didn't set the values correctly.");
quat4.calculateW(q1);
ok(isApproxVec(q1, [5, 6, 7, -10.440306663513184]),
"The quat4.calculateW() function didn't compute the values correctly.");
quat4.inverse(q1);
ok(isApproxVec(q1, [-5, -6, -7, -10.440306663513184]),
"The quat4.inverse() function didn't compute the values correctly.");
quat4.normalize(q1);
ok(isApproxVec(q1, [
-0.33786869049072266, -0.40544241666793823,
-0.4730161726474762, -0.7054905295372009
]), "The quat4.normalize() function didn't compute the values correctly.");
ok(isApprox(quat4.length(q1), 1),
"The mat4.length() function didn't calculate the value correctly.");
}

View File

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isApproxVec, quat4 */
"use strict";
function test() {
let q1 = quat4.create([1, 2, 3, 4]);
let q2 = quat4.create([5, 6, 7, 8]);
quat4.multiply(q1, q2);
ok(isApproxVec(q1, [24, 48, 48, -6]),
"The quat4.multiply() function didn't set the values correctly.");
let v1 = quat4.multiplyVec3(q1, [9, 9, 9]);
ok(isApproxVec(v1, [5508, 54756, 59940]),
"The quat4.multiplyVec3() function didn't set the values correctly.");
let m1 = quat4.toMat3(q1);
ok(isApproxVec(m1, [
-9215, 2880, 1728, 1728, -5759, 4896, 2880, 4320, -5759
]), "The quat4.toMat3() function didn't set the values correctly.");
let m2 = quat4.toMat4(q1);
ok(isApproxVec(m2, [
-9215, 2880, 1728, 0, 1728, -5759, 4896, 0,
2880, 4320, -5759, 0, 0, 0, 0, 1
]), "The quat4.toMat4() function didn't set the values correctly.");
quat4.calculateW(q1);
quat4.calculateW(q2);
quat4.slerp(q1, q2, 0.5);
ok(isApproxVec(q1, [24, 48, 48, -71.99305725097656]),
"The quat4.slerp() function didn't set the values correctly.");
let q3 = quat4.fromAxis([1, 1, 1], 0.5);
ok(isApproxVec(q3, [
0.24740396440029144, 0.24740396440029144, 0.24740396440029144,
0.9689124226570129
]), "The quat4.fromAxis() function didn't compute the values correctly.");
let q4 = quat4.fromEuler(0.5, 0.75, 1.25);
ok(isApproxVec(q4, [
0.15310347080230713, 0.39433568716049194,
0.4540249705314636, 0.7841683626174927
]), "The quat4.fromEuler() function didn't compute the values correctly.");
is(quat4.str([1, 2, 3, 4]), "[1, 2, 3, 4]",
"The quat4.str() function didn't work properly.");
}

View File

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, TiltUtils */
"use strict";
function test() {
let prefs = TiltUtils.Preferences;
ok(prefs, "The TiltUtils.Preferences wasn't found.");
prefs.create("test-pref-bool", "boolean", true);
prefs.create("test-pref-int", "integer", 42);
prefs.create("test-pref-string", "string", "hello world!");
is(prefs.get("test-pref-bool", "boolean"), true,
"The boolean test preference wasn't initially set correctly.");
is(prefs.get("test-pref-int", "integer"), 42,
"The integer test preference wasn't initially set correctly.");
is(prefs.get("test-pref-string", "string"), "hello world!",
"The string test preference wasn't initially set correctly.");
prefs.set("test-pref-bool", "boolean", false);
prefs.set("test-pref-int", "integer", 24);
prefs.set("test-pref-string", "string", "!dlrow olleh");
is(prefs.get("test-pref-bool", "boolean"), false,
"The boolean test preference wasn't changed correctly.");
is(prefs.get("test-pref-int", "integer"), 24,
"The integer test preference wasn't changed correctly.");
is(prefs.get("test-pref-string", "string"), "!dlrow olleh",
"The string test preference wasn't changed correctly.");
is(typeof prefs.get("unknown-pref", "boolean"), "undefined",
"Inexisted boolean prefs should be handled as undefined.");
is(typeof prefs.get("unknown-pref", "integer"), "undefined",
"Inexisted integer prefs should be handled as undefined.");
is(typeof prefs.get("unknown-pref", "string"), "undefined",
"Inexisted string prefs should be handled as undefined.");
is(prefs.get("test-pref-bool", "integer"), null,
"The get() boolean function didn't handle incorrect types as it should.");
is(prefs.get("test-pref-bool", "string"), null,
"The get() boolean function didn't handle incorrect types as it should.");
is(prefs.get("test-pref-int", "boolean"), null,
"The get() integer function didn't handle incorrect types as it should.");
is(prefs.get("test-pref-int", "string"), null,
"The get() integer function didn't handle incorrect types as it should.");
is(prefs.get("test-pref-string", "boolean"), null,
"The get() string function didn't handle incorrect types as it should.");
is(prefs.get("test-pref-string", "integer"), null,
"The get() string function didn't handle incorrect types as it should.");
is(typeof prefs.get(), "undefined",
"The get() function should not work if not enough params are passed.");
is(typeof prefs.set(), "undefined",
"The set() function should not work if not enough params are passed.");
is(typeof prefs.create(), "undefined",
"The create() function should not work if not enough params are passed.");
is(prefs.get("test-pref-wrong-type", "wrong-type", 1), null,
"The get() function should expect only correct pref types.");
is(prefs.set("test-pref-wrong-type", "wrong-type", 1), false,
"The set() function should expect only correct pref types.");
is(prefs.create("test-pref-wrong-type", "wrong-type", 1), false,
"The create() function should expect only correct pref types.");
}

View File

@ -0,0 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, TiltUtils */
"use strict";
function test() {
let l10 = TiltUtils.L10n;
ok(l10, "The TiltUtils.L10n wasn't found.");
ok(l10.stringBundle,
"The necessary string bundle wasn't found.");
is(l10.get(), null,
"The get() function shouldn't work if no params are passed.");
is(l10.format(), null,
"The format() function shouldn't work if no params are passed.");
is(typeof l10.get("initWebGL.error"), "string",
"No valid string was returned from a corect name in the bundle.");
is(typeof l10.format("linkProgram.error", ["error"]), "string",
"No valid formatted string was returned from a name in the bundle.");
}

View File

@ -0,0 +1,20 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, TiltUtils */
"use strict";
function test() {
let dom = TiltUtils.DOM;
is(dom.parentNode, null,
"The parent node should not be initially set.");
dom.parentNode = {};
ok(dom.parentNode,
"The parent node should now be set.");
TiltUtils.clearCache();
is(dom.parentNode, null,
"The parent node should not be set after clearing the cache.");
}

View File

@ -0,0 +1,56 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, gBrowser, TiltUtils */
"use strict";
function test() {
let dom = TiltUtils.DOM;
ok(dom, "The TiltUtils.DOM wasn't found.");
is(dom.initCanvas(), null,
"The initCanvas() function shouldn't work if no parent node is set.");
dom.parentNode = gBrowser.parentNode;
ok(dom.parentNode,
"The necessary parent node wasn't found.");
let canvas = dom.initCanvas(null, {
append: true,
focusable: true,
width: 123,
height: 456,
id: "tilt-test-canvas"
});
is(canvas.width, 123,
"The test canvas doesn't have the correct width set.");
is(canvas.height, 456,
"The test canvas doesn't have the correct height set.");
is(canvas.getAttribute("tabindex"), 1,
"The test canvas tab index wasn't set correctly.");
is(canvas.getAttribute("id"), "tilt-test-canvas",
"The test canvas doesn't have the correct id set.");
ok(dom.parentNode.ownerDocument.getElementById(canvas.id),
"A canvas should be appended to the parent node if specified.");
canvas.parentNode.removeChild(canvas);
let canvas2 = dom.initCanvas(null, { id: "tilt-test-canvas2" });
is(canvas2.width, dom.parentNode.clientWidth,
"The second test canvas doesn't have the implicit width set.");
is(canvas2.height, dom.parentNode.clientHeight,
"The second test canvas doesn't have the implicit height set.");
is(canvas2.id, "tilt-test-canvas2",
"The second test canvas doesn't have the correct id set.");
is(dom.parentNode.ownerDocument.getElementById(canvas2.id), null,
"A canvas shouldn't be appended to the parent node if not specified.");
dom.parentNode = null;
is(dom.parentNode, null,
"The necessary parent node shouldn't be found anymore.");
}

View File

@ -0,0 +1,109 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, waitForExplicitFinish, finish, gBrowser, TiltUtils */
"use strict";
function init(callback) {
let iframe = gBrowser.ownerDocument.createElement("iframe");
iframe.addEventListener("load", function onLoad() {
iframe.removeEventListener("load", onLoad, true);
callback(iframe);
gBrowser.parentNode.removeChild(iframe);
finish();
}, true);
iframe.setAttribute("src", ["data:text/html,",
"<!DOCTYPE html>",
"<html>",
"<head>",
"<style>",
"</style>",
"<script>",
"</script>",
"</head>",
"<body style='margin: 0;'>",
"<div style='margin-top: 98px;" +
"margin-left: 76px;" +
"width: 123px;" +
"height: 456px;' id='test-div'>",
"<span></span>",
"</div>",
"</body>",
"</html>"
].join(""));
gBrowser.parentNode.appendChild(iframe);
}
function test() {
waitForExplicitFinish();
ok(TiltUtils, "The TiltUtils object doesn't exist.");
let dom = TiltUtils.DOM;
ok(dom, "The TiltUtils.DOM wasn't found.");
init(function(iframe) {
let cwDimensions = dom.getContentWindowDimensions(iframe.contentWindow);
is(cwDimensions.width - iframe.contentWindow.scrollMaxX,
iframe.contentWindow.innerWidth,
"The content window width wasn't calculated correctly.");
is(cwDimensions.height - iframe.contentWindow.scrollMaxY,
iframe.contentWindow.innerHeight,
"The content window height wasn't calculated correctly.");
let nodeCoordinates = dom.getNodeCoordinates(
iframe.contentDocument.getElementById("test-div"), iframe.contentWindow);
let frameOffset = dom.getFrameOffset(iframe);
is(nodeCoordinates.top, frameOffset.top + 98,
"The node coordinates top value wasn't calculated correctly.");
is(nodeCoordinates.left, frameOffset.left + 76,
"The node coordinates left value wasn't calculated correctly.");
is(nodeCoordinates.width, 123,
"The node coordinates width value wasn't calculated correctly.");
is(nodeCoordinates.height, 456,
"The node coordinates height value wasn't calculated correctly.");
let store = dom.traverse(iframe.contentWindow);
is(store.nodes.length, 7,
"The traverse() function didn't walk the correct number of nodes.");
is(store.info.length, 7,
"The traverse() function didn't examine the correct number of nodes.");
is(store.info[0].name, "html",
"the 1st traversed node isn't the expected one.");
is(store.info[0].depth, 0,
"the 1st traversed node doesn't have the expected depth.");
is(store.info[1].name, "head",
"the 2nd traversed node isn't the expected one.");
is(store.info[1].depth, 1,
"the 2nd traversed node doesn't have the expected depth.");
is(store.info[2].name, "body",
"the 3rd traversed node isn't the expected one.");
is(store.info[2].depth, 1,
"the 3rd traversed node doesn't have the expected depth.");
is(store.info[3].name, "style",
"the 4th traversed node isn't the expected one.");
is(store.info[3].depth, 2,
"the 4th traversed node doesn't have the expected depth.");
is(store.info[4].name, "script",
"the 5th traversed node isn't the expected one.");
is(store.info[4].depth, 2,
"the 5th traversed node doesn't have the expected depth.");
is(store.info[5].name, "div",
"the 6th traversed node isn't the expected one.");
is(store.info[5].depth, 2,
"the 6th traversed node doesn't have the expected depth.");
is(store.info[6].name, "span",
"the 7th traversed node isn't the expected one.");
is(store.info[6].depth, 3,
"the 7th traversed node doesn't have the expected depth.");
});
}

View File

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, isnot, gBrowser, TiltUtils */
"use strict";
let someObject = {
a: 1,
func: function()
{
this.b = 2;
}
};
let anotherObject = {
finalize: function()
{
someObject.c = 3;
}
};
function test() {
ok(TiltUtils, "The TiltUtils object doesn't exist.");
TiltUtils.bindObjectFunc(someObject, "", anotherObject);
someObject.func();
is(someObject.a, 1,
"The bindObjectFunc() messed the non-function members of the object.");
isnot(someObject.b, 2,
"The bindObjectFunc() didn't ignore the old scope correctly.");
is(anotherObject.b, 2,
"The bindObjectFunc() didn't set the new scope correctly.");
TiltUtils.destroyObject(anotherObject);
is(someObject.c, 3,
"The finalize function wasn't called when an object was destroyed.");
TiltUtils.destroyObject(someObject);
is(typeof someObject.a, "undefined",
"Not all members of the destroyed object were deleted.");
is(typeof someObject.func, "undefined",
"Not all function members of the destroyed object were deleted.");
}

View File

@ -0,0 +1,124 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global ok, is, info, isApproxVec, isTiltEnabled, isWebGLSupported, gBrowser*/
/*global TiltVisualizer */
"use strict";
function test() {
if (!isTiltEnabled()) {
info("Skipping notifications test because Tilt isn't enabled.");
return;
}
if (!isWebGLSupported()) {
info("Skipping visualizer test because WebGL isn't supported.");
return;
}
let webGLError = false;
let webGLLoad = false;
let visualizer = new TiltVisualizer({
parentNode: gBrowser.selectedBrowser.parentNode,
contentWindow: gBrowser.selectedBrowser.contentWindow,
requestAnimationFrame: window.mozRequestAnimationFrame,
onError: function onWebGLError()
{
webGLError = true;
},
onLoad: function onWebGLLoad()
{
webGLLoad = true;
}
});
ok(webGLError ^ webGLLoad,
"The WebGL context should either be created or not.");
if (webGLError) {
info("Skipping visualizer test because WebGL couldn't be initialized.");
return;
}
ok(visualizer.canvas,
"Visualizer constructor should have created a child canvas object.");
ok(visualizer.presenter,
"Visualizer constructor should have created a child presenter object.");
ok(visualizer.controller,
"Visualizer constructor should have created a child controller object.");
ok(visualizer.isInitialized(),
"The visualizer should have been initialized properly.");
ok(visualizer.presenter.isInitialized(),
"The visualizer presenter should have been initialized properly.");
ok(visualizer.controller.isInitialized(),
"The visualizer controller should have been initialized properly.");
testPresenter(visualizer.presenter);
testController(visualizer.controller);
visualizer.removeOverlay();
is(visualizer.canvas.parentNode, null,
"The visualizer canvas wasn't removed from the parent node.");
visualizer.cleanup();
is(visualizer.presenter, undefined,
"The visualizer presenter wasn't destroyed.");
is(visualizer.controller, undefined,
"The visualizer controller wasn't destroyed.");
is(visualizer.canvas, undefined,
"The visualizer canvas wasn't destroyed.");
}
function testPresenter(presenter) {
ok(presenter.renderer,
"The presenter renderer wasn't initialized properly.");
ok(presenter.visualizationProgram,
"The presenter visualizationProgram wasn't initialized properly.");
ok(presenter.texture,
"The presenter texture wasn't initialized properly.");
ok(!presenter.meshStacks,
"The presenter meshStacks shouldn't be initialized yet.");
ok(!presenter.meshWireframe,
"The presenter meshWireframe shouldn't be initialized yet.");
ok(presenter.traverseData,
"The presenter nodesInformation wasn't initialized properly.");
ok(presenter.highlight,
"The presenter highlight wasn't initialized properly.");
ok(presenter.highlight.disabled,
"The presenter highlight should be initially disabled");
ok(isApproxVec(presenter.highlight.v0, [0, 0, 0]),
"The presenter highlight first vertex should be initially zeroed.");
ok(isApproxVec(presenter.highlight.v1, [0, 0, 0]),
"The presenter highlight second vertex should be initially zeroed.");
ok(isApproxVec(presenter.highlight.v2, [0, 0, 0]),
"The presenter highlight third vertex should be initially zeroed.");
ok(isApproxVec(presenter.highlight.v3, [0, 0, 0]),
"The presenter highlight fourth vertex should be initially zeroed.");
ok(presenter.transforms,
"The presenter transforms wasn't initialized properly.");
ok(isApproxVec(presenter.transforms.offset, [0, 0, 0]),
"The presenter transforms offset should be initially zeroed.");
ok(isApproxVec(presenter.transforms.translation, [0, 0, 0]),
"The presenter transforms translation should be initially zeroed.");
ok(isApproxVec(presenter.transforms.rotation, [0, 0, 0, 1]),
"The presenter transforms rotation should be initially set to identity.");
presenter.setTranslation([1, 2, 3]);
presenter.setRotation([5, 6, 7, 8]);
ok(isApproxVec(presenter.transforms.translation, [1, 2, 3]),
"The presenter transforms translation wasn't modified as it should");
ok(isApproxVec(presenter.transforms.rotation, [5, 6, 7, 8]),
"The presenter transforms rotation wasn't modified as it should");
ok(presenter.redraw,
"The new transforms should have issued a redraw request.");
}
function testController(controller) {
ok(controller.arcball,
"The controller arcball wasn't initialized properly.");
ok(!controller.coordinates,
"The presenter meshWireframe shouldn't be initialized yet.");
}

View File

@ -0,0 +1,151 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global Services, Components, gBrowser, executeSoon */
/*global InspectorUI, Tilt, TiltGL, EPSILON */
"use strict";
Components.utils.import("resource:///modules/devtools/TiltGL.jsm");
Components.utils.import("resource:///modules/devtools/TiltMath.jsm");
Components.utils.import("resource:///modules/devtools/TiltUtils.jsm");
Components.utils.import("resource:///modules/devtools/TiltVisualizer.jsm");
const DEFAULT_HTML = "data:text/html," +
"<DOCTYPE html>" +
"<html>" +
"<head>" +
"<title>Three Laws</title>" +
"</head>" +
"<body>" +
"<div>" +
"A robot may not injure a human being or, through inaction, allow a" +
"human being to come to harm." +
"</div>" +
"<div>" +
"A robot must obey the orders given to it by human beings, except" +
"where such orders would conflict with the First Law." +
"</div>" +
"<div>" +
"A robot must protect its own existence as long as such protection" +
"does not conflict with the First or Second Laws." +
"</div>" +
"<body>" +
"</html>";
const INSPECTOR_OPENED = InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED;
const INSPECTOR_CLOSED = InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED;
const TILT_INITIALIZED = Tilt.NOTIFICATIONS.INITIALIZED;
const TILT_DESTROYED = Tilt.NOTIFICATIONS.DESTROYED;
const TILT_SHOWN = Tilt.NOTIFICATIONS.SHOWN;
const TILT_HIDDEN = Tilt.NOTIFICATIONS.HIDDEN;
const TILT_ENABLED = Services.prefs.getBoolPref("devtools.tilt.enabled");
const INSP_ENABLED = Services.prefs.getBoolPref("devtools.inspector.enabled");
function isTiltEnabled() {
return TILT_ENABLED && INSP_ENABLED;
}
function isWebGLSupported() {
return TiltGL.isWebGLSupported() &&
TiltGL.create3DContext(
document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"));
}
function isApprox(num1, num2) {
return Math.abs(num1 - num2) < EPSILON;
}
function isApproxVec(vec1, vec2) {
if (vec1.length !== vec2.length) {
return false;
}
for (let i = 0, len = vec1.length; i < len; i++) {
if (!isApprox(vec1[i], vec2[i])) {
return false;
}
}
return true;
}
function createCanvas() {
return gBrowser.parentNode
.ownerDocument
.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
}
function createTab(callback, location) {
let tab = gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
callback(tab);
}, true);
gBrowser.selectedBrowser.contentWindow.location = location || DEFAULT_HTML;
return tab;
}
function createTilt(callbacks, close) {
Services.obs.addObserver(onInspectorOpen, INSPECTOR_OPENED, false);
InspectorUI.toggleInspectorUI();
function onInspectorOpen() {
Services.obs.removeObserver(onInspectorOpen, INSPECTOR_OPENED);
executeSoon(function() {
if ("function" === typeof callbacks.onInspectorOpen) {
callbacks.onInspectorOpen();
}
Services.obs.addObserver(onTiltOpen, TILT_INITIALIZED, false);
Tilt.initialize();
});
}
function onTiltOpen() {
Services.obs.removeObserver(onTiltOpen, TILT_INITIALIZED);
executeSoon(function() {
if ("function" === typeof callbacks.onTiltOpen) {
callbacks.onTiltOpen();
}
if (close) {
Services.obs.addObserver(onTiltClose, TILT_DESTROYED, false);
Tilt.destroy(Tilt.currentWindowId);
}
});
}
function onTiltClose() {
Services.obs.removeObserver(onTiltClose, TILT_DESTROYED);
executeSoon(function() {
if ("function" === typeof callbacks.onTiltClose) {
callbacks.onTiltClose();
}
if (close) {
Services.obs.addObserver(onInspectorClose, INSPECTOR_CLOSED, false);
InspectorUI.closeInspectorUI();
}
});
}
function onInspectorClose() {
Services.obs.removeObserver(onInspectorClose, INSPECTOR_CLOSED);
executeSoon(function() {
if ("function" === typeof callbacks.onInspectorClose) {
callbacks.onInspectorClose();
}
if ("function" === typeof callbacks.onEnd) {
callbacks.onEnd();
}
});
}
}

View File

@ -217,6 +217,8 @@ can reach it easily. -->
<!ENTITY inspectButton.label "Inspect">
<!ENTITY inspectButton.accesskey "I">
<!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
<!ENTITY inspect3DButton.label "3D">
<!ENTITY inspect3DButton.accesskey "M">
<!ENTITY inspectStyleButton.label "Style">
<!ENTITY inspectStyleButton.accesskey "S">

View File

@ -0,0 +1,45 @@
# LOCALIZATION NOTE These strings are used inside the Tilt Inspector
# which is available from the Web Developer sub-menu -> 'Tilt'.
#
# The correct localization of this file might be to keep it in
# English, or another language commonly spoken among web developers.
# You want to make that choice consistent across the developer tools.
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (initTilt.error): Tilt requires WebGL capabilities, which
# are not available on every hardware. This message is displayed as an modal
# popup window when initialization fails because of unsupported hardware.
initTilt.error = Could not initialize Tilt, please check the\ntroubleshooting information available at http://get.webgl.org/troubleshooting
# LOCALIZATION NOTE (initWebGL.error): Tilt requires WebGL capabilities, which
# are not available on every hardware. This message is displayed in the console
# when initialization fails because of unsupported hardware.
initWebGL.error = Could not initialize the WebGL context, your hardware or drivers may not support it.
# LOCALIZATION NOTE (linkProgram.error): This error happens when the WebGL
# context can't link two compiled shader programs together. It is displayed in
# the Error Console.
linkProgram.error = Could not initialize shader program: %S
# LOCALIZATION NOTE (compileShader.source.error): This error is caused when the
# source (uri or path) of a shader is not the expected one. It is displayed in
# the Error Console.
compileShader.source.error = Bad shader source type (expected String).
# LOCALIATION NOTE (compileShader.type.error): There are two types of shader
# programs - vertex and fragment. At a shader initialization, if none of these
# two types is specified, this compile-time error is shown. It is displayed in
# the Error Console.
compileShader.type.error = Wrong shader type specified for: %S
# LOCALIZATION NOTE (compileShader.compile.error): If the shader source and
# type are correctly specified, there may be syntax errors in the shader code.
# If this is the case, this compile-time error is shown. It is displayed in
# the Error Console.
compileShader.compile.error = Shader compile status:\n%S
# LOCALIZATION NOTE (compileShader.source.error): This error is caused when the
# source (canvas or image) of a texture is not as expected. It is displayed in
# the Error Console.
initTexture.source.error = Bad texture source type (expected Image).

View File

@ -19,6 +19,7 @@
locale/browser/devtools/gclicommands.properties (%chrome/browser/devtools/gclicommands.properties)
locale/browser/devtools/webconsole.properties (%chrome/browser/devtools/webconsole.properties)
locale/browser/devtools/inspector.properties (%chrome/browser/devtools/inspector.properties)
locale/browser/devtools/tilt.properties (%chrome/browser/devtools/tilt.properties)
locale/browser/devtools/scratchpad.properties (%chrome/browser/devtools/scratchpad.properties)
locale/browser/devtools/scratchpad.dtd (%chrome/browser/devtools/scratchpad.dtd)
locale/browser/devtools/styleeditor.properties (%chrome/browser/devtools/styleeditor.properties)