Merge autoland to central, a=merge

MozReview-Commit-ID: 4ygim4sQ5zd
This commit is contained in:
Wes Kocher 2017-10-02 16:02:42 -07:00
commit 55fe1fc9f2
120 changed files with 4103 additions and 2004 deletions

View File

@ -51,6 +51,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
PageThumbs: "resource://gre/modules/PageThumbs.jsm",
PdfJs: "resource://pdf.js/PdfJs.jsm",
PermissionUI: "resource:///modules/PermissionUI.jsm",
PingCentre: "resource:///modules/PingCentre.jsm",
PlacesBackups: "resource://gre/modules/PlacesBackups.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
PluralForm: "resource://gre/modules/PluralForm.jsm",
@ -264,6 +265,7 @@ const OBSERVE_LASTWINDOW_CLOSE_TOPICS = AppConstants.platform != "macosx";
BrowserGlue.prototype = {
_saveSession: false,
_migrationImportsDefaultBookmarks: false,
_placesBrowserInitComplete: false,
_setPrefToSaveSession: function BG__setPrefToSaveSession(aForce) {
if (!this._saveSession && !aForce)
@ -299,6 +301,30 @@ BrowserGlue.prototype = {
Weave.Service.scheduler.delayedAutoConnect(delay);
},
/**
* Lazily initialize PingCentre
*/
get pingCentre() {
const MAIN_TOPIC_ID = "main";
Object.defineProperty(this, "pingCentre", {
value: new PingCentre({ topic: MAIN_TOPIC_ID })
});
return this.pingCentre;
},
_sendMainPingCentrePing() {
const ACTIVITY_STREAM_ENABLED_PREF = "browser.newtabpage.activity-stream.enabled";
const ACTIVITY_STREAM_ID = "activity-stream";
let asEnabled = Services.prefs.getBoolPref(ACTIVITY_STREAM_ENABLED_PREF, false);
const payload = {
event: "AS_ENABLED",
value: asEnabled
};
const options = {filter: ACTIVITY_STREAM_ID};
this.pingCentre.sendPing(payload, options);
},
// nsIObserver implementation
observe: function BG_observe(subject, topic, data) {
switch (topic) {
@ -407,6 +433,10 @@ BrowserGlue.prototype = {
Object.defineProperty(this, "AlertsService", {
value: subject.wrappedJSObject
});
} else if (data == "places-browser-init-complete") {
if (this._placesBrowserInitComplete) {
Services.obs.notifyObservers(null, "places-browser-init-complete");
}
}
break;
case "initial-migration-will-import-default-bookmarks":
@ -491,6 +521,9 @@ BrowserGlue.prototype = {
// shim for privileged api access.
PdfJs.init(true);
break;
case "shield-init-complete":
this._sendMainPingCentrePing();
break;
}
},
@ -527,6 +560,7 @@ BrowserGlue.prototype = {
os.addObserver(this, "xpi-signature-changed");
os.addObserver(this, "sync-ui-state:update");
os.addObserver(this, "handlersvc-store-initialized");
os.addObserver(this, "shield-init-complete");
this._flashHangCount = 0;
this._firstWindowReady = new Promise(resolve => this._firstWindowLoaded = resolve);
@ -579,6 +613,7 @@ BrowserGlue.prototype = {
os.removeObserver(this, "flash-plugin-hang");
os.removeObserver(this, "xpi-signature-changed");
os.removeObserver(this, "sync-ui-state:update");
os.removeObserver(this, "shield-init-complete");
},
_onAppDefaults: function BG__onAppDefaults() {
@ -965,6 +1000,10 @@ BrowserGlue.prototype = {
}
BrowserUsageTelemetry.uninit();
// Only uninit PingCentre if the getter has initialized it
if (Object.prototype.hasOwnProperty.call(this, "pingCentre")) {
this.pingCentre.uninit();
}
PageThumbs.uninit();
NewTabUtils.uninit();
@ -1455,6 +1494,7 @@ BrowserGlue.prototype = {
// in any case, better safe than sorry.
this._firstWindowReady.then(() => {
this._showPlacesLockedNotificationBox();
this._placesBrowserInitComplete = true;
Services.obs.notifyObservers(null, "places-browser-init-complete");
});
return;
@ -1623,6 +1663,7 @@ BrowserGlue.prototype = {
}).then(() => {
// NB: deliberately after the catch so that we always do this, even if
// we threw halfway through initializing in the Task above.
this._placesBrowserInitComplete = true;
Services.obs.notifyObservers(null, "places-browser-init-complete");
});
},

View File

@ -27,12 +27,12 @@ support-files =
[browser_bookmarksProperties.js]
[browser_check_correct_controllers.js]
[browser_click_bookmarks_on_toolbar.js]
[browser_cutting_bookmarks.js]
subsuite = clipboard
[browser_controller_onDrop.js]
[browser_copy_folder_tree.js]
[browser_copy_query_without_tree.js]
subsuite = clipboard
[browser_cutting_bookmarks.js]
subsuite = clipboard
[browser_drag_bookmarks_on_toolbar.js]
[browser_forgetthissite_single.js]
[browser_history_sidebar_search.js]

View File

@ -8,6 +8,8 @@ const SHORTCUT_URL = "place:folder=2";
const QUERY_URL = "place:sort=8&maxResults=10";
add_task(async function copy_toolbar_shortcut() {
await promisePlacesInitComplete();
let library = await promiseLibrary();
registerCleanupFunction(function() {
@ -21,6 +23,7 @@ add_task(async function copy_toolbar_shortcut() {
PlacesUtils.TYPE_X_MOZ_PLACE);
library.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
await library.ContentTree.view.controller.paste();
let toolbarCopyNode = library.ContentTree.view.view.nodeForTreeIndex(0);

View File

@ -75,8 +75,8 @@ function promiseLibraryClosed(organizer) {
* Data flavor to expect.
*/
function promiseClipboard(aPopulateClipboardFn, aFlavor) {
return new Promise(resolve => {
waitForClipboard(data => !!data, aPopulateClipboardFn, resolve, aFlavor);
return new Promise((resolve, reject) => {
waitForClipboard(data => !!data, aPopulateClipboardFn, resolve, reject, aFlavor);
});
}
@ -471,3 +471,15 @@ var withSidebarTree = async function(type, taskFn) {
SidebarUI.hide();
}
};
function promisePlacesInitComplete() {
const gBrowserGlue = Cc["@mozilla.org/browser/browserglue;1"]
.getService(Ci.nsIObserver);
let placesInitCompleteObserved = TestUtils.topicObserved("places-browser-init-complete")
gBrowserGlue.observe(null, "browser-glue-test",
"places-browser-init-complete");
return placesInitCompleteObserved;
}

View File

@ -21,5 +21,6 @@ support-files =
[test_browserGlue_urlbar_defaultbehavior_migration.js]
[test_clearHistory_shutdown.js]
[test_leftpane_corruption_handling.js]
[test_PUIU_batchUpdatesForNode.js]
[test_PUIU_livemarksCache.js]
[test_PUIU_makeTransaction.js]

View File

@ -515,7 +515,7 @@
</menulist>
</hbox>
</hbox>
<spacer flex="1" />
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
<hbox>
<button id="advancedFonts"

View File

@ -385,7 +385,7 @@
class="accessory-button"
label="&clearOnCloseSettings.label;"
accesskey="&clearOnCloseSettings.accesskey;"
searchkeywords="&clearDataSettings2.label;
searchkeywords="&clearDataSettings3.label;
&historySection.label;
&itemHistoryAndDownloads.label;
&itemCookies.label;

View File

@ -42,7 +42,7 @@
<preference id="privacy.clearOnShutdown.siteSettings" name="privacy.clearOnShutdown.siteSettings" type="bool"/>
</preferences>
<description>&clearDataSettings2.label;</description>
<description>&clearDataSettings3.label;</description>
<groupbox orient="horizontal">
<caption><label>&historySection.label;</label></caption>

View File

@ -6,4 +6,13 @@ const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
// ================================================
// Load mocking/stubbing library, sinon
// docs: http://sinonjs.org/releases/v2.3.2/
/* exported sinon */
Cu.import("resource://gre/modules/Timer.jsm");
Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js", this);
/* globals sinon */
// ================================================
var gProfD = do_get_profile().QueryInterface(Ci.nsIFile);

View File

@ -0,0 +1,25 @@
Cu.import("resource:///modules/PingCentre.jsm");
const TOPIC_SHIELD_INIT_COMPLETE = "shield-init-complete";
const ACTIVITY_STREAM_ENABLED_PREF = "browser.newtabpage.activity-stream.enabled";
const SEND_PING_MOCK = sinon.stub(PingCentre.prototype, "sendPing");
let gBrowserGlue = Cc["@mozilla.org/browser/browserglue;1"]
.getService(Ci.nsIObserver);
add_task(async function() {
let asEnabled = Services.prefs.getBoolPref(ACTIVITY_STREAM_ENABLED_PREF, false);
// Simulate ping centre sendPing() trigger.
gBrowserGlue.observe(null, TOPIC_SHIELD_INIT_COMPLETE, null);
const SEND_PING_CALL_ARGS = {
event: "AS_ENABLED",
value: asEnabled
}
const SEND_PING_FILTER = { filter: "activity-stream" };
Assert.ok(SEND_PING_MOCK.called, "gBrowserGlue.pingCentre.sendPing() is called");
Assert.ok(SEND_PING_MOCK.calledWithExactly(SEND_PING_CALL_ARGS, SEND_PING_FILTER),
"sendPing() is called with the correct param");
});

View File

@ -9,3 +9,4 @@ support-files =
[test_browserGlue_migration_loop_cleanup.js]
[test_distribution.js]
[test_distribution_cachedexistence.js]
[test_browserGlue_pingcentre.js]

View File

@ -393,6 +393,11 @@ var FormAutofillContent = {
notify(formElement, domWin) {
this.log.debug("Notifying form early submission");
if (!FormAutofillUtils.isAutofillEnabled) {
this.log.debug("Form Autofill is disabled");
return true;
}
if (domWin && PrivateBrowsingUtils.isContentWindowPrivate(domWin)) {
this.log.debug("Ignoring submission in a private window");
return true;

View File

@ -550,8 +550,16 @@ FormAutofillHandler.prototype = {
*/
createRecords() {
let data = {};
let target = [];
["address", "creditCard"].forEach(type => {
if (FormAutofillUtils.isAutofillAddressesEnabled) {
target.push("address");
}
if (FormAutofillUtils.isAutofillCreditCardsEnabled) {
target.push("creditCard");
}
target.forEach(type => {
let details = this[type].fieldDetails;
if (!details || details.length == 0) {
return;

View File

@ -483,6 +483,64 @@ add_task(async function handle_earlyformsubmit_event() {
FormAutofillContent._onFormSubmit.restore();
});
add_task(async function autofill_disabled() {
let form = MOCK_DOC.getElementById("form1");
form.reset();
let testcase = {
"street-addr": "331 E. Evelyn Avenue",
"country": "US",
"tel": "+16509030800",
"cc-number": "1111222233334444",
};
for (let key in testcase) {
let input = MOCK_DOC.getElementById(key);
input.value = testcase[key];
}
let element = MOCK_DOC.getElementById(TARGET_ELEMENT_ID);
FormAutofillContent.identifyAutofillFields(element);
sinon.stub(FormAutofillContent, "_onFormSubmit");
// "_onFormSubmit" shouldn't be called if both "addresses" and "creditCards"
// are disabled.
Services.prefs.setBoolPref("extensions.formautofill.addresses.enabled", false);
Services.prefs.setBoolPref("extensions.formautofill.creditCards.enabled", false);
FormAutofillContent.notify(form);
do_check_eq(FormAutofillContent._onFormSubmit.called, false);
FormAutofillContent._onFormSubmit.reset();
// "_onFormSubmit" should be called as usual.
Services.prefs.clearUserPref("extensions.formautofill.addresses.enabled");
Services.prefs.clearUserPref("extensions.formautofill.creditCards.enabled");
FormAutofillContent.notify(form);
do_check_eq(FormAutofillContent._onFormSubmit.called, true);
do_check_neq(FormAutofillContent._onFormSubmit.args[0][0].address, undefined);
do_check_neq(FormAutofillContent._onFormSubmit.args[0][0].creditCard, undefined);
FormAutofillContent._onFormSubmit.reset();
// "address" should be empty if "addresses" pref is disabled.
Services.prefs.setBoolPref("extensions.formautofill.addresses.enabled", false);
FormAutofillContent.notify(form);
do_check_eq(FormAutofillContent._onFormSubmit.called, true);
do_check_eq(FormAutofillContent._onFormSubmit.args[0][0].address, undefined);
do_check_neq(FormAutofillContent._onFormSubmit.args[0][0].creditCard, undefined);
FormAutofillContent._onFormSubmit.reset();
Services.prefs.clearUserPref("extensions.formautofill.addresses.enabled");
// "creditCard" should be empty if "creditCards" pref is disabled.
Services.prefs.setBoolPref("extensions.formautofill.creditCards.enabled", false);
FormAutofillContent.notify(form);
do_check_eq(FormAutofillContent._onFormSubmit.called, true);
do_check_neq(FormAutofillContent._onFormSubmit.args[0][0].address, undefined);
do_check_eq(FormAutofillContent._onFormSubmit.args[0][0].creditCard, undefined);
FormAutofillContent._onFormSubmit.reset();
Services.prefs.clearUserPref("extensions.formautofill.creditCards.enabled");
FormAutofillContent._onFormSubmit.restore();
});
TESTCASES.forEach(testcase => {
add_task(async function check_records_saving_is_called_correctly() {
do_print("Starting testcase: " + testcase.description);

View File

@ -44,6 +44,7 @@ hr
hsb
hu
hy-AM
ia
id
is
it

View File

@ -21,7 +21,7 @@
<!-- LOCALIZATION NOTE (sanitizeDialog2.width): width of the Clear Recent History dialog -->
<!ENTITY sanitizeDialog2.width "34em">
<!ENTITY clearDataSettings2.label "When I quit &brandShortName;, it should automatically clear all:">
<!ENTITY clearDataSettings3.label "When I quit &brandShortName;, it should automatically clear all">
<!-- XXX rearrange entities to match physical layout when l10n isn't an issue -->
<!-- LOCALIZATION NOTE (clearTimeDuration.*): "Time range to clear" dropdown.

View File

@ -0,0 +1,987 @@
{
"ach": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"af": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"an": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ar": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"as": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ast": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"az": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"be": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"bg": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"bn-BD": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"bn-IN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"br": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"bs": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ca": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"cak": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"cs": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"cy": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"da": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"de": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"dsb": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"el": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"en-GB": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"en-ZA": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"eo": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"es-AR": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"es-CL": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"es-ES": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"es-MX": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"et": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"eu": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"fa": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ff": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"fi": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"fr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"fy-NL": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ga-IE": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"gd": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"gl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"gn": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"gu-IN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"he": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hi-IN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hsb": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hu": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hy-AM": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"id": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"is": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"it": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ja": {
"platforms": [
"linux",
"linux64",
"win32",
"win64"
],
"revision": "default"
},
"ja-JP-mac": {
"platforms": [
"macosx64"
],
"revision": "default"
},
"ka": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"kab": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"kk": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"km": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"kn": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ko": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"lij": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"lo": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"lt": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ltg": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"lv": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"mai": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"mk": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ml": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"mr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ms": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"my": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"nb-NO": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ne-NP": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"nl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"nn-NO": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"or": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"pa-IN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"pl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"pt-BR": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"pt-PT": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"rm": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ro": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ru": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"si": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sk": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"son": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sq": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sv-SE": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ta": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"te": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"th": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"tl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"tr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"uk": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ur": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"uz": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"vi": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"xh": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"zh-CN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"zh-TW": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
}
}

View File

@ -51,6 +51,7 @@ locales = [
"hsb",
"hu",
"hy-AM",
"ia",
"id",
"is",
"it",

View File

@ -373,6 +373,13 @@
]
}
},
"ia": {
"default": {
"visibleDefaultEngines": [
"google", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia-ia"
]
}
},
"id": {
"default": {
"visibleDefaultEngines": [

View File

@ -0,0 +1,19 @@
<!-- 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/. -->
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>Wikipedia (ia)</ShortName>
<Description>Wikipedia, le encyclopedia libere</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">resource://search-plugins/images/wikipedia.ico</Image>
<Url type="application/x-suggestions+json" method="GET" template="https://ia.wikipedia.org/w/api.php">
<Param name="action" value="opensearch"/>
<Param name="search" value="{searchTerms}"/>
</Url>
<Url type="text/html" method="GET" template="https://ia.wikipedia.org/wiki/Special:Recerca"
resultdomain="wikipedia.org" rel="searchform">
<Param name="search" value="{searchTerms}"/>
<Param name="sourceid" value="Mozilla-search"/>
</Url>
</SearchPlugin>

View File

@ -1,8 +1,9 @@
%include build/sparse-profiles/mach
[include]
# This file is read as part of validating the taskgraph.
path:browser/locales/all-locales
# These files are read as part of generating the taskgraph.
path:browser/locales/l10n-changesets.json
path:mobile/locales/l10n-changesets.json
# Lots of random files in here are read. Just pull in the whole thing.
path:build/
@ -12,9 +13,6 @@ path:build/
path:layout/tools/reftest/
path:testing/web-platform/tests/tools/
# This file is read as part of validating the taskgraph.
path:mobile/locales/l10n-changesets.json
# The main meat of this profile.
path:taskcluster/

View File

@ -100,7 +100,7 @@ Tools.webConsole = {
accesskey: l10n("webConsoleCmd.accesskey"),
ordinal: 2,
oldWebConsoleURL: "chrome://devtools/content/webconsole/webconsole.xul",
newWebConsoleURL: "chrome://devtools/content/webconsole/webconsole.xhtml",
newWebConsoleURL: "chrome://devtools/content/webconsole/webconsole.html",
icon: "chrome://devtools/skin/images/tool-webconsole.svg",
invertIconForDarkTheme: true,
label: l10n("ToolboxTabWebconsole.label"),

View File

@ -10,7 +10,7 @@ devtools.jar:
content/netmonitor/src/assets/styles/netmonitor.css (netmonitor/src/assets/styles/netmonitor.css)
content/shared/widgets/VariablesView.xul (shared/widgets/VariablesView.xul)
content/netmonitor/index.html (netmonitor/index.html)
content/webconsole/webconsole.xhtml (webconsole/webconsole.xhtml)
content/webconsole/webconsole.html (webconsole/webconsole.html)
content/webconsole/webconsole.xul (webconsole/webconsole.xul)
content/scratchpad/scratchpad.xul (scratchpad/scratchpad.xul)
content/scratchpad/scratchpad.js (scratchpad/scratchpad.js)

View File

@ -68,7 +68,6 @@
.treeTable .treeRow.hasChildren > .treeLabelCell > .treeLabel:hover {
cursor: pointer;
color: var(--tree-link-color);
text-decoration: underline;
}
@ -76,8 +75,8 @@
background-color: var(--theme-selection-background);
}
.treeTable .treeRow.selected:not(:hover) *,
.treeTable .treeRow.selected:not(:hover) .treeLabelCell::after {
.treeTable .treeRow.selected *,
.treeTable .treeRow.selected .treeLabelCell::after {
color: var(--theme-selection-color);
}
@ -180,25 +179,26 @@
/******************************************************************************/
/* Themes */
.theme-light .treeTable .treeRow:hover,
.theme-dark .treeTable .treeRow:hover {
/* :not(.selected) is used because row selection styles should have
more precedence than row hovering. */
.theme-light .treeTable .treeRow:not(.selected):hover,
.theme-dark .treeTable .treeRow:not(.selected):hover {
background-color: var(--theme-selection-background-hover) !important;
}
.theme-firebug .treeTable .treeRow:hover {
.theme-firebug .treeTable .treeRow:not(.selected):hover {
background-color: var(--theme-body-background);
}
.theme-light .treeTable .treeLabel,
.theme-dark .treeTable .treeLabel {
.theme-light .treeTable,
.theme-dark .treeTable {
color: var(--theme-highlight-blue);
}
.theme-light .treeTable .treeRow.hasChildren > .treeLabelCell > .treeLabel:hover,
.theme-dark .treeTable .treeRow.hasChildren > .treeLabelCell > .treeLabel:hover {
color: var(--theme-highlight-blue);
}
.theme-firebug .treeTable .treeLabel {
.theme-firebug .treeTable {
color: var(--theme-body-color);
}
.theme-firebug .treeTable .treeRow.hasChildren:not(.selected) > .treeLabelCell > .treeLabel:hover {
color: var(--tree-link-color);
}

View File

@ -150,13 +150,7 @@
let doc = node.ownerDocument;
const inspectorUrl = "chrome://devtools/content/inspector/inspector.xhtml";
const netMonitorUrl = "chrome://devtools/content/netmonitor/netmonitor.xhtml";
const webConsoleUrl = "chrome://devtools/content/webconsole/webconsole.xhtml";
while (doc instanceof XULDocument ||
doc.location.href === inspectorUrl ||
doc.location.href === netMonitorUrl ||
doc.location.href === webConsoleUrl) {
while (doc instanceof XULDocument || doc.location.href === inspectorUrl) {
const {frameElement} = doc.defaultView;
if (!frameElement) {

View File

@ -16,8 +16,6 @@ this.NewConsoleOutput = function (parentNode, jsterm, toolbox, owner, serviceCon
// privileges and runs entirely in content scope.
let NewConsoleOutputWrapper = BrowserLoader({
baseURI: "resource://devtools/client/webconsole/new-console-output/",
// The toolbox is not available for the browser console.
commonLibRequire: toolbox ? toolbox.browserRequire : null,
window
}).require("./new-console-output-wrapper");

View File

@ -88,7 +88,7 @@ NewConsoleOutputWrapper.prototype = {
this.jsterm.hud.owner.openLink(url);
},
createElement: nodename => {
return this.document.createElementNS("http://www.w3.org/1999/xhtml", nodename);
return this.document.createElement(nodename);
},
};

View File

@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" dir="">
<html dir="">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="chrome://devtools/skin/widgets.css"/>
@ -21,16 +20,16 @@
</head>
<body class="theme-sidebar" role="application">
<div id="app-wrapper" class="theme-body">
<div id="output-container" role="document" aria-live="polite"/>
<div id="output-container" role="document" aria-live="polite"></div>
<div id="jsterm-wrapper">
<div id="webconsole-notificationbox">
<div class="jsterm-input-container" style="direction:ltr">
<div class="jsterm-stack-node">
<textarea class="jsterm-complete-node devtools-monospace"
tabindex="-1"/>
tabindex="-1"></textarea>
<textarea class="jsterm-input-node devtools-monospace"
rows="1" tabindex="0"
aria-autocomplete="list"/>
aria-autocomplete="list"></textarea>
</div>
</div>
</div>

View File

@ -4425,7 +4425,6 @@ NoteDirtyElement(Element* aElement, uint32_t aBits)
// Similarly, if our parent already has the bit we're propagating, we can
// assume everything is already set up.
if (parent->HasAllFlags(aBits)) {
MOZ_ASSERT(aElement->GetComposedDoc()->GetServoRestyleRoot());
return;
}

View File

@ -7,19 +7,20 @@
/*
* Util base class to help test a captured canvas element. Initializes the
* output canvas (used for testing the color of video elements), and optionally
* overrides the default element |width| and |height|.
* overrides the default `createAndAppendElement` element |width| and |height|.
*/
function CaptureStreamTestHelper(width, height) {
this.cout = document.createElement('canvas');
if (width) {
this.elemWidth = width;
}
if (height) {
this.elemHeight = height;
}
this.cout.width = this.elemWidth;
this.cout.height = this.elemHeight;
document.body.appendChild(this.cout);
/* cout is used for `getPixel`; only needs to be big enough for one pixel */
this.cout = document.createElement('canvas');
this.cout.width = 1;
this.cout.height = 1;
}
CaptureStreamTestHelper.prototype = {
@ -58,21 +59,23 @@ CaptureStreamTestHelper.prototype = {
/*
* Returns the pixel at (|offsetX|, |offsetY|) (from top left corner) of
* |video| as an array of the pixel's color channels: [R,G,B,A]. Allows
* optional scaling of the drawImage() call (so that a 1x1 black image
* won't just draw 1 pixel in the corner)
* |video| as an array of the pixel's color channels: [R,G,B,A].
*/
getPixel: function (video, offsetX = 0, offsetY = 0, width = 0, height = 0) {
getPixel: function (video, offsetX = 0, offsetY = 0) {
// Avoids old values in case of a transparent image.
CaptureStreamTestHelper2D.prototype.clear.call(this, this.cout);
var ctxout = this.cout.getContext('2d');
if (width != 0 || height != 0) {
ctxout.drawImage(video, 0, 0, width, height);
} else {
ctxout.drawImage(video, 0, 0);
}
return ctxout.getImageData(offsetX, offsetY, 1, 1).data;
ctxout.drawImage(video,
offsetX, // source x coordinate
offsetY, // source y coordinate
1, // source width
1, // source height
0, // destination x coordinate
0, // destination y coordinate
1, // destination width
1); // destination height
return ctxout.getImageData(0, 0, 1, 1).data;
},
/*
@ -216,7 +219,12 @@ CaptureStreamTestHelper2D.prototype.clear = function(canvas) {
};
/* Draw the color |color| to the source canvas |canvas|. Format [R,G,B,A]. */
CaptureStreamTestHelper2D.prototype.drawColor = function(canvas, color) {
CaptureStreamTestHelper2D.prototype.drawColor = function(canvas, color,
{ offsetX = 0,
offsetY = 0,
width = canvas.width / 2,
height = canvas.height / 2,
} = {}) {
var ctx = canvas.getContext('2d');
var rgba = color.data.slice(); // Copy to not overwrite the original array
rgba[3] = rgba[3] / 255.0; // Convert opacity to double in range [0,1]
@ -224,7 +232,7 @@ CaptureStreamTestHelper2D.prototype.drawColor = function(canvas, color) {
ctx.fillStyle = "rgba(" + rgba.join(',') + ")";
// Only fill top left corner to test that output is not flipped or rotated.
ctx.fillRect(0, 0, canvas.width / 2, canvas.height / 2);
ctx.fillRect(offsetX, offsetY, width, height);
};
/* Test that the given 2d canvas is NOT origin-clean. */

View File

@ -161,6 +161,12 @@ CryptoBuffer::ToUint8Array(JSContext* aCx) const
return Uint8Array::Create(aCx, Length(), Elements());
}
JSObject*
CryptoBuffer::ToArrayBuffer(JSContext* aCx) const
{
return ArrayBuffer::Create(aCx, Length(), Elements());
}
bool
CryptoBuffer::ToNewUnsignedBuffer(uint8_t** aBuf, uint32_t* aBufLen) const
{

View File

@ -47,6 +47,7 @@ public:
nsresult ToJwkBase64(nsString& aBase64) const;
bool ToSECItem(PLArenaPool* aArena, SECItem* aItem) const;
JSObject* ToUint8Array(JSContext* aCx) const;
JSObject* ToArrayBuffer(JSContext* aCx) const;
bool ToNewUnsignedBuffer(uint8_t** aBuf, uint32_t* aBufLen) const;
bool GetBigIntValue(unsigned long& aRetVal);

View File

@ -189,21 +189,18 @@ HTMLFormElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
{
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::action || aName == nsGkAtoms::target) {
// This check is mostly to preserve previous behavior.
if (aValue) {
if (mPendingSubmission) {
// aha, there is a pending submission that means we're in
// the script and we need to flush it. let's tell it
// that the event was ignored to force the flush.
// the second argument is not playing a role at all.
FlushPendingSubmission();
}
// Don't forget we've notified the password manager already if the
// page sets the action/target in the during submit. (bug 343182)
bool notifiedObservers = mNotifiedObservers;
ForgetCurrentSubmission();
mNotifiedObservers = notifiedObservers;
if (mPendingSubmission) {
// aha, there is a pending submission that means we're in
// the script and we need to flush it. let's tell it
// that the event was ignored to force the flush.
// the second argument is not playing a role at all.
FlushPendingSubmission();
}
// Don't forget we've notified the password manager already if the
// page sets the action/target in the during submit. (bug 343182)
bool notifiedObservers = mNotifiedObservers;
ForgetCurrentSubmission();
mNotifiedObservers = notifiedObservers;
}
}

View File

@ -2319,7 +2319,9 @@ nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
"element should be equals to the current element "
"associated with the id in @form!");
if (element && element->IsHTMLElement(nsGkAtoms::form)) {
if (element &&
element->IsHTMLElement(nsGkAtoms::form) &&
nsContentUtils::IsInSameAnonymousTree(this, element)) {
SetForm(static_cast<HTMLFormElement*>(element), aBindToTree);
}
}

View File

@ -6,6 +6,8 @@ support-files =
file_bug649778.html^headers^
file_fullscreen-api-keys.html
file_content_contextmenu.html
submission_flush.html
post_action_page.html
form_data_file.bin
form_data_file.txt
form_submit_server.sjs
@ -27,3 +29,4 @@ support-files =
tags = fullscreen
[browser_fullscreen-contextmenu-esc.js]
tags = fullscreen
[browser_submission_flush.js]

View File

@ -0,0 +1,85 @@
"use strict";
// Form submissions triggered by the Javascript 'submit' event listener are
// deferred until the event listener finishes. However, changes to specific
// attributes ("action" and "target" attributes) need to cause an immediate
// flush of any pending submission to prevent the form submission from using the
// wrong action or target. This test ensures that such flushes happen properly.
const kTestPage = "http://example.org/browser/dom/html/test/submission_flush.html";
// This is the page pointed to by the form action in the test HTML page.
const kPostActionPage = "http://example.org/browser/dom/html/test/post_action_page.html";
const kFormId = "test_form"
const kFrameId = "test_frame"
const kSubmitButtonId = "submit_button"
// Take in a variety of actions (in the form of setting and unsetting form
// attributes). Then submit the form in the submit event listener to cause a
// deferred form submission. Then perform the test actions and ensure that the
// form used the correct attribute values rather than the changed ones.
async function runTest(aTestActions) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kTestPage);
registerCleanupFunction(() => BrowserTestUtils.removeTab(tab));
let frame_url = await ContentTask.spawn(gBrowser.selectedBrowser,
{kFormId, kFrameId, kSubmitButtonId, aTestActions},
async function({kFormId, kFrameId, kSubmitButtonId,
aTestActions}) {
let form = content.document.getElementById(kFormId);
form.addEventListener("submit", (event) => {
// Need to trigger the deferred submission by submitting in the submit
// event handler. To prevent the form from being submitted twice, the
// <form> tag contains the attribute |onsubmit="return false;"| to cancel
// the original submission.
form.submit();
if (aTestActions.setattr) {
for (let {attr, value} of aTestActions.setattr) {
form.setAttribute(attr, value);
}
}
if (aTestActions.unsetattr) {
for (let attr of aTestActions.unsetattr) {
form.removeAttribute(attr);
}
}
}, {capture: true, once: true});
// Trigger the above event listener
content.document.getElementById(kSubmitButtonId).click();
// Test that the form was submitted to the correct target (the frame) with
// the correct action (kPostActionPage).
let frame = content.document.getElementById(kFrameId);
await new Promise(resolve => {
frame.addEventListener("load", resolve, {once: true});
});
return frame.contentWindow.location.href;
});
is(frame_url, kPostActionPage,
"Form should have submitted with correct target and action");
}
add_task(async function() {
info("Changing action should flush pending submissions");
await runTest({setattr: [{attr: "action", value: "about:blank"}]});
});
add_task(async function() {
info("Changing target should flush pending submissions");
await runTest({setattr: [{attr: "target", value: "_blank"}]});
});
add_task(async function() {
info("Unsetting action should flush pending submissions");
await runTest({unsetattr: ["action"]});
});
// On failure, this test will time out rather than failing an assert. When the
// target attribute is not set, the form will submit the active page, navigating
// it away and preventing the wait for iframe load from ever finishing.
add_task(async function() {
info("Unsetting target should flush pending submissions");
await runTest({unsetattr: ["target"]});
});

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Submission Flush Test Post Action Page</title>
</head>
<body>
<h1>Post Action Page</h1>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Submission Flush Test</title>
</head>
<body>
<form id="test_form" action="post_action_page.html" target="form_target" method="POST" onsubmit="return false;">
<button type="submit" id="submit_button">Submit</button>
</form>
<iframe name="form_target" id="test_frame"></iframe>
</body>
</html>

View File

@ -2,38 +2,131 @@
<html>
<head>
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
<script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
title: "getUserMedia Basic Screenshare Test",
bug: "1211656"
bug: "1211656",
visible: true,
});
var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
let verifyScreenshare = async (video, helper, upleft, upright, downleft, downright) => {
if (video.readyState < video.HAVE_CURRENT_DATA) {
info("Waiting for data");
await new Promise(r => video.addEventListener("loadeddata", r, {once: true}));
}
// We assume video size will not change. Offsets help to account for a
// square fullscreen-canvas, while the screen is rectangular.
let offsetX = Math.max(0, video.videoWidth - video.videoHeight) / 2;
let offsetY = Math.max(0, video.videoHeight - video.videoWidth) / 2;
let verifyAround = async (internalX, internalY, color) => {
// Pick a couple of samples around a coordinate to check for a color.
// We check multiple rows and columns, to avoid most artifact issues.
let areaSamples = [
{dx: 0, dy: 0},
{dx: 1, dy: 3},
{dx: 8, dy: 5},
];
for (let {dx, dy} of areaSamples) {
let x = offsetX + dx + internalX;
let y = offsetY + dy + internalY;
info("Checking screen coordinate (" + [x,y] + ") of total resolution "
+ video.videoWidth + "x" + video.videoHeight
+ " against " + color.name + ".");
await helper.waitForPixel(video, px => {
let result = helper.isPixel(px, color, 16);
info("Checking pixel against " + color.name + ". Got ["
+ Array.slice(px) + "] (" + (result ? "YES" : "NO") + ")");
return result;
}, {offsetX: x, offsetY: y});
}
};
let screenSizeSq = Math.min(video.videoWidth, video.videoHeight);
info("Waiting for upper left quadrant to become " + upleft.name);
await verifyAround(screenSizeSq / 4, screenSizeSq / 4, upleft);
info("Waiting for upper right quadrant to become " + upright.name);
await verifyAround(screenSizeSq * 3 / 4, screenSizeSq / 4, upright);
info("Waiting for lower left quadrant to become " + downleft.name);
await verifyAround(screenSizeSq / 4, screenSizeSq * 3 / 4, downleft);
info("Waiting for lower right quadrant to become " + downright.name);
await verifyAround(screenSizeSq * 3 / 4, screenSizeSq * 3 / 4, downright);
};
/**
* Run a test to verify that we can complete a start and stop media playback
* cycle for a screenshare LocalMediaStream on a video HTMLMediaElement.
* cycle for a screenshare MediaStream on a video HTMLMediaElement.
*/
runTest(function () {
runTest(async function () {
const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
if (IsMacOSX10_6orOlder() || isWinXP) {
ok(true, "Screensharing disabled for OSX10.6 and WinXP");
return;
}
var testVideo = createMediaElement('video', 'testVideo');
var constraints = {
video: {
mozMediaSource: "screen",
mediaSource: "screen"
},
fake: false
// Screensharing must work even without "mochi.test," in allowed_domains
await pushPrefs(
["media.getusermedia.screensharing.allowed_domains",
"mozilla.github.io,*.bugzilla.mozilla.org"],
["full-screen-api.enabled", true],
["full-screen-api.unprefix.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
["full-screen-api.transition-duration.enter", "0 0"],
["full-screen-api.transition-duration.leave", "0 0"],
);
let testVideo = createMediaElement('video', 'testVideo');
let canvas = document.createElement("canvas");
canvas.width = canvas.height = 20;
document.getElementById("content").appendChild(canvas);
let draw = (upleft, upright, downleft, downright) => {
helper.drawColor(canvas, upleft, {offsetX: 0, offsetY: 0});
helper.drawColor(canvas, upright, {offsetX: 10, offsetY: 0});
helper.drawColor(canvas, downleft, {offsetX: 0, offsetY: 10});
helper.drawColor(canvas, downright, {offsetX: 10, offsetY: 10});
};
var videoConstraints = [
{
let helper = new CaptureStreamTestHelper2D(1, 1);
await new Promise((resolve, reject) => {
document.onfullscreenchange = resolve;
document.onfullscreenerror = () => reject(new Error("fullscreenerror"));
// Note that going fullscreen requires the tab (and window) to be in the
// foreground and having focus.
canvas.requestFullscreen();
});
info("Testing screenshare without constraints");
let stream = await getUserMedia({
video: {mediaSource: "screen"},
fake: false,
});
draw(helper.red, helper.blue,
helper.green, helper.grey);
let playback = new LocalMediaStreamPlayback(testVideo, stream);
playback.startMedia();
await playback.verifyPlaying();
await verifyScreenshare(testVideo, helper,
helper.red, helper.blue,
helper.green, helper.grey);
for (let track of stream.getTracks()) {
track.stop();
}
playback.detachFromMediaElement();
info("Testing screenshare with size and framerate constraints");
stream = await getUserMedia({
video: {
mediaSource: 'screen',
width: {
min: '10',
@ -46,9 +139,22 @@
frameRate: {
min: '10',
max: '15'
}
},
},
{
fake: false,
});
draw(helper.green, helper.red,
helper.grey, helper.blue);
playback = new LocalMediaStreamPlayback(testVideo, stream);
playback.startMedia();
await playback.verifyPlaying();
await verifyScreenshare(testVideo, helper,
helper.green, helper.red,
helper.grey, helper.blue);
info("Testing modifying screenshare with applyConstraints");
await Promise.all([
testVideo.srcObject.getVideoTracks()[0].applyConstraints({
mediaSource: 'screen',
width: 200,
height: 200,
@ -56,31 +162,20 @@
min: '5',
max: '10'
}
}
];
return Promise.resolve()
// Screensharing must work even without "mochi.test," in allowed_domains
.then(() => pushPrefs(["media.getusermedia.screensharing.allowed_domains",
"mozilla.github.io,*.bugzilla.mozilla.org"]))
.then(() => getUserMedia(constraints).then(stream => {
var playback = new LocalMediaStreamPlayback(testVideo, stream);
return playback.playMediaWithDeprecatedStreamStop(false);
}))
.then(() => getUserMedia({video: videoConstraints[0], fake: false}))
.then(stream => {
var playback = new LocalMediaStreamPlayback(testVideo, stream);
playback.startMedia(false);
return playback.verifyPlaying()
.then(() => Promise.all([
() => testVideo.srcObject.getVideoTracks()[0].applyConstraints(videoConstraints[1]),
() => listenUntil(testVideo, "resize", () => true)
]))
.then(() => playback.verifyPlaying()) // still playing
.then(() => playback.deprecatedStopStreamInMediaPlayback())
.then(() => playback.detachFromMediaElement());
});
});
}),
haveEvent(testVideo, "resize", wait(5000, new Error("Timeout"))),
]);
draw(helper.grey, helper.green,
helper.blue, helper.red);
await playback.verifyPlaying(); // still playing
await verifyScreenshare(testVideo, helper,
helper.grey, helper.green,
helper.blue, helper.red);
await playback.deprecatedStopStreamInMediaPlayback();
playback.detachFromMediaElement();
document.exitFullscreen();
});
</script>
</pre>
</body>

View File

@ -0,0 +1,3 @@
<svg>
<animate id='a' calcMode='discrete' attributeName='height' by='-159'/>
<animate id='a' calcMode='discrete' attributeName='height' by='-159'/>

After

Width:  |  Height:  |  Size: 148 B

View File

@ -53,3 +53,4 @@ load 709907-1.svg
load 720103-1.svg
load 1010681-1.svg
load 1375596-1.svg
load 1402547-1.html

View File

@ -114,12 +114,12 @@ GetZeroValueForUnit(StyleAnimationValue::Unit aUnit)
}
}
// This method requires at least one of its arguments to be non-null.
//
// If one argument is null, this method updates it to point to "zero"
// for the other argument's Unit (if applicable; otherwise, we return false).
//
// If neither argument is null, this method does nothing.
// If neither argument is null, this method simply returns true.
//
// If both arguments are null, this method returns false.
//
// |aZeroValueStorage| should be a reference to a RefPtr<RawServoAnimationValue>.
// This is used where we may need to allocate a new ServoAnimationValue to
@ -131,7 +131,9 @@ FinalizeServoAnimationValues(const RefPtr<RawServoAnimationValue>*& aValue1,
const RefPtr<RawServoAnimationValue>*& aValue2,
RefPtr<RawServoAnimationValue>& aZeroValueStorage)
{
MOZ_ASSERT(aValue1 || aValue2, "expecting at least one non-null value");
if (!aValue1 && !aValue2) {
return false;
}
// Are we missing either val? (If so, it's an implied 0 in other val's units)
@ -149,8 +151,9 @@ static bool
FinalizeStyleAnimationValues(const StyleAnimationValue*& aValue1,
const StyleAnimationValue*& aValue2)
{
MOZ_ASSERT(aValue1 || aValue2,
"expecting at least one non-null value");
if (!aValue1 && !aValue2) {
return false;
}
if (!aValue1) {
aValue1 = GetZeroValueForUnit(aValue2->GetUnit());
@ -298,7 +301,7 @@ AddOrAccumulateForServo(nsSMILValue& aDest,
MOZ_ASSERT(!aValueToAddWrapper || !aDestWrapper ||
aValueToAddWrapper->mServoValues.Length() ==
aDestWrapper->mServoValues.Length(),
"Both of values'length in the wrappers should be the same if "
"Both of values' length in the wrappers should be the same if "
"both of them exist");
for (size_t i = 0; i < len; i++) {
@ -359,8 +362,15 @@ AddOrAccumulate(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
const ValueWrapper* valueToAddWrapper = ExtractValueWrapper(aValueToAdd);
MOZ_ASSERT(destWrapper || valueToAddWrapper,
"need at least one fully-initialized value");
// If both of the values are empty just fail. This can happen in rare cases
// such as when the underlying animation produced an empty value.
//
// Technically, it doesn't matter what we return here since in either case it
// will produce the same result: an empty value.
if (!destWrapper && !valueToAddWrapper) {
return false;
}
nsCSSPropertyID property = valueToAddWrapper
? valueToAddWrapper->mPropID

View File

@ -59,7 +59,7 @@ AuthenticatorAssertionResponse::GetAuthenticatorData(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetVal)
{
if (!mAuthenticatorDataCachedObj) {
mAuthenticatorDataCachedObj = mAuthenticatorData.ToUint8Array(aCx);
mAuthenticatorDataCachedObj = mAuthenticatorData.ToArrayBuffer(aCx);
}
aRetVal.set(mAuthenticatorDataCachedObj);
}
@ -78,7 +78,7 @@ AuthenticatorAssertionResponse::GetSignature(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetVal)
{
if (!mSignatureCachedObj) {
mSignatureCachedObj = mSignature.ToUint8Array(aCx);
mSignatureCachedObj = mSignature.ToArrayBuffer(aCx);
}
aRetVal.set(mSignatureCachedObj);
}

View File

@ -56,7 +56,7 @@ AuthenticatorAttestationResponse::GetAttestationObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetVal)
{
if (!mAttestationObjectCachedObj) {
mAttestationObjectCachedObj = mAttestationObject.ToUint8Array(aCx);
mAttestationObjectCachedObj = mAttestationObject.ToArrayBuffer(aCx);
}
aRetVal.set(mAttestationObjectCachedObj);
}

View File

@ -58,7 +58,7 @@ AuthenticatorResponse::GetClientDataJSON(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetVal)
{
if (!mClientDataJSONCachedObj) {
mClientDataJSONCachedObj = mClientDataJSON.ToUint8Array(aCx);
mClientDataJSONCachedObj = mClientDataJSON.ToArrayBuffer(aCx);
}
aRetVal.set(mClientDataJSONCachedObj);
}

View File

@ -55,7 +55,7 @@ PublicKeyCredential::GetRawId(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetVal)
{
if (!mRawIdCachedObj) {
mRawIdCachedObj = mRawId.ToUint8Array(aCx);
mRawIdCachedObj = mRawId.ToArrayBuffer(aCx);
}
aRetVal.set(mRawIdCachedObj);
}

View File

@ -1,6 +1,6 @@
[DEFAULT]
support-files =
frame_webauthn_success.html
tab_webauthn_success.html
../cbor/*
../pkijs/*
../u2futil.js

View File

@ -61,7 +61,7 @@ add_task(async function test_loopback() {
// These tests can't run simultaneously as the preference changes will race.
// So let's run them sequentially here, but in an async function so we can
// use await.
const testPage = "https://example.com/browser/dom/webauthn/tests/browser/frame_webauthn_success.html";
const testPage = "https://example.com/browser/dom/webauthn/tests/browser/tab_webauthn_success.html";
{
cleanupTelemetry();
// Enable the soft token, and execute a simple end-to-end test

View File

@ -1,128 +0,0 @@
<!DOCTYPE html>
<meta charset=utf-8>
<head>
<title>Full-run test for MakeCredential/GetAssertion for W3C Web Authentication</title>
<script type="text/javascript" src="u2futil.js"></script>
<script type="text/javascript" src="../pkijs/common.js"></script>
<script type="text/javascript" src="../pkijs/asn1.js"></script>
<script type="text/javascript" src="../pkijs/x509_schema.js"></script>
<script type="text/javascript" src="../pkijs/x509_simpl.js"></script>
<script type="text/javascript" src="../cbor/cbor.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<h1>Full-run test for MakeCredential/GetAssertion for W3C Web Authentication</h1>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1265472">Mozilla Bug 1265472</a>
<script class="testbody" type="text/javascript">
"use strict";
let gCredentialChallenge = new Uint8Array(16);
window.crypto.getRandomValues(gCredentialChallenge);
let gAssertionChallenge = new Uint8Array(16);
window.crypto.getRandomValues(gAssertionChallenge);
// the WebAuthn browser chrome tests watch for an element 'result' to appear in the DOM
function signalCompletion(aText) {
console.log(aText)
let result = document.createElement('h1');
result.id = "result";
result.textContent = aText;
document.body.append(result);
}
function util_decodeCreatedCredential(aCredInfo) {
/* PublicKeyCredential : Credential
- rawId: Key Handle buffer pulled from U2F Register() Response
- response : AuthenticatorAttestationResponse : AuthenticatorResponse
- attestationObject: CBOR object
- clientDataJSON: serialized JSON
- clientExtensionResults: (not yet supported)
*/
return webAuthnDecodeAttestation(aCredInfo.response.attestationObject.buffer)
.then(function(decodedResult) {
aCredInfo.publicKeyHandle = decodedResult.publicKeyHandle;
aCredInfo.attestationObject = decodedResult.attestationObject;
return aCredInfo;
});
}
function util_checkAssertionAndSigValid(aPublicKey, aAssertion) {
/* PublicKeyCredential : Credential
- rawId: ID of Credential from AllowList that succeeded
- response : AuthenticatorAssertionResponse : AuthenticatorResponse
- clientDataJSON: serialized JSON
- authenticatorData: RP ID Hash || U2F Sign() Response
- signature: U2F Sign() Response
*/
// Parse the signature data
if (aAssertion.response.signature[0] != 0x01) {
throw "User presence byte not set";
}
let presenceAndCounter = aAssertion.response.signature.slice(0,5);
let signatureValue = aAssertion.response.signature.slice(5);
let rpIdHash = aAssertion.response.authenticatorData.slice(0,32);
// Assemble the signed data and verify the signature
return deriveAppAndChallengeParam(window.location.host, aAssertion.response.clientDataJSON)
.then(function(aParams) {
console.log(aParams.appParam, rpIdHash, presenceAndCounter, aParams.challengeParam);
console.log("ClientData buffer: ", hexEncode(aAssertion.response.clientDataJSON));
console.log("ClientDataHash: ", hexEncode(aParams.challengeParam));
return assembleSignedData(aParams.appParam, presenceAndCounter, aParams.challengeParam);
})
.then(function(aSignedData) {
console.log(aPublicKey, aSignedData, signatureValue);
return verifySignature(aPublicKey, aSignedData, signatureValue);
})
}
let rp = {id: document.domain, name: "none", icon: "none"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "ES256"};
let makeCredentialOptions = {
rp: rp,
user: user,
challenge: gCredentialChallenge,
parameters: [param]
};
let credm = navigator.credentials;
credm.create({publicKey: makeCredentialOptions})
.then(util_decodeCreatedCredential)
.then(function testAssertion(aCredInfo) {
let newCredential = {
type: "public-key",
id: Uint8Array.from(aCredInfo.rawId),
transports: ["usb"],
}
let publicKeyCredentialRequestOptions = {
challenge: gAssertionChallenge,
timeout: 5000, // the minimum timeout is actually 15 seconds
rpId: document.domain,
allowList: [newCredential]
};
return credm.get({publicKey: publicKeyCredentialRequestOptions})
.then(function(aAssertion) {
/* Pass along the pubKey. */
return util_checkAssertionAndSigValid(aCredInfo.publicKeyHandle, aAssertion);
});
})
.then(function(aSigVerifyResult) {
signalCompletion("Signing signature verified: " + aSigVerifyResult);
})
.catch(function failure(aReason) {
signalCompletion("Failure: " + aReason);
});
</script>
</body>
</html>

View File

@ -0,0 +1,119 @@
<!DOCTYPE html>
<meta charset=utf-8>
<head>
<title>Full-run test for MakeCredential/GetAssertion for W3C Web Authentication</title>
<script type="text/javascript" src="u2futil.js"></script>
<script type="text/javascript" src="../pkijs/common.js"></script>
<script type="text/javascript" src="../pkijs/asn1.js"></script>
<script type="text/javascript" src="../pkijs/x509_schema.js"></script>
<script type="text/javascript" src="../pkijs/x509_simpl.js"></script>
<script type="text/javascript" src="../cbor/cbor.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<h1>Full-run test for MakeCredential/GetAssertion for W3C Web Authentication</h1>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1265472">Mozilla Bug 1265472</a>
<script class="testbody" type="text/javascript">
"use strict";
let gCredentialChallenge = new Uint8Array(16);
window.crypto.getRandomValues(gCredentialChallenge);
let gAssertionChallenge = new Uint8Array(16);
window.crypto.getRandomValues(gAssertionChallenge);
// the WebAuthn browser chrome tests watch for an element 'result' to appear in the DOM
function signalCompletion(aText) {
console.log(aText)
let result = document.createElement('h1');
result.id = "result";
result.textContent = aText;
document.body.append(result);
}
let gState = {};
let makeCredentialOptions = {
rp: {id: document.domain, name: "none", icon: "none"},
user: {id: "none", name: "none", icon: "none", displayName: "none"},
challenge: gCredentialChallenge,
timeout: 5000, // the minimum timeout is actually 15 seconds
parameters: [{type: "public-key", algorithm: "ES256"}],
};
navigator.credentials.create({publicKey: makeCredentialOptions})
.then(function (aNewCredentialInfo) {
gState.credential = aNewCredentialInfo;
return webAuthnDecodeCBORAttestation(aNewCredentialInfo.response.attestationObject);
})
.then(function testAssertion(aCredInfo) {
gState.publicKeyHandle = aCredInfo.authDataObj.publicKeyHandle;
let newCredential = {
type: "public-key",
id: new Uint8Array(gState.credential.rawId),
transports: ["usb"],
}
let publicKeyCredentialRequestOptions = {
challenge: gAssertionChallenge,
timeout: 5000, // the minimum timeout is actually 15 seconds
rpId: document.domain,
allowList: [newCredential]
};
return navigator.credentials.get({publicKey: publicKeyCredentialRequestOptions});
})
.then(function(aAssertion) {
let clientData = JSON.parse(buffer2string(aAssertion.response.clientDataJSON));
gState.assertion = aAssertion;
return webAuthnDecodeAuthDataArray(new Uint8Array(aAssertion.response.authenticatorData));
})
.then(function(aAttestationObj) {
gState.attestation = aAttestationObj;
// Make sure the RP ID hash matches what we calculate.
return crypto.subtle.digest("SHA-256", string2buffer(document.domain))
.then(function(calculatedRpIdHash) {
let calcHashStr = bytesToBase64UrlSafe(new Uint8Array(calculatedRpIdHash));
let providedHashStr = bytesToBase64UrlSafe(new Uint8Array(aAttestationObj.authDataObj.rpIdHash));
if (calcHashStr != providedHashStr) {
return Promise.reject("Calculated RP ID hash must match what the browser derived.");
}
return Promise.resolve(aAttestationObj);
});
})
.then(function(aAttestation) {
if (new Uint8Array(aAttestation.flags) != flag_TUP) {
return Promise.reject("Assertion's user presence byte not set correctly.");
}
let clientDataJSON = gState.assertion.response.clientDataJSON;
return deriveAppAndChallengeParam(document.domain, clientDataJSON, aAttestation);
})
.then(function(aParams) {
return assembleSignedData(aParams.appParam, aParams.attestation.flags,
aParams.attestation.counter, aParams.challengeParam);
})
.then(function(aSignedData) {
let signature = gState.assertion.response.signature;
console.log(gState.publicKeyHandle, aSignedData, signature);
return verifySignature(gState.publicKeyHandle, aSignedData, new Uint8Array(signature));
})
.then(function(aSigVerifyResult) {
signalCompletion("Signing signature verified: " + aSigVerifyResult);
gState = {};
})
.catch(function(aReason) {
signalCompletion("Failure: " + aReason);
gState = {};
});
</script>
</body>
</html>

View File

@ -53,7 +53,7 @@ function() {
is(aCredInfo.type, "public-key", "Credential type must be public-key")
ok(aCredInfo.rawId.length > 0, "Key ID exists");
ok(aCredInfo.rawId.byteLength > 0, "Key ID exists");
is(aCredInfo.id, bytesToBase64UrlSafe(aCredInfo.rawId), "Encoded Key ID and Raw Key ID match");
ok(aCredInfo.rawId === aCredInfo.rawId, "PublicKeyCredential.RawID is SameObject");
@ -66,23 +66,26 @@ function() {
is(clientData.origin, window.location.origin, "Origin is correct");
is(clientData.hashAlg, "SHA-256", "Hash algorithm is correct");
return webAuthnDecodeCBORAttestation(aCredInfo.response.attestationObject.buffer)
.then(function(decodedResult) {
return webAuthnDecodeCBORAttestation(aCredInfo.response.attestationObject)
.then(function(aAttestationObj) {
// Make sure the RP ID hash matches what we calculate.
return crypto.subtle.digest("SHA-256", string2buffer(document.domain))
.then(function(calculatedHash) {
is(bytesToBase64(new Uint8Array(calculatedHash)), bytesToBase64(decodedResult.rpIdHash),
.then(function(calculatedRpIdHash) {
let calcHashStr = bytesToBase64UrlSafe(new Uint8Array(calculatedRpIdHash));
let providedHashStr = bytesToBase64UrlSafe(new Uint8Array(aAttestationObj.authDataObj.rpIdHash));
is(calcHashStr, providedHashStr,
"Calculated RP ID hash must match what the browser derived.");
return Promise.resolve(decodedResult);
return Promise.resolve(aAttestationObj);
});
})
.then(function(decodedResult) {
ok(decodedResult.flags == (flag_TUP | flag_AT),
.then(function(aAttestationObj) {
ok(aAttestationObj.authDataObj.flags == (flag_TUP | flag_AT),
"User presence and Attestation Object must both be set");
aCredInfo.clientDataObj = clientData;
aCredInfo.publicKeyHandle = decodedResult.publicKeyHandle;
aCredInfo.attestationObject = decodedResult.attestationObject;
aCredInfo.publicKeyHandle = aAttestationObj.authDataObj.publicKeyHandle;
aCredInfo.attestationObject = aAttestationObj.authDataObj.attestationAuthData;
return aCredInfo;
});
}
@ -100,23 +103,23 @@ function() {
is(aAssertion.type, "public-key", "Credential type must be public-key")
ok(aAssertion.rawId.length > 0, "Key ID exists");
is(aAssertion.id, bytesToBase64UrlSafe(aAssertion.rawId), "Encoded Key ID and Raw Key ID match");
ok(aAssertion.rawId.byteLength > 0, "Key ID exists");
is(aAssertion.id, bytesToBase64UrlSafe(new Uint8Array(aAssertion.rawId)), "Encoded Key ID and Raw Key ID match");
ok(aAssertion.response.authenticatorData === aAssertion.response.authenticatorData, "AuthenticatorAssertionResponse.AuthenticatorData is SameObject");
ok(aAssertion.response.signature === aAssertion.response.signature, "AuthenticatorAssertionResponse.Signature is SameObject");
ok(aAssertion.response.authenticatorData.length > 0, "Authenticator data exists");
ok(aAssertion.response.authenticatorData.byteLength > 0, "Authenticator data exists");
let clientData = JSON.parse(buffer2string(aAssertion.response.clientDataJSON));
is(clientData.challenge, bytesToBase64UrlSafe(gAssertionChallenge), "Challenge is correct");
is(clientData.origin, window.location.origin, "Origin is correct");
is(clientData.hashAlg, "SHA-256", "Hash algorithm is correct");
return webAuthnDecodeAttestation(aAssertion.response.authenticatorData)
.then(function(decodedResult) {
ok(decodedResult.flags == flag_TUP, "User presence must be the only flag set");
is(decodedResult.counter.length, 4, "Counter must be 4 bytes");
return deriveAppAndChallengeParam(window.location.host, aAssertion.response.clientDataJSON, decodedResult)
return webAuthnDecodeAuthDataArray(aAssertion.response.authenticatorData)
.then(function(aAttestation) {
ok(new Uint8Array(aAttestation.flags) == flag_TUP, "User presence must be the only flag set");
is(aAttestation.counter.byteLength, 4, "Counter must be 4 bytes");
return deriveAppAndChallengeParam(window.location.host, aAssertion.response.clientDataJSON, aAttestation)
})
.then(function(aParams) {
console.log(aParams);
@ -159,7 +162,7 @@ function() {
user: user,
challenge: gCredentialChallenge,
parameters: [param],
excludeList: [{type: "public-key", id: Uint8Array.from(aCredInfo.rawId),
excludeList: [{type: "public-key", id: new Uint8Array(aCredInfo.rawId),
transports: ["usb"]}]
};
credm.create({publicKey: makeCredentialOptions})
@ -177,7 +180,7 @@ function() {
function testAssertion(aCredInfo) {
let newCredential = {
type: "public-key",
id: Uint8Array.from(aCredInfo.rawId),
id: new Uint8Array(aCredInfo.rawId),
transports: ["usb"],
}

View File

@ -42,7 +42,7 @@
return function(aPublicKeyCredential) {
gTrackedCredential[aIdentifier] = {
type: "public-key",
id: Uint8Array.from(aPublicKeyCredential.rawId),
id: new Uint8Array(aPublicKeyCredential.rawId),
transports: [ "usb" ],
}
return Promise.resolve(aPublicKeyCredential);

View File

@ -82,15 +82,19 @@ function string2buffer(str) {
function buffer2string(buf) {
let str = "";
buf.map(x => str += String.fromCharCode(x));
if (!(buf.constructor === Uint8Array)) {
buf = new Uint8Array(buf);
}
buf.map(function(x){ return str += String.fromCharCode(x) });
return str;
}
function bytesToBase64(u8a){
let CHUNK_SZ = 0x8000;
let c = [];
for (let i = 0; i < u8a.length; i += CHUNK_SZ) {
c.push(String.fromCharCode.apply(null, u8a.subarray(i, i + CHUNK_SZ)));
let array = new Uint8Array(u8a);
for (let i = 0; i < array.length; i += CHUNK_SZ) {
c.push(String.fromCharCode.apply(null, array.subarray(i, i + CHUNK_SZ)));
}
return window.btoa(c.join(""));
}
@ -134,25 +138,25 @@ function webAuthnDecodeCBORAttestation(aCborAttBuf) {
let attObj = CBOR.decode(aCborAttBuf);
console.log(":: Attestation CBOR Object ::");
if (!("authData" in attObj && "fmt" in attObj && "attStmt" in attObj)) {
throw "Invalid CBOR Attestation Object";
return Promise.reject("Invalid CBOR Attestation Object");
}
if (!("sig" in attObj.attStmt && "x5c" in attObj.attStmt)) {
throw "Invalid CBOR Attestation Statement";
return Promise.reject("Invalid CBOR Attestation Statement");
}
return webAuthnDecodeAttestation(attObj.authData)
.then(function (aAttestationObj) {
aAttestationObj.attestationObject = attObj;
return Promise.resolve(aAttestationObj);
return webAuthnDecodeAuthDataArray(new Uint8Array(attObj.authData))
.then(function (aAuthDataObj) {
attObj.authDataObj = aAuthDataObj;
return Promise.resolve(attObj);
});
}
function webAuthnDecodeAttestation(aAuthData) {
function webAuthnDecodeAuthDataArray(aAuthData) {
let rpIdHash = aAuthData.slice(0, 32);
let flags = aAuthData.slice(32, 33);
let counter = aAuthData.slice(33, 37);
console.log(":: Attestation Object Data ::");
console.log(":: Authenticator Data ::");
console.log("RP ID Hash: " + hexEncode(rpIdHash));
console.log("Counter: " + hexEncode(counter) + " Flags: " + flags);
@ -166,7 +170,7 @@ function webAuthnDecodeAttestation(aAuthData) {
}
if (aAuthData.length < 38) {
throw "Attestation Data flag was set, but not enough data passed in!";
return Promise.reject("Authenticator Data flag was set, but not enough data passed in!");
}
let attData = {};
@ -174,16 +178,16 @@ function webAuthnDecodeAttestation(aAuthData) {
attData.credIdLen = (aAuthData[53] << 8) + aAuthData[54];
attData.credId = aAuthData.slice(55, 55 + attData.credIdLen);
console.log(":: Attestation Data ::");
console.log(":: Authenticator Data ::");
console.log("AAGUID: " + hexEncode(attData.aaguid));
cborPubKey = aAuthData.slice(55 + attData.credIdLen);
var pubkeyObj = CBOR.decode(cborPubKey.buffer);
if (!("alg" in pubkeyObj && "x" in pubkeyObj && "y" in pubkeyObj)) {
throw "Invalid CBOR Public Key Object";
return Promise.reject("Invalid CBOR Public Key Object");
}
if (pubkeyObj.alg != "ES256") {
throw "Unexpected public key algorithm";
return Promise.reject("Unexpected public key algorithm");
}
let pubKeyBytes = assemblePublicKeyBytesData(pubkeyObj.x, pubkeyObj.y);
@ -249,20 +253,20 @@ function assemblePublicKeyBytesData(xCoord, yCoord) {
function assembleSignedData(appParam, flags, counter, challengeParam) {
let signedData = new Uint8Array(32 + 1 + 4 + 32);
appParam.map((x, i) => signedData[0 + i] = x);
signedData[32] = flags;
counter.map((x, i) => signedData[33 + i] = x);
challengeParam.map((x, i) => signedData[37 + i] = x);
new Uint8Array(appParam).map((x, i) => signedData[0 + i] = x);
signedData[32] = new Uint8Array(flags)[0];
new Uint8Array(counter).map((x, i) => signedData[33 + i] = x);
new Uint8Array(challengeParam).map((x, i) => signedData[37 + i] = x);
return signedData;
}
function assembleRegistrationSignedData(appParam, challengeParam, keyHandle, pubKey) {
let signedData = new Uint8Array(1 + 32 + 32 + keyHandle.length + 65);
signedData[0] = 0x00;
appParam.map((x, i) => signedData[1 + i] = x);
challengeParam.map((x, i) => signedData[33 + i] = x);
keyHandle.map((x, i) => signedData[65 + i] = x);
pubKey.map((x, i) => signedData[65 + keyHandle.length + i] = x);
new Uint8Array(appParam).map((x, i) => signedData[1 + i] = x);
new Uint8Array(challengeParam).map((x, i) => signedData[33 + i] = x);
new Uint8Array(keyHandle).map((x, i) => signedData[65 + i] = x);
new Uint8Array(pubKey).map((x, i) => signedData[65 + keyHandle.length + i] = x);
return signedData;
}
@ -279,7 +283,12 @@ function sanitizeSigArray(arr) {
}
function verifySignature(key, data, derSig) {
let sigAsn1 = org.pkijs.fromBER(derSig.buffer);
if (derSig.byteLength < 70) {
console.log("bad sig: " + hexEncode(new Uint8Array(derSig)))
return Promise.reject("Invalid signature length: " + derSig.byteLength);
}
let sigAsn1 = org.pkijs.fromBER(derSig);
let sigR = new Uint8Array(sigAsn1.result.value_block.value[0].value_block.value_hex);
let sigS = new Uint8Array(sigAsn1.result.value_block.value[1].value_block.value_hex);

View File

@ -2084,6 +2084,12 @@ gfxFont::Draw(const gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxPoint origPt = *aPt;
if (aRunParams.isVerticalRun && !fontParams.isVerticalFont) {
if (textDrawer) {
textDrawer->FoundUnsupportedFeature();
return;
}
sideways = true;
matrixRestore.SetContext(aRunParams.context);
gfxPoint p(aPt->x * aRunParams.devPerApp,
@ -2139,6 +2145,11 @@ gfxFont::Draw(const gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
// use as many strikes as needed for the the increased advance
fontParams.extraStrikes =
std::max(1, NS_lroundf(GetSyntheticBoldOffset() / xscale));
if (textDrawer) {
textDrawer->FoundUnsupportedFeature();
return;
}
}
} else {
fontParams.synBoldOnePixelOffset = 0;
@ -2167,6 +2178,10 @@ gfxFont::Draw(const gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
cairo_matrix_t matrix;
cairo_scaled_font_get_font_matrix(mScaledFont, &matrix);
if (matrix.xy != 0) {
if (textDrawer) {
textDrawer->FoundUnsupportedFeature();
}
// If this matrix applies a skew, which can happen when drawing
// oblique fonts, we will set the DrawTarget matrix to apply the
// skew. We'll need to move the glyphs by the inverse of the skew to

View File

@ -642,7 +642,9 @@ gfxTextRun::Draw(Range aRange, gfxPoint aPt, const DrawParams& aParams) const
if (aParams.drawMode & DrawMode::GLYPH_FILL &&
HasNonOpaqueNonTransparentColor(aParams.context, currentColor) &&
HasSyntheticBoldOrColor(this, aRange)) {
HasSyntheticBoldOrColor(this, aRange) &&
!aParams.context->GetTextDrawer()) {
needToRestore = true;
// Measure text; use the bounding box to determine the area we need
// to buffer.

View File

@ -220,6 +220,7 @@ function treatAsSafeArgument(entry, varName, csuName)
["Gecko_CopyShapeSourceFrom", "aDst", null],
["Gecko_DestroyShapeSource", "aShape", null],
["Gecko_StyleShapeSource_SetURLValue", "aShape", null],
["Gecko_NewBasicShape", "aShape", null],
["Gecko_nsFont_InitSystem", "aDest", null],
["Gecko_nsFont_SetFontFeatureValuesLookup", "aFont", null],
["Gecko_nsFont_ResetFontFeatureValuesLookup", "aFont", null],
@ -370,6 +371,14 @@ function ignoreCallEdge(entry, callee)
return true;
}
// StyleShapeSource exclusively owns its UniquePtr<nsStyleImage>.
if (/nsStyleImage::SetURLValue/.test(callee) &&
/StyleShapeSource::SetURL/.test(name) &&
entry.isSafeArgument(0))
{
return true;
}
// The AddRef through a just-assigned heap pointer here is not handled by
// the analysis.
if (/nsCSSValue::Array::AddRef/.test(callee) &&

View File

@ -3703,7 +3703,7 @@ PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent,
RestyleManager* restyleManager = mPresContext->RestyleManager();
uint32_t hoverGenerationBefore =
restyleManager->GetHoverGeneration();
nsEventStatus status;
nsEventStatus status = nsEventStatus_eIgnore;
nsView* targetView = nsView::GetViewFor(aEvent->mWidget);
if (!targetView)
return;

View File

@ -38,7 +38,7 @@ ShapeUtils::ComputeShapeRadius(const StyleShapeRadius aType,
}
nsPoint
ShapeUtils::ComputeCircleOrEllipseCenter(const StyleBasicShape* aBasicShape,
ShapeUtils::ComputeCircleOrEllipseCenter(const UniquePtr<StyleBasicShape>& aBasicShape,
const nsRect& aRefBox)
{
MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Circle ||
@ -54,7 +54,7 @@ ShapeUtils::ComputeCircleOrEllipseCenter(const StyleBasicShape* aBasicShape,
}
nscoord
ShapeUtils::ComputeCircleRadius(const StyleBasicShape* aBasicShape,
ShapeUtils::ComputeCircleRadius(const UniquePtr<StyleBasicShape>& aBasicShape,
const nsPoint& aCenter,
const nsRect& aRefBox)
{
@ -86,7 +86,7 @@ ShapeUtils::ComputeCircleRadius(const StyleBasicShape* aBasicShape,
}
nsSize
ShapeUtils::ComputeEllipseRadii(const StyleBasicShape* aBasicShape,
ShapeUtils::ComputeEllipseRadii(const UniquePtr<StyleBasicShape>& aBasicShape,
const nsPoint& aCenter,
const nsRect& aRefBox)
{
@ -117,7 +117,7 @@ ShapeUtils::ComputeEllipseRadii(const StyleBasicShape* aBasicShape,
}
/* static */ nsRect
ShapeUtils::ComputeInsetRect(const StyleBasicShape* aBasicShape,
ShapeUtils::ComputeInsetRect(const UniquePtr<StyleBasicShape>& aBasicShape,
const nsRect& aRefBox)
{
MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Inset,
@ -138,7 +138,7 @@ ShapeUtils::ComputeInsetRect(const StyleBasicShape* aBasicShape,
}
/* static */ bool
ShapeUtils::ComputeInsetRadii(const StyleBasicShape* aBasicShape,
ShapeUtils::ComputeInsetRadii(const UniquePtr<StyleBasicShape>& aBasicShape,
const nsRect& aInsetRect,
const nsRect& aRefBox,
nscoord aRadii[8])
@ -150,7 +150,7 @@ ShapeUtils::ComputeInsetRadii(const StyleBasicShape* aBasicShape,
}
/* static */ nsTArray<nsPoint>
ShapeUtils::ComputePolygonVertices(const StyleBasicShape* aBasicShape,
ShapeUtils::ComputePolygonVertices(const UniquePtr<StyleBasicShape>& aBasicShape,
const nsRect& aRefBox)
{
MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Polygon,

View File

@ -36,7 +36,7 @@ struct ShapeUtils final
// @param aRefBox The reference box of the basic shape.
// @return The point of the center.
static nsPoint ComputeCircleOrEllipseCenter(
const StyleBasicShape* aBasicShape,
const UniquePtr<StyleBasicShape>& aBasicShape,
const nsRect& aRefBox);
// Compute the radius for a circle.
@ -44,7 +44,7 @@ struct ShapeUtils final
// @param aRefBox the reference box of the circle.
// @return The length of the radius in app units.
static nscoord ComputeCircleRadius(
const StyleBasicShape* aBasicShape,
const UniquePtr<StyleBasicShape>& aBasicShape,
const nsPoint& aCenter, const nsRect& aRefBox);
// Compute the radii for an ellipse.
@ -53,14 +53,14 @@ struct ShapeUtils final
// @return The radii of the ellipse in app units. The width and height
// represent the x-axis and y-axis radii of the ellipse.
static nsSize ComputeEllipseRadii(
const StyleBasicShape* aBasicShape,
const UniquePtr<StyleBasicShape>& aBasicShape,
const nsPoint& aCenter, const nsRect& aRefBox);
// Compute the rect for an inset.
// @param aRefBox the reference box of the inset.
// @return The inset rect in app units.
static nsRect ComputeInsetRect(
const StyleBasicShape* aBasicShape,
const UniquePtr<StyleBasicShape>& aBasicShape,
const nsRect& aRefBox);
// Compute the radii for an inset.
@ -69,7 +69,7 @@ struct ShapeUtils final
// @param aRadii the returned radii in app units.
// @return true if any of the radii is nonzero; false otherwise.
static bool ComputeInsetRadii(
const StyleBasicShape* aBasicShape,
const UniquePtr<StyleBasicShape>& aBasicShape,
const nsRect& aInsetRect,
const nsRect& aRefBox,
nscoord aRadii[8]);
@ -79,7 +79,7 @@ struct ShapeUtils final
// @return The vertices in app units; the coordinate space is the same
// as aRefBox.
static nsTArray<nsPoint> ComputePolygonVertices(
const StyleBasicShape* aBasicShape,
const UniquePtr<StyleBasicShape>& aBasicShape,
const nsRect& aRefBox);
};

View File

@ -160,19 +160,6 @@ public:
size_t oldLength = glyphs.Length();
glyphs.SetLength(oldLength + aBuffer.mNumGlyphs);
PodCopy(glyphs.Elements() + oldLength, aBuffer.mGlyphs, aBuffer.mNumGlyphs);
// If there's a skew for synthetic italics we need to apply it, as the font
// code applies the inverse transformation to glyph positions in anticipation.
Matrix trans = GetTransform();
if (trans._21 != 0) {
Matrix skew = Matrix(1, trans._12,
trans._21, 1,
0, 0);
for (size_t i = oldLength; i < oldLength + aBuffer.mNumGlyphs; ++i) {
auto position = &glyphs[i].mPosition;
*position = skew.TransformPoint(*position);
}
}
}
void

View File

@ -774,7 +774,7 @@ nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame,
mShapeInfo = ShapeInfo::CreateShapeBox(mFrame, shapeBoxRect, aWM,
aContainerSize);
} else if (shapeOutside.GetType() == StyleShapeSourceType::Shape) {
StyleBasicShape* const basicShape = shapeOutside.GetBasicShape();
const UniquePtr<StyleBasicShape>& basicShape = shapeOutside.GetBasicShape();
switch (basicShape->GetShapeType()) {
case StyleBasicShapeType::Polygon:
@ -961,7 +961,7 @@ nsFloatManager::ShapeInfo::CreateShapeBox(
/* static */ UniquePtr<nsFloatManager::ShapeInfo>
nsFloatManager::ShapeInfo::CreateInset(
const StyleBasicShape* aBasicShape,
const UniquePtr<StyleBasicShape>& aBasicShape,
const LogicalRect& aShapeBoxRect,
WritingMode aWM,
const nsSize& aContainerSize)
@ -993,7 +993,7 @@ nsFloatManager::ShapeInfo::CreateInset(
/* static */ UniquePtr<nsFloatManager::ShapeInfo>
nsFloatManager::ShapeInfo::CreateCircleOrEllipse(
const StyleBasicShape* aBasicShape,
const UniquePtr<StyleBasicShape>& aBasicShape,
const LogicalRect& aShapeBoxRect,
WritingMode aWM,
const nsSize& aContainerSize)
@ -1029,7 +1029,7 @@ nsFloatManager::ShapeInfo::CreateCircleOrEllipse(
/* static */ UniquePtr<nsFloatManager::ShapeInfo>
nsFloatManager::ShapeInfo::CreatePolygon(
const StyleBasicShape* aBasicShape,
const UniquePtr<StyleBasicShape>& aBasicShape,
const LogicalRect& aShapeBoxRect,
WritingMode aWM,
const nsSize& aContainerSize)

View File

@ -382,19 +382,19 @@ private:
const nsSize& aContainerSize);
static mozilla::UniquePtr<ShapeInfo> CreateInset(
const mozilla::StyleBasicShape* aBasicShape,
const mozilla::UniquePtr<mozilla::StyleBasicShape>& aBasicShape,
const mozilla::LogicalRect& aShapeBoxRect,
mozilla::WritingMode aWM,
const nsSize& aContainerSize);
static mozilla::UniquePtr<ShapeInfo> CreateCircleOrEllipse(
const mozilla::StyleBasicShape* aBasicShape,
const mozilla::UniquePtr<mozilla::StyleBasicShape>& aBasicShape,
const mozilla::LogicalRect& aShapeBoxRect,
mozilla::WritingMode aWM,
const nsSize& aContainerSize);
static mozilla::UniquePtr<ShapeInfo> CreatePolygon(
const mozilla::StyleBasicShape* aBasicShape,
const mozilla::UniquePtr<mozilla::StyleBasicShape>& aBasicShape,
const mozilla::LogicalRect& aShapeBoxRect,
mozilla::WritingMode aWM,
const nsSize& aContainerSize);

View File

@ -9,7 +9,7 @@
== unit-vh-vw.html unit-vh-vw-ref.html
== unit-vh-vw-zoom.html unit-vh-vw-zoom-ref.html
== unit-vh-vw-overflow-auto.html unit-vh-vw-overflow-auto-ref.html
fails-if(styloVsGecko||stylo) == unit-vh-vw-overflow-scroll.html unit-vh-vw-overflow-scroll-ref.html
fails-if(styloVsGecko||stylo) == unit-vh-vw-overflow-scroll-x.html unit-vh-vw-overflow-scroll-x-ref.html
fails-if(styloVsGecko||stylo) == unit-vh-vw-overflow-scroll-y.html unit-vh-vw-overflow-scroll-y-ref.html
fails-if(!Android&&(styloVsGecko||stylo)) == unit-vh-vw-overflow-scroll.html unit-vh-vw-overflow-scroll-ref.html
fails-if(!Android&&(styloVsGecko||stylo)) == unit-vh-vw-overflow-scroll-x.html unit-vh-vw-overflow-scroll-x-ref.html
fails-if(!Android&&(styloVsGecko||stylo)) == unit-vh-vw-overflow-scroll-y.html unit-vh-vw-overflow-scroll-y-ref.html
skip-if(Android) fails-if(stylo) != unit-vh-vw-overflow-auto.html unit-vh-vw-overflow-scroll.html

View File

@ -0,0 +1 @@
<input type="checkbox" style="top:58px; position:absolute">

View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<meta charset="utf-8">
<title>Test clamping width/height of checkbox.</title>
<link rel="author" title="Louis Chang" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1400050">
<link rel="match" href="checkbox-clamp-ref.html">
</head>
<body>
<input type="checkbox" style="height:113px">
</body>
</html>

View File

@ -15,3 +15,4 @@ skip-if(!gtkWidget) == gtk-theme-width-height.html gtk-theme-width-height-ref.ht
== checkbox-baseline.html checkbox-baseline-ref.html
== checkbox-radio-color.html checkbox-radio-color-ref.html
skip-if(OSX) == checkbox-radio-auto-sized.html checkbox-radio-auto-sized-ref.html
fails-if(gtkWidget) == checkbox-clamp.html checkbox-clamp-ref.html

View File

@ -0,0 +1 @@
<input type="radio" style="top:58px; position:absolute">

View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<meta charset="utf-8">
<title>Test clamping width/height of radio.</title>
<link rel="author" title="Louis Chang" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1400050">
<link rel="match" href="radio-clamp-ref.html">
</head>
<body>
<input type="radio" style="height:113px">
</body>
</html>

View File

@ -5,3 +5,4 @@
!= checked-native.html about:blank
!= checked-native-notref.html about:blank
skip-if(!gtkWidget) == gtk-theme-width-height.html gtk-theme-width-height-ref.html
fails-if(gtkWidget) == radio-clamp.html radio-clamp-ref.html

View File

@ -9,7 +9,7 @@ pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == fallback-c
pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == remove-insertion-point-1.html remove-insertion-point-1-ref.html
pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == nested-insertion-point-1.html nested-insertion-point-1-ref.html
pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == update-dist-node-descendants-1.html update-dist-node-descendants-1-ref.html
pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) fuzzy-if(Android,2,7) == input-transition-1.html input-transition-1-ref.html
pref(dom.webcomponents.enabled,true) fuzzy-if(Android,2,7) fails-if(stylo||styloVsGecko) == input-transition-1.html input-transition-1-ref.html
pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == dynamic-insertion-point-distribution-1.html dynamic-insertion-point-distribution-1-ref.html
pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == dynamic-insertion-point-distribution-2.html dynamic-insertion-point-distribution-2-ref.html
pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == remove-append-shadow-host-1.html remove-append-shadow-host-1-ref.html

View File

@ -16,6 +16,7 @@
#include "mozilla/dom/FontFaceSetLoadEvent.h"
#include "mozilla/dom/FontFaceSetLoadEventBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/net/ReferrerPolicy.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
@ -1100,6 +1101,7 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
face->mSourceType = gfxFontFaceSrc::eSourceType_Buffer;
face->mBuffer = aFontFace->CreateBufferSource();
face->mReferrerPolicy = mozilla::net::RP_Unset;
} else {
aFontFace->GetDesc(eCSSFontDesc_Src, val);
unit = val.GetUnit();
@ -1121,6 +1123,7 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
face->mSourceType = gfxFontFaceSrc::eSourceType_Local;
face->mURI = nullptr;
face->mFormatFlags = 0;
face->mReferrerPolicy = mozilla::net::RP_Unset;
break;
case eCSSUnit_URL: {
face->mSourceType = gfxFontFaceSrc::eSourceType_URL;

View File

@ -1993,11 +1993,12 @@ Gecko_StyleShapeSource_SetURLValue(mozilla::StyleShapeSource* aShape, ServoBundl
aShape->SetURL(url.get());
}
mozilla::StyleBasicShape*
Gecko_NewBasicShape(mozilla::StyleBasicShapeType aType)
void
Gecko_NewBasicShape(mozilla::StyleShapeSource* aShape,
mozilla::StyleBasicShapeType aType)
{
RefPtr<StyleBasicShape> ptr = new mozilla::StyleBasicShape(aType);
return ptr.forget().take();
aShape->SetBasicShape(MakeUnique<mozilla::StyleBasicShape>(aType),
StyleGeometryBox::NoBox);
}
void

View File

@ -504,7 +504,8 @@ void Gecko_SetStyleCoordCalcValue(nsStyleUnit* unit, nsStyleUnion* value, nsStyl
void Gecko_CopyShapeSourceFrom(mozilla::StyleShapeSource* dst, const mozilla::StyleShapeSource* src);
void Gecko_DestroyShapeSource(mozilla::StyleShapeSource* shape);
mozilla::StyleBasicShape* Gecko_NewBasicShape(mozilla::StyleBasicShapeType type);
void Gecko_NewBasicShape(mozilla::StyleShapeSource* shape,
mozilla::StyleBasicShapeType type);
void Gecko_StyleShapeSource_SetURLValue(mozilla::StyleShapeSource* shape, ServoBundledURI uri);
void Gecko_ResetFilters(nsStyleEffects* effects, size_t new_len);

View File

@ -287,7 +287,6 @@ whitelist-types = [
"SheetParsingMode",
"StaticRefPtr",
"StyleAnimation",
"StyleBasicShape",
"StyleBasicShapeType",
"StyleGeometryBox",
"StyleShapeSource",
@ -442,7 +441,6 @@ structs-types = [
"ServoElementSnapshotTable",
"ServoStyleSetSizes",
"SheetParsingMode",
"StyleBasicShape",
"StyleBasicShapeType",
"StyleShapeSource",
"StyleTransition",

View File

@ -4158,7 +4158,7 @@ StyleShapeSourceToCSSArray(const StyleShapeSource& aShapeSource,
MOZ_ASSERT(aResult->Count() == 2,
"Expected array to be presized for a function and the sizing-box");
const StyleBasicShape* shape = aShapeSource.GetBasicShape();
const UniquePtr<StyleBasicShape>& shape = aShapeSource.GetBasicShape();
nsCSSKeyword functionName = shape->GetShapeTypeName();
RefPtr<nsCSSValue::Array> functionArray;
switch (shape->GetShapeType()) {

View File

@ -0,0 +1,22 @@
<script>
function jsfuzzer() {
try { htmlvar00016.appendChild(htmlvar00017); } catch(e) { }
try { htmlvar00016.form.setAttribute("novalidate", "novalidate"); } catch(e) { }
try { htmlvar00017.appendChild(htmlvar00036); } catch(e) { }
try { svgvar00007.appendChild(htmlvar00008); } catch(e) { }
}
</script>
<body onload=jsfuzzer()>
<form id="htmlvar00007">
<legend id="htmlvar00008">
<output id="htmlvar00016"></output>
</legend>
<link id="htmlvar00017"></link>
<svg>
<path id="svgvar00006">
<animateTransform id="svgvar00007"/>
</path>
<use xlink:href="#svgvar00006">
<table id="htmlvar00036">
<th>
<output form="htmlvar00007">

View File

@ -239,4 +239,5 @@ load 1403465.html
load 1403592.html
load 1403615.html
load 1403712.html
load 1404180-1.html
load 1404316.html

View File

@ -6356,7 +6356,7 @@ nsComputedDOMStyle::BasicShapeRadiiToString(nsAString& aCssText,
already_AddRefed<CSSValue>
nsComputedDOMStyle::CreatePrimitiveValueForBasicShape(
const StyleBasicShape* aStyleBasicShape)
const UniquePtr<StyleBasicShape>& aStyleBasicShape)
{
MOZ_ASSERT(aStyleBasicShape, "Expect a valid basic shape pointer!");
@ -6437,7 +6437,7 @@ nsComputedDOMStyle::CreatePrimitiveValueForBasicShape(
template<typename ReferenceBox>
already_AddRefed<CSSValue>
nsComputedDOMStyle::CreatePrimitiveValueForShapeSource(
const StyleBasicShape* aStyleBasicShape,
const UniquePtr<StyleBasicShape>& aStyleBasicShape,
ReferenceBox aReferenceBox,
const KTableEntry aBoxKeywordTable[])
{

View File

@ -12,6 +12,7 @@
#include "mozilla/ArenaRefPtrInlines.h"
#include "mozilla/Attributes.h"
#include "mozilla/StyleComplexColor.h"
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h"
#include "nscore.h"
#include "nsCSSProps.h"
@ -703,13 +704,13 @@ private:
template<typename ReferenceBox>
already_AddRefed<CSSValue>
CreatePrimitiveValueForShapeSource(
const mozilla::StyleBasicShape* aStyleBasicShape,
const mozilla::UniquePtr<mozilla::StyleBasicShape>& aStyleBasicShape,
ReferenceBox aReferenceBox,
const KTableEntry aBoxKeywordTable[]);
// Helper function for computing basic shape styles.
already_AddRefed<CSSValue> CreatePrimitiveValueForBasicShape(
const mozilla::StyleBasicShape* aStyleBasicShape);
const mozilla::UniquePtr<mozilla::StyleBasicShape>& aStyleBasicShape);
void BoxValuesToString(nsAString& aString,
const nsTArray<nsStyleCoord>& aBoxValues);
void BasicShapeRadiiToString(nsAString& aCssText,

View File

@ -9795,13 +9795,13 @@ nsRuleNode::ComputeSVGData(void* aStartStruct,
COMPUTE_END_INHERITED(SVG, svg)
}
static already_AddRefed<StyleBasicShape>
static UniquePtr<StyleBasicShape>
GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
GeckoStyleContext* aStyleContext,
nsPresContext* aPresContext,
RuleNodeCacheConditions& aConditions)
{
RefPtr<StyleBasicShape> basicShape;
UniquePtr<StyleBasicShape> basicShape;
nsCSSValue::Array* shapeFunction = aValue.GetArrayValue();
nsCSSKeyword functionName =
@ -9809,7 +9809,7 @@ GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
if (functionName == eCSSKeyword_polygon) {
MOZ_ASSERT(!basicShape, "did not expect value");
basicShape = new StyleBasicShape(StyleBasicShapeType::Polygon);
basicShape = MakeUnique<StyleBasicShape>(StyleBasicShapeType::Polygon);
MOZ_ASSERT(shapeFunction->Count() > 1,
"polygon has wrong number of arguments");
size_t j = 1;
@ -9846,7 +9846,7 @@ GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
StyleBasicShapeType::Circle :
StyleBasicShapeType::Ellipse;
MOZ_ASSERT(!basicShape, "did not expect value");
basicShape = new StyleBasicShape(type);
basicShape = MakeUnique<StyleBasicShape>(type);
const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
SETCOORD_STORE_CALC | SETCOORD_ENUMERATED;
size_t count = type == StyleBasicShapeType::Circle ? 2 : 3;
@ -9882,7 +9882,7 @@ GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
}
} else if (functionName == eCSSKeyword_inset) {
MOZ_ASSERT(!basicShape, "did not expect value");
basicShape = new StyleBasicShape(StyleBasicShapeType::Inset);
basicShape = MakeUnique<StyleBasicShape>(StyleBasicShapeType::Inset);
MOZ_ASSERT(shapeFunction->Count() == 6,
"inset function has wrong number of arguments");
MOZ_ASSERT(shapeFunction->Item(1).GetUnit() != eCSSUnit_Null,
@ -9943,7 +9943,7 @@ GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
NS_NOTREACHED("unexpected basic shape function");
}
return basicShape.forget();
return basicShape;
}
static void
@ -9962,7 +9962,7 @@ SetStyleShapeSourceToCSSValue(
"Expect one or both of a shape function and a reference box");
StyleGeometryBox referenceBox = StyleGeometryBox::NoBox;
RefPtr<StyleBasicShape> basicShape;
UniquePtr<StyleBasicShape> basicShape;
for (size_t i = 0; i < array->Count(); ++i) {
const nsCSSValue& item = array->Item(i);
@ -9978,7 +9978,7 @@ SetStyleShapeSourceToCSSValue(
}
if (basicShape) {
aShapeSource->SetBasicShape(basicShape, referenceBox);
aShapeSource->SetBasicShape(Move(basicShape), referenceBox);
} else {
aShapeSource->SetReferenceBox(referenceBox);
}

View File

@ -1038,6 +1038,97 @@ StyleBasicShape::GetShapeTypeName() const
return eCSSKeyword_UNKNOWN;
}
// --------------------
// StyleShapeSource
StyleShapeSource::StyleShapeSource(const StyleShapeSource& aSource)
{
DoCopy(aSource);
}
StyleShapeSource&
StyleShapeSource::operator=(const StyleShapeSource& aOther)
{
if (this != &aOther) {
DoCopy(aOther);
}
return *this;
}
bool
StyleShapeSource::operator==(const StyleShapeSource& aOther) const
{
if (mType != aOther.mType) {
return false;
}
if (mType == StyleShapeSourceType::URL) {
return DefinitelyEqualURIs(GetURL(), aOther.GetURL());
} else if (mType == StyleShapeSourceType::Shape) {
return *mBasicShape == *aOther.mBasicShape &&
mReferenceBox == aOther.mReferenceBox;
} else if (mType == StyleShapeSourceType::Box) {
return mReferenceBox == aOther.mReferenceBox;
}
return true;
}
bool
StyleShapeSource::SetURL(css::URLValue* aValue)
{
MOZ_ASSERT(aValue);
if (!mShapeImage) {
mShapeImage = MakeUnique<nsStyleImage>();
}
mShapeImage->SetURLValue(do_AddRef(aValue));
mType = StyleShapeSourceType::URL;
return true;
}
void
StyleShapeSource::SetBasicShape(UniquePtr<StyleBasicShape> aBasicShape,
StyleGeometryBox aReferenceBox)
{
NS_ASSERTION(aBasicShape, "expected pointer");
mBasicShape = Move(aBasicShape);
mReferenceBox = aReferenceBox;
mType = StyleShapeSourceType::Shape;
}
void
StyleShapeSource::SetReferenceBox(StyleGeometryBox aReferenceBox)
{
mReferenceBox = aReferenceBox;
mType = StyleShapeSourceType::Box;
}
void
StyleShapeSource::DoCopy(const StyleShapeSource& aOther)
{
switch (aOther.mType) {
case StyleShapeSourceType::None:
mReferenceBox = StyleGeometryBox::NoBox;
mType = StyleShapeSourceType::None;
break;
case StyleShapeSourceType::URL:
SetURL(aOther.GetURL());
break;
case StyleShapeSourceType::Shape:
SetBasicShape(MakeUnique<StyleBasicShape>(*aOther.GetBasicShape()),
aOther.GetReferenceBox());
break;
case StyleShapeSourceType::Box:
SetReferenceBox(aOther.GetReferenceBox());
break;
}
}
// --------------------
// nsStyleFilter
//
@ -1219,7 +1310,7 @@ nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aNewData) const
{
nsChangeHint hint = nsChangeHint(0);
if (!mClipPath.DefinitelyEquals(aNewData.mClipPath)) {
if (mClipPath != aNewData.mClipPath) {
hint |= nsChangeHint_UpdateEffects |
nsChangeHint_RepaintFrame;
// clip-path changes require that we update the PreEffectsBBoxProperty,
@ -3572,7 +3663,7 @@ nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const
hint |= nsChangeHint_ReflowHintsForFloatAreaChange;
}
if (!mShapeOutside.DefinitelyEquals(aNewData.mShapeOutside)) {
if (mShapeOutside != aNewData.mShapeOutside) {
if (aNewData.mFloat != StyleFloat::None) {
// If we are floating, and our shape-outside property changes, our
// descendants are not impacted, but our ancestor and siblings are.

View File

@ -2421,11 +2421,7 @@ public:
return !(*this == aOther);
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StyleBasicShape);
private:
~StyleBasicShape() {}
StyleBasicShapeType mType;
StyleFillRule mFillRule;
@ -2439,78 +2435,19 @@ private:
nsStyleCorners mRadius;
};
struct StyleShapeSource
struct StyleShapeSource final
{
StyleShapeSource()
: mURL(nullptr)
{}
StyleShapeSource() = default;
StyleShapeSource(const StyleShapeSource& aSource)
: StyleShapeSource()
{
if (aSource.mType == StyleShapeSourceType::URL) {
SetURL(aSource.mURL);
} else if (aSource.mType == StyleShapeSourceType::Shape) {
SetBasicShape(aSource.mBasicShape, aSource.mReferenceBox);
} else if (aSource.mType == StyleShapeSourceType::Box) {
SetReferenceBox(aSource.mReferenceBox);
}
}
StyleShapeSource(const StyleShapeSource& aSource);
~StyleShapeSource()
{
ReleaseRef();
}
StyleShapeSource& operator=(const StyleShapeSource& aOther)
{
if (this == &aOther) {
return *this;
}
StyleShapeSource& operator=(const StyleShapeSource& aOther);
if (aOther.mType == StyleShapeSourceType::URL) {
SetURL(aOther.mURL);
} else if (aOther.mType == StyleShapeSourceType::Shape) {
SetBasicShape(aOther.mBasicShape, aOther.mReferenceBox);
} else if (aOther.mType == StyleShapeSourceType::Box) {
SetReferenceBox(aOther.mReferenceBox);
} else {
ReleaseRef();
mReferenceBox = StyleGeometryBox::NoBox;
mType = StyleShapeSourceType::None;
}
return *this;
}
bool operator==(const StyleShapeSource& aOther) const
{
return EqualsInternal<true>(aOther);
}
bool DefinitelyEquals(const StyleShapeSource& aOther) const
{
return EqualsInternal<false>(aOther);
}
template<bool aPrecise>
bool EqualsInternal(const StyleShapeSource& aOther) const
{
if (mType != aOther.mType) {
return false;
}
if (mType == StyleShapeSourceType::URL) {
return aPrecise ? mURL->Equals(*aOther.mURL)
: mURL->DefinitelyEqualURIs(*aOther.mURL);
} else if (mType == StyleShapeSourceType::Shape) {
return *mBasicShape == *aOther.mBasicShape &&
mReferenceBox == aOther.mReferenceBox;
} else if (mType == StyleShapeSourceType::Box) {
return mReferenceBox == aOther.mReferenceBox;
}
return true;
}
bool operator==(const StyleShapeSource& aOther) const;
bool operator!=(const StyleShapeSource& aOther) const
{
@ -2525,35 +2462,21 @@ struct StyleShapeSource
css::URLValue* GetURL() const
{
MOZ_ASSERT(mType == StyleShapeSourceType::URL, "Wrong shape source type!");
return mURL;
return mShapeImage
? static_cast<css::URLValue*>(mShapeImage->GetURLValue())
: nullptr;
}
bool SetURL(css::URLValue* aValue)
{
MOZ_ASSERT(aValue);
ReleaseRef();
mURL = aValue;
mURL->AddRef();
mType = StyleShapeSourceType::URL;
return true;
}
bool SetURL(css::URLValue* aValue);
StyleBasicShape* GetBasicShape() const
const UniquePtr<StyleBasicShape>& GetBasicShape() const
{
MOZ_ASSERT(mType == StyleShapeSourceType::Shape, "Wrong shape source type!");
return mBasicShape;
}
void SetBasicShape(StyleBasicShape* aBasicShape,
StyleGeometryBox aReferenceBox)
{
NS_ASSERTION(aBasicShape, "expected pointer");
ReleaseRef();
mBasicShape = aBasicShape;
mBasicShape->AddRef();
mReferenceBox = aReferenceBox;
mType = StyleShapeSourceType::Shape;
}
void SetBasicShape(UniquePtr<StyleBasicShape> aBasicShape,
StyleGeometryBox aReferenceBox);
StyleGeometryBox GetReferenceBox() const
{
@ -2563,34 +2486,15 @@ struct StyleShapeSource
return mReferenceBox;
}
void SetReferenceBox(StyleGeometryBox aReferenceBox)
{
ReleaseRef();
mReferenceBox = aReferenceBox;
mType = StyleShapeSourceType::Box;
}
void SetReferenceBox(StyleGeometryBox aReferenceBox);
private:
void ReleaseRef()
{
if (mType == StyleShapeSourceType::Shape) {
NS_ASSERTION(mBasicShape, "expected pointer");
mBasicShape->Release();
} else if (mType == StyleShapeSourceType::URL) {
NS_ASSERTION(mURL, "expected pointer");
mURL->Release();
}
// Both mBasicShape and mURL are pointers in a union. Nulling one of them
// nulls both of them.
mURL = nullptr;
}
void* operator new(size_t) = delete;
union {
StyleBasicShape* mBasicShape;
css::URLValue* mURL;
};
void DoCopy(const StyleShapeSource& aOther);
mozilla::UniquePtr<StyleBasicShape> mBasicShape;
mozilla::UniquePtr<nsStyleImage> mShapeImage;
StyleShapeSourceType mType = StyleShapeSourceType::None;
StyleGeometryBox mReferenceBox = StyleGeometryBox::NoBox;
};

View File

@ -87,7 +87,7 @@ nsCSSClipPathInstance::CreateClipPath(DrawTarget* aDrawTarget)
mTargetFrame->PresContext()->AppUnitsPerDevPixel();
r = ToAppUnits(r.ToNearestPixels(appUnitsPerDevPixel), appUnitsPerDevPixel);
StyleBasicShape* basicShape = mClipPathStyle.GetBasicShape();
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
switch (basicShape->GetShapeType()) {
case StyleBasicShapeType::Circle:
return CreateClipPathCircle(aDrawTarget, r);
@ -110,7 +110,7 @@ already_AddRefed<Path>
nsCSSClipPathInstance::CreateClipPathCircle(DrawTarget* aDrawTarget,
const nsRect& aRefBox)
{
StyleBasicShape* basicShape = mClipPathStyle.GetBasicShape();
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
@ -130,7 +130,7 @@ already_AddRefed<Path>
nsCSSClipPathInstance::CreateClipPathEllipse(DrawTarget* aDrawTarget,
const nsRect& aRefBox)
{
StyleBasicShape* basicShape = mClipPathStyle.GetBasicShape();
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
@ -150,7 +150,7 @@ already_AddRefed<Path>
nsCSSClipPathInstance::CreateClipPathPolygon(DrawTarget* aDrawTarget,
const nsRect& aRefBox)
{
StyleBasicShape* basicShape = mClipPathStyle.GetBasicShape();
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
FillRule fillRule = basicShape->GetFillRule() == StyleFillRule::Nonzero ?
FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(fillRule);
@ -176,7 +176,7 @@ already_AddRefed<Path>
nsCSSClipPathInstance::CreateClipPathInset(DrawTarget* aDrawTarget,
const nsRect& aRefBox)
{
StyleBasicShape* basicShape = mClipPathStyle.GetBasicShape();
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();

View File

@ -66,6 +66,10 @@ user_pref("browser.search.geoSpecificDefaults", false);
// Make sure Shield doesn't hit the network.
user_pref("extensions.shield-recipe-client.api_url", "https://localhost/selfsupport-dummy/");
// Make sure Ping Centre doesn't hit the network.
user_pref("browser.ping-centre.staging.endpoint", "https://localhost");
user_pref("browser.ping-centre.production.endpoint", "https://localhost");
// use about:blank, not browser.startup.homepage
user_pref("browser.startup.page", 0);

View File

@ -3318,8 +3318,6 @@ nsTreeBodyFrame::PaintCell(int32_t aRowIndex,
twistyContext->StyleMargin()->GetMargin(twistyMargin);
twistyRect.Inflate(twistyMargin);
aRenderingContext.Save();
const nsStyleBorder* borderStyle = lineContext->StyleBorder();
// Resolve currentcolor values against the treeline context
nscolor color = lineContext->StyleColor()->
@ -3383,8 +3381,6 @@ nsTreeBodyFrame::PaintCell(int32_t aRowIndex,
currentParent = parent;
srcX -= mIndentation;
}
aRenderingContext.Restore();
}
// Always leave space for the twisty.

View File

@ -3625,6 +3625,20 @@ TEST_F(JsepSessionTest, ValidateAnsweredCodecParams)
#endif
}
TEST_F(JsepSessionTest, OfferWithBundleGroupNoTags)
{
AddTracks(*mSessionOff, "audio,video");
AddTracks(*mSessionAns, "audio,video");
std::string offer = CreateOffer();
size_t i = offer.find("a=group:BUNDLE");
offer.insert(i, "a=group:BUNDLE\r\n");
SetLocalOffer(offer, CHECK_SUCCESS);
SetRemoteOffer(offer, CHECK_SUCCESS);
std::string answer(CreateAnswer());
}
static void
Replace(const std::string& toReplace,
const std::string& with,

View File

@ -207,8 +207,7 @@ SdpHelper::GetBundledMids(const Sdp& sdp, BundledMids* bundledMids)
for (SdpGroupAttributeList::Group& group : bundleGroups) {
if (group.tags.empty()) {
SDP_SET_ERROR("Empty BUNDLE group");
return NS_ERROR_INVALID_ARG;
continue;
}
const SdpMediaSection* masterBundleMsection(

View File

@ -523,7 +523,6 @@ SessionStore.prototype = {
}
break;
}
case "change":
case "input":
case "DOMAutoComplete": {
let browser = aEvent.currentTarget;
@ -631,7 +630,6 @@ SessionStore.prototype = {
aBrowser.addEventListener("AboutReaderContentReady", this, true);
// Use a combination of events to watch for text data changes
aBrowser.addEventListener("change", this, true);
aBrowser.addEventListener("input", this, true);
aBrowser.addEventListener("DOMAutoComplete", this, true);
@ -660,7 +658,6 @@ SessionStore.prototype = {
aBrowser.removeEventListener("load", this, true);
aBrowser.removeEventListener("pageshow", this, true);
aBrowser.removeEventListener("AboutReaderContentReady", this, true);
aBrowser.removeEventListener("change", this, true);
aBrowser.removeEventListener("input", this, true);
aBrowser.removeEventListener("DOMAutoComplete", this, true);
aBrowser.removeEventListener("scroll", this, true);

View File

@ -112,6 +112,10 @@ class Repository(object):
def name(self):
"""Name of the tool."""
@abc.abstractproperty
def head_ref(self):
"""Hash of HEAD revision."""
@abc.abstractmethod
def sparse_checkout_present(self):
"""Whether the working directory is using a sparse checkout.
@ -204,6 +208,10 @@ class HgRepository(Repository):
def name(self):
return 'hg'
@property
def head_ref(self):
return self._run('log', '-r', '.', '-T', '{node}')
def __enter__(self):
if self._client.server is None:
# The cwd if the spawned process should be the repo root to ensure
@ -313,6 +321,10 @@ class GitRepository(Repository):
def name(self):
return 'git'
@property
def head_ref(self):
return self._run('rev-parse', 'HEAD')
def sparse_checkout_present(self):
# Not yet implemented.
return False

View File

@ -314,8 +314,7 @@ static const char contentSandboxRules[] = R"(
(iokit-user-client-class "IOSurfaceSendRight")
(iokit-user-client-class "IOFramebufferSharedUserClient")
(iokit-user-client-class "AGPMClient")
(iokit-user-client-class "AppleGraphicsControlClient")
(iokit-user-client-class "AppleGraphicsPolicyClient"))
(iokit-user-client-class "AppleGraphicsControlClient"))
; bug 1153809
(allow iokit-open

View File

@ -50,8 +50,8 @@ use std::sync::Arc;
use style::computed_values::{background_attachment, background_clip, background_origin};
use style::computed_values::{background_repeat, border_style, cursor};
use style::computed_values::{image_rendering, overflow_x, pointer_events, position, visibility};
use style::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
use style::properties::{self, ComputedValues};
use style::logical_geometry::{LogicalMargin, LogicalPoint, LogicalRect, LogicalSize, WritingMode};
use style::properties::ComputedValues;
use style::properties::longhands::border_image_repeat::computed_value::RepeatKeyword;
use style::properties::style_structs;
use style::servo::restyle_damage::REPAINT;
@ -138,12 +138,16 @@ fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
&arr[index % arr.len()]
}
pub struct InlineNodeBorderInfo {
is_first_fragment_of_element: bool,
is_last_fragment_of_element: bool,
}
#[derive(Debug)]
struct StackingContextInfo {
children: Vec<StackingContext>,
clip_scroll_nodes: Vec<ClipScrollNode>,
}
impl StackingContextInfo {
fn new() -> StackingContextInfo {
StackingContextInfo {
@ -503,13 +507,15 @@ pub trait FragmentDisplayListBuilding {
/// Adds the display items necessary to paint the borders of this fragment to a display list if
/// necessary.
fn build_display_list_for_borders_if_applicable(
&self,
state: &mut DisplayListBuildState,
style: &ComputedValues,
border_painting_mode: BorderPaintingMode,
bounds: &Rect<Au>,
display_list_section: DisplayListSection,
clip: &Rect<Au>);
&self,
state: &mut DisplayListBuildState,
style: &ComputedValues,
inline_node_info: Option<InlineNodeBorderInfo>,
border_painting_mode: BorderPaintingMode,
bounds: &Rect<Au>,
display_list_section: DisplayListSection,
clip: &Rect<Au>,
);
/// Adds the display items necessary to paint the outline of this fragment to the display list
/// if necessary.
@ -1488,15 +1494,21 @@ impl FragmentDisplayListBuilding for Fragment {
}
fn build_display_list_for_borders_if_applicable(
&self,
state: &mut DisplayListBuildState,
style: &ComputedValues,
border_painting_mode: BorderPaintingMode,
bounds: &Rect<Au>,
display_list_section: DisplayListSection,
clip: &Rect<Au>) {
&self,
state: &mut DisplayListBuildState,
style: &ComputedValues,
inline_info: Option<InlineNodeBorderInfo>,
border_painting_mode: BorderPaintingMode,
bounds: &Rect<Au>,
display_list_section: DisplayListSection,
clip: &Rect<Au>
) {
let mut border = style.logical_border_width();
if let Some(inline_info) = inline_info {
modify_border_width_for_inline_sides(&mut border, inline_info);
}
match border_painting_mode {
BorderPaintingMode::Separate => {}
BorderPaintingMode::Collapse(collapsed_borders) => {
@ -1518,6 +1530,7 @@ impl FragmentDisplayListBuilding for Fragment {
border_style_struct.border_right_style,
border_style_struct.border_bottom_style,
border_style_struct.border_left_style);
if let BorderPaintingMode::Collapse(collapsed_borders) = border_painting_mode {
collapsed_borders.adjust_border_colors_and_styles_for_painting(&mut colors,
&mut border_style,
@ -1880,55 +1893,73 @@ impl FragmentDisplayListBuilding for Fragment {
state,
&*node.style,
display_list_section,
&stacking_relative_border_box);
&stacking_relative_border_box,
);
self.build_display_list_for_box_shadow_if_applicable(
state,
&*node.style,
display_list_section,
&stacking_relative_border_box,
clip);
clip,
);
let mut style = node.style.clone();
properties::modify_border_style_for_inline_sides(
&mut style,
node.flags.contains(FIRST_FRAGMENT_OF_ELEMENT),
node.flags.contains(LAST_FRAGMENT_OF_ELEMENT));
self.build_display_list_for_borders_if_applicable(
state,
&*style,
&*node.style,
Some(InlineNodeBorderInfo {
is_first_fragment_of_element: node.flags.contains(FIRST_FRAGMENT_OF_ELEMENT),
is_last_fragment_of_element: node.flags.contains(LAST_FRAGMENT_OF_ELEMENT),
}),
border_painting_mode,
&stacking_relative_border_box,
display_list_section,
clip);
clip,
);
// FIXME(emilio): Why does outline not do the same width
// fixup as border?
self.build_display_list_for_outline_if_applicable(
state,
&*node.style,
&stacking_relative_border_box,
clip);
clip,
);
}
}
if !self.is_scanned_text_fragment() {
self.build_display_list_for_background_if_applicable(state,
&*self.style,
display_list_section,
&stacking_relative_border_box);
self.build_display_list_for_box_shadow_if_applicable(state,
&*self.style,
display_list_section,
&stacking_relative_border_box,
clip);
self.build_display_list_for_borders_if_applicable(state,
&*self.style,
border_painting_mode,
&stacking_relative_border_box,
display_list_section,
clip);
self.build_display_list_for_outline_if_applicable(state,
&*self.style,
&stacking_relative_border_box,
clip);
self.build_display_list_for_background_if_applicable(
state,
&*self.style,
display_list_section,
&stacking_relative_border_box,
);
self.build_display_list_for_box_shadow_if_applicable(
state,
&*self.style,
display_list_section,
&stacking_relative_border_box,
clip,
);
self.build_display_list_for_borders_if_applicable(
state,
&*self.style,
/* inline_node_info = */ None,
border_painting_mode,
&stacking_relative_border_box,
display_list_section,
clip,
);
self.build_display_list_for_outline_if_applicable(
state,
&*self.style,
&stacking_relative_border_box,
clip,
);
}
}
@ -3135,6 +3166,24 @@ fn shadow_bounds(content_rect: &Rect<Au>, blur: Au, spread: Au) -> Rect<Au> {
content_rect.inflate(inflation, inflation)
}
/// Adjusts borders as appropriate to account for a fragment's status as the
/// first or last fragment within the range of an element.
///
/// Specifically, this function sets border widths to zero on the sides for
/// which the fragment is not outermost.
fn modify_border_width_for_inline_sides(
border_width: &mut LogicalMargin<Au>,
inline_border_info: InlineNodeBorderInfo,
) {
if !inline_border_info.is_first_fragment_of_element {
border_width.inline_start = Au(0);
}
if !inline_border_info.is_last_fragment_of_element {
border_width.inline_end = Au(0);
}
}
/// Allows a CSS color to be converted into a graphics color.
pub trait ToGfxColor {
/// Converts a CSS color to a graphics color.

View File

@ -617,13 +617,14 @@ pub mod basic_shape {
StyleShapeSourceType::Box => ShapeSource::Box(other.mReferenceBox.into()),
StyleShapeSourceType::URL => {
unsafe {
let other_url = &(**other.__bindgen_anon_1.mURL.as_ref());
let shape_image = &*other.mShapeImage.mPtr;
let other_url = &(**shape_image.__bindgen_anon_1.mURLValue.as_ref());
let url = SpecifiedUrl::from_url_value_data(&other_url._base).unwrap();
ShapeSource::Url(url)
}
},
StyleShapeSourceType::Shape => {
let other_shape = unsafe { &(**other.__bindgen_anon_1.mBasicShape.as_ref()) };
let other_shape = unsafe { &*other.mBasicShape.mPtr };
let shape = other_shape.into();
let reference_box = if other.mReferenceBox == StyleGeometryBox::NoBox {
None

View File

@ -4074,6 +4074,8 @@ cfg_if! {
pub static nsGkAtoms_http: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms5httpsE"]
pub static nsGkAtoms_https: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms5proxyE"]
pub static nsGkAtoms_proxy: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms12cdataTagNameE"]
pub static nsGkAtoms_cdataTagName: *mut nsIAtom;
#[link_name = "_ZN9nsGkAtoms14commentTagNameE"]
@ -9239,6 +9241,8 @@ cfg_if! {
pub static nsGkAtoms_http: *mut nsIAtom;
#[link_name = "?https@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_https: *mut nsIAtom;
#[link_name = "?proxy@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_proxy: *mut nsIAtom;
#[link_name = "?cdataTagName@nsGkAtoms@@2PEAVnsIAtom@@EA"]
pub static nsGkAtoms_cdataTagName: *mut nsIAtom;
#[link_name = "?commentTagName@nsGkAtoms@@2PEAVnsIAtom@@EA"]
@ -14404,6 +14408,8 @@ cfg_if! {
pub static nsGkAtoms_http: *mut nsIAtom;
#[link_name = "\x01?https@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_https: *mut nsIAtom;
#[link_name = "\x01?proxy@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_proxy: *mut nsIAtom;
#[link_name = "\x01?cdataTagName@nsGkAtoms@@2PAVnsIAtom@@A"]
pub static nsGkAtoms_cdataTagName: *mut nsIAtom;
#[link_name = "\x01?commentTagName@nsGkAtoms@@2PAVnsIAtom@@A"]
@ -19572,6 +19578,8 @@ macro_rules! atom {
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_http as *mut _) } };
("https") =>
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_https as *mut _) } };
("proxy") =>
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_proxy as *mut _) } };
("#cdata-section") =>
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_cdataTagName as *mut _) } };
("#comment") =>

View File

@ -65,7 +65,6 @@ use gecko_bindings::structs::ServoElementSnapshot;
use gecko_bindings::structs::ServoElementSnapshotTable;
use gecko_bindings::structs::ServoStyleSetSizes;
use gecko_bindings::structs::SheetParsingMode;
use gecko_bindings::structs::StyleBasicShape;
use gecko_bindings::structs::StyleBasicShapeType;
use gecko_bindings::structs::StyleShapeSource;
use gecko_bindings::structs::StyleTransition;
@ -1220,8 +1219,8 @@ extern "C" {
pub fn Gecko_DestroyShapeSource(shape: *mut StyleShapeSource);
}
extern "C" {
pub fn Gecko_NewBasicShape(type_: StyleBasicShapeType)
-> *mut StyleBasicShape;
pub fn Gecko_NewBasicShape(shape: *mut StyleShapeSource,
type_: StyleBasicShapeType);
}
extern "C" {
pub fn Gecko_StyleShapeSource_SetURLValue(shape: *mut StyleShapeSource,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4912,17 +4912,13 @@ fn static_assert() {
${ident}.mType = StyleShapeSourceType::Box;
}
ShapeSource::Shape(servo_shape, maybe_box) => {
${ident}.mReferenceBox = maybe_box.map(Into::into)
.unwrap_or(StyleGeometryBox::NoBox);
${ident}.mType = StyleShapeSourceType::Shape;
fn init_shape(${ident}: &mut StyleShapeSource, ty: StyleBasicShapeType) -> &mut StyleBasicShape {
fn init_shape(${ident}: &mut StyleShapeSource, basic_shape_type: StyleBasicShapeType)
-> &mut StyleBasicShape {
unsafe {
// We have to be very careful to avoid a copy here!
let ref mut union = ${ident}.__bindgen_anon_1;
let shape: &mut *mut StyleBasicShape = union.mBasicShape.as_mut();
*shape = Gecko_NewBasicShape(ty);
&mut **shape
// Create StyleBasicShape in StyleShapeSource. mReferenceBox and mType
// will be set manually later.
Gecko_NewBasicShape(${ident}, basic_shape_type);
&mut *${ident}.mBasicShape.mPtr
}
}
match servo_shape {
@ -4984,6 +4980,10 @@ fn static_assert() {
};
}
}
${ident}.mReferenceBox = maybe_box.map(Into::into)
.unwrap_or(StyleGeometryBox::NoBox);
${ident}.mType = StyleShapeSourceType::Shape;
}
}

View File

@ -17,7 +17,6 @@ use smallbitvec::SmallBitVec;
use std::borrow::Cow;
use std::{fmt, mem, ops};
use std::cell::RefCell;
#[cfg(feature = "gecko")] use std::ptr;
#[cfg(feature = "servo")] use cssparser::RGBA;
use cssparser::{CowRcStr, Parser, TokenSerializationType, serialize_identifier};
@ -28,7 +27,7 @@ use context::QuirksMode;
use font_metrics::FontMetricsProvider;
#[cfg(feature = "gecko")] use gecko_bindings::bindings;
#[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
#[cfg(feature = "servo")] use logical_geometry::LogicalMargin;
use logical_geometry::WritingMode;
use media_queries::Device;
use parser::ParserContext;
@ -49,7 +48,6 @@ use values::computed::NonNegativeLength;
use rule_tree::{CascadeLevel, StrongRuleNode};
use self::computed_value_flags::*;
use style_adjuster::StyleAdjuster;
#[cfg(feature = "servo")] use values::specified::BorderStyle;
pub use self::declaration_block::*;
@ -2661,8 +2659,8 @@ impl<'a> StyleBuilder<'a> {
debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some());
#[cfg(feature = "gecko")]
debug_assert!(parent_style.is_none() ||
ptr::eq(parent_style.unwrap(),
parent_style_ignoring_first_line.unwrap()) ||
::std::ptr::eq(parent_style.unwrap(),
parent_style_ignoring_first_line.unwrap()) ||
parent_style.unwrap().pseudo() == Some(PseudoElement::FirstLine));
let reset_style = device.default_computed_values();
let inherited_style = parent_style.unwrap_or(reset_style);
@ -3131,11 +3129,6 @@ pub fn cascade(
rule_cache_conditions: &mut RuleCacheConditions,
) -> Arc<ComputedValues> {
debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some());
#[cfg(feature = "gecko")]
debug_assert!(parent_style.is_none() ||
ptr::eq(parent_style.unwrap(),
parent_style_ignoring_first_line.unwrap()) ||
parent_style.unwrap().pseudo() == Some(PseudoElement::FirstLine));
let empty = SmallBitVec::new();
let iter_declarations = || {
rule_node.self_and_ancestors().flat_map(|node| {
@ -3219,8 +3212,8 @@ where
debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some());
#[cfg(feature = "gecko")]
debug_assert!(parent_style.is_none() ||
ptr::eq(parent_style.unwrap(),
parent_style_ignoring_first_line.unwrap()) ||
::std::ptr::eq(parent_style.unwrap(),
parent_style_ignoring_first_line.unwrap()) ||
parent_style.unwrap().pseudo() == Some(PseudoElement::FirstLine));
let (inherited_style, layout_parent_style) = match parent_style {
Some(parent_style) => {
@ -3567,62 +3560,6 @@ pub fn adjust_border_width(style: &mut StyleBuilder) {
% endfor
}
/// Adjusts borders as appropriate to account for a fragment's status as the
/// first or last fragment within the range of an element.
///
/// Specifically, this function sets border widths to zero on the sides for
/// which the fragment is not outermost.
#[cfg(feature = "servo")]
#[inline]
pub fn modify_border_style_for_inline_sides(style: &mut Arc<ComputedValues>,
is_first_fragment_of_element: bool,
is_last_fragment_of_element: bool) {
fn modify_side(style: &mut Arc<ComputedValues>, side: PhysicalSide) {
{
let border = &style.border;
let current_style = match side {
PhysicalSide::Left => (border.border_left_width, border.border_left_style),
PhysicalSide::Right => (border.border_right_width, border.border_right_style),
PhysicalSide::Top => (border.border_top_width, border.border_top_style),
PhysicalSide::Bottom => (border.border_bottom_width, border.border_bottom_style),
};
if current_style == (NonNegativeLength::zero(), BorderStyle::none) {
return;
}
}
let style = Arc::make_mut(style);
let border = Arc::make_mut(&mut style.border);
match side {
PhysicalSide::Left => {
border.border_left_width = NonNegativeLength::zero();
border.border_left_style = BorderStyle::none;
}
PhysicalSide::Right => {
border.border_right_width = NonNegativeLength::zero();
border.border_right_style = BorderStyle::none;
}
PhysicalSide::Bottom => {
border.border_bottom_width = NonNegativeLength::zero();
border.border_bottom_style = BorderStyle::none;
}
PhysicalSide::Top => {
border.border_top_width = NonNegativeLength::zero();
border.border_top_style = BorderStyle::none;
}
}
}
if !is_first_fragment_of_element {
let side = style.writing_mode.inline_start_physical_side();
modify_side(style, side)
}
if !is_last_fragment_of_element {
let side = style.writing_mode.inline_end_physical_side();
modify_side(style, side)
}
}
/// An identifier for a given alias property.
#[derive(Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]

View File

@ -13,11 +13,8 @@ use selector_parser::PseudoElement;
use sharing::StyleSharingTarget;
use smallvec::SmallVec;
use style_resolver::{PseudoElementResolution, StyleResolverForElement};
#[cfg(feature = "servo")] use style_traits::ToCss;
use stylist::RuleInclusion;
use traversal_flags::{TraversalFlags, self};
#[cfg(feature = "servo")] use values::Either;
#[cfg(feature = "servo")] use values::generics::image::Image;
/// A per-traversal-level chunk of data. This is sent down by the traversal, and
/// currently only holds the dom depth for the bloom filter.
@ -783,6 +780,10 @@ fn notify_paint_worklet<E>(context: &StyleContext<E>, data: &ElementData)
where
E: TElement,
{
use style_traits::ToCss;
use values::Either;
use values::generics::image::Image;
// We speculatively evaluate any paint worklets during styling.
// This allows us to run paint worklets in parallel with style and layout.
// Note that this is wasted effort if the size of the node has

Some files were not shown because too many files have changed in this diff Show More