Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE

This commit is contained in:
Ciure Andrei 2018-04-04 00:58:50 +03:00
Родитель d339cd56de 7208a2fee8
Коммит 5ffac2bcd3
220 изменённых файлов: 3229 добавлений и 2485 удалений

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

@ -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,11 +242,12 @@ 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) {
child.classList.add("visually-hidden");
child.hidden = false;
if (child.hidden) {
child.classList.add("visually-hidden");
child.hidden = false;
}
}
let ts = performance.now();
@ -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,12 +7,12 @@
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");
ok(panel.querySelector(".animation-list"),
"The animation-list is in the DOM");
"The animation-list is in the DOM");
is(panel.querySelectorAll(".animation-list .animation-item").length,
animationInspector.state.animations.length,
"The number of animations displayed matches the number of animations");
@ -24,11 +24,10 @@ add_task(async function() {
const oddColor =
panel.ownerGlobal.getComputedStyle(animationItemEls[1]).backgroundColor;
isnot(evenColor, oddColor,
"Background color of an even animation should be different from odd");
"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");
"The number of animations displayed should be 1 for .animated element");
});

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

@ -10,18 +10,19 @@
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");
ok(animationTargetEl,
"The animation target element should be in each animation item element");
"The animation target element should be in each animation item element");
}
info("Checking the content of animation target");
@ -29,7 +30,6 @@ add_task(async function() {
const animationTargetEl =
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");
"The target element's content is correct");
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);
@ -49,7 +50,7 @@ function assertTimelineTickItems(timeScale, listHeaderEl) {
const animationTimelineTickListEl =
listHeaderEl.querySelector(".animation-timeline-tick-list");
ok(animationTimelineTickListEl,
"The animation timeline tick list element should be in header");
"The animation timeline tick list element should be in header");
const width = animationTimelineTickListEl.offsetWidth;
const animationDuration = timeScale.getDuration();
@ -60,14 +61,14 @@ function assertTimelineTickItems(timeScale, listHeaderEl) {
const timelineTickItemEls =
listHeaderEl.querySelectorAll(".animation-timeline-tick-item");
is(timelineTickItemEls.length, expectedTickItem,
"The expected number of timeline ticks were found");
"The expected number of timeline ticks were found");
info("Make sure graduations are evenly distributed and show the right times");
for (const [index, tickEl] of timelineTickItemEls.entries()) {
const left = parseFloat(tickEl.style.left);
const expectedPos = index * interval * 100 / animationDuration;
is(Math.round(left), Math.round(expectedPos),
`Graduation ${ index } is positioned correctly`);
`Graduation ${ index } is positioned correctly`);
// Note that the distancetoRelativeTime and formatTime functions are tested
// separately in xpcshell test test_timeScale.js, so we assume that they
@ -75,6 +76,6 @@ function assertTimelineTickItems(timeScale, listHeaderEl) {
const formattedTime =
timeScale.formatTime(timeScale.distanceToRelativeTime(expectedPos, width));
is(tickEl.textContent, formattedTime,
`Graduation ${ index } has the right text content`);
`Graduation ${ index } has the right text content`);
}
}

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

@ -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");
@ -21,14 +19,14 @@ add_task(async function() {
ANIMATION_L10N.getStr("panel.noAnimation"),
"The correct error message is displayed");
ok(!panel.querySelector(".animation-list"),
"Element which has animations class should not exist for a still node");
"Element which has animations class should not exist for a still node");
info("Checking animation list and error message existence for a text node");
const commentNode = await inspector.walker.previousSibling(stillNode);
await selectNodeAndWaitForAnimations(commentNode, inspector);
ok(panel.querySelector(".animation-error-message"),
"Element which has animation-error-message class should exist for a text node");
"Element which has animation-error-message class should exist for a text node");
ok(!panel.querySelector(".animation-list"),
"Element which has animations class should not exist for a text node");
"Element which has animations class should not exist for a text 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 }`;
@ -165,11 +161,11 @@ add_task(async function() {
info(`Checking title in ${ hintTarget }`);
is(markerEl.getAttribute("title"), expectedValue.title,
`title in ${ hintTarget } should be ${ expectedValue.title }`);
`title in ${ hintTarget } should be ${ expectedValue.title }`);
info(`Checking left style in ${ hintTarget }`);
is(markerEl.style.left, expectedValue.left,
`left in ${ hintTarget } should be ${ expectedValue.left }`);
`left in ${ hintTarget } should be ${ expectedValue.left }`);
}
}
}

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

@ -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");

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

@ -37,11 +37,11 @@ add_task(async function() {
"Should not update after selecting another tool");
await selectAnimationInspector(inspector);
is(animationInspector.state.animations.length, 1,
"Should update after selecting animation inspector");
"Should update after selecting animation inspector");
await assertCurrentTimeUpdated(animationInspector, panel, true);
await inspector.toolbox.selectTool("webconsole");
is(animationInspector.state.animations.length, 1,
"Should not update after selecting another tool again");
"Should not update after selecting another tool again");
await assertCurrentTimeUpdated(animationInspector, panel, false);
});

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

@ -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");
@ -20,12 +22,12 @@ add_task(async function() {
info("Checking added animation existence even the animation name is duplicated");
is(getAnimationNameCount(panel, "no-compositor"), 2,
"Count of animation should be plus one to original count");
"Count of animation should be plus one to original count");
info("Checking the mutation for remove an animation");
await setClassAttribute(animationInspector, ".compositor-notall", "ball still");
is(animationInspector.state.animations.length, originalAnimationCount,
"Count of animation should be same to original count since we remove an animation");
"Count of animation should be same to original count since we remove an animation");
info("Checking the mutation for modify an animation");
await selectNodeAndWaitForAnimations(".compositor-all", inspector);
@ -33,8 +35,8 @@ add_task(async function() {
await setStyle(animationInspector, ".compositor-all", "animationIterationCount", 1);
const summaryGraphPathEl = getSummaryGraphPathElement(panel, "compositor-all");
is(summaryGraphPathEl.viewBox.baseVal.width, 100000,
"Width of summary graph path should be 100000 " +
"after modifing the duration and iteration count");
"Width of summary graph path should be 100000 " +
"after modifing the duration and iteration count");
await setStyle(animationInspector, ".compositor-all", "animationDelay", "100s");
is(summaryGraphPathEl.viewBox.baseVal.width, 200000,
"Width of summary graph path should be 200000 after modifing the delay");

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

@ -7,53 +7,48 @@
// * 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) {
ok(animationNameEl,
"The animation name element should be in animation item element");
"The animation name element should be in animation item element");
is(animationNameEl.textContent, expectedLabel,
`The animation name should be ${ expectedLabel }`);
`The animation name should be ${ expectedLabel }`);
} else {
ok(!animationNameEl,
"The animation name element should not be in animation item element");
"The animation name element should not be in animation item element");
}
}
});

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

@ -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");
@ -16,7 +17,7 @@ add_task(async function() {
const summaryGraphEl = panel.querySelector(".animation-summary-graph");
ok(summaryGraphEl.classList.contains("compositor"),
"The element has the compositor css class");
"The element has the compositor css class");
ok(hasTooltip(summaryGraphEl,
ANIMATION_L10N.getStr("player.allPropertiesOnCompositorTooltip")),
"The element has the right tooltip content");
@ -25,7 +26,7 @@ add_task(async function() {
await selectNodeAndWaitForAnimations(".no-compositor", inspector);
ok(!summaryGraphEl.classList.contains("compositor"),
"The element does not have the compositor css class");
"The element does not have the compositor css class");
ok(!hasTooltip(summaryGraphEl,
ANIMATION_L10N.getStr("player.allPropertiesOnCompositorTooltip")),
"The element does not have oncompositor tooltip content");
@ -37,7 +38,7 @@ add_task(async function() {
await selectNodeAndWaitForAnimations(".compositor-notall", inspector);
ok(summaryGraphEl.classList.contains("compositor"),
"The element has the compositor css class");
"The element has the compositor css class");
ok(hasTooltip(summaryGraphEl,
ANIMATION_L10N.getStr("player.somePropertiesOnCompositorTooltip")),
"The element has the right tooltip content");

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

@ -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,38 +45,33 @@ 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) {
ok(delaySignEl, "The delay sign element should be in animation item element");
is(delaySignEl.style.left, expectedResult.left,
`Left position should be ${ expectedResult.left }`);
`Left position should be ${ expectedResult.left }`);
is(delaySignEl.style.width, expectedResult.width,
`Width should be ${ expectedResult.width }`);
`Width should be ${ expectedResult.width }`);
if (expectedResult.additionalClass) {
ok(delaySignEl.classList.contains(expectedResult.additionalClass),
`delay sign element should have ${ expectedResult.additionalClass } class`);
`delay sign element should have ${ expectedResult.additionalClass } class`);
} else {
ok(!delaySignEl.classList.contains(expectedResult.additionalClass),
"delay sign element should not have " +

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

@ -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,36 +25,31 @@ 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");
if (expectedPath) {
ok(effectTimingPathEl,
"The effect timing path element should be in animation item element");
"The effect timing path element should be in animation item element");
const pathEl = effectTimingPathEl.querySelector(".animation-iteration-path");
assertPathSegments(pathEl, false, expectedPath);
} else {
ok(!effectTimingPathEl,
"The effect timing path element should not be in animation item element");
"The effect timing path element should not be in animation item element");
}
}
});

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

@ -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,41 +34,36 @@ 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) {
ok(endDelaySignEl, "The endDelay sign element should be in animation item element");
is(endDelaySignEl.style.left, expectedResult.left,
`Left position should be ${ expectedResult.left }`);
`Left position should be ${ expectedResult.left }`);
is(endDelaySignEl.style.width, expectedResult.width,
`Width should be ${ expectedResult.width }`);
`Width should be ${ expectedResult.width }`);
if (expectedResult.additionalClass) {
ok(endDelaySignEl.classList.contains(expectedResult.additionalClass),
`endDelay sign element should have ${ expectedResult.additionalClass } class`);
`endDelay sign element should have ${ expectedResult.additionalClass } class`);
} else {
ok(!endDelaySignEl.classList.contains(expectedResult.additionalClass),
"endDelay sign element should not have " +
@ -76,7 +71,7 @@ add_task(async function() {
}
} else {
ok(!endDelaySignEl,
"The endDelay sign element should not be in animation item element");
"The endDelay sign element should not be in animation item element");
}
}
});

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

@ -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,30 +24,25 @@ 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");
if (expectedPath) {
ok(negativeDelayPathEl,
"The negative delay path element should be in animation item element");
"The negative delay path element should be in animation item element");
const pathEl = negativeDelayPathEl.querySelector("path");
assertPathSegments(pathEl, true, expectedPath);
} else {
ok(!negativeDelayPathEl,
"The negative delay path element should not be in animation item element");
"The negative delay path element should not be in animation item element");
}
}
});

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

@ -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,30 +25,25 @@ 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");
if (expectedPath) {
ok(negativeEndDelayPathEl,
"The negative endDelay path element should be in animation item element");
"The negative endDelay path element should be in animation item element");
const pathEl = negativeEndDelayPathEl.querySelector("path");
assertPathSegments(pathEl, true, expectedPath);
} else {
ok(!negativeEndDelayPathEl,
"The negative endDelay path element should not be in animation item element");
"The negative endDelay path element should not be in animation item element");
}
}
});

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

@ -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,22 +176,17 @@ 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");
"Summary graph should have 'title' attribute");
const tooltip = summaryGraphEl.getAttribute("title");
const {
@ -214,7 +209,7 @@ add_task(async function() {
ok(tooltip.includes(expected), `Tooltip should include '${ expected }'`);
} else {
ok(!tooltip.includes("Animation timing function:"),
"Tooltip should not include animation timing function");
"Tooltip should not include animation timing function");
}
if (delay) {
@ -271,7 +266,7 @@ add_task(async function() {
ok(tooltip.includes(expected), `Tooltip should include '${ expected }'`);
} else {
ok(!tooltip.includes("Iteration start:"),
"Tooltip should not include iterationStart");
"Tooltip should not include iterationStart");
}
}
});

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

@ -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]);
await wait;
// Open GET request in new tab
await performRequest("GET");
let onTabOpen = once(gBrowser.tabContainer, "TabOpen", false);
monitor.panelWin.parent.document
.querySelector("#request-list-context-newtab").click();
await onTabOpen;
newTab = await openLastRequestInTab();
await checkTabResponse(newTab, "GET");
ok(true, "A new tab has been opened");
// 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");
let awaitedTab = gBrowser.selectedTab;
await BrowserTestUtils.browserLoaded(awaitedTab.linkedBrowser);
info("The tab load completed");
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\&amp;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);
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 (imgRequest) {
rv = GetImageData(img, imgRequest);
NS_ENSURE_SUCCESS(rv, rv);
}
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;
@ -9978,9 +9985,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,

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

@ -1433,7 +1433,6 @@ nsIDocument::nsIDocument()
mEncodingMenuDisabled(false),
mIsShadowDOMEnabled(false),
mIsSVGGlyphsDocument(false),
mAllowUnsafeHTML(false),
mInDestructor(false),
mIsGoingAway(false),
mInXBLUpdate(false),
@ -5865,13 +5864,6 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
return attribute.forget();
}
bool
nsIDocument::AllowUnsafeHTML() const
{
return (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) ||
mAllowUnsafeHTML);
}
void
nsIDocument::ResolveScheduledSVGPresAttrs()
{

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

@ -3163,8 +3163,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;
@ -3992,10 +3990,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>(
contentTransform
* asyncUntransform
* contentUntransform);
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

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

@ -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;
@ -2322,10 +2337,17 @@ public class BrowserApp extends GeckoApp
return (TextUtils.equals(packageName, getPackageName()));
}
@Override
public void addTab(final int flags) {
if ((flags & Tabs.LOADURL_PRIVATE) == 0) {
MmaDelegate.track(NEW_TAB);
}
Tabs.getInstance().addTab(flags);
}
@Override
public void addTab() {
MmaDelegate.track(NEW_TAB);
Tabs.getInstance().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

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 29 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 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']

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