Merge autoland to central, a=merge

MozReview-Commit-ID: 9TWPWlHDRi2
This commit is contained in:
Wes Kocher 2017-06-12 13:52:10 -07:00
Родитель 1421659aba ccf4e450a6
Коммит 315b5d099f
75 изменённых файлов: 3280 добавлений и 1675 удалений

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

@ -1669,6 +1669,7 @@ pref("extensions.formautofill.experimental", true);
pref("extensions.formautofill.experimental", false);
#endif
pref("extensions.formautofill.addresses.enabled", true);
pref("extensions.formautofill.firstTimeUse", true);
pref("extensions.formautofill.heuristics.enabled", true);
pref("extensions.formautofill.loglevel", "Warn");

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

@ -324,9 +324,11 @@ var FormAutofillContent = {
* Send the profile to parent for doorhanger and storage saving/updating.
*
* @param {Object} profile Submitted form's address/creditcard guid and record.
* @param {Object} domWin Current content window.
*/
_onFormSubmit(profile) {
Services.cpmm.sendAsyncMessage("FormAutofill:OnFormSubmit", profile);
_onFormSubmit(profile, domWin) {
let mm = this._messageManagerFromWindow(domWin);
mm.sendAsyncMessage("FormAutofill:OnFormSubmit", profile);
},
/**
@ -365,7 +367,7 @@ var FormAutofillContent = {
record: pendingAddress,
},
// creditCard: {}
});
}, domWin);
return true;
},
@ -507,6 +509,14 @@ var FormAutofillContent = {
ProfileAutocomplete._previewSelectedProfile(selectedIndex);
}
},
_messageManagerFromWindow(win) {
return win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
},
};

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

@ -0,0 +1,173 @@
/* 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/. */
/*
* Implements doorhanger singleton that wraps up the PopupNotifications and handles
* the doorhager UI for formautofill related features.
*/
/* exported FormAutofillDoorhanger */
"use strict";
this.EXPORTED_SYMBOLS = ["FormAutofillDoorhanger"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
this.log = null;
FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
const BUNDLE_URI = "chrome://formautofill/locale/formautofill.properties";
const GetStringFromName = Services.strings.createBundle(BUNDLE_URI).GetStringFromName;
const CONTENT = {
firstTimeUse: {
notificationId: "autofill-address",
message: GetStringFromName("saveAddressMessage"),
anchor: {
id: "autofill-address-notification-icon",
URL: "chrome://formautofill/content/icon-address-save.svg",
tooltiptext: GetStringFromName("openAutofillMessagePanel"),
},
options: {
persistWhileVisible: true,
popupIconURL: "chrome://formautofill/content/icon-address-save.svg",
},
},
};
let FormAutofillDoorhanger = {
/**
* Generate the main action and secondary actions from content parameters and
* promise resolve.
*
* @private
* @param {Object} mainActionParams
* Parameters for main action.
* @param {Array<Object>} secondaryActionParams
* Array of the parameters for secondary actions.
* @param {Function} resolve Should be called in action callback.
* @returns {Array<Object>}
Return the mainAction and secondary actions in an array for showing doorhanger
*/
_createActions(mainActionParams, secondaryActionParams, resolve) {
if (!mainActionParams) {
return [null, null];
}
let {label, accessKey, callbackState} = mainActionParams;
let callback = resolve.bind(null, callbackState);
let mainAction = {label, accessKey, callback};
if (!secondaryActionParams) {
return [mainAction, null];
}
let secondaryActions = [];
for (let params of secondaryActionParams) {
let cb = resolve.bind(null, params.callbackState);
secondaryActions.push({
label: params.label,
accessKey: params.accessKey,
callback: cb,
});
}
return [mainAction, secondaryActions];
},
/**
* Append the link label element to the popupnotificationcontent.
* @param {XULElement} browser
* Target browser element for showing doorhanger.
* @param {string} id
* The ID of the doorhanger.
*/
_appendPrivacyPanelLink(browser, id) {
let notificationId = id + "-notification";
let chromeDoc = browser.ownerDocument;
let notification = chromeDoc.getElementById(notificationId);
if (!notification.querySelector("popupnotificationcontent")) {
let notificationcontent = chromeDoc.createElement("popupnotificationcontent");
let privacyLinkElement = chromeDoc.createElement("label");
privacyLinkElement.className = "text-link";
privacyLinkElement.setAttribute("useoriginprincipal", true);
privacyLinkElement.setAttribute("href", "about:preferences#privacy");
privacyLinkElement.setAttribute("value", GetStringFromName("viewAutofillOptions"));
notificationcontent.appendChild(privacyLinkElement);
notification.append(notificationcontent);
}
},
/**
* Create an image element for notification anchor if it doesn't already exist.
* @param {XULElement} browser
* Target browser element for showing doorhanger.
* @param {Object} anchor
* Anchor options for setting the anchor element.
* @param {string} anchor.id
* ID of the anchor element.
* @param {string} anchor.URL
* Path of the icon asset.
* @param {string} anchor.tooltiptext
* Tooltip string for the anchor.
*/
_setAnchor(browser, anchor) {
let chromeDoc = browser.ownerDocument;
let {id, URL, tooltiptext} = anchor;
let anchorEt = chromeDoc.getElementById(id);
if (!anchorEt) {
let notificationPopupBox =
chromeDoc.getElementById("notification-popup-box");
// Icon shown on URL bar
let anchorElement = chromeDoc.createElement("image");
anchorElement.id = id;
anchorElement.setAttribute("src", URL);
anchorElement.classList.add("notification-anchor-icon");
anchorElement.setAttribute("role", "button");
anchorElement.setAttribute("tooltiptext", tooltiptext);
anchorElement.style.setProperty("-moz-context-properties", "fill");
anchorElement.style.fill = "currentcolor";
notificationPopupBox.appendChild(anchorElement);
}
},
/**
* Show different types of doorhanger by leveraging PopupNotifications.
* @param {XULElement} browser
* Target browser element for showing doorhanger.
* @param {string} type
* The type of the doorhanger. There will have first time use/update/credit card.
* @returns {Promise}
Resolved with action type when action callback is triggered.
*/
async show(browser, type) {
log.debug("show doorhanger with type:", type);
return new Promise((resolve) => {
let content = CONTENT[type];
let chromeWin = browser.ownerGlobal;
content.options.eventCallback = (topic) => {
log.debug("eventCallback:", topic);
switch (topic) {
// We can only append label element when notification box is shown
case "shown":
this._appendPrivacyPanelLink(browser, content.notificationId);
break;
}
};
this._setAnchor(browser, content.anchor);
chromeWin.PopupNotifications.show(
browser,
content.notificationId,
content.message,
content.anchor.id,
...this._createActions(content.mainAction, content.secondaryActions, resolve),
content.options,
);
});
},
};

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

@ -35,12 +35,13 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillPreferences",
"resource://formautofill/FormAutofillPreferences.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillDoorhanger",
"resource://formautofill/FormAutofillDoorhanger.jsm");
this.log = null;
FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
@ -80,7 +81,7 @@ FormAutofillParent.prototype = {
Services.ppmm.addMessageListener("FormAutofill:GetAddresses", this);
Services.ppmm.addMessageListener("FormAutofill:SaveAddress", this);
Services.ppmm.addMessageListener("FormAutofill:RemoveAddresses", this);
Services.ppmm.addMessageListener("FormAutofill:OnFormSubmit", this);
Services.mm.addMessageListener("FormAutofill:OnFormSubmit", this);
// Observing the pref and storage changes
Services.prefs.addObserver(ENABLED_PREF, this);
@ -276,8 +277,16 @@ FormAutofillParent.prototype = {
}
this.profileStorage.addresses.notifyUsed(address.guid);
} else {
// TODO: Add first time use probe(bug 990199) and doorhanger(bug 1303510)
// profileStorage.addresses.add(address.record);
if (!Services.prefs.getBoolPref("extensions.formautofill.firstTimeUse")) {
if (!this.profileStorage.addresses.mergeToStorage(address.record)) {
this.profileStorage.addresses.add(address.record);
}
return;
}
this.profileStorage.addresses.add(address.record);
Services.prefs.setBoolPref("extensions.formautofill.firstTimeUse", false);
FormAutofillDoorhanger.show(target, "firstTimeUse");
}
},
};

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

@ -0,0 +1,6 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path fill="#999899" d="M22 13.7H9.4c-.6 0-1.2.5-1.2 1.2 0 .6.5 1.2 1.2 1.2H22c.6 0 1.2-.5 1.2-1.2s-.6-1.2-1.2-1.2zM6.1 26.6V5.5c0-.8.7-1.5 1.5-1.5h16c.9 0 1.5.6 1.5 1.5V16h2V3.8c0-1-.7-1.8-1.8-1.8H5.9c-1 0-1.8.8-1.8 1.8v24.5c0 1 .8 1.7 1.8 1.7h9.3v-2H7.6c-.8 0-1.5-.6-1.5-1.4zm21.1-1.9h-2.5V20c0-.4-.3-.8-.8-.8h-3.1c-.4 0-.8.3-.8.8v4.6h-2.5c-.6 0-.8.4-.3.8l4.3 4.2c.2.2.5.3.8.3s.6-.1.8-.3l4.3-4.2c.6-.4.4-.7-.2-.7zm-11.3-5.6H9.4c-.6 0-1.2.5-1.2 1.2s.5 1.2 1.2 1.2h6.5c.6 0 1.2-.5 1.2-1.2s-.6-1.2-1.2-1.2zM22 7.8H9.4c-.6 0-1.2.5-1.2 1.2s.5 1.2 1.2 1.2H22c.6 0 1.2-.5 1.2-1.2s-.6-1.2-1.2-1.2z"/>
</svg>

После

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

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

@ -5,3 +5,6 @@
preferenceGroupTitle = Form Autofill
enableProfileAutofill = Enable Profile Autofill
savedProfiles = Saved Profiles…
saveAddressMessage = Firefox now saves your form data to help you fill out forms faster!
viewAutofillOptions = View Form Autofill options…
openAutofillMessagePanel = Open Form Autofill message panel

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

@ -6,6 +6,7 @@ support-files =
[browser_check_installed.js]
[browser_editProfileDialog.js]
[browser_first_time_use_doorhanger.js]
[browser_privacyPreferences.js]
[browser_manageProfilesDialog.js]
[browser_submission_in_private_mode.js]

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

@ -0,0 +1,87 @@
"use strict";
const FORM_URL = "http://mochi.test:8888/browser/browser/extensions/formautofill/test/browser/autocomplete_basic.html";
const FTU_PREF = "extensions.formautofill.firstTimeUse";
const ENABLED_PREF = "extensions.formautofill.addresses.enabled";
registerCleanupFunction(async function() {
let addresses = await getAddresses();
if (addresses.length) {
await removeAddresses(addresses.map(address => address.guid));
}
});
add_task(async function test_first_time_save() {
let addresses = await getAddresses();
is(addresses.length, 0, "No profile in storage");
await SpecialPowers.pushPrefEnv({
"set": [
[FTU_PREF, true],
[ENABLED_PREF, true],
],
});
await BrowserTestUtils.withNewTab({gBrowser, url: FORM_URL},
async function(browser) {
let promiseShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel,
"popupshown");
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:preferences#privacy");
await ContentTask.spawn(browser, null, async function() {
let form = content.document.getElementById("form");
form.querySelector("#organization").focus();
form.querySelector("#organization").value = "Sesame Street";
form.querySelector("#street-address").value = "123 Sesame Street";
form.querySelector("#tel").value = "1-345-345-3456";
// Wait 500ms before submission to make sure the input value applied
setTimeout(() => {
form.querySelector("input[type=submit]").click();
}, 500);
});
await promiseShown;
let notificationElement = PopupNotifications.panel.firstChild;
// Open the panel via link
let link = notificationElement.querySelector("popupnotificationcontent label");
link.click();
let tab = await tabPromise;
ok(tab, "Privacy panel opened");
await BrowserTestUtils.removeTab(tab);
}
);
addresses = await getAddresses();
is(addresses.length, 1, "Profile saved");
let ftuPref = SpecialPowers.getBoolPref(FTU_PREF);
is(ftuPref, false, "First time use flag is false");
});
add_task(async function test_non_first_time_save() {
let addresses = await getAddresses();
let ftuPref = SpecialPowers.getBoolPref(FTU_PREF);
is(ftuPref, false, "First time use flag is false");
is(addresses.length, 1, "1 address in storage");
await BrowserTestUtils.withNewTab({gBrowser, url: FORM_URL},
async function(browser) {
await ContentTask.spawn(browser, null, async function() {
let form = content.document.getElementById("form");
form.querySelector("#organization").focus();
form.querySelector("#organization").value = "Mozilla";
form.querySelector("#street-address").value = "331 E. Evelyn Avenue";
form.querySelector("#tel").value = "1-650-903-0800";
// Wait 500ms before submission to make sure the input value applied
setTimeout(() => {
form.querySelector("input[type=submit]").click();
}, 500);
});
await new Promise(resolve => setTimeout(resolve, 1000));
is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
}
);
addresses = await getAddresses();
is(addresses.length, 2, "Another address saved");
});

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

@ -23,6 +23,26 @@ function setInput(selector, value) {
}, 500));
}
function clickOnElement(selector) {
let element = document.querySelector(selector);
if (!element) {
throw new Error("Can not find the element");
}
SimpleTest.executeSoon(() => element.click());
}
async function onAddressChanged(type) {
return new Promise(resolve => {
formFillChromeScript.addMessageListener("formautofill-storage-changed", function onChanged(data) {
formFillChromeScript.removeMessageListener("formautofill-storage-changed", onChanged);
is(data.data, type, `Receive ${type} storage changed event`);
resolve();
});
});
}
function checkMenuEntries(expectedValues) {
let actualValues = getMenuEntries();
@ -32,7 +52,7 @@ function checkMenuEntries(expectedValues) {
}
}
function addAddress(address) {
async function addAddress(address) {
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:AddAddress", {address});
formFillChromeScript.addMessageListener("FormAutofillTest:AddressAdded", function onAdded(data) {
@ -43,7 +63,7 @@ function addAddress(address) {
});
}
function removeAddress(guid) {
async function removeAddress(guid) {
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:RemoveAddress", {guid});
formFillChromeScript.addMessageListener("FormAutofillTest:AddressRemoved", function onDeleted(data) {
@ -54,7 +74,7 @@ function removeAddress(guid) {
});
}
function updateAddress(guid, address) {
async function updateAddress(guid, address) {
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:UpdateAddress", {address, guid});
formFillChromeScript.addMessageListener("FormAutofillTest:AddressUpdated", function onUpdated(data) {
@ -65,6 +85,17 @@ function updateAddress(guid, address) {
});
}
async function checkAddresses(expectedAddresses) {
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:CheckAddresses", {expectedAddresses});
formFillChromeScript.addMessageListener("FormAutofillTest:areAddressesMatching", function onChecked(data) {
formFillChromeScript.removeMessageListener("FormAutofillTest:areAddressesMatching", onChecked);
resolve(data);
});
});
}
function formAutoFillCommonSetup() {
let chromeURL = SimpleTest.getTestFileURL("formautofill_parent_utils.js");
formFillChromeScript = SpecialPowers.loadChromeScript(chromeURL);

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

@ -7,6 +7,7 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
let {profileStorage} = Cu.import("resource://formautofill/ProfileStorage.jsm", {});
var ParentUtils = {
cleanUpAddress() {
@ -42,6 +43,41 @@ var ParentUtils = {
Services.obs.removeObserver(this, "formautofill-storage-changed");
this.cleanUpAddress();
},
areAddressesMatching(addressA, addressB) {
for (let field of profileStorage.addresses.VALID_FIELDS) {
if (addressA[field] !== addressB[field]) {
return false;
}
}
return true;
},
checkAddresses({expectedAddresses}) {
Services.cpmm.addMessageListener("FormAutofill:Addresses", function getResult(result) {
Services.cpmm.removeMessageListener("FormAutofill:Addresses", getResult);
let addresses = result.data;
if (addresses.length !== expectedAddresses.length) {
sendAsyncMessage("FormAutofillTest:areAddressesMatching", false);
return;
}
for (let address of addresses) {
let matching = expectedAddresses.some((expectedAddress) => {
return ParentUtils.areAddressesMatching(address, expectedAddress);
});
if (!matching) {
sendAsyncMessage("FormAutofillTest:areAddressesMatching", false);
return;
}
}
sendAsyncMessage("FormAutofillTest:areAddressesMatching", true);
});
Services.cpmm.sendAsyncMessage("FormAutofill:GetAddresses", {searchString: ""});
},
};
Services.obs.addObserver(ParentUtils, "formautofill-storage-changed");
@ -58,6 +94,10 @@ addMessageListener("FormAutofillTest:UpdateAddress", (msg) => {
ParentUtils.updateAddress("update", "FormAutofill:SaveAddress", msg, "FormAutofillTest:AddressUpdated");
});
addMessageListener("FormAutofillTest:CheckAddresses", (msg) => {
ParentUtils.checkAddresses(msg);
});
addMessageListener("cleanup", () => {
ParentUtils.cleanup();
});

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

@ -8,3 +8,4 @@ support-files =
[test_autofocus_form.html]
[test_basic_autocomplete_form.html]
[test_formautofill_preview_highlight.html]
[test_on_address_submission.html]

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

@ -0,0 +1,66 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test autofill submit</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="formautofill_common.js"></script>
<script type="text/javascript" src="satchel_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
Form autofill test: check if address is saved/updated correctly
<script>
/* import-globals-from ../../../../../testing/mochitest/tests/SimpleTest/SpawnTask.js */
/* import-globals-from ../../../../../toolkit/components/satchel/test/satchel_common.js */
/* import-globals-from formautofill_common.js */
"use strict";
let TEST_ADDRESSES = [{
organization: "Sesame Street",
"street-address": "123 Sesame Street.",
tel: "1-345-345-3456",
}, {
organization: "Mozilla",
"street-address": "331 E. Evelyn Avenue",
tel: "1-650-903-0800",
}];
// Autofill the address from dropdown menu.
add_task(async function check_storage_after_form_submitted() {
// We already verified the first time use case in browser test
await SpecialPowers.pushPrefEnv({
set: [["extensions.formautofill.firstTimeUse", false]],
});
for (let key in TEST_ADDRESSES[0]) {
await setInput("#" + key, TEST_ADDRESSES[0][key]);
}
clickOnElement("input[type=submit]");
let expectedAddresses = TEST_ADDRESSES.slice(0, 1);
await onAddressChanged("add");
let matching = await checkAddresses(expectedAddresses);
ok(matching, "Address saved as expected");
});
</script>
<div>
<form onsubmit="return false">
<p>This is a basic form for submitting test.</p>
<p><label>organization: <input id="organization" name="organization" autocomplete="organization" type="text"></label></p>
<p><label>streetAddress: <input id="street-address" name="street-address" autocomplete="street-address" type="text"></label></p>
<p><label>tel: <input id="tel" name="tel" autocomplete="tel" type="text"></label></p>
<p><label>country: <input id="country" name="country" autocomplete="country" type="text"></label></p>
<p><input type="submit"></p>
</form>
</div>
</body>
</html>

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

@ -108,7 +108,7 @@ TESTCASES.forEach(testcase => {
let input = MOCK_DOC.getElementById(key);
input.value = testcase.formValue[key];
}
sinon.spy(FormAutofillContent, "_onFormSubmit");
sinon.stub(FormAutofillContent, "_onFormSubmit");
FormAutofillContent.identifyAutofillFields(MOCK_DOC);
FormAutofillContent.notify(form);

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

@ -11,15 +11,17 @@
add_task(function* () {
yield addTab(URL_ROOT + "doc_negative_animation.html");
let {controller, panel} = yield openAnimationInspector();
const {controller, panel} = yield openAnimationInspector();
const timeline = panel.animationsTimelineComponent;
info("Wait until all animations have been added " +
"(they're added with setTimeout)");
while (controller.animationPlayers.length < 3) {
yield controller.once(controller.PLAYERS_UPDATED_EVENT);
const areTracksReady = () => timeline.animations.every(a => timeline.tracksMap.has(a));
// We need to wait for all tracks to be ready, cause this is an async part of the init
// of the panel.
while (controller.animationPlayers.length < 3 || !areTracksReady()) {
yield waitForAnimationTimelineRendering(panel);
}
// Same for animation targets, they're retrieved asynchronously.
yield waitForAllAnimationTargets(panel);
is(panel.animationsTimelineComponent.animations.length, 3,
@ -28,6 +30,5 @@ add_task(function* () {
// Reduce the known nodeFronts to a set to make them unique.
let nodeFronts = new Set(panel.animationsTimelineComponent
.targetNodes.map(n => n.previewer.nodeFront));
is(nodeFronts.size, 3,
"The animations are applied to 3 different node fronts");
is(nodeFronts.size, 3, "The animations are applied to 3 different node fronts");
});

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

@ -11,10 +11,12 @@
*
* @param {object} target
* The object the toolbox is debugging.
* @param {object} threadClient
* The toolbox's thread client
* @param {SourceMapService} sourceMapService
* The devtools-source-map functions
*/
function SourceMapURLService(target, sourceMapService) {
function SourceMapURLService(target, threadClient, sourceMapService) {
this._target = target;
this._sourceMapService = sourceMapService;
this._urls = new Map();
@ -24,6 +26,14 @@ function SourceMapURLService(target, sourceMapService) {
target.on("source-updated", this._onSourceUpdated);
target.on("will-navigate", this.reset);
// Start fetching the sources now.
this._loadingPromise = new Promise(resolve => {
threadClient.getSources(({sources}) => {
// Just ignore errors.
resolve(sources);
});
});
}
/**
@ -75,6 +85,14 @@ SourceMapURLService.prototype._onSourceUpdated = function (_, sourceEvent) {
* A promise resolving either to the original location, or null.
*/
SourceMapURLService.prototype.originalPositionFor = async function (url, line, column) {
// Ensure the sources are loaded before replying.
await this._loadingPromise;
// Maybe we were shut down while waiting.
if (!this._urls) {
return null;
}
const urlInfo = this._urls.get(url);
if (!urlInfo) {
return null;

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

@ -13,6 +13,8 @@ support-files =
code_binary_search.map
code_binary_search_absolute.js
code_binary_search_absolute.map
code_bundle_no_race.js
code_bundle_no_race.js.map
code_bundle_reload_1.js
code_bundle_reload_1.js.map
code_bundle_reload_2.js
@ -20,6 +22,7 @@ support-files =
code_inline_bundle.js
code_inline_original.js
code_math.js
code_no_race.js
code_reload_1.js
code_reload_2.js
doc_empty-tab-01.html
@ -52,6 +55,7 @@ support-files =
[browser_source_map-01.js]
[browser_source_map-absolute.js]
[browser_source_map-inline.js]
[browser_source_map-no-race.js]
[browser_source_map-reload.js]
[browser_target_from_url.js]
[browser_target_events.js]

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

@ -0,0 +1,41 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that the source map service doesn't race against source
// reporting.
"use strict";
const JS_URL = URL_ROOT + "code_bundle_no_race.js";
const PAGE_URL = `data:text/html,
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Empty test page to test race case</title>
</head>
<body>
<script src="${JS_URL}"></script>
</body>
</html>`;
const ORIGINAL_URL = "webpack:///code_no_race.js";
const GENERATED_LINE = 84;
const ORIGINAL_LINE = 11;
add_task(function* () {
// Start with the empty page, then navigate, so that we can properly
// listen for new sources arriving.
const toolbox = yield openNewTabAndToolbox(PAGE_URL, "webconsole");
const service = toolbox.sourceMapURLService;
info(`checking original location for ${JS_URL}:${GENERATED_LINE}`);
let newLoc = yield service.originalPositionFor(JS_URL, GENERATED_LINE);
is(newLoc.sourceUrl, ORIGINAL_URL, "check mapped URL");
is(newLoc.line, ORIGINAL_LINE, "check mapped line number");
});

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

@ -0,0 +1,95 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Original source code for the inline source map test.
// The generated file was made with
// webpack --devtool source-map code_no_race.js code_bundle_no_race.js
function f() {
console.log("anything will do");
}
f();
// Avoid script GC.
window.f = f;
/***/ })
/******/ ]);
//# sourceMappingURL=code_bundle_no_race.js.map

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

@ -0,0 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap bac8dffc0cc5eb13fa9d","webpack:///./code_no_race.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AChEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA","file":"code_bundle_no_race.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap bac8dffc0cc5eb13fa9d","/* Any copyright is dedicated to the Public Domain.\n http://creativecommons.org/publicdomain/zero/1.0/ */\n\n// Original source code for the inline source map test.\n// The generated file was made with\n// webpack --devtool source-map code_no_race.js code_bundle_no_race.js\n\n\"use strict\";\n\nfunction f() {\n console.log(\"anything will do\");\n}\n\nf();\n\n// Avoid script GC.\nwindow.f = f;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./code_no_race.js\n// module id = 0\n// module chunks = 0"],"sourceRoot":""}

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

@ -0,0 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Original source code for the inline source map test.
// The generated file was made with
// webpack --devtool source-map code_no_race.js code_bundle_no_race.js
"use strict";
function f() {
console.log("anything will do");
}
f();
// Avoid script GC.
window.f = f;

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

@ -567,7 +567,8 @@ Toolbox.prototype = {
if (!sourceMaps) {
return null;
}
this._sourceMapURLService = new SourceMapURLService(this._target, sourceMaps);
this._sourceMapURLService = new SourceMapURLService(this._target, this.threadClient,
sourceMaps);
return this._sourceMapURLService;
},

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

@ -25,7 +25,6 @@
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsEscape.h"
#include "nsITextToSubURI.h"
#include "nsCRT.h"
#include "nsIParserService.h"
#include "nsContentUtils.h"
@ -132,10 +131,6 @@ nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
}
}
}
// Need to escape URI.
nsAutoString tempURI(valueStr);
if (!isJS && NS_FAILED(EscapeURI(aContent, tempURI, valueStr)))
valueStr = tempURI;
}
if (mRewriteEncodingDeclaration && aTagName == nsGkAtoms::meta &&

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

@ -25,7 +25,6 @@
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsEscape.h"
#include "nsITextToSubURI.h"
#include "nsCRT.h"
#include "nsIParserService.h"
#include "nsContentUtils.h"
@ -157,70 +156,6 @@ nsXHTMLContentSerializer::AppendText(nsIContent* aText,
return NS_OK;
}
nsresult
nsXHTMLContentSerializer::EscapeURI(nsIContent* aContent, const nsAString& aURI, nsAString& aEscapedURI)
{
// URL escape %xx cannot be used in JS.
// No escaping if the scheme is 'javascript'.
if (IsJavaScript(aContent, nsGkAtoms::href, kNameSpaceID_None, aURI)) {
aEscapedURI = aURI;
return NS_OK;
}
// nsITextToSubURI does charset convert plus uri escape
// This is needed to convert to a document charset which is needed to support existing browsers.
// But we eventually want to use UTF-8 instead of a document charset, then the code would be much simpler.
// See HTML 4.01 spec, "Appendix B.2.1 Non-ASCII characters in URI attribute values"
nsCOMPtr<nsITextToSubURI> textToSubURI;
nsAutoString uri(aURI); // in order to use FindCharInSet()
nsresult rv = NS_OK;
if (!mCharset.IsEmpty() && !IsASCII(uri)) {
textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
int32_t start = 0;
int32_t end;
nsAutoString part;
nsXPIDLCString escapedURI;
aEscapedURI.Truncate(0);
// Loop and escape parts by avoiding escaping reserved characters
// (and '%', '#', as well as '[' and ']' for IPv6 address literals).
while ((end = uri.FindCharInSet("%#;/?:@&=+$,[]", start)) != -1) {
part = Substring(aURI, start, (end-start));
if (textToSubURI && !IsASCII(part)) {
rv = textToSubURI->ConvertAndEscape(mCharset.get(), part.get(), getter_Copies(escapedURI));
NS_ENSURE_SUCCESS(rv, rv);
} else if (NS_WARN_IF(!NS_Escape(NS_ConvertUTF16toUTF8(part), escapedURI,
url_Path))) {
return NS_ERROR_OUT_OF_MEMORY;
}
AppendASCIItoUTF16(escapedURI, aEscapedURI);
// Append a reserved character without escaping.
part = Substring(aURI, end, 1);
aEscapedURI.Append(part);
start = end + 1;
}
if (start < (int32_t) aURI.Length()) {
// Escape the remaining part.
part = Substring(aURI, start, aURI.Length()-start);
if (textToSubURI) {
rv = textToSubURI->ConvertAndEscape(mCharset.get(), part.get(), getter_Copies(escapedURI));
NS_ENSURE_SUCCESS(rv, rv);
} else if (NS_WARN_IF(!NS_Escape(NS_ConvertUTF16toUTF8(part), escapedURI,
url_Path))) {
return NS_ERROR_OUT_OF_MEMORY;
}
AppendASCIItoUTF16(escapedURI, aEscapedURI);
}
return rv;
}
bool
nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
nsIContent *aOriginalElement,
@ -373,10 +308,6 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
}
}
}
// Need to escape URI.
nsAutoString tempURI(valueStr);
if (!isJS && NS_FAILED(EscapeURI(aContent, tempURI, valueStr)))
valueStr = tempURI;
}
if (mRewriteEncodingDeclaration && aTagName == nsGkAtoms::meta &&

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

@ -92,10 +92,6 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
virtual bool AppendAndTranslateEntities(const nsAString& aStr,
nsAString& aOutputStr) override;
nsresult EscapeURI(nsIContent* aContent,
const nsAString& aURI,
nsAString& aEscapedURI);
private:
bool IsElementPreformatted(nsIContent* aNode);

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

@ -67,8 +67,6 @@ function beginTest() {
[ "-moz-MenubarHoverText", 0x00, 0x00, 0x00 ],
[ "-moz-NativeHyperlinkText", 0x00, 0x66, 0xCC ],
[ "-moz-OddTreeRow", 0xFF, 0xFF, 0xFF ],
[ "-moz-html-CellHighlight", 0x33, 0x99, 0xFF ],
[ "-moz-html-CellHighlightText", 0xFF, 0xFF, 0xFF ],
[ "-moz-mac-chrome-active", 0xB2, 0xB2, 0xB2 ],
[ "-moz-mac-chrome-inactive", 0xE1, 0xE1, 0xE1 ],
[ "-moz-mac-focusring", 0x60, 0x9D, 0xD7 ],
@ -81,6 +79,8 @@ function beginTest() {
[ "-moz-mac-SecondaryHighlight", 0xD4, 0xD4, 0xD4 ],
[ "-moz-win-MediaText", 0xFF, 0xFF, 0xFF ],
[ "-moz-win-CommunicationsText", 0xFF, 0xFF, 0xFF ],
[ "-moz-html-CellHighlight", 0x33, 0x99, 0xFF ],
[ "-moz-html-CellHighlightText", 0xFF, 0xFF, 0xFF ],
// These five are configured via Tools -> Options -> Content -> Colors.
//"-moz-ActiveHyperlinkText",

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

@ -4,17 +4,20 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ChromiumCDMParent.h"
#include "mozilla/gmp/GMPTypes.h"
#include "ChromiumCDMProxy.h"
#include "content_decryption_module.h"
#include "GMPContentChild.h"
#include "GMPContentParent.h"
#include "mozilla/Unused.h"
#include "ChromiumCDMProxy.h"
#include "mozilla/dom/MediaKeyMessageEventBinding.h"
#include "mozilla/Telemetry.h"
#include "content_decryption_module.h"
#include "GMPLog.h"
#include "MediaPrefs.h"
#include "GMPUtils.h"
#include "MediaPrefs.h"
#include "mozilla/dom/MediaKeyMessageEventBinding.h"
#include "mozilla/gmp/GMPTypes.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Unused.h"
#include "mp4_demuxer/AnnexB.h"
#include "mp4_demuxer/H264.h"
namespace mozilla {
namespace gmp {
@ -731,7 +734,7 @@ ChromiumCDMParent::RecvDecodedData(const CDMVideoFrame& aFrame,
return IPC_OK();
}
mDecodePromise.ResolveIfExists({ Move(v) }, __func__);
ReorderAndReturnOutput(Move(v));
return IPC_OK();
}
@ -740,7 +743,11 @@ ipc::IPCResult
ChromiumCDMParent::RecvDecodedShmem(const CDMVideoFrame& aFrame,
ipc::Shmem&& aShmem)
{
GMP_LOG("ChromiumCDMParent::RecvDecodedShmem(this=%p)", this);
GMP_LOG("ChromiumCDMParent::RecvDecodedShmem(this=%p) time=%" PRId64
" duration=%" PRId64,
this,
aFrame.mTimestamp(),
aFrame.mDuration());
// On failure we need to deallocate the shmem we're to return to the
// CDM. On success we return it to the CDM to be reused.
@ -775,11 +782,26 @@ ChromiumCDMParent::RecvDecodedShmem(const CDMVideoFrame& aFrame,
// for it again.
autoDeallocateShmem.release();
mDecodePromise.ResolveIfExists({ Move(v) }, __func__);
ReorderAndReturnOutput(Move(v));
return IPC_OK();
}
void
ChromiumCDMParent::ReorderAndReturnOutput(RefPtr<VideoData>&& aFrame)
{
if (mMaxRefFrames == 0) {
mDecodePromise.ResolveIfExists({ Move(aFrame) }, __func__);
return;
}
mReorderQueue.Push(Move(aFrame));
MediaDataDecoder::DecodedData results;
while (mReorderQueue.Length() > mMaxRefFrames) {
results.AppendElement(mReorderQueue.Pop());
}
mDecodePromise.Resolve(Move(results), __func__);
}
already_AddRefed<VideoData>
ChromiumCDMParent::CreateVideoFrame(const CDMVideoFrame& aFrame,
Span<uint8_t> aData)
@ -915,6 +937,13 @@ ChromiumCDMParent::InitializeVideoDecoder(
__func__);
}
mMaxRefFrames =
(aConfig.mCodec() == cdm::VideoDecoderConfig::kCodecH264)
? mp4_demuxer::AnnexB::HasSPS(aInfo.mExtraData)
? mp4_demuxer::H264::ComputeMaxRefFrames(aInfo.mExtraData)
: 16
: 0;
mVideoDecoderInitialized = true;
mImageContainer = aImageContainer;
mVideoInfo = aInfo;
@ -987,12 +1016,15 @@ RefPtr<MediaDataDecoder::FlushPromise>
ChromiumCDMParent::FlushVideoDecoder()
{
if (mIsShutdown) {
MOZ_ASSERT(mReorderQueue.IsEmpty());
return MediaDataDecoder::FlushPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent is shutdown")),
__func__);
}
mReorderQueue.Clear();
mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
if (!SendResetVideoDecoder()) {
return MediaDataDecoder::FlushPromise::CreateAndReject(
@ -1005,6 +1037,7 @@ ChromiumCDMParent::FlushVideoDecoder()
ipc::IPCResult
ChromiumCDMParent::RecvResetVideoDecoderComplete()
{
MOZ_ASSERT(mReorderQueue.IsEmpty());
if (mIsShutdown) {
MOZ_ASSERT(mFlushDecoderPromise.IsEmpty());
return IPC_OK();
@ -1038,7 +1071,13 @@ ChromiumCDMParent::RecvDrainComplete()
MOZ_ASSERT(mDecodePromise.IsEmpty());
return IPC_OK();
}
mDecodePromise.ResolveIfExists(MediaDataDecoder::DecodedData(), __func__);
MediaDataDecoder::DecodedData samples;
while (!mReorderQueue.IsEmpty()) {
samples.AppendElement(Move(mReorderQueue.Pop()));
}
mDecodePromise.ResolveIfExists(Move(samples), __func__);
return IPC_OK();
}
RefPtr<ShutdownPromise>
@ -1097,6 +1136,8 @@ ChromiumCDMParent::Shutdown()
// (including from an already-queued task, e.g.: ActorDestroy).
mProxy = nullptr;
mReorderQueue.Clear();
for (RefPtr<DecryptJob>& decrypt : mDecrypts) {
decrypt->PostResult(eme::AbortedErr);
}

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

@ -16,6 +16,7 @@
#include "PlatformDecoderModule.h"
#include "ImageContainer.h"
#include "mozilla/Span.h"
#include "ReorderQueue.h"
namespace mozilla {
@ -128,6 +129,8 @@ protected:
void ActorDestroy(ActorDestroyReason aWhy) override;
bool SendBufferToCDM(uint32_t aSizeInBytes);
void ReorderAndReturnOutput(RefPtr<VideoData>&& aFrame);
void RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage);
@ -172,6 +175,15 @@ protected:
bool mIsShutdown = false;
bool mVideoDecoderInitialized = false;
bool mActorDestroyed = false;
// The H.264 decoder in Widevine CDM versions 970 and later output in decode
// order rather than presentation order, so we reorder in presentation order
// before presenting. mMaxRefFrames is non-zero if we have an initialized
// decoder and we are decoding H.264. If so, it stores the maximum length of
// the reorder queue that we need. Note we may have multiple decoders for the
// life time of this object, but never more than one active at once.
uint32_t mMaxRefFrames = 0;
ReorderQueue mReorderQueue;
};
} // namespace gmp

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

@ -14,6 +14,7 @@ EXPORTS += [
'MediaTelemetryConstants.h',
'PDMFactory.h',
'PlatformDecoderModule.h',
'ReorderQueue.h',
'SimpleMap.h',
'wrappers/H264Converter.h',
'wrappers/MediaDataDecoderProxy.h'

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

@ -100,6 +100,10 @@ using namespace mozilla::layers;
uint8_t gNotifySubDocInvalidationData;
// This preference was first introduced in Bug 232227, in order to prevent
// system colors from being exposed to CSS or canvas.
constexpr char kUseStandinsForNativeColors[] = "ui.use_standins_for_native_colors";
/**
* Layer UserData for ContainerLayers that want to be notified
* of local invalidations of them and their descendant layers.
@ -381,6 +385,9 @@ nsPresContext::Destroy()
Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
"nglayout.debug.paint_flashing_chrome",
this);
Preferences::UnregisterCallback(nsPresContext::PrefChangedCallback,
kUseStandinsForNativeColors,
this);
mRefreshDriver = nullptr;
}
@ -468,11 +475,17 @@ nsPresContext::GetDocumentColorPreferences()
bool isChromeDocShell = false;
static int32_t sDocumentColorsSetting;
static bool sDocumentColorsSettingPrefCached = false;
static bool sUseStandinsForNativeColors = false;
if (!sDocumentColorsSettingPrefCached) {
sDocumentColorsSettingPrefCached = true;
Preferences::AddIntVarCache(&sDocumentColorsSetting,
"browser.display.document_color_use",
0);
// The preference "ui.use_standins_for_native_colors" also affects
// default foreground and background colors.
Preferences::AddBoolVarCache(&sUseStandinsForNativeColors,
kUseStandinsForNativeColors);
}
nsIDocument* doc = mDocument->GetDisplayDocument();
@ -501,7 +514,14 @@ nsPresContext::GetDocumentColorPreferences()
!Preferences::GetBool("browser.display.use_system_colors", false);
}
if (usePrefColors) {
if (sUseStandinsForNativeColors) {
// Once the preference "ui.use_standins_for_native_colors" is enabled,
// use fixed color values instead of prefered colors and system colors.
mDefaultColor = LookAndFeel::GetColorUsingStandins(
LookAndFeel::eColorID_windowtext, NS_RGB(0x00, 0x00, 0x00));
mBackgroundColor = LookAndFeel::GetColorUsingStandins(
LookAndFeel::eColorID_window, NS_RGB(0xff, 0xff, 0xff));
} else if (usePrefColors) {
nsAdoptingString colorStr =
Preferences::GetString("browser.display.foreground_color");
@ -924,6 +944,9 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
"nglayout.debug.paint_flashing_chrome",
this);
Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
kUseStandinsForNativeColors,
this);
nsresult rv = mEventManager->Init();
NS_ENSURE_SUCCESS(rv, rv);

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

@ -149,9 +149,12 @@ SERVO_BINDING_FUNC(Servo_StyleRule_SetStyle, void,
RawServoDeclarationBlockBorrowed declarations)
SERVO_BINDING_FUNC(Servo_StyleRule_GetSelectorText, void,
RawServoStyleRuleBorrowed rule, nsAString* result)
SERVO_BINDING_FUNC(Servo_StyleRule_GetSelectorTextFromIndex, void,
SERVO_BINDING_FUNC(Servo_StyleRule_GetSelectorTextAtIndex, void,
RawServoStyleRuleBorrowed rule, uint32_t index,
nsAString* result)
SERVO_BINDING_FUNC(Servo_StyleRule_GetSpecificityAtIndex, void,
RawServoStyleRuleBorrowed rule, uint32_t index,
uint64_t* specificity)
SERVO_BINDING_FUNC(Servo_StyleRule_GetSelectorCount, void,
RawServoStyleRuleBorrowed rule, uint32_t* count)
SERVO_BINDING_FUNC(Servo_ImportRule_GetHref, void,

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

@ -262,14 +262,14 @@ ServoStyleRule::GetSelectorCount()
nsresult
ServoStyleRule::GetSelectorText(uint32_t aSelectorIndex, nsAString& aText)
{
Servo_StyleRule_GetSelectorTextFromIndex(mRawRule, aSelectorIndex, &aText);
Servo_StyleRule_GetSelectorTextAtIndex(mRawRule, aSelectorIndex, &aText);
return NS_OK;
}
nsresult
ServoStyleRule::GetSpecificity(uint32_t aSelectorIndex, uint64_t* aSpecificity)
{
// TODO Bug 1370501
Servo_StyleRule_GetSpecificityAtIndex(mRawRule, aSelectorIndex, aSpecificity);
return NS_OK;
}

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

@ -49,3 +49,9 @@ if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
# Suppress warnings in third-party code.
if CONFIG['GNU_CC']:
CFLAGS += ['-Wno-sign-compare']
if CONFIG['_MSC_VER'] and not CONFIG['CLANG_CL']:
CFLAGS += [
'-wd4018', # '<' : signed/unsigned mismatch
'-wd4101', # unreferenced local variable
]

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

827
npm-shrinkwrap.json сгенерированный

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

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

@ -4,10 +4,12 @@
"repository": {},
"license": "MPL-2.0",
"dependencies": {
"escope": "^3.6.0",
"eslint": "3.19.0",
"eslint-plugin-html": "2.0.3",
"eslint-plugin-mozilla": "file:tools\\lint\\eslint\\eslint-plugin-mozilla",
"eslint-plugin-react": "6.10.3",
"escope": "^3.6.0",
"eslint-plugin-spidermonkey-js": "file:tools\\lint\\eslint\\eslint-plugin-spidermonkey-js",
"espree": "^3.4.0",
"estraverse": "^4.2.0",
"ini-parser": "^0.0.2",

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

@ -431,7 +431,7 @@ var vectors = [
},
{
"data": "<!-- IE 5-8 standards mode -->\r\n<a href=http://foo.bar/#x=`y></a><img alt=\"`><img src=xx:x onerror=alert(1)></a>\">\r\n\r\n<!-- IE 5-9 standards mode -->\r\n<!a foo=x=`y><img alt=\"`><img src=xx:x onerror=alert(2)//\">\r\n<?a foo=x=`y><img alt=\"`><img src=xx:x onerror=alert(3)//\">",
"sanitized": "<html><head></head><body><a href=\"http://foo.bar/#x=%60y\"></a><img alt=\"`&gt;&lt;img src=xx:x onerror=alert(1)&gt;&lt;/a&gt;\">\n\n\n<img alt=\"`&gt;&lt;img src=xx:x onerror=alert(2)//\">\n<img alt=\"`&gt;&lt;img src=xx:x onerror=alert(3)//\"></body></html>"
"sanitized": "<html><head></head><body><a href=\"http://foo.bar/#x=`y\"></a><img alt=\"`&gt;&lt;img src=xx:x onerror=alert(1)&gt;&lt;/a&gt;\">\n\n\n<img alt=\"`&gt;&lt;img src=xx:x onerror=alert(2)//\">\n<img alt=\"`&gt;&lt;img src=xx:x onerror=alert(3)//\"></body></html>"
},
{
"data": "<svg xmlns=\"http://www.w3.org/2000/svg\">\n<a id=\"x\"><rect fill=\"white\" width=\"1000\" height=\"1000\"/></a>\n<rect fill=\"white\" style=\"clip-path:url(test3.svg#a);fill:url(#b);filter:url(#c);marker:url(#d);mask:url(#e);stroke:url(#f);\"/>\n</svg>",

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

@ -17,11 +17,12 @@ import functools
from WebIDL import (
BuiltinTypes,
IDLBuiltinType,
IDLNullValue,
IDLNullableType,
IDLObject,
IDLType,
IDLInterfaceMember,
IDLNullableType,
IDLNullValue,
IDLObject,
IDLPromiseType,
IDLType,
IDLUndefinedValue,
IDLWrapperType,
)
@ -94,14 +95,14 @@ def stripTrailingWhitespace(text):
def innerContainerType(type):
assert type.isSequence() or type.isMozMap()
assert type.isSequence() or type.isRecord()
return type.inner.inner if type.nullable() else type.inner
def wrapInNativeContainerType(type, inner):
if type.isSequence():
containerType = "Vec"
elif type.isMozMap():
elif type.isRecord():
containerType = "MozMap"
else:
raise TypeError("Unexpected container type %s", type)
@ -697,7 +698,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not (isEnforceRange and isClamp) # These are mutually exclusive
if type.isSequence() or type.isMozMap():
if type.isSequence() or type.isRecord():
innerInfo = getJSToNativeConversionInfo(innerContainerType(type),
descriptorProvider,
isMember=isMember)
@ -754,6 +755,56 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
return handleOptional(templateBody, declType, default)
if type.isPromise():
assert not type.nullable()
# Per spec, what we're supposed to do is take the original
# Promise.resolve and call it with the original Promise as this
# value to make a Promise out of whatever value we actually have
# here. The question is which global we should use. There are
# a couple cases to consider:
#
# 1) Normal call to API with a Promise argument. This is a case the
# spec covers, and we should be using the current Realm's
# Promise. That means the current compartment.
# 2) Promise return value from a callback or callback interface.
# This is in theory a case the spec covers but in practice it
# really doesn't define behavior here because it doesn't define
# what Realm we're in after the callback returns, which is when
# the argument conversion happens. We will use the current
# compartment, which is the compartment of the callable (which
# may itself be a cross-compartment wrapper itself), which makes
# as much sense as anything else. In practice, such an API would
# once again be providing a Promise to signal completion of an
# operation, which would then not be exposed to anyone other than
# our own implementation code.
templateBody = fill(
"""
{ // Scope for our JSAutoCompartment.
rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx));
let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get());
rooted!(in(cx) let mut valueToResolve = $${val}.get());
if !JS_WrapValue(cx, valueToResolve.handle_mut()) {
$*{exceptionCode}
}
match Promise::Resolve(&promiseGlobal, cx, valueToResolve.handle()) {
Ok(value) => value,
Err(error) => {
throw_dom_exception(cx, &promiseGlobal, error);
$*{exceptionCode}
}
}
}
""",
exceptionCode=exceptionCode)
if isArgument:
declType = CGGeneric("&Promise")
else:
declType = CGGeneric("Rc<Promise>")
return handleOptional(templateBody, declType, handleDefaultNull("None"))
if type.isGeckoInterface():
assert not isEnforceRange and not isClamp
@ -780,79 +831,34 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
elif isArgument:
descriptorType = descriptor.argumentType
templateBody = ""
isPromise = descriptor.interface.identifier.name == "Promise"
if isPromise:
# Per spec, what we're supposed to do is take the original
# Promise.resolve and call it with the original Promise as this
# value to make a Promise out of whatever value we actually have
# here. The question is which global we should use. There are
# a couple cases to consider:
#
# 1) Normal call to API with a Promise argument. This is a case the
# spec covers, and we should be using the current Realm's
# Promise. That means the current compartment.
# 2) Promise return value from a callback or callback interface.
# This is in theory a case the spec covers but in practice it
# really doesn't define behavior here because it doesn't define
# what Realm we're in after the callback returns, which is when
# the argument conversion happens. We will use the current
# compartment, which is the compartment of the callable (which
# may itself be a cross-compartment wrapper itself), which makes
# as much sense as anything else. In practice, such an API would
# once again be providing a Promise to signal completion of an
# operation, which would then not be exposed to anyone other than
# our own implementation code.
templateBody = fill(
"""
{ // Scope for our JSAutoCompartment.
if descriptor.interface.isConsequential():
raise TypeError("Consequential interface %s being used as an "
"argument" % descriptor.interface.identifier.name)
rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx));
let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get());
rooted!(in(cx) let mut valueToResolve = $${val}.get());
if !JS_WrapValue(cx, valueToResolve.handle_mut()) {
$*{exceptionCode}
}
match Promise::Resolve(&promiseGlobal, cx, valueToResolve.handle()) {
Ok(value) => value,
Err(error) => {
throw_dom_exception(cx, &promiseGlobal, error);
$*{exceptionCode}
}
}
}
""",
exceptionCode=exceptionCode)
if failureCode is None:
substitutions = {
"sourceDescription": sourceDescription,
"interface": descriptor.interface.identifier.name,
"exceptionCode": exceptionCode,
}
unwrapFailureCode = string.Template(
'throw_type_error(cx, "${sourceDescription} does not '
'implement interface ${interface}.");\n'
'${exceptionCode}').substitute(substitutions)
else:
if descriptor.interface.isConsequential():
raise TypeError("Consequential interface %s being used as an "
"argument" % descriptor.interface.identifier.name)
unwrapFailureCode = failureCode
if failureCode is None:
substitutions = {
"sourceDescription": sourceDescription,
"interface": descriptor.interface.identifier.name,
"exceptionCode": exceptionCode,
templateBody = fill(
"""
match ${function}($${val}) {
Ok(val) => val,
Err(()) => {
$*{failureCode}
}
unwrapFailureCode = string.Template(
'throw_type_error(cx, "${sourceDescription} does not '
'implement interface ${interface}.");\n'
'${exceptionCode}').substitute(substitutions)
else:
unwrapFailureCode = failureCode
templateBody = fill(
"""
match ${function}($${val}) {
Ok(val) => val,
Err(()) => {
$*{failureCode}
}
}
""",
failureCode=unwrapFailureCode + "\n",
function=conversionFunction)
}
""",
failureCode=unwrapFailureCode + "\n",
function=conversionFunction)
declType = CGGeneric(descriptorType)
if type.nullable():
@ -1323,7 +1329,7 @@ def typeNeedsCx(type, retVal=False):
# Returns a conversion behavior suitable for a type
def getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs):
if type.isSequence() or type.isMozMap():
if type.isSequence() or type.isRecord():
return getConversionConfigForType(innerContainerType(type), isEnforceRange, isClamp, treatNullAs)
if type.isDOMString():
assert not isEnforceRange and not isClamp
@ -1381,6 +1387,9 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
if returnType.nullable():
result = CGWrapper(result, pre="Option<", post=">")
return result
if returnType.isPromise():
assert not returnType.nullable()
return CGGeneric("Rc<Promise>")
if returnType.isGeckoInterface():
descriptor = descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name)
@ -1408,7 +1417,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
if returnType.nullable():
result = CGWrapper(result, pre="Option<", post=">")
return result
if returnType.isSequence() or returnType.isMozMap():
if returnType.isSequence() or returnType.isRecord():
result = getRetvalDeclarationForType(innerContainerType(returnType), descriptorProvider)
result = wrapInNativeContainerType(returnType, result)
if returnType.nullable():
@ -1946,8 +1955,10 @@ class CGImports(CGWrapper):
if parentName:
descriptor = descriptorProvider.getDescriptor(parentName)
extras += [descriptor.path, descriptor.bindingPath]
elif t.isType() and t.isMozMap():
elif t.isType() and t.isRecord():
extras += ['dom::bindings::mozmap::MozMap']
elif isinstance(t, IDLPromiseType):
extras += ["dom::promise::Promise"]
else:
if t.isEnum():
extras += [getModuleFromObject(t) + '::' + getIdentifier(t).name + 'Values']
@ -3819,7 +3830,9 @@ class CGMemberJITInfo(CGThing):
return "JSVAL_TYPE_UNDEFINED"
if t.isSequence():
return "JSVAL_TYPE_OBJECT"
if t.isMozMap():
if t.isRecord():
return "JSVAL_TYPE_OBJECT"
if t.isPromise():
return "JSVAL_TYPE_OBJECT"
if t.isGeckoInterface():
return "JSVAL_TYPE_OBJECT"
@ -4055,7 +4068,7 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
elif type.isDictionary():
name = type.name
typeName = name
elif type.isSequence() or type.isMozMap():
elif type.isSequence() or type.isRecord():
name = type.name
inner = getUnionTypeTemplateVars(innerContainerType(type), descriptorProvider)
typeName = wrapInNativeContainerType(type, CGGeneric(inner["typeName"])).define()
@ -4208,7 +4221,7 @@ class CGUnionConversionStruct(CGThing):
else:
object = None
mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes)
mozMapMemberTypes = filter(lambda t: t.isRecord(), memberTypes)
if len(mozMapMemberTypes) > 0:
assert len(mozMapMemberTypes) == 1
typeName = mozMapMemberTypes[0].name
@ -6870,6 +6883,8 @@ def process_arg(expr, arg):
expr += ".r()"
else:
expr = "&" + expr
elif isinstance(arg.type, IDLPromiseType):
expr = "&" + expr
return expr

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

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

@ -0,0 +1,162 @@
def WebIDLTest(parser, harness):
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions(DOMString a)] void foo(boolean arg2);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] with an argument")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions(DOMString b)] readonly attribute boolean bar;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] with an argument")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] attribute boolean bar;
};
""")
results = parser.finish()
except Exception, e:
harness.ok(False, "Shouldn't have thrown for [CEReactions] used on writable attribute. %s" % e)
threw = True
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] void foo(boolean arg2);
};
""")
results = parser.finish()
except Exception, e:
harness.ok(False, "Shouldn't have thrown for [CEReactions] used on regular operations. %s" % e)
threw = True
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] readonly attribute boolean A;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] used on a readonly attribute")
parser = parser.reset()
threw = False
try:
parser.parse("""
[CEReactions]
interface Foo {
}
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] used on a interface")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] getter any(DOMString name);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw,
"Should have thrown for [CEReactions] used on a named getter")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] creator boolean (DOMString name, boolean value);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw,
"Should have thrown for [CEReactions] used on a named creator")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] legacycaller double compute(double x);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw,
"Should have thrown for [CEReactions] used on a legacycaller")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] stringifier DOMString ();
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw,
"Should have thrown for [CEReactions] used on a stringifier")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] jsonifier;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] used on a jsonifier")

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

@ -13,7 +13,7 @@ def WebIDLTest(parser, harness):
def checkMethod(method, QName, name, signatures,
static=True, getter=False, setter=False, creator=False,
deleter=False, legacycaller=False, stringifier=False,
chromeOnly=False):
chromeOnly=False, htmlConstructor=False):
harness.ok(isinstance(method, WebIDL.IDLMethod),
"Should be an IDLMethod")
harness.ok(method.isMethod(), "Method is a method")
@ -29,6 +29,7 @@ def WebIDLTest(parser, harness):
harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value")
harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value")
harness.check(method.getExtendedAttribute("ChromeOnly") is not None, chromeOnly, "Method has the correct value for ChromeOnly")
harness.check(method.isHTMLConstructor(), htmlConstructor, "Method has the correct htmlConstructor value")
harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures")
sigpairs = zip(method.signatures(), signatures)
@ -93,6 +94,21 @@ def WebIDLTest(parser, harness):
"constructor", [("TestChromeConstructor (Wrapper)", [])],
chromeOnly=True)
parser = parser.reset()
parser.parse("""
[HTMLConstructor]
interface TestHTMLConstructor {
};
""")
results = parser.finish()
harness.check(len(results), 1, "Should be one production")
harness.ok(isinstance(results[0], WebIDL.IDLInterface),
"Should be an IDLInterface")
checkMethod(results[0].ctor(), "::TestHTMLConstructor::constructor",
"constructor", [("TestHTMLConstructor (Wrapper)", [])],
htmlConstructor=True)
parser = parser.reset()
threw = False
try:
@ -107,3 +123,151 @@ def WebIDLTest(parser, harness):
threw = True
harness.ok(threw, "Can't have both a Constructor and a ChromeConstructor")
# Test HTMLConstructor with argument
parser = parser.reset()
threw = False
try:
parser.parse("""
[HTMLConstructor(DOMString a)]
interface TestHTMLConstructorWithArgs {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "HTMLConstructor should take no argument")
# Test HTMLConstructor on a callback interface
parser = parser.reset()
threw = False
try:
parser.parse("""
[HTMLConstructor]
callback interface TestHTMLConstructorOnCallbackInterface {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "HTMLConstructor can't be used on a callback interface")
# Test HTMLConstructor and Constructor
parser = parser.reset()
threw = False
try:
parser.parse("""
[Constructor,
HTMLConstructor]
interface TestHTMLConstructorAndConstructor {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Can't have both a Constructor and a HTMLConstructor")
parser = parser.reset()
threw = False
try:
parser.parse("""
[HTMLConstructor,
Constructor]
interface TestHTMLConstructorAndConstructor {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor")
parser = parser.reset()
threw = False
try:
parser.parse("""
[HTMLConstructor,
Constructor(DOMString a)]
interface TestHTMLConstructorAndConstructor {
};
""")
except:
threw = True
harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor")
parser = parser.reset()
threw = False
try:
parser.parse("""
[Constructor(DOMString a),
HTMLConstructor]
interface TestHTMLConstructorAndConstructor {
};
""")
except:
threw = True
harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor")
# Test HTMLConstructor and ChromeConstructor
parser = parser.reset()
threw = False
try:
parser.parse("""
[ChromeConstructor,
HTMLConstructor]
interface TestHTMLConstructorAndChromeConstructor {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor")
parser = parser.reset()
threw = False
try:
parser.parse("""
[HTMLConstructor,
ChromeConstructor]
interface TestHTMLConstructorAndChromeConstructor {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor")
parser = parser.reset()
threw = False
try:
parser.parse("""
[ChromeConstructor(DOMString a),
HTMLConstructor]
interface TestHTMLConstructorAndChromeConstructor {
};
""")
results = parser.finish()
except:
threw = True
parser = parser.reset()
threw = False
try:
parser.parse("""
[HTMLConstructor,
ChromeConstructor(DOMString a)]
interface TestHTMLConstructorAndChromeConstructor {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor")

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

@ -34,3 +34,36 @@ def WebIDLTest(parser, harness):
interface TestNamedConstructorNoInterfaceObject {
};
""")
# Test HTMLConstructor and NoInterfaceObject
parser = parser.reset()
threw = False
try:
parser.parse("""
[NoInterfaceObject, HTMLConstructor]
interface TestHTMLConstructorNoInterfaceObject {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown.")
parser = parser.reset()
threw = False
try:
parser.parse("""
[HTMLConstructor, NoInterfaceObject]
interface TestHTMLConstructorNoInterfaceObject {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown.")

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

@ -158,21 +158,27 @@ def WebIDLTest(parser, harness):
"CallbackInterface?", "CallbackInterface2",
"object", "Callback", "Callback2", "optional Dict",
"optional Dict2", "sequence<long>", "sequence<short>",
"MozMap<object>", "MozMap<Dict>", "MozMap<long>",
"record<DOMString, object>",
"record<USVString, Dict>",
"record<ByteString, long>",
"Date", "Date?", "any",
"Promise<any>", "Promise<any>?",
"USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer",
"Uint8Array", "Uint16Array" ]
# When we can parse Date and RegExp, we need to add them here.
"Uint8Array", "Uint16Array",
"(long or Callback)", "optional (long or Dict)",
]
# When we can parse Date, we need to add it here.
# XXXbz we can, and should really do that...
# Try to categorize things a bit to keep list lengths down
def allBut(list1, list2):
return [a for a in list1 if a not in list2 and
(a != "any" and a != "Promise<any>" and a != "Promise<any>?")]
unions = [ "(long or Callback)", "optional (long or Dict)" ]
numerics = [ "long", "short", "long?", "short?" ]
booleans = [ "boolean", "boolean?" ]
primitives = numerics + booleans
nonNumerics = allBut(argTypes, numerics)
nonNumerics = allBut(argTypes, numerics + unions)
nonBooleans = allBut(argTypes, booleans)
strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString" ]
nonStrings = allBut(argTypes, strings)
@ -182,16 +188,18 @@ def WebIDLTest(parser, harness):
sharedBufferSourceTypes = ["SharedArrayBuffer"]
interfaces = [ "Interface", "Interface?", "AncestorInterface",
"UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes
nullables = ["long?", "short?", "boolean?", "Interface?",
"CallbackInterface?", "optional Dict", "optional Dict2",
"Date?", "any", "Promise<any>?"]
nullables = (["long?", "short?", "boolean?", "Interface?",
"CallbackInterface?", "optional Dict", "optional Dict2",
"Date?", "any", "Promise<any>?"] +
allBut(unions, [ "(long or Callback)" ]))
dates = [ "Date", "Date?" ]
sequences = [ "sequence<long>", "sequence<short>" ]
nonUserObjects = nonObjects + interfaces + dates + sequences
otherObjects = allBut(argTypes, nonUserObjects + ["object"])
notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] +
otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes)
mozMaps = [ "MozMap<object>", "MozMap<Dict>", "MozMap<long>" ]
records = [ "record<DOMString, object>", "record<USVString, Dict>",
"record<ByteString, long>" ]
# Build a representation of the distinguishability table as a dict
# of dicts, holding True values where needed, holes elsewhere.
@ -231,9 +239,9 @@ def WebIDLTest(parser, harness):
allBut(argTypes, sequences + ["object"]))
setDistinguishable("sequence<short>",
allBut(argTypes, sequences + ["object"]))
setDistinguishable("MozMap<object>", nonUserObjects)
setDistinguishable("MozMap<Dict>", nonUserObjects)
setDistinguishable("MozMap<long>", nonUserObjects)
setDistinguishable("record<DOMString, object>", nonUserObjects)
setDistinguishable("record<USVString, Dict>", nonUserObjects)
setDistinguishable("record<ByteString, long>", nonUserObjects)
setDistinguishable("Date", allBut(argTypes, dates + ["object"]))
setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"]))
setDistinguishable("any", [])
@ -244,6 +252,10 @@ def WebIDLTest(parser, harness):
setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"]))
setDistinguishable("Uint16Array", allBut(argTypes, ["ArrayBufferView", "Uint16Array", "object"]))
setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"]))
setDistinguishable("(long or Callback)",
allBut(nonUserObjects, numerics))
setDistinguishable("optional (long or Dict)",
allBut(nonUserObjects, numerics + nullables))
def areDistinguishable(type1, type2):
return data[type1].get(type2, False)
@ -263,7 +275,6 @@ def WebIDLTest(parser, harness):
callback Callback2 = long(short arg);
dictionary Dict {};
dictionary Dict2 {};
interface _Promise {};
interface TestInterface {%s
};
"""

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

@ -0,0 +1,39 @@
# Import the WebIDL module, so we can do isinstance checks and whatnot
import WebIDL
def WebIDLTest(parser, harness):
try:
parser.parse("""
enum Foo { "a" };
interface Foo;
""")
results = parser.finish()
harness.ok(False, "Should fail to parse")
except Exception, e:
harness.ok("Name collision" in e.message,
"Should have name collision for interface")
parser = parser.reset()
try:
parser.parse("""
dictionary Foo { long x; };
enum Foo { "a" };
""")
results = parser.finish()
harness.ok(False, "Should fail to parse")
except Exception, e:
harness.ok("Name collision" in e.message,
"Should have name collision for dictionary")
parser = parser.reset()
try:
parser.parse("""
enum Foo { "a" };
enum Foo { "b" };
""")
results = parser.finish()
harness.ok(False, "Should fail to parse")
except Exception, e:
harness.ok("Multiple unresolvable definitions" in e.message,
"Should have name collision for dictionary")

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

@ -88,6 +88,8 @@ def WebIDLTest(parser, harness):
disallowedNonMethodNames = ["clear", "delete"]
mapDisallowedNonMethodNames = ["set"] + disallowedNonMethodNames
setDisallowedNonMethodNames = ["add"] + disallowedNonMethodNames
unrelatedMembers = [("unrelatedAttribute", WebIDL.IDLAttribute),
("unrelatedMethod", WebIDL.IDLMethod)]
#
# Simple Usage Tests
@ -99,52 +101,147 @@ def WebIDLTest(parser, harness):
iterable<long>;
readonly attribute unsigned long length;
getter long(unsigned long index);
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", valueIterableMembers)
""", valueIterableMembers + unrelatedMembers)
shouldPass("Iterable (key only) inheriting from parent",
"""
interface Foo1 : Foo2 {
iterable<long>;
readonly attribute unsigned long length;
getter long(unsigned long index);
};
interface Foo2 {
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", valueIterableMembers, numProductions=2)
shouldPass("Iterable (key and value)",
"""
interface Foo1 {
iterable<long, long>;
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", iterableMembers,
""", iterableMembers + unrelatedMembers,
# numProductions == 2 because of the generated iterator iface,
numProductions=2)
shouldPass("Maplike (readwrite)",
shouldPass("Iterable (key and value) inheriting from parent",
"""
interface Foo1 {
maplike<long, long>;
interface Foo1 : Foo2 {
iterable<long, long>;
};
""", mapRWMembers)
interface Foo2 {
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", iterableMembers,
# numProductions == 3 because of the generated iterator iface,
numProductions=3)
shouldPass("Maplike (readwrite)",
"""
interface Foo1 {
maplike<long, long>;
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", mapRWMembers)
""", mapRWMembers + unrelatedMembers)
shouldPass("Maplike (readwrite) inheriting from parent",
"""
interface Foo1 : Foo2 {
maplike<long, long>;
};
interface Foo2 {
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", mapRWMembers, numProductions=2)
shouldPass("Maplike (readwrite)",
"""
interface Foo1 {
maplike<long, long>;
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", mapRWMembers + unrelatedMembers)
shouldPass("Maplike (readwrite) inheriting from parent",
"""
interface Foo1 : Foo2 {
maplike<long, long>;
};
interface Foo2 {
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", mapRWMembers, numProductions=2)
shouldPass("Maplike (readonly)",
"""
interface Foo1 {
readonly maplike<long, long>;
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", mapROMembers)
""", mapROMembers + unrelatedMembers)
shouldPass("Maplike (readonly) inheriting from parent",
"""
interface Foo1 : Foo2 {
readonly maplike<long, long>;
};
interface Foo2 {
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", mapROMembers, numProductions=2)
shouldPass("Setlike (readwrite)",
"""
interface Foo1 {
setlike<long>;
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", setRWMembers)
""", setRWMembers + unrelatedMembers)
shouldPass("Setlike (readwrite) inheriting from parent",
"""
interface Foo1 : Foo2 {
setlike<long>;
};
interface Foo2 {
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", setRWMembers, numProductions=2)
shouldPass("Setlike (readonly)",
"""
interface Foo1 {
readonly setlike<long>;
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", setROMembers)
""", setROMembers + unrelatedMembers)
shouldPass("Setlike (readonly) inheriting from parent",
"""
interface Foo1 : Foo2 {
readonly setlike<long>;
};
interface Foo2 {
attribute long unrelatedAttribute;
long unrelatedMethod();
};
""", setROMembers, numProductions=2)
shouldPass("Inheritance of maplike/setlike",
"""

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

@ -0,0 +1,70 @@
# Import the WebIDL module, so we can do isinstance checks and whatnot
import WebIDL
def WebIDLTest(parser, harness):
# Basic functionality
parser.parse(
"""
interface Iface {
[NewObject] readonly attribute Iface attr;
[NewObject] Iface method();
};
""")
results = parser.finish()
harness.ok(results, "Should not have thrown on basic [NewObject] usage")
parser = parser.reset()
threw = False
try:
parser.parse(
"""
interface Iface {
[Pure, NewObject] readonly attribute Iface attr;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "[NewObject] attributes must depend on something")
parser = parser.reset()
threw = False
try:
parser.parse(
"""
interface Iface {
[Pure, NewObject] Iface method();
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "[NewObject] methods must depend on something")
parser = parser.reset()
threw = False
try:
parser.parse(
"""
interface Iface {
[Cached, NewObject, Affects=Nothing] readonly attribute Iface attr;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "[NewObject] attributes must not be [Cached]")
parser = parser.reset()
threw = False
try:
parser.parse(
"""
interface Iface {
[StoreInSlot, NewObject, Affects=Nothing] readonly attribute Iface attr;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "[NewObject] attributes must not be [StoreInSlot]")

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

@ -2,7 +2,6 @@ def WebIDLTest(parser, harness):
threw = False
try:
parser.parse("""
interface _Promise {};
interface A {
legacycaller Promise<any> foo();
};
@ -18,7 +17,6 @@ def WebIDLTest(parser, harness):
threw = False
try:
parser.parse("""
interface _Promise {};
interface A {
Promise<any> foo();
long foo(long arg);
@ -35,7 +33,6 @@ def WebIDLTest(parser, harness):
threw = False
try:
parser.parse("""
interface _Promise {};
interface A {
long foo(long arg);
Promise<any> foo();
@ -48,9 +45,36 @@ def WebIDLTest(parser, harness):
"Should not allow overloads which have both Promise and "
"non-Promise return types.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface A {
Promise<any>? foo();
};
""")
results = parser.finish();
except:
threw = True
harness.ok(threw,
"Should not allow nullable Promise return values.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface A {
void foo(Promise<any>? arg);
};
""")
results = parser.finish();
except:
threw = True
harness.ok(threw,
"Should not allow nullable Promise arguments.")
parser = parser.reset()
parser.parse("""
interface _Promise {};
interface A {
Promise<any> foo();
Promise<any> foo(long arg);
@ -61,3 +85,73 @@ def WebIDLTest(parser, harness):
harness.ok(True,
"Should allow overloads which only have Promise and return "
"types.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface A {
attribute Promise<any> attr;
};
""")
results = parser.finish();
except:
threw = True
harness.ok(threw,
"Should not allow writable Promise-typed attributes.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface A {
[LenientSetter] readonly attribute Promise<any> attr;
};
""")
results = parser.finish();
except:
threw = True
harness.ok(threw,
"Should not allow [LenientSetter] Promise-typed attributes.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface A {
[PutForwards=bar] readonly attribute Promise<any> attr;
};
""")
results = parser.finish();
except:
threw = True
harness.ok(threw,
"Should not allow [PutForwards] Promise-typed attributes.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface A {
[Replaceable] readonly attribute Promise<any> attr;
};
""")
results = parser.finish();
except:
threw = True
harness.ok(threw,
"Should not allow [Replaceable] Promise-typed attributes.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface A {
[SameObject] readonly attribute Promise<any> attr;
};
""")
results = parser.finish();
except:
threw = True
harness.ok(threw,
"Should not allow [SameObject] Promise-typed attributes.")

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

@ -3,8 +3,8 @@ import WebIDL
def WebIDLTest(parser, harness):
parser.parse("""
dictionary Dict {};
interface MozMapArg {
void foo(MozMap<Dict> arg);
interface RecordArg {
void foo(record<DOMString, Dict> arg);
};
""")
@ -19,7 +19,7 @@ def WebIDLTest(parser, harness):
signature = members[0].signatures()[0]
args = signature[1]
harness.check(len(args), 1, "Should have one arg")
harness.ok(args[0].type.isMozMap(), "Should have a MozMap type here")
harness.ok(args[0].type.isRecord(), "Should have a record type here")
harness.ok(args[0].type.inner.isDictionary(),
"Should have a dictionary inner type")
@ -27,13 +27,27 @@ def WebIDLTest(parser, harness):
threw = False
try:
parser.parse("""
interface MozMapVoidArg {
void foo(MozMap<void> arg);
interface RecordVoidArg {
void foo(record<DOMString, void> arg);
};
""")
results = parser.finish()
except Exception,x:
threw = True
harness.ok(threw, "Should have thrown because record can't have void as value type.")
parser = parser.reset()
threw = False
try:
parser.parse("""
dictionary Dict {
record<DOMString, Dict> val;
};
""")
harness.ok(threw, "Should have thrown.")
results = parser.finish()
except Exception,x:
threw = True
harness.ok(threw,
"Should have thrown on dictionary containing itself via record.")

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

@ -6,15 +6,14 @@ def WebIDLTest(parser, harness):
getter long long (unsigned long index);
setter long long (unsigned long index, long long value);
creator long long (unsigned long index, long long value);
deleter long long (unsigned long index);
getter boolean (DOMString name);
setter boolean (DOMString name, boolean value);
creator boolean (DOMString name, boolean value);
deleter boolean (DOMString name);
readonly attribute unsigned long length;
};
interface SpecialMethodsCombination {
getter deleter long long (unsigned long index);
setter creator long long (unsigned long index, long long value);
getter deleter boolean (DOMString name);
setter creator boolean (DOMString name, boolean value);
@ -49,25 +48,39 @@ def WebIDLTest(parser, harness):
setter=True)
checkMethod(iface.members[2], "::SpecialMethods::__indexedcreator", "__indexedcreator",
creator=True)
checkMethod(iface.members[3], "::SpecialMethods::__indexeddeleter", "__indexeddeleter",
deleter=True)
checkMethod(iface.members[4], "::SpecialMethods::__namedgetter", "__namedgetter",
checkMethod(iface.members[3], "::SpecialMethods::__namedgetter", "__namedgetter",
getter=True)
checkMethod(iface.members[5], "::SpecialMethods::__namedsetter", "__namedsetter",
checkMethod(iface.members[4], "::SpecialMethods::__namedsetter", "__namedsetter",
setter=True)
checkMethod(iface.members[6], "::SpecialMethods::__namedcreator", "__namedcreator",
checkMethod(iface.members[5], "::SpecialMethods::__namedcreator", "__namedcreator",
creator=True)
checkMethod(iface.members[7], "::SpecialMethods::__nameddeleter", "__nameddeleter",
checkMethod(iface.members[6], "::SpecialMethods::__nameddeleter", "__nameddeleter",
deleter=True)
iface = results[1]
harness.check(len(iface.members), 4, "Expect 4 members")
harness.check(len(iface.members), 3, "Expect 3 members")
checkMethod(iface.members[0], "::SpecialMethodsCombination::__indexedgetterdeleter",
"__indexedgetterdeleter", getter=True, deleter=True)
checkMethod(iface.members[1], "::SpecialMethodsCombination::__indexedsettercreator",
checkMethod(iface.members[0], "::SpecialMethodsCombination::__indexedsettercreator",
"__indexedsettercreator", setter=True, creator=True)
checkMethod(iface.members[2], "::SpecialMethodsCombination::__namedgetterdeleter",
checkMethod(iface.members[1], "::SpecialMethodsCombination::__namedgetterdeleter",
"__namedgetterdeleter", getter=True, deleter=True)
checkMethod(iface.members[3], "::SpecialMethodsCombination::__namedsettercreator",
checkMethod(iface.members[2], "::SpecialMethodsCombination::__namedsettercreator",
"__namedsettercreator", setter=True, creator=True)
parser = parser.reset();
threw = False
try:
parser.parse(
"""
interface IndexedDeleter {
deleter void(unsigned long index);
};
""")
parser.finish()
except:
threw = True
harness.ok(threw, "There are no indexed deleters")

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

@ -194,7 +194,7 @@ impl Headers {
}
Ok(())
},
Some(HeadersInit::ByteStringMozMap(m)) => {
Some(HeadersInit::StringByteStringRecord(m)) => {
for (key, value) in m.iter() {
let key_vec = key.as_ref().to_string().into();
let headers_key = ByteString::new(key_vec);

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

@ -311,9 +311,9 @@ impl Request {
try!(headers_copy.fill(Some(
HeadersInit::ByteStringSequenceSequence(init_sequence.clone()))));
},
&HeadersInit::ByteStringMozMap(ref init_map) => {
&HeadersInit::StringByteStringRecord(ref init_map) => {
try!(headers_copy.fill(Some(
HeadersInit::ByteStringMozMap(init_map.clone()))));
HeadersInit::StringByteStringRecord(init_map.clone()))));
},
}
}
@ -880,8 +880,8 @@ impl Clone for HeadersInit {
HeadersInit::Headers(h.clone()),
&HeadersInit::ByteStringSequenceSequence(ref b) =>
HeadersInit::ByteStringSequenceSequence(b.clone()),
&HeadersInit::ByteStringMozMap(ref m) =>
HeadersInit::ByteStringMozMap(m.clone()),
&HeadersInit::StringByteStringRecord(ref m) =>
HeadersInit::StringByteStringRecord(m.clone()),
}
}
}

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

@ -662,9 +662,9 @@ impl TestBindingMethods for TestBinding {
fn PassStringMozMap(&self, _: MozMap<DOMString>) {}
fn PassByteStringMozMap(&self, _: MozMap<ByteString>) {}
fn PassMozMapOfMozMaps(&self, _: MozMap<MozMap<i32>>) {}
fn PassMozMapUnion(&self, _: UnionTypes::LongOrByteStringMozMap) {}
fn PassMozMapUnion2(&self, _: UnionTypes::TestBindingOrByteStringMozMap) {}
fn PassMozMapUnion3(&self, _: UnionTypes::TestBindingOrByteStringSequenceSequenceOrByteStringMozMap) {}
fn PassMozMapUnion(&self, _: UnionTypes::LongOrStringByteStringRecord) {}
fn PassMozMapUnion2(&self, _: UnionTypes::TestBindingOrStringByteStringRecord) {}
fn PassMozMapUnion3(&self, _: UnionTypes::TestBindingOrByteStringSequenceSequenceOrStringByteStringRecord) {}
fn ReceiveMozMap(&self) -> MozMap<i32> { MozMap::new() }
fn ReceiveNullableMozMap(&self) -> Option<MozMap<i32>> { Some(MozMap::new()) }
fn ReceiveMozMapOfNullableInts(&self) -> MozMap<Option<i32>> { MozMap::new() }
@ -750,9 +750,6 @@ impl TestBindingMethods for TestBinding {
fn AcceptPromise(&self, _promise: &Promise) {
}
fn AcceptNullablePromise(&self, _promise: Option<&Promise>) {
}
fn PassSequenceSequence(&self, _seq: Vec<Vec<i32>>) {}
fn ReturnSequenceSequence(&self) -> Vec<Vec<i32>> { vec![] }
fn PassUnionSequenceSequence(&self, seq: LongOrLongSequenceSequence) {

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

@ -16,9 +16,9 @@ dictionary BluetoothLEScanFilterInit {
DOMString name;
DOMString namePrefix;
// Maps unsigned shorts to BluetoothDataFilters.
MozMap<BluetoothDataFilterInit> manufacturerData;
record<DOMString, BluetoothDataFilterInit> manufacturerData;
// Maps BluetoothServiceUUIDs to BluetoothDataFilters.
MozMap<BluetoothDataFilterInit> serviceData;
record<DOMString, BluetoothDataFilterInit> serviceData;
};
dictionary RequestDeviceOptions {

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

@ -4,7 +4,7 @@
// https://fetch.spec.whatwg.org/#headers-class
typedef (Headers or sequence<sequence<ByteString>> or MozMap<ByteString>) HeadersInit;
typedef (Headers or sequence<sequence<ByteString>> or record<DOMString, ByteString>) HeadersInit;
[Constructor(optional HeadersInit init),
Exposed=(Window,Worker)]

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

@ -434,33 +434,33 @@ interface TestBinding {
sequence<sequence<long>> returnSequenceSequence();
void passUnionSequenceSequence((long or sequence<sequence<long>>) seq);
void passMozMap(MozMap<long> arg);
void passNullableMozMap(MozMap<long>? arg);
void passMozMapOfNullableInts(MozMap<long?> arg);
void passOptionalMozMapOfNullableInts(optional MozMap<long?> arg);
void passOptionalNullableMozMapOfNullableInts(optional MozMap<long?>? arg);
void passCastableObjectMozMap(MozMap<TestBinding> arg);
void passNullableCastableObjectMozMap(MozMap<TestBinding?> arg);
void passCastableObjectNullableMozMap(MozMap<TestBinding>? arg);
void passNullableCastableObjectNullableMozMap(MozMap<TestBinding?>? arg);
void passOptionalMozMap(optional MozMap<long> arg);
void passOptionalNullableMozMap(optional MozMap<long>? arg);
void passOptionalNullableMozMapWithDefaultValue(optional MozMap<long>? arg = null);
void passOptionalObjectMozMap(optional MozMap<TestBinding> arg);
void passStringMozMap(MozMap<DOMString> arg);
void passByteStringMozMap(MozMap<ByteString> arg);
void passMozMapOfMozMaps(MozMap<MozMap<long>> arg);
void passMozMap(record<DOMString, long> arg);
void passNullableMozMap(record<DOMString, long>? arg);
void passMozMapOfNullableInts(record<DOMString, long?> arg);
void passOptionalMozMapOfNullableInts(optional record<DOMString, long?> arg);
void passOptionalNullableMozMapOfNullableInts(optional record<DOMString, long?>? arg);
void passCastableObjectMozMap(record<DOMString, TestBinding> arg);
void passNullableCastableObjectMozMap(record<DOMString, TestBinding?> arg);
void passCastableObjectNullableMozMap(record<DOMString, TestBinding>? arg);
void passNullableCastableObjectNullableMozMap(record<DOMString, TestBinding?>? arg);
void passOptionalMozMap(optional record<DOMString, long> arg);
void passOptionalNullableMozMap(optional record<DOMString, long>? arg);
void passOptionalNullableMozMapWithDefaultValue(optional record<DOMString, long>? arg = null);
void passOptionalObjectMozMap(optional record<DOMString, TestBinding> arg);
void passStringMozMap(record<DOMString, DOMString> arg);
void passByteStringMozMap(record<DOMString, ByteString> arg);
void passMozMapOfMozMaps(record<DOMString, record<DOMString, long>> arg);
void passMozMapUnion((long or MozMap<ByteString>) init);
void passMozMapUnion2((TestBinding or MozMap<ByteString>) init);
void passMozMapUnion3((TestBinding or sequence<sequence<ByteString>> or MozMap<ByteString>) init);
void passMozMapUnion((long or record<DOMString, ByteString>) init);
void passMozMapUnion2((TestBinding or record<DOMString, ByteString>) init);
void passMozMapUnion3((TestBinding or sequence<sequence<ByteString>> or record<DOMString, ByteString>) init);
MozMap<long> receiveMozMap();
MozMap<long>? receiveNullableMozMap();
MozMap<long?> receiveMozMapOfNullableInts();
MozMap<long?>? receiveNullableMozMapOfNullableInts();
MozMap<MozMap<long>> receiveMozMapOfMozMaps();
MozMap<any> receiveAnyMozMap();
record<DOMString, long> receiveMozMap();
record<DOMString, long>? receiveNullableMozMap();
record<DOMString, long?> receiveMozMapOfNullableInts();
record<DOMString, long?>? receiveNullableMozMapOfNullableInts();
record<DOMString, record<DOMString, long>> receiveMozMapOfMozMaps();
record<DOMString, any> receiveAnyMozMap();
static attribute boolean booleanAttributeStatic;
static void receiveVoidStatic();
@ -519,7 +519,6 @@ interface TestBinding {
Promise<any> returnRejectedPromise(any value);
readonly attribute Promise<boolean> promiseAttribute;
void acceptPromise(Promise<DOMString> string);
void acceptNullablePromise(Promise<DOMString>? string);
Promise<any> promiseNativeHandler(SimpleCallback? resolve, SimpleCallback? reject);
void promiseResolveNative(Promise<any> p, any value);
void promiseRejectNative(Promise<any> p, any value);

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

@ -201,23 +201,6 @@ impl<Impl: SelectorImpl> SelectorList<Impl> {
pub fn from_vec(v: Vec<Selector<Impl>>) -> Self {
SelectorList(v.into_iter().map(SelectorAndHashes::new).collect())
}
pub fn to_css_from_index<W>(&self, from_index: usize, dest: &mut W)
-> fmt::Result where W: fmt::Write {
let mut iter = self.0.iter().skip(from_index);
let first = match iter.next() {
Some(f) => f,
None => return Ok(()),
};
first.selector.to_css(dest)?;
for selector_and_hashes in iter {
dest.write_str(", ")?;
selector_and_hashes.selector.to_css(dest)?;
}
Ok(())
}
}
/// Copied from Gecko, who copied it from WebKit. Note that increasing the
@ -714,7 +697,15 @@ impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.to_css_from_index(/* from_index = */ 0, dest)
let mut iter = self.0.iter();
let first = iter.next()
.expect("Empty SelectorList, should contain at least one selector");
first.selector.to_css(dest)?;
for selector_and_hashes in iter {
dest.write_str(", ")?;
selector_and_hashes.selector.to_css(dest)?;
}
Ok(())
}
}

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

@ -2112,11 +2112,17 @@ extern "C" {
result: *mut nsAString);
}
extern "C" {
pub fn Servo_StyleRule_GetSelectorTextFromIndex(rule:
pub fn Servo_StyleRule_GetSelectorTextAtIndex(rule:
RawServoStyleRuleBorrowed,
index: u32,
result: *mut nsAString);
}
extern "C" {
pub fn Servo_StyleRule_GetSpecificityAtIndex(rule:
RawServoStyleRuleBorrowed,
index: u32,
specificity: *mut u64);
}
extern "C" {
pub fn Servo_StyleRule_GetSelectorCount(rule: RawServoStyleRuleBorrowed,
count: *mut u32);

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

@ -1187,14 +1187,15 @@ pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowe
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_GetSelectorTextFromIndex(rule: RawServoStyleRuleBorrowed,
aSelectorIndex: u32,
result: *mut nsAString) {
pub extern "C" fn Servo_StyleRule_GetSelectorTextAtIndex(rule: RawServoStyleRuleBorrowed,
index: u32,
result: *mut nsAString) {
read_locked_arc(rule, |rule: &StyleRule| {
rule.selectors.to_css_from_index(
aSelectorIndex as usize,
unsafe { result.as_mut().unwrap() }
).unwrap();
let index = index as usize;
if index >= rule.selectors.0.len() {
return;
}
rule.selectors.0[index].selector.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
})
}
@ -1205,6 +1206,21 @@ pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: RawServoStyleRuleBorrow
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_GetSpecificityAtIndex(rule: RawServoStyleRuleBorrowed,
index: u32,
specificity: *mut u64) {
read_locked_arc(rule, |rule: &StyleRule| {
let mut specificity = unsafe { specificity.as_mut().unwrap() };
let index = index as usize;
if index >= rule.selectors.0.len() {
*specificity = 0;
return;
}
*specificity = rule.selectors.0[index].selector.specificity() as u64;
})
}
#[no_mangle]
pub extern "C" fn Servo_ImportRule_GetHref(rule: RawServoImportRuleBorrowed, result: *mut nsAString) {
read_locked_arc(rule, |rule: &ImportRule| {

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

@ -247,6 +247,7 @@ class MachCommands(CommandBase):
if android:
# Build OpenSSL for android
env["OPENSSL_VERSION"] = "1.0.2k"
make_cmd = ["make"]
if jobs is not None:
make_cmd += ["-j" + jobs]
@ -264,7 +265,7 @@ class MachCommands(CommandBase):
verbose=verbose)
if status:
return status
openssl_dir = path.join(openssl_dir, "openssl-1.0.1t")
openssl_dir = path.join(openssl_dir, "openssl-{}".format(env["OPENSSL_VERSION"]))
env['OPENSSL_LIB_DIR'] = openssl_dir
env['OPENSSL_INCLUDE_DIR'] = path.join(openssl_dir, "include")
env['OPENSSL_STATIC'] = 'TRUE'

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

@ -4,11 +4,11 @@ all: openssl
# From http://wiki.openssl.org/index.php/Android
.PHONY: openssl
openssl: openssl-1.0.1t/libssl.so
openssl: openssl-${OPENSSL_VERSION}/libssl.so
openssl-1.0.1t/libssl.so: openssl-1.0.1t/Configure
./openssl.sh ${ANDROID_NDK}
openssl-${OPENSSL_VERSION}/libssl.so: openssl-${OPENSSL_VERSION}/Configure
./openssl.sh ${ANDROID_NDK} ${OPENSSL_VERSION}
openssl-1.0.1t/Configure:
wget https://www.openssl.org/source/old/1.0.1/openssl-1.0.1t.tar.gz
tar -zxf openssl-1.0.1t.tar.gz
openssl-${OPENSSL_VERSION}/Configure:
URL=https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/openssl-${OPENSSL_VERSION}.tar.gz; \
curl $$URL | tar xzf -

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

@ -181,7 +181,7 @@ if [ ! -z "$VERBOSE" ] && [ "$VERBOSE" != "0" ]; then
echo "ANDROID_DEV: $ANDROID_DEV"
fi
cd openssl-1.0.1t
cd openssl-$2
perl -pi -e 's/install: all install_docs install_sw/install: install_docs install_sw/g' Makefile.org
# The code being built isn't maintained by us, so we redirect stderr to stdout

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

@ -123,6 +123,7 @@ win64-nightly/opt:
- builds/taskcluster_firefox_windows_64_opt.py
- disable_signing.py
- taskcluster_nightly.py
run-on-projects: []
win64/pgo:
description: "Win64 Opt PGO"

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

@ -244,6 +244,9 @@ def target_tasks_mozilla_beta(full_task_graph, parameters):
if platform in ('linux64-pgo', 'linux-pgo', 'android-api-15-nightly',
'android-x86-nightly'):
return False
if platform in ('macosx64-nightly', 'win64-nightly'):
# Don't do some nightlies on-push until it's ready.
return False
if platform in ('linux64', 'linux', 'macosx64'):
if task.attributes['build_type'] == 'opt':
return False

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

@ -39,13 +39,13 @@ and [specification](https://github.com/mozilla/geckodriver/issues?q=is%3Aissue+i
problems in our
[issue tracker](https://github.com/mozilla/geckodriver/issues).
Support is best in Firefox 52.0.3 and onwards,
Support is best in Firefox 53 and greater,
although generally the more recent the Firefox version,
the better the experience as they have more bug fixes and features.
Some features will only be available in the most recent Firefox versions,
and we strongly advise using the [latest Firefox Nightly](https://nightly.mozilla.org/) with geckodriver.
Since Windows XP support in Firefox will be dropped with Firefox 53,
we do not support this platform.
Since Windows XP support was dropped with Firefox 53,
geckodriver is not supported on this platform.
## WebDriver capabilities

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

@ -114,6 +114,24 @@ assert.window = function (win, msg = "") {
}, msg, NoSuchWindowError)(win);
};
/**
* Asserts that |context| is a valid browsing context.
*
* @param {browser.Context} context
* Browsing context to test.
* @param {string=} msg
* Custom error message.
*
* @throws {NoSuchWindowError}
* If |context| is invalid.
*/
assert.contentBrowser = function (context, msg = "") {
msg = msg || "Current window does not have a content browser";
assert.that(c => c && c.contentBrowser,
msg,
NoSuchWindowError)(context);
};
/**
* Asserts that there is no current user prompt.
*

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

@ -145,6 +145,21 @@ browser.Context = class {
return rv;
}
/**
* Returns the current URL of the content browser.
* If no browser is available, null will be returned.
*/
get currentURL() {
// Bug 1363368 - contentBrowser could be null until we wait for its
// initialization been finished
if (this.contentBrowser) {
return this.contentBrowser.currentURI.spec;
} else {
throw new NoSuchWindowError("Current window does not have a content browser");
}
}
/**
* Retrieves the current tabmodal UI object. According to the browser
* associated with the currently selected tab.

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

@ -145,6 +145,18 @@ Object.defineProperty(GeckoDriver.prototype, "a11yChecks", {
}
});
Object.defineProperty(GeckoDriver.prototype, "currentURL", {
get: function () {
switch (this.context) {
case Context.CHROME:
return this.getCurrentWindow().location.href;
case Context.CONTENT:
return this.curBrowser.currentURL;
}
}
});
Object.defineProperty(GeckoDriver.prototype, "proxy", {
get: function () {
return this.capabilities.get("proxy");
@ -194,7 +206,7 @@ Object.defineProperty(GeckoDriver.prototype, "windowHandles", {
});
Object.defineProperty(GeckoDriver.prototype, "chromeWindowHandles", {
get : function () {
get: function () {
let hs = [];
let winEn = Services.wm.getEnumerator(null);
@ -968,21 +980,10 @@ GeckoDriver.prototype.get = function* (cmd, resp) {
* A modal dialog is open, blocking this operation.
*/
GeckoDriver.prototype.getCurrentUrl = function (cmd) {
const win = assert.window(this.getCurrentWindow());
assert.window(this.getCurrentWindow());
assert.noUserPrompt(this.dialog);
switch (this.context) {
case Context.CHROME:
return win.location.href;
case Context.CONTENT:
if (this.curBrowser.contentBrowser) {
return this.curBrowser.contentBrowser.currentURI.spec;
} else {
throw new NoSuchWindowError(
"Not a browser window, or no tab currently selected");
}
}
return this.currentURL;
};
/**
@ -1059,19 +1060,15 @@ GeckoDriver.prototype.getPageSource = function* (cmd, resp) {
*/
GeckoDriver.prototype.goBack = function* (cmd, resp) {
assert.content(this.context);
assert.window(this.getCurrentWindow());
assert.contentBrowser(this.curBrowser);
assert.noUserPrompt(this.dialog);
if (!this.curBrowser.tab) {
// Navigation does not work for non-browser windows
return;
}
// If there is no history, just return
if (!this.curBrowser.contentBrowser.webNavigation.canGoBack) {
return;
}
let currentURL = this.getCurrentUrl();
let currentURL = this.currentURL;
let goBack = this.listener.goBack({pageTimeout: this.timeouts.pageLoad});
// If a remoteness update interrupts our page load, this will never return
@ -1106,19 +1103,15 @@ GeckoDriver.prototype.goBack = function* (cmd, resp) {
*/
GeckoDriver.prototype.goForward = function* (cmd, resp) {
assert.content(this.context);
assert.window(this.getCurrentWindow());
assert.contentBrowser(this.curBrowser);
assert.noUserPrompt(this.dialog);
if (!this.curBrowser.tab) {
// Navigation does not work for non-browser windows
return;
}
// If there is no history, just return
if (!this.curBrowser.contentBrowser.webNavigation.canGoForward) {
return;
}
let currentURL = this.getCurrentUrl();
let currentURL = this.currentURL;
let goForward = this.listener.goForward({pageTimeout: this.timeouts.pageLoad});
// If a remoteness update interrupts our page load, this will never return

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

@ -118,6 +118,16 @@ add_test(function test_window() {
run_next_test();
});
add_test(function test_contentBrowser() {
assert.contentBrowser({contentBrowser: 42});
for (let typ of [null, undefined, {contentBrowser: null}]) {
Assert.throws(() => assert.contentBrowser(typ), NoSuchWindowError);
}
run_next_test();
});
add_test(function test_object() {
assert.object({});
assert.object(new Object());

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

@ -67,6 +67,18 @@ test(function() {
assert_equals(serialize(dt), '<!DOCTYPE html PUBLIC ""\'" "\'"">');
}, "DocumentType: 'APOSTROPHE' (U+0027) and 'QUOTATION MARK' (U+0022)");
test(function() {
var el = document.createElement("a");
el.setAttribute("href", "\u3042\u3044\u3046 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
assert_equals(serialize(el), "<a xmlns=\"http://www.w3.org/1999/xhtml\" href=\"\u3042\u3044\u3046 !&quot;#$%&amp;'()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"></a>");
}, "Element: href attributes are not percent-encoded");
test(function() {
var el = document.createElement("a");
el.setAttribute("href", "?\u3042\u3044\u3046 !\"$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
assert_equals(serialize(el), "<a xmlns=\"http://www.w3.org/1999/xhtml\" href=\"?\u3042\u3044\u3046 !&quot;$%&amp;'()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"></a>");
}, "Element: query parts in href attributes are not percent-encoded");
test(function() {
var pi = document.createProcessingInstruction("a", "");
assert_equals(serialize(pi), "<?a ?>");

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

@ -11,9 +11,6 @@ namespace Telemetry {
using namespace HangMonitor;
/** The maximum number of stacks that we're keeping for hang reports. */
const size_t kMaxHangStacksKept = 50;
// This utility function generates a string key that is used to index the annotations
// in a hash map from |HangReports::AddHang|.
nsresult
@ -36,6 +33,9 @@ ComputeAnnotationsKey(const HangAnnotationsPtr& aAnnotations, nsAString& aKeyOut
}
#if defined(MOZ_GECKO_PROFILER)
/** The maximum number of stacks that we're keeping for hang reports. */
const size_t kMaxHangStacksKept = 50;
void
HangReports::AddHang(const Telemetry::ProcessedStack& aStack,
uint32_t aDuration,

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

@ -12,8 +12,6 @@
namespace {
#if defined(MOZ_GECKO_PROFILER)
/** Defines the size of the keyed stack dictionary. */
const uint8_t kMaxKeyLength = 50;
@ -161,7 +159,6 @@ KeyedStackCapturer::Clear()
mStackInfos.Clear();
mStacks.Clear();
}
#endif
} // namespace Telemetry
} // namespace mozilla

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

@ -6,8 +6,6 @@
#ifndef KeyedStackCapturer_h__
#define KeyedStackCapturer_h__
#ifdef MOZ_GECKO_PROFILER
#include "Telemetry.h"
#include "nsString.h"
#include "nsClassHashtable.h"
@ -74,6 +72,4 @@ private:
} // namespace Telemetry
} // namespace mozilla
#endif // MOZ_GECKO_PROFILER
#endif // KeyedStackCapturer_h__

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

@ -99,10 +99,13 @@ using Telemetry::Common::AutoHashtable;
using mozilla::dom::Promise;
using mozilla::dom::AutoJSAPI;
using mozilla::Telemetry::HangReports;
using mozilla::Telemetry::KeyedStackCapturer;
using mozilla::Telemetry::CombinedStacks;
using mozilla::Telemetry::ComputeAnnotationsKey;
#if defined(MOZ_GECKO_PROFILER)
using mozilla::Telemetry::KeyedStackCapturer;
#endif
/**
* IOInterposeObserver recording statistics of main-thread I/O during execution,
* aimed at consumption by TelemetryImpl

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

@ -57,7 +57,6 @@ SOURCES += [
'HangReports.cpp',
'ipc/TelemetryIPC.cpp',
'ipc/TelemetryIPCAccumulator.cpp',
'KeyedStackCapturer.cpp',
'Telemetry.cpp',
'TelemetryCommon.cpp',
'TelemetryEvent.cpp',
@ -66,6 +65,12 @@ SOURCES += [
'WebrtcTelemetry.cpp',
]
# KeyedStackCapturer entirely relies on profiler to be enabled.
if CONFIG['MOZ_GECKO_PROFILER']:
SOURCES += [
'KeyedStackCapturer.cpp'
]
EXTRA_COMPONENTS += [
'TelemetryStartup.js',
'TelemetryStartup.manifest'

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

@ -244,34 +244,32 @@ def get_possible_node_paths_win():
def simple_which(filename, path=None):
try:
return which.which(filename, path)
except which.WhichError:
return None
exts = [".cmd", ".exe", ""] if platform.system() == "Windows" else [""]
for ext in exts:
try:
return which.which(filename + ext, path)
except which.WhichError:
pass
# If we got this far, we didn't find it with any of the extensions, so
# just return.
return None
def which_path(filename):
"""
Return the nodejs or npm path.
"""
if platform.system() == "Windows":
for ext in [".cmd", ".exe", ""]:
# Look in the system path first.
filepath = simple_which(filename + ext)
if filepath is None:
# If we don't find it there, fallback to the non-system paths.
filepath = simple_which(filename + ext, get_possible_node_paths_win())
if filepath is not None:
return filepath
# If we got this far, we didn't find it with any of the extensions, so
# just return.
return None
# Non-windows.
# Look in the system path first.
path = simple_which(filename)
if path is None and filename == "node":
if path is not None:
return path
if platform.system() == "Windows":
# If we didn't find it fallback to the non-system paths.
path = simple_which(filename, get_possible_node_paths_win())
elif filename == "node":
path = simple_which("nodejs")
return path

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

@ -537,6 +537,18 @@ public:
return result;
}
static nscolor GetColorUsingStandins(ColorID aID,
nscolor aDefault = NS_RGB(0, 0, 0))
{
nscolor result = NS_RGB(0, 0, 0);
if (NS_FAILED(GetColor(aID,
true, // aUseStandinsForNativeColors
&result))) {
return aDefault;
}
return result;
}
static int32_t GetInt(IntID aID, int32_t aDefault = 0)
{
int32_t result;