This commit is contained in:
Ryan VanderMeulen 2014-04-15 12:28:18 -04:00
Родитель 506698ccd1 1c376e5653
Коммит 43c521d5fa
188 изменённых файлов: 20278 добавлений и 3410 удалений

Просмотреть файл

@ -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) {
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.

9275
browser/devtools/webaudioeditor/lib/d3.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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,41 +410,44 @@ 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)

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше