зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
This commit is contained in:
Коммит
2104aead80
|
@ -2007,8 +2007,13 @@
|
|||
// Ctrl (Cmd for mac) key is pressed
|
||||
if (this.multiselected) {
|
||||
gBrowser.removeFromMultiSelectedTabs(this);
|
||||
} else {
|
||||
gBrowser.addToMultiSelectedTabs(this);
|
||||
if (this == gBrowser.selectedTab) {
|
||||
gBrowser.selectedTab = gBrowser.lastMultiSelectedTab;
|
||||
}
|
||||
} else if (this != gBrowser.selectedTab) {
|
||||
for (let tab of [this, gBrowser.selectedTab]) {
|
||||
gBrowser.addToMultiSelectedTabs(tab);
|
||||
}
|
||||
gBrowser.lastMultiSelectedTab = this;
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -7,6 +7,7 @@ support-files =
|
|||
[browser_accessibility_indicator.js]
|
||||
skip-if = (verify && debug && (os == 'linux'))
|
||||
[browser_allow_process_switches_despite_related_browser.js]
|
||||
[browser_bug_1387976_restore_lazy_tab_browser_muted_state.js]
|
||||
[browser_bug580956.js]
|
||||
[browser_close_tab_by_dblclick.js]
|
||||
[browser_contextmenu_openlink_after_tabnavigated.js]
|
||||
|
@ -14,43 +15,43 @@ skip-if = (verify && debug && (os == 'linux'))
|
|||
support-files =
|
||||
test_bug1358314.html
|
||||
[browser_isLocalAboutURI.js]
|
||||
[browser_tabCloseProbes.js]
|
||||
[browser_tabSpinnerProbe.js]
|
||||
skip-if = !e10s # Tab spinner is e10s only.
|
||||
[browser_tabSwitchPrintPreview.js]
|
||||
skip-if = os == 'mac'
|
||||
[browser_multiselect_tabs_active_tab_selected_by_default.js]
|
||||
[browser_multiselect_tabs_close_using_shortcuts.js]
|
||||
[browser_multiselect_tabs_close.js]
|
||||
[browser_multiselect_tabs_mute_unmute.js]
|
||||
support-files =
|
||||
../general/audio.ogg
|
||||
../general/file_mediaPlayback.html
|
||||
[browser_multiselect_tabs_positional_attrs.js]
|
||||
[browser_multiselect_tabs_using_Ctrl.js]
|
||||
[browser_multiselect_tabs_using_Shift.js]
|
||||
[browser_navigatePinnedTab.js]
|
||||
[browser_new_file_whitelisted_http_tab.js]
|
||||
skip-if = !e10s # Test only relevant for e10s.
|
||||
[browser_new_web_tab_in_file_process_pref.js]
|
||||
skip-if = !e10s # Pref and test only relevant for e10s.
|
||||
[browser_newwindow_tabstrip_overflow.js]
|
||||
[browser_opened_file_tab_navigated_to_web.js]
|
||||
[browser_new_tab_insert_position.js]
|
||||
skip-if = (debug && os == 'linux' && bits == 32) #Bug 1455882, disabled on Linux32 for almost permafailing
|
||||
support-files = file_new_tab_page.html
|
||||
[browser_new_web_tab_in_file_process_pref.js]
|
||||
skip-if = !e10s # Pref and test only relevant for e10s.
|
||||
[browser_newwindow_tabstrip_overflow.js]
|
||||
[browser_open_newtab_start_observer_notification.js]
|
||||
[browser_opened_file_tab_navigated_to_web.js]
|
||||
[browser_overflowScroll.js]
|
||||
[browser_pinnedTabs.js]
|
||||
[browser_pinnedTabs_clickOpen.js]
|
||||
[browser_pinnedTabs_closeByKeyboard.js]
|
||||
[browser_pinnedTabs.js]
|
||||
[browser_positional_attributes.js]
|
||||
skip-if = (verify && (os == 'win' || os == 'mac'))
|
||||
[browser_preloadedBrowser_zoom.js]
|
||||
[browser_reload_deleted_file.js]
|
||||
skip-if = (debug && os == 'mac') || (debug && os == 'linux' && bits == 64) #Bug 1421183, disabled on Linux/OSX for leaked windows
|
||||
[browser_tabCloseProbes.js]
|
||||
[browser_tabReorder_overflow.js]
|
||||
[browser_tabSpinnerProbe.js]
|
||||
skip-if = !e10s # Tab spinner is e10s only.
|
||||
[browser_tabSwitchPrintPreview.js]
|
||||
skip-if = os == 'mac'
|
||||
[browser_tabswitch_updatecommands.js]
|
||||
[browser_viewsource_of_data_URI_in_file_process.js]
|
||||
[browser_visibleTabs_bookmarkAllTabs.js]
|
||||
[browser_visibleTabs_contextMenu.js]
|
||||
[browser_open_newtab_start_observer_notification.js]
|
||||
[browser_bug_1387976_restore_lazy_tab_browser_muted_state.js]
|
||||
[browser_multiselect_tabs_using_Ctrl.js]
|
||||
[browser_multiselect_tabs_using_Shift.js]
|
||||
[browser_multiselect_tabs_close.js]
|
||||
[browser_multiselect_tabs_positional_attrs.js]
|
||||
[browser_multiselect_tabs_close_using_shortcuts.js]
|
||||
[browser_multiselect_tabs_mute_unmute.js]
|
||||
support-files =
|
||||
../general/audio.ogg
|
||||
../general/file_mediaPlayback.html
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
|
||||
|
||||
add_task(async function multiselectActiveTabByDefault() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[PREF_MULTISELECT_TABS, true]]
|
||||
});
|
||||
|
||||
const tab1 = await addTab();
|
||||
const tab2 = await addTab();
|
||||
const tab3 = await addTab();
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||
|
||||
info("Try multiselecting Tab1 (active) with click+CtrlKey");
|
||||
await triggerClickOn(tab1, { ctrlKey: true });
|
||||
|
||||
is(gBrowser.selectedTab, tab1, "Tab1 is active");
|
||||
ok(!tab1.multiselected,
|
||||
"Tab1 is not multi-selected because we are not in multi-select context yet");
|
||||
ok(!tab2.multiselected, "Tab2 is not multi-selected");
|
||||
ok(!tab3.multiselected, "Tab3 is not multi-selected");
|
||||
is(gBrowser.multiSelectedTabsCount, 0, "Zero tabs multi-selected");
|
||||
|
||||
info("We multi-select tab1 and tab2 with ctrl key down");
|
||||
await triggerClickOn(tab2, { ctrlKey: true });
|
||||
await triggerClickOn(tab3, { ctrlKey: true });
|
||||
|
||||
is(gBrowser.selectedTab, tab1, "Tab1 is active");
|
||||
ok(tab1.multiselected, "Tab1 is multi-selected");
|
||||
ok(tab2.multiselected, "Tab2 is multi-selected");
|
||||
ok(tab3.multiselected, "Tab3 is multi-selected");
|
||||
is(gBrowser.multiSelectedTabsCount, 3, "Three tabs multi-selected");
|
||||
is(gBrowser.lastMultiSelectedTab, tab3, "Tab3 is the last multi-selected tab");
|
||||
|
||||
info("Unselect tab1 from multi-selection using ctrlKey");
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, triggerClickOn(tab1, { ctrlKey: true }));
|
||||
|
||||
isnot(gBrowser.selectedTab, tab1, "Tab1 is not active anymore");
|
||||
is(gBrowser.selectedTab, tab3, "Tab3 is active");
|
||||
ok(!tab1.multiselected, "Tab1 is not multi-selected");
|
||||
ok(tab2.multiselected, "Tab2 is multi-selected");
|
||||
ok(tab3.multiselected, "Tab3 is multi-selected");
|
||||
is(gBrowser.multiSelectedTabsCount, 2, "Two tabs multi-selected");
|
||||
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
BrowserTestUtils.removeTab(tab2);
|
||||
BrowserTestUtils.removeTab(tab3);
|
||||
});
|
|
@ -18,7 +18,7 @@ add_task(async function usingTabCloseButton() {
|
|||
|
||||
is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs");
|
||||
|
||||
await triggerClickOn(tab1, { ctrlKey: true });
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||
await triggerClickOn(tab2, { ctrlKey: true });
|
||||
|
||||
ok(tab1.multiselected, "Tab1 is multiselected");
|
||||
|
@ -69,7 +69,7 @@ add_task(async function usingTabContextMenu() {
|
|||
|
||||
is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs");
|
||||
|
||||
await triggerClickOn(tab1, { ctrlKey: true });
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||
await triggerClickOn(tab2, { ctrlKey: true });
|
||||
|
||||
ok(tab1.multiselected, "Tab1 is multiselected");
|
||||
|
|
|
@ -24,13 +24,13 @@ add_task(async function using_Ctrl_W() {
|
|||
await triggerClickOn(tab2, { ctrlKey: true });
|
||||
await triggerClickOn(tab3, { ctrlKey: true });
|
||||
|
||||
is(gBrowser.selectedTab, tab1, "Tab1 is focused");
|
||||
ok(!tab1.multiselected, "Tab1 is not multiselected");
|
||||
ok(tab1.multiselected, "Tab1 is multiselected");
|
||||
ok(tab2.multiselected, "Tab2 is multiselected");
|
||||
ok(tab3.multiselected, "Tab3 is multiselected");
|
||||
ok(!tab4.multiselected, "Tab4 is not multiselected");
|
||||
is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs");
|
||||
is(gBrowser.multiSelectedTabsCount, 3, "Three multiselected tabs");
|
||||
|
||||
let tab1Closing = BrowserTestUtils.waitForTabClosing(tab1);
|
||||
let tab2Closing = BrowserTestUtils.waitForTabClosing(tab2);
|
||||
let tab3Closing = BrowserTestUtils.waitForTabClosing(tab3);
|
||||
|
||||
|
@ -40,28 +40,29 @@ add_task(async function using_Ctrl_W() {
|
|||
const shouldBeClosing = key == "w" || AppConstants.platform != "macosx";
|
||||
|
||||
if (shouldBeClosing) {
|
||||
await tab1Closing;
|
||||
await tab2Closing;
|
||||
await tab3Closing;
|
||||
}
|
||||
|
||||
is(gBrowser.selectedTab, tab1, "Tab1 is still focused");
|
||||
ok(!tab1.closing, "Tab1 is not closing");
|
||||
ok(!tab4.closing, "Tab4 is not closing");
|
||||
|
||||
if (shouldBeClosing) {
|
||||
ok(tab1.closing, "Tab1 is closing");
|
||||
ok(tab2.closing, "Tab2 is closing");
|
||||
ok(tab3.closing, "Tab3 is closing");
|
||||
is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs");
|
||||
} else {
|
||||
ok(!tab1.closing, "Tab1 is not closing");
|
||||
ok(!tab2.closing, "Tab2 is not closing");
|
||||
ok(!tab3.closing, "Tab3 is not closing");
|
||||
is(gBrowser.multiSelectedTabsCount, 2, "Still Two multiselected tabs");
|
||||
is(gBrowser.multiSelectedTabsCount, 3, "Still Three multiselected tabs");
|
||||
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
BrowserTestUtils.removeTab(tab2);
|
||||
BrowserTestUtils.removeTab(tab3);
|
||||
}
|
||||
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
BrowserTestUtils.removeTab(tab4);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -30,7 +30,8 @@ add_task(async function clickWithPrefSet() {
|
|||
});
|
||||
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsSet;
|
||||
const initialFocusedTab = gBrowser.selectedTab;
|
||||
const initialFocusedTab = await addTab();
|
||||
await BrowserTestUtils.switchTab(gBrowser, initialFocusedTab);
|
||||
const tab = await addTab();
|
||||
|
||||
await triggerClickOn(tab, { ctrlKey: true });
|
||||
|
@ -42,6 +43,7 @@ add_task(async function clickWithPrefSet() {
|
|||
ok(!tab.multiselected && !mSelectedTabs.has(tab), "Tab is not (multi) selected anymore");
|
||||
is(gBrowser.selectedTab, initialFocusedTab, "Focused tab still doesn't change");
|
||||
|
||||
BrowserTestUtils.removeTab(initialFocusedTab);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
|
@ -56,8 +58,8 @@ add_task(async function clearSelection() {
|
|||
const tab2 = await addTab();
|
||||
const tab3 = await addTab();
|
||||
|
||||
info("We multi-select tab1 and tab2 with ctrl key down");
|
||||
await triggerClickOn(tab1, { ctrlKey: true });
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||
info("We multi-select tab2 with ctrl key down");
|
||||
await triggerClickOn(tab2, { ctrlKey: true });
|
||||
|
||||
ok(tab1.multiselected && gBrowser._multiSelectedTabsSet.has(tab1), "Tab1 is (multi) selected");
|
||||
|
|
|
@ -86,19 +86,20 @@ add_task(async function itemsInTheCollectionBeforeShiftClicking() {
|
|||
|
||||
await triggerClickOn(tab3, { ctrlKey: true });
|
||||
is(gBrowser.selectedTab, tab1, "Tab1 still has focus");
|
||||
is(gBrowser.multiSelectedTabsCount, 1, "One tab is multi-selected");
|
||||
is(gBrowser.multiSelectedTabsCount, 2, "Two tabs are multi-selected");
|
||||
ok(tab1.multiselected && mSelectedTabs.has(tab1), "Tab1 is multi-selected");
|
||||
ok(tab3.multiselected && mSelectedTabs.has(tab3), "Tab3 is multi-selected");
|
||||
|
||||
info("Click on tab5 while holding Shift key");
|
||||
await triggerClickOn(tab5, { shiftKey: true });
|
||||
|
||||
is(gBrowser.selectedTab, tab1, "Tab1 still has focus");
|
||||
ok(!tab1.multiselected && !mSelectedTabs.has(tab1), "Tab1 is not multi-selected");
|
||||
ok(tab1.multiselected && mSelectedTabs.has(tab1), "Tab1 is multi-selected");
|
||||
ok(!tab2.multiselected && !mSelectedTabs.has(tab2), "Tab2 is not multi-selected ");
|
||||
ok(tab3.multiselected && mSelectedTabs.has(tab3), "Tab3 is multi-selected");
|
||||
ok(tab4.multiselected && mSelectedTabs.has(tab4), "Tab4 is multi-selected");
|
||||
ok(tab5.multiselected && mSelectedTabs.has(tab5), "Tab5 is multi-selected");
|
||||
is(gBrowser.multiSelectedTabsCount, 3, "Three tabs are multi-selected");
|
||||
is(gBrowser.multiSelectedTabsCount, 4, "Four tabs are multi-selected");
|
||||
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
BrowserTestUtils.removeTab(tab2);
|
||||
|
|
|
@ -112,7 +112,7 @@ class AddonsControls extends Component {
|
|||
dom.button({
|
||||
id: "load-addon-from-file",
|
||||
onClick: this.loadAddonFromFile,
|
||||
}, Strings.GetStringFromName("loadTemporaryAddon"))
|
||||
}, Strings.GetStringFromName("loadTemporaryAddon2"))
|
||||
),
|
||||
AddonsInstallError({
|
||||
error: this.state.installError,
|
||||
|
|
|
@ -14,7 +14,7 @@ const FontSize = createFactory(require("./FontSize"));
|
|||
const FontStyle = createFactory(require("./FontStyle"));
|
||||
const FontWeight = createFactory(require("./FontWeight"));
|
||||
|
||||
const { getStr } = require("../utils/l10n");
|
||||
const { getStr, getFormatStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
|
||||
class FontEditor extends PureComponent {
|
||||
|
@ -79,16 +79,45 @@ class FontEditor extends PureComponent {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderFamilesNotUsed(familiesNotUsed = []) {
|
||||
if (!familiesNotUsed.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const familiesList = familiesNotUsed.map(family => {
|
||||
return dom.div(
|
||||
{
|
||||
className: "font-family-unused",
|
||||
},
|
||||
family
|
||||
);
|
||||
});
|
||||
|
||||
return dom.details(
|
||||
{},
|
||||
dom.summary(
|
||||
{
|
||||
className: "font-family-unused-header",
|
||||
},
|
||||
getFormatStr("fontinspector.familiesNotUsedLabel", familiesNotUsed.length)
|
||||
),
|
||||
familiesList
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render font family, font name, and metadata for all fonts used on selected node.
|
||||
*
|
||||
* @param {Array} fonts
|
||||
* Fonts used on selected node.
|
||||
* @param {Array} families
|
||||
* Font familes declared on selected node.
|
||||
* @param {Function} onToggleFontHighlight
|
||||
* Callback to trigger in-context highlighting of text that uses a font.
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
renderFontFamily(fonts, onToggleFontHighlight) {
|
||||
renderFontFamily(fonts, families, onToggleFontHighlight) {
|
||||
if (!fonts.length) {
|
||||
return null;
|
||||
}
|
||||
|
@ -119,7 +148,8 @@ class FontEditor extends PureComponent {
|
|||
{
|
||||
className: "font-control-box",
|
||||
},
|
||||
fontList
|
||||
fontList,
|
||||
this.renderFamilesNotUsed(families.notUsed)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -215,7 +245,7 @@ class FontEditor extends PureComponent {
|
|||
|
||||
render() {
|
||||
const { fontEditor, onToggleFontHighlight } = this.props;
|
||||
const { fonts, axes, instance, properties } = fontEditor;
|
||||
const { fonts, families, axes, instance, properties } = fontEditor;
|
||||
// Pick the first font to show editor controls regardless of how many fonts are used.
|
||||
const font = fonts[0];
|
||||
const hasFontAxes = font && font.variationAxes;
|
||||
|
@ -237,7 +267,7 @@ class FontEditor extends PureComponent {
|
|||
// Render empty state message for nodes that don't have font properties.
|
||||
!hasWeight && this.renderWarning(),
|
||||
// Always render UI for font family, format and font file URL.
|
||||
this.renderFontFamily(fonts, onToggleFontHighlight),
|
||||
this.renderFontFamily(fonts, families, onToggleFontHighlight),
|
||||
// Render UI for font variation instances if they are defined.
|
||||
hasFontInstances && this.renderInstances(font.variationInstances, instance),
|
||||
// Always render UI for font size.
|
||||
|
|
|
@ -411,8 +411,7 @@ class FontInspector {
|
|||
const familiesUsedLowercase = families.used.map(family => family.toLowerCase());
|
||||
// Font family names declared but not used.
|
||||
families.notUsed = fontFamilies
|
||||
.map(family => family.toLowerCase())
|
||||
.filter(family => !familiesUsedLowercase.includes(family));
|
||||
.filter(family => !familiesUsedLowercase.includes(family.toLowerCase()));
|
||||
|
||||
return families;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ skip-if = !e10s # too slow on !e10s, logging fully serialized actors (Bug 144659
|
|||
subsuite = clipboard
|
||||
[browser_fontinspector_edit-previews.js]
|
||||
[browser_fontinspector_expand-css-code.js]
|
||||
[browser_fontinspector_family-unused.js]
|
||||
[browser_fontinspector_other-fonts.js]
|
||||
[browser_fontinspector_reveal-in-page.js]
|
||||
[browser_fontinspector_theme-change.js]
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
}
|
||||
div {
|
||||
font-family:Arial;
|
||||
font-family:bar;
|
||||
font-family:bar, "Missing Family", sans-serif;
|
||||
}
|
||||
.normal-text {
|
||||
font-family: barnormal;
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
|
||||
|
||||
// Test that unused font families show up in the font editor.
|
||||
add_task(async function() {
|
||||
await pushPref("devtools.inspector.fonteditor.enabled", true);
|
||||
const { inspector, view } = await openFontInspectorForURL(TEST_URI);
|
||||
const viewDoc = view.document;
|
||||
|
||||
await testFamiliesUnused(inspector, viewDoc);
|
||||
await testZeroFamiliesUnused(inspector, viewDoc);
|
||||
});
|
||||
|
||||
function getUnusedFontFamilies(viewDoc) {
|
||||
return [...viewDoc.querySelectorAll("#font-editor .font-family-unused")]
|
||||
.map(el => el.textContent);
|
||||
}
|
||||
|
||||
async function testFamiliesUnused(inspector, viewDoc) {
|
||||
await selectNode("div", inspector);
|
||||
|
||||
const unused = getUnusedFontFamilies(viewDoc);
|
||||
is(unused.length, 2, "Two font families were not used");
|
||||
is(unused[0], "Missing Family", "First unused family is correct");
|
||||
is(unused[1], "sans-serif", "Second unused family is correct");
|
||||
}
|
||||
|
||||
async function testZeroFamiliesUnused(inspector, viewDoc) {
|
||||
await selectNode(".normal-text", inspector);
|
||||
|
||||
const unused = getUnusedFontFamilies(viewDoc);
|
||||
const header = viewDoc.querySelector("#font-editor .font-family-unused-header");
|
||||
is(unused.length, 0, "All font families were used");
|
||||
is(header, null, "Container for unused font families was not rendered");
|
||||
}
|
|
@ -8,5 +8,6 @@ const { LocalizationHelper } = require("devtools/shared/l10n");
|
|||
const L10N = new LocalizationHelper("devtools/client/locales/font-inspector.properties");
|
||||
|
||||
module.exports = {
|
||||
getFormatStr: (...args) => L10N.getFormatStr(...args),
|
||||
getStr: (...args) => L10N.getStr(...args),
|
||||
};
|
||||
|
|
|
@ -83,7 +83,8 @@ skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keybo
|
|||
[browser_inspector_highlighter-cssshape_03.js]
|
||||
[browser_inspector_highlighter-cssshape_04.js]
|
||||
[browser_inspector_highlighter-cssshape_05.js]
|
||||
[browser_inspector_highlighter-cssshape_06.js]
|
||||
[browser_inspector_highlighter-cssshape_06-scale.js]
|
||||
[browser_inspector_highlighter-cssshape_06-translate.js]
|
||||
[browser_inspector_highlighter-cssshape_07.js]
|
||||
[browser_inspector_highlighter-cssshape_iframe_01.js]
|
||||
skip-if = (verify && debug)
|
||||
|
|
|
@ -18,7 +18,6 @@ add_task(async function() {
|
|||
const highlighters = view.highlighters;
|
||||
const config = { inspector, view, highlighters, testActor, helper };
|
||||
|
||||
await testTranslate(config);
|
||||
await testScale(config);
|
||||
});
|
||||
|
||||
|
@ -34,48 +33,6 @@ async function teardown(config) {
|
|||
await toggleShapesHighlighter(view, selector, property, false);
|
||||
}
|
||||
|
||||
async function testTranslate(config) {
|
||||
const { testActor, helper, highlighters } = config;
|
||||
const options = { transformMode: true };
|
||||
const property = "clip-path";
|
||||
|
||||
for (const selector of SHAPE_SELECTORS) {
|
||||
await setup({selector, property, options, ...config});
|
||||
const { mouse } = helper;
|
||||
|
||||
const { center, width, height } = await getBoundingBoxInPx({selector, ...config});
|
||||
const [x, y] = center;
|
||||
const dx = width / 10;
|
||||
const dy = height / 10;
|
||||
let onShapeChangeApplied;
|
||||
|
||||
info(`Translating ${selector}`);
|
||||
onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
|
||||
await mouse.down(x, y, selector);
|
||||
await mouse.move(x + dx, y + dy, selector);
|
||||
await mouse.up(x + dx, y + dy, selector);
|
||||
await onShapeChangeApplied;
|
||||
|
||||
let newBB = await getBoundingBoxInPx({selector, ...config});
|
||||
isnot(newBB.center[0], x, `${selector} translated on y axis`);
|
||||
isnot(newBB.center[1], y, `${selector} translated on x axis`);
|
||||
|
||||
info(`Translating ${selector} back`);
|
||||
onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
|
||||
await mouse.down(x + dx, y + dy, selector);
|
||||
await mouse.move(x, y, selector);
|
||||
await mouse.up(x, y, selector);
|
||||
await testActor.reflow();
|
||||
await onShapeChangeApplied;
|
||||
|
||||
newBB = await getBoundingBoxInPx({selector, ...config});
|
||||
is(newBB.center[0], x, `${selector} translated back on x axis`);
|
||||
is(newBB.center[1], y, `${selector} translated back on y axis`);
|
||||
|
||||
await teardown({selector, property, ...config});
|
||||
}
|
||||
}
|
||||
|
||||
async function testScale(config) {
|
||||
const { testActor, helper, highlighters } = config;
|
||||
const options = { transformMode: true };
|
|
@ -0,0 +1,103 @@
|
|||
/* 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";
|
||||
|
||||
// Test that shapes are updated correctly on mouse events in transform mode.
|
||||
|
||||
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_cssshapes.html";
|
||||
const HIGHLIGHTER_TYPE = "ShapesHighlighter";
|
||||
const SHAPE_SELECTORS = ["#polygon-transform", "#circle", "#ellipse", "#inset"];
|
||||
|
||||
add_task(async function() {
|
||||
const env = await openInspectorForURL(TEST_URL);
|
||||
const helper = await getHighlighterHelperFor(HIGHLIGHTER_TYPE)(env);
|
||||
const {testActor, inspector} = env;
|
||||
const view = selectRuleView(inspector);
|
||||
const highlighters = view.highlighters;
|
||||
const config = { inspector, view, highlighters, testActor, helper };
|
||||
|
||||
await testTranslate(config);
|
||||
});
|
||||
|
||||
async function setup(config) {
|
||||
const { inspector, view, selector, property, options } = config;
|
||||
await selectNode(selector, inspector);
|
||||
await toggleShapesHighlighter(view, selector, property, true, options);
|
||||
}
|
||||
|
||||
async function teardown(config) {
|
||||
const { view, selector, property } = config;
|
||||
info(`Turn off shapes highlighter for ${selector}`);
|
||||
await toggleShapesHighlighter(view, selector, property, false);
|
||||
}
|
||||
|
||||
async function testTranslate(config) {
|
||||
const { testActor, helper, highlighters } = config;
|
||||
const options = { transformMode: true };
|
||||
const property = "clip-path";
|
||||
|
||||
for (const selector of SHAPE_SELECTORS) {
|
||||
await setup({selector, property, options, ...config});
|
||||
const { mouse } = helper;
|
||||
|
||||
const { center, width, height } = await getBoundingBoxInPx({selector, ...config});
|
||||
const [x, y] = center;
|
||||
const dx = width / 10;
|
||||
const dy = height / 10;
|
||||
let onShapeChangeApplied;
|
||||
|
||||
info(`Translating ${selector}`);
|
||||
onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
|
||||
await mouse.down(x, y, selector);
|
||||
await mouse.move(x + dx, y + dy, selector);
|
||||
await mouse.up(x + dx, y + dy, selector);
|
||||
await testActor.reflow();
|
||||
await onShapeChangeApplied;
|
||||
|
||||
let newBB = await getBoundingBoxInPx({selector, ...config});
|
||||
isnot(newBB.center[0], x, `${selector} translated on y axis`);
|
||||
isnot(newBB.center[1], y, `${selector} translated on x axis`);
|
||||
|
||||
info(`Translating ${selector} back`);
|
||||
onShapeChangeApplied = highlighters.once("shapes-highlighter-changes-applied");
|
||||
await mouse.down(x + dx, y + dy, selector);
|
||||
await mouse.move(x, y, selector);
|
||||
await mouse.up(x, y, selector);
|
||||
await testActor.reflow();
|
||||
await onShapeChangeApplied;
|
||||
|
||||
newBB = await getBoundingBoxInPx({selector, ...config});
|
||||
is(newBB.center[0], x, `${selector} translated back on x axis`);
|
||||
is(newBB.center[1], y, `${selector} translated back on y axis`);
|
||||
|
||||
await teardown({selector, property, ...config});
|
||||
}
|
||||
}
|
||||
|
||||
async function getBoundingBoxInPx(config) {
|
||||
const { testActor, selector, inspector, highlighters } = config;
|
||||
const quads = await testActor.getAllAdjustedQuads(selector);
|
||||
const { width, height } = quads.content[0].bounds;
|
||||
const highlightedNode = await getNodeFront(selector, inspector);
|
||||
const computedStyle = await inspector.pageStyle.getComputed(highlightedNode);
|
||||
const paddingTop = parseFloat(computedStyle["padding-top"].value);
|
||||
const paddingLeft = parseFloat(computedStyle["padding-left"].value);
|
||||
// path is always of form "Mx y Lx y Lx y Lx y Z", where x/y are numbers
|
||||
const path = await testActor.getHighlighterNodeAttribute(
|
||||
"shapes-bounding-box", "d", highlighters.highlighters[HIGHLIGHTER_TYPE]);
|
||||
const coords = path.replace(/[MLZ]/g, "").split(" ").map((n, i) => {
|
||||
return i % 2 === 0 ? paddingLeft + width * n / 100 : paddingTop + height * n / 100;
|
||||
});
|
||||
|
||||
const nw = [coords[0], coords[1]];
|
||||
const ne = [coords[2], coords[3]];
|
||||
const se = [coords[4], coords[5]];
|
||||
const sw = [coords[6], coords[7]];
|
||||
const center = [(nw[0] + se[0]) / 2, (nw[1] + se[1]) / 2];
|
||||
const shapeWidth = Math.sqrt((ne[0] - nw[0]) ** 2 + (ne[1] - nw[1]) ** 2);
|
||||
const shapeHeight = Math.sqrt((sw[0] - nw[0]) ** 2 + (sw[1] - nw[1]) ** 2);
|
||||
|
||||
return { nw, ne, se, sw, center, width: shapeWidth, height: shapeHeight };
|
||||
}
|
|
@ -53,10 +53,10 @@ addonDebugging.tooltip = Turning this on will allow you to debug add-ons and var
|
|||
# (https://developer.mozilla.org/docs/Tools/about:debugging#Enabling_add-on_debugging)
|
||||
addonDebugging.learnMore = Learn more
|
||||
|
||||
# LOCALIZATION NOTE (loadTemporaryAddon):
|
||||
# LOCALIZATION NOTE (loadTemporaryAddon2):
|
||||
# This string is displayed as a label of a button that allows the user to
|
||||
# load additional add-ons.
|
||||
loadTemporaryAddon = Load Temporary Add-on
|
||||
loadTemporaryAddon2 = Load Temporary Add-on…
|
||||
|
||||
# LOCALIZATION NOTE (addonInstallError):
|
||||
# This string is displayed when an error occurs while installing an addon.
|
||||
|
|
|
@ -55,3 +55,8 @@ fontinspector.fontWeightLabel=Weight
|
|||
# LOCALIZATION NOTE (fontinspector.fontItalicLabel): This label is shown next to the UI
|
||||
# in the font editor which allows the user to change the style of the font to italic.
|
||||
fontinspector.fontItalicLabel=Italic
|
||||
|
||||
# LOCALIZATION NOTE (fontinspector.familiesNotUsedLabel): This label is shown at the top
|
||||
# of the list of unused font families. %S is the number of unused font families. It is
|
||||
# always a positive integer larger than zero.
|
||||
fontinspector.familiesNotUsedLabel=%S not used
|
||||
|
|
|
@ -156,6 +156,17 @@
|
|||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.font-family-unused-header {
|
||||
-moz-user-select: none;
|
||||
margin-bottom: .7em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.font-family-unused {
|
||||
margin-bottom: .3em;
|
||||
color: var(--grey-50);
|
||||
}
|
||||
|
||||
.font-instance-select:active{
|
||||
outline: none;
|
||||
}
|
||||
|
|
|
@ -1883,12 +1883,18 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
|||
// used width and height of the reference box as sqrt(width^2+height^2)/sqrt(2).
|
||||
const computedSize = Math.sqrt((width ** 2) + (height ** 2)) / Math.sqrt(2);
|
||||
|
||||
// Position coordinates for circle center in pixels.
|
||||
const cxPx = width * center[0] / 100;
|
||||
const cyPx = height * center[1] / 100;
|
||||
|
||||
if (radius === "closest-side") {
|
||||
// radius is the distance from center to closest side of reference box
|
||||
radius = Math.min(center[0], center[1], 100 - center[0], 100 - center[1]);
|
||||
radius = Math.min(cxPx, cyPx, width - cxPx, height - cyPx);
|
||||
radius = coordToPercent(`${radius}px`, computedSize);
|
||||
} else if (radius === "farthest-side") {
|
||||
// radius is the distance from center to farthest side of reference box
|
||||
radius = Math.max(center[0], center[1], 100 - center[0], 100 - center[1]);
|
||||
radius = Math.max(cxPx, cyPx, width - cxPx, height - cyPx);
|
||||
radius = coordToPercent(`${radius}px`, computedSize);
|
||||
} else if (radius.includes("calc(")) {
|
||||
radius = evalCalcExpression(radius.substring(5, radius.length - 1), computedSize);
|
||||
} else {
|
||||
|
|
|
@ -2720,12 +2720,6 @@ HTMLMediaElement::FastSeek(double aTime, ErrorResult& aRv)
|
|||
already_AddRefed<Promise>
|
||||
HTMLMediaElement::SeekToNextFrame(ErrorResult& aRv)
|
||||
{
|
||||
if (mSeekDOMPromise) {
|
||||
// We can't perform NextFrameSeek while seek is already in action.
|
||||
// Just return the pending seek promise.
|
||||
return do_AddRef(mSeekDOMPromise);
|
||||
}
|
||||
|
||||
/* This will cause JIT code to be kept around longer, to help performance
|
||||
* when using SeekToNextFrame to iterate through every frame of a video.
|
||||
*/
|
||||
|
|
|
@ -876,6 +876,21 @@ public:
|
|||
// Do nothing. We will resume video decoding in the decoding state.
|
||||
}
|
||||
|
||||
// We specially handle next frame seeks by ignoring them if we're already
|
||||
// seeking.
|
||||
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
|
||||
{
|
||||
if (aTarget.IsNextFrame()) {
|
||||
// We ignore next frame seeks if we already have a seek pending
|
||||
SLOG("Already SEEKING, ignoring seekToNextFrame");
|
||||
MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
|
||||
return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true,
|
||||
__func__);
|
||||
}
|
||||
|
||||
return StateObject::HandleSeek(aTarget);
|
||||
}
|
||||
|
||||
protected:
|
||||
SeekJob mSeekJob;
|
||||
EventVisibility mVisibility;
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<title>Bug 1450845: Avoid seek to next frame when already seeking</title>
|
||||
<script>
|
||||
async function boom() {
|
||||
let video = document.getElementById('video');
|
||||
|
||||
// Internally play causes a seek, make sure we don't crash during this
|
||||
video.play();
|
||||
try {
|
||||
await document.getElementById('video').seekToNextFrame();
|
||||
} catch (e) {
|
||||
// We don't mind if the promise was rejected so long as we don't crash
|
||||
}
|
||||
// Didn't crash
|
||||
|
||||
// Stop playback and cause a seek to 0
|
||||
video.pause();
|
||||
video.currentTime = 0;
|
||||
try {
|
||||
await document.getElementById('video').seekToNextFrame();
|
||||
} finally {
|
||||
// Didn't crash
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
}
|
||||
window.addEventListener('load', boom)
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<video id='video' src='data:video/webm;base64,GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBQoWBAhhTgGcBAAAAAAAB6BFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua1OsggEwTbuMU6uEHFO7a1OsggHL7AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAAEUqTYCNTGF2ZjU3LjI5LjEwMVdBjUxhdmY1Ny4yOS4xMDFzpJBAb17Yv2oNAF1ZEESuco33RImIQFCAAAAAAAAWVK5rAQAAAAAAADyuAQAAAAAAADPXgQFzxYEBnIEAIrWcg3VuZIaFVl9WUDmDgQEj44OEAfygVeABAAAAAAAAB7CCAUC6gfAfQ7Z1AQAAAAAAAEfngQCjqYEAAICCSYNCABPwDvYAOCQcGFQAAFBh9jAAABML7AAATEnjdRwIJ+gAo5eBACEAhgBAkpwATEAABCasAABekcXgAB'>
|
||||
</body>
|
||||
</html>
|
|
@ -97,6 +97,7 @@ load 1384248.html
|
|||
load 1389304.html
|
||||
load 1393272.webm
|
||||
load 1411322.html
|
||||
load 1450845.html
|
||||
load disconnect-wrong-destination.html
|
||||
load analyser-channels-1.html
|
||||
skip-if(verify&&isDebugBuild&>kWidget) load audiocontext-double-suspend.html
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "AudioWorkletNode.h"
|
||||
|
||||
#include "AudioParamMap.h"
|
||||
#include "mozilla/dom/AudioWorkletNodeBinding.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(AudioWorkletNode, AudioNode)
|
||||
|
||||
AudioWorkletNode::AudioWorkletNode(AudioContext* aAudioContext,
|
||||
const nsAString& aName)
|
||||
: AudioNode(aAudioContext,
|
||||
2,
|
||||
ChannelCountMode::Max,
|
||||
ChannelInterpretation::Speakers)
|
||||
, mNodeName(aName)
|
||||
{
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<AudioWorkletNode>
|
||||
AudioWorkletNode::Constructor(const GlobalObject& aGlobal,
|
||||
AudioContext& aAudioContext,
|
||||
const nsAString& aName,
|
||||
const AudioWorkletNodeOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (aAudioContext.CheckClosed(aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aOptions.mNumberOfInputs == 0 && aOptions.mNumberOfOutputs == 0) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aOptions.mOutputChannelCount.WasPassed()) {
|
||||
if (aOptions.mOutputChannelCount.Value().Length() !=
|
||||
aOptions.mNumberOfOutputs) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (uint32_t channelCount : aOptions.mOutputChannelCount.Value()) {
|
||||
if (channelCount == 0 ||
|
||||
channelCount > WebAudioUtils::MaxChannelCount) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<AudioWorkletNode> audioWorkletNode =
|
||||
new AudioWorkletNode(&aAudioContext, aName);
|
||||
|
||||
audioWorkletNode->Initialize(aOptions, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return audioWorkletNode.forget();
|
||||
}
|
||||
|
||||
AudioParamMap* AudioWorkletNode::GetParameters(ErrorResult& aRv) const
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MessagePort* AudioWorkletNode::GetPort(ErrorResult& aRv) const
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
AudioWorkletNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return AudioWorkletNodeBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
size_t
|
||||
AudioWorkletNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
|
||||
return amount;
|
||||
}
|
||||
|
||||
size_t
|
||||
AudioWorkletNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,58 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef AudioWorkletNode_h_
|
||||
#define AudioWorkletNode_h_
|
||||
|
||||
#include "AudioNode.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class AudioParamMap;
|
||||
struct AudioWorkletNodeOptions;
|
||||
class MessagePort;
|
||||
|
||||
class AudioWorkletNode : public AudioNode
|
||||
{
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
IMPL_EVENT_HANDLER(processorerror)
|
||||
|
||||
static already_AddRefed<AudioWorkletNode>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
AudioContext& aAudioContext,
|
||||
const nsAString& aName,
|
||||
const AudioWorkletNodeOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
AudioParamMap* GetParameters(ErrorResult& aRv) const;
|
||||
|
||||
MessagePort* GetPort(ErrorResult& aRv) const;
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
const char* NodeType() const override
|
||||
{
|
||||
return "AudioWorkletNode";
|
||||
}
|
||||
|
||||
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
|
||||
|
||||
private:
|
||||
AudioWorkletNode(AudioContext* aAudioContext, const nsAString& aName);
|
||||
~AudioWorkletNode() = default;
|
||||
|
||||
nsString mNodeName;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // AudioWorkletNode_h_
|
|
@ -52,6 +52,7 @@ EXPORTS.mozilla.dom += [
|
|||
'AudioParamMap.h',
|
||||
'AudioProcessingEvent.h',
|
||||
'AudioScheduledSourceNode.h',
|
||||
'AudioWorkletNode.h',
|
||||
'BiquadFilterNode.h',
|
||||
'ChannelMergerNode.h',
|
||||
'ChannelSplitterNode.h',
|
||||
|
@ -89,6 +90,7 @@ UNIFIED_SOURCES += [
|
|||
'AudioParamMap.cpp',
|
||||
'AudioProcessingEvent.cpp',
|
||||
'AudioScheduledSourceNode.cpp',
|
||||
'AudioWorkletNode.cpp',
|
||||
'BiquadFilterNode.cpp',
|
||||
'ChannelMergerNode.cpp',
|
||||
'ChannelSplitterNode.cpp',
|
||||
|
|
|
@ -158,6 +158,8 @@ var interfaceNamesInGlobalScope =
|
|||
{name: "AudioScheduledSourceNode", insecureContext: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AudioStreamTrack", insecureContext: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AudioWorkletNode", insecureContext: false, disabled: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AuthenticatorAssertionResponse"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://webaudio.github.io/web-audio-api/
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
dictionary AudioWorkletNodeOptions : AudioNodeOptions {
|
||||
unsigned long numberOfInputs = 1;
|
||||
unsigned long numberOfOutputs = 1;
|
||||
sequence<unsigned long> outputChannelCount;
|
||||
record<DOMString, double> parameterData;
|
||||
object? processorOptions = null;
|
||||
};
|
||||
|
||||
[SecureContext, Pref="dom.audioworklet.enabled",
|
||||
Constructor (BaseAudioContext context, DOMString name, optional AudioWorkletNodeOptions options)]
|
||||
interface AudioWorkletNode : AudioNode {
|
||||
[Throws]
|
||||
readonly attribute AudioParamMap parameters;
|
||||
[Throws]
|
||||
readonly attribute MessagePort port;
|
||||
attribute EventHandler onprocessorerror;
|
||||
};
|
|
@ -385,6 +385,7 @@ WEBIDL_FILES = [
|
|||
'AudioTrack.webidl',
|
||||
'AudioTrackList.webidl',
|
||||
'AudioWorkletGlobalScope.webidl',
|
||||
'AudioWorkletNode.webidl',
|
||||
'AutocompleteInfo.webidl',
|
||||
'BarProp.webidl',
|
||||
'BaseAudioContext.webidl',
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<title>Clock</title>
|
||||
<style type="text/css">
|
||||
* {
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
.inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: white;
|
||||
border-radius: 100%;
|
||||
box-shadow: 0px 0px 18px black inset;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 588px; height: 588px; padding: 26px;">
|
||||
<div class="inner"></div>
|
||||
</div>
|
||||
</body></html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<title>Clock</title>
|
||||
<style type="text/css">
|
||||
* {
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
.inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: white;
|
||||
border-radius: 100%;
|
||||
box-shadow: 0px 0px 18px black inset;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 588px; height: 588px; padding: 26.01px;">
|
||||
<div class="inner"></div>
|
||||
</div>
|
||||
</body></html>
|
|
@ -13,3 +13,4 @@ fuzzy(100,30) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted
|
|||
== 1435143.html 1435143-ref.html
|
||||
== 1444904.html 1444904-ref.html
|
||||
== 1451168.html 1451168-ref.html
|
||||
fuzzy(5-32,21908-26354) fuzzy-if(webrender,0-1,0-3) == 1463802.html 1463802-ref.html
|
||||
|
|
|
@ -46,6 +46,7 @@ raptor-firefox-speedometer:
|
|||
run-on-projects:
|
||||
by-test-platform:
|
||||
macosx.*: ['try', 'mozilla-central']
|
||||
linux64.*: ['try', 'mozilla-central']
|
||||
default: ['try']
|
||||
max-run-time: 1500
|
||||
mozharness:
|
||||
|
|
|
@ -41,6 +41,8 @@ function pprint(ss, ...values) {
|
|||
return prettyElement(val);
|
||||
} else if (["[object Window]", "[object ChromeWindow]"].includes(proto)) {
|
||||
return prettyWindowGlobal(val);
|
||||
} else if (proto == "[object Attr]") {
|
||||
return prettyAttr(val);
|
||||
}
|
||||
return prettyObject(val);
|
||||
}
|
||||
|
@ -63,6 +65,10 @@ function pprint(ss, ...values) {
|
|||
return `[${proto.substring(1, proto.length - 1)} ${win.location}]`;
|
||||
}
|
||||
|
||||
function prettyAttr(obj) {
|
||||
return `[object Attr ${obj.name}="${obj.value}"]`;
|
||||
}
|
||||
|
||||
function prettyObject(obj) {
|
||||
let proto = Object.prototype.toString.call(obj);
|
||||
let s = "";
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
[DEFAULT]
|
||||
type = benchmark
|
||||
test_url = http://localhost:<port>/Speedometer/index.html?raptor
|
||||
page_cycles = 1
|
||||
page_timeout = 120000
|
||||
page_cycles = 5
|
||||
page_timeout = 180000
|
||||
unit = score
|
||||
lower_is_better = false
|
||||
alert_threshold = 2.0
|
||||
|
|
|
@ -5,7 +5,7 @@ import json
|
|||
import os
|
||||
from datetime import datetime, timedelta
|
||||
import tarfile
|
||||
from vcs import Mercurial
|
||||
import vcs
|
||||
import requests
|
||||
from cStringIO import StringIO
|
||||
|
||||
|
@ -14,10 +14,28 @@ def abs_path(path):
|
|||
|
||||
|
||||
def hg_commits(repo_root):
|
||||
hg = Mercurial.get_func(repo_root)
|
||||
return [item for item in hg("log", "-fl50", "--template={node}\n",
|
||||
"testing/web-platform/tests/", "testing/web-platform/mozilla/tests").split("\n")
|
||||
if item]
|
||||
hg = vcs.Mercurial.get_func(repo_root)
|
||||
for item in hg("log", "-fl50", "--template={node}\n", "testing/web-platform/tests",
|
||||
"testing/web-platform/mozilla/tests").splitlines():
|
||||
yield item
|
||||
|
||||
|
||||
def git_commits(repo_root):
|
||||
git = vcs.Git.get_func(repo_root)
|
||||
for item in git("log", "--format=%H", "-n50", "testing/web-platform/tests",
|
||||
"testing/web-platform/mozilla/tests").splitlines():
|
||||
yield git("cinnabar", "git2hg", item)
|
||||
|
||||
|
||||
def get_commits(logger, repo_root):
|
||||
if vcs.Mercurial.is_hg_repo(repo_root):
|
||||
return hg_commits(repo_root)
|
||||
|
||||
elif vcs.Git.is_git_repo(repo_root):
|
||||
return git_commits(repo_root)
|
||||
|
||||
logger.warning("No VCS found")
|
||||
return False
|
||||
|
||||
|
||||
def should_download(logger, manifest_path, rebuild_time=timedelta(days=5)):
|
||||
|
@ -59,10 +77,12 @@ def taskcluster_url(logger, commits):
|
|||
|
||||
|
||||
def download_manifest(logger, wpt_dir, commits_func, url_func, force=False):
|
||||
if not force and not should_download(logger, wpt_dir):
|
||||
if not force and not should_download(logger, os.path.join(wpt_dir, "meta", "MANIFEST.json")):
|
||||
return False
|
||||
|
||||
commits = commits_func()
|
||||
if not commits:
|
||||
return False
|
||||
url = url_func(logger, commits) + "/artifacts/public/manifests.tar.gz"
|
||||
|
||||
if not url:
|
||||
|
@ -106,7 +126,7 @@ def create_parser():
|
|||
|
||||
|
||||
def download_from_taskcluster(logger, wpt_dir, repo_root, force=False):
|
||||
return download_manifest(logger, wpt_dir, lambda: hg_commits(repo_root),
|
||||
return download_manifest(logger, wpt_dir, lambda: get_commits(logger, repo_root),
|
||||
taskcluster_url, force)
|
||||
|
||||
|
||||
|
|
|
@ -2,19 +2,50 @@ import os
|
|||
import subprocess
|
||||
|
||||
class Mercurial(object):
|
||||
|
||||
def __init__(self, repo_root):
|
||||
self.root = os.path.abspath(repo_root)
|
||||
self.hg = Mercurial.get_func(repo_root)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_func(repo_path):
|
||||
def get_func(repo_root):
|
||||
def hg(cmd, *args):
|
||||
full_cmd = ["hg", cmd] + list(args)
|
||||
try:
|
||||
return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT)
|
||||
except Exception as e:
|
||||
raise(e)
|
||||
return subprocess.check_output(full_cmd, cwd=repo_root)
|
||||
# TODO: Test on Windows.
|
||||
return hg
|
||||
|
||||
@staticmethod
|
||||
def is_hg_repo(repo_root):
|
||||
try:
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
subprocess.check_call(["hg", "root"], cwd=repo_root, stdout=devnull,
|
||||
stderr=devnull)
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
# TODO: Test on windows
|
||||
return True
|
||||
|
||||
|
||||
class Git(object):
|
||||
def __init__(self, repo_root, url_base):
|
||||
self.root = os.path.abspath(repo_root)
|
||||
self.git = Git.get_func(repo_root)
|
||||
|
||||
@staticmethod
|
||||
def get_func(repo_root):
|
||||
def git(cmd, *args):
|
||||
full_cmd = ["git", cmd] + list(args)
|
||||
return subprocess.check_output(full_cmd, cwd=repo_root)
|
||||
# TODO: Test on Windows.
|
||||
return git
|
||||
|
||||
@staticmethod
|
||||
def is_git_repo(repo_root):
|
||||
try:
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
subprocess.check_call(["git", "rev-parse", "--show-cdup"], cwd=repo_root,
|
||||
stdout=devnull, stderr=devnull)
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
# TODO: Test on windows
|
||||
return True
|
||||
|
|
|
@ -731,11 +731,21 @@ body:not(.loaded) .toolbar:-moz-locale-dir(rtl) {
|
|||
list-style: decimal;
|
||||
}
|
||||
|
||||
/* Hide elements with common "hidden" class names */
|
||||
/* Visually hide (but don't display: none) screen reader elements */
|
||||
.moz-reader-content .visually-hidden,
|
||||
.moz-reader-content .visuallyhidden,
|
||||
.moz-reader-content .hidden,
|
||||
.moz-reader-content .invisible,
|
||||
.moz-reader-content .sr-only {
|
||||
display: inline-block;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
/* Hide elements with common "hidden" class names */
|
||||
.moz-reader-content .hidden,
|
||||
.moz-reader-content .invisible {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -808,6 +808,7 @@ GK_ATOM(onpopuphiding, "onpopuphiding")
|
|||
GK_ATOM(onpopuppositioned, "onpopuppositioned")
|
||||
GK_ATOM(onpopupshowing, "onpopupshowing")
|
||||
GK_ATOM(onpopupshown, "onpopupshown")
|
||||
GK_ATOM(onprocessorerror, "onprocessorerror")
|
||||
GK_ATOM(onpush, "onpush")
|
||||
GK_ATOM(onpushsubscriptionchange, "onpushsubscriptionchange")
|
||||
GK_ATOM(onRadioStateChange, "onRadioStateChange")
|
||||
|
|
Загрузка…
Ссылка в новой задаче