зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
3e349fa00d
|
@ -1,16 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
|
||||
|
||||
// This file is used as a stub object for platforms which
|
||||
// don't have CAN_DRAW_IN_TITLEBAR defined.
|
||||
|
||||
var TabsInTitlebar = {
|
||||
init() {},
|
||||
whenWindowLayoutReady() {},
|
||||
uninit() {},
|
||||
allowedBy() {},
|
||||
update() {},
|
||||
enabled: false,
|
||||
};
|
|
@ -3,19 +3,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/. */
|
||||
|
||||
// Note: the file browser-tabsintitlebar-stub.js is used instead of
|
||||
// this one on platforms which don't have CAN_DRAW_IN_TITLEBAR defined.
|
||||
|
||||
var TabsInTitlebar = {
|
||||
init() {
|
||||
this._readPref();
|
||||
Services.prefs.addObserver(this._prefName, this);
|
||||
|
||||
// Always disable on unsupported GTK versions.
|
||||
if (AppConstants.MOZ_WIDGET_TOOLKIT == "gtk3") {
|
||||
this.allowedBy("gtk", window.matchMedia("(-moz-gtk-csd-available)"));
|
||||
}
|
||||
|
||||
// We need to update the appearance of the titlebar when the menu changes
|
||||
// from the active to the inactive state. We can't, however, rely on
|
||||
// DOMMenuBarInactive, because the menu fires this event and then removes
|
||||
|
@ -66,6 +58,21 @@ var TabsInTitlebar = {
|
|||
}
|
||||
},
|
||||
|
||||
get systemSupported() {
|
||||
let isSupported = false;
|
||||
switch (AppConstants.MOZ_WIDGET_TOOLKIT) {
|
||||
case "windows":
|
||||
case "cocoa":
|
||||
isSupported = true;
|
||||
break;
|
||||
case "gtk3":
|
||||
isSupported = window.matchMedia("(-moz-gtk-csd-available)");
|
||||
break;
|
||||
}
|
||||
delete this.systemSupported;
|
||||
return this.systemSupported = isSupported;
|
||||
},
|
||||
|
||||
get enabled() {
|
||||
return document.documentElement.getAttribute("tabsintitlebar") == "true";
|
||||
},
|
||||
|
@ -134,7 +141,8 @@ var TabsInTitlebar = {
|
|||
return;
|
||||
}
|
||||
|
||||
let allowed = (Object.keys(this._disallowed)).length == 0;
|
||||
let allowed = this.systemSupported &&
|
||||
(Object.keys(this._disallowed)).length == 0;
|
||||
if (allowed) {
|
||||
document.documentElement.setAttribute("tabsintitlebar", "true");
|
||||
if (AppConstants.platform == "macosx") {
|
||||
|
|
|
@ -277,7 +277,6 @@ window:not([chromehidden~="toolbar"]) #nav-bar[nonemptyoverflow] > .overflow-but
|
|||
}
|
||||
|
||||
|
||||
%ifdef CAN_DRAW_IN_TITLEBAR
|
||||
%ifdef MENUBAR_CAN_AUTOHIDE
|
||||
#toolbar-menubar:not([autohide=true]) + #TabsToolbar > .titlebar-placeholder,
|
||||
%endif
|
||||
|
@ -347,8 +346,6 @@ toolbarpaletteitem {
|
|||
}
|
||||
%endif
|
||||
|
||||
%endif
|
||||
|
||||
#main-window[inFullscreen][inDOMFullscreen] #navigator-toolbox,
|
||||
#main-window[inFullscreen][inDOMFullscreen] #fullscr-toggler,
|
||||
#main-window[inFullscreen][inDOMFullscreen] #sidebar-box,
|
||||
|
|
|
@ -46,14 +46,12 @@
|
|||
titlemodifier_normal="&mainWindow.titlemodifier;"
|
||||
titlemodifier_privatebrowsing="&mainWindow.titlemodifier; &mainWindow.titlePrivateBrowsingSuffix;"
|
||||
#endif
|
||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||
#ifdef XP_WIN
|
||||
chromemargin="0,2,2,2"
|
||||
#else
|
||||
chromemargin="0,-1,-1,-1"
|
||||
#endif
|
||||
tabsintitlebar="true"
|
||||
#endif
|
||||
titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
|
||||
windowtype="navigator:browser"
|
||||
macanimationtype="document"
|
||||
|
@ -598,7 +596,6 @@
|
|||
</popupset>
|
||||
<box id="appMenu-viewCache" hidden="true"/>
|
||||
|
||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||
<vbox id="titlebar">
|
||||
<hbox id="titlebar-content">
|
||||
<spacer id="titlebar-spacer" flex="1"/>
|
||||
|
@ -620,7 +617,6 @@
|
|||
#endif
|
||||
</hbox>
|
||||
</vbox>
|
||||
#endif
|
||||
|
||||
<toolbox id="navigator-toolbox">
|
||||
<!-- Menu -->
|
||||
|
@ -640,11 +636,9 @@
|
|||
#include browser-menubar.inc
|
||||
</toolbaritem>
|
||||
|
||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||
#ifndef XP_MACOSX
|
||||
<hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"
|
||||
skipintoolbarset="true"/>
|
||||
#endif
|
||||
#endif
|
||||
</toolbar>
|
||||
|
||||
|
@ -656,11 +650,8 @@
|
|||
aria-label="&tabsToolbar.label;"
|
||||
context="toolbar-context-menu"
|
||||
collapsed="true">
|
||||
|
||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||
<hbox class="titlebar-placeholder" type="pre-tabs"
|
||||
skipintoolbarset="true"/>
|
||||
#endif
|
||||
|
||||
<tabs id="tabbrowser-tabs"
|
||||
flex="1"
|
||||
|
@ -704,18 +695,15 @@
|
|||
</menupopup>
|
||||
</toolbarbutton>
|
||||
|
||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||
<hbox class="titlebar-placeholder" type="post-tabs"
|
||||
ordinal="1000"
|
||||
skipintoolbarset="true"/>
|
||||
#endif
|
||||
|
||||
<button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;"
|
||||
ordinal="1000"
|
||||
aria-live="polite" skipintoolbarset="true"/>
|
||||
<hbox class="private-browsing-indicator" skipintoolbarset="true"
|
||||
ordinal="1000"/>
|
||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||
<hbox class="titlebar-placeholder" type="caption-buttons"
|
||||
#ifndef XP_MACOSX
|
||||
ordinal="1000"
|
||||
|
@ -725,7 +713,6 @@
|
|||
#ifdef XP_MACOSX
|
||||
<hbox class="titlebar-placeholder" type="fullscreen-button"
|
||||
skipintoolbarset="true"/>
|
||||
#endif
|
||||
#endif
|
||||
</toolbar>
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function invokeUsingCtrlD(phase) {
|
||||
switch (phase) {
|
||||
case 1:
|
||||
|
@ -31,96 +33,58 @@ function invokeUsingStarButton(phase) {
|
|||
}
|
||||
}
|
||||
|
||||
var testURL = "data:text/plain,Content";
|
||||
var bookmarkId;
|
||||
add_task(async function() {
|
||||
const TEST_URL = "data:text/plain,Content";
|
||||
|
||||
function add_bookmark(aURI, aTitle) {
|
||||
return PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
aURI, PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
aTitle);
|
||||
}
|
||||
|
||||
// test bug 432599
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
|
||||
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
|
||||
waitForStarChange(false, initTest);
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
|
||||
registerCleanupFunction(async () => {
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
});
|
||||
|
||||
gBrowser.loadURI(testURL);
|
||||
}
|
||||
// Changing the location causes the star to asynchronously update, thus wait
|
||||
// for it to be in a stable state before proceeding.
|
||||
await TestUtils.waitForCondition(
|
||||
() => BookmarkingUI.status == BookmarkingUI.STATUS_UNSTARRED
|
||||
);
|
||||
|
||||
function initTest() {
|
||||
// First, bookmark the page.
|
||||
bookmarkId = add_bookmark(makeURI(testURL), "Bug 432599 Test");
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: TEST_URL,
|
||||
title: "Bug 432599 Test"
|
||||
});
|
||||
Assert.equal(BookmarkingUI.status, BookmarkingUI.STATUS_STARRED,
|
||||
"The star state should be starred");
|
||||
|
||||
checkBookmarksPanel(invokers[currentInvoker], 1);
|
||||
}
|
||||
|
||||
function waitForStarChange(aValue, aCallback) {
|
||||
let expectedStatus = aValue ? BookmarkingUI.STATUS_STARRED
|
||||
: BookmarkingUI.STATUS_UNSTARRED;
|
||||
if (BookmarkingUI.status == BookmarkingUI.STATUS_UPDATING ||
|
||||
BookmarkingUI.status != expectedStatus) {
|
||||
info("Waiting for star button change.");
|
||||
setTimeout(waitForStarChange, 50, aValue, aCallback);
|
||||
return;
|
||||
for (let invoker of [invokeUsingStarButton, invokeUsingCtrlD]) {
|
||||
for (let phase = 1; phase < 5; ++phase) {
|
||||
let promise = checkBookmarksPanel(phase);
|
||||
invoker(phase);
|
||||
await promise;
|
||||
Assert.equal(BookmarkingUI.status, BookmarkingUI.STATUS_STARRED,
|
||||
"The star state shouldn't change");
|
||||
}
|
||||
aCallback();
|
||||
}
|
||||
|
||||
var invokers = [invokeUsingStarButton, invokeUsingCtrlD];
|
||||
var currentInvoker = 0;
|
||||
}
|
||||
});
|
||||
|
||||
var initialValue;
|
||||
var initialRemoveHidden;
|
||||
|
||||
var popupElement = document.getElementById("editBookmarkPanel");
|
||||
var titleElement = document.getElementById("editBookmarkPanelTitle");
|
||||
var removeElement = document.getElementById("editBookmarkPanelRemoveButton");
|
||||
|
||||
function checkBookmarksPanel(invoker, phase) {
|
||||
let onPopupShown = function popupShownListener(aEvent) {
|
||||
if (aEvent.originalTarget == popupElement) {
|
||||
popupElement.removeEventListener("popupshown", popupShownListener);
|
||||
checkBookmarksPanel(invoker, phase + 1);
|
||||
}
|
||||
};
|
||||
let onPopupHidden = function listener(aEvent) {
|
||||
if (aEvent.originalTarget == popupElement) {
|
||||
popupElement.removeEventListener("popuphidden", listener);
|
||||
if (phase < 4) {
|
||||
checkBookmarksPanel(invoker, phase + 1);
|
||||
} else {
|
||||
++currentInvoker;
|
||||
if (currentInvoker < invokers.length) {
|
||||
checkBookmarksPanel(invokers[currentInvoker], 1);
|
||||
} else {
|
||||
gBrowser.removeTab(gBrowser.selectedTab, {skipPermitUnload: true});
|
||||
PlacesUtils.bookmarks.removeItem(bookmarkId);
|
||||
executeSoon(finish);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function checkBookmarksPanel(phase) {
|
||||
let popupElement = document.getElementById("editBookmarkPanel");
|
||||
let titleElement = document.getElementById("editBookmarkPanelTitle");
|
||||
let removeElement = document.getElementById("editBookmarkPanelRemoveButton");
|
||||
switch (phase) {
|
||||
case 1:
|
||||
case 3:
|
||||
popupElement.addEventListener("popupshown", onPopupShown);
|
||||
break;
|
||||
return promisePopupEvent(popupElement, "shown");
|
||||
case 2:
|
||||
popupElement.addEventListener("popuphidden", onPopupHidden);
|
||||
initialValue = titleElement.value;
|
||||
initialRemoveHidden = removeElement.hidden;
|
||||
break;
|
||||
return promisePopupEvent(popupElement, "hidden");
|
||||
case 4:
|
||||
popupElement.addEventListener("popuphidden", onPopupHidden);
|
||||
is(titleElement.value, initialValue, "The bookmark panel's title should be the same");
|
||||
is(removeElement.hidden, initialRemoveHidden, "The bookmark panel's visibility should not change");
|
||||
break;
|
||||
Assert.equal(titleElement.value, initialValue, "The bookmark panel's title should be the same");
|
||||
Assert.equal(removeElement.hidden, initialRemoveHidden, "The bookmark panel's visibility should not change");
|
||||
return promisePopupEvent(popupElement, "hidden");
|
||||
}
|
||||
invoker(phase);
|
||||
return Promise.reject(new Error("Unknown phase"));
|
||||
}
|
||||
|
|
|
@ -68,11 +68,7 @@ browser.jar:
|
|||
content/browser/browser-sidebar.js (content/browser-sidebar.js)
|
||||
content/browser/browser-sync.js (content/browser-sync.js)
|
||||
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
|
||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||
content/browser/browser-tabsintitlebar.js (content/browser-tabsintitlebar.js)
|
||||
#else
|
||||
content/browser/browser-tabsintitlebar.js (content/browser-tabsintitlebar-stub.js)
|
||||
#endif
|
||||
content/browser/browser-thumbnails.js (content/browser-thumbnails.js)
|
||||
content/browser/browser-trackingprotection.js (content/browser-trackingprotection.js)
|
||||
content/browser/browser-webrender.js (content/browser-webrender.js)
|
||||
|
|
|
@ -62,9 +62,6 @@ DEFINES['APP_LICENSE_BLOCK'] = '%s/content/overrides/app-license.html' % SRCDIR
|
|||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk3', 'cocoa'):
|
||||
DEFINES['CONTEXT_COPY_IMAGE_CONTENTS'] = 1
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa', 'gtk3'):
|
||||
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk3'):
|
||||
DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
|
||||
|
||||
|
|
|
@ -102,14 +102,19 @@ function CustomizeMode(aWindow) {
|
|||
// toolbar items in browser.xul. This is invisible, and never seen by the
|
||||
// user. Then there's the visible palette, which gets populated and displayed
|
||||
// to the user when in customizing mode.
|
||||
this.visiblePalette = this.document.getElementById(kPaletteId);
|
||||
this.pongArena = this.document.getElementById("customization-pong-arena");
|
||||
if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
|
||||
this.visiblePalette = this.$(kPaletteId);
|
||||
this.pongArena = this.$("customization-pong-arena");
|
||||
|
||||
if (this._canDrawInTitlebar()) {
|
||||
this._updateTitlebarCheckbox();
|
||||
this._updateDragSpaceCheckbox();
|
||||
Services.prefs.addObserver(kDrawInTitlebarPref, this);
|
||||
Services.prefs.addObserver(kExtraDragSpacePref, this);
|
||||
} else {
|
||||
this.$("customization-titlebar-visibility-checkbox").hidden = true;
|
||||
this.$("customization-extra-drag-space-checkbox").hidden = true;
|
||||
}
|
||||
|
||||
this.window.addEventListener("unload", this);
|
||||
}
|
||||
|
||||
|
@ -138,12 +143,16 @@ CustomizeMode.prototype = {
|
|||
},
|
||||
|
||||
uninit() {
|
||||
if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
|
||||
if (this._canDrawInTitlebar()) {
|
||||
Services.prefs.removeObserver(kDrawInTitlebarPref, this);
|
||||
Services.prefs.removeObserver(kExtraDragSpacePref, this);
|
||||
}
|
||||
},
|
||||
|
||||
$(id) {
|
||||
return this.document.getElementById(id);
|
||||
},
|
||||
|
||||
toggle() {
|
||||
if (this._handler.isEnteringCustomizeMode || this._handler.isExitingCustomizeMode) {
|
||||
this._wantToBeInCustomizeMode = !this._wantToBeInCustomizeMode;
|
||||
|
@ -1577,7 +1586,7 @@ CustomizeMode.prototype = {
|
|||
case "nsPref:changed":
|
||||
this._updateResetButton();
|
||||
this._updateUndoResetButton();
|
||||
if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
|
||||
if (this._canDrawInTitlebar()) {
|
||||
this._updateTitlebarCheckbox();
|
||||
this._updateDragSpaceCheckbox();
|
||||
}
|
||||
|
@ -1585,12 +1594,13 @@ CustomizeMode.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
_canDrawInTitlebar() {
|
||||
return this.window.TabsInTitlebar.systemSupported;
|
||||
},
|
||||
|
||||
_updateTitlebarCheckbox() {
|
||||
if (!AppConstants.CAN_DRAW_IN_TITLEBAR) {
|
||||
return;
|
||||
}
|
||||
let drawInTitlebar = Services.prefs.getBoolPref(kDrawInTitlebarPref, true);
|
||||
let checkbox = this.document.getElementById("customization-titlebar-visibility-checkbox");
|
||||
let checkbox = this.$("customization-titlebar-visibility-checkbox");
|
||||
// Drawing in the titlebar means 'hiding' the titlebar.
|
||||
// We use the attribute rather than a property because if we're not in
|
||||
// customize mode the button is hidden and properties don't work.
|
||||
|
@ -1602,18 +1612,14 @@ CustomizeMode.prototype = {
|
|||
},
|
||||
|
||||
_updateDragSpaceCheckbox() {
|
||||
if (!AppConstants.CAN_DRAW_IN_TITLEBAR) {
|
||||
return;
|
||||
}
|
||||
|
||||
let extraDragSpace = Services.prefs.getBoolPref(kExtraDragSpacePref);
|
||||
let drawInTitlebar = Services.prefs.getBoolPref(kDrawInTitlebarPref, true);
|
||||
let menuBar = this.document.getElementById("toolbar-menubar");
|
||||
let menuBar = this.$("toolbar-menubar");
|
||||
let menuBarEnabled = menuBar
|
||||
&& AppConstants.platform != "macosx"
|
||||
&& menuBar.getAttribute("autohide") != "true";
|
||||
|
||||
let checkbox = this.document.getElementById("customization-extra-drag-space-checkbox");
|
||||
let checkbox = this.$("customization-extra-drag-space-checkbox");
|
||||
if (extraDragSpace) {
|
||||
checkbox.setAttribute("checked", "true");
|
||||
} else {
|
||||
|
@ -1628,19 +1634,12 @@ CustomizeMode.prototype = {
|
|||
},
|
||||
|
||||
toggleTitlebar(aShouldShowTitlebar) {
|
||||
if (!AppConstants.CAN_DRAW_IN_TITLEBAR) {
|
||||
return;
|
||||
}
|
||||
// Drawing in the titlebar means not showing the titlebar, hence the negation:
|
||||
Services.prefs.setBoolPref(kDrawInTitlebarPref, !aShouldShowTitlebar);
|
||||
this._updateDragSpaceCheckbox();
|
||||
},
|
||||
|
||||
toggleDragSpace(aShouldShowDragSpace) {
|
||||
if (!AppConstants.CAN_DRAW_IN_TITLEBAR) {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.prefs.setBoolPref(kExtraDragSpacePref, aShouldShowDragSpace);
|
||||
},
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
</vbox>
|
||||
</box>
|
||||
<hbox id="customization-footer">
|
||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||
<checkbox id="customization-titlebar-visibility-checkbox" class="customizationmode-checkbox"
|
||||
label="&customizeMode.titlebar;"
|
||||
#NB: because oncommand fires after click, by the time we've fired, the checkbox binding
|
||||
|
@ -37,7 +36,6 @@
|
|||
<checkbox id="customization-extra-drag-space-checkbox" class="customizationmode-checkbox"
|
||||
label="&customizeMode.extraDragSpace;"
|
||||
oncommand="gCustomizeMode.toggleDragSpace(this.checked)"/>
|
||||
#endif
|
||||
<button id="customization-toolbar-visibility-button" label="&customizeMode.toolbars2;" class="customizationmode-button" type="menu">
|
||||
<menupopup id="customization-toolbar-menu" onpopupshowing="onViewToolbarsPopupShowing(event)"/>
|
||||
</button>
|
||||
|
|
|
@ -20,8 +20,5 @@ EXTRA_JS_MODULES += [
|
|||
'SearchWidgetTracker.jsm',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
|
||||
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Firefox', 'Toolbars and Customization')
|
||||
|
|
|
@ -242,12 +242,13 @@ var gSearchResultsPane = {
|
|||
rootPreferencesChildren = rootPreferencesChildren.filter(el => !el.hidden);
|
||||
}
|
||||
|
||||
// Mark all the children to check be visible to bind JS, Access Keys, etc,
|
||||
// but don't really show them by setting their visibility to hidden in CSS.
|
||||
// Attach the bindings for all children if they were not already visible.
|
||||
for (let child of rootPreferencesChildren) {
|
||||
if (child.hidden) {
|
||||
child.classList.add("visually-hidden");
|
||||
child.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
let ts = performance.now();
|
||||
let FRAME_THRESHOLD = 1000 / 60;
|
||||
|
@ -268,7 +269,6 @@ var gSearchResultsPane = {
|
|||
if (!child.classList.contains("header") &&
|
||||
!child.classList.contains("subcategory") &&
|
||||
await this.searchWithinNode(child, this.query)) {
|
||||
child.hidden = false;
|
||||
child.classList.remove("visually-hidden");
|
||||
|
||||
// Show the preceding search-header if one exists.
|
||||
|
@ -280,7 +280,7 @@ var gSearchResultsPane = {
|
|||
|
||||
resultsFound = true;
|
||||
} else {
|
||||
child.hidden = true;
|
||||
child.classList.add("visually-hidden");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -513,7 +513,7 @@ var gSearchResultsPane = {
|
|||
}
|
||||
let searchTooltip = anchorNode.ownerDocument.createElement("span");
|
||||
let searchTooltipText = anchorNode.ownerDocument.createElement("span");
|
||||
searchTooltip.setAttribute("class", "search-tooltip");
|
||||
searchTooltip.className = "search-tooltip";
|
||||
searchTooltipText.textContent = query;
|
||||
searchTooltip.appendChild(searchTooltipText);
|
||||
|
||||
|
@ -535,15 +535,11 @@ var gSearchResultsPane = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Remove all search tooltips that were created.
|
||||
* Remove all search tooltips.
|
||||
*/
|
||||
removeAllSearchTooltips() {
|
||||
let searchTooltips = Array.from(document.querySelectorAll(".search-tooltip"));
|
||||
for (let searchTooltip of searchTooltips) {
|
||||
searchTooltip.parentElement.classList.remove("search-tooltip-parent");
|
||||
searchTooltip.remove();
|
||||
}
|
||||
for (let anchorNode of this.listSearchTooltips) {
|
||||
anchorNode.parentElement.classList.remove("search-tooltip-parent");
|
||||
anchorNode.tooltipNode.remove();
|
||||
anchorNode.tooltipNode = null;
|
||||
}
|
||||
|
|
|
@ -192,9 +192,7 @@ function search(aQuery, aAttribute) {
|
|||
let elements = mainPrefPane.children;
|
||||
for (let element of elements) {
|
||||
// If the "data-hidden-from-search" is "true", the
|
||||
// element will not get considered during search. This
|
||||
// should only be used when an element is still under
|
||||
// development and should not be shown for any reason.
|
||||
// element will not get considered during search.
|
||||
if (element.getAttribute("data-hidden-from-search") != "true" ||
|
||||
element.getAttribute("data-subpanel") == "true") {
|
||||
let attributeValue = element.getAttribute(aAttribute);
|
||||
|
@ -203,6 +201,9 @@ function search(aQuery, aAttribute) {
|
|||
} else {
|
||||
element.hidden = true;
|
||||
}
|
||||
} else if (element.getAttribute("data-hidden-from-search") == "true" &&
|
||||
!element.hidden) {
|
||||
element.hidden = true;
|
||||
}
|
||||
element.classList.remove("visually-hidden");
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ skip-if = !updater
|
|||
[browser_bug410900.js]
|
||||
[browser_bug705422.js]
|
||||
[browser_bug731866.js]
|
||||
[browser_search_no_results_change_category.js]
|
||||
[browser_search_within_preferences_1.js]
|
||||
[browser_search_within_preferences_2.js]
|
||||
[browser_search_within_preferences_command.js]
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
"use strict";
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [["browser.preferences.search", true]]});
|
||||
});
|
||||
|
||||
add_task(async function() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
|
||||
|
||||
let searchInput = gBrowser.contentDocument.getElementById("searchInput");
|
||||
is(searchInput, gBrowser.contentDocument.activeElement.closest("#searchInput"),
|
||||
"Search input should be focused when visiting preferences");
|
||||
let query = "ffff____noresults____ffff";
|
||||
let searchCompletedPromise = BrowserTestUtils.waitForEvent(
|
||||
gBrowser.contentWindow, "PreferencesSearchCompleted", evt => evt.detail == query);
|
||||
EventUtils.sendString(query);
|
||||
await searchCompletedPromise;
|
||||
|
||||
let noResultsEl = gBrowser.contentDocument.querySelector("#no-results-message");
|
||||
is_element_visible(noResultsEl, "Should be reporting no results for this query");
|
||||
|
||||
let privacyCategory = gBrowser.contentDocument.querySelector("#category-privacy");
|
||||
privacyCategory.click();
|
||||
is_element_hidden(noResultsEl,
|
||||
"Should not be showing the 'no results' message after selecting a category");
|
||||
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
|
@ -8,21 +8,18 @@
|
|||
"use strict";
|
||||
|
||||
class EditAutofillForm {
|
||||
constructor(elements, record) {
|
||||
constructor(elements) {
|
||||
this._elements = elements;
|
||||
this._record = record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the form with a record object.
|
||||
* @param {object} record
|
||||
* @param {object} [record = {}]
|
||||
*/
|
||||
loadInitialValues(record) {
|
||||
for (let field in record) {
|
||||
let input = document.getElementById(field);
|
||||
if (input) {
|
||||
input.value = record[field];
|
||||
}
|
||||
loadRecord(record = {}) {
|
||||
for (let field of this._elements.form.elements) {
|
||||
let value = record[field.id];
|
||||
field.value = typeof(value) == "undefined" ? "" : value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +29,7 @@ class EditAutofillForm {
|
|||
*/
|
||||
buildFormObject() {
|
||||
return Array.from(this._elements.form.elements).reduce((obj, input) => {
|
||||
if (input.value) {
|
||||
if (input.value && !input.disabled) {
|
||||
obj[input.id] = input.value;
|
||||
}
|
||||
return obj;
|
||||
|
@ -85,9 +82,7 @@ class EditAddress extends EditAutofillForm {
|
|||
* @param {string[]} config.supportedCountries
|
||||
*/
|
||||
constructor(elements, record, config) {
|
||||
let country = record ? record.country :
|
||||
config.supportedCountries.find(supported => supported == config.DEFAULT_REGION);
|
||||
super(elements, record || {country});
|
||||
super(elements);
|
||||
|
||||
Object.assign(this, config);
|
||||
Object.assign(this._elements, {
|
||||
|
@ -99,11 +94,21 @@ class EditAddress extends EditAutofillForm {
|
|||
this.populateCountries();
|
||||
// Need to populate the countries before trying to set the initial country.
|
||||
// Also need to use this._record so it has the default country selected.
|
||||
this.loadInitialValues(this._record);
|
||||
this.formatForm(country);
|
||||
this.loadRecord(record);
|
||||
this.attachEventListeners();
|
||||
}
|
||||
|
||||
loadRecord(record) {
|
||||
this._record = record;
|
||||
if (!record) {
|
||||
record = {
|
||||
country: this.supportedCountries.find(supported => supported == this.DEFAULT_REGION),
|
||||
};
|
||||
}
|
||||
super.loadRecord(record);
|
||||
this.formatForm(record.country);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the form based on country. The address-level1 and postal-code labels
|
||||
* should be specific to the given country.
|
||||
|
@ -176,23 +181,33 @@ class EditCreditCard extends EditAutofillForm {
|
|||
* @param {function} config.isCCNumber Function to determine is a string is a valid CC number.
|
||||
*/
|
||||
constructor(elements, record, config) {
|
||||
super(elements, record);
|
||||
super(elements);
|
||||
|
||||
Object.assign(this, config);
|
||||
Object.assign(this._elements, {
|
||||
ccNumber: this._elements.form.querySelector("#cc-number"),
|
||||
year: this._elements.form.querySelector("#cc-exp-year"),
|
||||
});
|
||||
this.generateYears();
|
||||
this.loadInitialValues(this._record);
|
||||
|
||||
this.loadRecord(record);
|
||||
this.attachEventListeners();
|
||||
}
|
||||
|
||||
loadRecord(record) {
|
||||
// _record must be updated before generateYears is called.
|
||||
this._record = record;
|
||||
this.generateYears();
|
||||
super.loadRecord(record);
|
||||
}
|
||||
|
||||
generateYears() {
|
||||
const count = 11;
|
||||
const currentYear = new Date().getFullYear();
|
||||
const ccExpYear = this._record && this._record["cc-exp-year"];
|
||||
|
||||
// Clear the list
|
||||
this._elements.year.textContent = "";
|
||||
|
||||
if (ccExpYear && ccExpYear < currentYear) {
|
||||
this._elements.year.appendChild(new Option(ccExpYear));
|
||||
}
|
||||
|
|
|
@ -147,3 +147,8 @@ update.locale
|
|||
# Aurora branding
|
||||
browser/chrome/browser/content/branding/icon128.png
|
||||
browser/chrome/devtools/content/framework/dev-edition-promo/dev-edition-logo.png
|
||||
# Bug 1451016 - Nightly-only PaymentRequest & Form Autofill code sharing.
|
||||
browser/features/formautofill@mozilla.org/chrome/content/editCreditCard.xhtml
|
||||
chrome/toolkit/res/payments/formautofill/editCreditCard.xhtml
|
||||
browser/features/formautofill@mozilla.org/chrome/content/autofillEditForms.js
|
||||
chrome/toolkit/res/payments/formautofill/autofillEditForms.js
|
||||
|
|
|
@ -8,5 +8,3 @@ DIRS += ['communicator']
|
|||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
|
||||
|
||||
|
|
|
@ -652,13 +652,11 @@
|
|||
margin-inline-start: -1px;
|
||||
}
|
||||
|
||||
%ifdef CAN_DRAW_IN_TITLEBAR
|
||||
%ifdef MENUBAR_CAN_AUTOHIDE
|
||||
:root[tabsintitlebar]:not([extradragspace]) #toolbar-menubar[autohide=true] + #TabsToolbar > #tabbrowser-tabs > .tabbrowser-tab::after,
|
||||
%else
|
||||
:root[tabsintitlebar]:not([extradragspace]) .tabbrowser-tab::after,
|
||||
%endif
|
||||
%endif
|
||||
/* Show full height tab separators on hover. */
|
||||
.tabbrowser-tab:hover::after,
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab[beforehovered]::after {
|
||||
|
|
|
@ -8,6 +8,5 @@ DIRS += ['communicator']
|
|||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
|
||||
DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ tags = devtools
|
|||
subsuite = devtools
|
||||
support-files =
|
||||
doc_custom_playback_rate.html
|
||||
doc_frame_script.js
|
||||
doc_multi_easings.html
|
||||
doc_multi_keyframes.html
|
||||
doc_multi_timings.html
|
||||
|
|
|
@ -7,47 +7,48 @@
|
|||
// 1. Existence for animated property list.
|
||||
// 2. Number of animated property item.
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
target: ".animated",
|
||||
targetClass: "animated",
|
||||
expectedNumber: 1,
|
||||
},
|
||||
{
|
||||
target: ".compositor-notall",
|
||||
targetClass: "compositor-notall",
|
||||
expectedNumber: 3,
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { animationInspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking animated property list and items existence at initial");
|
||||
ok(!panel.querySelector(".animated-property-list"),
|
||||
"The animated-property-list should not be in the DOM at initial");
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
info(`Checking animated-property-list and items existence at ${ testCase.target }`);
|
||||
const animatedNode = await getNodeFront(testCase.target, inspector);
|
||||
await selectNodeAndWaitForAnimations(animatedNode, inspector);
|
||||
for (const { targetClass, expectedNumber } of TEST_DATA) {
|
||||
info(`Checking animated-property-list and items existence at ${ targetClass }`);
|
||||
await clickOnAnimationByTargetSelector(animationInspector,
|
||||
panel, `.${ targetClass }`);
|
||||
ok(panel.querySelector(".animated-property-list"),
|
||||
`The animated-property-list should be in the DOM at ${ testCase.target }`);
|
||||
`The animated-property-list should be in the DOM at ${ targetClass }`);
|
||||
const itemEls =
|
||||
panel.querySelectorAll(".animated-property-list .animated-property-item");
|
||||
is(itemEls.length, testCase.expectedNumber,
|
||||
`The number of animated-property-list should be ${ testCase.expectedNumber } `
|
||||
+ `at ${ testCase.target }`);
|
||||
is(itemEls.length, expectedNumber,
|
||||
`The number of animated-property-list should be ${ expectedNumber } ` +
|
||||
`at ${ targetClass }`);
|
||||
|
||||
if (itemEls.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
info(`Checking the background color for `
|
||||
+ `the animated property item at ${ testCase.target }`);
|
||||
info("Checking the background color for " +
|
||||
`the animated property item at ${ targetClass }`);
|
||||
const evenColor = panel.ownerGlobal.getComputedStyle(itemEls[0]).backgroundColor;
|
||||
const oddColor = panel.ownerGlobal.getComputedStyle(itemEls[1]).backgroundColor;
|
||||
isnot(evenColor, oddColor,
|
||||
"Background color of an even animated property item "
|
||||
+ "should be different from odd");
|
||||
"Background color of an even animated property item " +
|
||||
"should be different from odd");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -23,10 +23,10 @@ const TEST_DATA = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
await removeAnimatedElementsExcept([".longhand"]);
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking unchanged animated property item");
|
||||
await selectNodeAndWaitForAnimations(".longhand", inspector);
|
||||
const itemEls = panel.querySelectorAll(".animated-property-item");
|
||||
is(itemEls.length, TEST_DATA.length,
|
||||
`Count of animated property item should be ${ TEST_DATA.length }`);
|
||||
|
|
|
@ -24,29 +24,32 @@ const TEST_DATA = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
await removeAnimatedElementsExcept([".compositor-notall"]);
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking animated property name component");
|
||||
await selectNodeAndWaitForAnimations(".compositor-notall", inspector);
|
||||
|
||||
const animatedPropertyNameEls = panel.querySelectorAll(".animated-property-name");
|
||||
is(animatedPropertyNameEls.length, TEST_DATA.length,
|
||||
`Number of animated property name elements should be ${ TEST_DATA.length }`);
|
||||
|
||||
for (const [index, animatedPropertyNameEl] of animatedPropertyNameEls.entries()) {
|
||||
const testData = TEST_DATA[index];
|
||||
const {
|
||||
property,
|
||||
isOnCompositor,
|
||||
isWarning,
|
||||
} = TEST_DATA[index];
|
||||
|
||||
info(`Checking text content for ${ testData.property }`);
|
||||
info(`Checking text content for ${ property }`);
|
||||
|
||||
const spanEl = animatedPropertyNameEl.querySelector("span");
|
||||
ok(spanEl,
|
||||
`<span> element should be in animated-property-name of ${ testData.property }`);
|
||||
is(spanEl.textContent, testData.property,
|
||||
`textContent should be ${ testData.property }`);
|
||||
`<span> element should be in animated-property-name of ${ property }`);
|
||||
is(spanEl.textContent, property,
|
||||
`textContent should be ${ property }`);
|
||||
|
||||
info(`Checking compositor sign for ${ testData.property }`);
|
||||
info(`Checking compositor sign for ${ property }`);
|
||||
|
||||
if (testData.isOnCompositor) {
|
||||
if (isOnCompositor) {
|
||||
ok(animatedPropertyNameEl.classList.contains("compositor"),
|
||||
"animatedPropertyNameEl should has .compositor class");
|
||||
isnot(getComputedStyle(spanEl, "::before").width, "auto",
|
||||
|
@ -58,9 +61,9 @@ add_task(async function() {
|
|||
"width of ::before pseud should be auto");
|
||||
}
|
||||
|
||||
info(`Checking warning for ${ testData.property }`);
|
||||
info(`Checking warning for ${ property }`);
|
||||
|
||||
if (testData.isWarning) {
|
||||
if (isWarning) {
|
||||
ok(animatedPropertyNameEl.classList.contains("warning"),
|
||||
"animatedPropertyNameEl should has .warning class");
|
||||
is(getComputedStyle(spanEl).textDecorationStyle, "dotted",
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Test that whether close button in header of animation detail works.
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
|
||||
const { animationInspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking close button in header of animation detail");
|
||||
|
|
|
@ -5,33 +5,34 @@
|
|||
|
||||
// Test that whether title in header of animations detail.
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
target: ".cssanimation-normal",
|
||||
targetClass: "cssanimation-normal",
|
||||
expectedTitle: "cssanimation - CSS Animation",
|
||||
},
|
||||
{
|
||||
target: ".delay-positive",
|
||||
targetClass: "delay-positive",
|
||||
expectedTitle: "test-delay-animation - Script Animation",
|
||||
},
|
||||
{
|
||||
target: ".easing-step",
|
||||
targetClass: "easing-step",
|
||||
expectedTitle: "Script Animation",
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { animationInspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking title in each header of animation detail");
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
info(`Checking title at ${ testCase.target }`);
|
||||
const animatedNode = await getNodeFront(testCase.target, inspector);
|
||||
await selectNodeAndWaitForAnimations(animatedNode, inspector);
|
||||
for (const { targetClass, expectedTitle } of TEST_DATA) {
|
||||
info(`Checking title at ${ targetClass }`);
|
||||
await clickOnAnimationByTargetSelector(animationInspector,
|
||||
panel, `.${ targetClass }`);
|
||||
const titleEl = panel.querySelector(".animation-detail-title");
|
||||
is(titleEl.textContent, testCase.expectedTitle,
|
||||
`Title of "${ testCase.target }" should be "${ testCase.expectedTitle }"`);
|
||||
is(titleEl.textContent, expectedTitle,
|
||||
`Title of "${ targetClass }" should be "${ expectedTitle }"`);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -5,10 +5,8 @@
|
|||
|
||||
// Test that whether animations detail could be displayed if there is selected animation.
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
await addTab(URL_ROOT + "doc_custom_playback_rate.html");
|
||||
const { animationInspector, inspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking animation detail visibility if animation was unselected");
|
||||
|
@ -27,7 +25,7 @@ add_task(async function() {
|
|||
"detailEl should be unvisibled after choose html node");
|
||||
|
||||
info("Checking animation detail visibility when choose node which has an animation");
|
||||
await selectNodeAndWaitForAnimations(".cssanimation-normal", inspector);
|
||||
await selectNodeAndWaitForAnimations("div", inspector);
|
||||
isnot(win.getComputedStyle(detailEl).display, "none",
|
||||
"detailEl should be visibled after choose .cssanimation-normal node");
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
|
||||
await removeAnimatedElementsExcept([".animated", ".long"]);
|
||||
const { animationInspector, inspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking animation list and items existence");
|
||||
|
@ -27,8 +27,7 @@ add_task(async function() {
|
|||
"Background color of an even animation should be different from odd");
|
||||
|
||||
info("Checking list and items existence after select a element which has an animation");
|
||||
const animatedNode = await getNodeFront(".animated", inspector);
|
||||
await selectNodeAndWaitForAnimations(animatedNode, inspector);
|
||||
await selectNodeAndWaitForAnimations(".animated", inspector);
|
||||
is(panel.querySelectorAll(".animation-list .animation-item").length, 1,
|
||||
"The number of animations displayed should be 1 for .animated element");
|
||||
});
|
||||
|
|
|
@ -10,13 +10,14 @@
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
await removeAnimatedElementsExcept([".animated", ".long"]);
|
||||
const { animationInspector, inspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking the animation target elements existance");
|
||||
const animationItemEls = panel.querySelectorAll(".animation-list .animation-item");
|
||||
is(animationItemEls.length, animationInspector.state.animations.length,
|
||||
"Number of animation target element should be same to number of animations "
|
||||
+ "that displays");
|
||||
"Number of animation target element should be same to number of animations " +
|
||||
"that displays");
|
||||
|
||||
for (const animationItemEl of animationItemEls) {
|
||||
const animationTargetEl = animationItemEl.querySelector(".animation-target");
|
||||
|
@ -30,6 +31,5 @@ add_task(async function() {
|
|||
panel.querySelector(".animation-list .animation-item .animation-target");
|
||||
is(animationTargetEl.textContent, "div.ball.animated",
|
||||
"The target element's content is correct");
|
||||
ok(animationTargetEl.querySelector(".objectBox"),
|
||||
"objectBox is in the page exists");
|
||||
ok(animationTargetEl.querySelector(".objectBox"), "objectBox is in the page exists");
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@ const TIME_GRADUATION_MIN_SPACING = 40;
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
await removeAnimatedElementsExcept([".end-delay", ".negative-delay"]);
|
||||
const { animationInspector, inspector, panel } = await openAnimationInspector();
|
||||
const timeScale = new TimeScale(animationInspector.state.animations);
|
||||
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
const { animationInspector, inspector, panel } = await openAnimationInspector();
|
||||
await removeAnimatedElementsExcept([".keyframes-easing-step"]);
|
||||
const { animationInspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking current time label existence");
|
||||
const labelEl = panel.querySelector(".current-time-label");
|
||||
ok(labelEl, "current time label should exist");
|
||||
|
||||
info("Checking current time label content");
|
||||
await selectNodeAndWaitForAnimations(".keyframes-easing-step", inspector);
|
||||
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.5);
|
||||
assertLabelContent(labelEl, animationInspector.state.animations[0].state.currentTime);
|
||||
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0.2);
|
||||
|
@ -50,6 +50,7 @@ function formatStopwatchTime(time) {
|
|||
if (nb < max) {
|
||||
return new Array((max + "").length - (nb + "").length + 1).join("0") + nb;
|
||||
}
|
||||
|
||||
return nb;
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
const { animationInspector, inspector, panel } = await openAnimationInspector();
|
||||
await removeAnimatedElementsExcept([".long"]);
|
||||
const { animationInspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking scrubber controller existence");
|
||||
const controllerEl = panel.querySelector(".current-time-scrubber-controller");
|
||||
|
@ -22,7 +23,6 @@ add_task(async function() {
|
|||
ok(scrubberEl, "scrubber should exist");
|
||||
|
||||
info("Checking scrubber changes current time of animation and the position");
|
||||
await selectNodeAndWaitForAnimations(".long", inspector);
|
||||
const duration = animationInspector.state.timeScale.getDuration();
|
||||
await clickOnCurrentTimeScrubberController(animationInspector, panel, 0);
|
||||
assertAnimationsCurrentTime(animationInspector, 0);
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
// Test that the panel shows no animation data for invalid or not animated nodes
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
|
||||
await removeAnimatedElementsExcept([".animated", ".long", ".still"]);
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking animation list and error message existence for a still node");
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
// * fill color by animation type
|
||||
// * stop color if the animation type is color
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetName: "multi-types",
|
||||
targetClass: "multi-types",
|
||||
properties: [
|
||||
{
|
||||
name: "background-color",
|
||||
|
@ -87,7 +85,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "multi-types-reverse",
|
||||
targetClass: "multi-types-reverse",
|
||||
properties: [
|
||||
{
|
||||
name: "background-color",
|
||||
|
@ -161,7 +159,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "middle-keyframe",
|
||||
targetClass: "middle-keyframe",
|
||||
properties: [
|
||||
{
|
||||
name: "background-color",
|
||||
|
@ -249,7 +247,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "steps-keyframe",
|
||||
targetClass: "steps-keyframe",
|
||||
properties: [
|
||||
{
|
||||
name: "background-color",
|
||||
|
@ -335,7 +333,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "steps-effect",
|
||||
targetClass: "steps-effect",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -351,7 +349,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "frames-keyframe",
|
||||
targetClass: "frames-keyframe",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -372,7 +370,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "narrow-offsets",
|
||||
targetClass: "narrow-offsets",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -391,7 +389,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "duplicate-offsets",
|
||||
targetClass: "duplicate-offsets",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -412,12 +410,12 @@ const TEST_DATA = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_keyframes.html");
|
||||
const { animationInspector, panel } = await openAnimationInspector();
|
||||
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
|
||||
for (const { properties, targetName } of TEST_DATA) {
|
||||
info(`Checking keyframes graph for ${ targetName }`);
|
||||
await selectNodeAndWaitForAnimations(`#${ targetName }`, inspector);
|
||||
for (const { properties, targetClass } of TEST_DATA) {
|
||||
info(`Checking keyframes graph for ${ targetClass }`);
|
||||
await clickOnAnimationByTargetSelector(animationInspector,
|
||||
panel, `.${ targetClass }`);
|
||||
|
||||
for (const property of properties) {
|
||||
const {
|
||||
|
@ -427,7 +425,7 @@ add_task(async function() {
|
|||
expectedStopColors,
|
||||
} = property;
|
||||
|
||||
const testTarget = `${ name } in ${ targetName }`;
|
||||
const testTarget = `${ name } in ${ targetClass }`;
|
||||
info(`Checking keyframes graph for ${ testTarget }`);
|
||||
info(`Checking keyframes graph path existence for ${ testTarget }`);
|
||||
const keyframesGraphPathEl = panel.querySelector(`.${ name }`);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetName: "no-easing",
|
||||
targetClass: "no-easing",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -28,7 +28,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "effect-easing",
|
||||
targetClass: "effect-easing",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -46,7 +46,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "keyframe-easing",
|
||||
targetClass: "keyframe-easing",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -66,7 +66,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "both-easing",
|
||||
targetClass: "both-easing",
|
||||
properties: [
|
||||
{
|
||||
name: "margin-left",
|
||||
|
@ -99,7 +99,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "narrow-keyframes",
|
||||
targetClass: "narrow-keyframes",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -130,7 +130,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "duplicate-keyframes",
|
||||
targetClass: "duplicate-keyframes",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -162,7 +162,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "color-keyframes",
|
||||
targetClass: "color-keyframes",
|
||||
properties: [
|
||||
{
|
||||
name: "color",
|
||||
|
@ -191,26 +191,22 @@ const TEST_DATA = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_easings.html");
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { animationInspector, panel } = await openAnimationInspector();
|
||||
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
for (const { properties, targetClass } of TEST_DATA) {
|
||||
info(`Checking keyframes graph for ${ targetClass }`);
|
||||
await clickOnAnimationByTargetSelector(animationInspector,
|
||||
panel, `.${ targetClass }`);
|
||||
|
||||
for (const { properties, targetName } of TEST_DATA) {
|
||||
info(`Checking keyframes graph for ${ targetName }`);
|
||||
await selectNodeAndWaitForAnimations(`#${ targetName }`, inspector);
|
||||
|
||||
for (const property of properties) {
|
||||
const {
|
||||
name,
|
||||
expectedHints,
|
||||
} = property;
|
||||
|
||||
const testTarget = `${ name } in ${ targetName }`;
|
||||
for (const { name, expectedHints } of properties) {
|
||||
const testTarget = `${ name } in ${ targetClass }`;
|
||||
info(`Checking easing hint for ${ testTarget }`);
|
||||
info(`Checking easing hint existence for ${ testTarget }`);
|
||||
const hintEls = panel.querySelectorAll(`.${ name } .hint`);
|
||||
is(hintEls.length, expectedHints.length,
|
||||
`Count of easing hint elements of ${ testTarget } `
|
||||
+ `should be ${ expectedHints.length }`);
|
||||
`Count of easing hint elements of ${ testTarget } ` +
|
||||
`should be ${ expectedHints.length }`);
|
||||
|
||||
for (let i = 0; i < expectedHints.length; i++) {
|
||||
const hintTarget = `hint[${ i }] of ${ testTarget }`;
|
||||
|
@ -248,12 +244,12 @@ add_task(async function() {
|
|||
// Mouse out once from pathEl.
|
||||
EventUtils.synthesizeMouse(interactionEl, -1, -1, { type: "mouseout" }, win);
|
||||
is(win.getComputedStyle(interactionEl).strokeOpacity, 0,
|
||||
`stroke-opacity of hintEl for ${ hintTarget } should be 0`
|
||||
+ " while mouse is out from the element");
|
||||
`stroke-opacity of hintEl for ${ hintTarget } should be 0` +
|
||||
" while mouse is out from the element");
|
||||
// Mouse over the pathEl.
|
||||
ok(isStrokeChangedByMouseOver(interactionEl, win),
|
||||
`stroke-opacity of hintEl for ${ hintTarget } should be 1`
|
||||
+ " while mouse is over the element");
|
||||
`stroke-opacity of hintEl for ${ hintTarget } should be 1` +
|
||||
" while mouse is over the element");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetName: "multi-types",
|
||||
targetClass: "multi-types",
|
||||
properties: [
|
||||
{
|
||||
name: "background-color",
|
||||
|
@ -106,7 +106,7 @@ const TEST_DATA = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetName: "narrow-offsets",
|
||||
targetClass: "narrow-offsets",
|
||||
properties: [
|
||||
{
|
||||
name: "opacity",
|
||||
|
@ -135,26 +135,22 @@ const TEST_DATA = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_keyframes.html");
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { animationInspector, panel } = await openAnimationInspector();
|
||||
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
for (const { properties, targetClass } of TEST_DATA) {
|
||||
info(`Checking keyframe marker for ${ targetClass }`);
|
||||
await clickOnAnimationByTargetSelector(animationInspector,
|
||||
panel, `.${ targetClass }`);
|
||||
|
||||
for (const { properties, targetName } of TEST_DATA) {
|
||||
info(`Checking keyframe marker for ${ targetName }`);
|
||||
await selectNodeAndWaitForAnimations(`#${ targetName }`, inspector);
|
||||
|
||||
for (const property of properties) {
|
||||
const {
|
||||
name,
|
||||
expectedValues,
|
||||
} = property;
|
||||
|
||||
const testTarget = `${ name } in ${ targetName }`;
|
||||
for (const { name, expectedValues } of properties) {
|
||||
const testTarget = `${ name } in ${ targetClass }`;
|
||||
info(`Checking keyframe marker for ${ testTarget }`);
|
||||
info(`Checking keyframe marker existence for ${ testTarget }`);
|
||||
const markerEls = panel.querySelectorAll(`.${ name } .keyframe-marker-item`);
|
||||
is(markerEls.length, expectedValues.length,
|
||||
`Count of keyframe marker elements of ${ testTarget } `
|
||||
+ `should be ${ expectedValues.length }`);
|
||||
`Count of keyframe marker elements of ${ testTarget } ` +
|
||||
`should be ${ expectedValues.length }`);
|
||||
|
||||
for (let i = 0; i < expectedValues.length; i++) {
|
||||
const hintTarget = `.keyframe-marker-item[${ i }] of ${ testTarget }`;
|
||||
|
|
|
@ -9,46 +9,46 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
|
|||
// * progress bar position after changing playback rate
|
||||
// * progress bar position when select another animation
|
||||
|
||||
requestLongerTimeout(5);
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const POSITION_TESTCASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetClassName: "cssanimation-linear",
|
||||
targetClass: "cssanimation-linear",
|
||||
scrubberPositions: [0, 0.25, 0.5, 0.75, 1],
|
||||
expectedPositions: [0, 0.25, 0.5, 0.75, 0],
|
||||
},
|
||||
{
|
||||
targetClassName: "easing-step",
|
||||
targetClass: "easing-step",
|
||||
scrubberPositions: [0, 0.49, 0.5, 0.99],
|
||||
expectedPositions: [0, 0, 0.5, 0.5],
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-positive",
|
||||
targetClass: "delay-positive",
|
||||
scrubberPositions: [0, 0.33, 0.5],
|
||||
expectedPositions: [0, 0, 0.25],
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-negative",
|
||||
targetClass: "delay-negative",
|
||||
scrubberPositions: [0, 0.49, 0.5, 0.75],
|
||||
expectedPositions: [0, 0, 0.5, 0.75],
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-positive",
|
||||
targetClass: "enddelay-positive",
|
||||
scrubberPositions: [0, 0.66, 0.67, 0.99],
|
||||
expectedPositions: [0, 0.99, 0, 0],
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-negative",
|
||||
targetClass: "enddelay-negative",
|
||||
scrubberPositions: [0, 0.49, 0.5, 0.99],
|
||||
expectedPositions: [0, 0.49, 0, 0],
|
||||
},
|
||||
{
|
||||
targetClassName: "direction-reverse-with-iterations-infinity",
|
||||
targetClass: "direction-reverse-with-iterations-infinity",
|
||||
scrubberPositions: [0, 0.25, 0.5, 0.75, 1],
|
||||
expectedPositions: [1, 0.75, 0.5, 0.25, 1],
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-both-width-delay-iterationstart",
|
||||
targetClass: "fill-both-width-delay-iterationstart",
|
||||
scrubberPositions: [0, 0.33, 0.66, 0.833, 1],
|
||||
expectedPositions: [0.5, 0.5, 0.99, 0.25, 0.5],
|
||||
},
|
||||
|
@ -56,13 +56,20 @@ const POSITION_TESTCASES = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { animationInspector, inspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking progress bar position in multi effect timings");
|
||||
|
||||
for (const testcase of POSITION_TESTCASES) {
|
||||
info(`Checking progress bar position for ${ testcase.targetClassName }`);
|
||||
await selectNodeAndWaitForAnimations(`.${ testcase.targetClassName }`, inspector);
|
||||
for (const testdata of TEST_DATA) {
|
||||
const {
|
||||
targetClass,
|
||||
scrubberPositions,
|
||||
expectedPositions,
|
||||
} = testdata;
|
||||
|
||||
info(`Checking progress bar position for ${ targetClass }`);
|
||||
await selectNodeAndWaitForAnimations(`.${ targetClass }`, inspector);
|
||||
|
||||
info("Checking progress bar existence");
|
||||
const areaEl = panel.querySelector(".keyframes-progress-bar-area");
|
||||
|
@ -70,9 +77,6 @@ add_task(async function() {
|
|||
const barEl = areaEl.querySelector(".keyframes-progress-bar");
|
||||
ok(barEl, "progress bar should exist");
|
||||
|
||||
const scrubberPositions = testcase.scrubberPositions;
|
||||
const expectedPositions = testcase.expectedPositions;
|
||||
|
||||
for (let i = 0; i < scrubberPositions.length; i++) {
|
||||
info(`Scrubber position is ${ scrubberPositions[i] }`);
|
||||
await clickOnCurrentTimeScrubberController(animationInspector,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
await removeAnimatedElementsExcept([".compositor-all", ".long"]);
|
||||
const { animationInspector, inspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking state after end of animation duration");
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
await removeAnimatedElementsExcept(
|
||||
[".compositor-all", ".compositor-notall", ".no-compositor", ".still"]);
|
||||
const { animationInspector, inspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking the mutation for add an animation");
|
||||
|
|
|
@ -7,43 +7,38 @@
|
|||
// * element existance
|
||||
// * name text
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetClassName: "cssanimation-normal",
|
||||
targetClass: "cssanimation-normal",
|
||||
expectedLabel: "cssanimation",
|
||||
},
|
||||
{
|
||||
targetClassName: "cssanimation-linear",
|
||||
targetClass: "cssanimation-linear",
|
||||
expectedLabel: "cssanimation",
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-positive",
|
||||
targetClass: "delay-positive",
|
||||
expectedLabel: "test-delay-animation",
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-negative",
|
||||
targetClass: "delay-negative",
|
||||
expectedLabel: "test-negative-delay-animation",
|
||||
},
|
||||
{
|
||||
targetClassName: "easing-step",
|
||||
targetClass: "easing-step",
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
const {
|
||||
expectedLabel,
|
||||
targetClassName,
|
||||
} = testCase;
|
||||
|
||||
for (const { targetClass, expectedLabel } of TEST_DATA) {
|
||||
const animationItemEl =
|
||||
findAnimationItemElementsByTargetClassName(panel, targetClassName);
|
||||
findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
|
||||
|
||||
info(`Checking animation name element existance for ${ targetClassName }`);
|
||||
info(`Checking animation name element existance for ${ targetClass }`);
|
||||
const animationNameEl = animationItemEl.querySelector(".animation-name");
|
||||
|
||||
if (expectedLabel) {
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
|
||||
await removeAnimatedElementsExcept(
|
||||
[".compositor-all", ".compositor-notall", ".no-compositor"]);
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Select a test node we know has an animation running on the compositor");
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
// * fill: path
|
||||
// * endDelay: path
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetClassName: "cssanimation-normal",
|
||||
targetClass: "cssanimation-normal",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -25,7 +25,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "cssanimation-linear",
|
||||
targetClass: "cssanimation-linear",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -38,7 +38,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-positive",
|
||||
targetClass: "delay-positive",
|
||||
expectedDelayPath: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 500000, y: 0 },
|
||||
|
@ -55,7 +55,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-negative",
|
||||
targetClass: "delay-negative",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -67,7 +67,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "easing-step",
|
||||
targetClass: "easing-step",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -79,7 +79,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-positive",
|
||||
targetClass: "enddelay-positive",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -96,7 +96,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-negative",
|
||||
targetClass: "enddelay-negative",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -107,7 +107,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-with-fill-forwards",
|
||||
targetClass: "enddelay-with-fill-forwards",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -132,7 +132,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-with-iterations-infinity",
|
||||
targetClass: "enddelay-with-iterations-infinity",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -154,7 +154,7 @@ const TEST_CASES = [
|
|||
isInfinity: true,
|
||||
},
|
||||
{
|
||||
targetClassName: "direction-alternate-with-iterations-infinity",
|
||||
targetClass: "direction-alternate-with-iterations-infinity",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -176,7 +176,7 @@ const TEST_CASES = [
|
|||
isInfinity: true,
|
||||
},
|
||||
{
|
||||
targetClassName: "direction-alternate-reverse-with-iterations-infinity",
|
||||
targetClass: "direction-alternate-reverse-with-iterations-infinity",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -198,7 +198,7 @@ const TEST_CASES = [
|
|||
isInfinity: true,
|
||||
},
|
||||
{
|
||||
targetClassName: "direction-reverse-with-iterations-infinity",
|
||||
targetClass: "direction-reverse-with-iterations-infinity",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -220,7 +220,7 @@ const TEST_CASES = [
|
|||
isInfinity: true,
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-backwards",
|
||||
targetClass: "fill-backwards",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -233,7 +233,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-backwards-with-delay-iterationstart",
|
||||
targetClass: "fill-backwards-with-delay-iterationstart",
|
||||
expectedDelayPath: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 0, y: 50 },
|
||||
|
@ -256,7 +256,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-both",
|
||||
targetClass: "fill-both",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -275,7 +275,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-both-width-delay-iterationstart",
|
||||
targetClass: "fill-both-width-delay-iterationstart",
|
||||
expectedDelayPath: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 0, y: 50 },
|
||||
|
@ -302,7 +302,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-forwards",
|
||||
targetClass: "fill-forwards",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -321,7 +321,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "iterationstart",
|
||||
targetClass: "iterationstart",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 50 },
|
||||
|
@ -338,7 +338,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "no-compositor",
|
||||
targetClass: "no-compositor",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -351,7 +351,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "keyframes-easing-step",
|
||||
targetClass: "keyframes-easing-step",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -363,7 +363,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "narrow-keyframes",
|
||||
targetClass: "narrow-keyframes",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -377,7 +377,7 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "duplicate-offsets",
|
||||
targetClass: "duplicate-offsets",
|
||||
expectedIterationPathList: [
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
|
@ -391,29 +391,28 @@ const TEST_CASES = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
for (const testData of TEST_DATA) {
|
||||
const {
|
||||
expectedDelayPath,
|
||||
expectedEndDelayPath,
|
||||
expectedForwardsPath,
|
||||
expectedIterationPathList,
|
||||
isInfinity,
|
||||
targetClassName,
|
||||
} = testCase;
|
||||
targetClass,
|
||||
} = testData;
|
||||
|
||||
const animationItemEl =
|
||||
findAnimationItemElementsByTargetClassName(panel, targetClassName);
|
||||
findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
|
||||
|
||||
info(`Checking computed timing path existance for ${ targetClassName }`);
|
||||
info(`Checking computed timing path existance for ${ targetClass }`);
|
||||
const computedTimingPathEl =
|
||||
animationItemEl.querySelector(".animation-computed-timing-path");
|
||||
ok(computedTimingPathEl,
|
||||
"The computed timing path element should be in each animation item element");
|
||||
|
||||
info(`Checking delay path for ${ targetClassName }`);
|
||||
info(`Checking delay path for ${ targetClass }`);
|
||||
const delayPathEl = computedTimingPathEl.querySelector(".animation-delay-path");
|
||||
|
||||
if (expectedDelayPath) {
|
||||
|
@ -423,7 +422,7 @@ add_task(async function() {
|
|||
ok(!delayPathEl, "delay path should not be existance");
|
||||
}
|
||||
|
||||
info(`Checking iteration path list for ${ targetClassName }`);
|
||||
info(`Checking iteration path list for ${ targetClass }`);
|
||||
const iterationPathEls =
|
||||
computedTimingPathEl.querySelectorAll(".animation-iteration-path");
|
||||
is(iterationPathEls.length, expectedIterationPathList.length,
|
||||
|
@ -432,7 +431,7 @@ add_task(async function() {
|
|||
for (const [j, iterationPathEl] of iterationPathEls.entries()) {
|
||||
assertPathSegments(iterationPathEl, true, expectedIterationPathList[j]);
|
||||
|
||||
info(`Checking infinity ${ targetClassName }`);
|
||||
info(`Checking infinity ${ targetClass }`);
|
||||
if (isInfinity && j >= 1) {
|
||||
ok(iterationPathEl.classList.contains("infinity"),
|
||||
"iteration path should have 'infinity' class");
|
||||
|
@ -442,7 +441,7 @@ add_task(async function() {
|
|||
}
|
||||
}
|
||||
|
||||
info(`Checking endDelay path for ${ targetClassName }`);
|
||||
info(`Checking endDelay path for ${ targetClass }`);
|
||||
const endDelayPathEl = computedTimingPathEl.querySelector(".animation-enddelay-path");
|
||||
|
||||
if (expectedEndDelayPath) {
|
||||
|
@ -452,7 +451,7 @@ add_task(async function() {
|
|||
ok(!endDelayPathEl, "endDelay path should not be existance");
|
||||
}
|
||||
|
||||
info(`Checking forwards fill path for ${ targetClassName }`);
|
||||
info(`Checking forwards fill path for ${ targetClass }`);
|
||||
const forwardsPathEl =
|
||||
computedTimingPathEl.querySelector(".animation-fill-forwards-path");
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_simple_animation.html");
|
||||
await removeAnimatedElementsExcept([".animated", ".end-delay"]);
|
||||
const { inspector, panel } = await openAnimationInspector();
|
||||
|
||||
info("Checking the path for different time scale");
|
||||
|
@ -14,7 +15,7 @@ add_task(async function() {
|
|||
const pathStringA = panel.querySelector(".animation-iteration-path").getAttribute("d");
|
||||
|
||||
info("Select animation which has different time scale from no-compositor");
|
||||
await selectNodeAndWaitForAnimations("#endDelayed", inspector);
|
||||
await selectNodeAndWaitForAnimations(".end-delay", inspector);
|
||||
|
||||
info("Select no-compositor again");
|
||||
await selectNodeAndWaitForAnimations(".animated", inspector);
|
||||
|
|
|
@ -9,16 +9,16 @@
|
|||
// * width
|
||||
// * additinal class
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetClassName: "delay-positive",
|
||||
targetClass: "delay-positive",
|
||||
expectedResult: {
|
||||
left: "25%",
|
||||
width: "25%",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-negative",
|
||||
targetClass: "delay-negative",
|
||||
expectedResult: {
|
||||
additionalClass: "negative",
|
||||
left: "0%",
|
||||
|
@ -26,7 +26,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-backwards-with-delay-iterationstart",
|
||||
targetClass: "fill-backwards-with-delay-iterationstart",
|
||||
expectedResult: {
|
||||
additionalClass: "fill",
|
||||
left: "25%",
|
||||
|
@ -34,10 +34,10 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-both",
|
||||
targetClass: "fill-both",
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-both-width-delay-iterationstart",
|
||||
targetClass: "fill-both-width-delay-iterationstart",
|
||||
expectedResult: {
|
||||
additionalClass: "fill",
|
||||
left: "25%",
|
||||
|
@ -45,25 +45,20 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "keyframes-easing-step",
|
||||
targetClass: "keyframes-easing-step",
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
const {
|
||||
expectedResult,
|
||||
targetClassName,
|
||||
} = testCase;
|
||||
|
||||
for (const { targetClass, expectedResult } of TEST_DATA) {
|
||||
const animationItemEl =
|
||||
findAnimationItemElementsByTargetClassName(panel, targetClassName);
|
||||
findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
|
||||
|
||||
info(`Checking delay sign existance for ${ targetClassName }`);
|
||||
info(`Checking delay sign existance for ${ targetClass }`);
|
||||
const delaySignEl = animationItemEl.querySelector(".animation-delay-sign");
|
||||
|
||||
if (expectedResult) {
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
// * element existance
|
||||
// * path
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetClassName: "cssanimation-linear",
|
||||
targetClass: "cssanimation-linear",
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-negative",
|
||||
targetClass: "delay-negative",
|
||||
},
|
||||
{
|
||||
targetClassName: "easing-step",
|
||||
targetClass: "easing-step",
|
||||
expectedPath: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 499999, y: 0 },
|
||||
|
@ -25,25 +25,20 @@ const TEST_CASES = [
|
|||
],
|
||||
},
|
||||
{
|
||||
targetClassName: "keyframes-easing-step",
|
||||
targetClass: "keyframes-easing-step",
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
const {
|
||||
expectedPath,
|
||||
targetClassName,
|
||||
} = testCase;
|
||||
|
||||
for (const { targetClass, expectedPath } of TEST_DATA) {
|
||||
const animationItemEl =
|
||||
findAnimationItemElementsByTargetClassName(panel, targetClassName);
|
||||
findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
|
||||
|
||||
info(`Checking effect timing path existance for ${ targetClassName }`);
|
||||
info(`Checking effect timing path existance for ${ targetClass }`);
|
||||
const effectTimingPathEl =
|
||||
animationItemEl.querySelector(".animation-effect-timing-path");
|
||||
|
||||
|
|
|
@ -9,16 +9,16 @@
|
|||
// * width
|
||||
// * additinal class
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetClassName: "enddelay-positive",
|
||||
targetClass: "enddelay-positive",
|
||||
expectedResult: {
|
||||
left: "75%",
|
||||
width: "25%",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-negative",
|
||||
targetClass: "enddelay-negative",
|
||||
expectedResult: {
|
||||
additionalClass: "negative",
|
||||
left: "50%",
|
||||
|
@ -26,7 +26,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-with-fill-forwards",
|
||||
targetClass: "enddelay-with-fill-forwards",
|
||||
expectedResult: {
|
||||
additionalClass: "fill",
|
||||
left: "75%",
|
||||
|
@ -34,28 +34,23 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-with-iterations-infinity",
|
||||
targetClass: "enddelay-with-iterations-infinity",
|
||||
},
|
||||
{
|
||||
targetClassName: "keyframes-easing-step",
|
||||
targetClass: "delay-negative",
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
const {
|
||||
expectedResult,
|
||||
targetClassName,
|
||||
} = testCase;
|
||||
|
||||
for (const { targetClass, expectedResult } of TEST_DATA) {
|
||||
const animationItemEl =
|
||||
findAnimationItemElementsByTargetClassName(panel, targetClassName);
|
||||
findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
|
||||
|
||||
info(`Checking endDelay sign existance for ${ targetClassName }`);
|
||||
info(`Checking endDelay sign existance for ${ targetClass }`);
|
||||
const endDelaySignEl = animationItemEl.querySelector(".animation-end-delay-sign");
|
||||
|
||||
if (expectedResult) {
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
// * element existance
|
||||
// * path
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetClassName: "delay-positive",
|
||||
targetClass: "delay-positive",
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-negative",
|
||||
targetClass: "delay-negative",
|
||||
expectedPath: [
|
||||
{ x: -500000, y: 0 },
|
||||
{ x: -250000, y: 25 },
|
||||
|
@ -24,19 +24,14 @@ const TEST_CASES = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
const {
|
||||
expectedPath,
|
||||
targetClassName,
|
||||
} = testCase;
|
||||
|
||||
for (const { targetClass, expectedPath } of TEST_DATA) {
|
||||
const animationItemEl =
|
||||
findAnimationItemElementsByTargetClassName(panel, targetClassName);
|
||||
findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
|
||||
|
||||
info(`Checking negative delay path existence for ${ targetClassName }`);
|
||||
info(`Checking negative delay path existence for ${ targetClass }`);
|
||||
const negativeDelayPathEl =
|
||||
animationItemEl.querySelector(".animation-negative-delay-path");
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
// * element existance
|
||||
// * path
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetClassName: "enddelay-positive",
|
||||
targetClass: "enddelay-positive",
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-negative",
|
||||
targetClass: "enddelay-negative",
|
||||
expectedPath: [
|
||||
{ x: 500000, y: 0 },
|
||||
{ x: 500000, y: 50 },
|
||||
|
@ -25,19 +25,14 @@ const TEST_CASES = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
const {
|
||||
expectedPath,
|
||||
targetClassName,
|
||||
} = testCase;
|
||||
|
||||
for (const { targetClass, expectedPath } of TEST_DATA) {
|
||||
const animationItemEl =
|
||||
findAnimationItemElementsByTargetClassName(panel, targetClassName);
|
||||
findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
|
||||
|
||||
info(`Checking negative endDelay path existance for ${ targetClassName }`);
|
||||
info(`Checking negative endDelay path existance for ${ targetClass }`);
|
||||
const negativeEndDelayPathEl =
|
||||
animationItemEl.querySelector(".animation-negative-end-delay-path");
|
||||
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
|
||||
// Test for existance and content of tooltip on summary graph element.
|
||||
|
||||
const TEST_CASES = [
|
||||
const TEST_DATA = [
|
||||
{
|
||||
targetClassName: "cssanimation-normal",
|
||||
targetClass: "cssanimation-normal",
|
||||
expectedResult: {
|
||||
nameAndType: "cssanimation - CSS Animation",
|
||||
duration: "1,000s",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "cssanimation-linear",
|
||||
targetClass: "cssanimation-linear",
|
||||
expectedResult: {
|
||||
nameAndType: "cssanimation - CSS Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -22,7 +22,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-positive",
|
||||
targetClass: "delay-positive",
|
||||
expectedResult: {
|
||||
nameAndType: "test-delay-animation - Script Animation",
|
||||
delay: "500s",
|
||||
|
@ -30,7 +30,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "delay-negative",
|
||||
targetClass: "delay-negative",
|
||||
expectedResult: {
|
||||
nameAndType: "test-negative-delay-animation - Script Animation",
|
||||
delay: "-500s",
|
||||
|
@ -38,7 +38,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "easing-step",
|
||||
targetClass: "easing-step",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -46,7 +46,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-positive",
|
||||
targetClass: "enddelay-positive",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -54,7 +54,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-negative",
|
||||
targetClass: "enddelay-negative",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -62,7 +62,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-with-fill-forwards",
|
||||
targetClass: "enddelay-with-fill-forwards",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -71,7 +71,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "enddelay-with-iterations-infinity",
|
||||
targetClass: "enddelay-with-iterations-infinity",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -80,7 +80,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "direction-alternate-with-iterations-infinity",
|
||||
targetClass: "direction-alternate-with-iterations-infinity",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -89,7 +89,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "direction-alternate-reverse-with-iterations-infinity",
|
||||
targetClass: "direction-alternate-reverse-with-iterations-infinity",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -98,7 +98,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "direction-reverse-with-iterations-infinity",
|
||||
targetClass: "direction-reverse-with-iterations-infinity",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -107,7 +107,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-backwards",
|
||||
targetClass: "fill-backwards",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -115,7 +115,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-backwards-with-delay-iterationstart",
|
||||
targetClass: "fill-backwards-with-delay-iterationstart",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
delay: "500s",
|
||||
|
@ -125,7 +125,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-both",
|
||||
targetClass: "fill-both",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -133,7 +133,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-both-width-delay-iterationstart",
|
||||
targetClass: "fill-both-width-delay-iterationstart",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
delay: "500s",
|
||||
|
@ -143,7 +143,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "fill-forwards",
|
||||
targetClass: "fill-forwards",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -151,7 +151,7 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "iterationstart",
|
||||
targetClass: "iterationstart",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -159,14 +159,14 @@ const TEST_CASES = [
|
|||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "no-compositor",
|
||||
targetClass: "no-compositor",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetClassName: "keyframes-easing-step",
|
||||
targetClass: "keyframes-easing-step",
|
||||
expectedResult: {
|
||||
nameAndType: "Script Animation",
|
||||
duration: "1,000s",
|
||||
|
@ -176,20 +176,15 @@ const TEST_CASES = [
|
|||
|
||||
add_task(async function() {
|
||||
await addTab(URL_ROOT + "doc_multi_timings.html");
|
||||
|
||||
await removeAnimatedElementsExcept(TEST_DATA.map(t => `.${ t.targetClass }`));
|
||||
const { panel } = await openAnimationInspector();
|
||||
|
||||
for (const testCase of TEST_CASES) {
|
||||
const {
|
||||
expectedResult,
|
||||
targetClassName,
|
||||
} = testCase;
|
||||
|
||||
for (const { targetClass, expectedResult } of TEST_DATA) {
|
||||
const animationItemEl =
|
||||
findAnimationItemElementsByTargetClassName(panel, targetClassName);
|
||||
findAnimationItemElementsByTargetSelector(panel, `.${ targetClass }`);
|
||||
const summaryGraphEl = animationItemEl.querySelector(".animation-summary-graph");
|
||||
|
||||
info(`Checking tooltip for ${ targetClassName }`);
|
||||
info(`Checking tooltip for ${ targetClass }`);
|
||||
ok(summaryGraphEl.hasAttribute("title"),
|
||||
"Summary graph should have 'title' attribute");
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* globals addMessageListener, sendAsyncMessage */
|
||||
|
||||
"use strict";
|
||||
|
||||
// A helper frame-script for animation inspector.
|
||||
|
||||
addMessageListener("Test:RemoveAnimatedElementsExcept", function(msg) {
|
||||
const { selectors } = msg.data;
|
||||
|
||||
for (const animation of content.document.getAnimations()) {
|
||||
if (isRemovableElement(animation, selectors)) {
|
||||
animation.effect.target.remove();
|
||||
}
|
||||
}
|
||||
|
||||
sendAsyncMessage("Test:RemoveAnimatedElementsExcept");
|
||||
});
|
||||
|
||||
function isRemovableElement(animation, selectors) {
|
||||
for (const selector of selectors) {
|
||||
if (animation.effect.target.matches(selector)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
function createAnimation(name, keyframes, effectEasing) {
|
||||
const div = document.createElement("div");
|
||||
div.id = name;
|
||||
div.classList.add(name);
|
||||
document.body.appendChild(div);
|
||||
|
||||
const effect = {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
function createAnimation(name, keyframes, effectEasing) {
|
||||
const div = document.createElement("div");
|
||||
div.id = name;
|
||||
div.classList.add(name);
|
||||
document.body.appendChild(div);
|
||||
|
||||
const effect = {
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
<div class="ball long"></div>
|
||||
<div class="ball negative-delay"></div>
|
||||
<div class="ball no-compositor"></div>
|
||||
<div class="ball" id="endDelayed"></div>
|
||||
<div class="ball end-delay"></div>
|
||||
<div class="ball compositor-all"></div>
|
||||
<div class="ball compositor-notall"></div>
|
||||
<div class="ball longhand"></div>
|
||||
|
@ -162,12 +162,12 @@
|
|||
/* globals KeyframeEffect, Animation */
|
||||
"use strict";
|
||||
|
||||
var el = document.getElementById("endDelayed");
|
||||
let effect = new KeyframeEffect(el, [
|
||||
const el = document.querySelector(".end-delay");
|
||||
const effect = new KeyframeEffect(el, [
|
||||
{ opacity: 0, offset: 0 },
|
||||
{ opacity: 1, offset: 1 }
|
||||
], { duration: 1000000, endDelay: 500000, fill: "none" });
|
||||
let animation = new Animation(effect, document.timeline);
|
||||
const animation = new Animation(effect, document.timeline);
|
||||
animation.play();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -84,6 +84,16 @@ addTab = async function(url) {
|
|||
return tab;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove animated elements from document except given selectors.
|
||||
*
|
||||
* @param {Array} selectors
|
||||
* @return {Promise}
|
||||
*/
|
||||
const removeAnimatedElementsExcept = async function(selectors) {
|
||||
return executeInContent("Test:RemoveAnimatedElementsExcept", { selectors });
|
||||
};
|
||||
|
||||
/**
|
||||
* Click on an animation in the timeline to select it.
|
||||
*
|
||||
|
@ -96,14 +106,24 @@ addTab = async function(url) {
|
|||
const clickOnAnimation = async function(animationInspector, panel, index) {
|
||||
info("Click on animation " + index + " in the timeline");
|
||||
const summaryGraphEl = panel.querySelectorAll(".animation-summary-graph")[index];
|
||||
// Scroll to show the timeBlock since the element may be out of displayed area.
|
||||
summaryGraphEl.scrollIntoView(false);
|
||||
const bounds = summaryGraphEl.getBoundingClientRect();
|
||||
const x = bounds.width / 2;
|
||||
const y = bounds.height / 2;
|
||||
EventUtils.synthesizeMouse(summaryGraphEl, x, y, {}, summaryGraphEl.ownerGlobal);
|
||||
await clickOnSummaryGraph(animationInspector, panel, summaryGraphEl);
|
||||
};
|
||||
|
||||
await waitForAnimationDetail(animationInspector);
|
||||
/**
|
||||
* Click on an animation by given selector of node which is target element of animation.
|
||||
*
|
||||
* @param {AnimationInspector} animationInspector.
|
||||
* @param {AnimationsPanel} panel
|
||||
* The panel instance.
|
||||
* @param {String} selector
|
||||
* Selector of node which is target element of animation.
|
||||
*/
|
||||
const clickOnAnimationByTargetSelector = async function(animationInspector,
|
||||
panel, selector) {
|
||||
info(`Click on animation whose selector of target element is '${ selector }'`);
|
||||
const animationItemEl = findAnimationItemElementsByTargetSelector(panel, selector);
|
||||
const summaryGraphEl = animationItemEl.querySelector(".animation-summary-graph");
|
||||
await clickOnSummaryGraph(animationInspector, panel, summaryGraphEl);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -202,6 +222,25 @@ const clickOnPlaybackRateSelector = async function(animationInspector, panel, ra
|
|||
await waitForSummaryAndDetail(animationInspector);
|
||||
};
|
||||
|
||||
/**
|
||||
* Click on given summary graph element.
|
||||
*
|
||||
* @param {AnimationInspector} animationInspector
|
||||
* @param {AnimationsPanel} panel
|
||||
* @param {Element} summaryGraphEl
|
||||
*/
|
||||
const clickOnSummaryGraph = async function(animationInspector, panel, summaryGraphEl) {
|
||||
// Disable pointer-events of the scrubber in order to avoid to click accidently.
|
||||
const scrubberEl = panel.querySelector(".current-time-scrubber");
|
||||
scrubberEl.style.pointerEvents = "none";
|
||||
// Scroll to show the timeBlock since the element may be out of displayed area.
|
||||
summaryGraphEl.scrollIntoView(false);
|
||||
EventUtils.synthesizeMouseAtCenter(summaryGraphEl, {}, summaryGraphEl.ownerGlobal);
|
||||
await waitForAnimationDetail(animationInspector);
|
||||
// Restore the scrubber style.
|
||||
scrubberEl.style.pointerEvents = "unset";
|
||||
};
|
||||
|
||||
/**
|
||||
* Drag on the scrubber to update the animation current time.
|
||||
*
|
||||
|
@ -590,22 +629,21 @@ function isPassingThrough(pathSegList, x, y) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return animation item element by target node class.
|
||||
* This function compares betweem animation-target textContent and given className.
|
||||
* Also, this function premises one class name.
|
||||
* Return animation item element by target node selector.
|
||||
* This function compares betweem animation-target textContent and given selector.
|
||||
* Then returns matched first item.
|
||||
*
|
||||
* @param {Element} panel - root element of animation inspector.
|
||||
* @param {String} targetClassName - class name of tested element.
|
||||
* @param {String} selector - selector of tested element.
|
||||
* @return {Element} animation item element.
|
||||
*/
|
||||
function findAnimationItemElementsByTargetClassName(panel, targetClassName) {
|
||||
const animationTargetEls = panel.querySelectorAll(".animation-target");
|
||||
function findAnimationItemElementsByTargetSelector(panel, selector) {
|
||||
const attrNameEls = panel.querySelectorAll(".animation-target .attrName");
|
||||
const regexp = new RegExp(`\\${ selector }(\\.|$)`, "gi");
|
||||
|
||||
for (const animationTargetEl of animationTargetEls) {
|
||||
const className = animationTargetEl.textContent.split(".")[1];
|
||||
|
||||
if (className === targetClassName) {
|
||||
return animationTargetEl.closest(".animation-item");
|
||||
for (const attrNameEl of attrNameEls) {
|
||||
if (regexp.exec(attrNameEl.textContent)) {
|
||||
return attrNameEl.closest(".animation-item");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1750,6 +1750,7 @@ function RuleViewTool(inspector, window) {
|
|||
this.refresh = this.refresh.bind(this);
|
||||
this.onDetachedFront = this.onDetachedFront.bind(this);
|
||||
this.onPanelSelected = this.onPanelSelected.bind(this);
|
||||
this.onDetachedFront = this.onDetachedFront.bind(this);
|
||||
this.onSelected = this.onSelected.bind(this);
|
||||
this.onViewRefreshed = this.onViewRefreshed.bind(this);
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ const { gDevTools } = require("devtools/client/framework/devtools");
|
|||
/**
|
||||
* Opens given request in a new tab.
|
||||
*/
|
||||
function openRequestInTab(request) {
|
||||
function openRequestInTab(url, requestPostData) {
|
||||
let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
|
||||
let rawData = request.requestPostData ? request.requestPostData.postData : null;
|
||||
let rawData = requestPostData ? requestPostData.postData : null;
|
||||
let postData;
|
||||
|
||||
if (rawData && rawData.text) {
|
||||
|
@ -25,7 +25,7 @@ function openRequestInTab(request) {
|
|||
postData.setData(stringStream);
|
||||
}
|
||||
|
||||
win.gBrowser.selectedTab = win.gBrowser.addTab(request.url, null, null, postData);
|
||||
win.gBrowser.selectedTab = win.gBrowser.addTab(url, null, null, postData);
|
||||
}
|
||||
|
||||
function getInputStreamFromString(data) {
|
||||
|
|
|
@ -10,26 +10,23 @@ const { gDevTools } = require("devtools/client/framework/devtools");
|
|||
/**
|
||||
* Opens given request in a new tab.
|
||||
*/
|
||||
function openRequestInTab(request) {
|
||||
function openRequestInTab(url, requestPostData) {
|
||||
let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
|
||||
if (request.method.toLowerCase() !== "get") {
|
||||
win.openUILinkIn(this.selectedRequest.url, "tab", {
|
||||
relatedToCurrent: true
|
||||
});
|
||||
if (!requestPostData) {
|
||||
win.openUILinkIn(url, "tab", {relatedToCurrent: true});
|
||||
} else {
|
||||
openRequestInTabHelper({
|
||||
url: request.url,
|
||||
method: request.method,
|
||||
data: request.requestPostData ? request.requestPostData.postData : null,
|
||||
openPostRequestInTabHelper({
|
||||
url,
|
||||
data: requestPostData.postData
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function openRequestInTabHelper({url, method, data}) {
|
||||
function openPostRequestInTabHelper({url, data}) {
|
||||
let form = document.createElement("form");
|
||||
form.target = "_blank";
|
||||
form.action = url;
|
||||
form.method = method;
|
||||
form.method = "post";
|
||||
|
||||
if (data) {
|
||||
for (let key in data) {
|
||||
|
|
|
@ -194,7 +194,7 @@ class RequestListContextMenu {
|
|||
label: L10N.getStr("netmonitor.context.newTab"),
|
||||
accesskey: L10N.getStr("netmonitor.context.newTab.accesskey"),
|
||||
visible: !!selectedRequest,
|
||||
click: () => this.openRequestInTab(selectedRequest),
|
||||
click: () => this.openRequestInTab(id, url, requestPostData),
|
||||
});
|
||||
|
||||
menu.push({
|
||||
|
@ -229,8 +229,10 @@ class RequestListContextMenu {
|
|||
/**
|
||||
* Opens selected item in a new tab.
|
||||
*/
|
||||
openRequestInTab(selectedRequest) {
|
||||
openRequestInTab(selectedRequest);
|
||||
async openRequestInTab(id, url, requestPostData) {
|
||||
requestPostData = requestPostData ||
|
||||
await this.props.connector.requestData(id, "requestPostData");
|
||||
openRequestInTab(url, requestPostData);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,11 +40,13 @@ support-files =
|
|||
html_api-calls-test-page.html
|
||||
html_copy-as-curl.html
|
||||
html_curl-utils.html
|
||||
html_open-request-in-tab.html
|
||||
sjs_content-type-test-server.sjs
|
||||
sjs_cors-test-server.sjs
|
||||
sjs_https-redirect-test-server.sjs
|
||||
sjs_hsts-test-server.sjs
|
||||
sjs_json-test-server.sjs
|
||||
sjs_method-test-server.sjs
|
||||
sjs_simple-test-server.sjs
|
||||
sjs_simple-unsorted-cookies-test-server.sjs
|
||||
sjs_sorting-test-server.sjs
|
||||
|
|
|
@ -8,33 +8,69 @@
|
|||
*/
|
||||
|
||||
add_task(async function() {
|
||||
let { tab, monitor } = await initNetMonitor(CUSTOM_GET_URL);
|
||||
let { tab, monitor } = await initNetMonitor(OPEN_REQUEST_IN_TAB_URL);
|
||||
info("Starting test...");
|
||||
|
||||
let { document, store, windowRequire } = monitor.panelWin;
|
||||
let contextMenuDoc = monitor.panelWin.parent.document;
|
||||
let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
let newTab;
|
||||
|
||||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
// Execute requests.
|
||||
await performRequests(monitor, tab, 1);
|
||||
// Post data may be fetched by the Header panel,
|
||||
// so set the Timings panel as the new default.
|
||||
store.getState().ui.detailsPanelSelectedTab = "timings";
|
||||
|
||||
wait = waitForDOM(contextMenuDoc, "#request-list-context-newtab");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[0]);
|
||||
EventUtils.sendMouseEvent({ type: "contextmenu" },
|
||||
document.querySelectorAll(".request-list-item")[0]);
|
||||
// Open GET request in new tab
|
||||
await performRequest("GET");
|
||||
|
||||
newTab = await openLastRequestInTab();
|
||||
await checkTabResponse(newTab, "GET");
|
||||
|
||||
// Open POST request in new tab
|
||||
await performRequest("POST");
|
||||
newTab = await openLastRequestInTab();
|
||||
await checkTabResponse(newTab, "POST");
|
||||
|
||||
await teardown(monitor);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
async function openLastRequestInTab() {
|
||||
let wait = waitForDOM(contextMenuDoc, "#request-list-context-newtab");
|
||||
let requestItems = document.querySelectorAll(".request-list-item");
|
||||
let lastRequest = requestItems[requestItems.length - 1];
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, lastRequest);
|
||||
EventUtils.sendMouseEvent({ type: "contextmenu" }, lastRequest);
|
||||
await wait;
|
||||
|
||||
let onTabOpen = once(gBrowser.tabContainer, "TabOpen", false);
|
||||
monitor.panelWin.parent.document
|
||||
.querySelector("#request-list-context-newtab").click();
|
||||
await onTabOpen;
|
||||
|
||||
ok(true, "A new tab has been opened");
|
||||
|
||||
await teardown(monitor);
|
||||
let awaitedTab = gBrowser.selectedTab;
|
||||
await BrowserTestUtils.browserLoaded(awaitedTab.linkedBrowser);
|
||||
info("The tab load completed");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
return awaitedTab;
|
||||
}
|
||||
|
||||
async function performRequest(method) {
|
||||
let wait = waitForNetworkEvents(monitor, 1);
|
||||
await ContentTask.spawn(tab.linkedBrowser, method, async function(meth) {
|
||||
content.wrappedJSObject.performRequest(meth);
|
||||
});
|
||||
await wait;
|
||||
}
|
||||
|
||||
async function checkTabResponse(checkedTab, method) {
|
||||
await ContentTask.spawn(checkedTab.linkedBrowser, method, async function(met) {
|
||||
let { body } = content.wrappedJSObject.document;
|
||||
let responseRE = RegExp(met + (met == "POST" ? "\n*\s*foo\=bar\&baz\=42" : ""));
|
||||
ok(body.innerHTML.match(responseRE), "Tab method and data match original request");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -63,6 +63,7 @@ const CURL_UTILS_URL = EXAMPLE_URL + "html_curl-utils.html";
|
|||
const SEND_BEACON_URL = EXAMPLE_URL + "html_send-beacon.html";
|
||||
const CORS_URL = EXAMPLE_URL + "html_cors-test-page.html";
|
||||
const PAUSE_URL = EXAMPLE_URL + "html_pause-test-page.html";
|
||||
const OPEN_REQUEST_IN_TAB_URL = EXAMPLE_URL + "html_open-request-in-tab.html";
|
||||
|
||||
const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs";
|
||||
const SIMPLE_UNSORTED_COOKIES_SJS = EXAMPLE_URL + "sjs_simple-unsorted-cookies-test-server.sjs";
|
||||
|
@ -73,6 +74,7 @@ const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
|
|||
const HTTPS_REDIRECT_SJS = EXAMPLE_URL + "sjs_https-redirect-test-server.sjs";
|
||||
const CORS_SJS_PATH = "/browser/devtools/client/netmonitor/test/sjs_cors-test-server.sjs";
|
||||
const HSTS_SJS = EXAMPLE_URL + "sjs_hsts-test-server.sjs";
|
||||
const METHOD_SJS = EXAMPLE_URL + "sjs_method-test-server.sjs";
|
||||
|
||||
const HSTS_BASE_URL = EXAMPLE_URL;
|
||||
const HSTS_PAGE_URL = CUSTOM_GET_URL;
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<title>Network Monitor test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Performing a GET or POST request</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
/* exported performRequest */
|
||||
"use strict";
|
||||
|
||||
function performRequest(method) {
|
||||
let xhr = new XMLHttpRequest();
|
||||
let url = "sjs_method-test-server.sjs";
|
||||
let payload = method == "POST" ? "foo=bar&baz=42" : null;
|
||||
xhr.open(method, url, true);
|
||||
xhr.setRequestHeader("Accept-Language", window.navigator.language);
|
||||
xhr.send(payload);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -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/. */
|
||||
|
||||
const CC = Components.Constructor;
|
||||
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream",
|
||||
"setInputStream");
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "Och Aye");
|
||||
response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
|
||||
|
||||
var body = request.method + "\n" ;
|
||||
if (request.method == "POST") {
|
||||
var bodyStream = new BinaryInputStream(request.bodyInputStream);
|
||||
var bytes = [], avail = 0;
|
||||
while ((avail = bodyStream.available()) > 0) {
|
||||
body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
|
||||
}
|
||||
}
|
||||
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
|
@ -1212,7 +1212,7 @@ function SymbolIteratorActor(objectActor) {
|
|||
const symbol = symbols[index];
|
||||
return {
|
||||
name: symbol.toString(),
|
||||
descriptor: objectActor._propertyDescriptor(symbol, true)
|
||||
descriptor: objectActor._propertyDescriptor(symbol)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* eslint-disable no-shadow, max-nested-callbacks */
|
||||
|
||||
"use strict";
|
||||
|
||||
var gDebuggee;
|
||||
var gThreadClient;
|
||||
|
||||
add_task(async function run_test() {
|
||||
await run_test_with_server(DebuggerServer);
|
||||
await run_test_with_server(WorkerDebuggerServer);
|
||||
});
|
||||
|
||||
async function run_test_with_server(server) {
|
||||
initTestDebuggerServer(server);
|
||||
let title = "test_enum_symbols";
|
||||
gDebuggee = addTestGlobal(title, server);
|
||||
gDebuggee.eval(function stopMe(arg) {
|
||||
debugger;
|
||||
}.toString());
|
||||
let client = new DebuggerClient(server.connectPipe());
|
||||
await client.connect();
|
||||
[,, gThreadClient] = await attachTestTabAndResume(client, title);
|
||||
await test_enum_symbols();
|
||||
await client.close();
|
||||
}
|
||||
|
||||
async function test_enum_symbols() {
|
||||
await new Promise(function(resolve) {
|
||||
gThreadClient.addOneTimeListener("paused", async function(event, packet) {
|
||||
let [grip] = packet.frame.arguments;
|
||||
let objClient = gThreadClient.pauseGrip(grip);
|
||||
let {iterator} = await objClient.enumSymbols();
|
||||
let {ownSymbols} = await iterator.slice(0, iterator.count);
|
||||
|
||||
strictEqual(ownSymbols.length, 1, "There is 1 symbol property.");
|
||||
let {name, descriptor} = ownSymbols[0];
|
||||
strictEqual(name, "Symbol(sym)", "Got right symbol name.");
|
||||
deepEqual(descriptor, {
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
value: 1,
|
||||
}, "Got right property descriptor.");
|
||||
|
||||
await gThreadClient.resume();
|
||||
resolve();
|
||||
});
|
||||
gDebuggee.eval(`stopMe(Object.defineProperty({}, Symbol("sym"), {value: 1}));`);
|
||||
});
|
||||
}
|
|
@ -174,6 +174,7 @@ reason = bug 1104838
|
|||
[test_objectgrips-19.js]
|
||||
[test_objectgrips-20.js]
|
||||
[test_objectgrips-21.js]
|
||||
[test_objectgrips-22.js]
|
||||
[test_objectgrips-array-like-object.js]
|
||||
[test_promise_state-01.js]
|
||||
[test_promise_state-02.js]
|
||||
|
|
|
@ -682,8 +682,10 @@ CustomElementRegistry::Define(const nsAString& aName,
|
|||
* 2. If name is not a valid custom element name, then throw a "SyntaxError"
|
||||
* DOMException and abort these steps.
|
||||
*/
|
||||
nsIDocument* doc = mWindow->GetExtantDoc();
|
||||
uint32_t nameSpaceID = doc ? doc->GetDefaultNamespaceID() : kNameSpaceID_XHTML;
|
||||
RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
|
||||
if (!nsContentUtils::IsCustomElementName(nameAtom)) {
|
||||
if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
|
@ -725,7 +727,7 @@ CustomElementRegistry::Define(const nsAString& aName,
|
|||
nsAutoString localName(aName);
|
||||
if (aOptions.mExtends.WasPassed()) {
|
||||
RefPtr<nsAtom> extendsAtom(NS_Atomize(aOptions.mExtends.Value()));
|
||||
if (nsContentUtils::IsCustomElementName(extendsAtom)) {
|
||||
if (nsContentUtils::IsCustomElementName(extendsAtom, nameSpaceID)) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
@ -965,7 +967,9 @@ CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
|
||||
if (!nsContentUtils::IsCustomElementName(nameAtom)) {
|
||||
nsIDocument* doc = mWindow->GetExtantDoc();
|
||||
uint32_t nameSpaceID = doc ? doc->GetDefaultNamespaceID() : kNameSpaceID_XHTML;
|
||||
if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
|
|
@ -1196,7 +1196,7 @@ Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError)
|
|||
* then throw a "NotSupportedError" DOMException.
|
||||
*/
|
||||
nsAtom* nameAtom = NodeInfo()->NameAtom();
|
||||
if (!(nsContentUtils::IsCustomElementName(nameAtom) ||
|
||||
if (!(nsContentUtils::IsCustomElementName(nameAtom, NodeInfo()->NamespaceID()) ||
|
||||
nameAtom == nsGkAtoms::article ||
|
||||
nameAtom == nsGkAtoms::aside ||
|
||||
nameAtom == nsGkAtoms::blockquote ||
|
||||
|
@ -4308,7 +4308,7 @@ Element::SetCustomElementData(CustomElementData* aData)
|
|||
#if DEBUG
|
||||
nsAtom* name = NodeInfo()->NameAtom();
|
||||
nsAtom* type = aData->GetCustomElementType();
|
||||
if (nsContentUtils::IsCustomElementName(name)) {
|
||||
if (nsContentUtils::IsCustomElementName(name, NodeInfo()->NamespaceID())) {
|
||||
MOZ_ASSERT(type == name);
|
||||
} else {
|
||||
MOZ_ASSERT(type != name);
|
||||
|
|
|
@ -77,9 +77,11 @@ private:
|
|||
void AddString(DataTransfer* aDataTransfer,
|
||||
const nsAString& aFlavor,
|
||||
const nsAString& aData,
|
||||
nsIPrincipal* aPrincipal);
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aHidden=false);
|
||||
nsresult AddStringsToDataTransfer(nsIContent* aDragNode,
|
||||
DataTransfer* aDataTransfer);
|
||||
nsresult GetImageData(imgIContainer* aImage, imgIRequest* aRequest);
|
||||
static nsresult GetDraggableSelectionData(nsISelection* inSelection,
|
||||
nsIContent* inRealTargetNode,
|
||||
nsIContent **outImageOrLinkNode,
|
||||
|
@ -99,6 +101,9 @@ private:
|
|||
nsString mUrlString;
|
||||
nsString mImageSourceString;
|
||||
nsString mImageDestFileName;
|
||||
#if defined (XP_MACOSX)
|
||||
nsString mImageRequestMime;
|
||||
#endif
|
||||
nsString mTitleString;
|
||||
// will be filled automatically if you fill urlstring
|
||||
nsString mHtmlString;
|
||||
|
@ -138,22 +143,16 @@ NS_IMPL_ISUPPORTS(nsContentAreaDragDropDataProvider, nsIFlavorDataProvider)
|
|||
// used on platforms where it's possible to drag items (e.g. images)
|
||||
// into the file system
|
||||
nsresult
|
||||
nsContentAreaDragDropDataProvider::SaveURIToFile(nsAString& inSourceURIString,
|
||||
nsContentAreaDragDropDataProvider::SaveURIToFile(nsIURI* inSourceURI,
|
||||
nsIFile* inDestFile,
|
||||
bool isPrivate)
|
||||
{
|
||||
nsCOMPtr<nsIURI> sourceURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(sourceURI), inSourceURIString);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(sourceURI);
|
||||
nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(inSourceURI);
|
||||
if (!sourceURL) {
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
rv = inDestFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
nsresult rv = inDestFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// we rely on the fact that the WPB is refcounted by the channel etc,
|
||||
|
@ -166,12 +165,56 @@ nsContentAreaDragDropDataProvider::SaveURIToFile(nsAString& inSourceURIString,
|
|||
persist->SetPersistFlags(nsIWebBrowserPersist::PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION);
|
||||
|
||||
// referrer policy can be anything since the referrer is nullptr
|
||||
return persist->SavePrivacyAwareURI(sourceURI, nullptr, nullptr,
|
||||
return persist->SavePrivacyAwareURI(inSourceURI, nullptr, nullptr,
|
||||
mozilla::net::RP_Unset,
|
||||
nullptr, nullptr,
|
||||
inDestFile, isPrivate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the provided filename extension is valid for the MIME type and
|
||||
* return the MIME type's primary extension.
|
||||
*
|
||||
* @param aExtension [in] the extension to check
|
||||
* @param aMimeType [in] the MIME type to check the extension with
|
||||
* @param aIsValidExtension [out] true if |aExtension| is valid for
|
||||
* |aMimeType|
|
||||
* @param aPrimaryExtension [out] the primary extension for the MIME type
|
||||
* to potentially be used as a replacement
|
||||
* for |aExtension|
|
||||
*/
|
||||
nsresult
|
||||
CheckAndGetExtensionForMime(const nsCString& aExtension,
|
||||
const nsCString& aMimeType,
|
||||
bool* aIsValidExtension,
|
||||
nsACString* aPrimaryExtension)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1");
|
||||
if (NS_WARN_IF(!mimeService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||
rv = mimeService->GetFromTypeAndExtension(aMimeType, EmptyCString(),
|
||||
getter_AddRefs(mimeInfo));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mimeInfo->GetPrimaryExtension(*aPrimaryExtension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aExtension.IsEmpty()) {
|
||||
*aIsValidExtension = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = mimeInfo->ExtensionExists(aExtension, aIsValidExtension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This is our nsIFlavorDataProvider callback. There are several
|
||||
// assumptions here that make this work:
|
||||
//
|
||||
|
@ -214,6 +257,10 @@ nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable *aTransferable,
|
|||
if (sourceURLString.IsEmpty())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIURI> sourceURI;
|
||||
rv = NS_NewURI(getter_AddRefs(sourceURI), sourceURLString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aTransferable->GetTransferData(kFilePromiseDestFilename,
|
||||
getter_AddRefs(tmp), &dataSize);
|
||||
supportsString = do_QueryInterface(tmp);
|
||||
|
@ -225,6 +272,60 @@ nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable *aTransferable,
|
|||
if (targetFilename.IsEmpty())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
// Use the image request's MIME type to ensure the filename's
|
||||
// extension is compatible with the OS's handler for this type.
|
||||
// If it isn't, or is missing, replace the extension with the
|
||||
// primary extension. On Mac, do this in the parent process
|
||||
// because sandboxing blocks access to MIME-handler info from
|
||||
// content processes.
|
||||
if (XRE_IsParentProcess()) {
|
||||
aTransferable->GetTransferData(kImageRequestMime,
|
||||
getter_AddRefs(tmp), &dataSize);
|
||||
supportsString = do_QueryInterface(tmp);
|
||||
if (!supportsString)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoString imageRequestMime;
|
||||
supportsString->GetData(imageRequestMime);
|
||||
|
||||
// If we have a MIME type, check the extension is compatible
|
||||
if (!imageRequestMime.IsEmpty()) {
|
||||
// Build a URL to get the filename extension
|
||||
nsCOMPtr<nsIURL> imageURL = do_QueryInterface(sourceURI, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString extension;
|
||||
rv = imageURL->GetFileExtension(extension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ConvertUTF16toUTF8 mimeCString(imageRequestMime);
|
||||
bool isValidExtension;
|
||||
nsAutoCString primaryExtension;
|
||||
rv = CheckAndGetExtensionForMime(extension,
|
||||
mimeCString,
|
||||
&isValidExtension,
|
||||
&primaryExtension);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!isValidExtension) {
|
||||
// The filename extension is missing or incompatible
|
||||
// with the MIME type, replace it with the primary
|
||||
// extension.
|
||||
nsAutoCString newFileName;
|
||||
rv = imageURL->GetFileBaseName(newFileName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
newFileName.Append(".");
|
||||
newFileName.Append(primaryExtension);
|
||||
targetFilename = NS_ConvertUTF8toUTF16(newFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
// make the filename safe for the filesystem
|
||||
targetFilename.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS,
|
||||
'-');
|
||||
#endif /* defined(XP_MACOSX) */
|
||||
|
||||
// get the target directory from the kFilePromiseDirectoryMime
|
||||
// flavor
|
||||
nsCOMPtr<nsISupports> dirPrimitive;
|
||||
|
@ -244,7 +345,7 @@ nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable *aTransferable,
|
|||
bool isPrivate;
|
||||
aTransferable->GetIsPrivateData(&isPrivate);
|
||||
|
||||
rv = SaveURIToFile(sourceURLString, file, isPrivate);
|
||||
rv = SaveURIToFile(sourceURI, file, isPrivate);
|
||||
// send back an nsIFile
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
CallQueryInterface(file, aData);
|
||||
|
@ -362,6 +463,80 @@ DragDataProducer::GetNodeString(nsIContent* inNode,
|
|||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
DragDataProducer::GetImageData(imgIContainer* aImage, imgIRequest* aRequest)
|
||||
{
|
||||
nsCOMPtr<nsIURI> imgUri;
|
||||
aRequest->GetURI(getter_AddRefs(imgUri));
|
||||
|
||||
nsCOMPtr<nsIURL> imgUrl(do_QueryInterface(imgUri));
|
||||
if (imgUrl) {
|
||||
nsAutoCString spec;
|
||||
nsresult rv = imgUrl->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// pass out the image source string
|
||||
CopyUTF8toUTF16(spec, mImageSourceString);
|
||||
|
||||
nsCString mimeType;
|
||||
aRequest->GetMimeType(getter_Copies(mimeType));
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
// Save the MIME type so we can make sure the extension
|
||||
// is compatible (and replace it if it isn't) when the
|
||||
// image is dropped. On Mac, we need to get the OS MIME
|
||||
// handler information in the parent due to sandboxing.
|
||||
CopyUTF8toUTF16(mimeType, mImageRequestMime);
|
||||
#else
|
||||
nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1");
|
||||
if (NS_WARN_IF(!mimeService)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||
mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
|
||||
getter_AddRefs(mimeInfo));
|
||||
if (mimeInfo) {
|
||||
nsAutoCString extension;
|
||||
imgUrl->GetFileExtension(extension);
|
||||
|
||||
bool validExtension;
|
||||
if (extension.IsEmpty() ||
|
||||
NS_FAILED(mimeInfo->ExtensionExists(extension,
|
||||
&validExtension)) ||
|
||||
!validExtension) {
|
||||
// Fix the file extension in the URL
|
||||
nsAutoCString primaryExtension;
|
||||
mimeInfo->GetPrimaryExtension(primaryExtension);
|
||||
|
||||
rv = NS_MutateURI(imgUrl)
|
||||
.Apply(NS_MutatorMethod(&nsIURLMutator::SetFileExtension,
|
||||
primaryExtension, nullptr))
|
||||
.Finalize(imgUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
#endif /* defined(XP_MACOSX) */
|
||||
|
||||
nsAutoCString fileName;
|
||||
imgUrl->GetFileName(fileName);
|
||||
|
||||
NS_UnescapeURL(fileName);
|
||||
|
||||
#if !defined(XP_MACOSX)
|
||||
// make the filename safe for the filesystem
|
||||
fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
|
||||
#endif
|
||||
|
||||
CopyUTF8toUTF16(fileName, mImageDestFileName);
|
||||
|
||||
// and the image object
|
||||
mImage = aImage;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DragDataProducer::Produce(DataTransfer* aDataTransfer,
|
||||
bool* aCanDrag,
|
||||
|
@ -564,67 +739,9 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer,
|
|||
nsCOMPtr<imgIContainer> img =
|
||||
nsContentUtils::GetImageFromContent(image,
|
||||
getter_AddRefs(imgRequest));
|
||||
|
||||
nsCOMPtr<nsIMIMEService> mimeService =
|
||||
do_GetService("@mozilla.org/mime;1");
|
||||
|
||||
// Fix the file extension in the URL if necessary
|
||||
if (imgRequest && mimeService) {
|
||||
nsCOMPtr<nsIURI> imgUri;
|
||||
imgRequest->GetURI(getter_AddRefs(imgUri));
|
||||
|
||||
nsCOMPtr<nsIURL> imgUrl(do_QueryInterface(imgUri));
|
||||
|
||||
if (imgUrl) {
|
||||
nsAutoCString extension;
|
||||
imgUrl->GetFileExtension(extension);
|
||||
|
||||
nsCString mimeType;
|
||||
imgRequest->GetMimeType(getter_Copies(mimeType));
|
||||
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||
mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
|
||||
getter_AddRefs(mimeInfo));
|
||||
|
||||
if (mimeInfo) {
|
||||
nsAutoCString spec;
|
||||
rv = imgUrl->GetSpec(spec);
|
||||
if (imgRequest) {
|
||||
rv = GetImageData(img, imgRequest);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// pass out the image source string
|
||||
CopyUTF8toUTF16(spec, mImageSourceString);
|
||||
|
||||
bool validExtension;
|
||||
if (extension.IsEmpty() ||
|
||||
NS_FAILED(mimeInfo->ExtensionExists(extension,
|
||||
&validExtension)) ||
|
||||
!validExtension) {
|
||||
// Fix the file extension in the URL
|
||||
nsAutoCString primaryExtension;
|
||||
mimeInfo->GetPrimaryExtension(primaryExtension);
|
||||
|
||||
rv = NS_MutateURI(imgUrl)
|
||||
.Apply(NS_MutatorMethod(&nsIURLMutator::SetFileExtension,
|
||||
primaryExtension, nullptr))
|
||||
.Finalize(imgUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsAutoCString fileName;
|
||||
imgUrl->GetFileName(fileName);
|
||||
|
||||
NS_UnescapeURL(fileName);
|
||||
|
||||
// make the filename safe for the filesystem
|
||||
fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS,
|
||||
'-');
|
||||
|
||||
CopyUTF8toUTF16(fileName, mImageDestFileName);
|
||||
|
||||
// and the image object
|
||||
mImage = img;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parentLink) {
|
||||
|
@ -730,11 +847,12 @@ void
|
|||
DragDataProducer::AddString(DataTransfer* aDataTransfer,
|
||||
const nsAString& aFlavor,
|
||||
const nsAString& aData,
|
||||
nsIPrincipal* aPrincipal)
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aHidden)
|
||||
{
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
variant->SetAsAString(aData);
|
||||
aDataTransfer->SetDataWithPrincipal(aFlavor, variant, 0, aPrincipal);
|
||||
aDataTransfer->SetDataWithPrincipal(aFlavor, variant, 0, aPrincipal, aHidden);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -810,6 +928,10 @@ DragDataProducer::AddStringsToDataTransfer(nsIContent* aDragNode,
|
|||
mImageSourceString, principal);
|
||||
AddString(aDataTransfer, NS_LITERAL_STRING(kFilePromiseDestFilename),
|
||||
mImageDestFileName, principal);
|
||||
#if defined(XP_MACOSX)
|
||||
AddString(aDataTransfer, NS_LITERAL_STRING(kImageRequestMime),
|
||||
mImageRequestMime, principal, /* aHidden= */ true);
|
||||
#endif
|
||||
|
||||
// if not an anchor, add the image url
|
||||
if (!mIsAnchor) {
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFLAVORDATAPROVIDER
|
||||
|
||||
nsresult SaveURIToFile(nsAString& inSourceURIString,
|
||||
nsresult SaveURIToFile(nsIURI* inSourceURI,
|
||||
nsIFile* inDestFile, bool isPrivate);
|
||||
};
|
||||
|
||||
|
|
|
@ -3194,8 +3194,13 @@ nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult,
|
|||
|
||||
// static
|
||||
bool
|
||||
nsContentUtils::IsCustomElementName(nsAtom* aName)
|
||||
nsContentUtils::IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID)
|
||||
{
|
||||
// Allow non-dashed names in XUL for XBL to Custom Element migrations.
|
||||
if (aNameSpaceID == kNameSpaceID_XUL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// A valid custom element name is a sequence of characters name which
|
||||
// must match the PotentialCustomElementName production:
|
||||
// PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)*
|
||||
|
@ -5091,7 +5096,8 @@ nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer,
|
|||
// If this is a chrome-privileged document, create a fragment first, and
|
||||
// sanitize it before insertion.
|
||||
RefPtr<DocumentFragment> fragment;
|
||||
if (aSanitize != NeverSanitize && !aTargetNode->OwnerDoc()->AllowUnsafeHTML()) {
|
||||
if (aSanitize != NeverSanitize &&
|
||||
IsSystemPrincipal(aTargetNode->NodePrincipal())) {
|
||||
fragment = new DocumentFragment(aTargetNode->OwnerDoc()->NodeInfoManager());
|
||||
target = fragment;
|
||||
}
|
||||
|
@ -5198,7 +5204,8 @@ nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
|
|||
|
||||
// If this is a chrome-privileged document, sanitize the fragment before
|
||||
// returning.
|
||||
if (aSanitize != NeverSanitize && !aDocument->AllowUnsafeHTML()) {
|
||||
if (aSanitize != NeverSanitize &&
|
||||
IsSystemPrincipal(aDocument->NodePrincipal())) {
|
||||
// Don't fire mutation events for nodes removed by the sanitizer.
|
||||
nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
|
||||
|
||||
|
@ -9984,9 +9991,9 @@ nsContentUtils::NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* a
|
|||
if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
|
||||
tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
|
||||
isCustomElementName = (tag == eHTMLTag_userdefined &&
|
||||
nsContentUtils::IsCustomElementName(name));
|
||||
nsContentUtils::IsCustomElementName(name, kNameSpaceID_XHTML));
|
||||
} else {
|
||||
isCustomElementName = nsContentUtils::IsCustomElementName(name);
|
||||
isCustomElementName = nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL);
|
||||
}
|
||||
|
||||
RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
|
||||
|
|
|
@ -710,7 +710,7 @@ public:
|
|||
* Returns true if |aName| is a valid name to be registered via
|
||||
* customElements.define.
|
||||
*/
|
||||
static bool IsCustomElementName(nsAtom* aName);
|
||||
static bool IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID);
|
||||
|
||||
static nsresult CheckQName(const nsAString& aQualifiedName,
|
||||
bool aNamespaceAware = true,
|
||||
|
|
|
@ -1434,7 +1434,6 @@ nsIDocument::nsIDocument()
|
|||
mEncodingMenuDisabled(false),
|
||||
mIsShadowDOMEnabled(false),
|
||||
mIsSVGGlyphsDocument(false),
|
||||
mAllowUnsafeHTML(false),
|
||||
mInDestructor(false),
|
||||
mIsGoingAway(false),
|
||||
mInXBLUpdate(false),
|
||||
|
@ -5862,13 +5861,6 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
|
|||
return attribute.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
nsIDocument::AllowUnsafeHTML() const
|
||||
{
|
||||
return (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) ||
|
||||
mAllowUnsafeHTML);
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::ResolveScheduledSVGPresAttrs()
|
||||
{
|
||||
|
|
|
@ -3211,8 +3211,6 @@ public:
|
|||
CreateAttributeNS(const nsAString& aNamespaceURI,
|
||||
const nsAString& aQualifiedName,
|
||||
mozilla::ErrorResult& rv);
|
||||
void SetAllowUnsafeHTML(bool aAllow) { mAllowUnsafeHTML = aAllow; }
|
||||
bool AllowUnsafeHTML() const;
|
||||
void GetInputEncoding(nsAString& aInputEncoding) const;
|
||||
already_AddRefed<mozilla::dom::Location> GetLocation() const;
|
||||
void GetReferrer(nsAString& aReferrer) const;
|
||||
|
@ -4044,10 +4042,6 @@ protected:
|
|||
// True if this document is for an SVG-in-OpenType font.
|
||||
bool mIsSVGGlyphsDocument : 1;
|
||||
|
||||
// True if unsafe HTML fragments should be allowed in chrome-privileged
|
||||
// documents.
|
||||
bool mAllowUnsafeHTML : 1;
|
||||
|
||||
// True if the document is being destroyed.
|
||||
bool mInDestructor: 1;
|
||||
|
||||
|
|
|
@ -898,7 +898,7 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
|
|||
kPNGImageMime, kJPEGImageMime, kGIFImageMime, kNativeImageMime,
|
||||
kFileMime, kFilePromiseMime, kFilePromiseURLMime,
|
||||
kFilePromiseDestFilename, kFilePromiseDirectoryMime,
|
||||
kMozTextInternal, kHTMLContext, kHTMLInfo };
|
||||
kMozTextInternal, kHTMLContext, kHTMLInfo, kImageRequestMime };
|
||||
|
||||
/*
|
||||
* Two passes are made here to iterate over all of the types. First, look for
|
||||
|
@ -1202,7 +1202,8 @@ nsresult
|
|||
DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
|
||||
nsIVariant* aData,
|
||||
uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal)
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aHidden)
|
||||
{
|
||||
nsAutoString format;
|
||||
GetRealFormat(aFormat, format);
|
||||
|
@ -1211,7 +1212,7 @@ DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
|
|||
RefPtr<DataTransferItem> item =
|
||||
mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal,
|
||||
/* aInsertOnly = */ false,
|
||||
/* aHidden= */ false,
|
||||
aHidden,
|
||||
rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
|
|
@ -374,7 +374,8 @@ public:
|
|||
nsresult SetDataWithPrincipal(const nsAString& aFormat,
|
||||
nsIVariant* aData,
|
||||
uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal);
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aHidden=false);
|
||||
|
||||
// Variation of SetDataWithPrincipal with handles extracting
|
||||
// kCustomTypesMime data into separate types.
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
// troubleshooting in the field and testing.
|
||||
#define PREF_CUBEB_FORCE_SAMPLE_RATE "media.cubeb.force_sample_rate"
|
||||
#define PREF_CUBEB_LOGGING_LEVEL "media.cubeb.logging_level"
|
||||
// Hidden pref used by tests to force failure to obtain cubeb context
|
||||
#define PREF_CUBEB_FORCE_NULL_CONTEXT "media.cubeb.force_null_context"
|
||||
#define PREF_CUBEB_SANDBOX "media.cubeb.sandbox"
|
||||
#define PREF_AUDIOIPC_POOL_SIZE "media.audioipc.pool_size"
|
||||
#define PREF_AUDIOIPC_STACK_SIZE "media.audioipc.stack_size"
|
||||
|
@ -127,6 +129,7 @@ uint32_t sCubebForcedSampleRate = 0;
|
|||
bool sCubebPlaybackLatencyPrefSet = false;
|
||||
bool sCubebMSGLatencyPrefSet = false;
|
||||
bool sAudioStreamInitEverSucceeded = false;
|
||||
bool sCubebForceNullContext = false;
|
||||
#ifdef MOZ_CUBEB_REMOTING
|
||||
bool sCubebSandbox = false;
|
||||
size_t sAudioIPCPoolSize;
|
||||
|
@ -235,6 +238,11 @@ void PrefChanged(const char* aPref, void* aClosure)
|
|||
PodCopy(sCubebBackendName.get(), value.get(), value.Length());
|
||||
sCubebBackendName[value.Length()] = 0;
|
||||
}
|
||||
} else if (strcmp(aPref, PREF_CUBEB_FORCE_NULL_CONTEXT) == 0) {
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
sCubebForceNullContext = Preferences::GetBool(aPref, false);
|
||||
MOZ_LOG(gCubebLog, LogLevel::Verbose,
|
||||
("%s: %s", PREF_CUBEB_FORCE_NULL_CONTEXT, sCubebForceNullContext ? "true" : "false"));
|
||||
}
|
||||
#ifdef MOZ_CUBEB_REMOTING
|
||||
else if (strcmp(aPref, PREF_CUBEB_SANDBOX) == 0) {
|
||||
|
@ -377,6 +385,12 @@ ipc::FileDescriptor CreateAudioIPCConnection()
|
|||
cubeb* GetCubebContextUnlocked()
|
||||
{
|
||||
sMutex.AssertCurrentThreadOwns();
|
||||
if (sCubebForceNullContext) {
|
||||
// Pref set such that we should return a null context
|
||||
MOZ_LOG(gCubebLog, LogLevel::Debug,
|
||||
("%s: returning null context due to %s!", __func__, PREF_CUBEB_FORCE_NULL_CONTEXT));
|
||||
return nullptr;
|
||||
}
|
||||
if (sCubebState != CubebState::Uninitialized) {
|
||||
// If we have already passed the initialization point (below), just return
|
||||
// the current context, which may be null (e.g., after error or shutdown.)
|
||||
|
@ -507,6 +521,7 @@ void InitLibrary()
|
|||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_MSG);
|
||||
Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_FORCE_SAMPLE_RATE);
|
||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
|
||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_FORCE_NULL_CONTEXT);
|
||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_SANDBOX);
|
||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_AUDIOIPC_POOL_SIZE);
|
||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_AUDIOIPC_STACK_SIZE);
|
||||
|
@ -542,6 +557,7 @@ void ShutdownLibrary()
|
|||
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_FORCE_SAMPLE_RATE);
|
||||
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
|
||||
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LOGGING_LEVEL);
|
||||
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_FORCE_NULL_CONTEXT);
|
||||
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
if (sCubebContext) {
|
||||
|
|
|
@ -67,6 +67,8 @@ skip-if = toolkit == 'android' # no windowshare on android
|
|||
[test_getUserMedia_bug1223696.html]
|
||||
[test_getUserMedia_constraints.html]
|
||||
[test_getUserMedia_callbacks.html]
|
||||
[test_getUserMedia_cubebDisabled.html]
|
||||
[test_getUserMedia_cubebDisabledFakeStreams.html]
|
||||
[test_getUserMedia_GC_MediaStream.html]
|
||||
[test_getUserMedia_getTrackById.html]
|
||||
[test_getUserMedia_gumWithinGum.html]
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
title: "getUserMedia with Cubeb Disabled Test",
|
||||
bug: "1443525"
|
||||
});
|
||||
/**
|
||||
* Run a test to verify we fail gracefully if we cannot fetch a cubeb context
|
||||
* during a gUM call.
|
||||
*/
|
||||
runTest(async function () {
|
||||
info("Get user media with cubeb disabled starting");
|
||||
// Push prefs to ensure no cubeb context and no fake streams.
|
||||
await pushPrefs(["media.cubeb.force_null_context", true],
|
||||
["media.navigator.streams.fake", false]);
|
||||
|
||||
// Android has its own codepath which means it works even when cubeb is
|
||||
// disabled. For examples see MediaEngineWebRTC::GetNumOfRecordingDevices and
|
||||
// MediaEngineWebRTC::GetRecordingDeviceName.
|
||||
let isAndroid = navigator.appVersion.includes("Android");
|
||||
// We're on android we expect to get an audio stream, create an elem for it
|
||||
let testAudio = createMediaElement('audio', 'testAudio');
|
||||
|
||||
// Request audio only, to avoid cams
|
||||
let constraints = {audio: true, video: false};
|
||||
let stream;
|
||||
try {
|
||||
stream = await getUserMedia(constraints);
|
||||
} catch (e) {
|
||||
if (isAndroid) {
|
||||
ok(false, `getUserMedia expected to succeed on android, even with null cubeb context, but got ${e}`);
|
||||
return;
|
||||
}
|
||||
// !isAndroid
|
||||
// We've got no audio backend, so we expect gUM to fail.
|
||||
ok(e.name == "NotFoundError", "Expected NotFoundError due to no audio tracks!");
|
||||
return;
|
||||
}
|
||||
if (isAndroid) {
|
||||
ok(stream, "getUserMedia expected to return a stream on Android even when cubeb context null!");
|
||||
let playback = new LocalMediaStreamPlayback(testAudio, stream);
|
||||
return playback.playMedia(false);
|
||||
}
|
||||
// !isAndroid
|
||||
// If we're not on android we should not have gotten a stream without a cubeb context!
|
||||
ok(false, "getUserMedia not expected to succeed when cubeb is disabled, but it did!");
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
title: "getUserMedia fake stream with Cubeb Disabled Test",
|
||||
bug: "1443525"
|
||||
});
|
||||
/**
|
||||
* Run a test to verify we can still return a fake stream even if we cannot
|
||||
* get a cubeb context. See also Bug 1434477
|
||||
*/
|
||||
runTest(async function () {
|
||||
info("Get user media with cubeb disabled and fake tracks starting");
|
||||
// Push prefs to ensure no cubeb context and fake streams
|
||||
await pushPrefs(["media.cubeb.force_null_context", true],
|
||||
["media.navigator.streams.fake", true],
|
||||
['media.audio_loopback_dev', '']);
|
||||
let testAudio = createMediaElement('audio', 'testAudio');
|
||||
// Request audio only, to avoid cams
|
||||
let constraints = {audio: true, video: false};
|
||||
let stream;
|
||||
try {
|
||||
stream = await getUserMedia(constraints);
|
||||
} catch (e) {
|
||||
// We've got no audio backend, so we expect gUM to fail
|
||||
ok(false, `Did not expect to fail, but got ${e}`);
|
||||
return;
|
||||
}
|
||||
ok(stream, "getUserMedia should get a stream!");
|
||||
let playback = new LocalMediaStreamPlayback(testAudio, stream);
|
||||
return playback.playMedia(false);
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -26,6 +26,9 @@
|
|||
|
||||
customElements.define("test-custom-element", TestCustomElement);
|
||||
|
||||
class TestWithoutDash extends XULElement { }
|
||||
customElements.define("testwithoutdash", TestWithoutDash);
|
||||
|
||||
function runTest() {
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
|
@ -53,6 +56,9 @@
|
|||
"Parser should have instantiated the custom element.");
|
||||
ok(element4 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
|
||||
|
||||
let element5 = document.getElementById("element5");
|
||||
ok(element5 instanceof TestWithoutDash, "Should be an instance of TestWithoutDash");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
]]>
|
||||
|
@ -62,6 +68,7 @@
|
|||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<test-custom-element id="element4" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
|
||||
<testwithoutdash id="element5" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
|
|
|
@ -106,11 +106,6 @@ interface Document : Node {
|
|||
Attr createAttribute(DOMString name);
|
||||
[NewObject, Throws]
|
||||
Attr createAttributeNS(DOMString? namespace, DOMString name);
|
||||
|
||||
// Allows setting innerHTML without automatic sanitization.
|
||||
// Do not use this.
|
||||
[ChromeOnly]
|
||||
attribute boolean allowUnsafeHTML;
|
||||
};
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/dom.html#the-document-object
|
||||
|
|
|
@ -3191,18 +3191,15 @@ APZCTreeManager::ComputeTransformForScrollThumb(
|
|||
const Matrix4x4& contentTransform = aScrollableContentTransform;
|
||||
Matrix4x4 contentUntransform = contentTransform.Inverse();
|
||||
|
||||
AsyncTransformComponentMatrix asyncCompensation =
|
||||
ViewAs<AsyncTransformComponentMatrix>(
|
||||
compensation *= ViewAs<AsyncTransformComponentMatrix>(
|
||||
contentTransform
|
||||
* asyncUntransform
|
||||
* contentUntransform);
|
||||
|
||||
compensation = compensation * asyncCompensation;
|
||||
|
||||
// Pass the async compensation out to the caller so that it can use it
|
||||
// Pass the total compensation out to the caller so that it can use it
|
||||
// to transform clip transforms as needed.
|
||||
if (aOutClipTransform) {
|
||||
*aOutClipTransform = asyncCompensation;
|
||||
*aOutClipTransform = compensation;
|
||||
}
|
||||
}
|
||||
transform = transform * compensation;
|
||||
|
|
|
@ -13,6 +13,11 @@ fuzzy-if(Android,3,7) skip-if(!Android) pref(apz.allow_zooming,true) == async-sc
|
|||
fuzzy-if(Android,54,20) skip-if(!Android) pref(apz.allow_zooming,true) == async-scrollbar-zoom-1.html async-scrollbar-zoom-1-ref.html
|
||||
fuzzy-if(Android,45,22) skip-if(!Android) pref(apz.allow_zooming,true) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html
|
||||
|
||||
# Test scrollbars working properly with pinch-zooming, i.e. different document resolutions.
|
||||
# As above, the end of the scrollthumb won't match perfectly, but the bulk of the scrollbar should be present and identical.
|
||||
fuzzy-if(Android,54,14) skip-if(!Android) pref(apz.allow_zooming,true) == scrollbar-zoom-resolution-1.html scrollbar-zoom-resolution-1-ref.html
|
||||
fuzzy-if(Android,51,22) skip-if(!Android) pref(apz.allow_zooming,true) == scrollbar-zoom-resolution-2.html scrollbar-zoom-resolution-2-ref.html
|
||||
|
||||
# Meta-viewport tag support
|
||||
skip-if(!Android) pref(apz.allow_zooming,true) == initial-scale-1.html initial-scale-1-ref.html
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
</head>
|
||||
<body onload="scrollTo(450,10000); document.documentElement.classList.remove('reftest-wait')">
|
||||
<div style="width: 9000px; height: 20000px; background: white;"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta name="viewport" content="initial-scale=2.0; width=device-width">
|
||||
</head>
|
||||
<body onload="scrollTo(225,5000); document.documentElement.classList.remove('reftest-wait')">
|
||||
<div style="width: 4500px; height: 10000px; background: white;"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
</head>
|
||||
<body onload="scrollTo(450,10000); document.documentElement.classList.remove('reftest-wait')">
|
||||
<div style="width: 9000px; height: 20000px; background: white;"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta name="viewport" content="initial-scale=0.5; width=device-width">
|
||||
</head>
|
||||
<body onload="scrollTo(900,20000); document.documentElement.classList.remove('reftest-wait')">
|
||||
<div style="width: 18000px; height: 40000px; background: white;"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -483,9 +483,6 @@ GetStringZone(JSString* str)
|
|||
extern JS_PUBLIC_API(Zone*)
|
||||
GetObjectZone(JSObject* obj);
|
||||
|
||||
extern JS_PUBLIC_API(Zone*)
|
||||
GetValueZone(const Value& value);
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
GCThingIsMarkedGray(GCCellPtr thing)
|
||||
{
|
||||
|
|
|
@ -45,13 +45,6 @@ static void ServoParsingBench() {
|
|||
}
|
||||
}
|
||||
|
||||
MOZ_GTEST_BENCH(Stylo, Servo_StyleSheet_FromUTF8Bytes_Bench, ServoParsingBench);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void ServoSetPropertyByIdBench(const nsACString& css) {
|
||||
RefPtr<RawServoDeclarationBlock> block = Servo_DeclarationBlock_CreateEmpty().Consume();
|
||||
RefPtr<URLExtraData> data = new URLExtraData(
|
||||
|
@ -73,14 +66,6 @@ static void ServoSetPropertyByIdBench(const nsACString& css) {
|
|||
}
|
||||
}
|
||||
|
||||
MOZ_GTEST_BENCH(Stylo, Servo_DeclarationBlock_SetPropertyById_Bench, [] {
|
||||
ServoSetPropertyByIdBench(NS_LITERAL_CSTRING("10px"));
|
||||
});
|
||||
|
||||
MOZ_GTEST_BENCH(Stylo, Servo_DeclarationBlock_SetPropertyById_WithInitialSpace_Bench, [] {
|
||||
ServoSetPropertyByIdBench(NS_LITERAL_CSTRING(" 10px"));
|
||||
});
|
||||
|
||||
static void ServoGetPropertyValueById() {
|
||||
RefPtr<RawServoDeclarationBlock> block = Servo_DeclarationBlock_CreateEmpty().Consume();
|
||||
RefPtr<URLExtraData> data = new URLExtraData(
|
||||
|
@ -110,6 +95,17 @@ static void ServoGetPropertyValueById() {
|
|||
}
|
||||
}
|
||||
|
||||
// Bug 1436018 - Disable Stylo microbenchmark on Windows
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
MOZ_GTEST_BENCH(Stylo, Servo_StyleSheet_FromUTF8Bytes_Bench, ServoParsingBench);
|
||||
|
||||
MOZ_GTEST_BENCH(Stylo, Servo_DeclarationBlock_SetPropertyById_Bench, [] {
|
||||
ServoSetPropertyByIdBench(NS_LITERAL_CSTRING("10px"));
|
||||
});
|
||||
|
||||
MOZ_GTEST_BENCH(Stylo, Servo_DeclarationBlock_SetPropertyById_WithInitialSpace_Bench, [] {
|
||||
ServoSetPropertyByIdBench(NS_LITERAL_CSTRING(" 10px"));
|
||||
});
|
||||
|
||||
MOZ_GTEST_BENCH(Stylo, Servo_DeclarationBlock_GetPropertyById_Bench, ServoGetPropertyValueById);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
15
mfbt/Span.h
15
mfbt/Span.h
|
@ -412,7 +412,8 @@ private:
|
|||
*
|
||||
* A Span<const char> or Span<const char16_t> can be obtained for const char*
|
||||
* or const char16_t pointing to a zero-terminated string using the
|
||||
* MakeStringSpan() function. Corresponding implicit constructor does not exist
|
||||
* MakeStringSpan() function (which treats a nullptr argument equivalently
|
||||
* to the empty string). Corresponding implicit constructor does not exist
|
||||
* in order to avoid accidental construction in cases where const char* or
|
||||
* const char16_t* do not point to a zero-terminated string.
|
||||
*
|
||||
|
@ -1061,20 +1062,28 @@ MakeSpan(Ptr& aPtr, size_t aLength)
|
|||
}
|
||||
|
||||
/**
|
||||
* Create span from C string.
|
||||
* Create span from a zero-terminated C string. nullptr is
|
||||
* treated as the empty string.
|
||||
*/
|
||||
inline Span<const char>
|
||||
MakeStringSpan(const char* aZeroTerminated)
|
||||
{
|
||||
if (!aZeroTerminated) {
|
||||
return Span<const char>();
|
||||
}
|
||||
return Span<const char>(aZeroTerminated, std::strlen(aZeroTerminated));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create span from UTF-16 C string.
|
||||
* Create span from a zero-terminated UTF-16 C string. nullptr is
|
||||
* treated as the empty string.
|
||||
*/
|
||||
inline Span<const char16_t>
|
||||
MakeStringSpan(const char16_t* aZeroTerminated)
|
||||
{
|
||||
if (!aZeroTerminated) {
|
||||
return Span<const char16_t>();
|
||||
}
|
||||
return Span<const char16_t>(aZeroTerminated, span_details::strlen16(aZeroTerminated));
|
||||
}
|
||||
|
||||
|
|
|
@ -1194,6 +1194,11 @@ SPAN_TEST(from_xpcom_collections)
|
|||
|
||||
SPAN_TEST(from_cstring)
|
||||
{
|
||||
{
|
||||
const char* str = nullptr;
|
||||
auto cs = MakeStringSpan(str);
|
||||
ASSERT_EQ(cs.size(), 0U);
|
||||
}
|
||||
{
|
||||
const char* str = "abc";
|
||||
|
||||
|
@ -1233,6 +1238,11 @@ SPAN_TEST(from_cstring)
|
|||
scccea = arr; // error
|
||||
#endif
|
||||
}
|
||||
{
|
||||
const char16_t* str = nullptr;
|
||||
auto cs = MakeStringSpan(str);
|
||||
ASSERT_EQ(cs.size(), 0U);
|
||||
}
|
||||
{
|
||||
char16_t arr[4] = {'a', 'b', 'c', 0};
|
||||
const char16_t* str = arr;
|
||||
|
|
|
@ -633,7 +633,7 @@ public class BrowserApp extends GeckoApp
|
|||
return true;
|
||||
|
||||
case KeyEvent.KEYCODE_R:
|
||||
tab.doReload(event.isShiftPressed() ? true : false);
|
||||
tab.doReload(event.isShiftPressed());
|
||||
return true;
|
||||
|
||||
case KeyEvent.KEYCODE_PERIOD:
|
||||
|
@ -641,9 +641,24 @@ public class BrowserApp extends GeckoApp
|
|||
return true;
|
||||
|
||||
case KeyEvent.KEYCODE_T:
|
||||
addTab();
|
||||
int flags = Tabs.LOADURL_START_EDITING;
|
||||
if (tab.isPrivate()) {
|
||||
flags |= Tabs.LOADURL_PRIVATE;
|
||||
}
|
||||
addTab(flags);
|
||||
return true;
|
||||
|
||||
case KeyEvent.KEYCODE_N:
|
||||
addTab(Tabs.LOADURL_START_EDITING);
|
||||
return true;
|
||||
|
||||
case KeyEvent.KEYCODE_P:
|
||||
if (event.isShiftPressed()) {
|
||||
addTab(Tabs.LOADURL_PRIVATE | Tabs.LOADURL_START_EDITING);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case KeyEvent.KEYCODE_W:
|
||||
Tabs.getInstance().closeTab(tab);
|
||||
return true;
|
||||
|
@ -2323,9 +2338,16 @@ public class BrowserApp extends GeckoApp
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addTab() {
|
||||
public void addTab(final int flags) {
|
||||
if ((flags & Tabs.LOADURL_PRIVATE) == 0) {
|
||||
MmaDelegate.track(NEW_TAB);
|
||||
Tabs.getInstance().addTab();
|
||||
}
|
||||
Tabs.getInstance().addTab(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab() {
|
||||
addTab(Tabs.LOADURL_NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -634,6 +634,8 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
outState.putBoolean(SAVED_STATE_IN_BACKGROUND, isApplicationInBackground());
|
||||
}
|
||||
|
||||
public void addTab(int flags) { }
|
||||
|
||||
public void addTab() { }
|
||||
|
||||
public void addPrivateTab() { }
|
||||
|
|
|
@ -1,11 +0,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/.
|
||||
|
||||
MOZ_APP_DISPLAYNAME=Nightly
|
||||
ANDROID_PACKAGE_NAME=org.mozilla.fennec
|
||||
MOZ_UPDATER=1
|
||||
MOZ_ANDROID_ANR_REPORTER=1
|
||||
MOZ_ANDROID_SHARED_ID=org.mozilla.fennec.sharedID
|
||||
MOZ_ANDROID_GCM_SENDERID=965234145045
|
||||
MOZ_MMA_GCM_SENDERID=242693410970
|
Двоичные данные
mobile/android/branding/nightly-old-id/content/about.png
Двоичные данные
mobile/android/branding/nightly-old-id/content/about.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 29 KiB |
Двоичные данные
mobile/android/branding/nightly-old-id/content/favicon32.png
Двоичные данные
mobile/android/branding/nightly-old-id/content/favicon32.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 2.0 KiB |
Двоичные данные
mobile/android/branding/nightly-old-id/content/favicon64.png
Двоичные данные
mobile/android/branding/nightly-old-id/content/favicon64.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 5.0 KiB |
|
@ -1,9 +0,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/.
|
||||
|
||||
chrome.jar:
|
||||
% content branding %content/branding/ contentaccessible=yes
|
||||
content/branding/about.png (about.png)
|
||||
content/branding/favicon32.png (favicon32.png)
|
||||
content/branding/favicon64.png (favicon64.png)
|
|
@ -1,7 +0,0 @@
|
|||
# -*- Mode: python; 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/.
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
|
@ -1,9 +0,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/. -->
|
||||
|
||||
<!ENTITY brandShortName "Nightly">
|
||||
<!ENTITY brandFullName "Mozilla Nightly">
|
||||
<!ENTITY vendorShortName "Mozilla">
|
||||
|
||||
<!ENTITY brandPocket "Pocket">
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче