зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-inbound.
This commit is contained in:
Коммит
43c521d5fa
|
@ -2,8 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
pref("startup.homepage_override_url", "http://www.mozilla.org/projects/firefox/%VERSION%/whatsnew/?oldversion=%OLD_VERSION%");
|
||||
pref("startup.homepage_welcome_url", "http://www.mozilla.org/projects/firefox/%VERSION%/firstrun/");
|
||||
pref("startup.homepage_override_url", "https://www.mozilla.org/projects/firefox/%VERSION%/whatsnew/?oldversion=%OLD_VERSION%");
|
||||
pref("startup.homepage_welcome_url", "https://www.mozilla.org/projects/firefox/%VERSION%/firstrun/");
|
||||
// The time interval between checks for a new version (in seconds)
|
||||
pref("app.update.interval", 7200); // 2 hours
|
||||
// The time interval between the downloading of mar file chunks in the
|
||||
|
|
|
@ -4,4 +4,5 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
head.js
|
||||
hosted_app.manifest
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
|
|
@ -3,10 +3,10 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
JS_MODULES_PATH = 'modules/devtools/canvasdebugger'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'panel.js'
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
head.js
|
||||
helpers.js
|
||||
|
|
|
@ -11,4 +11,3 @@ EXTRA_JS_MODULES += [
|
|||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
addon1.xpi
|
||||
addon2.xpi
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
JS_MODULES_PATH = 'modules/devtools/eyedropper'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'eyedropper.js'
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
color-block.html
|
||||
head.js
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
|
@ -4,4 +4,4 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
browser_font.woff
|
||||
browser_fontinspector.html
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -4,4 +4,4 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
browser_toolbox_options_disable_js.html
|
||||
browser_toolbox_options_disable_js_iframe.html
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -11,4 +11,4 @@ EXTRA_JS_MODULES += [
|
|||
'selector-search.js'
|
||||
]
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
browser_inspector_breadcrumbs.html
|
||||
browser_inspector_bug_650804_search.html
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -64,6 +64,11 @@ browser.jar:
|
|||
content/browser/devtools/shadereditor.js (shadereditor/shadereditor.js)
|
||||
content/browser/devtools/canvasdebugger.xul (canvasdebugger/canvasdebugger.xul)
|
||||
content/browser/devtools/canvasdebugger.js (canvasdebugger/canvasdebugger.js)
|
||||
content/browser/devtools/webaudioeditor.xul (webaudioeditor/webaudioeditor.xul)
|
||||
content/browser/devtools/d3.js (webaudioeditor/lib/d3.js)
|
||||
content/browser/devtools/dagre-d3.js (webaudioeditor/lib/dagre-d3.js)
|
||||
content/browser/devtools/webaudioeditor-controller.js (webaudioeditor/webaudioeditor-controller.js)
|
||||
content/browser/devtools/webaudioeditor-view.js (webaudioeditor/webaudioeditor-view.js)
|
||||
content/browser/devtools/profiler.xul (profiler/profiler.xul)
|
||||
content/browser/devtools/cleopatra.html (profiler/cleopatra/cleopatra.html)
|
||||
content/browser/devtools/profiler/cleopatra/css/ui.css (profiler/cleopatra/css/ui.css)
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
head.js
|
||||
subsuite = devtools
|
||||
|
||||
[browser_layoutview.js]
|
||||
skip-if = true
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -29,6 +29,7 @@ loader.lazyGetter(this, "DebuggerPanel", () => require("devtools/debugger/panel"
|
|||
loader.lazyGetter(this, "StyleEditorPanel", () => require("devtools/styleeditor/styleeditor-panel").StyleEditorPanel);
|
||||
loader.lazyGetter(this, "ShaderEditorPanel", () => require("devtools/shadereditor/panel").ShaderEditorPanel);
|
||||
loader.lazyGetter(this, "CanvasDebuggerPanel", () => require("devtools/canvasdebugger/panel").CanvasDebuggerPanel);
|
||||
loader.lazyGetter(this, "WebAudioEditorPanel", () => require("devtools/webaudioeditor/panel").WebAudioEditorPanel);
|
||||
loader.lazyGetter(this, "ProfilerPanel", () => require("devtools/profiler/panel"));
|
||||
loader.lazyGetter(this, "NetMonitorPanel", () => require("devtools/netmonitor/panel").NetMonitorPanel);
|
||||
loader.lazyGetter(this, "ScratchpadPanel", () => require("devtools/scratchpad/scratchpad-panel").ScratchpadPanel);
|
||||
|
@ -40,6 +41,8 @@ const debuggerProps = "chrome://browser/locale/devtools/debugger.properties";
|
|||
const styleEditorProps = "chrome://browser/locale/devtools/styleeditor.properties";
|
||||
const shaderEditorProps = "chrome://browser/locale/devtools/shadereditor.properties";
|
||||
const canvasDebuggerProps = "chrome://browser/locale/devtools/canvasdebugger.properties";
|
||||
const webAudioEditorProps = "chrome://browser/locale/devtools/webaudioeditor.properties";
|
||||
|
||||
const webConsoleProps = "chrome://browser/locale/devtools/webconsole.properties";
|
||||
const profilerProps = "chrome://browser/locale/devtools/profiler.properties";
|
||||
const netMonitorProps = "chrome://browser/locale/devtools/netmonitor.properties";
|
||||
|
@ -50,6 +53,7 @@ loader.lazyGetter(this, "debuggerStrings", () => Services.strings.createBundle(d
|
|||
loader.lazyGetter(this, "styleEditorStrings", () => Services.strings.createBundle(styleEditorProps));
|
||||
loader.lazyGetter(this, "shaderEditorStrings", () => Services.strings.createBundle(shaderEditorProps));
|
||||
loader.lazyGetter(this, "canvasDebuggerStrings", () => Services.strings.createBundle(canvasDebuggerProps));
|
||||
loader.lazyGetter(this, "webAudioEditorStrings", () => Services.strings.createBundle(webAudioEditorProps));
|
||||
loader.lazyGetter(this, "inspectorStrings", () => Services.strings.createBundle(inspectorProps));
|
||||
loader.lazyGetter(this, "profilerStrings",() => Services.strings.createBundle(profilerProps));
|
||||
loader.lazyGetter(this, "netMonitorStrings", () => Services.strings.createBundle(netMonitorProps));
|
||||
|
@ -219,17 +223,33 @@ Tools.canvasDebugger = {
|
|||
url: "chrome://browser/content/devtools/canvasdebugger.xul",
|
||||
label: l10n("ToolboxCanvasDebugger.label", canvasDebuggerStrings),
|
||||
tooltip: l10n("ToolboxCanvasDebugger.tooltip", canvasDebuggerStrings),
|
||||
|
||||
isTargetSupported: function(target) {
|
||||
return !target.isAddon;
|
||||
},
|
||||
|
||||
build: function(iframeWindow, toolbox) {
|
||||
build: function (iframeWindow, toolbox) {
|
||||
let panel = new CanvasDebuggerPanel(iframeWindow, toolbox);
|
||||
return panel.open();
|
||||
}
|
||||
};
|
||||
|
||||
Tools.webAudioEditor = {
|
||||
id: "webaudioeditor",
|
||||
ordinal: 10,
|
||||
visibilityswitch: "devtools.webaudioeditor.enabled",
|
||||
icon: "chrome://browser/skin/devtools/tool-styleeditor.svg",
|
||||
invertIconForLightTheme: true,
|
||||
url: "chrome://browser/content/devtools/webaudioeditor.xul",
|
||||
label: l10n("ToolboxWebAudioEditor.label", webAudioEditorStrings),
|
||||
tooltip: l10n("ToolboxWebAudioEditor.tooltip", webAudioEditorStrings),
|
||||
isTargetSupported: function(target) {
|
||||
return !target.isAddon;
|
||||
},
|
||||
build: function(iframeWindow, toolbox) {
|
||||
let panel = new WebAudioEditorPanel(iframeWindow, toolbox);
|
||||
return panel.open();
|
||||
}
|
||||
};
|
||||
|
||||
Tools.jsprofiler = {
|
||||
id: "jsprofiler",
|
||||
accesskey: l10n("profiler.accesskey", profilerStrings),
|
||||
|
@ -310,6 +330,7 @@ let defaultTools = [
|
|||
Tools.styleEditor,
|
||||
Tools.shaderEditor,
|
||||
Tools.canvasDebugger,
|
||||
Tools.webAudioEditor,
|
||||
Tools.jsprofiler,
|
||||
Tools.netMonitor,
|
||||
Tools.scratchpad
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
doc_markup_edit.html
|
||||
doc_markup_flashing.html
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -3,10 +3,10 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
JS_MODULES_PATH = 'modules/devtools/netmonitor'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'panel.js'
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
head.js
|
||||
html_content-type-test-page.html
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -4,4 +4,4 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
# Disabled globally due to crashes/timeouts on all platforms (bug 973974)
|
||||
skip-if = true # Overrides the e10s case above.
|
||||
subsuite = devtools
|
||||
|
||||
# Crashes/timeouts on all platforms (bug 973974)
|
||||
skip-if = true
|
||||
support-files =
|
||||
head.js
|
||||
mock_console_api.html
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -8,4 +8,4 @@ EXTRA_JS_MODULES += [
|
|||
'resize-commands.js'
|
||||
]
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
head.js
|
||||
touch.html
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -4,11 +4,11 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
JS_MODULES_PATH = 'modules/devtools/scratchpad'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'scratchpad-commands.js',
|
||||
'scratchpad-panel.js'
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files = head.js
|
||||
|
||||
[browser_scratchpad_browser_last_window_closing.js]
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -3,10 +3,10 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
JS_MODULES_PATH = 'modules/devtools/shadereditor'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'panel.js'
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
doc_blended-geometry.html
|
||||
doc_multiple-contexts.html
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
|
@ -4,4 +4,5 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
browser_layoutHelpers.html
|
||||
browser_layoutHelpers_iframe.html
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -4,8 +4,6 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
JS_MODULES_PATH = 'modules/devtools/sourceeditor'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
|
@ -16,3 +14,4 @@ EXTRA_JS_MODULES += [
|
|||
'editor.js'
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
cm_comment_test.js
|
||||
cm_doc_test.js
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -4,4 +4,4 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
autocomplete.html
|
||||
browser_styleeditor_cmd_edit.html
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -4,4 +4,5 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
doc_content_stylesheet.html
|
||||
doc_content_stylesheet.xul
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
|
@ -16,4 +16,4 @@ EXTRA_JS_MODULES += [
|
|||
'TiltWorkerPicker.js'
|
||||
]
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files = head.js
|
||||
|
||||
[browser_tilt_01_lazy_getter.js]
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
Copyright (c) 2014, Michael Bostock
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* The name Michael Bostock may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2013 Chris Pettitt
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -3,10 +3,10 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
||||
JS_MODULES_PATH = 'modules/devtools/webaudioeditor'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'panel.js'
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { Cc, Ci, Cu, Cr } = require("chrome");
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const { WebAudioFront } = require("devtools/server/actors/webaudio");
|
||||
let Promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
|
||||
function WebAudioEditorPanel (iframeWindow, toolbox) {
|
||||
this.panelWin = iframeWindow;
|
||||
this._toolbox = toolbox;
|
||||
this._destroyer = null;
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
exports.WebAudioEditorPanel = WebAudioEditorPanel;
|
||||
|
||||
WebAudioEditorPanel.prototype = {
|
||||
open: function() {
|
||||
let targetPromise;
|
||||
|
||||
// Local debugging needs to make the target remote.
|
||||
if (!this.target.isRemote) {
|
||||
targetPromise = this.target.makeRemote();
|
||||
} else {
|
||||
targetPromise = Promise.resolve(this.target);
|
||||
}
|
||||
|
||||
return targetPromise
|
||||
.then(() => {
|
||||
this.panelWin.gToolbox = this._toolbox;
|
||||
this.panelWin.gTarget = this.target;
|
||||
this.panelWin.gFront = new WebAudioFront(this.target.client, this.target.form);
|
||||
return this.panelWin.startupWebAudioEditor();
|
||||
})
|
||||
.then(() => {
|
||||
this.isReady = true;
|
||||
this.emit("ready");
|
||||
return this;
|
||||
})
|
||||
.then(null, function onError(aReason) {
|
||||
Cu.reportError("WebAudioEditorPanel open failed. " +
|
||||
aReason.error + ": " + aReason.message);
|
||||
});
|
||||
},
|
||||
|
||||
// DevToolPanel API
|
||||
|
||||
get target() this._toolbox.target,
|
||||
|
||||
destroy: function() {
|
||||
// Make sure this panel is not already destroyed.
|
||||
if (this._destroyer) {
|
||||
return this._destroyer;
|
||||
}
|
||||
|
||||
return this._destroyer = this.panelWin.shutdownWebAudioEditor().then(() => {
|
||||
this.emit("destroyed");
|
||||
});
|
||||
}
|
||||
};
|
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
doc_simple-context.html
|
||||
|
@ -6,7 +7,19 @@ support-files =
|
|||
doc_simple-node-creation.html
|
||||
head.js
|
||||
|
||||
[browser_webaudio-actor-simple.js]
|
||||
[browser_audionode-actor-get-set-param.js]
|
||||
[browser_audionode-actor-is-source.js]
|
||||
[browser_audionode-actor-get-type.js]
|
||||
[browser_audionode-actor-get-params.js]
|
||||
[browser_audionode-actor-get-param-flags.js]
|
||||
[browser_audionode-actor-is-source.js]
|
||||
[browser_webaudio-actor-simple.js]
|
||||
|
||||
[browser_wa_first-run.js]
|
||||
|
||||
[browser_wa_graph_mouseover.js]
|
||||
[browser_wa_graph_render_01.js]
|
||||
[browser_wa_graph_render_02.js]
|
||||
|
||||
[browser_wa_params_view_edit.js]
|
||||
[browser_wa_params_view_events.js]
|
||||
[browser_wa_params_view_mouseover.js]
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test AudioNode#getParamFlags()
|
||||
*/
|
||||
|
||||
function spawnTest () {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_NODES_URL);
|
||||
let [_, nodes] = yield Promise.all([
|
||||
front.setup({ reload: true }),
|
||||
getN(front, "create-node", 14)
|
||||
]);
|
||||
|
||||
let allNodeParams = yield Promise.all(nodes.map(node => node.getParams()));
|
||||
let nodeTypes = [
|
||||
"AudioDestinationNode",
|
||||
"AudioBufferSourceNode", "ScriptProcessorNode", "AnalyserNode", "GainNode",
|
||||
"DelayNode", "BiquadFilterNode", "WaveShaperNode", "PannerNode", "ConvolverNode",
|
||||
"ChannelSplitterNode", "ChannelMergerNode", "DynamicsCompressorNode", "OscillatorNode"
|
||||
];
|
||||
|
||||
nodeTypes.forEach(function (type, i) {
|
||||
let params = allNodeParams[i];
|
||||
params.forEach(function ({param, value, flags}) {
|
||||
|
||||
let testFlags = yield nodes[i].getParamFlag(param);
|
||||
ok(typeof testFlags === "object", type + " has flags from #getParamFlag(" + param + ")");
|
||||
|
||||
if (param === "buffer") {
|
||||
is(flags.Buffer, true, "`buffer` params have Buffer flag");
|
||||
}
|
||||
else if (param === "bufferSize" || param === "frequencyBinCount") {
|
||||
is(flags.readonly, true, param + " is readonly");
|
||||
}
|
||||
else if (param === "curve") {
|
||||
is(flags["Float32Array"], true, "`curve` param has Float32Array flag");
|
||||
} else {
|
||||
is(Object.keys(flags), 0, type + "-" + param + " has no flags set")
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test AudioNode#getParams()
|
||||
*/
|
||||
|
||||
function spawnTest () {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_NODES_URL);
|
||||
let [_, nodes] = yield Promise.all([
|
||||
front.setup({ reload: true }),
|
||||
getN(front, "create-node", 14)
|
||||
]);
|
||||
|
||||
let allNodeParams = yield Promise.all(nodes.map(node => node.getParams()));
|
||||
let nodeTypes = [
|
||||
"AudioDestinationNode",
|
||||
"AudioBufferSourceNode", "ScriptProcessorNode", "AnalyserNode", "GainNode",
|
||||
"DelayNode", "BiquadFilterNode", "WaveShaperNode", "PannerNode", "ConvolverNode",
|
||||
"ChannelSplitterNode", "ChannelMergerNode", "DynamicsCompressorNode", "OscillatorNode"
|
||||
];
|
||||
|
||||
nodeTypes.forEach((type, i) => {
|
||||
let params = allNodeParams[i];
|
||||
params.forEach(({param, value, flags}) => {
|
||||
ok(~NODE_PROPERTIES[type].indexOf(param), "expected parameter for " + type);
|
||||
|
||||
// Skip over some properties that are undefined by default
|
||||
if (!/buffer|loop|smoothing|curve|cone/.test(param)) {
|
||||
ok(value != undefined, param + " is not undefined");
|
||||
}
|
||||
|
||||
ok(typeof flags === "object", type + " has a flags object");
|
||||
|
||||
if (param === "buffer") {
|
||||
is(flags.Buffer, true, "`buffer` params have Buffer flag");
|
||||
}
|
||||
else if (param === "bufferSize" || param === "frequencyBinCount") {
|
||||
is(flags.readonly, true, param + " is readonly");
|
||||
}
|
||||
else if (param === "curve") {
|
||||
is(flags["Float32Array"], true, "`curve` param has Float32Array flag");
|
||||
} else {
|
||||
is(Object.keys(flags), 0, type + "-" + param + " has no flags set")
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* 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 spawnTest() {
|
||||
let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_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 an audio 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 started = once(gFront, "start-context");
|
||||
|
||||
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 an audio context' notice should be visible when navigating.");
|
||||
is($("#content").hidden, true,
|
||||
"The tool's content should still be hidden.");
|
||||
|
||||
yield started;
|
||||
|
||||
is($("#reload-notice").hidden, true,
|
||||
"The 'reload this page' notice should be hidden after context found.");
|
||||
is($("#waiting-notice").hidden, true,
|
||||
"The 'waiting for an audio context' notice should be hidden after context found.");
|
||||
is($("#content").hidden, false,
|
||||
"The tool's content should not be hidden anymore.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/* 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 spawnTest() {
|
||||
let [target, debuggee, panel] = yield initWebAudioEditor(COMPLEX_CONTEXT_URL);
|
||||
let { gFront, $, $$, EVENTS, WebAudioParamView } = panel.panelWin;
|
||||
let gVars = WebAudioParamView._paramsView;
|
||||
|
||||
let started = once(gFront, "start-context");
|
||||
|
||||
reload(target);
|
||||
|
||||
yield Promise.all([
|
||||
getN(gFront, "create-node", 8),
|
||||
getNSpread(panel.panelWin, EVENTS.UI_ADD_NODE_LIST, 8),
|
||||
waitForGraphRendered(panel.panelWin, 8, 8)
|
||||
]);
|
||||
|
||||
let $items = $$(".variables-view-scope");
|
||||
let $graphNodes = $$(".nodes > g");
|
||||
|
||||
for (let $item of $items) {
|
||||
mouseOver(panel.panelWin, $(".devtools-toolbar", $item));
|
||||
// Get actorID from id of variable scope
|
||||
let id = $item.id.match(/\(([^\)]*)\)/)[1];
|
||||
|
||||
// Go over all graph nodes and check only the selected one is highlighted
|
||||
for (let $node of $graphNodes) {
|
||||
let shouldBeSelected = id === $node.getAttribute("data-id");
|
||||
ok($node.classList.contains("selected") === shouldBeSelected,
|
||||
"graph node correctly " + (shouldBeSelected ? "" : "not ") + "highlighted on param view mouseover");
|
||||
}
|
||||
}
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/* 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 spawnTest() {
|
||||
let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
|
||||
let { panelWin } = panel;
|
||||
let { gFront, $, $$, EVENTS, WebAudioParamView } = panelWin;
|
||||
let gVars = WebAudioParamView._paramsView;
|
||||
|
||||
let started = once(gFront, "start-context");
|
||||
|
||||
reload(target);
|
||||
|
||||
let [[dest, osc, gain], [[_, destID], [_, oscID], [_, gainID]]] = yield Promise.all([
|
||||
get3(gFront, "create-node"),
|
||||
get3Spread(panelWin, EVENTS.UI_ADD_NODE_LIST),
|
||||
waitForGraphRendered(panelWin, 3, 2)
|
||||
]);
|
||||
|
||||
ok(findGraphNode(panelWin, oscID).classList.contains("type-OscillatorNode"), "found OscillatorNode with class");
|
||||
ok(findGraphNode(panelWin, gainID).classList.contains("type-GainNode"), "found GainNode with class");
|
||||
ok(findGraphNode(panelWin, destID).classList.contains("type-AudioDestinationNode"), "found AudioDestinationNode with class");
|
||||
is(findGraphEdge(panelWin, oscID, gainID).toString(), "[object SVGGElement]", "found edge for osc -> gain");
|
||||
is(findGraphEdge(panelWin, gainID, destID).toString(), "[object SVGGElement]", "found edge for gain -> dest");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/* 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 spawnTest() {
|
||||
let [target, debuggee, panel] = yield initWebAudioEditor(COMPLEX_CONTEXT_URL);
|
||||
let { panelWin } = panel;
|
||||
let { gFront, $, $$, EVENTS, WebAudioParamView } = panelWin;
|
||||
let gVars = WebAudioParamView._paramsView;
|
||||
|
||||
let started = once(gFront, "start-context");
|
||||
|
||||
reload(target);
|
||||
|
||||
let [[dest, osc, gain], nodeIDs ]= yield Promise.all([
|
||||
getN(gFront, "create-node", 8),
|
||||
getNSpread(panelWin, EVENTS.UI_ADD_NODE_LIST, 8),
|
||||
waitForGraphRendered(panelWin, 8, 8)
|
||||
]);
|
||||
|
||||
// Map result to only have ID, since we don't need the event name
|
||||
nodeIDs = nodeIDs.map(eventResult => eventResult[1]);
|
||||
let types = ["AudioDestinationNode", "OscillatorNode", "GainNode", "ScriptProcessorNode",
|
||||
"OscillatorNode", "GainNode", "AudioBufferSourceNode", "BiquadFilterNode"];
|
||||
|
||||
|
||||
types.forEach((type, i) => {
|
||||
ok(findGraphNode(panelWin, nodeIDs[i]).classList.contains("type-" + type), "found " + type + " with class");
|
||||
});
|
||||
|
||||
let edges = [
|
||||
[1, 2, "osc1 -> gain1"],
|
||||
[1, 3, "osc1 -> proc"],
|
||||
[2, 0, "gain1 -> dest"],
|
||||
[4, 5, "osc2 -> gain2"],
|
||||
[5, 0, "gain2 -> dest"],
|
||||
[6, 7, "buf -> filter"],
|
||||
[4, 7, "osc2 -> filter"],
|
||||
[7, 0, "filter -> dest"],
|
||||
];
|
||||
|
||||
edges.forEach(([source, target, msg], i) => {
|
||||
is(findGraphEdge(panelWin, nodeIDs[source], nodeIDs[target]).toString(), "[object SVGGElement]",
|
||||
"found edge for " + msg);
|
||||
});
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/* 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 spawnTest() {
|
||||
let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
|
||||
let { gFront, $, $$, EVENTS, WebAudioParamView } = panel.panelWin;
|
||||
let gVars = WebAudioParamView._paramsView;
|
||||
|
||||
let started = once(gFront, "start-context");
|
||||
|
||||
reload(target);
|
||||
|
||||
let [[dest, osc, gain], [[_, destID], [_, oscID], [_, gainID]]] = yield Promise.all([
|
||||
get3(gFront, "create-node"),
|
||||
get3Spread(panel.panelWin, EVENTS.UI_ADD_NODE_LIST)
|
||||
]);
|
||||
|
||||
|
||||
checkVariableView(gVars, 1, {
|
||||
"type": "\"sine\"",
|
||||
"frequency": 440,
|
||||
"detune": 0
|
||||
});
|
||||
|
||||
checkVariableView(gVars, 2, {
|
||||
"gain": 0
|
||||
});
|
||||
|
||||
yield modifyVariableView(panel.panelWin, gVars, 1, "type", "square");
|
||||
|
||||
checkVariableView(gVars, 1, {
|
||||
"type": "\"square\""
|
||||
});
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/* 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 spawnTest() {
|
||||
let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
|
||||
let { gFront, $, $$, EVENTS, WebAudioParamView } = panel.panelWin;
|
||||
let gVars = WebAudioParamView._paramsView;
|
||||
|
||||
let started = once(gFront, "start-context");
|
||||
|
||||
reload(target);
|
||||
|
||||
let [[dest, osc, gain], [[_, destID], [_, oscID], [_, gainID]]] = yield Promise.all([
|
||||
get3(gFront, "create-node"),
|
||||
get3Spread(panel.panelWin, EVENTS.UI_ADD_NODE_LIST)
|
||||
]);
|
||||
|
||||
yield modifyVariableView(panel.panelWin, gVars, 1, "frequency", "invalid-frequency").then(null, (message) => {
|
||||
ok(true, "Correctly fires EVENTS.UI_SET_PARAM_ERROR");
|
||||
});
|
||||
|
||||
checkVariableView(gVars, 1, {
|
||||
"frequency": 1000
|
||||
});
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/* 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 spawnTest() {
|
||||
let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
|
||||
let { gFront, $, $$, EVENTS } = panel.panelWin;
|
||||
|
||||
let started = once(gFront, "start-context");
|
||||
|
||||
reload(target);
|
||||
|
||||
let [[dest, osc, gain], [[_, destID], [_, oscID], [_, gainID]]] = yield Promise.all([
|
||||
get3(gFront, "create-node"),
|
||||
get3Spread(panel.panelWin, EVENTS.UI_ADD_NODE_LIST)
|
||||
]);
|
||||
|
||||
is(dest.actorID, destID, "EVENTS.UI_ADD_NODE_LIST fired for node with ID");
|
||||
is(osc.actorID, oscID, "EVENTS.UI_ADD_NODE_LIST fired for node with ID");
|
||||
is(gain.actorID, gainID, "EVENTS.UI_ADD_NODE_LIST fired for node with ID");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/* 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 spawnTest() {
|
||||
let [target, debuggee, panel] = yield initWebAudioEditor(COMPLEX_CONTEXT_URL);
|
||||
let { gFront, $, $$, EVENTS, WebAudioParamView } = panel.panelWin;
|
||||
let gVars = WebAudioParamView._paramsView;
|
||||
|
||||
let started = once(gFront, "start-context");
|
||||
|
||||
reload(target);
|
||||
|
||||
yield Promise.all([
|
||||
getN(gFront, "create-node", 8),
|
||||
getNSpread(panel.panelWin, EVENTS.UI_ADD_NODE_LIST, 8),
|
||||
waitForGraphRendered(panel.panelWin, 8, 8)
|
||||
]);
|
||||
|
||||
let $items = $$(".variables-view-scope");
|
||||
let $graphNodes = $$(".nodes > g");
|
||||
|
||||
Array.prototype.forEach.call($items, $item => {
|
||||
mouseOver(panel.panelWin, $(".devtools-toolbar", $item));
|
||||
// Get actorID from id of variable scope
|
||||
let id = $item.id.match(/\(([^\)]*)\)/)[1];
|
||||
|
||||
// Go over all graph nodes and check only the selected one is highlighted
|
||||
Array.prototype.forEach.call($graphNodes, $node => {
|
||||
let shouldBeSelected = id === $node.getAttribute("data-id");
|
||||
ok($node.classList.contains("selected") === shouldBeSelected,
|
||||
"graph node correctly " + (shouldBeSelected ? "" : "not ") + "highlighted on param view mouseover");
|
||||
});
|
||||
});
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
|
@ -16,11 +16,9 @@ let { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
|||
let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
|
||||
let { WebAudioFront } = devtools.require("devtools/server/actors/webaudio");
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let Toolbox = devtools.Toolbox;
|
||||
|
||||
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/webaudioeditor/test/";
|
||||
const SIMPLE_CONTEXT_URL = EXAMPLE_URL + "doc_simple-context.html";
|
||||
|
@ -104,6 +102,11 @@ function once(aTarget, aEventName, aUseCapture = false) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
function reload(aTarget, aWaitForTargetEvent = "navigate") {
|
||||
aTarget.activeTab.reload();
|
||||
return once(aTarget, aWaitForTargetEvent);
|
||||
}
|
||||
|
||||
function test () {
|
||||
Task.spawn(spawnTest).then(finish, handleError);
|
||||
}
|
||||
|
@ -128,6 +131,38 @@ function initBackend(aUrl) {
|
|||
});
|
||||
}
|
||||
|
||||
function initWebAudioEditor(aUrl) {
|
||||
info("Initializing a web audio editor pane.");
|
||||
|
||||
return Task.spawn(function*() {
|
||||
let tab = yield addTab(aUrl);
|
||||
let target = TargetFactory.forTab(tab);
|
||||
let debuggee = target.window.wrappedJSObject;
|
||||
|
||||
yield target.makeRemote();
|
||||
|
||||
Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", true);
|
||||
let toolbox = yield gDevTools.showToolbox(target, "webaudioeditor");
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
return [target, debuggee, panel];
|
||||
});
|
||||
}
|
||||
|
||||
function teardown(aPanel) {
|
||||
info("Destroying the web audio editor.");
|
||||
|
||||
return Promise.all([
|
||||
once(aPanel, "destroyed"),
|
||||
removeTab(aPanel.target.tab)
|
||||
]).then(() => {
|
||||
let gBrowser = window.gBrowser;
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
gBrowser = null;
|
||||
});
|
||||
}
|
||||
|
||||
// Due to web audio will fire most events synchronously back-to-back,
|
||||
// and we can't yield them in a chain without missing actors, this allows
|
||||
// us to listen for `n` events and return a promise resolving to them.
|
||||
|
@ -158,3 +193,116 @@ function getSpread (front, eventName) { return getN(front, eventName, 1, true);
|
|||
function get2Spread (front, eventName) { return getN(front, eventName, 2, true); }
|
||||
function get3Spread (front, eventName) { return getN(front, eventName, 3, true); }
|
||||
function getNSpread (front, eventName, count) { return getN(front, eventName, count, true); }
|
||||
|
||||
/**
|
||||
* Waits for the UI_GRAPH_RENDERED event to fire, but only
|
||||
* resolves when the graph was rendered with the correct count of
|
||||
* nodes and edges.
|
||||
*/
|
||||
function waitForGraphRendered (front, nodeCount, edgeCount) {
|
||||
let deferred = Promise.defer();
|
||||
let eventName = front.EVENTS.UI_GRAPH_RENDERED;
|
||||
front.on(eventName, function onGraphRendered (_, nodes, edges) {
|
||||
if (nodes === nodeCount && edges === edgeCount) {
|
||||
front.off(eventName, onGraphRendered);
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkVariableView (view, index, hash) {
|
||||
let scope = view.getScopeAtIndex(index);
|
||||
let variables = Object.keys(hash);
|
||||
variables.forEach(variable => {
|
||||
let aVar = scope.get(variable);
|
||||
is(aVar.target.querySelector(".name").getAttribute("value"), variable,
|
||||
"Correct property name for " + variable);
|
||||
is(aVar.target.querySelector(".value").getAttribute("value"), hash[variable],
|
||||
"Correct property value of " + hash[variable] + " for " + variable);
|
||||
});
|
||||
}
|
||||
|
||||
function modifyVariableView (win, view, index, prop, value) {
|
||||
let deferred = Promise.defer();
|
||||
let scope = view.getScopeAtIndex(index);
|
||||
let aVar = scope.get(prop);
|
||||
scope.expand();
|
||||
|
||||
// Must wait for the scope DOM to be available to receive
|
||||
// events
|
||||
executeSoon(() => {
|
||||
let varValue = aVar.target.querySelector(".title > .value");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, varValue, win);
|
||||
|
||||
win.on(win.EVENTS.UI_SET_PARAM, handleSetting);
|
||||
win.on(win.EVENTS.UI_SET_PARAM_ERROR, handleSetting);
|
||||
|
||||
info("Setting " + value + " for " + prop + "....");
|
||||
let varInput = aVar.target.querySelector(".title > .element-value-input");
|
||||
setText(varInput, value);
|
||||
EventUtils.sendKey("RETURN", win);
|
||||
});
|
||||
|
||||
function handleSetting (eventName) {
|
||||
win.off(win.EVENTS.UI_SET_PARAM, handleSetting);
|
||||
win.off(win.EVENTS.UI_SET_PARAM_ERROR, handleSetting);
|
||||
if (eventName === win.EVENTS.UI_SET_PARAM)
|
||||
deferred.resolve();
|
||||
if (eventName === win.EVENTS.UI_SET_PARAM_ERROR)
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function clearText (aElement) {
|
||||
info("Clearing text...");
|
||||
aElement.focus();
|
||||
aElement.value = "";
|
||||
}
|
||||
|
||||
function setText (aElement, aText) {
|
||||
clearText(aElement);
|
||||
info("Setting text: " + aText);
|
||||
aElement.value = aText;
|
||||
}
|
||||
|
||||
function findGraphEdge (win, source, target) {
|
||||
let selector = ".edgePaths .edgePath[data-source='" + source + "'][data-target='" + target + "']";
|
||||
return win.document.querySelector(selector);
|
||||
}
|
||||
|
||||
function findGraphNode (win, node) {
|
||||
let selector = ".nodes > g[data-id='" + node + "']";
|
||||
return win.document.querySelector(selector);
|
||||
}
|
||||
|
||||
function click (win, element) {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, element, win);
|
||||
}
|
||||
|
||||
function mouseOver (win, element) {
|
||||
EventUtils.sendMouseEvent({ type: "mouseover" }, element, win);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of audio node properties to test against expectations of the AudioNode actor
|
||||
*/
|
||||
|
||||
const NODE_PROPERTIES = {
|
||||
"OscillatorNode": ["type", "frequency", "detune"],
|
||||
"GainNode": ["gain"],
|
||||
"DelayNode": ["delayTime"],
|
||||
"AudioBufferSourceNode": ["buffer", "playbackRate", "loop", "loopStart", "loopEnd"],
|
||||
"ScriptProcessorNode": ["bufferSize"],
|
||||
"PannerNode": ["panningModel", "distanceModel", "refDistance", "maxDistance", "rolloffFactor", "coneInnerAngle", "coneOuterAngle", "coneOuterGain"],
|
||||
"ConvolverNode": ["buffer", "normalize"],
|
||||
"DynamicsCompressorNode": ["threshold", "knee", "ratio", "reduction", "attack", "release"],
|
||||
"BiquadFilterNode": ["type", "frequency", "Q", "detune", "gain"],
|
||||
"WaveShaperNode": ["curve", "oversample"],
|
||||
"AnalyserNode": ["fftSize", "minDecibels", "maxDecibels", "smoothingTimeConstraint", "frequencyBinCount"],
|
||||
"AudioDestinationNode": [],
|
||||
"ChannelSplitterNode": [],
|
||||
"ChannelMergerNode": []
|
||||
};
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
|
@ -0,0 +1,310 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
|
||||
// Override DOM promises with Promise.jsm helpers
|
||||
const { defer, all } = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
|
||||
const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties"
|
||||
let { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||
|
||||
// The panel's window global is an EventEmitter firing the following events:
|
||||
const EVENTS = {
|
||||
// Fired when the first AudioNode has been created, signifying
|
||||
// that the AudioContext is being used and should be tracked via the editor.
|
||||
START_CONTEXT: "WebAudioEditor:StartContext",
|
||||
|
||||
// On node creation, connect and disconnect.
|
||||
CREATE_NODE: "WebAudioEditor:CreateNode",
|
||||
CONNECT_NODE: "WebAudioEditor:ConnectNode",
|
||||
DISCONNECT_NODE: "WebAudioEditor:DisconnectNode",
|
||||
|
||||
// When a node gets GC'd.
|
||||
DESTROY_NODE: "WebAudioEditor:DestroyNode",
|
||||
|
||||
// On a node parameter's change.
|
||||
CHANGE_PARAM: "WebAudioEditor:ChangeParam",
|
||||
|
||||
// When the UI is reset from tab navigation.
|
||||
UI_RESET: "WebAudioEditor:UIReset",
|
||||
|
||||
// When a param has been changed via the UI and successfully
|
||||
// pushed via the actor to the raw audio node.
|
||||
UI_SET_PARAM: "WebAudioEditor:UISetParam",
|
||||
|
||||
// When an audio node is added to the list pane.
|
||||
UI_ADD_NODE_LIST: "WebAudioEditor:UIAddNodeList",
|
||||
|
||||
// When the Audio Context graph finishes rendering.
|
||||
// Is called with two arguments, first representing number of nodes
|
||||
// rendered, second being the number of edges rendered.
|
||||
UI_GRAPH_RENDERED: "WebAudioEditor:UIGraphRendered"
|
||||
};
|
||||
|
||||
/**
|
||||
* The current target and the Web Audio Editor front, set by this tool's host.
|
||||
*/
|
||||
let gToolbox, gTarget, gFront;
|
||||
|
||||
/**
|
||||
* Track an array of audio nodes
|
||||
*/
|
||||
let AudioNodes = [];
|
||||
let AudioNodeConnections = new WeakMap();
|
||||
|
||||
|
||||
// Light representation wrapping an AudioNode actor with additional properties
|
||||
function AudioNodeView (actor) {
|
||||
this.actor = actor;
|
||||
this.id = actor.actorID;
|
||||
}
|
||||
|
||||
// A proxy for the underlying AudioNodeActor to fetch its type
|
||||
// and subsequently assign the type to the instance.
|
||||
AudioNodeView.prototype.getType = Task.async(function* () {
|
||||
this.type = yield this.actor.getType();
|
||||
return this.type;
|
||||
});
|
||||
|
||||
// Helper method to create connections in the AudioNodeConnections
|
||||
// WeakMap for rendering
|
||||
AudioNodeView.prototype.connect = function (destination) {
|
||||
let connections = AudioNodeConnections.get(this);
|
||||
if (!connections) {
|
||||
connections = [];
|
||||
AudioNodeConnections.set(this, connections);
|
||||
}
|
||||
connections.push(destination);
|
||||
};
|
||||
|
||||
// Helper method to remove audio connections from the current AudioNodeView
|
||||
AudioNodeView.prototype.disconnect = function () {
|
||||
AudioNodeConnections.set(this, []);
|
||||
};
|
||||
|
||||
// Returns a promise that resolves to an array of objects containing
|
||||
// both a `param` name property and a `value` property.
|
||||
AudioNodeView.prototype.getParams = function () {
|
||||
return this.actor.getParams();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the web audio editor views
|
||||
*/
|
||||
function startupWebAudioEditor() {
|
||||
return all([
|
||||
WebAudioEditorController.initialize(),
|
||||
WebAudioGraphView.initialize(),
|
||||
WebAudioParamView.initialize()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the web audio editor controller and views.
|
||||
*/
|
||||
function shutdownWebAudioEditor() {
|
||||
return all([
|
||||
WebAudioEditorController.destroy(),
|
||||
WebAudioGraphView.destroy(),
|
||||
WebAudioParamView.destroy()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions handling target-related lifetime events.
|
||||
*/
|
||||
let WebAudioEditorController = {
|
||||
/**
|
||||
* Listen for events emitted by the current tab target.
|
||||
*/
|
||||
initialize: function() {
|
||||
this._onTabNavigated = this._onTabNavigated.bind(this);
|
||||
gTarget.on("will-navigate", this._onTabNavigated);
|
||||
gTarget.on("navigate", this._onTabNavigated);
|
||||
gFront.on("start-context", this._onStartContext);
|
||||
gFront.on("create-node", this._onCreateNode);
|
||||
gFront.on("connect-node", this._onConnectNode);
|
||||
gFront.on("disconnect-node", this._onDisconnectNode);
|
||||
gFront.on("change-param", this._onChangeParam);
|
||||
|
||||
// Set up events to refresh the Graph view
|
||||
window.on(EVENTS.CREATE_NODE, this._onUpdatedContext);
|
||||
window.on(EVENTS.CONNECT_NODE, this._onUpdatedContext);
|
||||
window.on(EVENTS.DISCONNECT_NODE, this._onUpdatedContext);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove events emitted by the current tab target.
|
||||
*/
|
||||
destroy: function() {
|
||||
gTarget.off("will-navigate", this._onTabNavigated);
|
||||
gTarget.off("navigate", this._onTabNavigated);
|
||||
gFront.off("start-context", this._onStartContext);
|
||||
gFront.off("create-node", this._onCreateNode);
|
||||
gFront.off("connect-node", this._onConnectNode);
|
||||
gFront.off("disconnect-node", this._onDisconnectNode);
|
||||
gFront.off("change-param", this._onChangeParam);
|
||||
window.off(EVENTS.CREATE_NODE, this._onUpdatedContext);
|
||||
window.off(EVENTS.CONNECT_NODE, this._onUpdatedContext);
|
||||
window.off(EVENTS.DISCONNECT_NODE, this._onUpdatedContext);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a new audio node is created, or the audio context
|
||||
* routing changes.
|
||||
*/
|
||||
_onUpdatedContext: function () {
|
||||
WebAudioGraphView.draw();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called for each location change in the debugged tab.
|
||||
*/
|
||||
_onTabNavigated: function(event) {
|
||||
switch (event) {
|
||||
case "will-navigate": {
|
||||
Task.spawn(function() {
|
||||
// Make sure the backend is prepared to handle audio contexts.
|
||||
yield gFront.setup({ reload: false });
|
||||
|
||||
// Reset UI to show "Waiting for Audio Context..." and clear out
|
||||
// current UI.
|
||||
WebAudioGraphView.resetUI();
|
||||
WebAudioParamView.resetUI();
|
||||
|
||||
// Clear out stored audio nodes
|
||||
AudioNodes.length = 0;
|
||||
AudioNodeConnections.clear();
|
||||
}).then(() => window.emit(EVENTS.UI_RESET));
|
||||
break;
|
||||
}
|
||||
case "navigate": {
|
||||
// TODO Case of bfcache, needs investigating
|
||||
// bug 994250
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called after the first audio node is created in an audio context,
|
||||
* signaling that the audio context is being used.
|
||||
*/
|
||||
_onStartContext: function() {
|
||||
WebAudioGraphView.showContent();
|
||||
window.emit(EVENTS.START_CONTEXT);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a new node is created. Creates an `AudioNodeView` instance
|
||||
* for tracking throughout the editor.
|
||||
*/
|
||||
_onCreateNode: Task.async(function* (nodeActor) {
|
||||
let node = new AudioNodeView(nodeActor);
|
||||
yield node.getType();
|
||||
AudioNodes.push(node);
|
||||
window.emit(EVENTS.CREATE_NODE, node.id);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Called when a node is connected to another node.
|
||||
*/
|
||||
_onConnectNode: Task.async(function* ({ source: sourceActor, dest: destActor }) {
|
||||
// Since node create and connect are probably executed back to back,
|
||||
// and the controller's `_onCreateNode` needs to look up type,
|
||||
// the edge creation could be called before the graph node is actually
|
||||
// created. This way, we can check and listen for the event before
|
||||
// adding an edge.
|
||||
let [source, dest] = yield waitForNodeCreation(sourceActor, destActor);
|
||||
|
||||
source.connect(dest);
|
||||
window.emit(EVENTS.CONNECT_NODE, source.id, dest.id);
|
||||
|
||||
function waitForNodeCreation (sourceActor, destActor) {
|
||||
let deferred = defer();
|
||||
let source = getViewNodeByActor(sourceActor);
|
||||
let dest = getViewNodeByActor(destActor);
|
||||
|
||||
if (!source || !dest)
|
||||
window.on(EVENTS.CREATE_NODE, function createNodeListener (_, id) {
|
||||
let createdNode = getViewNodeById(id);
|
||||
if (equalActors(sourceActor, createdNode.actor))
|
||||
source = createdNode;
|
||||
if (equalActors(destActor, createdNode.actor))
|
||||
dest = createdNode;
|
||||
if (source && dest) {
|
||||
window.off(EVENTS.CREATE_NODE, createNodeListener);
|
||||
deferred.resolve([source, dest]);
|
||||
}
|
||||
});
|
||||
else
|
||||
deferred.resolve([source, dest]);
|
||||
return deferred.promise;
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Called when a node is disconnected.
|
||||
*/
|
||||
_onDisconnectNode: function(nodeActor) {
|
||||
let node = getViewNodeByActor(nodeActor);
|
||||
node.disconnect();
|
||||
window.emit(EVENTS.DISCONNECT_NODE, node.id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a node param is changed.
|
||||
*/
|
||||
_onChangeParam: function({ actor, param, value }) {
|
||||
window.emit(EVENTS.CHANGE_PARAM, getViewNodeByActor(actor), param, value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenient way of emitting events from the panel window.
|
||||
*/
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
/**
|
||||
* DOM query helper.
|
||||
*/
|
||||
function $(selector, target = document) { return target.querySelector(selector); }
|
||||
function $$(selector, target = document) { return target.querySelectorAll(selector); }
|
||||
|
||||
/**
|
||||
* Compare `actorID` between two actors to determine if they're corresponding
|
||||
* to the same underlying actor.
|
||||
*/
|
||||
function equalActors (actor1, actor2) {
|
||||
return actor1.actorID === actor2.actorID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the corresponding ViewNode by actor
|
||||
*/
|
||||
function getViewNodeByActor (actor) {
|
||||
for (let i = 0; i < AudioNodes.length; i++) {
|
||||
if (equalActors(AudioNodes[i].actor, actor))
|
||||
return AudioNodes[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the corresponding ViewNode by actorID
|
||||
*/
|
||||
function getViewNodeById (id) {
|
||||
return getViewNodeByActor({ actorID: id });
|
||||
}
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource:///modules/devtools/VariablesView.jsm");
|
||||
Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
|
||||
const { debounce } = require("sdk/lang/functional");
|
||||
|
||||
// Globals for d3 stuff
|
||||
// Width/height in pixels of SVG graph
|
||||
// TODO investigate to see how this works in other host types bug 994257
|
||||
const WIDTH = 1000;
|
||||
const HEIGHT = 400;
|
||||
|
||||
// Sizes of SVG arrows in graph
|
||||
const ARROW_HEIGHT = 5;
|
||||
const ARROW_WIDTH = 8;
|
||||
|
||||
const GRAPH_DEBOUNCE_TIMER = 100;
|
||||
|
||||
const GENERIC_VARIABLES_VIEW_SETTINGS = {
|
||||
lazyEmpty: true,
|
||||
lazyEmptyDelay: 10, // ms
|
||||
searchEnabled: false,
|
||||
editableValueTooltip: "",
|
||||
editableNameTooltip: "",
|
||||
preventDisableOnChange: true,
|
||||
preventDescriptorModifiers: true,
|
||||
eval: () => {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Functions handling the graph UI.
|
||||
*/
|
||||
let WebAudioGraphView = {
|
||||
/**
|
||||
* Initialization function, called when the tool is started.
|
||||
*/
|
||||
initialize: function() {
|
||||
this._onGraphNodeClick = this._onGraphNodeClick.bind(this);
|
||||
this.draw = debounce(this.draw.bind(this), GRAPH_DEBOUNCE_TIMER);
|
||||
},
|
||||
|
||||
/**
|
||||
* Destruction function, called when the tool is closed.
|
||||
*/
|
||||
destroy: function() {
|
||||
if (this._zoomBinding) {
|
||||
this._zoomBinding.on("zoom", null);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a page is reloaded and waiting for a "start-context" event
|
||||
* and clears out old content
|
||||
*/
|
||||
resetUI: function () {
|
||||
$("#reload-notice").hidden = true;
|
||||
$("#waiting-notice").hidden = false;
|
||||
$("#content").hidden = true;
|
||||
this.resetGraph();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called once "start-context" is fired, indicating that there is audio context
|
||||
* activity to view and inspect
|
||||
*/
|
||||
showContent: function () {
|
||||
$("#reload-notice").hidden = true;
|
||||
$("#waiting-notice").hidden = true;
|
||||
$("#content").hidden = false;
|
||||
this.draw();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears out the rendered graph, called when resetting the SVG elements to draw again,
|
||||
* or when resetting the entire UI tool
|
||||
*/
|
||||
resetGraph: function () {
|
||||
$("#graph-target").innerHTML = "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Makes the corresponding graph node appear "focused", called from WebAudioParamView
|
||||
*/
|
||||
focusNode: function (actorID) {
|
||||
// Remove class "selected" from all nodes
|
||||
Array.prototype.forEach.call($$(".nodes > g"), $node => $node.classList.remove("selected"));
|
||||
// Add to "selected"
|
||||
this._getNodeByID(actorID).classList.add("selected");
|
||||
},
|
||||
|
||||
/**
|
||||
* Unfocuses the corresponding graph node, called from WebAudioParamView
|
||||
*/
|
||||
blurNode: function (actorID) {
|
||||
this._getNodeByID(actorID).classList.remove("selected");
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes an actorID and returns the corresponding DOM SVG element in the graph
|
||||
*/
|
||||
_getNodeByID: function (actorID) {
|
||||
return $(".nodes > g[data-id='" + actorID + "']");
|
||||
},
|
||||
|
||||
/**
|
||||
* `draw` renders the ViewNodes currently available in `AudioNodes` with `AudioNodeConnections`,
|
||||
* and is throttled to be called at most every `GRAPH_DEBOUNCE_TIMER` milliseconds. Is called
|
||||
* whenever the audio context routing changes, after being debounced.
|
||||
*/
|
||||
draw: function () {
|
||||
// Clear out previous SVG information
|
||||
this.resetGraph();
|
||||
|
||||
let graph = new dagreD3.Digraph();
|
||||
let edges = [];
|
||||
|
||||
AudioNodes.forEach(node => {
|
||||
// Add node to graph
|
||||
graph.addNode(node.id, { label: node.type, id: node.id });
|
||||
|
||||
// Add all of the connections from this node to the edge array to be added
|
||||
// after all the nodes are added, otherwise edges will attempted to be created
|
||||
// for nodes that have not yet been added
|
||||
AudioNodeConnections.get(node, []).forEach(dest => edges.push([node, dest]));
|
||||
});
|
||||
|
||||
edges.forEach(([node, dest]) => graph.addEdge(null, node.id, dest.id, {
|
||||
source: node.id,
|
||||
target: dest.id
|
||||
}));
|
||||
|
||||
let renderer = new dagreD3.Renderer();
|
||||
|
||||
// Post-render manipulation of the nodes
|
||||
let oldDrawNodes = renderer.drawNodes();
|
||||
renderer.drawNodes(function(graph, root) {
|
||||
let svgNodes = oldDrawNodes(graph, root);
|
||||
svgNodes.attr("class", (n) => {
|
||||
let node = graph.node(n);
|
||||
return "type-" + node.label;
|
||||
});
|
||||
svgNodes.attr("data-id", (n) => {
|
||||
let node = graph.node(n);
|
||||
return node.id;
|
||||
});
|
||||
return svgNodes;
|
||||
});
|
||||
|
||||
// Post-render manipulation of edges
|
||||
let oldDrawEdgePaths = renderer.drawEdgePaths();
|
||||
renderer.drawEdgePaths(function(graph, root) {
|
||||
let svgNodes = oldDrawEdgePaths(graph, root);
|
||||
svgNodes.attr("data-source", (n) => {
|
||||
let edge = graph.edge(n);
|
||||
return edge.source;
|
||||
});
|
||||
svgNodes.attr("data-target", (n) => {
|
||||
let edge = graph.edge(n);
|
||||
return edge.target;
|
||||
});
|
||||
return svgNodes;
|
||||
});
|
||||
|
||||
// Override Dagre-d3's post render function by passing in our own.
|
||||
// This way we can leave styles out of it.
|
||||
renderer.postRender(function (graph, root) {
|
||||
// TODO change arrowhead color depending on theme-dark/theme-light
|
||||
// and possibly refactor rendering this as it's ugly
|
||||
// Bug 994256
|
||||
// let color = window.classList.contains("theme-dark") ? "#f5f7fa" : "#585959";
|
||||
if (graph.isDirected() && root.select("#arrowhead").empty()) {
|
||||
root
|
||||
.append("svg:defs")
|
||||
.append("svg:marker")
|
||||
.attr("id", "arrowhead")
|
||||
.attr("viewBox", "0 0 10 10")
|
||||
.attr("refX", ARROW_WIDTH)
|
||||
.attr("refY", ARROW_HEIGHT)
|
||||
.attr("markerUnits", "strokewidth")
|
||||
.attr("markerWidth", ARROW_WIDTH)
|
||||
.attr("markerHeight", ARROW_HEIGHT)
|
||||
.attr("orient", "auto")
|
||||
.attr("style", "fill: #f5f7fa")
|
||||
.append("svg:path")
|
||||
.attr("d", "M 0 0 L 10 5 L 0 10 z");
|
||||
}
|
||||
|
||||
// Fire an event upon completed rendering
|
||||
window.emit(EVENTS.UI_GRAPH_RENDERED, AudioNodes.length, edges.length);
|
||||
});
|
||||
|
||||
let layout = dagreD3.layout().rankDir("LR");
|
||||
renderer.layout(layout).run(graph, d3.select("#graph-target"));
|
||||
|
||||
// Handle the sliding and zooming of the graph,
|
||||
// store as `this._zoomBinding` so we can unbind during destruction
|
||||
if (!this._zoomBinding) {
|
||||
this._zoomBinding = d3.behavior.zoom().on("zoom", function () {
|
||||
var ev = d3.event;
|
||||
d3.select("#graph-target")
|
||||
.attr("transform", "translate(" + ev.translate + ") scale(" + ev.scale + ")");
|
||||
});
|
||||
d3.select("svg").call(this._zoomBinding);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handlers
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fired when a node in the svg graph is clicked. Used to handle triggering the AudioNodePane.
|
||||
*
|
||||
* @param Object AudioNodeView
|
||||
* The object stored in `AudioNodes` which contains render information, but most importantly,
|
||||
* the actorID under `id` property.
|
||||
*/
|
||||
_onGraphNodeClick: function (node) {
|
||||
WebAudioParamView.focusNode(node.id);
|
||||
}
|
||||
};
|
||||
|
||||
let WebAudioParamView = {
|
||||
_paramsView: null,
|
||||
|
||||
/**
|
||||
* Initialization function called when the tool starts up.
|
||||
*/
|
||||
initialize: function () {
|
||||
this._paramsView = new VariablesView($("#web-audio-inspector-content"), GENERIC_VARIABLES_VIEW_SETTINGS);
|
||||
this._paramsView.eval = this._onEval.bind(this);
|
||||
window.on(EVENTS.CREATE_NODE, this.addNode = this.addNode.bind(this));
|
||||
window.on(EVENTS.DESTROY_NODE, this.removeNode = this.removeNode.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Destruction function called when the tool cleans up.
|
||||
*/
|
||||
destroy: function() {
|
||||
window.off(EVENTS.CREATE_NODE, this.addNode);
|
||||
window.off(EVENTS.DESTROY_NODE, this.removeNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Empties out the params view.
|
||||
*/
|
||||
resetUI: function () {
|
||||
this._paramsView.empty();
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes an `id` and focuses and expands the corresponding scope.
|
||||
*/
|
||||
focusNode: function (id) {
|
||||
let scope = this._getScopeByID(id);
|
||||
if (!scope) return;
|
||||
|
||||
scope.focus();
|
||||
scope.expand();
|
||||
},
|
||||
|
||||
/**
|
||||
* Executed when an audio param is changed in the UI.
|
||||
*/
|
||||
_onEval: Task.async(function* (variable, value) {
|
||||
let ownerScope = variable.ownerView;
|
||||
let node = getViewNodeById(ownerScope.actorID);
|
||||
let propName = variable.name;
|
||||
let errorMessage = yield node.actor.setParam(propName, value);
|
||||
|
||||
// TODO figure out how to handle and display set param errors
|
||||
// and enable `test/brorwser_wa_params_view_edit_error.js`
|
||||
// Bug 994258
|
||||
if (!errorMessage) {
|
||||
ownerScope.get(propName).setGrip(value);
|
||||
window.emit(EVENTS.UI_SET_PARAM, node.id, propName, value);
|
||||
} else {
|
||||
window.emit(EVENTS.UI_SET_PARAM_ERROR, node.id, propName, value);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Takes an `id` and returns the corresponding variables scope.
|
||||
*/
|
||||
_getScopeByID: function (id) {
|
||||
let view = this._paramsView;
|
||||
for (let i = 0; i < view._store.length; i++) {
|
||||
let scope = view.getScopeAtIndex(i);
|
||||
if (scope.actorID === id)
|
||||
return scope;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when hovering over a variable scope.
|
||||
*/
|
||||
_onMouseOver: function (e) {
|
||||
let id = WebAudioParamView._getScopeID(this);
|
||||
|
||||
if (!id) return;
|
||||
|
||||
WebAudioGraphView.focusNode(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when hovering out of a variable scope.
|
||||
*/
|
||||
_onMouseOut: function (e) {
|
||||
let id = WebAudioParamView._getScopeID(this);
|
||||
|
||||
if (!id) return;
|
||||
|
||||
WebAudioGraphView.blurNode(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Uses in event handlers, takes an element `$el` and finds the
|
||||
* associated actor ID with that variable scope to be used in other contexts.
|
||||
*/
|
||||
_getScopeID: function ($el) {
|
||||
let match = $el.parentNode.id.match(/\(([^\)]*)\)/);
|
||||
return match ? match[1] : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when `CREATE_NODE` is fired to update the params view with the
|
||||
* freshly created audio node.
|
||||
*/
|
||||
addNode: Task.async(function* (_, id) {
|
||||
let viewNode = getViewNodeById(id);
|
||||
let type = viewNode.type;
|
||||
|
||||
let audioParamsTitle = type + " (" + id + ")";
|
||||
let paramsView = this._paramsView;
|
||||
let paramsScopeView = paramsView.addScope(audioParamsTitle);
|
||||
|
||||
paramsScopeView.actorID = id;
|
||||
paramsScopeView.expanded = false;
|
||||
|
||||
paramsScopeView.addEventListener("mouseover", this._onMouseOver, false);
|
||||
paramsScopeView.addEventListener("mouseout", this._onMouseOut, false);
|
||||
|
||||
let params = yield viewNode.getParams();
|
||||
params.forEach(({ param, value }) => {
|
||||
let descriptor = { value: value };
|
||||
paramsScopeView.addItem(param, descriptor);
|
||||
});
|
||||
|
||||
window.emit(EVENTS.UI_ADD_NODE_LIST, id);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Called when `DESTROY_NODE` is fired to remove the node from params view.
|
||||
* TODO bug 994263, dependent on node GC events
|
||||
*/
|
||||
removeNode: Task.async(function* (viewNode) {
|
||||
|
||||
})
|
||||
};
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/webaudioeditor.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/devtools/widgets.css" type="text/css"?>
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/webaudioeditor.dtd">
|
||||
%debuggerDTD;
|
||||
]>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://browser/content/devtools/theme-switching.js"/>
|
||||
|
||||
<script type="application/javascript" src="d3.js"/>
|
||||
<script type="application/javascript" src="dagre-d3.js"/>
|
||||
<script type="application/javascript" src="webaudioeditor-controller.js"/>
|
||||
<script type="application/javascript" src="webaudioeditor-view.js"/>
|
||||
|
||||
<vbox class="theme-body" flex="1">
|
||||
<hbox id="reload-notice"
|
||||
class="notice-container"
|
||||
align="center"
|
||||
pack="center"
|
||||
flex="1">
|
||||
<button id="requests-menu-reload-notice-button"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&webAudioEditorUI.reloadNotice1;"
|
||||
oncommand="gFront.setup({ reload: true });"/>
|
||||
<label id="requests-menu-reload-notice-label"
|
||||
class="plain"
|
||||
value="&webAudioEditorUI.reloadNotice2;"/>
|
||||
</hbox>
|
||||
<hbox id="waiting-notice"
|
||||
class="notice-container"
|
||||
align="center"
|
||||
pack="center"
|
||||
flex="1"
|
||||
hidden="true">
|
||||
<label id="requests-menu-waiting-notice-label"
|
||||
class="plain"
|
||||
value="&webAudioEditorUI.emptyNotice;"/>
|
||||
</hbox>
|
||||
|
||||
<box id="content"
|
||||
class="devtools-responsive-container"
|
||||
flex="1"
|
||||
hidden="true">
|
||||
<vbox id="web-audio-inspector">
|
||||
<vbox id="web-audio-inspector-content" flex="1"></vbox>
|
||||
</vbox>
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<box id="web-audio-graph" class="devtools-responsive-container" flex="1">
|
||||
<vbox flex="1">
|
||||
<svg id="graph-svg" flex="1" viewBox="0 0 1000 500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph-target" transform="translate(20,20)"/>
|
||||
</svg>
|
||||
</vbox>
|
||||
</box>
|
||||
</box>
|
||||
</vbox>
|
||||
|
||||
</window>
|
|
@ -4,4 +4,4 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
|
||||
subsuite = devtools
|
||||
|
||||
support-files =
|
||||
head.js
|
||||
test-bug-585956-console-trace.html
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 0.8.1334
|
||||
Current extension version is: 1.0.21
|
||||
|
||||
|
|
|
@ -64,7 +64,9 @@ function initializeDefaultPreferences() {
|
|||
var DEFAULT_PREFERENCES = {
|
||||
showPreviousViewOnLoad: true,
|
||||
defaultZoomValue: '',
|
||||
ifAvailableShowOutlineOnLoad: false
|
||||
ifAvailableShowOutlineOnLoad: false,
|
||||
enableHandToolOnLoad: false,
|
||||
enableWebGL: false
|
||||
};
|
||||
|
||||
|
||||
|
@ -134,15 +136,19 @@ let PdfJs = {
|
|||
},
|
||||
|
||||
_migrate: function migrate() {
|
||||
const VERSION = 1;
|
||||
const VERSION = 2;
|
||||
var currentVersion = getIntPref(PREF_MIGRATION_VERSION, 0);
|
||||
if (currentVersion >= VERSION) {
|
||||
return;
|
||||
}
|
||||
// Make pdf.js the default pdf viewer on the first migration.
|
||||
if (currentVersion < 2) {
|
||||
if (currentVersion < 1) {
|
||||
this._becomeHandler();
|
||||
}
|
||||
if (currentVersion < 2) {
|
||||
// cleaning up of unused database preference (see #3994)
|
||||
Services.prefs.clearUserPref(PREF_PREFIX + '.database');
|
||||
}
|
||||
Services.prefs.setIntPref(PREF_MIGRATION_VERSION, VERSION);
|
||||
},
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ const PDFJS_EVENT_ID = 'pdf.js.message';
|
|||
const PDF_CONTENT_TYPE = 'application/pdf';
|
||||
const PREF_PREFIX = 'pdfjs';
|
||||
const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html';
|
||||
const MAX_DATABASE_LENGTH = 4096;
|
||||
const MAX_NUMBER_OF_PREFS = 50;
|
||||
const MAX_STRING_PREF_LENGTH = 128;
|
||||
|
||||
|
@ -295,19 +294,6 @@ ChromeActions.prototype = {
|
|||
channel.asyncOpen(listener, null);
|
||||
});
|
||||
},
|
||||
setDatabase: function(data) {
|
||||
if (this.isInPrivateBrowsing())
|
||||
return;
|
||||
// Protect against something sending tons of data to setDatabase.
|
||||
if (data.length > MAX_DATABASE_LENGTH)
|
||||
return;
|
||||
setStringPref(PREF_PREFIX + '.database', data);
|
||||
},
|
||||
getDatabase: function() {
|
||||
if (this.isInPrivateBrowsing())
|
||||
return '{}';
|
||||
return getStringPref(PREF_PREFIX + '.database', '{}');
|
||||
},
|
||||
getLocale: function() {
|
||||
return getStringPref('general.useragent.locale', 'en-US');
|
||||
},
|
||||
|
@ -452,7 +438,7 @@ ChromeActions.prototype = {
|
|||
getChromeWindow(this.domWindow).gFindBar
|
||||
.updateControlState(result, findPrevious);
|
||||
},
|
||||
setPreferences: function(prefs) {
|
||||
setPreferences: function(prefs, sendResponse) {
|
||||
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
|
||||
var numberOfPrefs = 0;
|
||||
var prefValue, prefName;
|
||||
|
@ -483,8 +469,11 @@ ChromeActions.prototype = {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (sendResponse) {
|
||||
sendResponse(true);
|
||||
}
|
||||
},
|
||||
getPreferences: function(prefs) {
|
||||
getPreferences: function(prefs, sendResponse) {
|
||||
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
|
||||
var currentPrefs = {}, numberOfPrefs = 0;
|
||||
var prefValue, prefName;
|
||||
|
@ -510,8 +499,12 @@ ChromeActions.prototype = {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (sendResponse) {
|
||||
sendResponse(JSON.stringify(currentPrefs));
|
||||
} else {
|
||||
return JSON.stringify(currentPrefs);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var RangedChromeActions = (function RangedChromeActionsClosure() {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -211,10 +211,11 @@ var StepperManager = (function StepperManagerClosure() {
|
|||
return stepper;
|
||||
},
|
||||
selectStepper: function selectStepper(pageIndex, selectPanel) {
|
||||
var i;
|
||||
if (selectPanel) {
|
||||
this.manager.selectPanel(this);
|
||||
}
|
||||
for (var i = 0; i < steppers.length; ++i) {
|
||||
for (i = 0; i < steppers.length; ++i) {
|
||||
var stepper = steppers[i];
|
||||
if (stepper.pageIndex == pageIndex) {
|
||||
stepper.panel.removeAttribute('hidden');
|
||||
|
@ -223,7 +224,7 @@ var StepperManager = (function StepperManagerClosure() {
|
|||
}
|
||||
}
|
||||
var options = stepperChooser.options;
|
||||
for (var i = 0; i < options.length; ++i) {
|
||||
for (i = 0; i < options.length; ++i) {
|
||||
var option = options[i];
|
||||
option.selected = option.value == pageIndex;
|
||||
}
|
||||
|
@ -369,7 +370,7 @@ var Stepper = (function StepperClosure() {
|
|||
if (fn in glyphCommands) {
|
||||
var glyphIndex = glyphCommands[fn];
|
||||
var glyphs = args[glyphIndex];
|
||||
var decArgs = args.slice();
|
||||
decArgs = args.slice();
|
||||
var newArg;
|
||||
if (fn === 'showSpacedText') {
|
||||
newArg = [];
|
||||
|
|
|
@ -67,10 +67,12 @@ select {
|
|||
|
||||
:-moz-full-screen .page {
|
||||
margin-bottom: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
:fullscreen .page {
|
||||
margin-bottom: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
:-moz-full-screen a:not(.internalLink) {
|
||||
|
@ -1187,7 +1189,6 @@ canvas {
|
|||
.textLayer > div {
|
||||
color: transparent;
|
||||
position: absolute;
|
||||
line-height: 1;
|
||||
white-space: pre;
|
||||
cursor: text;
|
||||
}
|
||||
|
@ -1305,6 +1306,9 @@ canvas {
|
|||
background-color: hsla(0,0%,0%,.2);
|
||||
z-index: 10000;
|
||||
}
|
||||
#overlayContainer > * {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#promptContainer {
|
||||
display: table-cell;
|
||||
|
|
|
@ -309,49 +309,99 @@ var Cache = function cacheCache(size) {
|
|||
var DEFAULT_PREFERENCES = {
|
||||
showPreviousViewOnLoad: true,
|
||||
defaultZoomValue: '',
|
||||
ifAvailableShowOutlineOnLoad: false
|
||||
ifAvailableShowOutlineOnLoad: false,
|
||||
enableHandToolOnLoad: false,
|
||||
enableWebGL: false
|
||||
};
|
||||
|
||||
|
||||
var Preferences = (function PreferencesClosure() {
|
||||
function Preferences() {
|
||||
this.prefs = {};
|
||||
this.isInitializedPromiseResolved = false;
|
||||
this.initializedPromise = this.readFromStorage(DEFAULT_PREFERENCES).then(
|
||||
function(prefObj) {
|
||||
/**
|
||||
* Preferences - Utility for storing persistent settings.
|
||||
* Used for settings that should be applied to all opened documents,
|
||||
* or every time the viewer is loaded.
|
||||
*/
|
||||
var Preferences = {
|
||||
prefs: Object.create(DEFAULT_PREFERENCES),
|
||||
isInitializedPromiseResolved: false,
|
||||
initializedPromise: null,
|
||||
|
||||
/**
|
||||
* Initialize and fetch the current preference values from storage.
|
||||
* @return {Promise} A promise that is resolved when the preferences
|
||||
* have been initialized.
|
||||
*/
|
||||
initialize: function preferencesInitialize() {
|
||||
return this.initializedPromise =
|
||||
this._readFromStorage(DEFAULT_PREFERENCES).then(function(prefObj) {
|
||||
this.isInitializedPromiseResolved = true;
|
||||
if (prefObj) {
|
||||
this.prefs = prefObj;
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Stub function for writing preferences to storage.
|
||||
* NOTE: This should be overridden by a build-specific function defined below.
|
||||
* @param {Object} prefObj The preferences that should be written to storage.
|
||||
* @return {Promise} A promise that is resolved when the preference values
|
||||
* have been written.
|
||||
*/
|
||||
_writeToStorage: function preferences_writeToStorage(prefObj) {
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
/**
|
||||
* Stub function for reading preferences from storage.
|
||||
* NOTE: This should be overridden by a build-specific function defined below.
|
||||
* @param {Object} prefObj The preferences that should be read from storage.
|
||||
* @return {Promise} A promise that is resolved with an {Object} containing
|
||||
* the preferences that have been read.
|
||||
*/
|
||||
_readFromStorage: function preferences_readFromStorage(prefObj) {
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the preferences to their default values and update storage.
|
||||
* @return {Promise} A promise that is resolved when the preference values
|
||||
* have been reset.
|
||||
*/
|
||||
reset: function preferencesReset() {
|
||||
return this.initializedPromise.then(function() {
|
||||
this.prefs = Object.create(DEFAULT_PREFERENCES);
|
||||
return this._writeToStorage(DEFAULT_PREFERENCES);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Replace the current preference values with the ones from storage.
|
||||
* @return {Promise} A promise that is resolved when the preference values
|
||||
* have been updated.
|
||||
*/
|
||||
reload: function preferencesReload() {
|
||||
return this.initializedPromise.then(function () {
|
||||
this._readFromStorage(DEFAULT_PREFERENCES).then(function(prefObj) {
|
||||
if (prefObj) {
|
||||
this.prefs = prefObj;
|
||||
}
|
||||
|
||||
Preferences.prototype = {
|
||||
writeToStorage: function Preferences_writeToStorage(prefObj) {
|
||||
return;
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
readFromStorage: function Preferences_readFromStorage(prefObj) {
|
||||
var readFromStoragePromise = Promise.resolve();
|
||||
return readFromStoragePromise;
|
||||
},
|
||||
|
||||
reset: function Preferences_reset() {
|
||||
if (this.isInitializedPromiseResolved) {
|
||||
this.prefs = {};
|
||||
this.writeToStorage(DEFAULT_PREFERENCES);
|
||||
}
|
||||
},
|
||||
|
||||
set: function Preferences_set(name, value) {
|
||||
if (!this.isInitializedPromiseResolved) {
|
||||
return;
|
||||
} else if (DEFAULT_PREFERENCES[name] === undefined) {
|
||||
console.error('Preferences_set: \'' + name + '\' is undefined.');
|
||||
return;
|
||||
/**
|
||||
* Set the value of a preference.
|
||||
* @param {string} name The name of the preference that should be changed.
|
||||
* @param {boolean|number|string} value The new value of the preference.
|
||||
* @return {Promise} A promise that is resolved when the value has been set,
|
||||
* provided that the preference exists and the types match.
|
||||
*/
|
||||
set: function preferencesSet(name, value) {
|
||||
return this.initializedPromise.then(function () {
|
||||
if (DEFAULT_PREFERENCES[name] === undefined) {
|
||||
throw new Error('preferencesSet: \'' + name + '\' is undefined.');
|
||||
} else if (value === undefined) {
|
||||
console.error('Preferences_set: no value is specified.');
|
||||
return;
|
||||
throw new Error('preferencesSet: no value is specified.');
|
||||
}
|
||||
var valueType = typeof value;
|
||||
var defaultType = typeof DEFAULT_PREFERENCES[name];
|
||||
|
@ -360,40 +410,43 @@ var Preferences = (function PreferencesClosure() {
|
|||
if (valueType === 'number' && defaultType === 'string') {
|
||||
value = value.toString();
|
||||
} else {
|
||||
console.error('Preferences_set: \'' + value + '\' is a \"' +
|
||||
valueType + '\", expected a \"' + defaultType + '\".');
|
||||
return;
|
||||
throw new Error('Preferences_set: \'' + value + '\' is a \"' +
|
||||
valueType + '\", expected \"' + defaultType + '\".');
|
||||
}
|
||||
} else {
|
||||
if (valueType === 'number' && (value | 0) !== value) {
|
||||
console.error('Preferences_set: \'' + value +
|
||||
throw new Error('Preferences_set: \'' + value +
|
||||
'\' must be an \"integer\".');
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.prefs[name] = value;
|
||||
this.writeToStorage(this.prefs);
|
||||
return this._writeToStorage(this.prefs);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
get: function Preferences_get(name) {
|
||||
var defaultPref = DEFAULT_PREFERENCES[name];
|
||||
/**
|
||||
* Get the value of a preference.
|
||||
* @param {string} name The name of the preference whose value is requested.
|
||||
* @return {Promise} A promise that is resolved with a {boolean|number|string}
|
||||
* containing the value of the preference.
|
||||
*/
|
||||
get: function preferencesGet(name) {
|
||||
return this.initializedPromise.then(function () {
|
||||
var defaultValue = DEFAULT_PREFERENCES[name];
|
||||
|
||||
if (defaultPref === undefined) {
|
||||
console.error('Preferences_get: \'' + name + '\' is undefined.');
|
||||
return;
|
||||
} else if (this.isInitializedPromiseResolved) {
|
||||
var pref = this.prefs[name];
|
||||
if (defaultValue === undefined) {
|
||||
throw new Error('preferencesGet: \'' + name + '\' is undefined.');
|
||||
} else {
|
||||
var prefValue = this.prefs[name];
|
||||
|
||||
if (pref !== undefined) {
|
||||
return pref;
|
||||
if (prefValue !== undefined) {
|
||||
return prefValue;
|
||||
}
|
||||
}
|
||||
return defaultPref;
|
||||
return defaultValue;
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
return Preferences;
|
||||
})();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -488,17 +541,19 @@ var DownloadManager = (function DownloadManagerClosure() {
|
|||
return DownloadManager;
|
||||
})();
|
||||
|
||||
Preferences.prototype.writeToStorage = function(prefObj) {
|
||||
FirefoxCom.requestSync('setPreferences', prefObj);
|
||||
Preferences._writeToStorage = function (prefObj) {
|
||||
return new Promise(function (resolve) {
|
||||
FirefoxCom.request('setPreferences', prefObj, resolve);
|
||||
});
|
||||
};
|
||||
|
||||
Preferences.prototype.readFromStorage = function(prefObj) {
|
||||
var readFromStoragePromise = new Promise(function (resolve) {
|
||||
var readPrefs = JSON.parse(FirefoxCom.requestSync('getPreferences',
|
||||
prefObj));
|
||||
Preferences._readFromStorage = function (prefObj) {
|
||||
return new Promise(function (resolve) {
|
||||
FirefoxCom.request('getPreferences', prefObj, function (prefStr) {
|
||||
var readPrefs = JSON.parse(prefStr);
|
||||
resolve(readPrefs);
|
||||
});
|
||||
return readFromStoragePromise;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
@ -513,7 +568,7 @@ var currentPageNumber = 1;
|
|||
*
|
||||
* The way that the view parameters are stored depends on how PDF.js is built,
|
||||
* for 'node make <flag>' the following cases exist:
|
||||
* - FIREFOX or MOZCENTRAL - uses about:config.
|
||||
* - FIREFOX or MOZCENTRAL - uses sessionStorage.
|
||||
* - B2G - uses asyncStorage.
|
||||
* - GENERIC or CHROME - uses localStorage, if it is available.
|
||||
*/
|
||||
|
@ -533,7 +588,7 @@ var ViewHistory = (function ViewHistoryClosure() {
|
|||
}).bind(this);
|
||||
|
||||
|
||||
resolvePromise(FirefoxCom.requestSync('getDatabase', null));
|
||||
resolvePromise(sessionStorage.getItem('pdfjsHistory'));
|
||||
|
||||
}
|
||||
|
||||
|
@ -570,7 +625,7 @@ var ViewHistory = (function ViewHistoryClosure() {
|
|||
var database = JSON.stringify(this.database);
|
||||
|
||||
|
||||
FirefoxCom.requestSync('setDatabase', database);
|
||||
sessionStorage.setItem('pdfjsHistory',database);
|
||||
|
||||
},
|
||||
|
||||
|
@ -871,11 +926,12 @@ var PDFFindController = {
|
|||
var self = this;
|
||||
function extractPageText(pageIndex) {
|
||||
self.pdfPageSource.pages[pageIndex].getTextContent().then(
|
||||
function textContentResolved(bidiTexts) {
|
||||
function textContentResolved(textContent) {
|
||||
var textItems = textContent.items;
|
||||
var str = '';
|
||||
|
||||
for (var i = 0; i < bidiTexts.length; i++) {
|
||||
str += bidiTexts[i].str;
|
||||
for (var i = 0; i < textItems.length; i++) {
|
||||
str += textItems[i].str;
|
||||
}
|
||||
|
||||
// Store the pageContent as a string.
|
||||
|
@ -1778,11 +1834,9 @@ var PresentationMode = {
|
|||
// Presentation Mode, by waiting until fullscreen mode is disabled.
|
||||
// Note: This is only necessary in non-Mozilla browsers.
|
||||
setTimeout(function exitPresentationModeTimeout() {
|
||||
this.active = false;
|
||||
PDFView.setScale(this.args.previousScale);
|
||||
PDFView.page = page;
|
||||
// Keep Presentation Mode active until the page is scrolled into view,
|
||||
// to prevent issues in non-Mozilla browsers.
|
||||
this.active = false;
|
||||
this.args = null;
|
||||
}.bind(this), 0);
|
||||
|
||||
|
@ -2110,8 +2164,15 @@ var HandTool = {
|
|||
});
|
||||
if (toggleHandTool) {
|
||||
toggleHandTool.addEventListener('click', this.toggle.bind(this), false);
|
||||
|
||||
window.addEventListener('localized', function (evt) {
|
||||
Preferences.get('enableHandToolOnLoad').then(function (prefValue) {
|
||||
if (prefValue) {
|
||||
this.handTool.activate();
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
// TODO: Read global prefs and call this.handTool.activate() if needed.
|
||||
},
|
||||
|
||||
toggle: function handToolToggle() {
|
||||
|
@ -2177,6 +2238,10 @@ var DocumentProperties = {
|
|||
options.closeButton.addEventListener('click', this.hide.bind(this));
|
||||
}
|
||||
|
||||
this.dataAvailablePromise = new Promise(function (resolve) {
|
||||
this.resolveDataAvailable = resolve;
|
||||
}.bind(this));
|
||||
|
||||
// Bind the event listener for the Esc key (to close the dialog).
|
||||
window.addEventListener('keydown',
|
||||
function (e) {
|
||||
|
@ -2187,44 +2252,51 @@ var DocumentProperties = {
|
|||
},
|
||||
|
||||
getProperties: function documentPropertiesGetProperties() {
|
||||
var self = this;
|
||||
|
||||
if (!this.visible) {
|
||||
// If the dialog was closed before dataAvailablePromise was resolved,
|
||||
// don't bother updating the properties.
|
||||
return;
|
||||
}
|
||||
// Get the file name.
|
||||
this.fileName = getPDFFileNameFromURL(PDFView.url);
|
||||
|
||||
// Get the file size.
|
||||
PDFView.pdfDocument.getDownloadInfo().then(function(data) {
|
||||
self.setFileSize(data.length);
|
||||
});
|
||||
this.setFileSize(data.length);
|
||||
this.updateUI(this.fileSizeField, this.fileSize);
|
||||
}.bind(this));
|
||||
|
||||
// Get the other document properties.
|
||||
PDFView.pdfDocument.getMetadata().then(function(data) {
|
||||
var fields = [
|
||||
{ field: self.fileNameField, content: self.fileName },
|
||||
{ field: self.fileSizeField, content: self.fileSize },
|
||||
{ field: self.titleField, content: data.info.Title },
|
||||
{ field: self.authorField, content: data.info.Author },
|
||||
{ field: self.subjectField, content: data.info.Subject },
|
||||
{ field: self.keywordsField, content: data.info.Keywords },
|
||||
{ field: self.creationDateField,
|
||||
content: self.parseDate(data.info.CreationDate) },
|
||||
{ field: self.modificationDateField,
|
||||
content: self.parseDate(data.info.ModDate) },
|
||||
{ field: self.creatorField, content: data.info.Creator },
|
||||
{ field: self.producerField, content: data.info.Producer },
|
||||
{ field: self.versionField, content: data.info.PDFFormatVersion },
|
||||
{ field: self.pageCountField, content: PDFView.pdfDocument.numPages }
|
||||
{ field: this.fileNameField, content: this.fileName },
|
||||
// The fileSize field is updated once getDownloadInfo is resolved.
|
||||
{ field: this.titleField, content: data.info.Title },
|
||||
{ field: this.authorField, content: data.info.Author },
|
||||
{ field: this.subjectField, content: data.info.Subject },
|
||||
{ field: this.keywordsField, content: data.info.Keywords },
|
||||
{ field: this.creationDateField,
|
||||
content: this.parseDate(data.info.CreationDate) },
|
||||
{ field: this.modificationDateField,
|
||||
content: this.parseDate(data.info.ModDate) },
|
||||
{ field: this.creatorField, content: data.info.Creator },
|
||||
{ field: this.producerField, content: data.info.Producer },
|
||||
{ field: this.versionField, content: data.info.PDFFormatVersion },
|
||||
{ field: this.pageCountField, content: PDFView.pdfDocument.numPages }
|
||||
];
|
||||
|
||||
// Show the properties in the dialog.
|
||||
for (var item in fields) {
|
||||
var element = fields[item];
|
||||
if (element.field && element.content !== undefined &&
|
||||
element.content !== '') {
|
||||
element.field.textContent = element.content;
|
||||
this.updateUI(element.field, element.content);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
updateUI: function documentPropertiesUpdateUI(field, content) {
|
||||
if (field && content !== undefined && content !== '') {
|
||||
field.textContent = content;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setFileSize: function documentPropertiesSetFileSize(fileSize) {
|
||||
|
@ -2249,7 +2321,10 @@ var DocumentProperties = {
|
|||
this.visible = true;
|
||||
this.overlayContainer.classList.remove('hidden');
|
||||
this.overlayContainer.lastElementChild.classList.remove('hidden');
|
||||
|
||||
this.dataAvailablePromise.then(function () {
|
||||
this.getProperties();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
hide: function documentPropertiesClose() {
|
||||
|
@ -2347,6 +2422,8 @@ var PDFView = {
|
|||
this.watchScroll(thumbnailContainer, this.thumbnailViewScroll,
|
||||
this.renderHighestPriority.bind(this));
|
||||
|
||||
Preferences.initialize();
|
||||
|
||||
PDFFindBar.initialize({
|
||||
bar: document.getElementById('findbar'),
|
||||
toggleButton: document.getElementById('viewFind'),
|
||||
|
@ -2421,10 +2498,20 @@ var PDFView = {
|
|||
pageCountField: document.getElementById('pageCountField')
|
||||
});
|
||||
|
||||
this.initialized = true;
|
||||
container.addEventListener('scroll', function() {
|
||||
self.lastScroll = Date.now();
|
||||
}, false);
|
||||
|
||||
var initializedPromise = Promise.all([
|
||||
Preferences.get('enableWebGL').then(function (value) {
|
||||
PDFJS.disableWebGL = !value;
|
||||
})
|
||||
// TODO move more preferences and other async stuff here
|
||||
]);
|
||||
|
||||
return initializedPromise.then(function () {
|
||||
PDFView.initialized = true;
|
||||
});
|
||||
},
|
||||
|
||||
getPage: function pdfViewGetPage(n) {
|
||||
|
@ -2490,9 +2577,11 @@ var PDFView = {
|
|||
if (!currentPage) {
|
||||
return;
|
||||
}
|
||||
var pageWidthScale = (this.container.clientWidth - SCROLLBAR_PADDING) /
|
||||
var hPadding = PresentationMode.active ? 0 : SCROLLBAR_PADDING;
|
||||
var vPadding = PresentationMode.active ? 0 : VERTICAL_PADDING;
|
||||
var pageWidthScale = (this.container.clientWidth - hPadding) /
|
||||
currentPage.width * currentPage.scale;
|
||||
var pageHeightScale = (this.container.clientHeight - VERTICAL_PADDING) /
|
||||
var pageHeightScale = (this.container.clientHeight - vPadding) /
|
||||
currentPage.height * currentPage.scale;
|
||||
switch (value) {
|
||||
case 'page-actual':
|
||||
|
@ -2774,6 +2863,9 @@ var PDFView = {
|
|||
pdfDataRangeTransport, args) {
|
||||
if (this.pdfDocument) {
|
||||
this.close();
|
||||
|
||||
// Reload the preferences if a document was previously opened.
|
||||
Preferences.reload();
|
||||
}
|
||||
|
||||
var parameters = {password: password};
|
||||
|
@ -2791,6 +2883,8 @@ var PDFView = {
|
|||
|
||||
var self = this;
|
||||
self.loading = true;
|
||||
self.downloadComplete = false;
|
||||
|
||||
var passwordNeeded = function passwordNeeded(updatePassword, reason) {
|
||||
PasswordPrompt.updatePassword = updatePassword;
|
||||
PasswordPrompt.reason = reason;
|
||||
|
@ -2813,13 +2907,13 @@ var PDFView = {
|
|||
|
||||
if (exception && exception.name === 'InvalidPDFException') {
|
||||
// change error message also for other builds
|
||||
var loadingErrorMessage = mozL10n.get('invalid_file_error', null,
|
||||
loadingErrorMessage = mozL10n.get('invalid_file_error', null,
|
||||
'Invalid or corrupted PDF file.');
|
||||
}
|
||||
|
||||
if (exception && exception.name === 'MissingPDFException') {
|
||||
// special message for missing PDF's
|
||||
var loadingErrorMessage = mozL10n.get('missing_file_error', null,
|
||||
loadingErrorMessage = mozL10n.get('missing_file_error', null,
|
||||
'Missing PDF file.');
|
||||
|
||||
}
|
||||
|
@ -2834,7 +2928,7 @@ var PDFView = {
|
|||
},
|
||||
|
||||
download: function pdfViewDownload() {
|
||||
function noData() {
|
||||
function downloadByUrl() {
|
||||
downloadManager.downloadUrl(url, filename);
|
||||
}
|
||||
|
||||
|
@ -2848,7 +2942,12 @@ var PDFView = {
|
|||
};
|
||||
|
||||
if (!this.pdfDocument) { // the PDF is not ready yet
|
||||
noData();
|
||||
downloadByUrl();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.downloadComplete) { // the PDF is still downloading
|
||||
downloadByUrl();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2857,8 +2956,8 @@ var PDFView = {
|
|||
var blob = PDFJS.createBlob(data, 'application/pdf');
|
||||
downloadManager.download(blob, url, filename);
|
||||
},
|
||||
noData // Error occurred try downloading with just the url.
|
||||
).then(null, noData);
|
||||
downloadByUrl // Error occurred try downloading with just the url.
|
||||
).then(null, downloadByUrl);
|
||||
},
|
||||
|
||||
fallback: function pdfViewFallback(featureId) {
|
||||
|
@ -3026,7 +3125,10 @@ var PDFView = {
|
|||
|
||||
this.pdfDocument = pdfDocument;
|
||||
|
||||
pdfDocument.getDownloadInfo().then(function() {
|
||||
DocumentProperties.resolveDataAvailable();
|
||||
|
||||
var downloadedPromise = pdfDocument.getDownloadInfo().then(function() {
|
||||
self.downloadComplete = true;
|
||||
PDFView.loadingBar.hide();
|
||||
var outerContainer = document.getElementById('outerContainer');
|
||||
outerContainer.classList.remove('loadingInProgress');
|
||||
|
@ -3039,7 +3141,6 @@ var PDFView = {
|
|||
mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}');
|
||||
document.getElementById('pageNumber').max = pagesCount;
|
||||
|
||||
var prefs = PDFView.prefs = new Preferences();
|
||||
PDFView.documentFingerprint = id;
|
||||
var store = PDFView.store = new ViewHistory(id);
|
||||
|
||||
|
@ -3101,22 +3202,35 @@ var PDFView = {
|
|||
}
|
||||
});
|
||||
|
||||
downloadedPromise.then(function () {
|
||||
var event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('documentload', true, true, {});
|
||||
window.dispatchEvent(event);
|
||||
});
|
||||
|
||||
PDFView.loadingBar.setWidth(container);
|
||||
|
||||
PDFFindController.resolveFirstPage();
|
||||
|
||||
// Initialize the browsing history.
|
||||
PDFHistory.initialize(self.documentFingerprint);
|
||||
});
|
||||
|
||||
var prefsPromise = prefs.initializedPromise;
|
||||
var storePromise = store.initializedPromise;
|
||||
Promise.all([firstPagePromise, prefsPromise, storePromise]).
|
||||
then(function() {
|
||||
var showPreviousViewOnLoad = prefs.get('showPreviousViewOnLoad');
|
||||
var defaultZoomValue = prefs.get('defaultZoomValue');
|
||||
// Fetch the necessary preference values.
|
||||
var showPreviousViewOnLoad;
|
||||
var showPreviousViewOnLoadPromise =
|
||||
Preferences.get('showPreviousViewOnLoad').then(function (prefValue) {
|
||||
showPreviousViewOnLoad = prefValue;
|
||||
});
|
||||
var defaultZoomValue;
|
||||
var defaultZoomValuePromise =
|
||||
Preferences.get('defaultZoomValue').then(function (prefValue) {
|
||||
defaultZoomValue = prefValue;
|
||||
});
|
||||
|
||||
var storePromise = store.initializedPromise;
|
||||
Promise.all([firstPagePromise, storePromise, showPreviousViewOnLoadPromise,
|
||||
defaultZoomValuePromise]).then(function resolved() {
|
||||
var storedHash = null;
|
||||
if (showPreviousViewOnLoad && store.get('exists', false)) {
|
||||
var pageNum = store.get('page', '1');
|
||||
|
@ -3129,9 +3243,6 @@ var PDFView = {
|
|||
} else if (defaultZoomValue) {
|
||||
storedHash = 'page=1&zoom=' + defaultZoomValue;
|
||||
}
|
||||
// Initialize the browsing history.
|
||||
PDFHistory.initialize(self.documentFingerprint);
|
||||
|
||||
self.setInitialView(storedHash, scale);
|
||||
|
||||
// Make all navigation keys work on document load,
|
||||
|
@ -3140,6 +3251,12 @@ var PDFView = {
|
|||
self.container.focus();
|
||||
self.container.blur();
|
||||
}
|
||||
}, function rejected(errorMsg) {
|
||||
console.error(errorMsg);
|
||||
|
||||
firstPagePromise.then(function () {
|
||||
self.setInitialView(null, scale);
|
||||
});
|
||||
});
|
||||
|
||||
pagesPromise.then(function() {
|
||||
|
@ -3178,13 +3295,18 @@ var PDFView = {
|
|||
self.outline = new DocumentOutlineView(outline);
|
||||
document.getElementById('viewOutline').disabled = !outline;
|
||||
|
||||
if (outline && prefs.get('ifAvailableShowOutlineOnLoad')) {
|
||||
if (outline) {
|
||||
Preferences.get('ifAvailableShowOutlineOnLoad').then(
|
||||
function (prefValue) {
|
||||
if (prefValue) {
|
||||
if (!self.sidebarOpen) {
|
||||
document.getElementById('sidebarToggle').click();
|
||||
}
|
||||
self.switchSidebarView('outline');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
pdfDocument.getMetadata().then(function(data) {
|
||||
|
@ -3194,9 +3316,10 @@ var PDFView = {
|
|||
|
||||
// Provides some basic debug information
|
||||
console.log('PDF ' + pdfDocument.fingerprint + ' [' +
|
||||
info.PDFFormatVersion + ' ' + (info.Producer || '-') +
|
||||
' / ' + (info.Creator || '-') + ']' +
|
||||
(PDFJS.version ? ' (PDF.js: ' + PDFJS.version + ')' : ''));
|
||||
info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() +
|
||||
' / ' + (info.Creator || '-').trim() + ']' +
|
||||
' (PDF.js: ' + (PDFJS.version || '-') +
|
||||
(!PDFJS.disableWebGL ? ' [WebGL]' : '') + ')');
|
||||
|
||||
var pdfTitle;
|
||||
if (metadata && metadata.has('dc:title')) {
|
||||
|
@ -3568,10 +3691,11 @@ var PDFView = {
|
|||
}
|
||||
|
||||
var alertNotReady = false;
|
||||
var i, ii;
|
||||
if (!this.pages.length) {
|
||||
alertNotReady = true;
|
||||
} else {
|
||||
for (var i = 0, ii = this.pages.length; i < ii; ++i) {
|
||||
for (i = 0, ii = this.pages.length; i < ii; ++i) {
|
||||
if (!this.pages[i].pdfPage) {
|
||||
alertNotReady = true;
|
||||
break;
|
||||
|
@ -3587,7 +3711,7 @@ var PDFView = {
|
|||
|
||||
var body = document.querySelector('body');
|
||||
body.setAttribute('data-mozPrintCallback', true);
|
||||
for (var i = 0, ii = this.pages.length; i < ii; ++i) {
|
||||
for (i = 0, ii = this.pages.length; i < ii; ++i) {
|
||||
this.pages[i].beforePrint();
|
||||
}
|
||||
},
|
||||
|
@ -3601,14 +3725,15 @@ var PDFView = {
|
|||
|
||||
rotatePages: function pdfViewRotatePages(delta) {
|
||||
var currentPage = this.pages[this.page - 1];
|
||||
var i, l;
|
||||
this.pageRotation = (this.pageRotation + 360 + delta) % 360;
|
||||
|
||||
for (var i = 0, l = this.pages.length; i < l; i++) {
|
||||
for (i = 0, l = this.pages.length; i < l; i++) {
|
||||
var page = this.pages[i];
|
||||
page.update(page.scale, this.pageRotation);
|
||||
}
|
||||
|
||||
for (var i = 0, l = this.thumbnails.length; i < l; i++) {
|
||||
for (i = 0, l = this.thumbnails.length; i < l; i++) {
|
||||
var thumb = this.thumbnails[i];
|
||||
thumb.update(this.pageRotation);
|
||||
}
|
||||
|
@ -4019,7 +4144,7 @@ var PageView = function pageView(container, id, scale,
|
|||
|
||||
var x = 0, y = 0;
|
||||
var width = 0, height = 0, widthScale, heightScale;
|
||||
var changeOrientation = !!(this.rotation % 180);
|
||||
var changeOrientation = (this.rotation % 180 === 0 ? false : true);
|
||||
var pageWidth = (changeOrientation ? this.height : this.width) /
|
||||
this.scale / CSS_UNITS;
|
||||
var pageHeight = (changeOrientation ? this.width : this.height) /
|
||||
|
@ -4156,8 +4281,8 @@ var PageView = function pageView(container, id, scale,
|
|||
if (!PDFJS.disableTextLayer) {
|
||||
textLayerDiv = document.createElement('div');
|
||||
textLayerDiv.className = 'textLayer';
|
||||
textLayerDiv.style.width = canvas.width + 'px';
|
||||
textLayerDiv.style.height = canvas.height + 'px';
|
||||
textLayerDiv.style.width = canvas.style.width;
|
||||
textLayerDiv.style.height = canvas.style.height;
|
||||
div.appendChild(textLayerDiv);
|
||||
}
|
||||
var textLayer = this.textLayer =
|
||||
|
@ -4174,14 +4299,6 @@ var PageView = function pageView(container, id, scale,
|
|||
if (outputScale.scaled) {
|
||||
ctx.scale(outputScale.sx, outputScale.sy);
|
||||
}
|
||||
if (outputScale.scaled && textLayerDiv) {
|
||||
var cssScale = 'scale(' + (1 / outputScale.sx) + ', ' +
|
||||
(1 / outputScale.sy) + ')';
|
||||
CustomStyle.setProp('transform' , textLayerDiv, cssScale);
|
||||
CustomStyle.setProp('transformOrigin' , textLayerDiv, '0% 0%');
|
||||
textLayerDiv.dataset._scaleX = outputScale.sx;
|
||||
textLayerDiv.dataset._scaleY = outputScale.sy;
|
||||
}
|
||||
|
||||
// Rendering area
|
||||
|
||||
|
@ -4267,19 +4384,18 @@ var PageView = function pageView(container, id, scale,
|
|||
this.renderTask.promise.then(
|
||||
function pdfPageRenderCallback() {
|
||||
pageViewDrawCallback(null);
|
||||
},
|
||||
function pdfPageRenderError(error) {
|
||||
pageViewDrawCallback(error);
|
||||
}
|
||||
);
|
||||
|
||||
if (textLayer) {
|
||||
this.getTextContent().then(
|
||||
self.getTextContent().then(
|
||||
function textContentResolved(textContent) {
|
||||
textLayer.setTextContent(textContent);
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
function pdfPageRenderError(error) {
|
||||
pageViewDrawCallback(error);
|
||||
}
|
||||
);
|
||||
|
||||
setupAnnotations(div, pdfPage, this.viewport);
|
||||
div.setAttribute('data-loaded', true);
|
||||
|
@ -4555,6 +4671,7 @@ var TextLayerBuilder = function textLayerBuilder(options) {
|
|||
this.lastScrollSource = options.lastScrollSource;
|
||||
this.viewport = options.viewport;
|
||||
this.isViewerInPresentationMode = options.isViewerInPresentationMode;
|
||||
this.textDivs = [];
|
||||
|
||||
if (typeof PDFFindController === 'undefined') {
|
||||
window.PDFFindController = null;
|
||||
|
@ -4564,16 +4681,6 @@ var TextLayerBuilder = function textLayerBuilder(options) {
|
|||
this.lastScrollSource = null;
|
||||
}
|
||||
|
||||
this.beginLayout = function textLayerBuilderBeginLayout() {
|
||||
this.textDivs = [];
|
||||
this.renderingDone = false;
|
||||
};
|
||||
|
||||
this.endLayout = function textLayerBuilderEndLayout() {
|
||||
this.layoutDone = true;
|
||||
this.insertDivContent();
|
||||
};
|
||||
|
||||
this.renderLayer = function textLayerBuilderRenderLayer() {
|
||||
var textDivs = this.textDivs;
|
||||
var canvas = document.createElement('canvas');
|
||||
|
@ -4633,70 +4740,56 @@ var TextLayerBuilder = function textLayerBuilder(options) {
|
|||
}
|
||||
};
|
||||
|
||||
this.appendText = function textLayerBuilderAppendText(geom) {
|
||||
this.appendText = function textLayerBuilderAppendText(geom, styles) {
|
||||
var style = styles[geom.fontName];
|
||||
var textDiv = document.createElement('div');
|
||||
|
||||
// vScale and hScale already contain the scaling to pixel units
|
||||
var fontHeight = geom.fontSize * Math.abs(geom.vScale);
|
||||
textDiv.dataset.canvasWidth = geom.canvasWidth * Math.abs(geom.hScale);
|
||||
textDiv.dataset.fontName = geom.fontName;
|
||||
textDiv.dataset.angle = geom.angle * (180 / Math.PI);
|
||||
|
||||
textDiv.style.fontSize = fontHeight + 'px';
|
||||
textDiv.style.fontFamily = geom.fontFamily;
|
||||
var fontAscent = (geom.ascent ? geom.ascent * fontHeight :
|
||||
(geom.descent ? (1 + geom.descent) * fontHeight : fontHeight));
|
||||
textDiv.style.left = (geom.x + (fontAscent * Math.sin(geom.angle))) + 'px';
|
||||
textDiv.style.top = (geom.y - (fontAscent * Math.cos(geom.angle))) + 'px';
|
||||
|
||||
// The content of the div is set in the `setTextContent` function.
|
||||
|
||||
this.textDivs.push(textDiv);
|
||||
};
|
||||
|
||||
this.insertDivContent = function textLayerUpdateTextContent() {
|
||||
// Only set the content of the divs once layout has finished, the content
|
||||
// for the divs is available and content is not yet set on the divs.
|
||||
if (!this.layoutDone || this.divContentDone || !this.textContent) {
|
||||
if (!/\S/.test(geom.str)) {
|
||||
textDiv.dataset.isWhitespace = true;
|
||||
return;
|
||||
}
|
||||
var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
|
||||
var angle = Math.atan2(tx[1], tx[0]);
|
||||
if (style.vertical) {
|
||||
angle += Math.PI / 2;
|
||||
}
|
||||
var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
|
||||
var fontAscent = (style.ascent ? style.ascent * fontHeight :
|
||||
(style.descent ? (1 + style.descent) * fontHeight : fontHeight));
|
||||
|
||||
this.divContentDone = true;
|
||||
textDiv.style.position = 'absolute';
|
||||
textDiv.style.left = (tx[4] + (fontAscent * Math.sin(angle))) + 'px';
|
||||
textDiv.style.top = (tx[5] - (fontAscent * Math.cos(angle))) + 'px';
|
||||
textDiv.style.fontSize = fontHeight + 'px';
|
||||
textDiv.style.fontFamily = style.fontFamily;
|
||||
|
||||
var textDivs = this.textDivs;
|
||||
var bidiTexts = this.textContent;
|
||||
|
||||
for (var i = 0; i < bidiTexts.length; i++) {
|
||||
var bidiText = bidiTexts[i];
|
||||
var textDiv = textDivs[i];
|
||||
if (!/\S/.test(bidiText.str)) {
|
||||
textDiv.dataset.isWhitespace = true;
|
||||
continue;
|
||||
textDiv.textContent = geom.str;
|
||||
textDiv.dataset.fontName = geom.fontName;
|
||||
textDiv.dataset.angle = angle * (180 / Math.PI);
|
||||
if (style.vertical) {
|
||||
textDiv.dataset.canvasWidth = geom.height * this.viewport.scale;
|
||||
} else {
|
||||
textDiv.dataset.canvasWidth = geom.width * this.viewport.scale;
|
||||
}
|
||||
|
||||
textDiv.textContent = bidiText.str;
|
||||
// TODO refactor text layer to use text content position
|
||||
/**
|
||||
* var arr = this.viewport.convertToViewportPoint(bidiText.x, bidiText.y);
|
||||
* textDiv.style.left = arr[0] + 'px';
|
||||
* textDiv.style.top = arr[1] + 'px';
|
||||
*/
|
||||
// bidiText.dir may be 'ttb' for vertical texts.
|
||||
textDiv.dir = bidiText.dir;
|
||||
}
|
||||
|
||||
this.setupRenderLayoutTimer();
|
||||
};
|
||||
|
||||
this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
|
||||
this.textContent = textContent;
|
||||
this.insertDivContent();
|
||||
|
||||
var textItems = textContent.items;
|
||||
for (var i = 0; i < textItems.length; i++) {
|
||||
this.appendText(textItems[i], textContent.styles);
|
||||
}
|
||||
this.divContentDone = true;
|
||||
|
||||
this.setupRenderLayoutTimer();
|
||||
};
|
||||
|
||||
this.convertMatches = function textLayerBuilderConvertMatches(matches) {
|
||||
var i = 0;
|
||||
var iIndex = 0;
|
||||
var bidiTexts = this.textContent;
|
||||
var bidiTexts = this.textContent.items;
|
||||
var end = bidiTexts.length - 1;
|
||||
var queryLen = (PDFFindController === null ?
|
||||
0 : PDFFindController.state.query.length);
|
||||
|
@ -4755,7 +4848,7 @@ var TextLayerBuilder = function textLayerBuilder(options) {
|
|||
return;
|
||||
}
|
||||
|
||||
var bidiTexts = this.textContent;
|
||||
var bidiTexts = this.textContent.items;
|
||||
var textDivs = this.textDivs;
|
||||
var prevEnd = null;
|
||||
var isSelectedPage = (PDFFindController === null ?
|
||||
|
@ -4776,26 +4869,17 @@ var TextLayerBuilder = function textLayerBuilder(options) {
|
|||
var divIdx = begin.divIdx;
|
||||
var div = textDivs[divIdx];
|
||||
div.textContent = '';
|
||||
|
||||
var content = bidiTexts[divIdx].str.substring(0, begin.offset);
|
||||
var node = document.createTextNode(content);
|
||||
if (className) {
|
||||
var isSelected = isSelectedPage &&
|
||||
divIdx === selectedMatchIdx;
|
||||
var span = document.createElement('span');
|
||||
span.className = className + (isSelected ? ' selected' : '');
|
||||
span.appendChild(node);
|
||||
div.appendChild(span);
|
||||
return;
|
||||
}
|
||||
div.appendChild(node);
|
||||
appendTextToDiv(divIdx, 0, begin.offset, className);
|
||||
}
|
||||
|
||||
function appendText(from, to, className) {
|
||||
var divIdx = from.divIdx;
|
||||
appendTextToDiv(from.divIdx, from.offset, to.offset, className);
|
||||
}
|
||||
|
||||
function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
|
||||
var div = textDivs[divIdx];
|
||||
|
||||
var content = bidiTexts[divIdx].str.substring(from.offset, to.offset);
|
||||
var content = bidiTexts[divIdx].str.substring(fromOffset, toOffset);
|
||||
var node = document.createTextNode(content);
|
||||
if (className) {
|
||||
var span = document.createElement('span');
|
||||
|
@ -4871,7 +4955,7 @@ var TextLayerBuilder = function textLayerBuilder(options) {
|
|||
// Clear out all matches.
|
||||
var matches = this.matches;
|
||||
var textDivs = this.textDivs;
|
||||
var bidiTexts = this.textContent;
|
||||
var bidiTexts = this.textContent.items;
|
||||
var clearedUntilDivIdx = -1;
|
||||
|
||||
// Clear out all current matches.
|
||||
|
@ -4951,8 +5035,10 @@ var DocumentOutlineView = function documentOutlineView(outline) {
|
|||
|
||||
|
||||
function webViewerLoad(evt) {
|
||||
PDFView.initialize();
|
||||
PDFView.initialize().then(webViewerInitialized);
|
||||
}
|
||||
|
||||
function webViewerInitialized() {
|
||||
var file = window.location.href.split('#')[0];
|
||||
|
||||
document.getElementById('openFile').setAttribute('hidden', 'true');
|
||||
|
@ -4982,6 +5068,10 @@ function webViewerLoad(evt) {
|
|||
PDFJS.disableHistory = (hashParams['disableHistory'] === 'true');
|
||||
}
|
||||
|
||||
if ('webgl' in hashParams) {
|
||||
PDFJS.disableWebGL = (hashParams['webgl'] !== 'true');
|
||||
}
|
||||
|
||||
if ('useOnlyCssZoom' in hashParams) {
|
||||
USE_ONLY_CSS_ZOOM = (hashParams['useOnlyCssZoom'] === 'true');
|
||||
}
|
||||
|
@ -5135,7 +5225,6 @@ function webViewerLoad(evt) {
|
|||
if (file) {
|
||||
PDFView.open(file, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', webViewerLoad, true);
|
||||
|
|
|
@ -3,7 +3,5 @@ skip-if = e10s # Bug 942707 - PDF viewer doesn't work with e10s.
|
|||
support-files = file_pdfjs_test.pdf
|
||||
|
||||
[browser_pdfjs_main.js]
|
||||
skip-if = (os == "mac" && debug) || os == "win" # Bug 963075 - leaks when run in chunked mochitest-bc mode
|
||||
[browser_pdfjs_savedialog.js]
|
||||
[browser_pdfjs_views.js]
|
||||
skip-if = (os == "mac" && debug) || os == "win" # Bug 963075 - leaks when run in chunked mochitest-bc mode
|
||||
|
|
|
@ -31,9 +31,9 @@ function test() {
|
|||
window = newTabBrowser.contentWindow;
|
||||
|
||||
// Runs tests after all 'load' event handlers have fired off
|
||||
setTimeout(function() {
|
||||
window.addEventListener("documentload", function() {
|
||||
runTests(document, window, finish);
|
||||
}, 0);
|
||||
}, false, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,9 @@ function test() {
|
|||
window = newTabBrowser.contentWindow;
|
||||
|
||||
// Runs tests after all 'load' event handlers have fired off
|
||||
window.addEventListener("documentload", function() {runTests(document, window, finish);}, false, true);
|
||||
window.addEventListener("documentload", function() {
|
||||
runTests(document, window, finish);
|
||||
}, false, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE This file contains the Debugger strings -->
|
||||
<!-- LOCALIZATION NOTE : FILE Do not translate commandkey -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
|
||||
- keep it in English, or another language commonly spoken among web developers.
|
||||
- You want to make that choice consistent across the developer tools.
|
||||
- A good criteria is the language in which you'd find the best
|
||||
- documentation on web development on the web. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE (webAudioEditorUI.reloadNotice1): This is the label shown
|
||||
- on the button that triggers a page refresh. -->
|
||||
<!ENTITY webAudioEditorUI.reloadNotice1 "Reload">
|
||||
|
||||
<!-- LOCALIZATION NOTE (webAudioEditorUI.reloadNotice2): This is the label shown
|
||||
- along with the button that triggers a page refresh. -->
|
||||
<!ENTITY webAudioEditorUI.reloadNotice2 "the page to view and edit the audio context.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (webAudioEditorUI.emptyNotice): This is the label shown
|
||||
- while the page is refreshing and the tool waits for a audio context. -->
|
||||
<!ENTITY webAudioEditorUI.emptyNotice "Waiting for an audio context to be created…">
|
|
@ -0,0 +1,21 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# LOCALIZATION NOTE These strings are used inside the Debugger
|
||||
# which is available from the Web Developer sub-menu -> 'Debugger'.
|
||||
# The correct localization of this file might be to keep it in
|
||||
# English, or another language commonly spoken among web developers.
|
||||
# You want to make that choice consistent across the developer tools.
|
||||
# A good criteria is the language in which you'd find the best
|
||||
# documentation on web development on the web.
|
||||
|
||||
# LOCALIZATION NOTE (ToolboxWebAudioEditor.label):
|
||||
# This string is displayed in the title of the tab when the Web Audio Editor
|
||||
# is displayed inside the developer tools window and in the Developer Tools Menu.
|
||||
ToolboxWebAudioEditor.label=Web Audio Editor
|
||||
|
||||
# LOCALIZATION NOTE (ToolboxWebAudioEditor.tooltip):
|
||||
# This string is displayed in the tooltip of the tab when the Web Audio Editor is
|
||||
# displayed inside the developer tools window.
|
||||
ToolboxWebAudioEditor.tooltip=Web Audio context visualizer and editor
|
|
@ -34,6 +34,8 @@
|
|||
locale/browser/devtools/shadereditor.properties (%chrome/browser/devtools/shadereditor.properties)
|
||||
locale/browser/devtools/canvasdebugger.dtd (%chrome/browser/devtools/canvasdebugger.dtd)
|
||||
locale/browser/devtools/canvasdebugger.properties (%chrome/browser/devtools/canvasdebugger.properties)
|
||||
locale/browser/devtools/webaudioeditor.dtd (%chrome/browser/devtools/webaudioeditor.dtd)
|
||||
locale/browser/devtools/webaudioeditor.properties (%chrome/browser/devtools/webaudioeditor.properties)
|
||||
locale/browser/devtools/gcli.properties (%chrome/browser/devtools/gcli.properties)
|
||||
locale/browser/devtools/gclicommands.properties (%chrome/browser/devtools/gclicommands.properties)
|
||||
locale/browser/devtools/webconsole.properties (%chrome/browser/devtools/webconsole.properties)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%include ../../shared/devtools/webaudioeditor.inc.css
|
|
@ -213,15 +213,16 @@ browser.jar:
|
|||
skin/classic/browser/devtools/breadcrumbs-divider@2x.png (../shared/devtools/images/breadcrumbs-divider@2x.png)
|
||||
skin/classic/browser/devtools/breadcrumbs-scrollbutton.png (../shared/devtools/images/breadcrumbs-scrollbutton.png)
|
||||
skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
|
||||
* skin/classic/browser/devtools/splitview.css (../shared/devtools/splitview.css)
|
||||
skin/classic/browser/devtools/styleeditor.css (../shared/devtools/styleeditor.css)
|
||||
* skin/classic/browser/devtools/shadereditor.css (devtools/shadereditor.css)
|
||||
* skin/classic/browser/devtools/canvasdebugger.css (devtools/canvasdebugger.css)
|
||||
* skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
|
||||
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
|
||||
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
|
||||
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
|
||||
skin/classic/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
|
||||
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
|
||||
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
|
||||
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
|
||||
* skin/classic/browser/devtools/shadereditor.css (devtools/shadereditor.css)
|
||||
* skin/classic/browser/devtools/splitview.css (../shared/devtools/splitview.css)
|
||||
skin/classic/browser/devtools/styleeditor.css (../shared/devtools/styleeditor.css)
|
||||
* skin/classic/browser/devtools/webaudioeditor.css (devtools/webaudioeditor.css)
|
||||
skin/classic/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
|
||||
skin/classic/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
|
||||
skin/classic/browser/devtools/magnifying-glass-light.png (../shared/devtools/images/magnifying-glass-light.png)
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче