summaryrefslogtreecommitdiffstats
path: root/devtools/client/shadereditor/test
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/shadereditor/test')
-rw-r--r--devtools/client/shadereditor/test/.eslintrc.js6
-rw-r--r--devtools/client/shadereditor/test/browser.ini47
-rw-r--r--devtools/client/shadereditor/test/browser_se_aaa_run_first_leaktest.js17
-rw-r--r--devtools/client/shadereditor/test/browser_se_bfcache.js60
-rw-r--r--devtools/client/shadereditor/test/browser_se_editors-contents.js30
-rw-r--r--devtools/client/shadereditor/test/browser_se_editors-error-gutter.js156
-rw-r--r--devtools/client/shadereditor/test/browser_se_editors-error-tooltip.js56
-rw-r--r--devtools/client/shadereditor/test/browser_se_editors-lazy-init.js34
-rw-r--r--devtools/client/shadereditor/test/browser_se_first-run.js43
-rw-r--r--devtools/client/shadereditor/test/browser_se_navigation.js71
-rw-r--r--devtools/client/shadereditor/test/browser_se_programs-blackbox-01.js169
-rw-r--r--devtools/client/shadereditor/test/browser_se_programs-blackbox-02.js63
-rw-r--r--devtools/client/shadereditor/test/browser_se_programs-cache.js41
-rw-r--r--devtools/client/shadereditor/test/browser_se_programs-highlight-01.js93
-rw-r--r--devtools/client/shadereditor/test/browser_se_programs-highlight-02.js49
-rw-r--r--devtools/client/shadereditor/test/browser_se_programs-list.js87
-rw-r--r--devtools/client/shadereditor/test/browser_se_shaders-edit-01.js73
-rw-r--r--devtools/client/shadereditor/test/browser_se_shaders-edit-02.js74
-rw-r--r--devtools/client/shadereditor/test/browser_se_shaders-edit-03.js85
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-01.js16
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-02.js21
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-03.js26
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-04.js27
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-05.js27
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-06.js64
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-07.js61
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-08.js37
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-09.js89
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-10.js44
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-11.js25
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-12.js27
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-13.js67
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-14.js46
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-15.js133
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-16.js141
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-17.js46
-rw-r--r--devtools/client/shadereditor/test/browser_webgl-actor-test-18.js31
-rw-r--r--devtools/client/shadereditor/test/doc_blended-geometry.html136
-rw-r--r--devtools/client/shadereditor/test/doc_multiple-contexts.html112
-rw-r--r--devtools/client/shadereditor/test/doc_overlapping-geometry.html120
-rw-r--r--devtools/client/shadereditor/test/doc_shader-order.html83
-rw-r--r--devtools/client/shadereditor/test/doc_simple-canvas.html125
-rw-r--r--devtools/client/shadereditor/test/head.js292
43 files changed, 3050 insertions, 0 deletions
diff --git a/devtools/client/shadereditor/test/.eslintrc.js b/devtools/client/shadereditor/test/.eslintrc.js
new file mode 100644
index 000000000..8d15a76d9
--- /dev/null
+++ b/devtools/client/shadereditor/test/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the shared list of defined globals for mochitests.
+ "extends": "../../../.eslintrc.mochitests.js"
+};
diff --git a/devtools/client/shadereditor/test/browser.ini b/devtools/client/shadereditor/test/browser.ini
new file mode 100644
index 000000000..b26bc3a74
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser.ini
@@ -0,0 +1,47 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+ doc_blended-geometry.html
+ doc_multiple-contexts.html
+ doc_overlapping-geometry.html
+ doc_shader-order.html
+ doc_simple-canvas.html
+ head.js
+
+[browser_se_aaa_run_first_leaktest.js]
+[browser_se_bfcache.js]
+skip-if = true # Bug 942473, caused by Bug 940541
+[browser_se_editors-contents.js]
+[browser_se_editors-error-gutter.js]
+[browser_se_editors-error-tooltip.js]
+[browser_se_editors-lazy-init.js]
+[browser_se_first-run.js]
+[browser_se_navigation.js]
+[browser_se_programs-blackbox-01.js]
+[browser_se_programs-blackbox-02.js]
+[browser_se_programs-cache.js]
+[browser_se_programs-highlight-01.js]
+[browser_se_programs-highlight-02.js]
+[browser_se_programs-list.js]
+[browser_se_shaders-edit-01.js]
+[browser_se_shaders-edit-02.js]
+[browser_se_shaders-edit-03.js]
+[browser_webgl-actor-test-01.js]
+[browser_webgl-actor-test-02.js]
+[browser_webgl-actor-test-03.js]
+[browser_webgl-actor-test-04.js]
+[browser_webgl-actor-test-05.js]
+[browser_webgl-actor-test-06.js]
+[browser_webgl-actor-test-07.js]
+[browser_webgl-actor-test-08.js]
+[browser_webgl-actor-test-09.js]
+[browser_webgl-actor-test-10.js]
+[browser_webgl-actor-test-11.js]
+[browser_webgl-actor-test-12.js]
+[browser_webgl-actor-test-13.js]
+[browser_webgl-actor-test-14.js]
+[browser_webgl-actor-test-15.js]
+[browser_webgl-actor-test-16.js]
+[browser_webgl-actor-test-17.js]
+[browser_webgl-actor-test-18.js]
diff --git a/devtools/client/shadereditor/test/browser_se_aaa_run_first_leaktest.js b/devtools/client/shadereditor/test/browser_se_aaa_run_first_leaktest.js
new file mode 100644
index 000000000..6efe51091
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_aaa_run_first_leaktest.js
@@ -0,0 +1,17 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the shader editor leaks on initialization and sudden destruction.
+ * You can also use this initialization format as a template for other tests.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+
+ ok(target, "Should have a target available.");
+ ok(panel, "Should have a panel available.");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_bfcache.js b/devtools/client/shadereditor/test/browser_se_bfcache.js
new file mode 100644
index 000000000..2b568e3fe
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_bfcache.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the shader editor works with bfcache.
+ */
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+ let { gFront, $, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+ // Attach frame scripts if in e10s to perform
+ // history navigation via the content
+ loadFrameScripts();
+
+ let reloaded = reload(target);
+ let firstProgram = yield once(gFront, "program-linked");
+ yield reloaded;
+
+ let navigated = navigate(target, MULTIPLE_CONTEXTS_URL);
+ let [secondProgram, thirdProgram] = yield getPrograms(gFront, 2);
+ yield navigated;
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ yield navigateInHistory(target, "back", "will-navigate");
+ yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED);
+ yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
+
+ is($("#content").hidden, false,
+ "The tool's content should not be hidden.");
+ is(ShadersListView.itemCount, 1,
+ "The shaders list contains one entry after navigating back.");
+ is(ShadersListView.selectedIndex, 0,
+ "The shaders list has a correct selection after navigating back.");
+
+ is(vsEditor.getText().indexOf("gl_Position"), 170,
+ "The vertex shader editor contains the correct text.");
+ is(fsEditor.getText().indexOf("gl_FragColor"), 97,
+ "The fragment shader editor contains the correct text.");
+
+ yield navigateInHistory(target, "forward", "will-navigate");
+ yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED);
+ yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
+
+ is($("#content").hidden, false,
+ "The tool's content should not be hidden.");
+ is(ShadersListView.itemCount, 2,
+ "The shaders list contains two entries after navigating forward.");
+ is(ShadersListView.selectedIndex, 0,
+ "The shaders list has a correct selection after navigating forward.");
+
+ is(vsEditor.getText().indexOf("gl_Position"), 100,
+ "The vertex shader editor contains the correct text.");
+ is(fsEditor.getText().indexOf("gl_FragColor"), 89,
+ "The fragment shader editor contains the correct text.");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_editors-contents.js b/devtools/client/shadereditor/test/browser_se_editors-contents.js
new file mode 100644
index 000000000..fdf2612ed
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_editors-contents.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the editors contain the correct text when a program
+ * becomes available.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+ let { gFront, ShadersEditorsView, EVENTS } = panel.panelWin;
+
+ reload(target);
+ yield promise.all([
+ once(gFront, "program-linked"),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+
+ is(vsEditor.getText().indexOf("gl_Position"), 170,
+ "The vertex shader editor contains the correct text.");
+ is(fsEditor.getText().indexOf("gl_FragColor"), 97,
+ "The fragment shader editor contains the correct text.");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_editors-error-gutter.js b/devtools/client/shadereditor/test/browser_se_editors-error-gutter.js
new file mode 100644
index 000000000..439d6074f
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_editors-error-gutter.js
@@ -0,0 +1,156 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if error indicators are shown in the editor's gutter and text area
+ * when there's a shader compilation error.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+ let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+ yield promise.all([
+ once(gFront, "program-linked"),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
+ let [, vertError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+ checkHasVertFirstError(true, vertError);
+ checkHasVertSecondError(false, vertError);
+ info("Error marks added in the vertex shader editor.");
+
+ vsEditor.insertText(" ", { line: 1, ch: 0 });
+ yield once(panel.panelWin, EVENTS.EDITOR_ERROR_MARKERS_REMOVED);
+ is(vsEditor.getText(1), " precision lowp float;", "Typed space.");
+ checkHasVertFirstError(false, vertError);
+ checkHasVertSecondError(false, vertError);
+ info("Error marks removed while typing in the vertex shader editor.");
+
+ [, vertError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+ checkHasVertFirstError(true, vertError);
+ checkHasVertSecondError(false, vertError);
+ info("Error marks were re-added after recompiling the vertex shader.");
+
+ fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
+ let [, fragError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+ checkHasVertFirstError(true, vertError);
+ checkHasVertSecondError(false, vertError);
+ checkHasFragError(true, fragError);
+ info("Error marks added in the fragment shader editor.");
+
+ fsEditor.insertText(" ", { line: 1, ch: 0 });
+ yield once(panel.panelWin, EVENTS.EDITOR_ERROR_MARKERS_REMOVED);
+ is(fsEditor.getText(1), " precision lowp float;", "Typed space.");
+ checkHasVertFirstError(true, vertError);
+ checkHasVertSecondError(false, vertError);
+ checkHasFragError(false, fragError);
+ info("Error marks removed while typing in the fragment shader editor.");
+
+ [, fragError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+ checkHasVertFirstError(true, vertError);
+ checkHasVertSecondError(false, vertError);
+ checkHasFragError(true, fragError);
+ info("Error marks were re-added after recompiling the fragment shader.");
+
+ vsEditor.replaceText("2", { line: 3, ch: 19 }, { line: 3, ch: 20 });
+ yield once(panel.panelWin, EVENTS.EDITOR_ERROR_MARKERS_REMOVED);
+ checkHasVertFirstError(false, vertError);
+ checkHasVertSecondError(false, vertError);
+ checkHasFragError(true, fragError);
+ info("Error marks removed while typing in the vertex shader editor again.");
+
+ [, vertError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+ checkHasVertFirstError(true, vertError);
+ checkHasVertSecondError(true, vertError);
+ checkHasFragError(true, fragError);
+ info("Error marks were re-added after recompiling the fragment shader again.");
+
+ yield teardown(panel);
+ finish();
+
+ function checkHasVertFirstError(bool, error) {
+ ok(error, "Vertex shader compiled with errors.");
+ isnot(error.link, "", "The linkage status should not be empty.");
+
+ let line = 7;
+ info("Checking first vertex shader error on line " + line + "...");
+
+ is(vsEditor.hasMarker(line, "errors", "error"), bool,
+ "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter.");
+ is(vsEditor.hasLineClass(line, "error-line"), bool,
+ "Error style is " + (bool ? "" : "not ") + "applied to the faulty line.");
+
+ let parsed = ShadersEditorsView._errors.vs;
+ is(parsed.length >= 1, bool,
+ "There's " + (bool ? ">= 1" : "< 1") + " parsed vertex shader error(s).");
+
+ if (bool) {
+ is(parsed[0].line, line,
+ "The correct line was parsed.");
+ is(parsed[0].messages.length, 2,
+ "There are 2 parsed messages.");
+ ok(parsed[0].messages[0].includes("'constructor' : too many arguments"),
+ "The correct first message was parsed.");
+ ok(parsed[0].messages[1].includes("'assign' : cannot convert from"),
+ "The correct second message was parsed.");
+ }
+ }
+
+ function checkHasVertSecondError(bool, error) {
+ ok(error, "Vertex shader compiled with errors.");
+ isnot(error.link, "", "The linkage status should not be empty.");
+
+ let line = 8;
+ info("Checking second vertex shader error on line " + line + "...");
+
+ is(vsEditor.hasMarker(line, "errors", "error"), bool,
+ "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter.");
+ is(vsEditor.hasLineClass(line, "error-line"), bool,
+ "Error style is " + (bool ? "" : "not ") + "applied to the faulty line.");
+
+ let parsed = ShadersEditorsView._errors.vs;
+ is(parsed.length >= 2, bool,
+ "There's " + (bool ? ">= 2" : "< 2") + " parsed vertex shader error(s).");
+
+ if (bool) {
+ is(parsed[1].line, line,
+ "The correct line was parsed.");
+ is(parsed[1].messages.length, 1,
+ "There is 1 parsed message.");
+ ok(parsed[1].messages[0].includes("'assign' : cannot convert from"),
+ "The correct message was parsed.");
+ }
+ }
+
+ function checkHasFragError(bool, error) {
+ ok(error, "Fragment shader compiled with errors.");
+ isnot(error.link, "", "The linkage status should not be empty.");
+
+ let line = 5;
+ info("Checking first vertex shader error on line " + line + "...");
+
+ is(fsEditor.hasMarker(line, "errors", "error"), bool,
+ "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter.");
+ is(fsEditor.hasLineClass(line, "error-line"), bool,
+ "Error style is " + (bool ? "" : "not ") + "applied to the faulty line.");
+
+ let parsed = ShadersEditorsView._errors.fs;
+ is(parsed.length >= 1, bool,
+ "There's " + (bool ? ">= 2" : "< 1") + " parsed fragment shader error(s).");
+
+ if (bool) {
+ is(parsed[0].line, line,
+ "The correct line was parsed.");
+ is(parsed[0].messages.length, 1,
+ "There is 1 parsed message.");
+ ok(parsed[0].messages[0].includes("'constructor' : too many arguments"),
+ "The correct message was parsed.");
+ }
+ }
+}
diff --git a/devtools/client/shadereditor/test/browser_se_editors-error-tooltip.js b/devtools/client/shadereditor/test/browser_se_editors-error-tooltip.js
new file mode 100644
index 000000000..1ce31bebf
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_editors-error-tooltip.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if error tooltips can be opened from the editor's gutter when there's
+ * a shader compilation error.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+ let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+ yield promise.all([
+ once(gFront, "program-linked"),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
+ yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
+
+ // Synthesizing 'mouseover' events doesn't work, hack around this by
+ // manually calling the event listener with the expected arguments.
+ let editorDocument = vsEditor.container.contentDocument;
+ let marker = editorDocument.querySelector(".error");
+ let parsed = ShadersEditorsView._errors.vs[0].messages;
+ ShadersEditorsView._onMarkerMouseOver(7, marker, parsed);
+
+ let tooltip = marker._markerErrorsTooltip;
+ ok(tooltip, "A tooltip was created successfully.");
+
+ let content = tooltip.content;
+ ok(tooltip.content,
+ "Some tooltip's content was set.");
+ ok(tooltip.content.className.includes("devtools-tooltip-simple-text-container"),
+ "The tooltip's content container was created correctly.");
+
+ let messages = content.childNodes;
+ is(messages.length, 2,
+ "There are two messages displayed in the tooltip.");
+ ok(messages[0].className.includes("devtools-tooltip-simple-text"),
+ "The first message was created correctly.");
+ ok(messages[1].className.includes("devtools-tooltip-simple-text"),
+ "The second message was created correctly.");
+
+ ok(messages[0].textContent.includes("'constructor' : too many arguments"),
+ "The first message contains the correct text.");
+ ok(messages[1].textContent.includes("'assign' : cannot convert"),
+ "The second message contains the correct text.");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_editors-lazy-init.js b/devtools/client/shadereditor/test/browser_se_editors-lazy-init.js
new file mode 100644
index 000000000..b2d9d888e
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_editors-lazy-init.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if source editors are lazily initialized.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+ let { gFront, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+ yield once(gFront, "program-linked");
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ ok(vsEditor, "A vertex shader editor was initialized.");
+ ok(fsEditor, "A fragment shader editor was initialized.");
+
+ isnot(vsEditor, fsEditor,
+ "The vertex shader editor is distinct from the fragment shader editor.");
+
+ let vsEditor2 = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor2 = yield ShadersEditorsView._getEditor("fs");
+
+ is(vsEditor, vsEditor2,
+ "The vertex shader editor instances are cached.");
+ is(fsEditor, fsEditor2,
+ "The fragment shader editor instances are cached.");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_first-run.js b/devtools/client/shadereditor/test/browser_se_first-run.js
new file mode 100644
index 000000000..33239bcbe
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_first-run.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the shader editor shows the appropriate UI when opened.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+ let { gFront, $ } = panel.panelWin;
+
+ is($("#reload-notice").hidden, false,
+ "The 'reload this page' notice should initially be visible.");
+ is($("#waiting-notice").hidden, true,
+ "The 'waiting for a WebGL context' notice should initially be hidden.");
+ is($("#content").hidden, true,
+ "The tool's content should initially be hidden.");
+
+ let navigating = once(target, "will-navigate");
+ let linked = once(gFront, "program-linked");
+ reload(target);
+
+ yield navigating;
+
+ is($("#reload-notice").hidden, true,
+ "The 'reload this page' notice should be hidden when navigating.");
+ is($("#waiting-notice").hidden, false,
+ "The 'waiting for a WebGL context' notice should be visible when navigating.");
+ is($("#content").hidden, true,
+ "The tool's content should still be hidden.");
+
+ yield linked;
+
+ is($("#reload-notice").hidden, true,
+ "The 'reload this page' notice should be hidden after linking.");
+ is($("#waiting-notice").hidden, true,
+ "The 'waiting for a WebGL context' notice should be hidden after linking.");
+ is($("#content").hidden, false,
+ "The tool's content should not be hidden anymore.");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_navigation.js b/devtools/client/shadereditor/test/browser_se_navigation.js
new file mode 100644
index 000000000..f1adc3e76
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_navigation.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests target navigations are handled correctly in the UI.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+ let { gFront, $, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+ yield promise.all([
+ once(gFront, "program-linked"),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ is($("#reload-notice").hidden, true,
+ "The 'reload this page' notice should be hidden after linking.");
+ is($("#waiting-notice").hidden, true,
+ "The 'waiting for a WebGL context' notice should be visible after linking.");
+ is($("#content").hidden, false,
+ "The tool's content should not be hidden anymore.");
+
+ is(ShadersListView.itemCount, 1,
+ "The shaders list contains one entry.");
+ is(ShadersListView.selectedItem, ShadersListView.items[0],
+ "The shaders list has a correct item selected.");
+ is(ShadersListView.selectedIndex, 0,
+ "The shaders list has a correct index selected.");
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ is(vsEditor.getText().indexOf("gl_Position"), 170,
+ "The vertex shader editor contains the correct text.");
+ is(fsEditor.getText().indexOf("gl_FragColor"), 97,
+ "The fragment shader editor contains the correct text.");
+
+ let navigating = once(target, "will-navigate");
+ let navigated = once(target, "will-navigate");
+ navigate(target, "about:blank");
+
+ yield promise.all([navigating, once(panel.panelWin, EVENTS.UI_RESET) ]);
+
+ is($("#reload-notice").hidden, true,
+ "The 'reload this page' notice should be hidden while navigating.");
+ is($("#waiting-notice").hidden, false,
+ "The 'waiting for a WebGL context' notice should be visible while navigating.");
+ is($("#content").hidden, true,
+ "The tool's content should be hidden now that there's no WebGL content.");
+
+ is(ShadersListView.itemCount, 0,
+ "The shaders list should be empty.");
+ is(ShadersListView.selectedItem, null,
+ "The shaders list has no correct item.");
+ is(ShadersListView.selectedIndex, -1,
+ "The shaders list has a negative index.");
+
+ yield navigated;
+
+ is($("#reload-notice").hidden, true,
+ "The 'reload this page' notice should still be hidden after navigating.");
+ is($("#waiting-notice").hidden, false,
+ "The 'waiting for a WebGL context' notice should still be visible after navigating.");
+ is($("#content").hidden, true,
+ "The tool's content should be still hidden since there's no WebGL content.");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_programs-blackbox-01.js b/devtools/client/shadereditor/test/browser_se_programs-blackbox-01.js
new file mode 100644
index 000000000..4c8199c22
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_programs-blackbox-01.js
@@ -0,0 +1,169 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if blackboxing a program works properly.
+ */
+
+function* ifWebGLSupported() {
+ let { target, debuggee, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL);
+ let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+ once(panel.panelWin, EVENTS.SHADER_COMPILED).then(() => {
+ ok(false, "No shaders should be publicly compiled during this test.");
+ });
+
+ reload(target);
+ let [[firstProgramActor, secondProgramActor]] = yield promise.all([
+ getPrograms(gFront, 2),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ vsEditor.once("change", () => {
+ ok(false, "The vertex shader source was unexpectedly changed.");
+ });
+ fsEditor.once("change", () => {
+ ok(false, "The fragment shader source was unexpectedly changed.");
+ });
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN).then(() => {
+ ok(false, "No sources should be changed form this point onward.");
+ });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+
+ ok(!ShadersListView.selectedAttachment.isBlackBoxed,
+ "The first program should not be blackboxed yet.");
+ is(getBlackBoxCheckbox(panel, 0).checked, true,
+ "The first blackbox checkbox should be initially checked.");
+ ok(!ShadersListView.attachments[1].isBlackBoxed,
+ "The second program should not be blackboxed yet.");
+ is(getBlackBoxCheckbox(panel, 1).checked, true,
+ "The second blackbox checkbox should be initially checked.");
+
+ getBlackBoxCheckbox(panel, 0).click();
+
+ ok(ShadersListView.selectedAttachment.isBlackBoxed,
+ "The first program should now be blackboxed.");
+ is(getBlackBoxCheckbox(panel, 0).checked, false,
+ "The first blackbox checkbox should now be unchecked.");
+ ok(!ShadersListView.attachments[1].isBlackBoxed,
+ "The second program should still not be blackboxed.");
+ is(getBlackBoxCheckbox(panel, 1).checked, true,
+ "The second blackbox checkbox should still be checked.");
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The first program was correctly blackboxed.");
+
+ getBlackBoxCheckbox(panel, 1).click();
+
+ ok(ShadersListView.selectedAttachment.isBlackBoxed,
+ "The first program should still be blackboxed.");
+ is(getBlackBoxCheckbox(panel, 0).checked, false,
+ "The first blackbox checkbox should still be unchecked.");
+ ok(ShadersListView.attachments[1].isBlackBoxed,
+ "The second program should now be blackboxed.");
+ is(getBlackBoxCheckbox(panel, 1).checked, false,
+ "The second blackbox checkbox should now be unchecked.");
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
+ ok(true, "The second program was correctly blackboxed.");
+
+ ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 0) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
+ ok(true, "Highlighting shouldn't work while blackboxed (1).");
+
+ ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 0) });
+ ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 1) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
+ ok(true, "Highlighting shouldn't work while blackboxed (2).");
+
+ ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 1) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
+ ok(true, "Highlighting shouldn't work while blackboxed (3).");
+
+ getBlackBoxCheckbox(panel, 0).click();
+ getBlackBoxCheckbox(panel, 1).click();
+
+ ok(!ShadersListView.selectedAttachment.isBlackBoxed,
+ "The first program should now be unblackboxed.");
+ is(getBlackBoxCheckbox(panel, 0).checked, true,
+ "The first blackbox checkbox should now be rechecked.");
+ ok(!ShadersListView.attachments[1].isBlackBoxed,
+ "The second program should now be unblackboxed.");
+ is(getBlackBoxCheckbox(panel, 1).checked, true,
+ "The second blackbox checkbox should now be rechecked.");
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two programs were correctly unblackboxed.");
+
+ ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 0) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The first program was correctly highlighted.");
+
+ ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 0) });
+ ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 1) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2");
+ ok(true, "The second program was correctly highlighted.");
+
+ ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 1) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two programs were correctly unhighlighted.");
+
+ yield teardown(panel);
+ finish();
+}
+
+function getItemLabel(aPanel, aIndex) {
+ return aPanel.panelWin.document.querySelectorAll(
+ ".side-menu-widget-item-contents")[aIndex];
+}
+
+function getBlackBoxCheckbox(aPanel, aIndex) {
+ return aPanel.panelWin.document.querySelectorAll(
+ ".side-menu-widget-item-checkbox")[aIndex];
+}
+
+function once(aTarget, aEvent) {
+ let deferred = promise.defer();
+ aTarget.once(aEvent, deferred.resolve);
+ return deferred.promise;
+}
diff --git a/devtools/client/shadereditor/test/browser_se_programs-blackbox-02.js b/devtools/client/shadereditor/test/browser_se_programs-blackbox-02.js
new file mode 100644
index 000000000..391a272c8
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_programs-blackbox-02.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if blackboxing a program works properly in tandem with blended
+ * overlapping geometry.
+ */
+
+function* ifWebGLSupported() {
+ let { target, debuggee, panel } = yield initShaderEditor(BLENDED_GEOMETRY_CANVAS_URL);
+ let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+ let [[firstProgramActor, secondProgramActor]] = yield promise.all([
+ getPrograms(gFront, 2),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+ ok(true, "The canvas was correctly drawn.");
+
+ getBlackBoxCheckbox(panel, 0).click();
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 0, b: 0, a: 127 }, true);
+ ok(true, "The first program was correctly blackboxed.");
+
+ getBlackBoxCheckbox(panel, 0).click();
+ getBlackBoxCheckbox(panel, 1).click();
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+ ok(true, "The second program was correctly blackboxed.");
+
+ getBlackBoxCheckbox(panel, 1).click();
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+ ok(true, "The two programs were correctly unblackboxed.");
+
+ getBlackBoxCheckbox(panel, 0).click();
+ getBlackBoxCheckbox(panel, 1).click();
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ ok(true, "The two programs were correctly blackboxed again.");
+
+ getBlackBoxCheckbox(panel, 0).click();
+ getBlackBoxCheckbox(panel, 1).click();
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+ ok(true, "The two programs were correctly unblackboxed again.");
+
+ yield teardown(panel);
+ finish();
+}
+
+function getBlackBoxCheckbox(aPanel, aIndex) {
+ return aPanel.panelWin.document.querySelectorAll(
+ ".side-menu-widget-item-checkbox")[aIndex];
+}
diff --git a/devtools/client/shadereditor/test/browser_se_programs-cache.js b/devtools/client/shadereditor/test/browser_se_programs-cache.js
new file mode 100644
index 000000000..5e5708e44
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_programs-cache.js
@@ -0,0 +1,41 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that program and shader actors are cached in the frontend.
+ */
+
+function* ifWebGLSupported() {
+ let { target, debuggee, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL);
+ let { EVENTS, gFront, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+ let [[programActor]] = yield promise.all([
+ getPrograms(gFront, 1),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ let programItem = ShadersListView.selectedItem;
+
+ is(programItem.attachment.programActor, programActor,
+ "The correct program actor is cached for the selected item.");
+
+ is((yield programActor.getVertexShader()),
+ (yield programItem.attachment.vs),
+ "The cached vertex shader promise returns the correct actor.");
+
+ is((yield programActor.getFragmentShader()),
+ (yield programItem.attachment.fs),
+ "The cached fragment shader promise returns the correct actor.");
+
+ is((yield (yield programActor.getVertexShader()).getText()),
+ (yield (yield ShadersEditorsView._getEditor("vs")).getText()),
+ "The cached vertex shader promise returns the correct text.");
+
+ is((yield (yield programActor.getFragmentShader()).getText()),
+ (yield (yield ShadersEditorsView._getEditor("fs")).getText()),
+ "The cached fragment shader promise returns the correct text.");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_programs-highlight-01.js b/devtools/client/shadereditor/test/browser_se_programs-highlight-01.js
new file mode 100644
index 000000000..863dc2672
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_programs-highlight-01.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if highlighting a program works properly.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL);
+ let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+ once(panel.panelWin, EVENTS.SHADER_COMPILED).then(() => {
+ ok(false, "No shaders should be publicly compiled during this test.");
+ });
+
+ reload(target);
+ let [[firstProgramActor, secondProgramActor]] = yield promise.all([
+ getPrograms(gFront, 2),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ vsEditor.once("change", () => {
+ ok(false, "The vertex shader source was unexpectedly changed.");
+ });
+ fsEditor.once("change", () => {
+ ok(false, "The fragment shader source was unexpectedly changed.");
+ });
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN).then(() => {
+ ok(false, "No sources should be changed form this point onward.");
+ });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+
+ ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 0) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The first program was correctly highlighted.");
+
+ ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 0) });
+ ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 1) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2");
+ ok(true, "The second program was correctly highlighted.");
+
+ ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 1) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two programs were correctly unhighlighted.");
+
+ ShadersListView._onProgramMouseOver({ target: getBlackBoxCheckbox(panel, 0) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two programs were left unchanged after hovering a blackbox checkbox.");
+
+ ShadersListView._onProgramMouseOut({ target: getBlackBoxCheckbox(panel, 0) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two programs were left unchanged after unhovering a blackbox checkbox.");
+
+ yield teardown(panel);
+ finish();
+}
+
+function getItemLabel(aPanel, aIndex) {
+ return aPanel.panelWin.document.querySelectorAll(
+ ".side-menu-widget-item-contents")[aIndex];
+}
+
+function getBlackBoxCheckbox(aPanel, aIndex) {
+ return aPanel.panelWin.document.querySelectorAll(
+ ".side-menu-widget-item-checkbox")[aIndex];
+}
diff --git a/devtools/client/shadereditor/test/browser_se_programs-highlight-02.js b/devtools/client/shadereditor/test/browser_se_programs-highlight-02.js
new file mode 100644
index 000000000..c6cbd796b
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_programs-highlight-02.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if highlighting a program works properly in tandem with blended
+ * overlapping geometry.
+ */
+
+function* ifWebGLSupported() {
+ let { target, debuggee, panel } = yield initShaderEditor(BLENDED_GEOMETRY_CANVAS_URL);
+ let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+ let [[firstProgramActor, secondProgramActor]] = yield promise.all([
+ getPrograms(gFront, 2),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+ ok(true, "The canvas was correctly drawn.");
+
+ ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 0) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 0, b: 32, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 0, b: 32, a: 127 }, true);
+ ok(true, "The first program was correctly highlighted.");
+
+ ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 0) });
+ ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 1) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 255, g: 0, b: 64, a: 255 }, true);
+ ok(true, "The second program was correctly highlighted.");
+
+ ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 1) });
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+ ok(true, "The two programs were correctly unhighlighted.");
+
+ yield teardown(panel);
+ finish();
+}
+
+function getItemLabel(aPanel, aIndex) {
+ return aPanel.panelWin.document.querySelectorAll(
+ ".side-menu-widget-item-contents")[aIndex];
+}
diff --git a/devtools/client/shadereditor/test/browser_se_programs-list.js b/devtools/client/shadereditor/test/browser_se_programs-list.js
new file mode 100644
index 000000000..621880886
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_programs-list.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the programs list contains an entry after vertex and fragment
+ * shaders are linked.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL);
+ let { gFront, EVENTS, L10N, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+ is(ShadersListView.itemCount, 0,
+ "The shaders list should initially be empty.");
+ is(ShadersListView.selectedItem, null,
+ "The shaders list has no selected item.");
+ is(ShadersListView.selectedIndex, -1,
+ "The shaders list has a negative index.");
+
+ reload(target);
+
+ let [firstProgramActor, secondProgramActor] = yield promise.all([
+ getPrograms(gFront, 2, (actors) => {
+ // Fired upon each actor addition, we want to check only
+ // after the first actor has been added so we can test state
+ if (actors.length === 1)
+ checkFirstProgram();
+ if (actors.length === 2)
+ checkSecondProgram();
+ }),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]).then(([programs, ]) => programs);
+
+ is(ShadersListView.attachments[0].label, L10N.getFormatStr("shadersList.programLabel", 0),
+ "The correct first label is shown in the shaders list.");
+ is(ShadersListView.attachments[1].label, L10N.getFormatStr("shadersList.programLabel", 1),
+ "The correct second label is shown in the shaders list.");
+
+ let vertexShader = yield firstProgramActor.getVertexShader();
+ let fragmentShader = yield firstProgramActor.getFragmentShader();
+ let vertSource = yield vertexShader.getText();
+ let fragSource = yield fragmentShader.getText();
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ is(vertSource, vsEditor.getText(),
+ "The vertex shader editor contains the correct text.");
+ is(fragSource, fsEditor.getText(),
+ "The vertex shader editor contains the correct text.");
+
+ let compiled = once(panel.panelWin, EVENTS.SHADER_COMPILED).then(() => {
+ ok(false, "Selecting a different program shouldn't recompile its shaders.");
+ });
+
+ let shown = once(panel.panelWin, EVENTS.SOURCES_SHOWN).then(() => {
+ ok(true, "The vertex and fragment sources have changed in the editors.");
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, ShadersListView.items[1].target);
+ yield shown;
+
+ is(ShadersListView.selectedItem, ShadersListView.items[1],
+ "The shaders list has a correct item selected.");
+ is(ShadersListView.selectedIndex, 1,
+ "The shaders list has a correct index selected.");
+
+ yield teardown(panel);
+ finish();
+
+ function checkFirstProgram() {
+ is(ShadersListView.itemCount, 1,
+ "The shaders list contains one entry.");
+ is(ShadersListView.selectedItem, ShadersListView.items[0],
+ "The shaders list has a correct item selected.");
+ is(ShadersListView.selectedIndex, 0,
+ "The shaders list has a correct index selected.");
+ }
+ function checkSecondProgram() {
+ is(ShadersListView.itemCount, 2,
+ "The shaders list contains two entries.");
+ is(ShadersListView.selectedItem, ShadersListView.items[0],
+ "The shaders list has a correct item selected.");
+ is(ShadersListView.selectedIndex, 0,
+ "The shaders list has a correct index selected.");
+ }
+}
diff --git a/devtools/client/shadereditor/test/browser_se_shaders-edit-01.js b/devtools/client/shadereditor/test/browser_se_shaders-edit-01.js
new file mode 100644
index 000000000..0cb52ac19
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_shaders-edit-01.js
@@ -0,0 +1,73 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if editing a vertex and a fragment shader works properly.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+ let { gFront, $, EVENTS, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+ yield promise.all([
+ once(gFront, "program-linked"),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ is(vsEditor.getText().indexOf("gl_Position"), 170,
+ "The vertex shader editor contains the correct text.");
+ is(fsEditor.getText().indexOf("gl_FragColor"), 97,
+ "The fragment shader editor contains the correct text.");
+
+ is($("#vs-editor-label").hasAttribute("selected"), false,
+ "The vertex shader editor shouldn't be initially selected.");
+ is($("#fs-editor-label").hasAttribute("selected"), false,
+ "The vertex shader editor shouldn't be initially selected.");
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 128, y: 128 }, { r: 191, g: 64, b: 0, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+
+ vsEditor.focus();
+
+ is($("#vs-editor-label").hasAttribute("selected"), true,
+ "The vertex shader editor should now be selected.");
+ is($("#fs-editor-label").hasAttribute("selected"), false,
+ "The vertex shader editor shouldn't still not be selected.");
+
+ vsEditor.replaceText("2.0", { line: 7, ch: 44 }, { line: 7, ch: 47 });
+ yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
+
+ ok(true, "Vertex shader was changed.");
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+
+ ok(true, "The vertex shader was recompiled successfully.");
+
+ fsEditor.focus();
+
+ is($("#vs-editor-label").hasAttribute("selected"), false,
+ "The vertex shader editor should now be deselected.");
+ is($("#fs-editor-label").hasAttribute("selected"), true,
+ "The vertex shader editor should now be selected.");
+
+ fsEditor.replaceText("0.5", { line: 5, ch: 44 }, { line: 5, ch: 47 });
+ yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
+
+ ok(true, "Fragment shader was changed.");
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 127 }, true);
+ yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+
+ ok(true, "The fragment shader was recompiled successfully.");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_shaders-edit-02.js b/devtools/client/shadereditor/test/browser_se_shaders-edit-02.js
new file mode 100644
index 000000000..0bb72c461
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_shaders-edit-02.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if compile or linkage errors are emitted when a shader source
+ * gets malformed after being edited.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL);
+ let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+ yield promise.all([
+ once(gFront, "program-linked"),
+ once(panel.panelWin, EVENTS.SOURCES_SHOWN)
+ ]);
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+
+ vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
+ let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+
+ ok(error,
+ "The new vertex shader source was compiled with errors.");
+
+ // The implementation has the choice to defer all compile-time errors to link time.
+ let infoLog = (error.compile != "") ? error.compile : error.link;
+
+ isnot(infoLog, "",
+ "The one of the compile or link info logs should not be empty.");
+ is(infoLog.split("ERROR").length - 1, 2,
+ "The info log status contains two errors.");
+ ok(infoLog.includes("ERROR: 0:8: 'constructor'"),
+ "A constructor error is contained in the info log.");
+ ok(infoLog.includes("ERROR: 0:8: 'assign'"),
+ "An assignment error is contained in the info log.");
+
+
+ fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
+ [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+
+ ok(error,
+ "The new fragment shader source was compiled with errors.");
+
+ infoLog = (error.compile != "") ? error.compile : error.link;
+
+ isnot(infoLog, "",
+ "The one of the compile or link info logs should not be empty.");
+ is(infoLog.split("ERROR").length - 1, 1,
+ "The info log contains one error.");
+ ok(infoLog.includes("ERROR: 0:6: 'constructor'"),
+ "A constructor error is contained in the info log.");
+
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+
+ vsEditor.replaceText("vec4", { line: 7, ch: 22 }, { line: 7, ch: 26 });
+ [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+ ok(!error, "The new vertex shader source was compiled successfully.");
+
+ fsEditor.replaceText("vec3", { line: 2, ch: 14 }, { line: 2, ch: 18 });
+ [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+ ok(!error, "The new fragment shader source was compiled successfully.");
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_se_shaders-edit-03.js b/devtools/client/shadereditor/test/browser_se_shaders-edit-03.js
new file mode 100644
index 000000000..2c413dd72
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_se_shaders-edit-03.js
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if editing a vertex and a fragment shader would permanently store
+ * their new source on the backend and reshow it in the frontend when required.
+ */
+
+function* ifWebGLSupported() {
+ let { target, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL);
+ let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+ reload(target);
+
+ yield promise.all([
+ once(gFront, "program-linked"),
+ once(gFront, "program-linked")
+ ]);
+
+ yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
+
+ let vsEditor = yield ShadersEditorsView._getEditor("vs");
+ let fsEditor = yield ShadersEditorsView._getEditor("fs");
+
+ is(ShadersListView.selectedIndex, 0,
+ "The first program is currently selected.");
+ is(vsEditor.getText().indexOf("1);"), 136,
+ "The vertex shader editor contains the correct initial text (1).");
+ is(fsEditor.getText().indexOf("1);"), 117,
+ "The fragment shader editor contains the correct initial text (1).");
+ is(vsEditor.getText().indexOf("2.);"), -1,
+ "The vertex shader editor contains the correct initial text (2).");
+ is(fsEditor.getText().indexOf(".0);"), -1,
+ "The fragment shader editor contains the correct initial text (2).");
+
+ vsEditor.replaceText("2.", { line: 5, ch: 44 }, { line: 5, ch: 45 });
+ yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
+
+ fsEditor.replaceText(".0", { line: 5, ch: 35 }, { line: 5, ch: 37 });
+ yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
+
+ ok(true, "Vertex and fragment shaders were changed.");
+
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 32, y: 32 }, { r: 255, g: 255, b: 0, a: 0 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 255, g: 255, b: 0, a: 0 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 32, y: 32 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+
+ ok(true, "The vertex and fragment shaders were recompiled successfully.");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, ShadersListView.items[1].target);
+ yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
+
+ is(ShadersListView.selectedIndex, 1,
+ "The second program is currently selected.");
+ is(vsEditor.getText().indexOf("1);"), 136,
+ "The vertex shader editor contains the correct text (1).");
+ is(fsEditor.getText().indexOf("1);"), 117,
+ "The fragment shader editor contains the correct text (1).");
+ is(vsEditor.getText().indexOf("2.);"), -1,
+ "The vertex shader editor contains the correct text (2).");
+ is(fsEditor.getText().indexOf(".0);"), -1,
+ "The fragment shader editor contains the correct text (2).");
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, ShadersListView.items[0].target);
+ yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
+
+ is(ShadersListView.selectedIndex, 0,
+ "The first program is currently selected again.");
+ is(vsEditor.getText().indexOf("1);"), -1,
+ "The vertex shader editor contains the correct text (3).");
+ is(fsEditor.getText().indexOf("1);"), -1,
+ "The fragment shader editor contains the correct text (3).");
+ is(vsEditor.getText().indexOf("2.);"), 136,
+ "The vertex shader editor contains the correct text (4).");
+ is(fsEditor.getText().indexOf(".0);"), 116,
+ "The fragment shader editor contains the correct text (4).");
+
+ yield teardown(panel);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-01.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-01.js
new file mode 100644
index 000000000..242018a76
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-01.js
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if a WebGL front can be created for a remote tab target.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+
+ ok(target, "Should have a target available.");
+ ok(front, "Should have a protocol front available.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-02.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-02.js
new file mode 100644
index 000000000..addec87ca
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-02.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if notifications about WebGL programs being linked are not sent
+ * if the front wasn't set up first.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+
+ once(front, "program-linked").then(() => {
+ ok(false, "A 'program-linked' notification shouldn't have been sent!");
+ });
+
+ ok(true, "Each test requires at least one pass, fail or todo so here is a pass.");
+
+ yield reload(target);
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-03.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-03.js
new file mode 100644
index 000000000..0381973ec
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-03.js
@@ -0,0 +1,26 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if notifications about WebGL programs being linked are sent
+ * after a target navigation.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+
+ let navigated = once(target, "navigate");
+ let linked = once(front, "program-linked");
+
+ yield front.setup({ reload: true });
+ ok(true, "The front was setup up successfully.");
+
+ yield navigated;
+ ok(true, "Target automatically navigated when the front was set up.");
+
+ yield linked;
+ ok(true, "A 'program-linked' notification was sent after reloading.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-04.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-04.js
new file mode 100644
index 000000000..4256a5329
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-04.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if a program actor is sent when WebGL programs are linked,
+ * and that the corresponding vertex and fragment actors can be retrieved.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+ front.setup({ reload: true });
+
+ let programActor = yield once(front, "program-linked");
+ ok(programActor,
+ "A program actor was sent along with the 'program-linked' notification.");
+
+ let vertexShader = yield programActor.getVertexShader();
+ ok(programActor,
+ "A vertex shader actor was retrieved from the program actor.");
+
+ let fragmentShader = yield programActor.getFragmentShader();
+ ok(programActor,
+ "A fragment shader actor was retrieved from the program actor.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-05.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-05.js
new file mode 100644
index 000000000..96e445e01
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-05.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the source contents can be retrieved from the vertex and fragment
+ * shader actors.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+ front.setup({ reload: true });
+
+ let programActor = yield once(front, "program-linked");
+ let vertexShader = yield programActor.getVertexShader();
+ let fragmentShader = yield programActor.getFragmentShader();
+
+ let vertSource = yield vertexShader.getText();
+ ok(vertSource.includes("gl_Position"),
+ "The correct vertex shader source was retrieved.");
+
+ let fragSource = yield fragmentShader.getText();
+ ok(fragSource.includes("gl_FragColor"),
+ "The correct fragment shader source was retrieved.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-06.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-06.js
new file mode 100644
index 000000000..5cbe88a77
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-06.js
@@ -0,0 +1,64 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the highlight/unhighlight and blackbox/unblackbox operations on
+ * program actors work as expected.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+ front.setup({ reload: true });
+
+ let programActor = yield once(front, "program-linked");
+ let vertexShader = yield programActor.getVertexShader();
+ let fragmentShader = yield programActor.getFragmentShader();
+
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ yield checkShaderSource("The shader sources are correct before highlighting.");
+ ok(true, "The corner pixel colors are correct before highlighting.");
+
+ yield programActor.highlight([0, 1, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ yield checkShaderSource("The shader sources are preserved after highlighting.");
+ ok(true, "The corner pixel colors are correct after highlighting.");
+
+ yield programActor.unhighlight();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ yield checkShaderSource("The shader sources are correct after unhighlighting.");
+ ok(true, "The corner pixel colors are correct after unhighlighting.");
+
+ yield programActor.blackbox();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield checkShaderSource("The shader sources are preserved after blackboxing.");
+ ok(true, "The corner pixel colors are correct after blackboxing.");
+
+ yield programActor.unblackbox();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ yield checkShaderSource("The shader sources are correct after unblackboxing.");
+ ok(true, "The corner pixel colors are correct after unblackboxing.");
+
+ function checkShaderSource(aMessage) {
+ return Task.spawn(function* () {
+ let newVertexShader = yield programActor.getVertexShader();
+ let newFragmentShader = yield programActor.getFragmentShader();
+ is(vertexShader, newVertexShader,
+ "The same vertex shader actor was retrieved.");
+ is(fragmentShader, newFragmentShader,
+ "The same fragment shader actor was retrieved.");
+
+ let vertSource = yield newVertexShader.getText();
+ let fragSource = yield newFragmentShader.getText();
+ ok(vertSource.includes("I'm special!") &&
+ fragSource.includes("I'm also special!"), aMessage);
+ });
+ }
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-07.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-07.js
new file mode 100644
index 000000000..a7634de44
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-07.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that vertex and fragment shader sources can be changed.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+ front.setup({ reload: true });
+
+ let programActor = yield once(front, "program-linked");
+ let vertexShader = yield programActor.getVertexShader();
+ let fragmentShader = yield programActor.getFragmentShader();
+
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 191, g: 64, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+
+ let vertSource = yield vertexShader.getText();
+ let fragSource = yield fragmentShader.getText();
+ ok(!vertSource.includes("2.0"),
+ "The vertex shader source is correct before changing it.");
+ ok(!fragSource.includes("0.5"),
+ "The fragment shader source is correct before changing it.");
+
+ let newVertSource = vertSource.replace("1.0", "2.0");
+ let status = yield vertexShader.compile(newVertSource);
+ ok(!status,
+ "The new vertex shader source was compiled without errors.");
+
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+
+ vertSource = yield vertexShader.getText();
+ fragSource = yield fragmentShader.getText();
+ ok(vertSource.includes("2.0"),
+ "The vertex shader source is correct after changing it.");
+ ok(!fragSource.includes("0.5"),
+ "The fragment shader source is correct after changing the vertex shader.");
+
+ let newFragSource = fragSource.replace("1.0", "0.5");
+ status = yield fragmentShader.compile(newFragSource);
+ ok(!status,
+ "The new fragment shader source was compiled without errors.");
+
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 127 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+
+ vertSource = yield vertexShader.getText();
+ fragSource = yield fragmentShader.getText();
+ ok(vertSource.includes("2.0"),
+ "The vertex shader source is correct after changing the fragment shader.");
+ ok(fragSource.includes("0.5"),
+ "The fragment shader source is correct after changing it.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-08.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-08.js
new file mode 100644
index 000000000..8025bc703
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-08.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the rendering is updated when a varying variable is
+ * changed in one shader.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+ front.setup({ reload: true });
+
+ let programActor = yield once(front, "program-linked");
+ let vertexShader = yield programActor.getVertexShader();
+ let fragmentShader = yield programActor.getFragmentShader();
+
+ let oldVertSource = yield vertexShader.getText();
+ let newVertSource = oldVertSource.replace("= aVertexColor", "= vec3(0, 0, 1)");
+ let status = yield vertexShader.compile(newVertSource);
+ ok(!status,
+ "The new vertex shader source was compiled without errors.");
+
+ yield front.waitForFrame();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 0, g: 0, b: 255, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 255, a: 255 }, true);
+
+ let vertSource = yield vertexShader.getText();
+ let fragSource = yield fragmentShader.getText();
+ ok(vertSource.includes("vFragmentColor = vec3(0, 0, 1);"),
+ "The vertex shader source is correct after changing it.");
+ ok(fragSource.includes("gl_FragColor = vec4(vFragmentColor, 1.0);"),
+ "The fragment shader source is correct after changing the vertex shader.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-09.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-09.js
new file mode 100644
index 000000000..2054140a6
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-09.js
@@ -0,0 +1,89 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that errors are properly handled when trying to compile a
+ * defective shader source.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+ front.setup({ reload: true });
+
+ let programActor = yield once(front, "program-linked");
+ let vertexShader = yield programActor.getVertexShader();
+ let fragmentShader = yield programActor.getFragmentShader();
+
+ let oldVertSource = yield vertexShader.getText();
+ let newVertSource = oldVertSource.replace("vec4", "vec3");
+
+ try {
+ yield vertexShader.compile(newVertSource);
+ ok(false, "Vertex shader was compiled with a defective source!");
+ } catch (error) {
+ ok(error,
+ "The new vertex shader source was compiled with errors.");
+
+ // The implementation has the choice to defer all compile-time errors to link time.
+ let infoLog = (error.compile != "") ? error.compile : error.link;
+
+ isnot(infoLog, "",
+ "The one of the compile or link info logs should not be empty.");
+ is(infoLog.split("ERROR").length - 1, 2,
+ "The info log contains two errors.");
+ ok(infoLog.includes("ERROR: 0:8: 'constructor'"),
+ "A constructor error is contained in the info log.");
+ ok(infoLog.includes("ERROR: 0:8: 'assign'"),
+ "An assignment error is contained in the info log.");
+ }
+
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The shader was reverted to the old source.");
+
+ let vertSource = yield vertexShader.getText();
+ ok(vertSource.includes("vec4(aVertexPosition, 1.0);"),
+ "The previous correct vertex shader source was preserved.");
+
+ let oldFragSource = yield fragmentShader.getText();
+ let newFragSource = oldFragSource.replace("vec3", "vec4");
+
+ try {
+ yield fragmentShader.compile(newFragSource);
+ ok(false, "Fragment shader was compiled with a defective source!");
+ } catch (error) {
+ ok(error,
+ "The new fragment shader source was compiled with errors.");
+
+ // The implementation has the choice to defer all compile-time errors to link time.
+ let infoLog = (error.compile != "") ? error.compile : error.link;
+
+ isnot(infoLog, "",
+ "The one of the compile or link info logs should not be empty.");
+ is(infoLog.split("ERROR").length - 1, 1,
+ "The info log contains one error.");
+ ok(infoLog.includes("ERROR: 0:6: 'constructor'"),
+ "A constructor error is contained in the info log.");
+ }
+
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The shader was reverted to the old source.");
+
+ let fragSource = yield fragmentShader.getText();
+ ok(fragSource.includes("vec3 vFragmentColor;"),
+ "The previous correct fragment shader source was preserved.");
+
+ yield programActor.highlight([0, 1, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "Highlighting worked after setting a defective fragment source.");
+
+ yield programActor.unhighlight();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "Unhighlighting worked after setting a defective vertex source.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-10.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-10.js
new file mode 100644
index 000000000..87dfe35bf
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-10.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the WebGL context is correctly instrumented every time the
+ * target navigates.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+
+ front.setup({ reload: true });
+ yield testHighlighting((yield once(front, "program-linked")));
+ ok(true, "Canvas was correctly instrumented on the first navigation.");
+
+ reload(target);
+ yield testHighlighting((yield once(front, "program-linked")));
+ ok(true, "Canvas was correctly instrumented on the second navigation.");
+
+ reload(target);
+ yield testHighlighting((yield once(front, "program-linked")));
+ ok(true, "Canvas was correctly instrumented on the third navigation.");
+
+ yield removeTab(target.tab);
+ finish();
+
+ function testHighlighting(programActor) {
+ return Task.spawn(function* () {
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner pixel colors are correct before highlighting.");
+
+ yield programActor.highlight([0, 1, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner pixel colors are correct after highlighting.");
+
+ yield programActor.unhighlight();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner pixel colors are correct after unhighlighting.");
+ });
+ }
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-11.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-11.js
new file mode 100644
index 000000000..28663057e
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-11.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the WebGL context is never instrumented anymore after the
+ * finalize method is called.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+
+ let linked = once(front, "program-linked");
+ front.setup({ reload: true });
+ yield linked;
+ ok(true, "Canvas was correctly instrumented on the first navigation.");
+
+ once(front, "program-linked").then(() => {
+ ok(false, "A 'program-linked' notification shouldn't have been sent!");
+ });
+
+ yield front.finalize();
+ yield reload(target);
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-12.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-12.js
new file mode 100644
index 000000000..f69d5e403
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-12.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the correct vertex and fragment shader sources are retrieved
+ * regardless of the order in which they were compiled and attached.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SHADER_ORDER_URL);
+ front.setup({ reload: true });
+
+ let programActor = yield once(front, "program-linked");
+ let vertexShader = yield programActor.getVertexShader();
+ let fragmentShader = yield programActor.getFragmentShader();
+
+ let vertSource = yield vertexShader.getText();
+ let fragSource = yield fragmentShader.getText();
+
+ ok(vertSource.includes("I'm a vertex shader!"),
+ "The correct vertex shader text was retrieved.");
+ ok(fragSource.includes("I'm a fragment shader!"),
+ "The correct fragment shader text was retrieved.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-13.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-13.js
new file mode 100644
index 000000000..f4730ba39
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-13.js
@@ -0,0 +1,67 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if multiple WebGL contexts are correctly handled.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(MULTIPLE_CONTEXTS_URL);
+ front.setup({ reload: true });
+
+ let [firstProgramActor, secondProgramActor] = yield getPrograms(front, 2);
+
+ isnot(firstProgramActor, secondProgramActor,
+ "Two distinct program actors were recevide from two separate contexts.");
+
+ let firstVertexShader = yield firstProgramActor.getVertexShader();
+ let firstFragmentShader = yield firstProgramActor.getFragmentShader();
+ let secondVertexShader = yield secondProgramActor.getVertexShader();
+ let secondFragmentShader = yield secondProgramActor.getFragmentShader();
+
+ isnot(firstVertexShader, secondVertexShader,
+ "The two programs should have distinct vertex shaders.");
+ isnot(firstFragmentShader, secondFragmentShader,
+ "The two programs should have distinct fragment shaders.");
+
+ let firstVertSource = yield firstVertexShader.getText();
+ let firstFragSource = yield firstFragmentShader.getText();
+ let secondVertSource = yield secondVertexShader.getText();
+ let secondFragSource = yield secondFragmentShader.getText();
+
+ is(firstVertSource, secondVertSource,
+ "The vertex shaders should have identical sources.");
+ is(firstFragSource, secondFragSource,
+ "The vertex shaders should have identical sources.");
+
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two canvases are correctly drawn.");
+
+ yield firstProgramActor.highlight([1, 0, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The first canvas was correctly filled after highlighting.");
+
+ yield secondProgramActor.highlight([0, 1, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
+ ok(true, "The second canvas was correctly filled after highlighting.");
+
+ yield firstProgramActor.unhighlight();
+ yield secondProgramActor.unhighlight();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two canvases were correctly filled after unhighlighting.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-14.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-14.js
new file mode 100644
index 000000000..342bba382
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-14.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the rendering is updated when a uniform variable is
+ * changed in one shader of a page with multiple WebGL contexts.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(MULTIPLE_CONTEXTS_URL);
+ front.setup({ reload: true });
+
+ let [firstProgramActor, secondProgramActor] = yield getPrograms(front, 2);
+
+ let firstFragmentShader = yield firstProgramActor.getFragmentShader();
+ let secondFragmentShader = yield secondProgramActor.getFragmentShader();
+
+ let oldFragSource = yield firstFragmentShader.getText();
+ let newFragSource = oldFragSource.replace("vec4(uColor", "vec4(0.25, 0.25, 0.25");
+ let status = yield firstFragmentShader.compile(newFragSource);
+ ok(!status,
+ "The first new fragment shader source was compiled without errors.");
+
+ yield front.waitForFrame();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The first fragment shader was changed.");
+
+ oldFragSource = yield secondFragmentShader.getText();
+ newFragSource = oldFragSource.replace("vec4(uColor", "vec4(0.75, 0.75, 0.75");
+ status = yield secondFragmentShader.compile(newFragSource);
+ ok(!status,
+ "The second new fragment shader source was compiled without errors.");
+
+ yield front.waitForFrame();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 191, g: 191, b: 191, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 191, g: 191, b: 191, a: 255 }, true, "#canvas2");
+ ok(true, "The second fragment shader was changed.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-15.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-15.js
new file mode 100644
index 000000000..0a65dbe0a
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-15.js
@@ -0,0 +1,133 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if program actors are cached when navigating in the bfcache.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+ front.setup({ reload: false });
+
+ // Attach frame scripts if in e10s to perform
+ // history navigation via the content
+ loadFrameScripts();
+
+ reload(target);
+ let firstProgram = yield once(front, "program-linked");
+ yield checkFirstCachedPrograms(firstProgram);
+ yield checkHighlightingInTheFirstPage(firstProgram);
+ ok(true, "The cached programs behave correctly before the navigation.");
+
+ navigate(target, MULTIPLE_CONTEXTS_URL);
+ let [secondProgram, thirdProgram] = yield getPrograms(front, 2);
+ yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
+ yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
+ ok(true, "The cached programs behave correctly after the navigation.");
+
+ once(front, "program-linked").then(() => {
+ ok(false, "Shouldn't have received any more program-linked notifications.");
+ });
+
+ yield navigateInHistory(target, "back");
+ yield checkFirstCachedPrograms(firstProgram);
+ yield checkHighlightingInTheFirstPage(firstProgram);
+ ok(true, "The cached programs behave correctly after navigating back.");
+
+ yield navigateInHistory(target, "forward");
+ yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
+ yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
+ ok(true, "The cached programs behave correctly after navigating forward.");
+
+ yield navigateInHistory(target, "back");
+ yield checkFirstCachedPrograms(firstProgram);
+ yield checkHighlightingInTheFirstPage(firstProgram);
+ ok(true, "The cached programs behave correctly after navigating back again.");
+
+ yield navigateInHistory(target, "forward");
+ yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
+ yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
+ ok(true, "The cached programs behave correctly after navigating forward again.");
+
+ yield removeTab(target.tab);
+ finish();
+
+ function checkFirstCachedPrograms(programActor) {
+ return Task.spawn(function* () {
+ let programs = yield front.getPrograms();
+
+ is(programs.length, 1,
+ "There should be 1 cached program actor.");
+ is(programs[0], programActor,
+ "The cached program actor was the expected one.");
+ });
+ }
+
+ function checkSecondCachedPrograms(oldProgramActor, newProgramActors) {
+ return Task.spawn(function* () {
+ let programs = yield front.getPrograms();
+
+ is(programs.length, 2,
+ "There should be 2 cached program actors after the navigation.");
+ is(programs[0], newProgramActors[0],
+ "The first cached program actor was the expected one after the navigation.");
+ is(programs[1], newProgramActors[1],
+ "The second cached program actor was the expected one after the navigation.");
+
+ isnot(newProgramActors[0], oldProgramActor,
+ "The old program actor is not equal to the new first program actor.");
+ isnot(newProgramActors[1], oldProgramActor,
+ "The old program actor is not equal to the new second program actor.");
+ });
+ }
+
+ function checkHighlightingInTheFirstPage(programActor) {
+ return Task.spawn(function* () {
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner pixel colors are correct before highlighting.");
+
+ yield programActor.highlight([0, 1, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner pixel colors are correct after highlighting.");
+
+ yield programActor.unhighlight();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner pixel colors are correct after unhighlighting.");
+ });
+ }
+
+ function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) {
+ return Task.spawn(function* () {
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two canvases are correctly drawn before highlighting.");
+
+ yield firstProgramActor.highlight([1, 0, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The first canvas was correctly filled after highlighting.");
+
+ yield secondProgramActor.highlight([0, 1, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
+ ok(true, "The second canvas was correctly filled after highlighting.");
+
+ yield firstProgramActor.unhighlight();
+ yield secondProgramActor.unhighlight();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two canvases were correctly filled after unhighlighting.");
+ });
+ }
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-16.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-16.js
new file mode 100644
index 000000000..e61e73102
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-16.js
@@ -0,0 +1,141 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if program actors are invalidated from the cache when a window is
+ * removed from the bfcache.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(SIMPLE_CANVAS_URL);
+ front.setup({ reload: false });
+
+ // Attach frame scripts if in e10s to perform
+ // history navigation via the content
+ loadFrameScripts();
+
+ // 0. Perform the initial reload.
+
+ reload(target);
+ let firstProgram = yield once(front, "program-linked");
+ let programs = yield front.getPrograms();
+ is(programs.length, 1,
+ "The first program should be returned by a call to getPrograms().");
+ is(programs[0], firstProgram,
+ "The first programs was correctly retrieved from the cache.");
+
+ let allPrograms = yield front._getAllPrograms();
+ is(allPrograms.length, 1,
+ "Should be only one program in cache.");
+
+ // 1. Perform a simple navigation.
+
+ navigate(target, MULTIPLE_CONTEXTS_URL);
+ let [secondProgram, thirdProgram] = yield getPrograms(front, 2);
+ programs = yield front.getPrograms();
+ is(programs.length, 2,
+ "The second and third programs should be returned by a call to getPrograms().");
+ is(programs[0], secondProgram,
+ "The second programs was correctly retrieved from the cache.");
+ is(programs[1], thirdProgram,
+ "The third programs was correctly retrieved from the cache.");
+
+ allPrograms = yield front._getAllPrograms();
+ is(allPrograms.length, 3,
+ "Should be three programs in cache.");
+
+ // 2. Perform a bfcache navigation.
+
+ yield navigateInHistory(target, "back");
+ let globalDestroyed = once(front, "global-created");
+ let globalCreated = once(front, "global-destroyed");
+ let programsLinked = once(front, "program-linked");
+ reload(target);
+
+ yield promise.all([programsLinked, globalDestroyed, globalCreated]);
+ allPrograms = yield front._getAllPrograms();
+ is(allPrograms.length, 3,
+ "Should be 3 programs total in cache.");
+
+ programs = yield front.getPrograms();
+ is(programs.length, 1,
+ "There should be 1 cached program actor now.");
+
+ yield checkHighlightingInTheFirstPage(programs[0]);
+ ok(true, "The cached programs behave correctly after navigating back and reloading.");
+
+ // 3. Perform a bfcache navigation and a page reload.
+
+ yield navigateInHistory(target, "forward");
+
+ globalDestroyed = once(front, "global-created");
+ globalCreated = once(front, "global-destroyed");
+ programsLinked = getPrograms(front, 2);
+
+ reload(target);
+
+ yield promise.all([programsLinked, globalDestroyed, globalCreated]);
+ allPrograms = yield front._getAllPrograms();
+ is(allPrograms.length, 3,
+ "Should be 3 programs total in cache.");
+
+ programs = yield front.getPrograms();
+ is(programs.length, 2,
+ "There should be 2 cached program actors now.");
+
+ yield checkHighlightingInTheSecondPage(programs[0], programs[1]);
+ ok(true, "The cached programs behave correctly after navigating forward and reloading.");
+
+ yield removeTab(target.tab);
+ finish();
+
+ function checkHighlightingInTheFirstPage(programActor) {
+ return Task.spawn(function* () {
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner pixel colors are correct before highlighting.");
+
+ yield programActor.highlight([0, 1, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner pixel colors are correct after highlighting.");
+
+ yield programActor.unhighlight();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner pixel colors are correct after unhighlighting.");
+ });
+ }
+
+ function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) {
+ return Task.spawn(function* () {
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two canvases are correctly drawn before highlighting.");
+
+ yield firstProgramActor.highlight([1, 0, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The first canvas was correctly filled after highlighting.");
+
+ yield secondProgramActor.highlight([0, 1, 0, 1]);
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
+ ok(true, "The second canvas was correctly filled after highlighting.");
+
+ yield firstProgramActor.unhighlight();
+ yield secondProgramActor.unhighlight();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
+ ok(true, "The two canvases were correctly filled after unhighlighting.");
+ });
+ }
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-17.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-17.js
new file mode 100644
index 000000000..92b940d4a
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-17.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the blackbox/unblackbox operations work as expected with
+ * overlapping geometry.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(OVERLAPPING_GEOMETRY_CANVAS_URL);
+ front.setup({ reload: true });
+
+ let [firstProgramActor, secondProgramActor] = yield getPrograms(front, 2);
+
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner vs. center pixel colors are correct before blackboxing.");
+
+ yield firstProgramActor.blackbox();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+ ok(true, "The corner vs. center pixel colors are correct after blackboxing (1).");
+
+ yield firstProgramActor.unblackbox();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner vs. center pixel colors are correct after unblackboxing (1).");
+
+ yield secondProgramActor.blackbox();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 255, g: 255, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner vs. center pixel colors are correct after blackboxing (2).");
+
+ yield secondProgramActor.unblackbox();
+ yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true);
+ yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true);
+ ok(true, "The corner vs. center pixel colors are correct after unblackboxing (2).");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-18.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-18.js
new file mode 100644
index 000000000..977b07d86
--- /dev/null
+++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-18.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests the `getPixel` actor method works across threads.
+ */
+
+function* ifWebGLSupported() {
+ let { target, front } = yield initBackend(MULTIPLE_CONTEXTS_URL);
+ front.setup({ reload: true });
+
+ yield getPrograms(front, 2);
+
+ // Wait a frame to ensure rendering
+ yield front.waitForFrame();
+
+ let pixel = yield front.getPixel({ selector: "#canvas1", position: { x: 0, y: 0 }});
+ is(pixel.r, 255, "correct `r` value for first canvas.");
+ is(pixel.g, 255, "correct `g` value for first canvas.");
+ is(pixel.b, 0, "correct `b` value for first canvas.");
+ is(pixel.a, 255, "correct `a` value for first canvas.");
+
+ pixel = yield front.getPixel({ selector: "#canvas2", position: { x: 0, y: 0 }});
+ is(pixel.r, 0, "correct `r` value for second canvas.");
+ is(pixel.g, 255, "correct `g` value for second canvas.");
+ is(pixel.b, 255, "correct `b` value for second canvas.");
+ is(pixel.a, 255, "correct `a` value for second canvas.");
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/devtools/client/shadereditor/test/doc_blended-geometry.html b/devtools/client/shadereditor/test/doc_blended-geometry.html
new file mode 100644
index 000000000..75cad6dc7
--- /dev/null
+++ b/devtools/client/shadereditor/test/doc_blended-geometry.html
@@ -0,0 +1,136 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>WebGL editor test page</title>
+
+ <script id="shader-vs" type="x-shader/x-vertex">
+ precision lowp float;
+ attribute vec3 aVertexPosition;
+ uniform float uDepth;
+
+ void main(void) {
+ gl_Position = vec4(aVertexPosition, uDepth);
+ }
+ </script>
+
+ <script id="shader-fs-0" type="x-shader/x-fragment">
+ precision lowp float;
+
+ void main(void) {
+ gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0);
+ }
+ </script>
+
+ <script id="shader-fs-1" type="x-shader/x-fragment">
+ precision lowp float;
+
+ void main(void) {
+ gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+ }
+ </script>
+ </head>
+
+ <body>
+ <canvas id="canvas" width="128" height="128"></canvas>
+
+ <script type="text/javascript;version=1.8">
+ "use strict";
+
+ let canvas, gl;
+ let program = [];
+ let squareVerticesPositionBuffer;
+ let vertexPositionAttribute = [];
+ let depthUniform = [];
+
+ window.onload = function() {
+ canvas = document.querySelector("canvas");
+ gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+ initProgram(0);
+ initProgram(1);
+ initBuffers();
+ drawScene();
+ }
+
+ function initProgram(i) {
+ let vertexShader = getShader("shader-vs");
+ let fragmentShader = getShader("shader-fs-" + i);
+
+ program[i] = gl.createProgram();
+ gl.attachShader(program[i], vertexShader);
+ gl.attachShader(program[i], fragmentShader);
+ gl.linkProgram(program[i]);
+
+ vertexPositionAttribute[i] = gl.getAttribLocation(program[i], "aVertexPosition");
+ gl.enableVertexAttribArray(vertexPositionAttribute[i]);
+
+ depthUniform[i] = gl.getUniformLocation(program[i], "uDepth");
+ }
+
+ function getShader(id) {
+ let script = document.getElementById(id);
+ let source = script.textContent;
+ let shader;
+
+ if (script.type == "x-shader/x-fragment") {
+ shader = gl.createShader(gl.FRAGMENT_SHADER);
+ } else if (script.type == "x-shader/x-vertex") {
+ shader = gl.createShader(gl.VERTEX_SHADER);
+ }
+
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+
+ return shader;
+ }
+
+ function initBuffers() {
+ squareVerticesPositionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 1.0, 1.0, 0.0,
+ -1.0, 1.0, 0.0,
+ 1.0, -1.0, 0.0,
+ -1.0, -1.0, 0.0
+ ]), gl.STATIC_DRAW);
+ }
+
+ function drawScene() {
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ for (let i = 0; i < 2; i++) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer);
+ gl.vertexAttribPointer(vertexPositionAttribute[i], 3, gl.FLOAT, false, 0, 0);
+
+ gl.useProgram(program[i]);
+ gl.uniform1f(depthUniform[i], i + 1);
+ blend(i);
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+ }
+
+ window.requestAnimationFrame(drawScene);
+ }
+
+ function blend(i) {
+ if (i == 0) {
+ gl.disable(gl.BLEND);
+ }
+ else if (i == 1) {
+ gl.enable(gl.BLEND);
+ gl.blendColor(0.5, 0, 0, 0.25);
+ gl.blendEquationSeparate(
+ gl.FUNC_REVERSE_SUBTRACT, gl.FUNC_SUBTRACT);
+ gl.blendFuncSeparate(
+ gl.CONSTANT_COLOR, gl.ONE_MINUS_CONSTANT_COLOR,
+ gl.ONE_MINUS_CONSTANT_COLOR, gl.CONSTANT_COLOR);
+ }
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/devtools/client/shadereditor/test/doc_multiple-contexts.html b/devtools/client/shadereditor/test/doc_multiple-contexts.html
new file mode 100644
index 000000000..039ee62d0
--- /dev/null
+++ b/devtools/client/shadereditor/test/doc_multiple-contexts.html
@@ -0,0 +1,112 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>WebGL editor test page</title>
+
+ <script id="shader-vs" type="x-shader/x-vertex">
+ precision lowp float;
+ attribute vec3 aVertexPosition;
+
+ void main(void) {
+ gl_Position = vec4(aVertexPosition, 1);
+ }
+ </script>
+
+ <script id="shader-fs" type="x-shader/x-fragment">
+ precision lowp float;
+ uniform vec3 uColor;
+
+ void main(void) {
+ gl_FragColor = vec4(uColor, 1);
+ }
+ </script>
+ </head>
+
+ <body>
+ <canvas id="canvas1" width="128" height="128"></canvas>
+ <canvas id="canvas2" width="128" height="128"></canvas>
+
+ <script type="text/javascript;version=1.8">
+ "use strict";
+
+ let canvas = [], gl = [];
+ let program = [];
+ let squareVerticesPositionBuffer = [];
+ let vertexPositionAttribute = [];
+ let colorUniform = [];
+
+ window.onload = function() {
+ for (let i = 0; i < 2; i++) {
+ canvas[i] = document.querySelector("#canvas" + (i + 1));
+ gl[i] = canvas[i].getContext("webgl", { preserveDrawingBuffer: true });
+ gl[i].clearColor(0.0, 0.0, 0.0, 1.0);
+
+ initProgram(i);
+ initBuffers(i);
+ drawScene(i);
+ }
+ }
+
+ function initProgram(i) {
+ let vertexShader = getShader(gl[i], "shader-vs");
+ let fragmentShader = getShader(gl[i], "shader-fs");
+
+ program[i] = gl[i].createProgram();
+ gl[i].attachShader(program[i], vertexShader);
+ gl[i].attachShader(program[i], fragmentShader);
+ gl[i].linkProgram(program[i]);
+
+ vertexPositionAttribute[i] = gl[i].getAttribLocation(program[i], "aVertexPosition");
+ gl[i].enableVertexAttribArray(vertexPositionAttribute[i]);
+
+ colorUniform[i] = gl[i].getUniformLocation(program[i], "uColor");
+ }
+
+ function getShader(gl, id) {
+ let script = document.getElementById(id);
+ let source = script.textContent;
+ let shader;
+
+ if (script.type == "x-shader/x-fragment") {
+ shader = gl.createShader(gl.FRAGMENT_SHADER);
+ } else if (script.type == "x-shader/x-vertex") {
+ shader = gl.createShader(gl.VERTEX_SHADER);
+ }
+
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+
+ return shader;
+ }
+
+ function initBuffers(i) {
+ squareVerticesPositionBuffer[i] = gl[i].createBuffer();
+ gl[i].bindBuffer(gl[i].ARRAY_BUFFER, squareVerticesPositionBuffer[i]);
+ gl[i].bufferData(gl[i].ARRAY_BUFFER, new Float32Array([
+ 1.0, 1.0, 0.0,
+ -1.0, 1.0, 0.0,
+ 1.0, -1.0, 0.0,
+ -1.0, -1.0, 0.0
+ ]), gl[i].STATIC_DRAW);
+ }
+
+ function drawScene(i) {
+ gl[i].clear(gl[i].COLOR_BUFFER_BIT);
+
+ gl[i].bindBuffer(gl[i].ARRAY_BUFFER, squareVerticesPositionBuffer[i]);
+ gl[i].vertexAttribPointer(vertexPositionAttribute[i], 3, gl[i].FLOAT, false, 0, 0);
+
+ gl[i].useProgram(program[i]);
+ gl[i].uniform3fv(colorUniform[i], i == 0 ? [1, 1, 0] : [0, 1, 1]);
+ gl[i].drawArrays(gl[i].TRIANGLE_STRIP, 0, 4);
+
+ window.requestAnimationFrame(() => drawScene(i));
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/devtools/client/shadereditor/test/doc_overlapping-geometry.html b/devtools/client/shadereditor/test/doc_overlapping-geometry.html
new file mode 100644
index 000000000..34be8f57a
--- /dev/null
+++ b/devtools/client/shadereditor/test/doc_overlapping-geometry.html
@@ -0,0 +1,120 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>WebGL editor test page</title>
+
+ <script id="shader-vs" type="x-shader/x-vertex">
+ precision lowp float;
+ attribute vec3 aVertexPosition;
+ uniform float uDepth;
+
+ void main(void) {
+ gl_Position = vec4(aVertexPosition, uDepth);
+ }
+ </script>
+
+ <script id="shader-fs-0" type="x-shader/x-fragment">
+ precision lowp float;
+
+ void main(void) {
+ gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
+ }
+ </script>
+
+ <script id="shader-fs-1" type="x-shader/x-fragment">
+ precision lowp float;
+
+ void main(void) {
+ gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);
+ }
+ </script>
+ </head>
+
+ <body>
+ <canvas id="canvas" width="128" height="128"></canvas>
+
+ <script type="text/javascript;version=1.8">
+ "use strict";
+
+ let canvas, gl;
+ let program = [];
+ let squareVerticesPositionBuffer;
+ let vertexPositionAttribute = [];
+ let depthUniform = [];
+
+ window.onload = function() {
+ canvas = document.querySelector("canvas");
+ gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+ initProgram(0);
+ initProgram(1);
+ initBuffers();
+ drawScene();
+ }
+
+ function initProgram(i) {
+ let vertexShader = getShader("shader-vs");
+ let fragmentShader = getShader("shader-fs-" + i);
+
+ program[i] = gl.createProgram();
+ gl.attachShader(program[i], vertexShader);
+ gl.attachShader(program[i], fragmentShader);
+ gl.linkProgram(program[i]);
+
+ vertexPositionAttribute[i] = gl.getAttribLocation(program[i], "aVertexPosition");
+ gl.enableVertexAttribArray(vertexPositionAttribute[i]);
+
+ depthUniform[i] = gl.getUniformLocation(program[i], "uDepth");
+ }
+
+ function getShader(id) {
+ let script = document.getElementById(id);
+ let source = script.textContent;
+ let shader;
+
+ if (script.type == "x-shader/x-fragment") {
+ shader = gl.createShader(gl.FRAGMENT_SHADER);
+ } else if (script.type == "x-shader/x-vertex") {
+ shader = gl.createShader(gl.VERTEX_SHADER);
+ }
+
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+
+ return shader;
+ }
+
+ function initBuffers() {
+ squareVerticesPositionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 1.0, 1.0, 0.0,
+ -1.0, 1.0, 0.0,
+ 1.0, -1.0, 0.0,
+ -1.0, -1.0, 0.0
+ ]), gl.STATIC_DRAW);
+ }
+
+ function drawScene() {
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ for (let i = 0; i < 2; i++) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer);
+ gl.vertexAttribPointer(vertexPositionAttribute[i], 3, gl.FLOAT, false, 0, 0);
+
+ gl.useProgram(program[i]);
+ gl.uniform1f(depthUniform[i], i + 1);
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+ }
+
+ window.requestAnimationFrame(drawScene);
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/devtools/client/shadereditor/test/doc_shader-order.html b/devtools/client/shadereditor/test/doc_shader-order.html
new file mode 100644
index 000000000..a7cec53aa
--- /dev/null
+++ b/devtools/client/shadereditor/test/doc_shader-order.html
@@ -0,0 +1,83 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>WebGL editor test page</title>
+
+ <script id="shader-vs" type="x-shader/x-vertex">
+ precision lowp float;
+
+ void main(void) {
+ gl_Position = vec4(0, 0, 0, 1); // I'm a vertex shader!
+ }
+ </script>
+
+ <script id="shader-fs" type="x-shader/x-fragment">
+ precision lowp float;
+ varying vec3 vFragmentColor;
+
+ void main(void) {
+ gl_FragColor = vec4(1, 0, 0, 1); // I'm a fragment shader!
+ }
+ </script>
+ </head>
+
+ <body>
+ <canvas width="512" height="512"></canvas>
+
+ <script type="text/javascript;version=1.8">
+ "use strict";
+
+ let canvas, gl;
+
+ window.onload = function() {
+ canvas = document.querySelector("canvas");
+ gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
+
+ let shaderProgram = gl.createProgram();
+ let vertexShader, fragmentShader;
+
+ // Compile and attach the shaders in a random order. The test will
+ // ensure that the correct vertex and fragment source is retrieved
+ // regardless of this crazyness.
+ if (Math.random() > 0.5) {
+ vertexShader = getShader(gl, "shader-vs");
+ fragmentShader = getShader(gl, "shader-fs");
+ } else {
+ fragmentShader = getShader(gl, "shader-fs");
+ vertexShader = getShader(gl, "shader-vs");
+ }
+ if (Math.random() > 0.5) {
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+ } else {
+ gl.attachShader(shaderProgram, fragmentShader);
+ gl.attachShader(shaderProgram, vertexShader);
+ }
+
+ gl.linkProgram(shaderProgram);
+ }
+
+ function getShader(gl, id) {
+ let script = document.getElementById(id);
+ let source = script.textContent;
+ let shader;
+
+ if (script.type == "x-shader/x-fragment") {
+ shader = gl.createShader(gl.FRAGMENT_SHADER);
+ } else if (script.type == "x-shader/x-vertex") {
+ shader = gl.createShader(gl.VERTEX_SHADER);
+ }
+
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+
+ return shader;
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/devtools/client/shadereditor/test/doc_simple-canvas.html b/devtools/client/shadereditor/test/doc_simple-canvas.html
new file mode 100644
index 000000000..2a709ad8e
--- /dev/null
+++ b/devtools/client/shadereditor/test/doc_simple-canvas.html
@@ -0,0 +1,125 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>WebGL editor test page</title>
+
+ <script id="shader-vs" type="x-shader/x-vertex">
+ precision lowp float;
+ attribute vec3 aVertexPosition;
+ attribute vec3 aVertexColor;
+ varying vec3 vFragmentColor;
+
+ void main(void) {
+ gl_Position = vec4(aVertexPosition, 1.0);
+ vFragmentColor = aVertexColor; // I'm special!
+ }
+ </script>
+
+ <script id="shader-fs" type="x-shader/x-fragment">
+ precision lowp float;
+ varying vec3 vFragmentColor;
+
+ void main(void) {
+ gl_FragColor = vec4(vFragmentColor, 1.0); // I'm also special!
+ }
+ </script>
+ </head>
+
+ <body>
+ <canvas width="512" height="512"></canvas>
+
+ <script type="text/javascript;version=1.8">
+ "use strict";
+
+ let canvas, gl;
+ let program;
+ let squareVerticesPositionBuffer;
+ let squareVerticesColorBuffer;
+ let vertexPositionAttribute;
+ let vertexColorAttribute;
+
+ window.onload = function() {
+ canvas = document.querySelector("canvas");
+ gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+ initProgram();
+ initBuffers();
+ drawScene();
+ }
+
+ function initProgram() {
+ let vertexShader = getShader(gl, "shader-vs");
+ let fragmentShader = getShader(gl, "shader-fs");
+
+ program = gl.createProgram();
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ gl.linkProgram(program);
+
+ vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition");
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+
+ vertexColorAttribute = gl.getAttribLocation(program, "aVertexColor");
+ gl.enableVertexAttribArray(vertexColorAttribute);
+ }
+
+ function getShader(gl, id) {
+ let script = document.getElementById(id);
+ let source = script.textContent;
+ let shader;
+
+ if (script.type == "x-shader/x-fragment") {
+ shader = gl.createShader(gl.FRAGMENT_SHADER);
+ } else if (script.type == "x-shader/x-vertex") {
+ shader = gl.createShader(gl.VERTEX_SHADER);
+ }
+
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+
+ return shader;
+ }
+
+ function initBuffers() {
+ squareVerticesPositionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 1.0, 1.0, 0.0,
+ -1.0, 1.0, 0.0,
+ 1.0, -1.0, 0.0,
+ -1.0, -1.0, 0.0
+ ]), gl.STATIC_DRAW);
+
+ squareVerticesColorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 1.0, 1.0, 1.0, 1.0,
+ 1.0, 0.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0
+ ]), gl.STATIC_DRAW);
+ }
+
+ function drawScene() {
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);
+ gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
+
+ gl.useProgram(program);
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+
+ window.requestAnimationFrame(drawScene);
+ }
+ </script>
+ </body>
+
+</html>
diff --git a/devtools/client/shadereditor/test/head.js b/devtools/client/shadereditor/test/head.js
new file mode 100644
index 000000000..754a0605d
--- /dev/null
+++ b/devtools/client/shadereditor/test/head.js
@@ -0,0 +1,292 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+var { Task } = require("devtools/shared/task");
+
+var Services = require("Services");
+var promise = require("promise");
+var { gDevTools } = require("devtools/client/framework/devtools");
+var { DebuggerClient } = require("devtools/shared/client/main");
+var { DebuggerServer } = require("devtools/server/main");
+var { WebGLFront } = require("devtools/shared/fronts/webgl");
+var DevToolsUtils = require("devtools/shared/DevToolsUtils");
+var flags = require("devtools/shared/flags");
+var { TargetFactory } = require("devtools/client/framework/target");
+var { Toolbox } = require("devtools/client/framework/toolbox");
+var { isWebGLSupported } = require("devtools/client/shared/webgl-utils");
+var mm = null;
+
+const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js";
+const EXAMPLE_URL = "http://example.com/browser/devtools/client/shadereditor/test/";
+const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html";
+const SHADER_ORDER_URL = EXAMPLE_URL + "doc_shader-order.html";
+const MULTIPLE_CONTEXTS_URL = EXAMPLE_URL + "doc_multiple-contexts.html";
+const OVERLAPPING_GEOMETRY_CANVAS_URL = EXAMPLE_URL + "doc_overlapping-geometry.html";
+const BLENDED_GEOMETRY_CANVAS_URL = EXAMPLE_URL + "doc_blended-geometry.html";
+
+var gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
+// To enable logging for try runs, just set the pref to true.
+Services.prefs.setBoolPref("devtools.debugger.log", false);
+
+// All tests are asynchronous.
+waitForExplicitFinish();
+
+var gToolEnabled = Services.prefs.getBoolPref("devtools.shadereditor.enabled");
+
+flags.testing = true;
+
+registerCleanupFunction(() => {
+ info("finish() was called, cleaning up...");
+ flags.testing = false;
+ Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
+ Services.prefs.setBoolPref("devtools.shadereditor.enabled", gToolEnabled);
+
+ // These tests use a lot of memory due to GL contexts, so force a GC to help
+ // fragmentation.
+ info("Forcing GC after shadereditor test.");
+ Cu.forceGC();
+});
+
+/**
+ * Call manually in tests that use frame script utils after initializing
+ * the shader editor. Must be called after initializing so we can detect
+ * whether or not `content` is a CPOW or not. Call after init but before navigating
+ * to different pages, as bfcache and thus shader caching gets really strange if
+ * frame script attached in the middle of the test.
+ */
+function loadFrameScripts() {
+ if (Cu.isCrossProcessWrapper(content)) {
+ mm = gBrowser.selectedBrowser.messageManager;
+ mm.loadFrameScript(FRAME_SCRIPT_UTILS_URL, false);
+ }
+}
+
+function addTab(aUrl, aWindow) {
+ info("Adding tab: " + aUrl);
+
+ let deferred = promise.defer();
+ let targetWindow = aWindow || window;
+ let targetBrowser = targetWindow.gBrowser;
+
+ targetWindow.focus();
+ let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
+ let linkedBrowser = tab.linkedBrowser;
+
+ BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
+ info("Tab added and finished loading: " + aUrl);
+ deferred.resolve(tab);
+ });
+
+ return deferred.promise;
+}
+
+function removeTab(aTab, aWindow) {
+ info("Removing tab.");
+
+ let deferred = promise.defer();
+ let targetWindow = aWindow || window;
+ let targetBrowser = targetWindow.gBrowser;
+ let tabContainer = targetBrowser.tabContainer;
+
+ tabContainer.addEventListener("TabClose", function onClose(aEvent) {
+ tabContainer.removeEventListener("TabClose", onClose, false);
+ info("Tab removed and finished closing.");
+ deferred.resolve();
+ }, false);
+
+ targetBrowser.removeTab(aTab);
+ return deferred.promise;
+}
+
+function handleError(aError) {
+ ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
+ finish();
+}
+
+function ifWebGLSupported() {
+ ok(false, "You need to define a 'ifWebGLSupported' function.");
+ finish();
+}
+
+function ifWebGLUnsupported() {
+ todo(false, "Skipping test because WebGL isn't supported.");
+ finish();
+}
+
+function test() {
+ let generator = isWebGLSupported(document) ? ifWebGLSupported : ifWebGLUnsupported;
+ Task.spawn(generator).then(null, handleError);
+}
+
+function createCanvas() {
+ return document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+}
+
+function once(aTarget, aEventName, aUseCapture = false) {
+ info("Waiting for event: '" + aEventName + "' on " + aTarget + ".");
+
+ let deferred = promise.defer();
+
+ for (let [add, remove] of [
+ ["on", "off"], // Use event emitter before DOM events for consistency
+ ["addEventListener", "removeEventListener"],
+ ["addListener", "removeListener"]
+ ]) {
+ if ((add in aTarget) && (remove in aTarget)) {
+ aTarget[add](aEventName, function onEvent(...aArgs) {
+ aTarget[remove](aEventName, onEvent, aUseCapture);
+ deferred.resolve(...aArgs);
+ }, aUseCapture);
+ break;
+ }
+ }
+
+ return deferred.promise;
+}
+
+// Hack around `once`, as that only resolves to a single (first) argument
+// and discards the rest. `onceSpread` is similar, except resolves to an
+// array of all of the arguments in the handler. These should be consolidated
+// into the same function, but many tests will need to be changed.
+function onceSpread(aTarget, aEvent) {
+ let deferred = promise.defer();
+ aTarget.once(aEvent, (...args) => deferred.resolve(args));
+ return deferred.promise;
+}
+
+function observe(aNotificationName, aOwnsWeak = false) {
+ info("Waiting for observer notification: '" + aNotificationName + ".");
+
+ let deferred = promise.defer();
+
+ Services.obs.addObserver(function onNotification(...aArgs) {
+ Services.obs.removeObserver(onNotification, aNotificationName);
+ deferred.resolve.apply(deferred, aArgs);
+ }, aNotificationName, aOwnsWeak);
+
+ return deferred.promise;
+}
+
+function isApprox(aFirst, aSecond, aMargin = 1) {
+ return Math.abs(aFirst - aSecond) <= aMargin;
+}
+
+function isApproxColor(aFirst, aSecond, aMargin) {
+ return isApprox(aFirst.r, aSecond.r, aMargin) &&
+ isApprox(aFirst.g, aSecond.g, aMargin) &&
+ isApprox(aFirst.b, aSecond.b, aMargin) &&
+ isApprox(aFirst.a, aSecond.a, aMargin);
+}
+
+function ensurePixelIs(aFront, aPosition, aColor, aWaitFlag = false, aSelector = "canvas") {
+ return Task.spawn(function* () {
+ let pixel = yield aFront.getPixel({ selector: aSelector, position: aPosition });
+ if (isApproxColor(pixel, aColor)) {
+ ok(true, "Expected pixel is shown at: " + aPosition.toSource());
+ return;
+ }
+
+ if (aWaitFlag) {
+ yield aFront.waitForFrame();
+ return ensurePixelIs(aFront, aPosition, aColor, aWaitFlag, aSelector);
+ }
+
+ ok(false, "Expected pixel was not already shown at: " + aPosition.toSource());
+ throw new Error("Expected pixel was not already shown at: " + aPosition.toSource());
+ });
+}
+
+function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate") {
+ if (Cu.isCrossProcessWrapper(content)) {
+ if (!mm) {
+ throw new Error("`loadFrameScripts()` must be called before attempting to navigate in e10s.");
+ }
+ mm.sendAsyncMessage("devtools:test:history", { direction: aDirection });
+ }
+ else {
+ executeSoon(() => content.history[aDirection]());
+ }
+ return once(aTarget, aWaitForTargetEvent);
+}
+
+function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") {
+ executeSoon(() => aTarget.activeTab.navigateTo(aUrl));
+ return once(aTarget, aWaitForTargetEvent);
+}
+
+function reload(aTarget, aWaitForTargetEvent = "navigate") {
+ executeSoon(() => aTarget.activeTab.reload());
+ return once(aTarget, aWaitForTargetEvent);
+}
+
+function initBackend(aUrl) {
+ info("Initializing a shader editor front.");
+
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ return Task.spawn(function* () {
+ let tab = yield addTab(aUrl);
+ let target = TargetFactory.forTab(tab);
+
+ yield target.makeRemote();
+
+ let front = new WebGLFront(target.client, target.form);
+ return { target, front };
+ });
+}
+
+function initShaderEditor(aUrl) {
+ info("Initializing a shader editor pane.");
+
+ return Task.spawn(function* () {
+ let tab = yield addTab(aUrl);
+ let target = TargetFactory.forTab(tab);
+
+ yield target.makeRemote();
+
+ Services.prefs.setBoolPref("devtools.shadereditor.enabled", true);
+ let toolbox = yield gDevTools.showToolbox(target, "shadereditor");
+ let panel = toolbox.getCurrentPanel();
+ return { target, panel };
+ });
+}
+
+function teardown(aPanel) {
+ info("Destroying the specified shader editor.");
+
+ return promise.all([
+ once(aPanel, "destroyed"),
+ removeTab(aPanel.target.tab)
+ ]);
+}
+
+// Due to `program-linked` events firing synchronously, we cannot
+// just yield/chain them together, as then we miss all actors after the
+// first event since they're fired consecutively. This allows us to capture
+// all actors and returns an array containing them.
+//
+// Takes a `front` object that is an event emitter, the number of
+// programs that should be listened to and waited on, and an optional
+// `onAdd` function that calls with the entire actors array on program link
+function getPrograms(front, count, onAdd) {
+ let actors = [];
+ let deferred = promise.defer();
+ front.on("program-linked", function onLink(actor) {
+ if (actors.length !== count) {
+ actors.push(actor);
+ if (typeof onAdd === "function") onAdd(actors);
+ }
+ if (actors.length === count) {
+ front.off("program-linked", onLink);
+ deferred.resolve(actors);
+ }
+ });
+ return deferred.promise;
+}