From f841e96453d45a75404a3e18ea2205657da22449 Mon Sep 17 00:00:00 2001 From: Victor Porof Date: Wed, 25 Jan 2012 10:04:15 +0200 Subject: [PATCH] Bug 715647 - I want to be able to remove nodes from the Tilt view; r=rcampbell --- browser/devtools/tilt/TiltVisualizer.jsm | 112 ++++++++++++------ browser/devtools/tilt/TiltWorkerPicker.js | 5 + browser/devtools/tilt/test/Makefile.in | 5 + .../tilt/test/browser_tilt_picking.js | 52 ++++++++ .../tilt/test/browser_tilt_picking_delete.js | 67 +++++++++++ .../test/browser_tilt_picking_highlight01.js | 50 ++++++++ .../test/browser_tilt_picking_highlight02.js | 52 ++++++++ .../test/browser_tilt_picking_highlight03.js | 47 ++++++++ 8 files changed, 357 insertions(+), 33 deletions(-) create mode 100644 browser/devtools/tilt/test/browser_tilt_picking.js create mode 100644 browser/devtools/tilt/test/browser_tilt_picking_delete.js create mode 100644 browser/devtools/tilt/test/browser_tilt_picking_highlight01.js create mode 100644 browser/devtools/tilt/test/browser_tilt_picking_highlight02.js create mode 100644 browser/devtools/tilt/test/browser_tilt_picking_highlight03.js diff --git a/browser/devtools/tilt/TiltVisualizer.jsm b/browser/devtools/tilt/TiltVisualizer.jsm index 17f1f667b98..8a93fb8fce7 100644 --- a/browser/devtools/tilt/TiltVisualizer.jsm +++ b/browser/devtools/tilt/TiltVisualizer.jsm @@ -480,6 +480,11 @@ TiltVisualizer.Presenter.prototype = { this.maxTextureSize), format: "RGB" }); + + if ("function" === typeof this.onSetupTexture) { + this.onSetupTexture(); + this.onSetupTexture = null; + } }, /** @@ -502,6 +507,9 @@ TiltVisualizer.Presenter.prototype = { return; } + // save the mesh data for future use + this.meshData = aData; + // create the visualization mesh using the vertices, texture coordinates // and indices computed when traversing the document object model this.meshStacks = { @@ -524,19 +532,28 @@ TiltVisualizer.Presenter.prototype = { this.highlightNode(this.inspectorUI.selection); } - let zoom = TiltUtils.getDocumentZoom(); - let width = Math.min(aData.meshWidth * zoom, renderer.width); - let height = Math.min(aData.meshHeight * zoom, renderer.height); + if (!this._initialMeshConfiguration) { + this._initialMeshConfiguration = true; - // set the necessary mesh offsets - this.transforms.offset[0] = -width * 0.5; - this.transforms.offset[1] = -height * 0.5; + let zoom = TiltUtils.getDocumentZoom(); + let width = Math.min(aData.meshWidth * zoom, renderer.width); + let height = Math.min(aData.meshHeight * zoom, renderer.height); - // make sure the canvas is opaque now that the initialization is finished - this.canvas.style.background = TiltVisualizerStyle.canvas.background; + // set the necessary mesh offsets + this.transforms.offset[0] = -width * 0.5; + this.transforms.offset[1] = -height * 0.5; - this.drawVisualization(); - this.redraw = true; + // make sure the canvas is opaque now that the initialization is finished + this.canvas.style.background = TiltVisualizerStyle.canvas.background; + + this.drawVisualization(); + this.redraw = true; + } + + if ("function" === typeof this.onSetupMesh) { + this.onSetupMesh(); + this.onSetupMesh = null; + } }, /** @@ -626,9 +643,16 @@ TiltVisualizer.Presenter.prototype = { * the current horizontal coordinate of the mouse * @param {Number} y * the current vertical coordinate of the mouse + * @param {Object} aProperties + * an object containing the following properties: + * {Function} onpick: function to be called after picking succeeded + * {Function} onfail: function to be called after picking failed */ - highlightNodeAt: function TVP_highlightNodeAt(x, y) + highlightNodeAt: function TVP_highlightNodeAt(x, y, aProperties) { + // make sure the properties parameter is a valid object + aProperties = aProperties || {}; + // try to pick a mesh node using the current x, y coordinates this.pickNode(x, y, { @@ -638,6 +662,10 @@ TiltVisualizer.Presenter.prototype = { onfail: function TVP_onHighlightFail() { this.highlightNodeFor(-1); + + if ("function" === typeof aProperties.onfail) { + aProperties.onfail(); + } }.bind(this), /** @@ -649,6 +677,10 @@ TiltVisualizer.Presenter.prototype = { onpick: function TVP_onHighlightPick(aIntersection) { this.highlightNodeFor(aIntersection.index); + + if ("function" === typeof aProperties.onpick) { + aProperties.onpick(); + } }.bind(this) }); }, @@ -701,6 +733,32 @@ TiltVisualizer.Presenter.prototype = { this.contentWindow.pageYOffset > 0); }, + /** + * Deletes a node from the visualization mesh. + * + * @param {Number} aNodeIndex + * the index of the node in the this.traverseData array; + * if not specified, it will default to the current selection + */ + deleteNode: function TVP_deleteNode(aNodeIndex) + { + // we probably don't want to delete the html or body node.. just sayin' + if ((aNodeIndex = aNodeIndex || this._currentSelection) < 1) { + return; + } + + let renderer = this.renderer; + let meshData = this.meshData; + + for (let i = 0, k = 36 * aNodeIndex; i < 36; i++) { + meshData.vertices[i + k] = 0; + } + + this.meshStacks.vertices = new renderer.VertexBuffer(meshData.vertices, 3); + this.highlight.disabled = true; + this.redraw = true; + }, + /** * Picks a stacked dom node at the x and y screen coordinates and issues * a callback function with the found intersection. @@ -923,7 +981,6 @@ TiltVisualizer.Controller.prototype = { // bind commonly used mouse and keyboard events with the controller canvas.addEventListener("mousedown", this.onMouseDown, false); canvas.addEventListener("mouseup", this.onMouseUp, false); - canvas.addEventListener("click", this.onMouseClick, false); canvas.addEventListener("mousemove", this.onMouseMove, false); canvas.addEventListener("mouseover", this.onMouseOver, false); canvas.addEventListener("mouseout", this.onMouseOut, false); @@ -946,7 +1003,6 @@ TiltVisualizer.Controller.prototype = { canvas.removeEventListener("mousedown", this.onMouseDown, false); canvas.removeEventListener("mouseup", this.onMouseUp, false); - canvas.removeEventListener("click", this.onMouseClick, false); canvas.removeEventListener("mousemove", this.onMouseMove, false); canvas.removeEventListener("mouseover", this.onMouseOver, false); canvas.removeEventListener("mouseout", this.onMouseOut, false); @@ -979,10 +1035,11 @@ TiltVisualizer.Controller.prototype = { e.stopPropagation(); // calculate x and y coordinates using using the client and target offset + let button = e.which; this._downX = e.clientX - e.target.offsetLeft; this._downY = e.clientY - e.target.offsetTop; - this.arcball.mouseDown(this._downX, this._downY, e.which); + this.arcball.mouseDown(this._downX, this._downY, button); }, /** @@ -998,29 +1055,15 @@ TiltVisualizer.Controller.prototype = { let upX = e.clientX - e.target.offsetLeft; let upY = e.clientY - e.target.offsetTop; - this.arcball.mouseUp(upX, upY, button); - }, - - /** - * Called every time a mouse button is clicked. - */ - onMouseClick: function TVC_onMouseClick(e) - { - e.preventDefault(); - e.stopPropagation(); - - // calculate x and y coordinates using using the client and target offset - let button = e.which; - let clickX = e.clientX - e.target.offsetLeft; - let clickY = e.clientY - e.target.offsetTop; - // a click in Tilt is issued only when the mouse pointer stays in // relatively the same position - if (Math.abs(this._downX - clickX) < MOUSE_CLICK_THRESHOLD && - Math.abs(this._downY - clickY) < MOUSE_CLICK_THRESHOLD) { + if (Math.abs(this._downX - upX) < MOUSE_CLICK_THRESHOLD && + Math.abs(this._downY - upY) < MOUSE_CLICK_THRESHOLD) { - this.presenter.highlightNodeAt(clickX, clickY); + this.presenter.highlightNodeAt(upX, upY); } + + this.arcball.mouseUp(upX, upY, button); }, /** @@ -1098,6 +1141,9 @@ TiltVisualizer.Controller.prototype = { this.presenter.tiltUI.destroy(this.presenter.tiltUI.currentWindowId, 1); return; } + if (code === e.DOM_VK_X) { + this.presenter.deleteNode(); + } if (!e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) { e.preventDefault(); diff --git a/browser/devtools/tilt/TiltWorkerPicker.js b/browser/devtools/tilt/TiltWorkerPicker.js index 100a1f05211..0226e2e623b 100644 --- a/browser/devtools/tilt/TiltWorkerPicker.js +++ b/browser/devtools/tilt/TiltWorkerPicker.js @@ -81,6 +81,11 @@ self.onmessage = function TWP_onMessage(event) let v2b = [v2f[0], v2f[1], v2f[2] - thickness]; let v3b = [v3f[0], v3f[1], v3f[2] - thickness]; + // don't do anything with degenerate quads + if (!v0f[0] && !v1f[0] && !v2f[0] && !v3f[0]) { + continue; + } + // 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 diff --git a/browser/devtools/tilt/test/Makefile.in b/browser/devtools/tilt/test/Makefile.in index 6e0ca2d98b8..6f15f00b33d 100644 --- a/browser/devtools/tilt/test/Makefile.in +++ b/browser/devtools/tilt/test/Makefile.in @@ -73,6 +73,11 @@ _BROWSER_TEST_FILES = \ browser_tilt_math05.js \ browser_tilt_math06.js \ browser_tilt_math07.js \ + browser_tilt_picking.js \ + browser_tilt_picking_delete.js \ + browser_tilt_picking_highlight01.js \ + browser_tilt_picking_highlight02.js \ + browser_tilt_picking_highlight03.js \ browser_tilt_utils01.js \ browser_tilt_utils02.js \ browser_tilt_utils03.js \ diff --git a/browser/devtools/tilt/test/browser_tilt_picking.js b/browser/devtools/tilt/test/browser_tilt_picking.js new file mode 100644 index 00000000000..2f90ef2547d --- /dev/null +++ b/browser/devtools/tilt/test/browser_tilt_picking.js @@ -0,0 +1,52 @@ +/* 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, InspectorUI, TILT_DESTROYED */ +"use strict"; + +function test() { + if (!isTiltEnabled()) { + info("Skipping picking test because Tilt isn't enabled."); + return; + } + if (!isWebGLSupported()) { + info("Skipping picking test because WebGL isn't supported."); + return; + } + + waitForExplicitFinish(); + + createTab(function() { + createTilt({ + onTiltOpen: function(instance) + { + let presenter = instance.presenter; + let canvas = presenter.canvas; + + presenter.onSetupMesh = function() { + + presenter.pickNode(canvas.width / 2, canvas.height / 2, { + onpick: function(data) + { + ok(data.index > 0, + "Simply picking a node didn't work properly."); + ok(!presenter.highlight.disabled, + "After only picking a node, it shouldn't be highlighted."); + + Services.obs.addObserver(cleanup, TILT_DESTROYED, false); + InspectorUI.closeInspectorUI(); + } + }); + }; + } + }); + }); +} + +function cleanup() { + Services.obs.removeObserver(cleanup, TILT_DESTROYED); + gBrowser.removeCurrentTab(); + finish(); +} diff --git a/browser/devtools/tilt/test/browser_tilt_picking_delete.js b/browser/devtools/tilt/test/browser_tilt_picking_delete.js new file mode 100644 index 00000000000..fa7dc2cd2b0 --- /dev/null +++ b/browser/devtools/tilt/test/browser_tilt_picking_delete.js @@ -0,0 +1,67 @@ +/* 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, InspectorUI, TILT_DESTROYED */ +"use strict"; + +function test() { + if (!isTiltEnabled()) { + info("Skipping picking delete test because Tilt isn't enabled."); + return; + } + if (!isWebGLSupported()) { + info("Skipping picking delete test because WebGL isn't supported."); + return; + } + + waitForExplicitFinish(); + + createTab(function() { + createTilt({ + onTiltOpen: function(instance) + { + let presenter = instance.presenter; + let canvas = presenter.canvas; + + presenter.onSetupMesh = function() { + + presenter.highlightNodeAt(canvas.width / 2, canvas.height / 2, { + onpick: function() + { + ok(presenter._currentSelection > 0, + "Highlighting a node didn't work properly."); + ok(!presenter.highlight.disabled, + "After highlighting a node, it should be highlighted. D'oh."); + + presenter.deleteNode(); + + ok(presenter._currentSelection > 0, + "Deleting a node shouldn't change the current selection."); + ok(presenter.highlight.disabled, + "After deleting a node, it shouldn't be highlighted."); + + let nodeIndex = presenter._currentSelection; + let meshData = presenter.meshData; + + for (let i = 0, k = 36 * nodeIndex; i < 36; i++) { + is(meshData.vertices[i + k], 0, + "The stack vertices weren't degenerated properly."); + } + + Services.obs.addObserver(cleanup, TILT_DESTROYED, false); + InspectorUI.closeInspectorUI(); + } + }); + }; + } + }); + }); +} + +function cleanup() { + Services.obs.removeObserver(cleanup, TILT_DESTROYED); + gBrowser.removeCurrentTab(); + finish(); +} diff --git a/browser/devtools/tilt/test/browser_tilt_picking_highlight01.js b/browser/devtools/tilt/test/browser_tilt_picking_highlight01.js new file mode 100644 index 00000000000..277a5204f9c --- /dev/null +++ b/browser/devtools/tilt/test/browser_tilt_picking_highlight01.js @@ -0,0 +1,50 @@ +/* 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, InspectorUI, TILT_DESTROYED */ +"use strict"; + +function test() { + if (!isTiltEnabled()) { + info("Skipping highlight test because Tilt isn't enabled."); + return; + } + if (!isWebGLSupported()) { + info("Skipping highlight test because WebGL isn't supported."); + return; + } + + waitForExplicitFinish(); + + createTab(function() { + createTilt({ + onTiltOpen: function(instance) + { + let presenter = instance.presenter; + + presenter.onSetupMesh = function() { + let contentDocument = presenter.contentWindow.document; + let body = contentDocument.getElementsByTagName("body")[0]; + + presenter.highlightNode(body); + + ok(presenter._currentSelection > 0, + "Highlighting a node didn't work properly."); + ok(!presenter.highlight.disabled, + "After highlighting a node, it should be highlighted. D'oh."); + + Services.obs.addObserver(cleanup, TILT_DESTROYED, false); + InspectorUI.closeInspectorUI(); + }; + } + }); + }); +} + +function cleanup() { + Services.obs.removeObserver(cleanup, TILT_DESTROYED); + gBrowser.removeCurrentTab(); + finish(); +} diff --git a/browser/devtools/tilt/test/browser_tilt_picking_highlight02.js b/browser/devtools/tilt/test/browser_tilt_picking_highlight02.js new file mode 100644 index 00000000000..70adeb62a61 --- /dev/null +++ b/browser/devtools/tilt/test/browser_tilt_picking_highlight02.js @@ -0,0 +1,52 @@ +/* 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, InspectorUI, TILT_DESTROYED */ +"use strict"; + +function test() { + if (!isTiltEnabled()) { + info("Skipping highlight test because Tilt isn't enabled."); + return; + } + if (!isWebGLSupported()) { + info("Skipping highlight test because WebGL isn't supported."); + return; + } + + waitForExplicitFinish(); + + createTab(function() { + createTilt({ + onTiltOpen: function(instance) + { + let presenter = instance.presenter; + let canvas = presenter.canvas; + + presenter.onSetupMesh = function() { + + presenter.highlightNodeAt(canvas.width / 2, canvas.height / 2, { + onpick: function() + { + ok(presenter._currentSelection > 0, + "Highlighting a node didn't work properly."); + ok(!presenter.highlight.disabled, + "After highlighting a node, it should be highlighted. D'oh."); + + Services.obs.addObserver(cleanup, TILT_DESTROYED, false); + InspectorUI.closeInspectorUI(); + } + }); + }; + } + }); + }); +} + +function cleanup() { + Services.obs.removeObserver(cleanup, TILT_DESTROYED); + gBrowser.removeCurrentTab(); + finish(); +} diff --git a/browser/devtools/tilt/test/browser_tilt_picking_highlight03.js b/browser/devtools/tilt/test/browser_tilt_picking_highlight03.js new file mode 100644 index 00000000000..0d6c8a1fe5b --- /dev/null +++ b/browser/devtools/tilt/test/browser_tilt_picking_highlight03.js @@ -0,0 +1,47 @@ +/* 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, InspectorUI, TILT_DESTROYED */ +"use strict"; + +function test() { + if (!isTiltEnabled()) { + info("Skipping highlight test because Tilt isn't enabled."); + return; + } + if (!isWebGLSupported()) { + info("Skipping highlight test because WebGL isn't supported."); + return; + } + + waitForExplicitFinish(); + + createTab(function() { + createTilt({ + onTiltOpen: function(instance) + { + let presenter = instance.presenter; + + presenter.onSetupMesh = function() { + presenter.highlightNodeFor(1); + + ok(presenter._currentSelection > 0, + "Highlighting a node didn't work properly."); + ok(!presenter.highlight.disabled, + "After highlighting a node, it should be highlighted. D'oh."); + + Services.obs.addObserver(cleanup, TILT_DESTROYED, false); + InspectorUI.closeInspectorUI(); + }; + } + }); + }); +} + +function cleanup() { + Services.obs.removeObserver(cleanup, TILT_DESTROYED); + gBrowser.removeCurrentTab(); + finish(); +}