This commit is contained in:
Ryan VanderMeulen 2016-08-31 22:37:49 -04:00
Родитель 97e69eb233 3611a7607d
Коммит 60c3cb1548
338 изменённых файлов: 5264 добавлений и 3184 удалений

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

@ -7,11 +7,15 @@ module.metadata = {
"stability": "unstable"
};
const { Ci } = require("chrome");
const { Ci, Cc, Cu } = require("chrome");
const core = require("../l10n/core");
const { loadSheet, removeSheet } = require("../stylesheet/utils");
const { process, frames } = require("../remote/child");
const { Services } = require("resource://gre/modules/Services.jsm");
var observerService = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
const addObserver = ShimWaiver.getProperty(observerService, "addObserver");
const removeObserver = ShimWaiver.getProperty(observerService, "removeObserver");
const assetsURI = require('../self').data.url();
@ -115,7 +119,7 @@ let enabled = false;
function enable() {
if (enabled)
return;
Services.obs.addObserver(onContentWindow, ON_CONTENT, false);
addObserver(onContentWindow, ON_CONTENT, false);
enabled = true;
}
process.port.on("sdk/l10n/html/enable", enable);
@ -123,7 +127,7 @@ process.port.on("sdk/l10n/html/enable", enable);
function disable() {
if (!enabled)
return;
Services.obs.removeObserver(onContentWindow, ON_CONTENT);
removeObserver(onContentWindow, ON_CONTENT);
enabled = false;
}
process.port.on("sdk/l10n/html/disable", disable);

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

@ -62,7 +62,6 @@ function WindowTracker(delegate) {
}
this._delegate = delegate;
this._loadingWindows = [];
for (let window of getWindows())
this._regWindow(window);
@ -81,17 +80,12 @@ WindowTracker.prototype = {
if (ignoreWindow(window))
return;
this._loadingWindows.push(window);
window.addEventListener('load', this, true);
},
_unregLoadingWindow: function _unregLoadingWindow(window) {
var index = this._loadingWindows.indexOf(window);
if (index != -1) {
this._loadingWindows.splice(index, 1);
window.removeEventListener('load', this, true);
}
// This may have no effect if we ignored the window in _regLoadingWindow().
window.removeEventListener('load', this, true);
},
_regWindow: function _regWindow(window) {

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

@ -254,16 +254,6 @@ toolbar[customizing] > .overflow-button {
-moz-box-ordinal-group: 0;
}
/* In private windows, the #titlebar-content is higher because of the
* private browsing indicator. With the margin-top the titlebar buttons
* align to the top correctly in that case, but only if we don't stretch
* the box they're in because the container is too high, so we override
* the default alignment value (stretch).
*/
#main-window[tabsintitlebar] > #titlebar > #titlebar-content > #titlebar-buttonbox-container {
-moz-box-align: start;
}
%else
/* On non-OSX, these should be start-aligned */
#titlebar-buttonbox-container {

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

@ -5394,7 +5394,9 @@ function hrefAndLinkNodeForClickEvent(event)
if (node.nodeType == Node.ELEMENT_NODE &&
(node.localName == "a" ||
node.namespaceURI == "http://www.w3.org/1998/Math/MathML")) {
href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
href = node.getAttribute("href") ||
node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (href) {
baseURI = node.baseURI;
break;

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

@ -593,7 +593,8 @@ var ClickEventHandler = {
if (node.nodeType == content.Node.ELEMENT_NODE &&
(node.localName == "a" ||
node.namespaceURI == "http://www.w3.org/1998/Math/MathML")) {
href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
href = node.getAttribute("href") ||
node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (href) {
baseURI = node.ownerDocument.baseURIObject;
break;

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

@ -221,7 +221,7 @@ var gDropTargetShim = {
*/
_dispatchEvent: function (aEvent, aType, aTarget) {
let node = aTarget.node;
let event = document.createEvent("DragEvents");
let event = document.createEvent("DragEvent");
// The event should not bubble to prevent recursion.
event.initDragEvent(aType, false, true, window, 0, 0, 0, 0, 0, false, false,

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

@ -1566,8 +1566,8 @@ nsContextMenu.prototype = {
if (href)
return href;
href = this.link.getAttributeNS("http://www.w3.org/1999/xlink",
"href");
href = this.link.getAttribute("href") ||
this.link.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (!href || !href.match(/\S/)) {
// Without this we try to save as the current doc,

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

@ -19,7 +19,7 @@ add_task(function* () {
function sendDragEvent(aEventType, aTarget) {
let dataTransfer = new content.DataTransfer(aEventType, false);
let event = content.document.createEvent("DragEvents");
let event = content.document.createEvent("DragEvent");
event.initDragEvent(aEventType, true, true, content, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);
aTarget.dispatchEvent(event);

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

@ -12,7 +12,7 @@ add_task(function* () {
return ContentTask.spawn(gBrowser.selectedBrowser, { data: data }, function*(args) {
let dataTransfer = new content.DataTransfer("dragstart", false);
dataTransfer.mozSetDataAt("text/x-moz-url", args.data, 0);
let event = content.document.createEvent("DragEvents");
let event = content.document.createEvent("DragEvent");
event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);

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

@ -15,7 +15,7 @@ add_task(function* () {
function sendDropEvent(aCellIndex, aDragData) {
let dataTransfer = new content.DataTransfer("dragstart", false);
dataTransfer.mozSetDataAt("text/x-moz-url", aDragData, 0);
let event = content.document.createEvent("DragEvents");
let event = content.document.createEvent("DragEvent");
event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);

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

@ -78,14 +78,14 @@ function doDragEvent(sourceIndex, dropIndex) {
return ContentTask.spawn(gBrowser.selectedBrowser,
{ sourceIndex: sourceIndex, dropIndex: dropIndex }, function*(args) {
let dataTransfer = new content.DataTransfer("dragstart", false);
let event = content.document.createEvent("DragEvents");
let event = content.document.createEvent("DragEvent");
event.initDragEvent("dragstart", true, true, content, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);
let target = content.gGrid.cells[args.sourceIndex].site.node;
target.dispatchEvent(event);
event = content.document.createEvent("DragEvents");
event = content.document.createEvent("DragEvent");
event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);

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

@ -419,7 +419,7 @@ function* simulateExternalDrop(aDestIndex) {
let dataTransfer = new iframe.contentWindow.DataTransfer("dragstart", false);
dataTransfer.mozSetDataAt("text/x-moz-url", "http://example99.com/", 0);
let event = content.document.createEvent("DragEvents");
let event = content.document.createEvent("DragEvent");
event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);

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

@ -834,7 +834,7 @@
"name": "result",
"optional": true,
"type": "array",
"items": {"type": "any", "minimum": 0},
"items": {"type": "any"},
"description": "The result of the script in every injected frame."
}
]

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

@ -41,8 +41,28 @@ const AutoMigrate = {
return BOOKMARKS | HISTORY | PASSWORDS;
},
_checkIfEnabled() {
let pref = Preferences.get(kAutoMigrateEnabledPref, false);
// User-set values should take precedence:
if (Services.prefs.prefHasUserValue(kAutoMigrateEnabledPref)) {
return pref;
}
// If we're using the default value, make sure the distribution.ini
// value is taken into account even early on startup.
try {
let distributionFile = Services.dirsvc.get("XREAppDist", Ci.nsIFile);
distributionFile.append("distribution.ini");
let parser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
getService(Ci.nsIINIParserFactory).
createINIParser(distributionFile);
return JSON.parse(parser.getString("Preferences", kAutoMigrateEnabledPref));
} catch (ex) { /* ignore exceptions (file doesn't exist, invalid value, etc.) */ }
return pref;
},
init() {
this.enabled = Preferences.get(kAutoMigrateEnabledPref, false);
this.enabled = this._checkIfEnabled();
if (this.enabled) {
this.maybeInitUndoObserver();
}

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

@ -6,8 +6,6 @@
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
MARIONETTE_UNIT_MANIFESTS += ['tests/marionette/manifest.ini']
JAR_MANIFESTS += ['jar.mn']
XPIDL_SOURCES += [

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

@ -2614,6 +2614,45 @@ ContentPermissionPrompt.prototype = {
"geo-notification-icon", options);
},
_promptFlyWebPublishServer : function(aRequest) {
var message = "Would you like to let this site start a server accessible to nearby devices and people?";
var actions = [
{
stringId: "flyWebPublishServer.allowPublishServer",
action: Ci.nsIPermissionManager.ALLOW_ACTION,
expireType: Ci.nsIPermissionManager.EXPIRE_SESSION
},
{
stringId: "flyWebPublishServer.denyPublishServer",
action: Ci.nsIPermissionManager.DENY_ACTION,
expireType: Ci.nsIPermissionManager.EXPIRE_SESSION
}
];
let options = {
learnMoreURL: "https://flyweb.github.io",
popupIconURL: "chrome://flyweb/skin/icon-64.png"
};
let browser = this._getBrowserForRequest(aRequest);
let chromeDoc = browser.ownerDocument;
let iconElem = chromeDoc.getElementById("flyweb-publish-server-notification-icon");
if (!iconElem) {
let notificationPopupBox = chromeDoc.getElementById("notification-popup-box");
let notificationIcon = chromeDoc.createElement("image");
notificationIcon.setAttribute("id", "flyweb-publish-server-notification-icon");
notificationIcon.setAttribute("src", "chrome://flyweb/skin/icon-64.png");
notificationIcon.setAttribute("class", "notification-anchor-icon flyweb-publish-server-icon");
notificationIcon.setAttribute("style", "filter: url(chrome://browser/skin/filters.svg#fill); fill: currentColor; opacity: .4;");
notificationIcon.setAttribute("role", "button");
notificationIcon.setAttribute("aria-label", "View the publish-server request");
notificationPopupBox.appendChild(notificationIcon);
}
this._showPrompt(aRequest, message, "flyweb-publish-server", actions, "flyweb-publish-server",
"flyweb-publish-server-notification-icon", options);
},
_promptWebNotifications : function(aRequest) {
var message = gBrowserBundle.GetStringFromName("webNotifications.receiveFromSite");
@ -2678,7 +2717,8 @@ ContentPermissionPrompt.prototype = {
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
const kFeatureKeys = { "geolocation" : "geo",
"desktop-notification" : "desktop-notification"
"desktop-notification" : "desktop-notification",
"flyweb-publish-server": "flyweb-publish-server"
};
// Make sure that we support the request.
@ -2721,6 +2761,11 @@ ContentPermissionPrompt.prototype = {
case "desktop-notification":
this._promptWebNotifications(request);
break;
case "flyweb-publish-server":
if (AppConstants.NIGHTLY_BUILD) {
this._promptFlyWebPublishServer(request);
}
break;
}
},

1
browser/extensions/e10srollout/bootstrap.js поставляемый
Просмотреть файл

@ -13,6 +13,7 @@ Cu.import("resource://gre/modules/UpdateUtils.jsm");
// The amount of people to be part of e10s
const TEST_THRESHOLD = {
"beta" : 0.5, // 50%
"release" : 1.0, // 100%
};
const ADDON_ROLLOUT_POLICY = {

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

@ -10,7 +10,7 @@
<Description about="urn:mozilla:install-manifest">
<em:id>e10srollout@mozilla.org</em:id>
<em:version>1.0</em:version>
<em:version>1.2</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

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

@ -378,6 +378,16 @@ geolocation.neverShareLocation.accesskey=N
geolocation.shareWithSite2=Would you like to share your location with this site?
geolocation.shareWithFile2=Would you like to share your location with this file?
# FlyWeb UI
# LOCALIZATION NOTE (flyWebPublishServer.allowPublishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation.
flyWebPublishServer.allowPublishServer=Allow Server
# LOCALIZATION NOTE (flyWebPublishServer.allowPublishServer.accessKey): This is an experimental feature only shipping in Nightly, and doesn't need translation.
flyWebPublishServer.allowPublishServer.accesskey=A
# LOCALIZATION NOTE (flyWebPublishServer.denyPublishServer): This is an experimental feature only shipping in Nightly, and doesn't need translation.
flyWebPublishServer.denyPublishServer=Block Server
# LOCALIZATION NOTE (flyWebPublishServer.denyPublishServer.accessKey): This is an experimental feature only shipping in Nightly, and doesn't need translation.
flyWebPublishServer.denyPublishServer.accesskey=B
webNotifications.receiveForSession=Receive for this session
webNotifications.receiveForSession.accesskey=s
webNotifications.alwaysReceive=Always Receive Notifications

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

@ -118,13 +118,17 @@
/**
* We also vertically center the window buttons.
*/
#titlebar-buttonbox-container {
-moz-box-align: start;
}
#main-window[tabsintitlebar] > #titlebar > #titlebar-content > #titlebar-buttonbox-container,
#main-window[tabsintitlebar] > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > #titlebar-fullscreen-button {
margin-top: @windowButtonMarginTop@;
}
#main-window:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-buttonbox-container:-moz-lwtheme,
#main-window:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > #titlebar-fullscreen-button:-moz-lwtheme {
#main-window:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-buttonbox-container,
#main-window:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > #titlebar-fullscreen-button {
margin-top: 3px;
}

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

@ -58,10 +58,6 @@
--urlbar-dropmarker-active-2x-region: rect(0px, 33px, 14px, 22px);
}
:root[devtoolstheme="dark"] #identity-box {
--identity-box-chrome-color: #46afe3;
}
:root[devtoolstheme="light"] {
--url-and-searchbar-background-color: #fff;

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

@ -5,17 +5,6 @@
%endif
#identity-box {
--identity-box-verified-color: hsl(92,100%,30%);
%ifdef MOZ_OFFICIAL_BRANDING
--identity-box-chrome-color: rgb(229,115,0);
%else
%if MOZ_UPDATE_CHANNEL == aurora
--identity-box-chrome-color: rgb(51,30,84);
%else
--identity-box-chrome-color: rgb(0,33,71);
%endif
%endif
font-size: .9em;
padding: 3px 5px;
overflow: hidden;
@ -24,14 +13,16 @@
transition: padding-left, padding-right;
}
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #identity-icon-labels {
color: var(--identity-box-verified-color);
color: hsl(92,100%,30%);
}
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon-labels {
color: var(--identity-box-chrome-color);
%ifdef MOZ_OFFICIAL_BRANDING
color: rgb(229,115,0);
%else
color: inherit;
%endif
}
#identity-icon-labels:-moz-locale-dir(ltr) {

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

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

@ -23,7 +23,6 @@
"use strict";
const {Ci, Cc} = require("chrome");
const Services = require("Services");
const focusManager = Services.focus;
const {KeyCodes} = require("devtools/client/shared/keycodes");
@ -43,7 +42,6 @@ const MAX_POPUP_ENTRIES = 500;
const FOCUS_FORWARD = focusManager.MOVEFOCUS_FORWARD;
const FOCUS_BACKWARD = focusManager.MOVEFOCUS_BACKWARD;
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
const EventEmitter = require("devtools/shared/event-emitter");
const { findMostRelevantCssPropertyIndex } = require("./suggestion-picker");
@ -1467,7 +1465,7 @@ InplaceEditor.prototype = {
* @return {Array} array of CSS property names (Strings)
*/
_getCSSPropertyList: function () {
return CSSPropertyList;
return this.cssProperties.getNames().sort();
},
/**
@ -1556,11 +1554,3 @@ function copyBoxModelStyles(from, to) {
function moveFocus(win, direction) {
return focusManager.moveFocus(win, null, direction, 0);
}
XPCOMUtils.defineLazyGetter(this, "CSSPropertyList", function () {
return domUtils.getCSSPropertyNames(domUtils.INCLUDE_ALIASES).sort();
});
XPCOMUtils.defineLazyGetter(this, "domUtils", function () {
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
});

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

@ -41,10 +41,6 @@ function PrefBranch(parent, name, fullName) {
this._hasUserValue = false;
this._userValue = null;
this._type = PREF_INVALID;
if (!parent) {
this._initializeRoot();
}
}
PrefBranch.prototype = {
@ -469,6 +465,7 @@ const Services = {
get prefs() {
if (!this._prefs) {
this._prefs = new PrefBranch(null, "", "");
this._prefs._initializeRoot();
}
return this._prefs;
},

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

@ -105,7 +105,8 @@ function initializeAutoCompletion(ctx, options = {}) {
// TODO: Integrate tern autocompletion with this autocomplete API.
return;
} else if (ed.config.mode == Editor.modes.css) {
completer = new CSSCompleter({walker: options.walker});
completer = new CSSCompleter({walker: options.walker,
cssProperties: options.cssProperties});
}
function insertSelectedPopupItem() {

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

@ -5,11 +5,8 @@
"use strict";
/* eslint-disable complexity */
/* eslint-disable mozilla/reject-some-requires */
const { Cc, Ci } = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const {cssTokenizer, cssTokenizerWithLineColumn} = require("devtools/shared/css-parsing-utils");
const {getClientCssProperties} = require("devtools/shared/fronts/css-properties");
/**
* Here is what this file (+ css-parsing-utils.js) do.
@ -78,8 +75,6 @@ const SELECTOR_STATES = {
};
/* eslint-enable no-inline-comments */
const { properties, propertyNames } = getCSSKeywords();
/**
* Constructor for the autocompletion object.
*
@ -87,10 +82,15 @@ const { properties, propertyNames } = getCSSKeywords();
* - walker {Object} The object used for query selecting from the current
* target's DOM.
* - maxEntries {Number} Maximum selectors suggestions to display.
* - cssProperties {Object} The database of CSS properties.
*/
function CSSCompleter(options = {}) {
this.walker = options.walker;
this.maxEntries = options.maxEntries || 15;
// If no css properties database is passed in, default to the client list.
this.cssProperties = options.cssProperties || getClientCssProperties();
this.propertyNames = this.cssProperties.getNames().sort();
// Array containing the [line, ch, scopeStack] for the locations where the
// CSS state is "null"
@ -844,18 +844,18 @@ CSSCompleter.prototype = {
return Promise.resolve(finalList);
}
let length = propertyNames.length;
let length = this.propertyNames.length;
let i = 0, count = 0;
for (; i < length && count < this.maxEntries; i++) {
if (propertyNames[i].startsWith(startProp)) {
if (this.propertyNames[i].startsWith(startProp)) {
count++;
let propName = propertyNames[i];
let propName = this.propertyNames[i];
finalList.push({
preLabel: startProp,
label: propName,
text: propName + ": "
});
} else if (propertyNames[i] > startProp) {
} else if (this.propertyNames[i] > startProp) {
// We have crossed all possible matches alphabetically.
break;
}
@ -872,7 +872,7 @@ CSSCompleter.prototype = {
*/
completeValues: function (propName, startValue) {
let finalList = [];
let list = ["!important;", ...(properties[propName] || [])];
let list = ["!important;", ...this.cssProperties.getValues(propName)];
// If there is no character being completed, we are showing an initial list
// of possible values. Skipping '!important' in this case.
if (!startValue) {
@ -1211,29 +1211,4 @@ CSSCompleter.prototype = {
}
};
/**
* Returns a list of all property names and a map of property name vs possible
* CSS values provided by the Gecko engine.
*
* @return {Object} An object with following properties:
* - propertyNames {Array} Array of string containing all the possible
* CSS property names.
* - properties {Object|Map} A map where key is the property name and
* value is an array of string containing all the possible
* CSS values the property can have.
*/
function getCSSKeywords() {
let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
.getService(Ci.inIDOMUtils);
let props = {};
let propNames = domUtils.getCSSPropertyNames(domUtils.INCLUDE_ALIASES);
propNames.forEach(prop => {
props[prop] = domUtils.getCSSValuesForProperty(prop).sort();
});
return {
properties: props,
propertyNames: propNames.sort()
};
}
module.exports = CSSCompleter;

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

@ -6,10 +6,6 @@
"use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Cc, Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const {
EXPAND_TAB,
TAB_SIZE,
@ -37,6 +33,7 @@ const Services = require("Services");
const promise = require("promise");
const events = require("devtools/shared/event-emitter");
const { PrefObserver } = require("devtools/client/styleeditor/utils");
const { getClientCssProperties } = require("devtools/shared/fronts/css-properties");
const {LocalizationHelper} = require("devtools/shared/l10n");
const L10N = new LocalizationHelper("devtools/locale/sourceeditor.properties");
@ -114,8 +111,6 @@ const CM_MAPPING = [
"getViewport"
];
const { cssProperties, cssValues, cssColors } = getCSSKeywords();
const editors = new WeakMap();
Editor.modes = {
@ -240,6 +235,14 @@ function Editor(config) {
this.config.externalScripts = [];
}
if (this.config.cssProperties) {
// Ensure that autocompletion has cssProperties if it's passed in via the options.
this.config.autocompleteOpts.cssProperties = this.config.cssProperties;
} else {
// Use a static client-side database of CSS values if none is provided.
this.config.cssProperties = getClientCssProperties();
}
events.decorate(this);
}
@ -289,17 +292,25 @@ Editor.prototype = {
}
});
// Replace the propertyKeywords, colorKeywords and valueKeywords
// properties of the CSS MIME type with the values provided by Gecko.
// properties of the CSS MIME type with the values provided by the CSS properties
// database.
const {
propertyKeywords,
colorKeywords,
valueKeywords
} = getCSSKeywords(this.config.cssProperties);
let cssSpec = win.CodeMirror.resolveMode("text/css");
cssSpec.propertyKeywords = cssProperties;
cssSpec.colorKeywords = cssColors;
cssSpec.valueKeywords = cssValues;
cssSpec.propertyKeywords = propertyKeywords;
cssSpec.colorKeywords = colorKeywords;
cssSpec.valueKeywords = valueKeywords;
win.CodeMirror.defineMIME("text/css", cssSpec);
let scssSpec = win.CodeMirror.resolveMode("text/x-scss");
scssSpec.propertyKeywords = cssProperties;
scssSpec.colorKeywords = cssColors;
scssSpec.valueKeywords = cssValues;
scssSpec.propertyKeywords = propertyKeywords;
scssSpec.colorKeywords = colorKeywords;
scssSpec.valueKeywords = valueKeywords;
win.CodeMirror.defineMIME("text/x-scss", scssSpec);
win.CodeMirror.commands.save = () => this.emit("saveRequested");
@ -1279,12 +1290,14 @@ Editor.keyFor = function (cmd, opts = { noaccel: false }) {
return opts.noaccel ? key : Editor.accel(key);
};
// Since Gecko already provide complete and up to date list of CSS property
// names, values and color names, we compute them so that they can replace
// the ones used in CodeMirror while initiating an editor object. This is done
// here instead of the file codemirror/css.js so as to leave that file untouched
// and easily upgradable.
function getCSSKeywords() {
/**
* We compute the CSS property names, values, and color names to be used with
* CodeMirror to more closely reflect what is supported by the target platform.
* The database is used to replace the values used in CodeMirror while initiating
* an editor object. This is done here instead of the file codemirror/css.js so
* as to leave that file untouched and easily upgradable.
*/
function getCSSKeywords(cssProperties) {
function keySet(array) {
let keys = {};
for (let i = 0; i < array.length; ++i) {
@ -1293,26 +1306,26 @@ function getCSSKeywords() {
return keys;
}
let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
.getService(Ci.inIDOMUtils);
let properties = domUtils.getCSSPropertyNames(domUtils.INCLUDE_ALIASES);
let colors = {};
let values = {};
properties.forEach(property => {
let propertyKeywords = cssProperties.getNames();
let colorKeywords = {};
let valueKeywords = {};
propertyKeywords.forEach(property => {
if (property.includes("color")) {
domUtils.getCSSValuesForProperty(property).forEach(value => {
colors[value] = true;
cssProperties.getValues(property).forEach(value => {
colorKeywords[value] = true;
});
} else {
domUtils.getCSSValuesForProperty(property).forEach(value => {
values[value] = true;
cssProperties.getValues(property).forEach(value => {
valueKeywords[value] = true;
});
}
});
return {
cssProperties: keySet(properties),
cssValues: values,
cssColors: colors
propertyKeywords: keySet(propertyKeywords),
colorKeywords: colorKeywords,
valueKeywords: valueKeywords
};
}

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

@ -95,7 +95,8 @@ function runTests() {
target.makeRemote().then(() => {
inspector = InspectorFront(target.client, target.form);
inspector.getWalker().then(walker => {
completer = new CSSCompleter({walker: walker});
completer = new CSSCompleter({walker: walker,
cssProperties: getClientCssProperties()});
checkStateAndMoveOn();
});
});
@ -107,13 +108,15 @@ function checkStateAndMoveOn() {
return;
}
let test = tests[index];
let [lineCh, expectedSuggestions] = tests[index];
let [line, ch] = lineCh;
progress.dataset.progress = ++index;
progressDiv.style.width = 100 * index / tests.length + "%";
completer.complete(limit(source, test[0]),
{line: test[0][0], ch: test[0][1]}).then(suggestions => {
checkState(test[1], suggestions);
}).then(checkStateAndMoveOn);
completer.complete(limit(source, lineCh), {line, ch})
.then(actualSuggestions => checkState(expectedSuggestions, actualSuggestions))
.then(checkStateAndMoveOn);
}
function checkState(expected, actual) {

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

@ -132,7 +132,7 @@ function test() {
}
function runTests() {
let completer = new CSSCompleter();
let completer = new CSSCompleter({cssProperties: getClientCssProperties()});
let matches = (arr, toCheck) => !arr.some((x, i) => x != toCheck[i]);
let checkState = (expected, actual) => {
if (expected[0] == "null" && actual == null) {

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

@ -5,7 +5,6 @@
"use strict";
const CSSCompleter = require("devtools/client/sourceeditor/css-autocompleter");
const { Cc, Ci } = require("chrome");
const CSS_URI = "http://mochi.test:8888/browser/devtools/client/sourceeditor" +
"/test/css_statemachine_testcases.css";
@ -66,7 +65,7 @@ function test() {
}
function runTests() {
let completer = new CSSCompleter();
let completer = new CSSCompleter({cssProperties: getClientCssProperties()});
let checkState = state => {
if (state[0] == "null" && (!completer.state || completer.state == "null")) {
return true;

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

@ -25,7 +25,7 @@ function* runTests() {
let {ed, win, edWin} = yield setup(null, {
autocomplete: true,
mode: Editor.modes.css,
autocompleteOpts: {walker: walker}
autocompleteOpts: {walker: walker, cssProperties: getClientCssProperties()}
});
yield testMouse(ed, edWin);
yield testKeyboard(ed, edWin);

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

@ -8,8 +8,8 @@ const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
const Editor = require("devtools/client/sourceeditor/editor");
const promise = require("promise");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const flags = require("devtools/shared/flags");
const {getClientCssProperties} = require("devtools/shared/fronts/css-properties");
flags.testing = true;
SimpleTest.registerCleanupFunction(() => {
@ -62,8 +62,10 @@ function setup(cb, additionalOpts = {}) {
value: "Hello.",
lineNumbers: true,
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "breakpoints", "CodeMirror-foldgutter"]
gutters: ["CodeMirror-linenumbers", "breakpoints", "CodeMirror-foldgutter"],
cssProperties: getClientCssProperties()
};
for (let o in additionalOpts) {
opts[o] = additionalOpts[o];
}

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

@ -57,13 +57,15 @@ const PREF_NAV_WIDTH = "devtools.styleeditor.navSidebarWidth";
* Interface for the page we're debugging
* @param {Document} panelDoc
* Document of the toolbox panel to populate UI in.
* @param {CssProperties} A css properties database.
*/
function StyleEditorUI(debuggee, target, panelDoc) {
function StyleEditorUI(debuggee, target, panelDoc, cssProperties) {
EventEmitter.decorate(this);
this._debuggee = debuggee;
this._target = target;
this._panelDoc = panelDoc;
this._cssProperties = cssProperties;
this._window = this._panelDoc.defaultView;
this._root = this._panelDoc.getElementById("style-editor-chrome");
@ -603,7 +605,7 @@ StyleEditorUI.prototype = {
// only initialize source editor when we switch to this view
let inputElement =
details.querySelector(".stylesheet-editor-input");
yield showEditor.load(inputElement);
yield showEditor.load(inputElement, this._cssProperties);
}
showEditor.onShow();

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

@ -417,11 +417,13 @@ StyleSheetEditor.prototype = {
* Create source editor and load state into it.
* @param {DOMElement} inputElement
* Element to load source editor in
* @param {CssProperties} cssProperties
* A css properties database.
*
* @return {Promise}
* Promise that will resolve when the style editor is loaded.
*/
load: function (inputElement) {
load: function (inputElement, cssProperties) {
if (this._isDestroyed) {
return promise.reject("Won't load source editor as the style sheet has " +
"already been removed from Style Editor.");
@ -438,7 +440,8 @@ StyleSheetEditor.prototype = {
extraKeys: this._getKeyBindings(),
contextMenu: "sourceEditorContextMenu",
autocomplete: Services.prefs.getBoolPref(AUTOCOMPLETION_PREF),
autocompleteOpts: { walker: this.walker }
autocompleteOpts: { walker: this.walker, cssProperties },
cssProperties
};
let sourceEditor = this._sourceEditor = new Editor(config);

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

@ -12,6 +12,7 @@ var EventEmitter = require("devtools/shared/event-emitter");
var {StyleEditorUI} = require("resource://devtools/client/styleeditor/StyleEditorUI.jsm");
var {getString} = require("resource://devtools/client/styleeditor/StyleEditorUtil.jsm");
var {initCssProperties} = require("devtools/shared/fronts/css-properties");
loader.lazyGetter(this, "StyleSheetsFront",
() => require("devtools/shared/fronts/stylesheets").StyleSheetsFront);
@ -60,8 +61,12 @@ StyleEditorPanel.prototype = {
this._debuggee = StyleEditorFront(this.target.client, this.target.form);
}
// Initialize the CSS properties database.
const {cssProperties} = yield initCssProperties(this._toolbox);
// Initialize the UI
this.UI = new StyleEditorUI(this._debuggee, this.target, this._panelDoc);
this.UI = new StyleEditorUI(this._debuggee, this.target, this._panelDoc,
cssProperties);
this.UI.on("error", this._showError);
yield this.UI.initialize();

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

@ -8,6 +8,7 @@
const TESTCASE_URI = TEST_BASE_HTTP + "autocomplete.html";
const MAX_SUGGESTIONS = 15;
const {getClientCssProperties} = require("devtools/shared/fronts/css-properties");
const {CSSProperties, CSSValues} = getCSSKeywords();
// Test cases to test that autocompletion works correctly when enabled.
@ -195,12 +196,11 @@ function checkState(index, sourceEditor, popup) {
* CSS values the property can have.
*/
function getCSSKeywords() {
let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
.getService(Ci.inIDOMUtils);
let cssProperties = getClientCssProperties();
let props = {};
let propNames = domUtils.getCSSPropertyNames(domUtils.INCLUDE_ALIASES);
let propNames = cssProperties.getNames();
propNames.forEach(prop => {
props[prop] = domUtils.getCSSValuesForProperty(prop).sort();
props[prop] = cssProperties.getValues(prop).sort();
});
return {
CSSValues: props,

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

@ -109,6 +109,15 @@ CssProperties.prototype = {
*/
getValues(property) {
return this.properties[property] ? this.properties[property].values : [];
},
/**
* Gets the CSS property names.
*
* @return {Array} An array of strings.
*/
getNames(property) {
return Object.keys(this.properties);
}
};
@ -140,7 +149,7 @@ const initCssProperties = Task.async(function* (toolbox) {
if (!serverDB.properties && !serverDB.margin) {
db = CSS_PROPERTIES_DB;
} else {
db = normalizeCssData(serverDB);
db = serverDB;
}
} else {
// The target does not support this actor, so require a static list of supported
@ -148,10 +157,7 @@ const initCssProperties = Task.async(function* (toolbox) {
db = CSS_PROPERTIES_DB;
}
// Color values are omitted to save on space. Add them back here.
reattachCssColorValues(db);
const cssProperties = new CssProperties(db);
const cssProperties = new CssProperties(normalizeCssData(db));
cachedCssProperties.set(client, {cssProperties, front});
return {cssProperties, front};
});
@ -171,6 +177,16 @@ function getCssProperties(toolbox) {
return cachedCssProperties.get(toolbox.target.client).cssProperties;
}
/**
* Get a client-side CssProperties. This is useful for dependencies in tests, or parts
* of the codebase that don't particularly need to match every known CSS property on
* the target.
* @return {CssProperties}
*/
function getClientCssProperties() {
return new CssProperties(normalizeCssData(CSS_PROPERTIES_DB));
}
/**
* Get the current browser version.
* @returns {string} The browser version.
@ -186,37 +202,42 @@ function getClientBrowserVersion(toolbox) {
/**
* Even if the target has the cssProperties actor, the returned data may not be in the
* same shape or have all of the data we need. This normalizes this data.
* same shape or have all of the data we need. This normalizes the data and fills in
* any missing information like color values.
*
* @return {Object} The normalized CSS database.
*/
function normalizeCssData(db) {
// Firefox 49's getCSSDatabase() just returned the properties object, but
// now it returns an object with multiple types of CSS information.
if (!db.properties) {
db = { properties: db };
}
if (db !== CSS_PROPERTIES_DB) {
// Firefox 49's getCSSDatabase() just returned the properties object, but
// now it returns an object with multiple types of CSS information.
if (!db.properties) {
db = { properties: db };
}
// Fill in any missing DB information from the static database.
db = Object.assign({}, CSS_PROPERTIES_DB, db);
// Fill in any missing DB information from the static database.
db = Object.assign({}, CSS_PROPERTIES_DB, db);
// Add "supports" information to the css properties if it's missing.
if (!db.properties.color.supports) {
for (let name in db.properties) {
if (typeof CSS_PROPERTIES_DB.properties[name] === "object") {
db.properties[name].supports = CSS_PROPERTIES_DB.properties[name].supports;
// Add "supports" information to the css properties if it's missing.
if (!db.properties.color.supports) {
for (let name in db.properties) {
if (typeof CSS_PROPERTIES_DB.properties[name] === "object") {
db.properties[name].supports = CSS_PROPERTIES_DB.properties[name].supports;
}
}
}
// Add "values" information to the css properties if it's missing.
if (!db.properties.color.values) {
for (let name in db.properties) {
if (typeof CSS_PROPERTIES_DB.properties[name] === "object") {
db.properties[name].values = CSS_PROPERTIES_DB.properties[name].values;
}
}
}
}
// Add "values" information to the css properties if it's missing.
if (!db.properties.color.values) {
for (let name in db.properties) {
if (typeof CSS_PROPERTIES_DB.properties[name] === "object") {
db.properties[name].values = CSS_PROPERTIES_DB.properties[name].values;
}
}
}
reattachCssColorValues(db);
return db;
}
@ -243,5 +264,6 @@ module.exports = {
CssPropertiesFront,
CssProperties,
getCssProperties,
getClientCssProperties,
initCssProperties
};

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

@ -174,14 +174,16 @@ Animation::SetEffectNoUpdate(AnimationEffectReadOnly* aEffect)
prevAnim->SetEffect(nullptr);
}
// Create links with the new effect.
// Create links with the new effect. SetAnimation(this) will also update
// mIsRelevant of this animation, and then notify mutation observer if
// needed by calling Animation::UpdateRelevance(), so we don't need to
// call it again.
mEffect = newEffect;
mEffect->SetAnimation(this);
// Update relevance and then notify possible add or change.
// Notify possible add or change.
// If the target is different, the change notification will be ignored by
// AutoMutationBatchForAnimation.
UpdateRelevance();
if (wasRelevant && mIsRelevant) {
nsNodeUtils::AnimationChanged(this);
}

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

@ -104,13 +104,7 @@ KeyframeEffectReadOnly::NotifyAnimationTimingUpdated()
// animation cascade for this element whenever that changes.
bool inEffect = IsInEffect();
if (inEffect != mInEffectOnLastAnimationTimingUpdate) {
if (mTarget) {
EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
mTarget->mPseudoType);
if (effectSet) {
effectSet->MarkCascadeNeedsUpdate();
}
}
MarkCascadeNeedsUpdate();
mInEffectOnLastAnimationTimingUpdate = inEffect;
}
@ -305,15 +299,9 @@ KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
CalculateCumulativeChangeHint(aStyleContext);
if (mTarget) {
EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
mTarget->mPseudoType);
if (effectSet) {
effectSet->MarkCascadeNeedsUpdate();
}
MarkCascadeNeedsUpdate();
RequestRestyle(EffectCompositor::RestyleType::Layer);
}
RequestRestyle(EffectCompositor::RestyleType::Layer);
}
void
@ -569,14 +557,6 @@ KeyframeEffectReadOnly::ConstructKeyframeEffect(
return effect.forget();
}
void
KeyframeEffectReadOnly::ResetWinsInCascade()
{
for (AnimationProperty& property : mProperties) {
property.mWinsInCascade = false;
}
}
void
KeyframeEffectReadOnly::UpdateTargetRegistration()
{
@ -1234,18 +1214,17 @@ KeyframeEffectReadOnly::SetAnimation(Animation* aAnimation)
mAnimation = aAnimation;
// Restyle for the new animation.
RequestRestyle(EffectCompositor::RestyleType::Layer);
if (mTarget) {
EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
mTarget->mPseudoType);
if (effectSet) {
effectSet->MarkCascadeNeedsUpdate();
}
// The order of these function calls is important:
// NotifyAnimationTimingUpdated() need the updated mIsRelevant flag to check
// if it should create the effectSet or not, and MarkCascadeNeedsUpdate()
// needs a valid effectSet, so we should call them in this order.
if (mAnimation) {
mAnimation->UpdateRelevance();
}
NotifyAnimationTimingUpdated();
if (mAnimation) {
MarkCascadeNeedsUpdate();
}
}
bool
@ -1283,6 +1262,21 @@ KeyframeEffectReadOnly::MaybeUpdateFrameForCompositor()
}
}
void
KeyframeEffectReadOnly::MarkCascadeNeedsUpdate()
{
if (!mTarget) {
return;
}
EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
mTarget->mPseudoType);
if (!effectSet) {
return;
}
effectSet->MarkCascadeNeedsUpdate();
}
//---------------------------------------------------------------------
//
// KeyframeEffect
@ -1361,7 +1355,9 @@ KeyframeEffect::SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget)
if (mTarget) {
UnregisterTarget();
ResetIsRunningOnCompositor();
ResetWinsInCascade();
// We don't need to reset the mWinsInCascade member since it will be updated
// when we later associate with a different target (and until that time this
// flag is not used).
RequestRestyle(EffectCompositor::RestyleType::Layer);

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

@ -319,8 +319,6 @@ protected:
const OptionsType& aOptions,
ErrorResult& aRv);
void ResetWinsInCascade();
// This effect is registered with its target element so long as:
//
// (a) It has a target element, and
@ -351,6 +349,10 @@ protected:
already_AddRefed<nsStyleContext>
GetTargetStyleContext();
// A wrapper for marking cascade update according to the current
// target and its effectSet.
void MarkCascadeNeedsUpdate();
Maybe<OwningAnimationTarget> mTarget;
KeyframeEffectParams mEffectOptions;

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

@ -560,5 +560,199 @@ promise_test(function(t) {
}, 'Clearing *important* opacity style on the target element sends the ' +
'animation to the compositor');
promise_test(function(t) {
var div = addDiv(t);
var firstAnimation = div.animate({ opacity: [1, 0] }, 100 * MS_PER_SEC);
var secondAnimation = div.animate({ opacity: [0, 1] }, 100 * MS_PER_SEC);
var another = addDiv(t);
return Promise.all([firstAnimation.ready, secondAnimation.ready]).then(function() {
assert_equals(secondAnimation.isRunningOnCompositor, omtaEnabled,
'The second opacity animation on an element reports that ' +
'it is running on the compositor');
assert_equals(firstAnimation.isRunningOnCompositor, false,
'The first opacity animation on the same element reports ' +
'that it is NOT running on the compositor');
firstAnimation.effect.target = another;
return waitForFrame();
}).then(function() {
assert_equals(secondAnimation.isRunningOnCompositor, omtaEnabled,
'The second opacity animation on the element keeps ' +
'running on the compositor after the preiously overridden ' +
'animation is applied to a different element');
assert_equals(firstAnimation.isRunningOnCompositor, omtaEnabled,
'The previously overridden opacity animation reports that ' +
'it it running on the compositor after being applied to a ' +
'different element');
});
}, 'Active animation which was not running on the compositor due to ' +
'composite order starts running on the compositor after changing ' +
'the target element');
promise_test(function(t) {
var div = addDiv(t);
var firstAnimation = div.animate({ opacity: [1, 0] }, 100 * MS_PER_SEC);
var secondAnimation = div.animate({ opacity: [0, 1] }, 100 * MS_PER_SEC);
var another = addDiv(t);
return Promise.all([firstAnimation.ready, secondAnimation.ready]).then(function() {
assert_equals(secondAnimation.isRunningOnCompositor, omtaEnabled,
'The second opacity animation on an element reports that ' +
'it is running on the compositor');
assert_equals(firstAnimation.isRunningOnCompositor, false,
'The first opacity animation on the same element reports ' +
'that it is NOT running on the compositor');
secondAnimation.effect.target = another;
return waitForFrame();
}).then(function() {
assert_equals(secondAnimation.isRunningOnCompositor, omtaEnabled,
'The second opacity animation continues to run on the ' +
'compositor after being applied to a different element');
assert_equals(firstAnimation.isRunningOnCompositor, omtaEnabled,
'The previously overridden opacity animation now reports ' +
'that it is running on the compositor after the animation ' +
'that was overridding it is applied to a different element');
});
}, 'Animation which was overridden and, as a result, not running on the ' +
'compositor begins running on the compositor after higher-priority ' +
'animation is applied to a different element');
promise_test(function(t) {
var div = addDiv(t);
var another = addDiv(t);
var animation = div.animate({ opacity: [1, 0] }, 100 * MS_PER_SEC);
var anotherAnimation = another.animate({ opacity: [0, 1] }, 100 * MS_PER_SEC);
return Promise.all([animation.ready, anotherAnimation.ready]).then(function() {
assert_equals(anotherAnimation.isRunningOnCompositor, omtaEnabled,
'An opacity animation on an element reports that ' +
'it is running on the compositor');
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Opacity animation running on a different element reports ' +
'that it is running on the compositor');
anotherAnimation.effect.target = div;
return waitForFrame();
}).then(function() {
assert_equals(anotherAnimation.isRunningOnCompositor, omtaEnabled,
'Animation continues to run on the compositor after ' +
'being applied to a different element with a ' +
'lower-priority animation');
assert_equals(animation.isRunningOnCompositor, false,
'Animation stops running on the compositor after ' +
'a higher-priority animation originally applied to ' +
'a different element is applied to the same element');
});
}, 'Moving a higher-priority animation to an element which already has the ' +
'same property animation running on the compositor makes the initial ' +
'animation stop running on the compositor');
promise_test(function(t) {
var div = addDiv(t);
var importantOpacityElement = addDiv(t, { style: "opacity: 1 ! important" });
var animation = div.animate({ opacity: [1, 0] }, 100 * MS_PER_SEC);
return animation.ready.then(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Opacity animation on an element reports ' +
'that it is running on the compositor');
animation.effect.target = null;
return waitForFrame();
}).then(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation is no longer running on the compositor after ' +
'removing from the element');
animation.effect.target = importantOpacityElement;
return waitForFrame();
}).then(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation is NOT running on the compositor even after ' +
'being applied to a different element which has an ' +
'!important opacity declaration');
});
}, 'Animation continues not running on the compositor after being ' +
'applied to an element which has an important declaration and ' +
'having previously been temporarily associated with no target element');
promise_test(function(t) {
var div = addDiv(t);
var another = addDiv(t);
var lowerAnimation = div.animate({ opacity: [1, 0] }, 100 * MS_PER_SEC);
var higherAnimation = another.animate({ opacity: [0, 1] }, 100 * MS_PER_SEC);
return Promise.all([lowerAnimation.ready, higherAnimation.ready]).then(function() {
assert_equals(lowerAnimation.isRunningOnCompositor, omtaEnabled,
'An opacity animation on an element reports that ' +
'it is running on the compositor');
assert_equals(higherAnimation.isRunningOnCompositor, omtaEnabled,
'Opacity animation on a different element reports ' +
'that it is running on the compositor');
lowerAnimation.effect.target = null;
return waitForFrame();
}).then(function() {
assert_equals(lowerAnimation.isRunningOnCompositor, false,
'Animation is no longer running on the compositor after ' +
'being removed from the element');
lowerAnimation.effect.target = another;
return waitForFrame();
}).then(function() {
assert_equals(lowerAnimation.isRunningOnCompositor, false,
'A lower-priority animation does NOT begin running ' +
'on the compositor after being applied to an element ' +
'which has a higher-priority animation');
assert_equals(higherAnimation.isRunningOnCompositor, omtaEnabled,
'A higher-priority animation continues to run on the ' +
'compositor even after a lower-priority animation is ' +
'applied to the same element');
});
}, 'Animation continues not running on the compositor after being applied ' +
'to an element which has a higher-priority animation and after ' +
'being remporarily associated with no target element');
promise_test(function(t) {
var div = addDiv(t);
var another = addDiv(t);
var lowerAnimation = div.animate({ opacity: [1, 0] }, 100 * MS_PER_SEC);
var higherAnimation = another.animate({ opacity: [0, 1] }, 100 * MS_PER_SEC);
return Promise.all([lowerAnimation.ready, higherAnimation.ready]).then(function() {
assert_equals(lowerAnimation.isRunningOnCompositor, omtaEnabled,
'An opacity animation on an element reports that ' +
'it is running on the compositor');
assert_equals(higherAnimation.isRunningOnCompositor, omtaEnabled,
'Opacity animation on a different element reports ' +
'that it is running on the compositor');
higherAnimation.effect.target = null;
return waitForFrame();
}).then(function() {
assert_equals(higherAnimation.isRunningOnCompositor, false,
'Animation is no longer running on the compositor after ' +
'being removed from the element');
higherAnimation.effect.target = div;
return waitForFrame();
}).then(function() {
assert_equals(lowerAnimation.isRunningOnCompositor, false,
'Animation stops running on the compositor after ' +
'a higher-priority animation applied to the same element');
assert_equals(higherAnimation.isRunningOnCompositor, omtaEnabled,
'A higher-priority animation begins to running on the ' +
'compositor after being applied to an element which has ' +
'a lower-priority-animation');
});
}, 'Animation begins running on the compositor after being applied ' +
'to an element which has a lower-priority animation once after ' +
'disassociating with an element');
</script>
</body>

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

@ -45,10 +45,9 @@ Link::~Link()
bool
Link::ElementHasHref() const
{
return ((!mElement->IsSVGElement() &&
mElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href))
|| (!mElement->IsHTMLElement() &&
mElement->HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)));
return mElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href) ||
(!mElement->IsHTMLElement() &&
mElement->HasAttr(kNameSpaceID_XLink, nsGkAtoms::href));
}
void

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

@ -120,10 +120,6 @@
#include "mozilla/DetailedPromise.h"
#endif
#ifdef MOZ_WIDGET_GONK
#include <cutils/properties.h>
#endif
namespace mozilla {
namespace dom {
@ -1639,157 +1635,6 @@ Navigator::PublishServer(const nsAString& aName,
return domPromise.forget();
}
already_AddRefed<Promise>
Navigator::GetFeature(const nsAString& aName, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
RefPtr<Promise> p = Promise::Create(go, aRv);
if (aRv.Failed()) {
return nullptr;
}
#if defined(XP_LINUX)
if (aName.EqualsLiteral("hardware.memory")) {
// with seccomp enabled, fopen() should be in a non-sandboxed process
if (XRE_IsParentProcess()) {
uint32_t memLevel = mozilla::hal::GetTotalSystemMemoryLevel();
if (memLevel == 0) {
p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
return p.forget();
}
p->MaybeResolve((int)memLevel);
} else {
mozilla::dom::ContentChild* cc =
mozilla::dom::ContentChild::GetSingleton();
RefPtr<Promise> ipcRef(p);
cc->SendGetSystemMemory(reinterpret_cast<uint64_t>(ipcRef.forget().take()));
}
return p.forget();
} // hardware.memory
#endif
#ifdef MOZ_WIDGET_GONK
if (StringBeginsWith(aName, NS_LITERAL_STRING("acl.")) &&
(aName.EqualsLiteral("acl.version") || CheckPermission("external-app"))) {
char value[PROPERTY_VALUE_MAX];
nsCString propertyKey("persist.");
propertyKey.Append(NS_ConvertUTF16toUTF8(aName));
uint32_t len = property_get(propertyKey.get(), value, nullptr);
if (len > 0) {
p->MaybeResolve(NS_ConvertUTF8toUTF16(value));
return p.forget();
}
}
#endif
// Mirror the dom.apps.developer_mode pref to let apps get it read-only.
if (aName.EqualsLiteral("dom.apps.developer_mode")) {
p->MaybeResolve(Preferences::GetBool("dom.apps.developer_mode", false));
return p.forget();
}
p->MaybeResolveWithUndefined();
return p.forget();
}
already_AddRefed<Promise>
Navigator::HasFeature(const nsAString& aName, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
RefPtr<Promise> p = Promise::Create(go, aRv);
if (aRv.Failed()) {
return nullptr;
}
// Hardcoded extensions features which are b2g specific.
#ifdef MOZ_B2G
if (aName.EqualsLiteral("web-extensions") ||
aName.EqualsLiteral("late-customization")) {
p->MaybeResolve(true);
return p.forget();
}
#endif
// Hardcoded manifest features. Some are still b2g specific.
const char manifestFeatures[][64] = {
"manifest.origin"
, "manifest.redirects"
#ifdef MOZ_B2G
, "manifest.chrome.navigation"
, "manifest.precompile"
, "manifest.role.homescreen"
#endif
};
nsAutoCString feature = NS_ConvertUTF16toUTF8(aName);
for (uint32_t i = 0; i < MOZ_ARRAY_LENGTH(manifestFeatures); i++) {
if (feature.Equals(manifestFeatures[i])) {
p->MaybeResolve(true);
return p.forget();
}
}
NS_NAMED_LITERAL_STRING(apiWindowPrefix, "api.window.");
if (StringBeginsWith(aName, apiWindowPrefix)) {
const nsAString& featureName = Substring(aName, apiWindowPrefix.Length());
// Temporary hardcoded entry points due to technical constraints
if (featureName.EqualsLiteral("Navigator.mozTCPSocket")) {
p->MaybeResolve(Preferences::GetBool("dom.mozTCPSocket.enabled"));
return p.forget();
}
if (featureName.EqualsLiteral("Navigator.mozMobileConnections") ||
featureName.EqualsLiteral("MozMobileNetworkInfo")) {
p->MaybeResolve(Preferences::GetBool("dom.mobileconnection.enabled"));
return p.forget();
}
if (featureName.EqualsLiteral("Navigator.mozInputMethod")) {
p->MaybeResolve(Preferences::GetBool("dom.mozInputMethod.enabled"));
return p.forget();
}
if (featureName.EqualsLiteral("Navigator.getDeviceStorage")) {
p->MaybeResolve(Preferences::GetBool("device.storage.enabled"));
return p.forget();
}
if (featureName.EqualsLiteral("Navigator.mozNetworkStats")) {
p->MaybeResolve(Preferences::GetBool("dom.mozNetworkStats.enabled"));
return p.forget();
}
if (featureName.EqualsLiteral("Navigator.push")) {
p->MaybeResolve(Preferences::GetBool("services.push.enabled"));
return p.forget();
}
if (featureName.EqualsLiteral("Navigator.mozAlarms")) {
p->MaybeResolve(Preferences::GetBool("dom.mozAlarms.enabled"));
return p.forget();
}
if (featureName.EqualsLiteral("Navigator.mozCameras")) {
p->MaybeResolve(true);
return p.forget();
}
if (featureName.EqualsLiteral("XMLHttpRequest.mozSystem")) {
p->MaybeResolve(true);
return p.forget();
}
p->MaybeResolveWithUndefined();
return p.forget();
}
// resolve with <undefined> because the feature name is not supported
p->MaybeResolveWithUndefined();
return p.forget();
}
PowerManager*
Navigator::GetMozPower(ErrorResult& aRv)
{

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

@ -185,13 +185,6 @@ public:
// NavigatorBinding::ClearCachedUserAgentValue(this);
void ClearUserAgentCache();
// Feature Detection API
already_AddRefed<Promise> GetFeature(const nsAString& aName,
ErrorResult& aRv);
already_AddRefed<Promise> HasFeature(const nsAString &aName,
ErrorResult& aRv);
bool Vibrate(uint32_t aDuration);
bool Vibrate(const nsTArray<uint32_t>& aDuration);
void SetVibrationPermission(bool aPermitted, bool aPersistent);

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

@ -593,6 +593,7 @@ nsIAtom** const kAttributesSVG[] = {
};
nsIAtom** const kURLAttributesSVG[] = {
&nsGkAtoms::href,
nullptr
};

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

@ -26,6 +26,4 @@ skip-if = buildapp == 'mulet'
[test_bug1008126.html]
[test_sandboxed_blob_uri.html]
[test_websocket_frame.html]
[test_getFeature_with_perm.html]
[test_hasFeature.html]
[test_mozbrowser_apis_allowed.html]

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

@ -1,135 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=979109
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 979109</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=983502">Mozilla Bug 983502</a>
<script type="application/javascript">
function testSupported() {
var mem;
navigator.getFeature("hardware.memory").then(function(mem) {
var isLinux = (navigator.platform.indexOf('Linux') != -1);
var isAndroid = !!navigator.userAgent.includes("Android");
var isB2G = !isAndroid && /Mobile|Tablet/.test(navigator.userAgent);
if (isLinux) {
info("It is Linux version:");
}
if (isAndroid) {
info("It is Android version");
}
if (isB2G) {
info("It is B2G version");
}
if (isLinux || isAndroid || isB2G) {
ok(typeof mem === 'number' && (mem) % 1 === 0, "We should receive an integer on this platform");
ok(mem > 0, "hardware.memory is supported on this platform. mem=" + mem + "MiB");
} else {
ok(typeof mem === 'undefined', "hardware.memory is not support on this platform");
}
runNextTest();
},function(mem) {
ok(false, "The Promise should not be rejected");
});
}
function testNotSupported() {
var tv;
navigator.getFeature("hardware.tv").then(function(tv) {
ok(typeof tv === 'undefined', "Resolve the Promise with undefined value (hardware.tv)");
runNextTest();
},function(tv) {
ok(false, "The Promise should not be rejected");
});
}
function testNotSupportedManifest() {
navigator.getFeature("manifest.origin").then(function(feature) {
ok(typeof feature == 'undefined', "manifest.* resolves with undefined on getFeature");
runNextTest();
}, function() {
ok(false, "The Promise should not be rejected");
});
}
function createManifestTest(aFeature) {
return function() {
var res;
navigator.hasFeature(aFeature).then(function(res) {
ok(res === true, "Resolve the Promise with 'true' for " + aFeature);
runNextTest();
}, function(tv) {
ok(false, "The Promise should not be rejected");
});
}
}
function testDevMode(aExpected) {
return function() {
navigator.getFeature("dom.apps.developer_mode").then(res => {
is(res, aExpected, "dom.apps.developer_mode is " + aExpected);
runNextTest();
}, function() {
ok(false, "The Promise should not be rejected");
});
}
}
function enableDevMode() {
SpecialPowers.pushPrefEnv({"set": [["dom.apps.developer_mode", true]]}, runNextTest);
}
var currentTest = -1;
var tests = [
testNotSupported,
testNotSupportedManifest,
testSupported,
createManifestTest("manifest.origin"),
createManifestTest("manifest.redirects"),
testDevMode(false),
enableDevMode,
testDevMode(true)
];
function runNextTest() {
currentTest++;
if (currentTest < tests.length) {
tests[currentTest]();
} else {
SimpleTest.finish();
}
}
info("About to run " + tests.length + " tests");
ok('getFeature' in navigator, "navigator.getFeature should exist");
ok('hasFeature' in navigator, "navigator.hasFeature should exist");
// B2G specific manifest features.
// Touching navigator before pushPermissions makes it fail.
if (!navigator.userAgent.includes("Android") &&
/Mobile|Tablet/.test(navigator.userAgent)) {
info("Adding B2G specific tests");
tests.push(createManifestTest("manifest.chrome.navigation"));
tests.push(createManifestTest("manifest.precompile"));
tests.push(createManifestTest("manifest.role.homescreen"));
}
runNextTest();
ok(true, "Test DONE");
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>

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

@ -1,101 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1009645
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1009645</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1009645">Mozilla Bug 1009645</a>
<script type="application/javascript">
var b2gOnly;
function pref(name) {
try {
return SpecialPowers.getBoolPref(name);
} catch (e) {
return false;
}
}
function testAPIs() {
var APIEndPoints = [
{ name: "MozMobileNetworkInfo", enabled: pref("dom.mobileconnection.enabled") },
// { name: "Navigator.mozBluetooth", enabled: b2gOnly }, // conditional on MOZ_B2G_BT, tricky to test
// Bug 1266035 { name: "Navigator.mozContacts", enabled: pref("dom.mozContacts.enabled") },
{ name: "Navigator.getDeviceStorage", enabled: pref("device.storage.enabled") },
// Bug 1266035 { name: "Navigator.addIdleObserver", enabled: true },
{ name: "Navigator.mozNetworkStats", enabled: pref("dom.mozNetworkStats.enabled") },
{ name: "Navigator.push", enabled: pref("services.push.enabled") },
// { name: "Navigator.mozTime", enabled: b2gOnly }, // conditional on MOZ_TIME_MANAGER, tricky to test
// { name: "Navigator.mozFMRadio", enabled: b2gOnly }, // conditional on MOZ_B2G_FM, tricky to test
{ name: "Navigator.mozCameras", enabled: true },
{ name: "Navigator.mozAlarms", enabled: pref("dom.mozAlarms.enabled") },
{ name: "Navigator.mozTCPSocket", enabled: pref("dom.mozTCPSocket.enabled") },
{ name: "Navigator.mozInputMethod", enabled: pref("dom.mozInputMethod.enabled") },
{ name: "Navigator.mozMobileConnections", enabled: pref("dom.mobileconnection.enabled") },
{ name: "XMLHttpRequest.mozSystem", enabled: true }
];
var promises = [];
APIEndPoints.forEach(function(v) {
promises.push(navigator.hasFeature("api.window." + v.name));
});
return Promise.all(promises).then(function(values) {
for (var i = 0; i < values.length; ++i) {
is(values[i], APIEndPoints[i].enabled,
"Endpoint " + APIEndPoints[i].name + " resolved with the correct value. " +
"If this is failing because you're changing how an API is exposed, you " +
"must contact the Marketplace team to let them know about the change.");
}
}, function() {
ok(false, "The Promise should not be rejected");
});
}
function testExtensions() {
if (!b2gOnly) {
return Promise.resolve();
}
var builtInFeatures = [
{feature: "web-extensions", value: true},
{feature: "late-customization", value: true}
];
builtInFeatures.forEach(function(x) {
navigator.hasFeature(x.feature).then(function(value) {
is(value, x.value, "Resolve the Promise with " + value + " for feature: " + x.feature);
}).catch(function(ex) {
ok(false, "The Promise should not be rejected");
});
});
return Promise.resolve();
}
SpecialPowers.pushPermissions([
{type: "feature-detection", allow: true, context: document}
], function() {
b2gOnly = (function() {
var isAndroid = !!navigator.userAgent.includes("Android");
var isMulet = pref("b2g.is_mulet");
var isB2g = isMulet || (!isAndroid && /Mobile|Tablet/.test(navigator.userAgent));
return isB2g ? true : undefined;
})();
ok('hasFeature' in navigator, "navigator.hasFeature should exist");
testAPIs().then(testExtensions).catch(function(e) {
ok(false, "The Promise should not be rejected: " + e);
}).then(SimpleTest.finish);
});
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>

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

@ -789,39 +789,25 @@ BrowserElementParent.prototype = {
radiisX, radiisY, rotationAngles, forces,
count, modifiers) {
let tabParent = this._frameLoader.tabParent;
if (tabParent && tabParent.useAsyncPanZoom) {
tabParent.injectTouchEvent(type,
identifiers,
touchesX,
touchesY,
radiisX,
radiisY,
rotationAngles,
forces,
count,
modifiers);
} else {
let offset = this.getChildProcessOffset();
for (var i = 0; i < touchesX.length; i++) {
touchesX[i] += offset.x;
}
for (var i = 0; i < touchesY.length; i++) {
touchesY[i] += offset.y;
}
this._sendAsyncMsg("send-touch-event", {
"type": type,
"identifiers": identifiers,
"touchesX": touchesX,
"touchesY": touchesY,
"radiisX": radiisX,
"radiisY": radiisY,
"rotationAngles": rotationAngles,
"forces": forces,
"count": count,
"modifiers": modifiers
});
let offset = this.getChildProcessOffset();
for (var i = 0; i < touchesX.length; i++) {
touchesX[i] += offset.x;
}
for (var i = 0; i < touchesY.length; i++) {
touchesY[i] += offset.y;
}
this._sendAsyncMsg("send-touch-event", {
"type": type,
"identifiers": identifiers,
"touchesX": touchesX,
"touchesY": touchesY,
"radiisX": radiisX,
"radiisY": radiisY,
"rotationAngles": rotationAngles,
"forces": forces,
"count": count,
"modifiers": modifiers
});
}),
getCanGoBack: defineDOMRequestMethod('get-can-go-back'),

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

@ -77,17 +77,6 @@ void main() {
color = (a == 2.0) ? vec4(0, 1.0, 0, 1.0) : vec4(1.0, 0, 0, 1.0);
}
</script>
<script id="fshader-sequence-operator" type="x-shader/x-fragment">#version 300 es
precision mediump float;
out vec4 color;
void main() {
float a[2] = float[2](1.0, 0.0);
float b[2] = float[2](2.0, 3.0);
float c = (a, b)[0];
color = (c == 2.0) ? vec4(0, 1.0, 0, 1.0) : vec4(1.0, 0, 0, 1.0);
}
</script>
<script type="application/javascript">
"use strict";
description("Indexing complex array expressions");
@ -112,12 +101,6 @@ GLSLConformanceTester.runRenderTests([
linkSuccess: true,
passMsg: 'Test indexing an array initialization: (float[3](2.0, 1.0, 0.0))[0]'
},
{
fShaderId: 'fshader-sequence-operator',
fShaderSuccess: true,
linkSuccess: true,
passMsg: 'Test indexing a sequence operator: (a, b)[0]'
},
], 2);
</script>

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

@ -23,7 +23,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=456273
/** Test for Bug 456273 **/
function doTest() {
var ev = document.createEvent('KeyEvents');
var ev = document.createEvent('KeyboardEvent');
ev.initKeyEvent("keypress", true, true, null, true, false,
false, false, 0, "z".charCodeAt(0));
SpecialPowers.dispatchEvent(window, document.getElementById('edit456273'), ev);

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

@ -39,7 +39,7 @@ function fireDrop(element, shouldAllowDrop, shouldAllowOnlyChromeDrop) {
ds.startDragSession();
var event = document.createEvent("DragEvents");
var event = document.createEvent("DragEvent");
event.initDragEvent("dragover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
fireEvent(element, event);
@ -47,7 +47,7 @@ function fireDrop(element, shouldAllowDrop, shouldAllowOnlyChromeDrop) {
is(ds.getCurrentSession().onlyChromeDrop, shouldAllowOnlyChromeDrop,
"Unexpected .onlyChromeDrop");
event = document.createEvent("DragEvents");
event = document.createEvent("DragEvent");
event.initDragEvent("drop", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
fireEvent(element, event);

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

@ -60,7 +60,7 @@ function RunTest() {
window.removeEventListener("dragstart", trapDrag, true);
synthesizeMouse(image, 20, 20, { type: "mouseup" });
var event = document.createEvent("DragEvents");
var event = document.createEvent("DragEvent");
event.initDragEvent("dragover", true, true, iBox.ownerDocument.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, iBox, dataTransfer);
fireEvent(iBox, event);
synthesizeMouse(image, 3, 3, { type: "mousedown" });

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

@ -42,22 +42,22 @@ function testInitializingUntrustedEvent()
ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
keyCode: 0x30, charCode: 0x40 },
{ createEventArg: "KeyEvents",
{ createEventArg: "KeyBoardEvent",
type: "foo", bubbles: true, cancelable: true, view: null,
ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
keyCode: 0x00, charCode: 0x50 },
{ createEventArg: "keyevents",
{ createEventArg: "keyboardevEnt",
type: "bar", bubbles: false, cancelable: true, view: window,
ctrlKey: true, altKey: true, shiftKey: false, metaKey: false,
keyCode: 0x00, charCode: 0x60 },
{ createEventArg: "Keyevents",
{ createEventArg: "KeyboaRdevent",
type: "keydown", bubbles: true, cancelable: false, view: null,
ctrlKey: false, altKey: true, shiftKey: false, metaKey: true,
keyCode: 0x30, charCode: 0x00 },
{ createEventArg: "keyEvents",
{ createEventArg: "KEYBOARDEVENT",
type: "keyup", bubbles: false, cancelable: false, view: window,
ctrlKey: true, altKey: false, shiftKey: true, metaKey: false,
keyCode: 0x10, charCode: 0x80 },

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

@ -57,8 +57,8 @@ function afterDragTests()
false, true, false, false, 0, null, null);
$("synthetic").dispatchEvent(evt);
var evt = document.createEvent("dragevents");
ok(evt instanceof DragEvent, "synthetic dragevents class")
var evt = document.createEvent("dragevent");
ok(evt instanceof DragEvent, "synthetic dragevent class")
evt.initDragEvent("dragover", true, true, window, 0, 40, 35, 20, 15,
true, false, true, true, 2, document.documentElement, null);
$("synthetic2").dispatchEvent(evt);

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

@ -171,6 +171,16 @@ FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(nsPIDOMWindowInner* aOwner,
, mHttpServer(new HttpServer())
{
LOG_I("FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(%p)", this);
}
void
FlyWebPublishedServerImpl::PermissionGranted(bool aGranted)
{
LOG_I("FlyWebPublishedServerImpl::PermissionGranted(%b)", aGranted);
if (!aGranted) {
PublishedServerStarted(NS_ERROR_FAILURE);
return;
}
mHttpServer->Init(-1, Preferences::GetBool("flyweb.use-tls", false), this);
}
@ -252,25 +262,37 @@ FlyWebPublishedServerChild::FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwne
const nsAString& aName,
const FlyWebPublishOptions& aOptions)
: FlyWebPublishedServer(aOwner, aName, aOptions)
, mActorDestroyed(false)
, mActorExists(false)
{
LOG_I("FlyWebPublishedServerChild::FlyWebPublishedServerChild(%p)", this);
ContentChild::GetSingleton()->
SendPFlyWebPublishedServerConstructor(this,
PromiseFlatString(aName),
aOptions);
// The matching release happens when the actor is destroyed, in
// ContentChild::DeallocPFlyWebPublishedServerChild
NS_ADDREF_THIS();
}
void
FlyWebPublishedServerChild::PermissionGranted(bool aGranted)
{
if (!aGranted) {
PublishedServerStarted(NS_ERROR_FAILURE);
return;
}
mActorExists = true;
FlyWebPublishOptions options;
options.mUiUrl = mUiUrl;
// Proceed with initialization.
ContentChild::GetSingleton()->
SendPFlyWebPublishedServerConstructor(this, mName, options);
}
bool
FlyWebPublishedServerChild::RecvServerReady(const nsresult& aStatus)
{
LOG_I("FlyWebPublishedServerChild::RecvServerReady(%p)", this);
MOZ_ASSERT(!mActorDestroyed);
MOZ_ASSERT(mActorExists);
PublishedServerStarted(aStatus);
return true;
@ -280,7 +302,7 @@ bool
FlyWebPublishedServerChild::RecvServerClose()
{
LOG_I("FlyWebPublishedServerChild::RecvServerClose(%p)", this);
MOZ_ASSERT(!mActorDestroyed);
MOZ_ASSERT(mActorExists);
Close();
@ -292,7 +314,7 @@ FlyWebPublishedServerChild::RecvFetchRequest(const IPCInternalRequest& aRequest,
const uint64_t& aRequestId)
{
LOG_I("FlyWebPublishedServerChild::RecvFetchRequest(%p)", this);
MOZ_ASSERT(!mActorDestroyed);
MOZ_ASSERT(mActorExists);
RefPtr<InternalRequest> request = new InternalRequest(aRequest);
mPendingRequests.Put(request, aRequestId);
@ -307,7 +329,7 @@ FlyWebPublishedServerChild::RecvWebSocketRequest(const IPCInternalRequest& aRequ
PTransportProviderChild* aProvider)
{
LOG_I("FlyWebPublishedServerChild::RecvWebSocketRequest(%p)", this);
MOZ_ASSERT(!mActorDestroyed);
MOZ_ASSERT(mActorExists);
RefPtr<InternalRequest> request = new InternalRequest(aRequest);
mPendingRequests.Put(request, aRequestId);
@ -327,7 +349,7 @@ FlyWebPublishedServerChild::ActorDestroy(ActorDestroyReason aWhy)
{
LOG_I("FlyWebPublishedServerChild::ActorDestroy(%p)", this);
mActorDestroyed = true;
mActorExists = false;
}
void
@ -336,7 +358,7 @@ FlyWebPublishedServerChild::OnFetchResponse(InternalRequest* aRequest,
{
LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
if (mActorDestroyed) {
if (!mActorExists) {
LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
return;
}
@ -361,7 +383,7 @@ FlyWebPublishedServerChild::OnWebSocketAcceptInternal(InternalRequest* aRequest,
{
LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p)", this);
if (mActorDestroyed) {
if (!mActorExists) {
LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p) - No actor!", this);
return nullptr;
}
@ -400,7 +422,7 @@ FlyWebPublishedServerChild::OnWebSocketResponse(InternalRequest* aRequest,
{
LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
if (mActorDestroyed) {
if (!mActorExists) {
LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
return;
}
@ -428,7 +450,7 @@ FlyWebPublishedServerChild::Close()
FlyWebPublishedServer::Close();
if (!mActorDestroyed) {
if (mActorExists) {
LOG_I("FlyWebPublishedServerChild::Close - sending __delete__ (%p)", this);
Send__delete__(this);

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

@ -57,6 +57,8 @@ public:
aUiUrl = mUiUrl;
}
virtual void PermissionGranted(bool aGranted) = 0;
virtual void OnFetchResponse(InternalRequest* aRequest,
InternalResponse* aResponse) = 0;
already_AddRefed<WebSocket>

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

@ -50,6 +50,7 @@ public:
}
}
virtual void PermissionGranted(bool aGranted) override;
virtual void OnFetchResponse(InternalRequest* aRequest,
InternalResponse* aResponse) override;
virtual void OnWebSocketResponse(InternalRequest* aConnectRequest,
@ -98,6 +99,7 @@ public:
const nsAString& aName,
const FlyWebPublishOptions& aOptions);
virtual void PermissionGranted(bool aGranted) override;
virtual bool RecvServerReady(const nsresult& aStatus) override;
virtual bool RecvServerClose() override;
virtual bool RecvFetchRequest(const IPCInternalRequest& aRequest,
@ -125,7 +127,7 @@ private:
nsDataHashtable<nsRefPtrHashKey<InternalRequest>, uint64_t> mPendingRequests;
nsRefPtrHashtable<nsUint64HashKey, TransportProviderChild>
mPendingTransportProviders;
bool mActorDestroyed;
bool mActorExists;
};
class FlyWebPublishedServerParent final : public PFlyWebPublishedServerParent

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

@ -9,6 +9,7 @@
#include "mozilla/ScopeExit.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/FlyWebPublishedServerIPC.h"
#include "mozilla/AddonPathService.h"
#include "nsISocketTransportService.h"
#include "mdns/libmdns/nsDNSServiceInfo.h"
#include "nsIUUIDGenerator.h"
@ -18,6 +19,7 @@
#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
#include "prnetdb.h"
#include "DNS.h"
#include "nsContentPermissionHelper.h"
#include "nsSocketTransportService2.h"
#include "nsSocketTransport2.h"
#include "nsHashPropertyBag.h"
@ -34,11 +36,123 @@ struct FlyWebPublishOptions;
static LazyLogModule gFlyWebServiceLog("FlyWebService");
#undef LOG_I
#define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
#undef LOG_E
#define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Error, (__VA_ARGS__))
#undef LOG_TEST_I
#define LOG_TEST_I(...) MOZ_LOG_TEST(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug)
class FlyWebPublishServerPermissionCheck final
: public nsIContentPermissionRequest
, public nsIRunnable
{
public:
NS_DECL_ISUPPORTS
FlyWebPublishServerPermissionCheck(const nsCString& aServiceName, uint64_t aWindowID,
FlyWebPublishedServer* aServer)
: mServiceName(aServiceName)
, mWindowID(aWindowID)
, mServer(aServer)
{}
uint64_t WindowID() const
{
return mWindowID;
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
if (!globalWindow) {
return Cancel();
}
mWindow = globalWindow->AsInner();
if (NS_WARN_IF(!mWindow)) {
return Cancel();
}
nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
if (NS_WARN_IF(!doc)) {
return Cancel();
}
mPrincipal = doc->NodePrincipal();
MOZ_ASSERT(mPrincipal);
mRequester = new nsContentPermissionRequester(mWindow);
return nsContentPermissionUtils::AskPermission(this, mWindow);
}
NS_IMETHOD Cancel() override
{
Resolve(false);
return NS_OK;
}
NS_IMETHOD Allow(JS::HandleValue aChoices) override
{
MOZ_ASSERT(aChoices.isUndefined());
Resolve(true);
return NS_OK;
}
NS_IMETHOD GetTypes(nsIArray** aTypes) override
{
nsTArray<nsString> emptyOptions;
return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("flyweb-publish-server"),
NS_LITERAL_CSTRING("unused"), emptyOptions, aTypes);
}
NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override
{
NS_ENSURE_ARG_POINTER(aRequester);
nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
requester.forget(aRequester);
return NS_OK;
}
NS_IMETHOD GetPrincipal(nsIPrincipal** aRequestingPrincipal) override
{
NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
return NS_OK;
}
NS_IMETHOD GetWindow(mozIDOMWindow** aRequestingWindow) override
{
NS_IF_ADDREF(*aRequestingWindow = mWindow);
return NS_OK;
}
NS_IMETHOD GetElement(nsIDOMElement** aRequestingElement) override
{
*aRequestingElement = nullptr;
return NS_OK;
}
private:
void Resolve(bool aResolve)
{
mServer->PermissionGranted(aResolve);
}
virtual ~FlyWebPublishServerPermissionCheck() = default;
nsCString mServiceName;
uint64_t mWindowID;
RefPtr<FlyWebPublishedServer> mServer;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIContentPermissionRequester> mRequester;
};
NS_IMPL_ISUPPORTS(FlyWebPublishServerPermissionCheck,
nsIContentPermissionRequest,
nsIRunnable)
class FlyWebMDNSService final
: public nsIDNSServiceDiscoveryListener
, public nsIDNSServiceResolveListener
@ -841,6 +955,15 @@ FlyWebService::Init()
return ErrorResult(NS_OK);
}
static already_AddRefed<FlyWebPublishPromise>
MakeRejectionPromise(const char* name)
{
MozPromiseHolder<FlyWebPublishPromise> holder;
RefPtr<FlyWebPublishPromise> promise = holder.Ensure(name);
holder.Reject(NS_ERROR_FAILURE, name);
return promise.forget();
}
already_AddRefed<FlyWebPublishPromise>
FlyWebService::PublishServer(const nsAString& aName,
const FlyWebPublishOptions& aOptions,
@ -853,10 +976,7 @@ FlyWebService::PublishServer(const nsAString& aName,
if (existingServer) {
LOG_I("PublishServer: Trying to publish server with already-existing name %s.",
NS_ConvertUTF16toUTF8(aName).get());
MozPromiseHolder<FlyWebPublishPromise> holder;
RefPtr<FlyWebPublishPromise> promise = holder.Ensure(__func__);
holder.Reject(NS_ERROR_FAILURE, __func__);
return promise.forget();
return MakeRejectionPromise(__func__);
}
RefPtr<FlyWebPublishedServer> server;
@ -864,6 +984,49 @@ FlyWebService::PublishServer(const nsAString& aName,
server = new FlyWebPublishedServerChild(aWindow, aName, aOptions);
} else {
server = new FlyWebPublishedServerImpl(aWindow, aName, aOptions);
// Before proceeding, ensure that the FlyWeb system addon exists.
nsresult rv;
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("chrome://flyweb/skin/icon-64.png"));
if (NS_FAILED(rv)) {
return MakeRejectionPromise(__func__);
}
JSAddonId *addonId = MapURIToAddonID(uri);
if (!addonId) {
LOG_E("PublishServer: Failed to find FlyWeb system addon.");
return MakeRejectionPromise(__func__);
}
JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId));
nsAutoString addonIdString;
AssignJSFlatString(addonIdString, flat);
if (!addonIdString.EqualsLiteral("flyweb@mozilla.org")) {
nsCString addonIdCString = NS_ConvertUTF16toUTF8(addonIdString);
LOG_E("PublishServer: FlyWeb resource found on wrong system addon: %s.", addonIdCString.get());
return MakeRejectionPromise(__func__);
}
}
if (aWindow) {
nsresult rv;
MOZ_ASSERT(NS_IsMainThread());
rv = NS_DispatchToCurrentThread(
MakeAndAddRef<FlyWebPublishServerPermissionCheck>(
NS_ConvertUTF16toUTF8(aName), aWindow->WindowID(), server));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG_E("PublishServer: Failed to dispatch permission check runnable for %s",
NS_ConvertUTF16toUTF8(aName).get());
return MakeRejectionPromise(__func__);
}
} else {
// If aWindow is null, we're definitely in the e10s parent process.
// In this case, we know that permission has already been granted
// by the user because of content-process prompt.
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
server->PermissionGranted(true);
}
mServers.AppendElement(server);

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

@ -1537,7 +1537,7 @@ HTMLFormElement::NamedGetter(const nsAString& aName, bool &aFound)
void
HTMLFormElement::GetSupportedNames(nsTArray<nsString >& aRetval)
{
// TODO https://www.w3.org/Bugs/Public/show_bug.cgi?id=22320
// TODO https://github.com/whatwg/html/issues/1731
}
already_AddRefed<nsISupports>

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

@ -3289,7 +3289,7 @@ HTMLInputElement::GetRadioGroupContainer() const
}
already_AddRefed<nsIDOMHTMLInputElement>
HTMLInputElement::GetSelectedRadioButton()
HTMLInputElement::GetSelectedRadioButton() const
{
nsIRadioGroupContainer* container = GetRadioGroupContainer();
if (!container) {
@ -3360,6 +3360,13 @@ HTMLInputElement::SetCheckedInternal(bool aChecked, bool aNotify)
// Notify the document that the CSS :checked pseudoclass for this element
// has changed state.
UpdateState(aNotify);
// Notify all radios in the group that value has changed, this is to let
// radios to have the chance to update its states, e.g., :indeterminate.
if (mType == NS_FORM_INPUT_RADIO) {
nsCOMPtr<nsIRadioVisitor> visitor = new nsRadioUpdateStateVisitor(this);
VisitGroup(visitor, aNotify);
}
}
void
@ -6420,6 +6427,15 @@ HTMLInputElement::IntrinsicState() const
state |= NS_EVENT_STATE_INDETERMINATE;
}
if (mType == NS_FORM_INPUT_RADIO) {
nsCOMPtr<nsIDOMHTMLInputElement> selected = GetSelectedRadioButton();
bool indeterminate = !selected && !mChecked;
if (indeterminate) {
state |= NS_EVENT_STATE_INDETERMINATE;
}
}
// Check whether we are the default checked element (:default)
if (DefaultChecked()) {
state |= NS_EVENT_STATE_DEFAULT;
@ -6643,6 +6659,9 @@ HTMLInputElement::WillRemoveFromRadioGroup()
// longer a selected radio button
if (mChecked) {
container->SetCurrentRadioButton(name, nullptr);
nsCOMPtr<nsIRadioVisitor> visitor = new nsRadioUpdateStateVisitor(this);
VisitGroup(visitor, true);
}
// Remove this radio from its group in the container.

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

@ -264,7 +264,7 @@ public:
*
* @return the selected button (or null).
*/
already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton();
already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton() const;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;

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

@ -6490,11 +6490,19 @@ HTMLMediaElement::OnVisibilityChange(Visibility aOldVisibility,
break;
}
case Visibility::NONVISIBLE: {
if (mPlayTime.IsStarted()) {
// Not visible, play time is running -> Start hidden play time if needed.
HiddenVideoStart();
}
mDecoder->NotifyOwnerActivityChanged(false);
break;
}
case Visibility::MAY_BECOME_VISIBLE: {
if (aOldVisibility == Visibility::NONVISIBLE) {
// Visible -> Just pause hidden play time (no-op if already paused).
HiddenVideoStop();
mDecoder->NotifyOwnerActivityChanged(true);
} else if (aOldVisibility == Visibility::IN_DISPLAYPORT) {
// Do nothing.
@ -6502,6 +6510,9 @@ HTMLMediaElement::OnVisibilityChange(Visibility aOldVisibility,
break;
}
case Visibility::IN_DISPLAYPORT: {
// Visible -> Just pause hidden play time (no-op if already paused).
HiddenVideoStop();
mDecoder->NotifyOwnerActivityChanged(true);
break;
}

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

@ -55,3 +55,15 @@ nsRadioSetValueMissingState::Visit(nsIFormControl* aRadio)
return true;
}
bool
nsRadioUpdateStateVisitor::Visit(nsIFormControl* aRadio)
{
if (aRadio == mExcludeElement) {
return true;
}
HTMLInputElement* input = static_cast<HTMLInputElement*>(aRadio);
input->UpdateState(true);
return true;
}

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

@ -94,5 +94,18 @@ protected:
bool mNotify;
};
class nsRadioUpdateStateVisitor : public nsRadioVisitor
{
public:
explicit nsRadioUpdateStateVisitor(nsIFormControl* aExcludeElement)
: mExcludeElement(aExcludeElement)
{ }
virtual bool Visit(nsIFormControl* aRadio) override;
protected:
nsIFormControl* mExcludeElement;
};
#endif // _nsRadioVisitor_h__

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

@ -6,7 +6,7 @@ skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == button-load.html bu
skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == button-create.html button-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == textarea-load.html textarea-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,3) needs-focus == textarea-create.html textarea-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,4) needs-focus == select-load.html select-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
skip-if(B2G||Mulet) fuzzy-if(skiaContent,9,6) needs-focus == select-load.html select-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
skip-if(B2G||Mulet) fuzzy-if(skiaContent,2,4) needs-focus == select-create.html select-ref.html # B2G timed out waiting for reftest-wait to be removed # Initial mulet triage: parity with B2G/B2G Desktop
needs-focus == autofocus-after-load.html autofocus-after-load-ref.html
fails-if(B2G||Mulet) fuzzy-if(skiaContent,2,5) needs-focus == autofocus-leaves-iframe.html autofocus-leaves-iframe-ref.html # B2G focus difference between test and reference # Initial mulet triage: parity with B2G/B2G Desktop

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

@ -9,19 +9,19 @@ window.addEventListener("Test:DispatchKeyEvents", aEvent => {
var keyCode = KeyEvent["DOM_" + aEvent.detail.code];
document.body.focus();
var evt = document.createEvent("KeyEvents");
var evt = document.createEvent("KeyboardEvent");
evt.initKeyEvent("keydown", true, true, window,
false, false, false, false,
keyCode, 0);
document.body.dispatchEvent(evt);
evt = document.createEvent("KeyEvents");
evt = document.createEvent("KeyboardEvent");
evt.initKeyEvent("keypress", true, true, window,
false, false, false, false,
keyCode, 0);
document.body.dispatchEvent(evt);
evt = document.createEvent("KeyEvents");
evt = document.createEvent("KeyboardEvent");
evt.initKeyEvent("keyup", true, true, window,
false, false, false, false,
keyCode, 0);

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

@ -9,6 +9,7 @@ support-files =
[test_bug1286509.html]
skip-if = os == "android" || appname == "b2g" # up/down arrow keys not supported on android/b2g
[test_button_attributes_reflection.html]
[test_input_radio_indeterminate.html]
[test_input_radio_radiogroup.html]
[test_input_radio_required.html]
[test_change_event.html]

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

@ -0,0 +1,109 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=885359
-->
<head>
<title>Test for Bug 885359</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=885359">Mozilla Bug 343444</a>
<p id="display"></p>
<form>
<input type="radio" id='radio1'/><br/>
<input type="radio" id="g1radio1" name="group1"/>
<input type="radio" id="g1radio2" name="group1"/></br>
<input type="radio" id="g1radio3" name="group1"/></br>
<input type="radio" id="g2radio1" name="group2"/>
<input type="radio" id="g2radio2" name="group2" checked/></br>
</form>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var radio1 = document.getElementById("radio1");
var g1radio1 = document.getElementById("g1radio1");
var g1radio2 = document.getElementById("g1radio2");
var g1radio3 = document.getElementById("g1radio3");
var g2radio1 = document.getElementById("g2radio1");
var g2radio2 = document.getElementById("g2radio2");
SimpleTest.waitForFocus(function() {
test();
SimpleTest.finish();
});
function verifyIndeterminateState(aElement, aIsIndeterminate, aMessage) {
is(aElement.mozMatchesSelector(':indeterminate'), aIsIndeterminate, aMessage);
}
function test() {
// Initial State.
verifyIndeterminateState(radio1, true,
"Unchecked radio in its own group (no name attribute)");
verifyIndeterminateState(g1radio1, true, "No selected radio in its group");
verifyIndeterminateState(g1radio2, true, "No selected radio in its group");
verifyIndeterminateState(g1radio3, true, "No selected radio in its group");
verifyIndeterminateState(g2radio1, false, "Selected radio in its group");
verifyIndeterminateState(g2radio2, false, "Selected radio in its group");
// Selecting radio buttion.
g1radio1.checked = true;
verifyIndeterminateState(g1radio1, false,
"Selecting a radio should affect all radios in the group");
verifyIndeterminateState(g1radio2, false,
"Selecting a radio should affect all radios in the group");
verifyIndeterminateState(g1radio3, false,
"Selecting a radio should affect all radios in the group");
// Changing the selected radio button.
g1radio3.checked = true;
verifyIndeterminateState(g1radio1, false,
"Selecting a radio should affect all radios in the group");
verifyIndeterminateState(g1radio2, false,
"Selecting a radio should affect all radios in the group");
verifyIndeterminateState(g1radio3, false,
"Selecting a radio should affect all radios in the group");
// Deselecting radio button.
g2radio2.checked = false;
verifyIndeterminateState(g2radio1, true,
"Deselecting a radio should affect all radios in the group");
verifyIndeterminateState(g2radio2, true,
"Deselecting a radio should affect all radios in the group");
// Move a selected radio button to another group.
g1radio3.name = "group2";
// The radios' state in the original group becomes indeterminated.
verifyIndeterminateState(g1radio1, true,
"Removing a radio from a group should affect all radios in the group");
verifyIndeterminateState(g1radio2, true,
"Removing a radio from a group should affect all radios in the group");
// The radios' state in the new group becomes determinated.
verifyIndeterminateState(g1radio3, false,
"Adding a radio from a group should affect all radios in the group");
verifyIndeterminateState(g2radio1, false,
"Adding a radio from a group should affect all radios in the group");
verifyIndeterminateState(g2radio2, false,
"Adding a radio from a group should affect all radios in the group");
// Change input type to 'text'.
g1radio3.type = "text";
verifyIndeterminateState(g1radio3, false,
"Input type text does not have an indeterminate state");
verifyIndeterminateState(g2radio1, true,
"Changing input type should affect all radios in the group");
verifyIndeterminateState(g2radio2, true,
"Changing input type should affect all radios in the group");
}
</script>
</pre>
</body>
</html>

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

@ -8,17 +8,6 @@
[builtinclass, scriptable, uuid(8e49f7b0-1f98-4939-bf91-e9c39cd56434)]
interface nsITabParent : nsISupports
{
void injectTouchEvent(in AString aType,
[array, size_is(count)] in uint32_t aIdentifiers,
[array, size_is(count)] in int32_t aXs,
[array, size_is(count)] in int32_t aYs,
[array, size_is(count)] in uint32_t aRxs,
[array, size_is(count)] in uint32_t aRys,
[array, size_is(count)] in float aRotationAngles,
[array, size_is(count)] in float aForces,
in uint32_t count,
in long aModifiers);
void getChildProcessOffset(out int32_t aCssX, out int32_t aCssY);
readonly attribute boolean useAsyncPanZoom;

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

@ -32,7 +32,6 @@
#include "mozilla/dom/GetFilesHelper.h"
#include "mozilla/dom/PCrashReporterChild.h"
#include "mozilla/dom/ProcessGlobal.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/dom/nsIContentChild.h"
#include "mozilla/gfx/gfxVars.h"
@ -2263,22 +2262,6 @@ ContentChild::AddRemoteAlertObserver(const nsString& aData,
return NS_OK;
}
bool
ContentChild::RecvSystemMemoryAvailable(const uint64_t& aGetterId,
const uint32_t& aMemoryAvailable)
{
RefPtr<Promise> p = dont_AddRef(reinterpret_cast<Promise*>(aGetterId));
if (!aMemoryAvailable) {
p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
return true;
}
p->MaybeResolve((int)aMemoryAvailable);
return true;
}
bool
ContentChild::RecvPreferenceUpdate(const PrefSetting& aPref)
{

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

@ -404,9 +404,6 @@ public:
// auto remove when alertfinished is received.
nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
virtual bool RecvSystemMemoryAvailable(const uint64_t& aGetterId,
const uint32_t& aMemoryAvailable) override;
virtual bool RecvPreferenceUpdate(const PrefSetting& aPref) override;
virtual bool RecvVarUpdate(const GfxVarUpdate& pref) override;

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

@ -3909,20 +3909,6 @@ ContentParent::RecvNSSU2FTokenSign(nsTArray<uint8_t>&& aApplication,
return NS_SUCCEEDED(rv);
}
bool
ContentParent::RecvGetSystemMemory(const uint64_t& aGetterId)
{
uint32_t memoryTotal = 0;
#if defined(XP_LINUX)
memoryTotal = mozilla::hal::GetTotalSystemMemoryLevel();
#endif
Unused << SendSystemMemoryAvailable(aGetterId, memoryTotal);
return true;
}
bool
ContentParent::RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>* aLookAndFeelIntCache)
{

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

@ -1013,8 +1013,6 @@ private:
const bool& aContentOrNormalChannel,
const bool& aAnyChannel) override;
virtual bool RecvGetSystemMemory(const uint64_t& getterId) override;
virtual bool RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>* aLookAndFeelIntCache) override;
virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue) override;

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

@ -518,8 +518,6 @@ child:
async NotifyVisited(URIParams uri);
async SystemMemoryAvailable(uint64_t getterId, uint32_t memoryAvailable);
async PreferenceUpdate(PrefSetting pref);
async VarUpdate(GfxVarUpdate var);
@ -829,8 +827,6 @@ parent:
uint8_t[] keyHandle)
returns (uint8_t[] signature);
async GetSystemMemory(uint64_t getterId);
sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
returns (bool isSecureURI);

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

@ -2809,71 +2809,6 @@ TabParent::GetLoadContext()
return loadContext.forget();
}
NS_IMETHODIMP
TabParent::InjectTouchEvent(const nsAString& aType,
uint32_t* aIdentifiers,
int32_t* aXs,
int32_t* aYs,
uint32_t* aRxs,
uint32_t* aRys,
float* aRotationAngles,
float* aForces,
uint32_t aCount,
int32_t aModifiers)
{
EventMessage msg;
nsContentUtils::GetEventMessageAndAtom(aType, eTouchEventClass, &msg);
if (msg != eTouchStart && msg != eTouchMove &&
msg != eTouchEnd && msg != eTouchCancel) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
WidgetTouchEvent event(true, msg, widget);
event.mModifiers = aModifiers;
event.mTime = PR_IntervalNow();
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
if (!content || !content->OwnerDoc()) {
return NS_ERROR_FAILURE;
}
nsIDocument* doc = content->OwnerDoc();
if (!doc || !doc->GetShell()) {
return NS_ERROR_FAILURE;
}
nsPresContext* presContext = doc->GetShell()->GetPresContext();
event.mTouches.SetCapacity(aCount);
for (uint32_t i = 0; i < aCount; ++i) {
LayoutDeviceIntPoint pt =
LayoutDeviceIntPoint::FromAppUnitsRounded(
CSSPoint::ToAppUnits(CSSPoint(aXs[i], aYs[i])),
presContext->AppUnitsPerDevPixel());
LayoutDeviceIntPoint radius =
LayoutDeviceIntPoint::FromAppUnitsRounded(
CSSPoint::ToAppUnits(CSSPoint(aRxs[i], aRys[i])),
presContext->AppUnitsPerDevPixel());
RefPtr<Touch> t =
new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i], aForces[i]);
// Consider all injected touch events as changedTouches. For more details
// about the meaning of changedTouches for each event, see
// https://developer.mozilla.org/docs/Web/API/TouchEvent.changedTouches
t->mChanged = true;
event.mTouches.AppendElement(t);
}
SendRealTouchEvent(event);
return NS_OK;
}
NS_IMETHODIMP
TabParent::GetUseAsyncPanZoom(bool* useAsyncPanZoom)
{

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

@ -2024,8 +2024,6 @@ MediaDecoderStateMachine::OnMetadataRead(MetadataHolder* aMetadata)
}
SetState(DECODER_STATE_DECODING);
ScheduleStateMachine();
}
void
@ -2181,12 +2179,6 @@ MediaDecoderStateMachine::SeekCompleted()
FinishDecodeFirstFrame();
}
if (nextState == DECODER_STATE_DECODING) {
SetState(DECODER_STATE_DECODING);
} else {
SetState(nextState);
}
// Ensure timestamps are up to date.
UpdatePlaybackPositionInternal(newCurrentTime);
@ -2198,12 +2190,13 @@ MediaDecoderStateMachine::SeekCompleted()
// if we need to buffer after the seek.
mQuickBuffering = false;
ScheduleStateMachine();
if (video) {
mMediaSink->Redraw(mInfo.mVideo);
mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
}
SetState(nextState);
MOZ_ASSERT(IsStateMachineScheduled());
}
RefPtr<ShutdownPromise>

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

@ -799,7 +799,8 @@ MediaDevice::FitnessDistance(nsString aN,
uint32_t
MediaDevice::GetBestFitnessDistance(
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets)
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
bool aIsChrome)
{
nsString mediaSource;
GetMediaSource(mediaSource);
@ -818,7 +819,11 @@ MediaDevice::GetBestFitnessDistance(
// Forward request to underlying object to interrogate per-mode capabilities.
// Pass in device's origin-specific id for deviceId constraint comparison.
nsString id;
GetId(id);
if (aIsChrome) {
GetRawId(id);
} else {
GetId(id);
}
return mSource->GetBestFitnessDistance(aConstraintSets, id);
}
@ -1333,6 +1338,7 @@ static auto& MediaManager_AnonymizeDevices = MediaManager::AnonymizeDevices;
already_AddRefed<MediaManager::PledgeChar>
MediaManager::SelectSettings(
MediaStreamConstraints& aConstraints,
bool aIsChrome,
RefPtr<Refcountable<UniquePtr<SourceSet>>>& aSources)
{
MOZ_ASSERT(NS_IsMainThread());
@ -1342,7 +1348,8 @@ MediaManager::SelectSettings(
// Algorithm accesses device capabilities code and must run on media thread.
// Modifies passed-in aSources.
MediaManager::PostTask(NewTaskFrom([id, aConstraints, aSources]() mutable {
MediaManager::PostTask(NewTaskFrom([id, aConstraints,
aSources, aIsChrome]() mutable {
auto& sources = **aSources;
// Since the advanced part of the constraints algorithm needs to know when
@ -1368,11 +1375,13 @@ MediaManager::SelectSettings(
if (needVideo && videos.Length()) {
badConstraint = MediaConstraintsHelper::SelectSettings(
NormalizedConstraints(GetInvariant(aConstraints.mVideo)), videos);
NormalizedConstraints(GetInvariant(aConstraints.mVideo)), videos,
aIsChrome);
}
if (!badConstraint && needAudio && audios.Length()) {
badConstraint = MediaConstraintsHelper::SelectSettings(
NormalizedConstraints(GetInvariant(aConstraints.mAudio)), audios);
NormalizedConstraints(GetInvariant(aConstraints.mAudio)), audios,
aIsChrome);
}
if (!badConstraint &&
!needVideo == !videos.Length() &&
@ -1414,6 +1423,7 @@ public:
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
MediaEnginePrefs &aPrefs,
const nsCString& aOrigin,
bool aIsChrome,
MediaManager::SourceSet* aSourceSet)
: mConstraints(aConstraints)
, mOnSuccess(aOnSuccess)
@ -1422,6 +1432,7 @@ public:
, mListener(aListener)
, mPrefs(aPrefs)
, mOrigin(aOrigin)
, mIsChrome(aIsChrome)
, mDeviceChosen(false)
, mSourceSet(aSourceSet)
, mManager(MediaManager::GetInstance())
@ -1473,7 +1484,7 @@ public:
nsTArray<RefPtr<AudioDevice>> audios;
audios.AppendElement(mAudioDevice);
badConstraint = MediaConstraintsHelper::SelectSettings(
NormalizedConstraints(constraints), audios);
NormalizedConstraints(constraints), audios, mIsChrome);
}
}
}
@ -1486,7 +1497,7 @@ public:
nsTArray<RefPtr<VideoDevice>> videos;
videos.AppendElement(mVideoDevice);
badConstraint = MediaConstraintsHelper::SelectSettings(
NormalizedConstraints(constraints), videos);
NormalizedConstraints(constraints), videos, mIsChrome);
}
if (mAudioDevice) {
mAudioDevice->Deallocate();
@ -1517,8 +1528,8 @@ public:
NS_DispatchToMainThread(do_AddRef(
new GetUserMediaStreamRunnable(mOnSuccess, mOnFailure, mWindowID,
mListener, mOrigin, mConstraints,
mAudioDevice, mVideoDevice,
mListener, mOrigin,
mConstraints, mAudioDevice, mVideoDevice,
peerIdentity)));
MOZ_ASSERT(!mOnSuccess);
MOZ_ASSERT(!mOnFailure);
@ -1600,6 +1611,7 @@ private:
RefPtr<VideoDevice> mVideoDevice;
MediaEnginePrefs mPrefs;
nsCString mOrigin;
bool mIsChrome;
bool mDeviceChosen;
public:
@ -1983,17 +1995,6 @@ MediaManager::NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow,
return NS_OK;
}
bool MediaManager::IsPrivileged()
{
bool permission = nsContentUtils::IsCallerChrome();
// Developer preference for turning off permission check.
if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
permission = true;
}
return permission;
}
bool MediaManager::IsLoop(nsIURI* aDocURI)
{
MOZ_ASSERT(aDocURI);
@ -2114,7 +2115,9 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
return NS_ERROR_UNEXPECTED;
}
bool loop = IsLoop(docURI);
bool privileged = IsPrivileged();
bool isChrome = nsContentUtils::IsCallerChrome();
bool privileged = isChrome ||
Preferences::GetBool("media.navigator.permission.disabled", false);
bool isHTTPS = false;
docURI->SchemeIs("https", &isHTTPS);
nsCString host;
@ -2208,7 +2211,7 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
false) && !IsVistaOrLater()) ||
#endif
(!privileged && !HostIsHttps(*docURI)) ||
!HostHasPermission(*docURI)) {
(!isChrome && !HostHasPermission(*docURI))) {
RefPtr<MediaStreamError> error =
new MediaStreamError(aWindow,
NS_LITERAL_STRING("NotAllowedError"));
@ -2378,7 +2381,7 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
RefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(windowID, videoType,
audioType, fake);
p->Then([this, onSuccess, onFailure, windowID, c, listener, askPermission,
prefs, isHTTPS, callID, origin](SourceSet*& aDevices) mutable {
prefs, isHTTPS, callID, origin, isChrome](SourceSet*& aDevices) mutable {
RefPtr<Refcountable<UniquePtr<SourceSet>>> devices(
new Refcountable<UniquePtr<SourceSet>>(aDevices)); // grab result
@ -2390,11 +2393,11 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
}
// Apply any constraints. This modifies the passed-in list.
RefPtr<PledgeChar> p2 = SelectSettings(c, devices);
RefPtr<PledgeChar> p2 = SelectSettings(c, isChrome, devices);
p2->Then([this, onSuccess, onFailure, windowID, c,
listener, askPermission, prefs, isHTTPS,
callID, origin, devices](const char*& badConstraint) mutable {
listener, askPermission, prefs, isHTTPS, callID,
origin, isChrome, devices](const char*& badConstraint) mutable {
// Ensure that the captured 'this' pointer and our windowID are still good.
auto* globalWindow = nsGlobalWindow::GetInnerWindowWithId(windowID);
@ -2441,6 +2444,7 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
onFailure.forget(),
windowID, listener,
prefs, origin,
isChrome,
devices->release()));
// Store the task w/callbacks.
mActiveCallbacks.Put(callID, task.forget());
@ -3489,10 +3493,11 @@ GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack(
RefPtr<MediaManager> mgr = MediaManager::GetInstance();
uint32_t id = mgr->mOutstandingVoidPledges.Append(*p);
uint64_t windowId = aWindow->WindowID();
bool isChrome = nsContentUtils::IsCallerChrome();
MediaManager::PostTask(NewTaskFrom([id, windowId,
audioDevice, videoDevice,
aConstraints]() mutable {
aConstraints, isChrome]() mutable {
MOZ_ASSERT(MediaManager::IsInMediaThread());
RefPtr<MediaManager> mgr = MediaManager::GetInstance();
const char* badConstraint = nullptr;
@ -3504,7 +3509,7 @@ GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack(
nsTArray<RefPtr<AudioDevice>> audios;
audios.AppendElement(audioDevice);
badConstraint = MediaConstraintsHelper::SelectSettings(
NormalizedConstraints(aConstraints), audios);
NormalizedConstraints(aConstraints), audios, isChrome);
}
} else {
rv = videoDevice->Restart(aConstraints, mgr->mPrefs, &badConstraint);
@ -3512,7 +3517,7 @@ GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack(
nsTArray<RefPtr<VideoDevice>> videos;
videos.AppendElement(videoDevice);
badConstraint = MediaConstraintsHelper::SelectSettings(
NormalizedConstraints(aConstraints), videos);
NormalizedConstraints(aConstraints), videos, isChrome);
}
}
NS_DispatchToMainThread(NewRunnableFrom([id, windowId, rv,

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

@ -72,7 +72,8 @@ public:
void SetId(const nsAString& aID);
void SetRawId(const nsAString& aID);
virtual uint32_t GetBestFitnessDistance(
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets);
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
bool aIsChrome);
virtual Source* GetSource() = 0;
nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
const MediaEnginePrefs &aPrefs,
@ -268,7 +269,6 @@ private:
typedef media::Pledge<const char*, dom::MediaStreamError*> PledgeChar;
typedef media::Pledge<bool, dom::MediaStreamError*> PledgeVoid;
static bool IsPrivileged();
static bool IsLoop(nsIURI* aDocURI);
static nsresult GenerateUUID(nsAString& aResult);
static nsresult AnonymizeId(nsAString& aId, const nsACString& aOriginKey);
@ -289,6 +289,7 @@ private:
already_AddRefed<PledgeChar>
SelectSettings(
dom::MediaStreamConstraints& aConstraints,
bool aIsChrome,
RefPtr<media::Refcountable<UniquePtr<SourceSet>>>& aSources);
StreamListeners* AddWindowID(uint64_t aWindowId);

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

@ -441,7 +441,8 @@ MediaConstraintsHelper::FindBadConstraint(
mDeviceId(MockDevice::HasThreadSafeRefCnt::value ? aDeviceId : nsString()) {}
uint32_t GetBestFitnessDistance(
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets)
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
bool aIsChrome)
{
return mMediaEngineSource->GetBestFitnessDistance(aConstraintSets,
mDeviceId);

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

@ -310,7 +310,7 @@ protected:
MOZ_ASSERT(aDevices.Length());
for (auto& device : aDevices) {
if (device->GetBestFitnessDistance(sets) != UINT32_MAX) {
if (device->GetBestFitnessDistance(sets, false) != UINT32_MAX) {
return true;
}
}
@ -323,7 +323,8 @@ public:
template<class DeviceType>
static const char*
SelectSettings(const NormalizedConstraints &aConstraints,
nsTArray<RefPtr<DeviceType>>& aDevices)
nsTArray<RefPtr<DeviceType>>& aDevices,
bool aIsChrome)
{
auto& c = aConstraints;
@ -339,7 +340,8 @@ public:
std::multimap<uint32_t, RefPtr<DeviceType>> ordered;
for (uint32_t i = 0; i < aDevices.Length();) {
uint32_t distance = aDevices[i]->GetBestFitnessDistance(aggregateConstraints);
uint32_t distance = aDevices[i]->GetBestFitnessDistance(aggregateConstraints,
aIsChrome);
if (distance == UINT32_MAX) {
unsatisfactory.AppendElement(aDevices[i]);
aDevices.RemoveElementAt(i);
@ -365,7 +367,8 @@ public:
aggregateConstraints.AppendElement(&c.mAdvanced[i]);
nsTArray<RefPtr<DeviceType>> rejects;
for (uint32_t j = 0; j < aDevices.Length();) {
if (aDevices[j]->GetBestFitnessDistance(aggregateConstraints) == UINT32_MAX) {
if (aDevices[j]->GetBestFitnessDistance(aggregateConstraints,
aIsChrome) == UINT32_MAX) {
rejects.AppendElement(aDevices[j]);
aDevices.RemoveElementAt(j);
} else {

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

@ -1,8 +1,8 @@
# basic sanity checking
random-if(!haveTestPlugin) != plugin-sanity.html about:blank
fails-if(!haveTestPlugin) == plugin-sanity.html div-sanity.html
fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-alpha-zindex.html div-alpha-zindex.html
fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,164000) == plugin-alpha-opacity.html div-alpha-opacity.html
fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-alpha-zindex.html div-alpha-zindex.html
fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,164000) == plugin-alpha-opacity.html div-alpha-opacity.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == windowless-clipping-1.html windowless-clipping-1-ref.html # bug 631832
# fuzzy because of anti-aliasing in dashed border
fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-1.html border-padding-1-ref.html # bug 629430
@ -11,14 +11,14 @@ fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) skip-if(!have
# The following two "pluginproblemui-direction" tests are unreliable on all platforms. They should be re-written or replaced.
#random-if(cocoaWidget||d2d||/^Windows\x20NT\x205\.1/.test(http.oscpu)) fails-if(!haveTestPlugin&&!Android) == pluginproblemui-direction-1.html pluginproblemui-direction-1-ref.html # bug 567367
#random-if(cocoaWidget) fails-if(!haveTestPlugin&&!Android) == pluginproblemui-direction-2.html pluginproblemui-direction-2-ref.html
fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html
fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-transform-alpha-zindex.html div-alpha-zindex.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,160000) == plugin-busy-alpha-zindex.html div-alpha-zindex.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background.html plugin-background-ref.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-1-step.html plugin-background-ref.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-2-step.html plugin-background-ref.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-5-step.html plugin-background-ref.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent,1,32400) == plugin-background-10-step.html plugin-background-ref.html
fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html
fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-transform-alpha-zindex.html div-alpha-zindex.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-busy-alpha-zindex.html div-alpha-zindex.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background.html plugin-background-ref.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-1-step.html plugin-background-ref.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-2-step.html plugin-background-ref.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-5-step.html plugin-background-ref.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-10-step.html plugin-background-ref.html
random-if(!haveTestPlugin) == plugin-transform-1.html plugin-transform-1-ref.html
fails-if(!haveTestPlugin) == plugin-transform-2.html plugin-transform-2-ref.html
skip-if(!haveTestPlugin) == shrink-1.html shrink-1-ref.html

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

@ -0,0 +1,99 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AvailabilityCollection.h"
#include "mozilla/ClearOnShutdown.h"
#include "PresentationAvailability.h"
namespace mozilla {
namespace dom {
/* static */
StaticAutoPtr<AvailabilityCollection>
AvailabilityCollection::sSingleton;
static bool gOnceAliveNowDead = false;
/* static */ AvailabilityCollection*
AvailabilityCollection::GetSingleton()
{
MOZ_ASSERT(NS_IsMainThread());
if (!sSingleton && !gOnceAliveNowDead) {
sSingleton = new AvailabilityCollection();
ClearOnShutdown(&sSingleton);
}
return sSingleton;
}
AvailabilityCollection::AvailabilityCollection()
{
MOZ_COUNT_CTOR(AvailabilityCollection);
}
AvailabilityCollection::~AvailabilityCollection()
{
MOZ_COUNT_DTOR(AvailabilityCollection);
gOnceAliveNowDead = true;
}
void
AvailabilityCollection::Add(PresentationAvailability* aAvailability)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aAvailability) {
return;
}
WeakPtr<PresentationAvailability> availability = aAvailability;
if (mAvailabilities.Contains(aAvailability)) {
return;
}
mAvailabilities.AppendElement(aAvailability);
}
void
AvailabilityCollection::Remove(PresentationAvailability* aAvailability)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aAvailability) {
return;
}
WeakPtr<PresentationAvailability> availability = aAvailability;
mAvailabilities.RemoveElement(availability);
}
already_AddRefed<PresentationAvailability>
AvailabilityCollection::Find(const uint64_t aWindowId, const nsAString& aUrl)
{
MOZ_ASSERT(NS_IsMainThread());
// Loop backwards to allow removing elements in the loop.
for (int i = mAvailabilities.Length() - 1; i >= 0; --i) {
WeakPtr<PresentationAvailability> availability = mAvailabilities[i];
if (!availability) {
// The availability object was destroyed. Remove it from the list.
mAvailabilities.RemoveElementAt(i);
continue;
}
if (availability->Equals(aWindowId, aUrl)) {
RefPtr<PresentationAvailability> matchedAvailability = availability.get();
return matchedAvailability.forget();
}
}
return nullptr;
}
} // namespace dom
} // namespace mozilla

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

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#ifndef mozilla_dom_AvailabilityCollection_h
#define mozilla_dom_AvailabilityCollection_h
#include "mozilla/StaticPtr.h"
#include "mozilla/WeakPtr.h"
#include "nsString.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
class PresentationAvailability;
class AvailabilityCollection final
{
public:
static AvailabilityCollection* GetSingleton();
void Add(PresentationAvailability* aAvailability);
void Remove(PresentationAvailability* aAvailability);
already_AddRefed<PresentationAvailability>
Find(const uint64_t aWindowId, const nsAString& aUrl);
private:
friend class StaticAutoPtr<AvailabilityCollection>;
AvailabilityCollection();
virtual ~AvailabilityCollection();
static StaticAutoPtr<AvailabilityCollection> sSingleton;
nsTArray<WeakPtr<PresentationAvailability>> mAvailabilities;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_AvailabilityCollection_h

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

@ -4,12 +4,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PresentationAvailability.h"
#include "mozilla/dom/PresentationAvailabilityBinding.h"
#include "mozilla/dom/Promise.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIPresentationDeviceManager.h"
#include "nsIPresentationService.h"
#include "nsServiceManagerUtils.h"
#include "PresentationAvailability.h"
#include "PresentationLog.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -17,9 +20,11 @@ using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationAvailability)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationAvailability, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromises)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationAvailability, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromises);
tmp->Shutdown();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -31,15 +36,21 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationAvailability)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
/* static */ already_AddRefed<PresentationAvailability>
PresentationAvailability::Create(nsPIDOMWindowInner* aWindow)
PresentationAvailability::Create(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl,
RefPtr<Promise>& aPromise)
{
RefPtr<PresentationAvailability> availability = new PresentationAvailability(aWindow);
return NS_WARN_IF(!availability->Init()) ? nullptr : availability.forget();
RefPtr<PresentationAvailability> availability =
new PresentationAvailability(aWindow, aUrl);
return NS_WARN_IF(!availability->Init(aPromise)) ? nullptr
: availability.forget();
}
PresentationAvailability::PresentationAvailability(nsPIDOMWindowInner* aWindow)
PresentationAvailability::PresentationAvailability(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl)
: DOMEventTargetHelper(aWindow)
, mIsAvailable(false)
, mUrl(aUrl)
{
}
@ -49,7 +60,7 @@ PresentationAvailability::~PresentationAvailability()
}
bool
PresentationAvailability::Init()
PresentationAvailability::Init(RefPtr<Promise>& aPromise)
{
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
@ -59,21 +70,30 @@ PresentationAvailability::Init()
nsresult rv = service->RegisterAvailabilityListener(this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
// If the user agent is unable to monitor available device,
// Resolve promise with |value| set to false.
mIsAvailable = false;
aPromise->MaybeResolve(this);
return true;
}
nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
if (NS_WARN_IF(!deviceManager)) {
return false;
EnqueuePromise(aPromise);
AvailabilityCollection* collection = AvailabilityCollection::GetSingleton();
if (collection) {
collection->Add(this);
}
deviceManager->GetDeviceAvailable(&mIsAvailable);
return true;
}
void PresentationAvailability::Shutdown()
{
AvailabilityCollection* collection = AvailabilityCollection::GetSingleton();
if (collection ) {
collection->Remove(this);
}
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if (NS_WARN_IF(!service)) {
@ -98,6 +118,32 @@ PresentationAvailability::WrapObject(JSContext* aCx,
return PresentationAvailabilityBinding::Wrap(aCx, this, aGivenProto);
}
bool
PresentationAvailability::Equals(const uint64_t aWindowID,
const nsAString& aUrl) const
{
if (GetOwner() && GetOwner()->WindowID() == aWindowID &&
mUrl.Equals(aUrl)) {
return true;
}
return false;
}
bool
PresentationAvailability::IsCachedValueReady()
{
// All pending promises will be solved when cached value is ready and
// no promise should be enqueued afterward.
return mPromises.IsEmpty();
}
void
PresentationAvailability::EnqueuePromise(RefPtr<Promise>& aPromise)
{
mPromises.AppendElement(aPromise);
}
bool
PresentationAvailability::Value() const
{
@ -114,8 +160,28 @@ PresentationAvailability::NotifyAvailableChange(bool aIsAvailable)
}
void
PresentationAvailability::UpdateAvailabilityAndDispatchEvent(bool aIsAvailable) {
PresentationAvailability::UpdateAvailabilityAndDispatchEvent(bool aIsAvailable)
{
PRES_DEBUG("%s:id[%s]\n", __func__,
NS_ConvertUTF16toUTF8(mUrl).get());
bool isChanged = (aIsAvailable != mIsAvailable);
mIsAvailable = aIsAvailable;
NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(NS_LITERAL_STRING("change"))));
if (!mPromises.IsEmpty()) {
// Use the first availability change notification to resolve promise.
do {
nsTArray<RefPtr<Promise>> promises = Move(mPromises);
for (auto& promise : promises) {
promise->MaybeResolve(this);
}
// more promises may have been added to mPromises, at least in theory
} while (!mPromises.IsEmpty());
return;
}
if (isChanged) {
NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(NS_LITERAL_STRING("change"))));
}
}

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

@ -9,44 +9,62 @@
#include "mozilla/DOMEventTargetHelper.h"
#include "nsIPresentationListener.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
class Promise;
class PresentationAvailability final : public DOMEventTargetHelper
, public nsIPresentationAvailabilityListener
, public SupportsWeakPtr<PresentationAvailability>
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationAvailability,
DOMEventTargetHelper)
NS_DECL_NSIPRESENTATIONAVAILABILITYLISTENER
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PresentationAvailability)
static already_AddRefed<PresentationAvailability>
Create(nsPIDOMWindowInner* aWindow);
Create(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl,
RefPtr<Promise>& aPromise);
virtual void DisconnectFromOwner() override;
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
bool Equals(const uint64_t aWindowID, const nsAString& aUrl) const;
bool IsCachedValueReady();
void EnqueuePromise(RefPtr<Promise>& aPromise);
// WebIDL (public APIs)
bool Value() const;
IMPL_EVENT_HANDLER(change);
private:
explicit PresentationAvailability(nsPIDOMWindowInner* aWindow);
explicit PresentationAvailability(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl);
~PresentationAvailability();
virtual ~PresentationAvailability();
bool Init();
bool Init(RefPtr<Promise>& aPromise);
void Shutdown();
void UpdateAvailabilityAndDispatchEvent(bool aIsAvailable);
bool mIsAvailable;
nsTArray<RefPtr<Promise>> mPromises;
nsString mUrl;
};
} // namespace dom

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

@ -6,6 +6,7 @@
#include "PresentationRequest.h"
#include "AvailabilityCollection.h"
#include "ControllerConnectionCollection.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/dom/PresentationRequestBinding.h"
@ -23,13 +24,11 @@
#include "nsServiceManagerUtils.h"
#include "PresentationAvailability.h"
#include "PresentationCallbacks.h"
#include "PresentationLog.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_INHERITED(PresentationRequest, DOMEventTargetHelper,
mAvailability)
NS_IMPL_ADDREF_INHERITED(PresentationRequest, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(PresentationRequest, DOMEventTargetHelper)
@ -107,11 +106,6 @@ PresentationRequest::~PresentationRequest()
bool
PresentationRequest::Init()
{
mAvailability = PresentationAvailability::Create(GetOwner());
if (NS_WARN_IF(!mAvailability)) {
return false;
}
return true;
}
@ -317,6 +311,8 @@ PresentationRequest::FindOrCreatePresentationConnection(
already_AddRefed<Promise>
PresentationRequest::GetAvailability(ErrorResult& aRv)
{
PRES_DEBUG("%s:id[%s]\n", __func__,
NS_ConvertUTF16toUTF8(mUrl).get());
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
if (NS_WARN_IF(!global)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
@ -345,10 +341,52 @@ PresentationRequest::GetAvailability(ErrorResult& aRv)
return promise.forget();
}
promise->MaybeResolve(mAvailability);
FindOrCreatePresentationAvailability(promise);
return promise.forget();
}
void
PresentationRequest::FindOrCreatePresentationAvailability(RefPtr<Promise>& aPromise)
{
MOZ_ASSERT(aPromise);
if (NS_WARN_IF(!GetOwner())) {
aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
return;
}
AvailabilityCollection* collection = AvailabilityCollection::GetSingleton();
if (NS_WARN_IF(!collection)) {
aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
return;
}
RefPtr<PresentationAvailability> availability =
collection->Find(GetOwner()->WindowID(), mUrl);
if (!availability) {
availability = PresentationAvailability::Create(GetOwner(), mUrl, aPromise);
} else {
PRES_DEBUG(">resolve with same object:id[%s]\n",
NS_ConvertUTF16toUTF8(mUrl).get());
// Fetching cached available devices is asynchronous in our implementation,
// we need to ensure the promise is resolved in order.
if (availability->IsCachedValueReady()) {
aPromise->MaybeResolve(availability);
return;
}
availability->EnqueuePromise(aPromise);
}
if (!availability) {
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
}
nsresult
PresentationRequest::DispatchConnectionAvailableEvent(PresentationConnection* aConnection)
{

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

@ -22,8 +22,6 @@ class PresentationRequest final : public DOMEventTargetHelper
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationRequest,
DOMEventTargetHelper)
static already_AddRefed<PresentationRequest> Constructor(const GlobalObject& aGlobal,
const nsAString& aUrl,
@ -58,6 +56,8 @@ private:
void FindOrCreatePresentationConnection(const nsAString& aPresentationId,
Promise* aPromise);
void FindOrCreatePresentationAvailability(RefPtr<Promise>& aPromise);
// Implement https://w3c.github.io/webappsec-mixed-content/#categorize-settings-object
bool IsProhibitMixedSecurityContexts(nsIDocument* aDocument);
@ -65,7 +65,6 @@ private:
bool IsPrioriAuthenticatedURL(const nsAString& aUrl);
nsString mUrl;
RefPtr<PresentationAvailability> mAvailability;
};
} // namespace dom

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

@ -617,8 +617,8 @@ PresentationService::StartSession(const nsAString& aUrl,
return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
nsCOMPtr<nsIMutableArray> presentationUrls
= do_CreateInstance(NS_ARRAY_CONTRACTID);
nsCOMPtr<nsIMutableArray> presentationUrls =
do_CreateInstance(NS_ARRAY_CONTRACTID);
if (!presentationUrls) {
return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
@ -806,11 +806,14 @@ PresentationService::RegisterAvailabilityListener(nsIPresentationAvailabilityLis
{
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(mAvailabilityListeners.Contains(aListener))) {
return NS_OK;
if (!mAvailabilityListeners.Contains(aListener)) {
mAvailabilityListeners.AppendElement(aListener);
}
mAvailabilityListeners.AppendElement(aListener);
// Leverage availablility change notification to assign
// the initial value of availability object.
NS_WARN_IF(NS_FAILED(aListener->NotifyAvailableChange(mIsAvailable)));
return NS_OK;
}

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

@ -198,7 +198,7 @@ PresentationIPCService::UnregisterAvailabilityListener(nsIPresentationAvailabili
MOZ_ASSERT(aListener);
mAvailabilityListeners.RemoveElement(aListener);
if (sPresentationChild) {
if (mAvailabilityListeners.IsEmpty() && sPresentationChild) {
NS_WARN_IF(!sPresentationChild->SendUnregisterAvailabilityHandler());
}
return NS_OK;

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

@ -32,6 +32,7 @@ EXPORTS.mozilla.dom += [
]
UNIFIED_SOURCES += [
'AvailabilityCollection.cpp',
'ControllerConnectionCollection.cpp',
'DCPresentationChannelDescription.cpp',
'ipc/PresentationBuilderChild.cpp',

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

@ -73,3 +73,4 @@ skip-if = toolkit == 'android'
[test_presentation_sandboxed_presentation.html]
[test_presentation_reconnect.html]
[test_presentation_mixed_security_contexts.html]
[test_presentation_availability.html]

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

@ -86,18 +86,19 @@ function testCreateRequest() {
info('Sender: --- testCreateRequest ---');
request = new PresentationRequest(receiverUrl);
request.getAvailability().then((aAvailability) => {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Sender: Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
}).catch((aError) => {
ok(false, "Sender: Error occurred when getting availability: " + aError);
teardown();
aReject();
});
gScript.sendAsyncMessage('trigger-device-add');
});
}

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

@ -89,18 +89,19 @@ function testCreateRequest() {
info('Sender: --- testCreateRequest ---');
request = new PresentationRequest("file_presentation_1ua_receiver.html");
request.getAvailability().then((aAvailability) => {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Sender: Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
}).catch((aError) => {
ok(false, "Sender: Error occurred when getting availability: " + aError);
teardown();
aReject();
});
gScript.sendAsyncMessage('trigger-device-add');
});
}

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

@ -0,0 +1,131 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for PresentationAvailability</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1228508">Test PresentationAvailability</a>
<script type="application/javascript;version=1.8">
"use strict";
var testDevice = {
id: 'id',
name: 'name',
type: 'type',
};
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationDeviceInfoChromeScript.js'));
var request;
var availability;
function testSetup() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('setup-complete', function() {
aResolve();
});
gScript.sendAsyncMessage('setup');
});
}
function testInitialUnavailable() {
request = new PresentationRequest("https://example.com");
return request.getAvailability().then(function(aAvailability) {
is(aAvailability.value, false, "Should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
}
availability = aAvailability;
gScript.sendAsyncMessage('trigger-device-add', testDevice);
}).catch(function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
});
}
function testInitialAvailable() {
let anotherRequest = new PresentationRequest("https://example.net");
return anotherRequest.getAvailability().then(function(aAvailability) {
is(aAvailability.value, true, "Should have available device initially");
isnot(aAvailability, availability, "Should get different availability object for different request URL");
}).catch(function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
});
}
function testSameObject() {
let sameUrlRequest = new PresentationRequest("https://example.com");
return sameUrlRequest.getAvailability().then(function(aAvailability) {
is(aAvailability, availability, "Should get same availability object for same request URL");
}).catch(function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
});
}
function testOnChangeEvent() {
return new Promise(function(aResolve, aReject) {
availability.onchange = function() {
availability.onchange = null;
is(availability.value, false, "Should have no available device after device removed");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-remove');
});
}
function testConsecutiveGetAvailability() {
let request = new PresentationRequest("https://example.org");
let firstAvailabilityResolved = false;
return Promise.all([
request.getAvailability().then(function() {
firstAvailabilityResolved = true;
}),
request.getAvailability().then(function() {
ok(firstAvailabilityResolved, "getAvailability() should be resolved in sequence");
})
]).catch(function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
});
}
function teardown() {
request = null;
availability = null;
gScript.sendAsyncMessage('teardown');
gScript.destroy();
SimpleTest.finish();
}
function runTests() {
ok(navigator.presentation, "navigator.presentation should be available.");
testSetup().then(testInitialUnavailable)
.then(testInitialAvailable)
.then(testSameObject)
.then(testOnChangeEvent)
.then(testConsecutiveGetAvailability)
.then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: "presentation-device-manage", allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ "set": [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});
</script>
</body>
</html>

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

@ -26,11 +26,14 @@ function testSetup() {
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
@ -38,8 +41,6 @@ function testSetup() {
aReject();
}
);
gScript.sendAsyncMessage('trigger-device-add');
});
}

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

@ -48,11 +48,14 @@ function testSetup() {
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
@ -60,8 +63,6 @@ function testSetup() {
aReject();
}
);
gScript.sendAsyncMessage('trigger-device-add');
});
}

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

@ -24,11 +24,14 @@ function testSetup() {
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
@ -36,8 +39,6 @@ function testSetup() {
aReject();
}
);
gScript.sendAsyncMessage('trigger-device-add');
});
}

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

@ -24,11 +24,14 @@ function testSetup() {
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
@ -36,8 +39,6 @@ function testSetup() {
aReject();
}
);
gScript.sendAsyncMessage('trigger-device-add');
});
}

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