Merge autoland to mozilla-central a=merge

This commit is contained in:
arthur.iakab 2019-03-08 06:38:18 +02:00
commit 6ac3e940d9
87 changed files with 1617 additions and 1198 deletions

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<blocklist lastupdate="1551250023025" xmlns="http://www.mozilla.org/2006/addons-blocklist">
<blocklist lastupdate="1551794995188" xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem blockID="i334" id="{0F827075-B026-42F3-885D-98981EE7B1AE}">
<prefs/>
@ -2532,6 +2532,30 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="01825fea-8c5c-4d76-bd06-e1019c188056" id="{ba74c7ee-32b1-11e9-ade5-1f2222a4f325}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="1d596a69-157f-4743-9465-f86d6452206b" id="Youtube-downloader@Myaddons.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="a30f9f2a-aa68-48b7-88cc-8a582405b385" id="Youtube-video@Myaddons.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="77a32be3-94ce-49c2-b129-fa2562a7f47b" id="/^((\{6745ccb4-833d-497e-b582-d98a5e790e8c\})|(\{cd205ddb-b106-4d2a-a965-5d1c610b5072\})|(\{218ec82e-2839-42da-acaa-e527454f4237\})|(\{7af25a3d-1caf-49f8-8be9-8ae6065db7c5\}))$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="7718be46-8e84-4bc7-a5a9-4c5de18378ee" id="/^((\{5084f455-bc8f-483c-b145-91245bcbfd64\})|(\{bd69d5d0-4b2f-48cb-bab5-dcf1e0f9c63b\}))$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="aca80fb4-760e-4cd4-9fec-649fb38b2947" id="/^((\{ee2d725e-9726-43ac-8040-60ce9ff2831b\})|(\{55417a80-e6f7-4d77-8d73-f59045e5e890\}))$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
</emItems>
<pluginItems>
<pluginItem blockID="p332">

View file

@ -16,7 +16,7 @@ var global = this;
XPCOMUtils.defineLazyModuleGetters(this, {
ContentMetaHandler: "resource:///modules/ContentMetaHandler.jsm",
LoginFormFactory: "resource://gre/modules/LoginManagerContent.jsm",
LoginFormFactory: "resource://gre/modules/LoginFormFactory.jsm",
InsecurePasswordUtils: "resource://gre/modules/InsecurePasswordUtils.jsm",
ContextMenuChild: "resource:///actors/ContextMenuChild.jsm",
});

View file

@ -259,7 +259,7 @@ tags = fullscreen
skip-if = toolkit == "gtk3" || verify # disabled on Linux due to bug 513558
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_contextmenu_input.js]
skip-if = toolkit == "gtk3" # disabled on Linux due to bug 513558
skip-if = toolkit == "gtk3" || (os == "win" && processor == "aarch64") # disabled on Linux due to bug 513558, aarch64 due to 1533161
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_ctrlTab.js]
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.

View file

@ -199,6 +199,9 @@ const ignorableWhitelist = new Set([
// Bug 1351669 - obsolete test file
"resource://gre/res/test.properties",
// Bug 1532703
"resource://app/localization/en-US/browser/aboutConfig.ftl",
]);
for (let entry of ignorableWhitelist) {
whitelist.add(entry);

View file

@ -200,8 +200,7 @@
</rows>
</grid>
<separator class="thin"/>
<hbox flex="1">
<spacer flex="1"/>
<hbox pack="end">
<hbox align="center" pack="end">
<label data-l10n-id="fonts-minsize" control="minSize"/>
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->

View file

@ -1657,8 +1657,7 @@ var gMainPane = {
this.selectedHandlerListItem = null;
// Clear the list of entries.
while (this._list.childNodes.length > 1)
this._list.removeChild(this._list.lastChild);
this._list.textContent = "";
var visibleTypes = this._visibleTypes;

View file

@ -249,6 +249,17 @@
margin-top: 10px;
}
#cfr-notification-feature-steps li {
padding-inline-start: 8px;
position: relative;
}
#cfr-notification-feature-steps li:before {
content: "\2022";
position: absolute;
inset-inline-start: 0;
}
#cfr-notification-footer-text,
#cfr-notification-footer-users,
#cfr-notification-footer-learn-more-link {

View file

@ -562,7 +562,7 @@
}
.request-list-item:not(.selected):hover {
background-color: var(--theme-selection-background-hover);
background-color: var(--table-selection-background-hover);
}
.request-list-item:not(.selected).fromCache > .requests-list-column:not(.requests-list-waterfall) {

View file

@ -6,6 +6,7 @@
--table-text-color: var(--grey-40);
--table-splitter-color: rgba(255,255,255,0.15);
--table-zebra-background: rgba(255,255,255,0.05);
--table-selection-background-hover: rgba(53, 59, 72, 1);
--timing-blocked-color: rgba(235, 83, 104, 0.8);
--timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */
@ -21,7 +22,8 @@
--table-text-color: var(--grey-70);
--table-splitter-color: rgba(0,0,0,0.15);
--table-zebra-background: rgba(0,0,0,0.05);
--table-zebra-background: rgba(247, 247, 247, 0.8);
--table-selection-background-hover: rgba(209, 232, 255, 0.8);
--timing-blocked-color: rgba(235, 83, 104, 0.8);
--timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */

View file

@ -60,7 +60,7 @@ add_task(async function() {
function testResponse(type) {
switch (type) {
case "br": {
is(document.querySelector(".CodeMirror-line").textContent, "X".repeat(64),
is(getCodeMirrorValue(monitor), "X".repeat(64),
"The text shown in the source editor is incorrect for the brotli request.");
break;
}

View file

@ -183,7 +183,7 @@ add_task(async function() {
is(values[0].textContent, queryStringParamValue,
"The first query string param value was incorrect.");
ok(tabpanel.querySelector(".CodeMirror-code").textContent.includes(requestPayload),
ok(getCodeMirrorValue(monitor).includes(requestPayload),
"The text shown in the source editor is incorrect.");
if (isJSON) {

View file

@ -185,7 +185,7 @@ add_task(async function() {
case "xml": {
checkVisibility("textarea");
const text = document.querySelector(".CodeMirror-line").textContent;
const text = getCodeMirrorValue(monitor);
is(text, "<label value='greeting'>Hello XML!</label>",
"The text shown in the source editor is incorrect for the xml request.");
@ -194,7 +194,7 @@ add_task(async function() {
case "css": {
checkVisibility("textarea");
const text = document.querySelector(".CodeMirror-line").textContent;
const text = getCodeMirrorValue(monitor);
is(text, "body:pre { content: 'Hello CSS!' }",
"The text shown in the source editor is incorrect for the css request.");
@ -203,7 +203,7 @@ add_task(async function() {
case "js": {
checkVisibility("textarea");
const text = document.querySelector(".CodeMirror-line").textContent;
const text = getCodeMirrorValue(monitor);
is(text, "function() { return 'Hello JS!'; }",
"The text shown in the source editor is incorrect for the js request.");
@ -235,7 +235,7 @@ add_task(async function() {
case "html": {
checkVisibility("textarea");
const text = document.querySelector(".CodeMirror-line").textContent;
const text = getCodeMirrorValue(monitor);
is(text, "<blink>Not Found</blink>",
"The text shown in the source editor is incorrect for the html request.");
@ -258,7 +258,7 @@ add_task(async function() {
case "gzip": {
checkVisibility("textarea");
const text = document.querySelector(".CodeMirror-line").textContent;
const text = getCodeMirrorValue(monitor);
is(text, new Array(1000).join("Hello gzip!"),
"The text shown in the source editor is incorrect for the gzip request.");

View file

@ -49,9 +49,8 @@ add_task(async function() {
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector("#response-tab"));
await wait;
const text = document.querySelector(".CodeMirror-line").textContent;
ok(text.includes("\u0411\u0440\u0430\u0442\u0430\u043d"),
ok(getCodeMirrorValue(monitor).includes("\u0411\u0440\u0430\u0442\u0430\u043d"),
"The text shown in the source editor is correct.");
return teardown(monitor);

View file

@ -67,8 +67,7 @@ add_task(async function() {
is(tabpanel.querySelector(".response-image-box") === null, true,
"The response image box doesn't have the intended visibility.");
is(document.querySelector(".CodeMirror-line").textContent,
"{ \"greeting\": \"Hello malformed JSON!\" },",
is(getCodeMirrorValue(monitor), "{ \"greeting\": \"Hello malformed JSON!\" },",
"The text shown in the source editor is incorrect.");
await teardown(monitor);

View file

@ -55,9 +55,8 @@ add_task(async function() {
document.querySelector("#response-tab"));
await wait;
const text = document.querySelector(".CodeMirror-line").textContent;
ok(text.match(/^<p>/), "The text shown in the source editor is incorrect.");
ok(getCodeMirrorValue(monitor).match(/^<p>/),
"The text shown in the source editor is incorrect.");
await teardown(monitor);

View file

@ -136,13 +136,7 @@ add_task(async function() {
is(labels.length, 3, "There should be 3 param values displayed in this tabpanel.");
// Collect code lines and combine into one text for checking
let text = "";
const lines = [...document.querySelectorAll(".CodeMirror-line")];
lines.forEach((line) => {
text += line.textContent + "\n";
});
const text = getCodeMirrorValue(monitor);
ok(text.includes("Content-Disposition: form-data; name=\"text\""),
"The text shown in the source editor is incorrect (1.1).");

View file

@ -57,7 +57,7 @@ add_task(async function() {
is(labels[0].textContent, "a", "The JSON var name was incorrect.");
is(values[0].textContent, "1", "The JSON var value was incorrect.");
ok(tabpanel.querySelector(".CodeMirror-code").textContent.includes('{"a":1}'),
ok(getCodeMirrorValue(monitor).includes('{"a":1}'),
"The text shown in the source editor is incorrect.");
return teardown(monitor);

View file

@ -75,7 +75,7 @@ add_task(async function() {
return teardown(monitor);
function testEditorContent([ fmt, textRe ]) {
ok(document.querySelector(".CodeMirror-line").textContent.match(textRe),
ok(getCodeMirrorValue(monitor).match(textRe),
"The text shown in the source editor for " + fmt + " is correct.");
}
});

View file

@ -767,6 +767,14 @@ async function performRequests(monitor, tab, count) {
await wait;
}
/**
* Helper function for retrieving `.CodeMirror` content
*/
function getCodeMirrorValue(monitor) {
const document = monitor.panelWin.document;
return document.querySelector(".CodeMirror").CodeMirror.getValue();
}
/**
* Wait for lazy fields to be loaded in a request.
*

View file

@ -162,8 +162,8 @@ JSWindowActorProtocol::FromIPC(const JSWindowActorInfo& aInfo) {
event->mFlags.mCapture = ipc.capture();
event->mFlags.mInSystemGroup = ipc.systemGroup();
event->mFlags.mAllowUntrustedEvents = ipc.allowUntrusted();
if (ipc.hasPassive()) {
event->mPassive.Construct(ipc.passive());
if (ipc.passive()) {
event->mPassive.Construct(ipc.passive().value());
}
}
@ -186,9 +186,8 @@ JSWindowActorInfo JSWindowActorProtocol::ToIPC() {
ipc->capture() = event.mFlags.mCapture;
ipc->systemGroup() = event.mFlags.mInSystemGroup;
ipc->allowUntrusted() = event.mFlags.mAllowUntrustedEvents;
ipc->hasPassive() = event.mPassive.WasPassed();
if (event.mPassive.WasPassed()) {
ipc->passive() = event.mPassive.Value();
ipc->passive() = Some(event.mPassive.Value());
}
}
@ -204,6 +203,7 @@ JSWindowActorProtocol::FromWebIDLOptions(const nsAString& aName,
RefPtr<JSWindowActorProtocol> proto = new JSWindowActorProtocol(aName);
proto->mAllFrames = aOptions.mAllFrames;
proto->mIncludeChrome = aOptions.mIncludeChrome;
proto->mParent.mModuleURI = aOptions.mParent.mModuleURI;
proto->mChild.mModuleURI = aOptions.mChild.mModuleURI;

View file

@ -230,11 +230,7 @@ struct JSWindowActorEventDecl
bool capture;
bool systemGroup;
bool allowUntrusted;
// FIXME(gross): Optional<bool> is a bit gross to encode here, so instead it's
// encoded as two booleans.
bool hasPassive;
bool passive;
bool? passive;
};
struct JSWindowActorInfo

View file

@ -52,6 +52,63 @@ add_task(async function test_getActor() {
});
});
add_task(async function test_getActor_without_allFrames() {
windowActorOptions.allFrames = false;
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
async function(browser) {
ChromeUtils.registerWindowActor("Test", windowActorOptions);
await ContentTask.spawn(
browser, {}, async function() {
// Create and append an iframe into the window's document.
let frame = content.document.createElement("iframe");
content.document.body.appendChild(frame);
is(content.window.frames.length, 1, "There should be an iframe.");
let child = frame.contentWindow.window.getWindowGlobalChild();
Assert.throws(() => child.getActor("Test"),
/NS_ERROR_NOT_AVAILABLE/, "Should throw if allFrames is false.");
});
ChromeUtils.unregisterWindowActor("Test");
});
});
add_task(async function test_getActor_with_allFrames() {
windowActorOptions.allFrames = true;
ChromeUtils.registerWindowActor("Test", windowActorOptions);
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
async function(browser) {
await ContentTask.spawn(
browser, {}, async function() {
// Create and append an iframe into the window's document.
let frame = content.document.createElement("iframe");
content.document.body.appendChild(frame);
is(content.window.frames.length, 1, "There should be an iframe.");
let child = frame.contentWindow.window.getWindowGlobalChild();
let actorChild = child.getActor("Test");
ok(actorChild, "JSWindowActorChild should have value.");
});
});
ChromeUtils.unregisterWindowActor("Test");
});
add_task(async function test_getActor_without_includeChrome() {
windowActorOptions.includeChrome = false;
let parent = window.docShell.browsingContext.currentWindowGlobal;
ChromeUtils.registerWindowActor("Test", windowActorOptions);
SimpleTest.doesThrow(() =>
parent.getActor("Test"),
"Should throw if includeChrome is false.");
ChromeUtils.unregisterWindowActor("Test");
});
add_task(async function test_getActor_with_includeChrome() {
windowActorOptions.includeChrome = true;
ChromeUtils.registerWindowActor("Test", windowActorOptions);
let parent = window.docShell.browsingContext.currentWindowGlobal;
let actorParent = parent.getActor("Test");
ok(actorParent, "JSWindowActorParent should have value.");
ChromeUtils.unregisterWindowActor("Test");
});
add_task(async function test_asyncMessage() {
await BrowserTestUtils.withNewTab({gBrowser, url: URL},
async function(browser) {

View file

@ -1310,7 +1310,8 @@ void WebRenderCommandBuilder::DoGroupingForDisplayList(
CreateOrRecycleWebRenderUserData<WebRenderGroupData>(aWrappingItem);
bool snapped;
nsRect groupBounds = aWrappingItem->GetBounds(aDisplayListBuilder, &snapped);
nsRect groupBounds =
aWrappingItem->GetUntransformedBounds(aDisplayListBuilder, &snapped);
// We don't want to restrict the size of the blob to the building rect of the
// display item, since that will change when we scroll and trigger a resize
// invalidation of the blob (will be fixed by blob recoordination).
@ -1382,12 +1383,15 @@ void WebRenderCommandBuilder::DoGroupingForDisplayList(
group.mImageBounds =
IntRect(0, 0, group.mLayerBounds.width, group.mLayerBounds.height);
group.mClippedImageBounds = group.mImageBounds;
group.mPaintRect =
LayerIntRect::FromUnknownRect(
ScaleToOutsidePixelsOffset(aWrappingItem->GetPaintRect(), scale.width,
scale.height, group.mAppUnitsPerDevPixel,
residualOffset))
.Intersect(group.mLayerBounds);
const nsRect& untransformedPaintRect =
aWrappingItem->GetUntransformedPaintRect();
group.mPaintRect = LayerIntRect::FromUnknownRect(
ScaleToOutsidePixelsOffset(
untransformedPaintRect, scale.width, scale.height,
group.mAppUnitsPerDevPixel, residualOffset))
.Intersect(group.mLayerBounds);
// XXX: Make the paint rect relative to the layer bounds. After we include
// mLayerBounds.TopLeft() in the blob image we want to stop doing this
// adjustment.
@ -1500,8 +1504,7 @@ bool WebRenderCommandBuilder::ShouldDumpDisplayList(
void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
nsDisplayList* aDisplayList, nsDisplayItem* aWrappingItem,
nsDisplayListBuilder* aDisplayListBuilder, const StackingContextHelper& aSc,
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
nsDisplayItem* aOuterItem) {
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources) {
if (mDoGrouping) {
MOZ_RELEASE_ASSERT(
aWrappingItem,
@ -1611,15 +1614,15 @@ void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
// animated geometry root, so we can combine subsequent items of that
// type into the same image.
mContainsSVGGroup = mDoGrouping = true;
if (aOuterItem &&
aOuterItem->GetType() == DisplayItemType::TYPE_TRANSFORM) {
if (aWrappingItem &&
aWrappingItem->GetType() == DisplayItemType::TYPE_TRANSFORM) {
// Inline <svg> should always have an overflow clip, but it gets put
// outside the nsDisplayTransform we create for scaling the svg
// viewport. Converting the clip into inner coordinates lets us
// restrict the size of the blob images and prevents unnecessary
// resizes.
nsDisplayTransform* transform =
static_cast<nsDisplayTransform*>(aOuterItem);
static_cast<nsDisplayTransform*>(aWrappingItem);
nsRect clippedBounds =
transform->GetClippedBounds(aDisplayListBuilder);

View file

@ -95,8 +95,7 @@ class WebRenderCommandBuilder {
nsDisplayList* aDisplayList, nsDisplayItem* aWrappingItem,
nsDisplayListBuilder* aDisplayListBuilder,
const StackingContextHelper& aSc, wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
nsDisplayItem* aOuterItem = nullptr);
wr::IpcResourceUpdateQueue& aResources);
// aWrappingItem has to be non-null.
void DoGroupingForDisplayList(nsDisplayList* aDisplayList,

View file

@ -2460,19 +2460,7 @@ bool BytecodeEmitter::emitInitializeInstanceFields() {
return true;
}
PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
PropOpEmitter::ObjKind::Other);
if (!poe.prepareForObj()) {
return false;
}
// This is guaranteed to run after super(), so we don't need TDZ checks.
if (!emitGetName(cx->names().dotThis)) {
// [stack] THIS
return false;
}
if (!poe.emitGet(cx->names().dotInitializers)) {
if (!emitGetName(cx->names().dotInitializers)) {
// [stack] ARRAY
return false;
}
@ -8020,23 +8008,14 @@ bool BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe,
// code (the initializer) for each field. Upon an object's construction,
// these lambdas will be called, defining the values.
PropOpEmitter poe(this, PropOpEmitter::Kind::SimpleAssignment,
PropOpEmitter::ObjKind::Other);
if (!poe.prepareForObj()) {
return false;
}
if (!emit1(JSOP_DUP)) {
// [stack] CTOR? OBJ OBJ
return false;
}
if (!poe.prepareForRhs()) {
NameOpEmitter noe(this, cx->names().dotInitializers,
NameOpEmitter::Kind::Initialize);
if (!noe.prepareForRhs()) {
return false;
}
if (!emitUint32Operand(JSOP_NEWARRAY, numFields)) {
// [stack] CTOR? OBJ OBJ ARRAY
// [stack] CTOR? OBJ ARRAY
return false;
}
@ -8049,12 +8028,12 @@ bool BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe,
}
if (!emitTree(initializer)) {
// [stack] CTOR? OBJ OBJ ARRAY LAMBDA
// [stack] CTOR? OBJ ARRAY LAMBDA
return false;
}
if (!emitUint32Operand(JSOP_INITELEM_ARRAY, curFieldIndex)) {
// [stack] CTOR? OBJ OBJ ARRAY
// [stack] CTOR? OBJ ARRAY
return false;
}
@ -8062,7 +8041,7 @@ bool BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe,
}
}
if (!poe.emitAssignment(cx->names().dotInitializers)) {
if (!noe.emitAssignment()) {
// [stack] CTOR? OBJ ARRAY
return false;
}

View file

@ -137,6 +137,16 @@ class UsedNameTracker {
MOZ_MUST_USE bool noteUse(JSContext* cx, JSAtom* name, uint32_t scriptId,
uint32_t scopeId);
MOZ_MUST_USE bool markAsAlwaysClosedOver(JSContext* cx, JSAtom* name,
uint32_t scriptId,
uint32_t scopeId) {
// This marks a variable as always closed over:
// UsedNameInfo::noteBoundInScope only checks if scriptId and scopeId are
// greater than the current scriptId/scopeId, so do a simple increment to
// make that so.
return noteUse(cx, name, scriptId + 1, scopeId + 1);
}
struct RewindToken {
private:
friend class UsedNameTracker;

View file

@ -1829,6 +1829,10 @@ GeneralParser<ParseHandler, Unit>::functionBody(InHandling inHandling,
uint32_t startYieldOffset = pc_->lastYieldOffset;
#endif
// One might expect noteUsedName(".initializers") here when parsing a
// constructor. See GeneralParser<ParseHandler, Unit>::classDefinition on why
// it's not here.
Node body;
if (type == StatementListBody) {
bool inheritedStrict = pc_->sc()->strict();
@ -7044,6 +7048,37 @@ GeneralParser<ParseHandler, Unit>::classDefinition(
}
}
if (numFieldsWithInitializers > 0) {
// .initializers is always closed over by the constructor when there are
// fields with initializers. However, there's some strange circumstances
// which prevents us from using the normal noteUsedName() system. We
// cannot call noteUsedName(".initializers") when parsing the constructor,
// because .initializers should be marked as used *only if* there are
// fields with initializers. Even if we haven't seen any fields yet,
// there may be fields after the constructor.
// Consider the following class:
//
// class C {
// constructor() {
// // do we noteUsedName(".initializers") here?
// }
// // ... because there might be some fields down here.
// }
//
// So, instead, at the end of class parsing (where we are now), we do some
// tricks to pretend that noteUsedName(".initializers") was called in the
// constructor.
if (!usedNames_.markAsAlwaysClosedOver(cx_, cx_->names().dotInitializers,
pc_->scriptId(),
pc_->innermostScope()->id())) {
return null();
}
if (!noteDeclaredName(cx_->names().dotInitializers,
DeclarationKind::Const, namePos)) {
return null();
}
}
classEndOffset = pos().end;
if (!finishClassConstructor(classStmt, className, classStartOffset,
classEndOffset, numFieldsWithInitializers,
@ -7161,6 +7196,9 @@ GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
return null();
}
// One might expect a noteUsedName(".initializers") here. See comment in
// GeneralParser<ParseHandler, Unit>::classDefinition on why it's not here.
bool canSkipLazyClosedOverBindings = handler_.canSkipLazyClosedOverBindings();
if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
return null();

View file

@ -0,0 +1,11 @@
(function({
k = class i {
[_ => i]()
{}
}
} = {}) {
var j = 0;
})()
if (typeof reportCompare === "function")
reportCompare(true, true);

View file

@ -3572,8 +3572,6 @@ bool JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script,
// Initialize script flags from BytecodeEmitter
script->setFlag(ImmutableFlags::Strict, bce->sc->strict());
script->setFlag(ImmutableFlags::ExplicitUseStrict,
bce->sc->hasExplicitUseStrict());
script->setFlag(ImmutableFlags::BindingsAccessedDynamically,
bce->sc->bindingsAccessedDynamically());
script->setFlag(ImmutableFlags::HasSingletons, bce->hasSingletons);

View file

@ -1686,8 +1686,7 @@ class JSScript : public js::gc::TenuredCell {
// Code is in strict mode.
Strict = 1 << 1,
// Code has "use strict"; explicitly.
ExplicitUseStrict = 1 << 2,
// (1 << 2) is unused.
// True if the script has a non-syntactic scope on its dynamic scope chain.
// That is, there are objects about which we know nothing between the
@ -2098,10 +2097,6 @@ class JSScript : public js::gc::TenuredCell {
bool strict() const { return hasFlag(ImmutableFlags::Strict); }
bool explicitUseStrict() const {
return hasFlag(ImmutableFlags::ExplicitUseStrict);
}
bool hasNonSyntacticScope() const {
return hasFlag(ImmutableFlags::HasNonSyntacticScope);
}

View file

@ -1,3 +1,6 @@
[test_loader_global_sharing.py]
skip-if = !manage_instance || appname == 'fennec'
[test_preloader_telemetry.py]
skip-if = appname == 'fennec'

View file

@ -27,8 +27,10 @@ class TestScriptPreloader(MarionetteTestCase):
self.assertMuchGreaterThan(misses, child_hits)
profile = self.marionette.profile_path
self.wait_for_file_change(start_time, "{}/startupCache/scriptCache.bin".format(profile))
self.wait_for_file_change(start_time, "{}/startupCache/scriptCache-child.bin".format(profile))
self.wait_for_file_change(start_time,
"{}/startupCache/scriptCache.bin".format(profile))
self.wait_for_file_change(start_time,
"{}/startupCache/scriptCache-child.bin".format(profile))
self.marionette.restart(clean=False, in_app=True)
histogram = self.get_histogram("SCRIPT_PRELOADER_REQUESTS")
misses = histogram.get(LABELS_SCRIPT_PRELOADER_REQUESTS["Miss"], 0)
@ -53,12 +55,11 @@ class TestScriptPreloader(MarionetteTestCase):
if os.stat(path).st_mtime > start_time:
return
if time.time() > expires:
raise Error("Never observed file change for {}".format(path))
raise Exception("Never observed file change for {}".format(path))
time.sleep(1)
except OSError:
pass
def wait_for_observer_notification(self, name):
with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
return self.marionette.execute_script("""

View file

@ -2787,7 +2787,7 @@ bool nsLayoutUtils::GetLayerTransformForFrame(nsIFrame* aFrame,
builder.BeginFrame();
nsDisplayList list;
nsDisplayTransform* item =
MakeDisplayItem<nsDisplayTransform>(&builder, aFrame, &list, nsRect());
MakeDisplayItem<nsDisplayTransform>(&builder, aFrame, &list, nsRect(), 0);
*aTransform = item->GetTransform();
item->Destroy(&builder);

View file

@ -2604,8 +2604,7 @@ static void WrapSeparatorTransform(nsDisplayListBuilder* aBuilder,
}
nsDisplayTransform* item = MakeDisplayItem<nsDisplayTransform>(
aBuilder, aFrame, aNonParticipants, aBuilder->GetVisibleRect(),
Matrix4x4(), aIndex);
aBuilder, aFrame, aNonParticipants, aBuilder->GetVisibleRect(), aIndex);
if (*aSeparator == nullptr) {
*aSeparator = item;
@ -8213,10 +8212,10 @@ nsresult nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos) {
bool movingInFrameDirection =
IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
done = current->PeekOffsetWord(
movingInFrameDirection, wordSelectEatSpace,
aPos->mIsKeyboardSelect, &offset, &state,
aPos->mTrimSpaces) == FOUND;
done =
current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
aPos->mIsKeyboardSelect, &offset, &state,
aPos->mTrimSpaces) == FOUND;
if (!done) {
nsIFrame* nextFrame;
@ -8463,12 +8462,9 @@ nsIFrame::FrameSearchResult nsFrame::PeekOffsetCharacter(
return CONTINUE;
}
nsIFrame::FrameSearchResult nsFrame::PeekOffsetWord(bool aForward,
bool aWordSelectEatSpace,
bool aIsKeyboardSelect,
int32_t* aOffset,
PeekWordState* aState,
bool aTrimSpaces) {
nsIFrame::FrameSearchResult nsFrame::PeekOffsetWord(
bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
int32_t* aOffset, PeekWordState* aState, bool aTrimSpaces) {
NS_ASSERTION(aOffset && *aOffset <= 1, "aOffset out of range");
int32_t startOffset = *aOffset;
// This isn't text, so truncate the context
@ -10522,9 +10518,8 @@ bool nsIFrame::IsStackingContext(const nsStyleDisplay* aStyleDisplay,
ChildrenHavePerspective(aStyleDisplay) ||
aStyleEffects->mMixBlendMode != NS_STYLE_BLEND_NORMAL ||
nsSVGIntegrationUtils::UsingEffectsForFrame(this) ||
(aIsPositioned &&
(aStyleDisplay->IsPositionForcingStackingContext() ||
aStylePosition->mZIndex.IsInteger())) ||
(aIsPositioned && (aStyleDisplay->IsPositionForcingStackingContext() ||
aStylePosition->mZIndex.IsInteger())) ||
(aStyleDisplay->mWillChangeBitField &
NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
aStyleDisplay->mIsolation != NS_STYLE_ISOLATION_AUTO;

View file

@ -546,7 +546,7 @@ void nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
content.AppendToTop(MakeDisplayItem<nsDisplayTransform>(
aBuilder, child, &content, content.GetBuildingRect(),
aBuilder, child, &content, content.GetBuildingRect(), 0,
::ComputePageTransform));
set.Content()->AppendToTop(&content);

View file

@ -725,7 +725,7 @@ void nsSimplePageSequenceFrame::BuildDisplayList(
}
content.AppendToTop(MakeDisplayItem<nsDisplayTransform>(
aBuilder, this, &content, content.GetBuildingRect(),
aBuilder, this, &content, content.GetBuildingRect(), 0,
::ComputePageSequenceTransform));
aLists.Content()->AppendToTop(&content);

View file

@ -3148,12 +3148,14 @@ bool nsDisplayItem::ForceActiveLayers() {
}
static int32_t ZIndexForFrame(nsIFrame* aFrame) {
if (!aFrame->IsAbsPosContainingBlock() && !aFrame->IsFlexOrGridItem())
if (!aFrame->IsAbsPosContainingBlock() && !aFrame->IsFlexOrGridItem()) {
return 0;
}
const nsStylePosition* position = aFrame->StylePosition();
if (position->mZIndex.IsInteger())
if (position->mZIndex.IsInteger()) {
return position->mZIndex.AsInteger();
}
MOZ_ASSERT(position->mZIndex.IsAuto());
// sort the auto and 0 elements together
return 0;
@ -5668,24 +5670,29 @@ bool nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
return retval;
}
static nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList,
const nsRect& aListBounds) {
if (aList->IsOpaque()) {
// Everything within list bounds that's visible is opaque. This is an
// optimization to avoid calculating the opaque region.
return aListBounds;
}
if (aBuilder->HitTestIsForVisibility()) {
// If we care about an accurate opaque region, iterate the display list
// and build up a region of opaque bounds.
return aList->GetOpaqueRegion(aBuilder);
}
return nsRegion();
}
nsRegion nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) const {
*aSnap = false;
nsRegion result;
if (mListPtr->IsOpaque()) {
// Everything within GetBounds that's visible is opaque.
result = GetBounds(aBuilder, aSnap);
} else if (aBuilder->HitTestIsForVisibility()) {
// If we care about an accurate opaque region, iterate the display list
// and build up a region of opaque bounds.
nsDisplayItem* item = mList.GetBottom();
while (item) {
result.OrWith(item->GetOpaqueRegion(aBuilder, aSnap));
item = item->GetAbove();
}
}
*aSnap = false;
return result;
bool snap;
return ::GetOpaqueRegion(aBuilder, GetChildren(), GetBounds(aBuilder, &snap));
}
Maybe<nscolor> nsDisplayWrapList::IsUniform(
@ -5753,11 +5760,7 @@ static LayerState RequiredLayerStateForChildren(
nsRect nsDisplayWrapList::GetComponentAlphaBounds(
nsDisplayListBuilder* aBuilder) const {
nsRect bounds;
for (nsDisplayItem* i = mListPtr->GetBottom(); i; i = i->GetAbove()) {
bounds.UnionRect(bounds, i->GetComponentAlphaBounds(aBuilder));
}
return bounds;
return mListPtr->GetComponentAlphaBounds(aBuilder);
}
void nsDisplayWrapList::SetReferenceFrame(const nsIFrame* aFrame) {
@ -7307,35 +7310,62 @@ already_AddRefed<Layer> nsDisplayAsyncZoom::BuildLayer(
// nsDisplayTransform Implementation
//
// Write #define UNIFIED_CONTINUATIONS here and in
// TransformReferenceBox::Initialize to have the transform property try
// to transform content with continuations as one unified block instead of
// several smaller ones. This is currently disabled because it doesn't work
// correctly, since when the frames are initially being reflowed, their
// continuations all compute their bounding rects independently of each other
// and consequently get the wrong value. Write #define DEBUG_HIT here to have
// the nsDisplayTransform class dump out a bunch of information about hit
// detection.
#undef UNIFIED_CONTINUATIONS
#undef DEBUG_HIT
#ifndef DEBUG
static_assert(sizeof(nsDisplayTransform) < 512, "nsDisplayTransform has grown");
#endif
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
const nsRect& aChildrenBuildingRect,
uint32_t aIndex)
: nsDisplayHitTestInfoItem(aBuilder, aFrame),
mTransform(Some(Matrix4x4())),
mTransformGetter(nullptr),
mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot),
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
mChildrenBuildingRect(aChildrenBuildingRect),
mIndex(aIndex),
mIsTransformSeparator(true),
mAllowAsyncAnimation(false) {
MOZ_COUNT_CTOR(nsDisplayTransform);
MOZ_ASSERT(aFrame, "Must have a frame!");
Init(aBuilder, aList);
}
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
const nsRect& aChildrenBuildingRect,
uint32_t aIndex,
bool aAllowAsyncAnimation)
: nsDisplayHitTestInfoItem(aBuilder, aFrame),
mTransformGetter(nullptr),
mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot),
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
mChildrenBuildingRect(aChildrenBuildingRect),
mIndex(aIndex),
mIsTransformSeparator(false),
mAllowAsyncAnimation(aAllowAsyncAnimation) {
MOZ_COUNT_CTOR(nsDisplayTransform);
MOZ_ASSERT(aFrame, "Must have a frame!");
SetReferenceFrameToAncestor(aBuilder);
Init(aBuilder, aList);
}
nsDisplayTransform::nsDisplayTransform(
nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
const nsRect& aChildrenBuildingRect,
ComputeTransformFunction aTransformGetter, uint32_t aIndex)
const nsRect& aChildrenBuildingRect, uint32_t aIndex,
ComputeTransformFunction aTransformGetter)
: nsDisplayHitTestInfoItem(aBuilder, aFrame),
mStoredList(aBuilder, aFrame, aList),
mTransformGetter(aTransformGetter),
mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot),
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
mChildrenBuildingRect(aChildrenBuildingRect),
mIndex(aIndex),
mIsTransformSeparator(false),
mTransformPreserves3DInited(false),
mAllowAsyncAnimation(false) {
MOZ_COUNT_CTOR(nsDisplayTransform);
MOZ_ASSERT(aFrame, "Must have a frame!");
Init(aBuilder);
Init(aBuilder, aList);
}
void nsDisplayTransform::SetReferenceFrameToAncestor(
@ -7374,55 +7404,11 @@ void nsDisplayTransform::SetReferenceFrameToAncestor(
SetBuildingRect(aBuilder->GetVisibleRect() + mToReferenceFrame);
}
void nsDisplayTransform::Init(nsDisplayListBuilder* aBuilder) {
void nsDisplayTransform::Init(nsDisplayListBuilder* aBuilder,
nsDisplayList* aChildren) {
mShouldFlatten = false;
mHasBounds = false;
mStoredList.SetClipChain(nullptr, true);
mStoredList.SetBuildingRect(mChildrenBuildingRect);
}
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
const nsRect& aChildrenBuildingRect,
uint32_t aIndex,
bool aAllowAsyncAnimation)
: nsDisplayHitTestInfoItem(aBuilder, aFrame),
mStoredList(aBuilder, aFrame, aList),
mTransformGetter(nullptr),
mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot),
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
mChildrenBuildingRect(aChildrenBuildingRect),
mIndex(aIndex),
mIsTransformSeparator(false),
mTransformPreserves3DInited(false),
mAllowAsyncAnimation(aAllowAsyncAnimation) {
MOZ_COUNT_CTOR(nsDisplayTransform);
MOZ_ASSERT(aFrame, "Must have a frame!");
SetReferenceFrameToAncestor(aBuilder);
Init(aBuilder);
UpdateBoundsFor3D(aBuilder);
}
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
const nsRect& aChildrenBuildingRect,
const Matrix4x4& aTransform,
uint32_t aIndex)
: nsDisplayHitTestInfoItem(aBuilder, aFrame),
mStoredList(aBuilder, aFrame, aList),
mTransform(Some(aTransform)),
mTransformGetter(nullptr),
mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot),
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
mChildrenBuildingRect(aChildrenBuildingRect),
mIndex(aIndex),
mIsTransformSeparator(true),
mTransformPreserves3DInited(false),
mAllowAsyncAnimation(false) {
MOZ_COUNT_CTOR(nsDisplayTransform);
MOZ_ASSERT(aFrame, "Must have a frame!");
Init(aBuilder);
UpdateBoundsFor3D(aBuilder);
mChildren.AppendToTop(aChildren);
UpdateBounds(aBuilder);
}
bool nsDisplayTransform::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
@ -7924,14 +7910,13 @@ Matrix4x4 nsDisplayTransform::GetTransformForRendering(
const Matrix4x4& nsDisplayTransform::GetAccumulatedPreserved3DTransform(
nsDisplayListBuilder* aBuilder) {
MOZ_ASSERT(!mFrame->Extend3DContext() || IsLeafOf3DContext());
// XXX: should go back to fix mTransformGetter.
if (!mTransformPreserves3DInited) {
mTransformPreserves3DInited = true;
if (!IsLeafOf3DContext()) {
mTransformPreserves3D = GetTransform().GetMatrix();
return mTransformPreserves3D;
}
if (!IsLeafOf3DContext()) {
return GetTransform().GetMatrix();
}
// XXX: should go back to fix mTransformGetter.
if (!mTransformPreserves3D) {
const nsIFrame* establisher; // Establisher of the 3D rendering context.
for (establisher = mFrame;
establisher && establisher->Combines3DTransformWithAncestors();
@ -7945,10 +7930,11 @@ const Matrix4x4& nsDisplayTransform::GetAccumulatedPreserved3DTransform(
float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
uint32_t flags =
INCLUDE_PRESERVE3D_ANCESTORS | INCLUDE_PERSPECTIVE | OFFSET_BY_ORIGIN;
mTransformPreserves3D =
GetResultingTransformMatrix(mFrame, offset, scale, flags);
mTransformPreserves3D = MakeUnique<Matrix4x4>(
GetResultingTransformMatrix(mFrame, offset, scale, flags));
}
return mTransformPreserves3D;
return *mTransformPreserves3D;
}
bool nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(
@ -8028,8 +8014,7 @@ bool nsDisplayTransform::CreateWebRenderCommands(
LayoutDeviceRect(position, LayoutDeviceSize()));
aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(
mStoredList.GetChildren(), &mStoredList, aDisplayListBuilder, sc,
aBuilder, aResources, this);
GetChildren(), this, aDisplayListBuilder, sc, aBuilder, aResources);
return true;
}
@ -8071,8 +8056,8 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(
uint32_t flags = FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR;
RefPtr<ContainerLayer> container =
aManager->GetLayerBuilder()->BuildContainerLayerFor(
aBuilder, aManager, mFrame, this, mStoredList.GetChildren(),
aContainerParameters, &newTransformMatrix, flags);
aBuilder, aManager, mFrame, this, GetChildren(), aContainerParameters,
&newTransformMatrix, flags);
if (!container) {
return nullptr;
@ -8152,7 +8137,7 @@ nsDisplayItem::LayerState nsDisplayTransform::GetLayerState(
// different animated geometry root, we'll make this an active layer so the
// animation can be accelerated.
return RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
*mStoredList.GetChildren(),
*GetChildren(),
mAnimatedGeometryRootForChildren);
}
@ -8174,14 +8159,124 @@ bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder* aBuilder,
if (!UntransformPaintRect(aBuilder, &untransformedVisibleRect)) {
untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf();
}
nsRegion untransformedVisible = untransformedVisibleRect;
// Call RecomputeVisiblity instead of ComputeVisibility since
// nsDisplayItem::ComputeVisibility should only be called from
// nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item)
mStoredList.RecomputeVisibility(aBuilder, &untransformedVisible);
bool snap;
const nsRect bounds = GetUntransformedBounds(aBuilder, &snap);
nsRegion visibleRegion;
visibleRegion.And(bounds, untransformedVisibleRect);
GetChildren()->ComputeVisibilityForSublist(aBuilder, &visibleRegion,
visibleRegion.GetBounds());
return true;
}
nsRect nsDisplayTransform::TransformUntransformedBounds(
nsDisplayListBuilder* aBuilder, const Matrix4x4Flagged& aMatrix) const {
bool snap;
const nsRect untransformedBounds = GetUntransformedBounds(aBuilder, &snap);
// GetTransform always operates in dev pixels.
const float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
return nsLayoutUtils::MatrixTransformRect(untransformedBounds, aMatrix,
factor);
}
/**
* Returns the bounds for this transform. The bounds are calculated during
* display list building and merging, see |nsDisplayTransform::UpdateBounds()|.
*/
nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const {
*aSnap = false;
return mBounds;
}
void nsDisplayTransform::ComputeBounds(nsDisplayListBuilder* aBuilder) {
MOZ_ASSERT(mFrame->Extend3DContext() || IsLeafOf3DContext());
/* Some transforms can get empty bounds in 2D, but might get transformed again
* and get non-empty bounds. A simple example of this would be a 180 degree
* rotation getting applied twice.
* We should not depend on transforming bounds level by level.
*
* This function collects the bounds of this transform and stores it in
* nsDisplayListBuilder. If this is not a leaf of a 3D context, we recurse
* down and include the bounds of the child transforms.
* The bounds are transformed with the accumulated transformation matrix up to
* the 3D context root coordinate space.
*/
nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
accTransform.Accumulate(GetTransform().GetMatrix());
// Do not dive into another 3D context.
if (!IsLeafOf3DContext()) {
for (nsDisplayItem* i = GetChildren()->GetBottom(); i; i = i->GetAbove()) {
i->DoUpdateBoundsPreserves3D(aBuilder);
}
}
/* The child transforms that extend 3D context further will have empty bounds,
* so the untransformed bounds here is the bounds of all the non-preserve-3d
* content under this transform.
*/
const nsRect rect = TransformUntransformedBounds(
aBuilder, accTransform.GetCurrentTransform());
aBuilder->AccumulateRect(rect);
}
void nsDisplayTransform::DoUpdateBoundsPreserves3D(
nsDisplayListBuilder* aBuilder) {
MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors() ||
IsTransformSeparator());
// Updating is not going through to child 3D context.
ComputeBounds(aBuilder);
}
void nsDisplayTransform::UpdateBounds(nsDisplayListBuilder* aBuilder) {
UpdateUntransformedBounds(aBuilder);
if (IsTransformSeparator()) {
MOZ_ASSERT(GetTransform().IsIdentity());
mBounds = mChildBounds;
return;
}
if (!mFrame->Combines3DTransformWithAncestors()) {
if (mFrame->Extend3DContext()) {
// The transform establishes a 3D context. |UpdateBoundsFor3D()| will
// collect the bounds from the child transforms.
UpdateBoundsFor3D(aBuilder);
} else {
// A stand-alone transform.
mBounds = TransformUntransformedBounds(aBuilder, GetTransform());
}
return;
}
// With nested 3D transforms, the 2D bounds might not be useful.
MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors());
mBounds = nsRect();
}
void nsDisplayTransform::UpdateBoundsFor3D(nsDisplayListBuilder* aBuilder) {
MOZ_ASSERT(mFrame->Extend3DContext() &&
!mFrame->Combines3DTransformWithAncestors() &&
!IsTransformSeparator());
// Always start updating from an establisher of a 3D rendering context.
nsDisplayListBuilder::AutoAccumulateRect accRect(aBuilder);
nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
accTransform.StartRoot();
ComputeBounds(aBuilder);
mBounds = aBuilder->GetAccumulatedRect();
}
void nsDisplayTransform::UpdateUntransformedBounds(
nsDisplayListBuilder* aBuilder) {
mChildBounds = GetChildren()->GetClippedBoundsWithRespectToASR(
aBuilder, mActiveScrolledRoot);
}
#ifdef DEBUG_HIT
# include <time.h>
#endif
@ -8191,7 +8286,7 @@ void nsDisplayTransform::HitTest(nsDisplayListBuilder* aBuilder,
const nsRect& aRect, HitTestState* aState,
nsTArray<nsIFrame*>* aOutFrames) {
if (aState->mInPreserves3D) {
mStoredList.HitTest(aBuilder, aRect, aState, aOutFrames);
GetChildren()->HitTest(aBuilder, aRect, aState, aOutFrames);
return;
}
@ -8240,7 +8335,7 @@ void nsDisplayTransform::HitTest(nsDisplayListBuilder* aBuilder,
NSAppUnitsToFloatPixels(aRect.height, factor));
bool snap;
nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
nsRect childBounds = GetUntransformedBounds(aBuilder, &snap);
Rect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
NSAppUnitsToFloatPixels(childBounds.y, factor),
NSAppUnitsToFloatPixels(childBounds.width, factor),
@ -8266,7 +8361,7 @@ void nsDisplayTransform::HitTest(nsDisplayListBuilder* aBuilder,
uint32_t originalFrameCount = aOutFrames.Length();
#endif
mStoredList.HitTest(aBuilder, resultingRect, aState, aOutFrames);
GetChildren()->HitTest(aBuilder, resultingRect, aState, aOutFrames);
#ifdef DEBUG_HIT
if (originalFrameCount != aOutFrames.Length())
@ -8297,64 +8392,6 @@ float nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder,
return transformed.z;
}
/* The bounding rectangle for the object is the overflow rectangle translated
* by the reference point.
*/
nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const {
*aSnap = false;
if (mHasBounds) {
return mBounds;
}
if (mFrame->Extend3DContext() && !mIsTransformSeparator) {
return nsRect();
}
nsRect untransformedBounds = mStoredList.GetBounds(aBuilder, aSnap);
// GetTransform always operates in dev pixels.
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
mBounds = nsLayoutUtils::MatrixTransformRect(untransformedBounds,
GetTransform(), factor);
mHasBounds = true;
return mBounds;
}
void nsDisplayTransform::ComputeBounds(nsDisplayListBuilder* aBuilder) {
MOZ_ASSERT(mFrame->Extend3DContext() || IsLeafOf3DContext());
/* For some cases, the transform would make an empty bounds, but it
* may be turned back again to get a non-empty bounds. We should
* not depend on transforming bounds level by level.
*
* Here, it applies accumulated transforms on the leaf frames of the
* 3d rendering context, and track and accmulate bounds at
* nsDisplayListBuilder.
*/
nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
accTransform.Accumulate(GetTransform().GetMatrix());
if (!IsLeafOf3DContext()) {
// Do not dive into another 3D context.
mStoredList.DoUpdateBoundsPreserves3D(aBuilder);
}
/* For Preserves3D, it is bounds of only children as leaf frames.
* For non-leaf frames, their bounds are accumulated and kept at
* nsDisplayListBuilder.
*/
bool snap;
nsRect untransformedBounds = mStoredList.GetBounds(aBuilder, &snap);
// GetTransform always operates in dev pixels.
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
nsRect rect = nsLayoutUtils::MatrixTransformRect(
untransformedBounds, accTransform.GetCurrentTransform(), factor);
aBuilder->AccumulateRect(rect);
}
/* The transform is opaque iff the transform consists solely of scales and
* translations and if the underlying content is opaque. Thus if the transform
* is of the form
@ -8374,24 +8411,40 @@ void nsDisplayTransform::ComputeBounds(nsDisplayListBuilder* aBuilder) {
nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) const {
*aSnap = false;
nsRect untransformedVisible;
if (!UntransformBuildingRect(aBuilder, &untransformedVisible)) {
return nsRegion();
}
const Matrix4x4Flagged& matrix = GetTransform();
Matrix matrix2d;
if (!matrix.Is2D(&matrix2d) || !matrix2d.PreservesAxisAlignedRectangles()) {
return nsRegion();
}
nsRegion result;
Matrix matrix2d;
bool tmpSnap;
if (matrix.Is2D(&matrix2d) && matrix2d.PreservesAxisAlignedRectangles() &&
mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap)
.Contains(untransformedVisible)) {
const nsRect bounds = GetUntransformedBounds(aBuilder, &tmpSnap);
const nsRegion opaque = ::GetOpaqueRegion(aBuilder, GetChildren(), bounds);
if (opaque.Contains(untransformedVisible)) {
result = GetBuildingRect().Intersect(GetBounds(aBuilder, &tmpSnap));
}
return result;
}
nsRect nsDisplayTransform::GetComponentAlphaBounds(
nsDisplayListBuilder* aBuilder) const {
if (GetChildren()->GetComponentAlphaBounds(aBuilder).IsEmpty()) {
return nsRect();
}
bool snap;
return GetBounds(aBuilder, &snap);
}
/* TransformRect takes in as parameters a rectangle (in app space) and returns
* the smallest rectangle (in app space) containing the transformed image of
* that rectangle. That is, it takes the four corners of the rectangle,
@ -8470,7 +8523,7 @@ bool nsDisplayTransform::UntransformRect(nsDisplayListBuilder* aBuilder,
NSAppUnitsToFloatPixels(aRect.height, factor));
bool snap;
nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
nsRect childBounds = GetUntransformedBounds(aBuilder, &snap);
RectDouble childGfxBounds(
NSAppUnitsToFloatPixels(childBounds.x, factor),
NSAppUnitsToFloatPixels(childBounds.y, factor),
@ -9415,8 +9468,7 @@ static float ClampStdDeviation(float aStdDeviation) {
return std::min(std::max(0.0f, aStdDeviation), 100.0f);
}
bool nsDisplayFilters::CreateWebRenderCSSFilters(
WrFiltersHolder& wrFilters) {
bool nsDisplayFilters::CreateWebRenderCSSFilters(WrFiltersHolder& wrFilters) {
// All CSS filters are supported by WebRender. SVG filters are not fully
// supported, those use NS_STYLE_FILTER_URL and are handled separately.
const nsTArray<nsStyleFilter>& filters = mFrame->StyleEffects()->mFilters;
@ -9469,9 +9521,10 @@ bool nsDisplayFilters::CreateWebRenderCSSFilters(
case NS_STYLE_FILTER_BLUR: {
float appUnitsPerDevPixel =
mFrame->PresContext()->AppUnitsPerDevPixel();
wrFilters.filters.AppendElement(mozilla::wr::FilterOp::Blur(ClampStdDeviation(
NSAppUnitsToFloatPixels(filter.GetFilterParameter().GetCoordValue(),
appUnitsPerDevPixel))));
wrFilters.filters.AppendElement(mozilla::wr::FilterOp::Blur(
ClampStdDeviation(NSAppUnitsToFloatPixels(
filter.GetFilterParameter().GetCoordValue(),
appUnitsPerDevPixel))));
break;
}
case NS_STYLE_FILTER_DROP_SHADOW: {

View file

@ -2271,6 +2271,14 @@ class nsDisplayItem : public nsDisplayItemLink {
return nsRect(ToReferenceFrame(), Frame()->GetSize());
}
/**
* Returns the untransformed bounds of this display item.
*/
virtual nsRect GetUntransformedBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const {
return GetBounds(aBuilder, aSnap);
}
virtual nsRegion GetTightBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const {
*aSnap = false;
@ -2894,6 +2902,10 @@ class nsDisplayItem : public nsDisplayItemLink {
const nsRect& GetPaintRect() const { return mPaintRect; }
virtual const nsRect& GetUntransformedPaintRect() const {
return GetPaintRect();
}
virtual bool HasHitTestInfo() const { return false; }
#ifdef DEBUG
@ -3260,6 +3272,29 @@ class nsDisplayList {
nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR,
nsRect* aBuildingRect = nullptr) const;
/**
* Returns the opaque region of this display list.
*/
nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder) {
nsRegion result;
bool snap;
for (nsDisplayItem* item = GetBottom(); item; item = item->GetAbove()) {
result.OrWith(item->GetOpaqueRegion(aBuilder, &snap));
}
return result;
}
/**
* Returns the bounds of the area that needs component alpha.
*/
nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const {
nsRect bounds;
for (nsDisplayItem* item = GetBottom(); item; item = item->GetAbove()) {
bounds.UnionRect(bounds, item->GetComponentAlphaBounds(aBuilder));
}
return bounds;
}
/**
* Find the topmost display item that returns a non-null frame, and return
* the frame.
@ -6419,37 +6454,6 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
typedef mozilla::gfx::Matrix4x4Flagged Matrix4x4Flagged;
typedef mozilla::gfx::Point3D Point3D;
/*
* Avoid doing UpdateBounds() during construction.
*/
class StoreList : public nsDisplayWrapList {
public:
StoreList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList)
: nsDisplayWrapList(aBuilder, aFrame, aList, true) {}
~StoreList() override = default;
void UpdateBounds(nsDisplayListBuilder* aBuilder) override {
// For extending 3d rendering context, the bounds would be
// updated by DoUpdateBoundsPreserves3D(), not here.
if (!mFrame->Extend3DContext()) {
nsDisplayWrapList::UpdateBounds(aBuilder);
}
}
void ForceUpdateBounds(nsDisplayListBuilder* aBuilder) {
nsDisplayWrapList::UpdateBounds(aBuilder);
}
void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override {
for (nsDisplayItem* i = mList.GetBottom(); i; i = i->GetAbove()) {
i->DoUpdateBoundsPreserves3D(aBuilder);
}
nsDisplayWrapList::UpdateBounds(aBuilder);
}
};
public:
enum PrerenderDecision { NoPrerender, FullPrerender, PartialPrerender };
@ -6468,14 +6472,16 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
*/
nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
uint32_t aIndex = 0, bool aAllowAsyncAnimation = false);
uint32_t aIndex);
nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
ComputeTransformFunction aTransformGetter,
uint32_t aIndex = 0);
uint32_t aIndex, bool aAllowAsyncAnimation);
nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
const Matrix4x4& aTransform, uint32_t aIndex = 0);
uint32_t aIndex,
ComputeTransformFunction aTransformGetter);
#ifdef NS_BUILD_REFCNT_LOGGING
~nsDisplayTransform() override { MOZ_COUNT_DTOR(nsDisplayTransform); }
@ -6485,41 +6491,37 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
void RestoreState() override { mShouldFlatten = false; }
void UpdateBounds(nsDisplayListBuilder* aBuilder) override {
mHasBounds = false;
if (IsTransformSeparator()) {
mStoredList.ForceUpdateBounds(aBuilder);
return;
}
mStoredList.UpdateBounds(aBuilder);
UpdateBoundsFor3D(aBuilder);
}
void UpdateBounds(nsDisplayListBuilder* aBuilder) override;
/**
* This function updates bounds for items with a frame establishing
* 3D rendering context.
*/
void UpdateBoundsFor3D(nsDisplayListBuilder* aBuilder);
void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override;
void Destroy(nsDisplayListBuilder* aBuilder) override {
mStoredList.GetChildren()->DeleteAll(aBuilder);
GetChildren()->DeleteAll(aBuilder);
nsDisplayItem::Destroy(aBuilder);
}
nsRect GetComponentAlphaBounds(
nsDisplayListBuilder* aBuilder) const override {
if (mStoredList.GetComponentAlphaBounds(aBuilder).IsEmpty())
return nsRect();
bool snap;
return GetBounds(aBuilder, &snap);
nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override;
RetainedDisplayList* GetChildren() const override { return &mChildren; }
nsRect GetUntransformedBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override {
*aSnap = false;
return mChildBounds;
}
RetainedDisplayList* GetChildren() const override {
return mStoredList.GetChildren();
const nsRect& GetUntransformedPaintRect() const override {
return mChildrenBuildingRect;
}
bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
void SetActiveScrolledRoot(
const ActiveScrolledRoot* aActiveScrolledRoot) override {
nsDisplayHitTestInfoItem::SetActiveScrolledRoot(aActiveScrolledRoot);
mStoredList.SetActiveScrolledRoot(aActiveScrolledRoot);
}
void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
@ -6752,41 +6754,12 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
void WriteDebugInfo(std::stringstream& aStream) override;
void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override {
MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors() ||
IsTransformSeparator());
// Updating is not going through to child 3D context.
ComputeBounds(aBuilder);
}
/**
* This function updates bounds for items with a frame establishing
* 3D rendering context.
*
* \see nsDisplayItem::DoUpdateBoundsPreserves3D()
*/
void UpdateBoundsFor3D(nsDisplayListBuilder* aBuilder) {
if (!mFrame->Extend3DContext() ||
mFrame->Combines3DTransformWithAncestors() || IsTransformSeparator()) {
// Not an establisher of a 3D rendering context.
return;
}
// Always start updating from an establisher of a 3D rendering context.
nsDisplayListBuilder::AutoAccumulateRect accRect(aBuilder);
nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
accTransform.StartRoot();
ComputeBounds(aBuilder);
mBounds = aBuilder->GetAccumulatedRect();
mHasBounds = true;
}
/**
* This item is an additional item as the boundary between parent
* and child 3D rendering context.
* \see nsIFrame::BuildDisplayListForStackingContext().
*/
bool IsTransformSeparator() { return mIsTransformSeparator; }
bool IsTransformSeparator() const { return mIsTransformSeparator; }
/**
* This item is the boundary between parent and child 3D rendering
* context.
@ -6805,33 +6778,33 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
mFrame->Combines3DTransformWithAncestors();
}
void RemoveFrame(nsIFrame* aFrame) override {
nsDisplayItem::RemoveFrame(aFrame);
mStoredList.RemoveFrame(aFrame);
}
private:
void ComputeBounds(nsDisplayListBuilder* aBuilder);
nsRect TransformUntransformedBounds(nsDisplayListBuilder* aBuilder,
const Matrix4x4Flagged& aMatrix) const;
void UpdateUntransformedBounds(nsDisplayListBuilder* aBuilder);
void SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder);
void Init(nsDisplayListBuilder* aBuilder);
void Init(nsDisplayListBuilder* aBuilder, nsDisplayList* aChildren);
static Matrix4x4 GetResultingTransformMatrixInternal(
const FrameTransformProperties& aProperties, const nsPoint& aOrigin,
float aAppUnitsPerPixel, uint32_t aFlags, const nsRect* aBoundsOverride);
StoreList mStoredList;
mutable mozilla::Maybe<Matrix4x4Flagged> mTransform;
mutable mozilla::Maybe<Matrix4x4Flagged> mInverseTransform;
// Accumulated transform of ancestors on the preserves-3d chain.
Matrix4x4 mTransformPreserves3D;
mozilla::UniquePtr<Matrix4x4> mTransformPreserves3D;
ComputeTransformFunction mTransformGetter;
RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForChildren;
RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForScrollMetadata;
nsRect mChildrenBuildingRect;
uint32_t mIndex;
mutable nsRect mBounds;
// True for mBounds is valid.
mutable bool mHasBounds;
mutable RetainedDisplayList mChildren;
// The untransformed bounds of |mChildren|.
nsRect mChildBounds;
// The transformed bounds of this display item.
nsRect mBounds;
// This item is a separator between 3D rendering contexts, and
// mTransform have been presetted by the constructor.
// This also forces us not to extend the 3D context. Since we don't create a
@ -6840,8 +6813,6 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
// parent context unintendedly if the root of the child preserves3d context
// doesn't create a transform item.
bool mIsTransformSeparator;
// True if mTransformPreserves3D have been initialized.
bool mTransformPreserves3DInited;
// True if async animation of the transform is allowed.
bool mAllowAsyncAnimation;
// True if this nsDisplayTransform should get flattened

View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=325">
<meta name="viewport" content="initial-scale=0.25">
<style> html { direction: rtl; } </style>
</head>
<body>
<div style="height: 8228px; width: 9000px;"></div>
<div style="height: 80000px; width: 36000px;"></div>
</body>
</html>

View file

@ -1,9 +1,9 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=325">
<meta name="viewport" content="initial-scale=0.25">
</head>
<body>
<div style="height: 8228px; width: 9000px;"></div>
<div style="height: 80000px; width: 36000px;"></div>
</body>
</html>

View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=125">
<meta name="viewport" content="initial-scale=0.5">
<style> html { direction: rtl; } </style>
</head>
<body>
<div style="height: 4787px; width: 9000px;"></div>
<div style="height: 40000px; width: 18000px;"></div>
</body>
</html>

View file

@ -1,9 +1,9 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=125">
<meta name="viewport" content="initial-scale=0.5">
</head>
<body>
<div style="height: 4787px; width: 9000px;"></div>
<div style="height: 40000px; width: 18000px;"></div>
</body>
</html>

View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=525">
<meta name="viewport" content="initial-scale=0.75">
<style> html { direction: rtl; } </style>
</head>
<body>
<div style="height: 13972px; width: 9000px;"></div>
<div style="height: 26667px; width: 12000px;"></div>
</body>
</html>

View file

@ -1,9 +1,9 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=525">
<meta name="viewport" content="initial-scale=0.75">
</head>
<body>
<div style="height: 13972px; width: 9000px;"></div>
<div style="height: 26667px; width: 12000px;"></div>
</body>
</html>

View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=725">
<meta name="viewport" content="initial-scale=1.25">
<style> html { direction: rtl; } </style>
</head>
<body>
<div style="height: 20000px; width: 9000px;"></div>
<div style="height: 16000px; width: 7200px;"></div>
</body>
</html>

View file

@ -1,9 +1,9 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=725">
<meta name="viewport" content="initial-scale=1.25">
</head>
<body>
<div style="height: 20000px; width: 9000px;"></div>
<div style="height: 16000px; width: 7200px;"></div>
</body>
</html>

View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=925">
<meta name="viewport" content="initial-scale=1.5">
<style> html { direction: rtl; } </style>
</head>
<body>
<div style="height: 26117px; width: 9000px;"></div>
<div style="height: 13333px; width: 6000px;"></div>
</body>
</html>

View file

@ -1,9 +1,9 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=925">
<meta name="viewport" content="initial-scale=1.5">
</head>
<body>
<div style="height: 26117px; width: 9000px;"></div>
<div style="height: 13333px; width: 6000px;"></div>
</body>
</html>

View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=1325">
<meta name="viewport" content="initial-scale=2.0">
<style> html { direction: rtl; } </style>
</head>
<body>
<div style="height: 37412px; width: 9000px;"></div>
<div style="height: 10000px; width: 4500px;"></div>
</body>
</html>

View file

@ -1,9 +1,9 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=1325">
<meta name="viewport" content="initial-scale=2.0">
</head>
<body>
<div style="height: 37412px; width: 9000px;"></div>
<div style="height: 10000px; width: 4500px;"></div>
</body>
</html>

View file

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=725">
<meta name="viewport" content="initial-scale=1.0">
<style> html { direction: rtl; } </style>
</head>
<body>

View file

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=725">
<meta name="viewport" content="initial-scale=1">
</head>
<body>
<div style="height: 20000px; width: 9000px;"></div>

View file

@ -1900,7 +1900,7 @@ skip-if(verify) == 1121748-2.html 1121748-2-ref.html
== 1130231-2-button-padding-rtl.html 1130231-2-button-padding-rtl-ref.html
# The 1133905-*.html reftests only make sense on platforms where both APZ and
# <meta viewport> are enabled.
# (Note: bug 1308702 covers these tests' failures on Android)
# (Note: bug 1308702 and bug 1527511 cover these tests' failures on Android)
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-1.html 1133905-ref.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-2.html 1133905-ref.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-3.html 1133905-ref.html
@ -1919,12 +1919,13 @@ pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-3-h.html 1133905-ref-h
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-4-h.html 1133905-ref-h.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-5-h.html 1133905-ref-h.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-6-h.html 1133905-ref-h.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-1-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-2-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) fuzzy-if(Android,0-54,0-6) == 1133905-1-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) fuzzy-if(Android,0-45,0-4) == 1133905-2-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-3-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-4-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-5-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-6-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) fuzzy-if(Android,0-45,0-4) == 1133905-4-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) fuzzy-if(Android,0-54,0-6) == 1133905-5-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) fuzzy-if(Android,0-54,0-8) == 1133905-6-vh.html 1133905-ref-vh.html
pref(apz.allow_zooming,true) skip-if(!Android) != 1133905-ref-vh.html about:blank # make sure it doesn't render blank
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-1-rtl.html 1133905-ref-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-2-rtl.html 1133905-ref-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-3-rtl.html 1133905-ref-rtl.html
@ -1943,12 +1944,13 @@ pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-3-h-rtl.html 1133905-r
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-4-h-rtl.html 1133905-ref-h-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-5-h-rtl.html 1133905-ref-h-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-6-h-rtl.html 1133905-ref-h-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-1-vh-rtl.html 1133905-ref-vh-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-2-vh-rtl.html 1133905-ref-vh-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) fuzzy-if(Android,0-54,0-6) == 1133905-1-vh-rtl.html 1133905-ref-vh-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) fuzzy-if(Android,0-45,0-4) == 1133905-2-vh-rtl.html 1133905-ref-vh-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-3-vh-rtl.html 1133905-ref-vh-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-4-vh-rtl.html 1133905-ref-vh-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-5-vh-rtl.html 1133905-ref-vh-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) == 1133905-6-vh-rtl.html 1133905-ref-vh-rtl.html
pref(apz.allow_zooming,true) skip-if(!Android) fails-if(Android) == 1133905-4-vh-rtl.html 1133905-ref-vh-rtl.html # bug 1527511
pref(apz.allow_zooming,true) skip-if(!Android) fails-if(Android) == 1133905-5-vh-rtl.html 1133905-ref-vh-rtl.html # bug 1527511
pref(apz.allow_zooming,true) skip-if(!Android) fails-if(Android) == 1133905-6-vh-rtl.html 1133905-ref-vh-rtl.html # bug 1527511
pref(apz.allow_zooming,true) skip-if(!Android) != 1133905-ref-vh-rtl.html about:blank # make sure it doesn't render blank
== 1149304-1-transform-change.html 1149304-1-transform-change-ref.html
== 1150021-1.xul 1150021-1-ref.xul
== 1151145-1.html 1151145-1-ref.html

View file

@ -24,14 +24,14 @@ fails-if(Android) skip-if(Android&&AndroidVersion=='18') == poster-2.html poster
random-if(Android) == poster-3.html poster-ref-black140x100.html
== poster-4.html poster-ref-black140x100.html
random-if(Android) == poster-5.html poster-ref-black140x100.html
== poster-6.html poster-ref-black140x100.html
== poster-7.html poster-ref-red140x100.html
fails-if(Android) == poster-6.html poster-ref-black140x100.html
fails-if(Android) == poster-7.html poster-ref-red140x100.html
fuzzy-if(Android,0-2,0-14000) == poster-8.html poster-ref-black140x100.html
random == poster-10.html poster-ref-blue125x100.html
random == poster-11.html poster-ref-blue140x100.html
random == poster-12.html poster-ref-blue140x100.html
== poster-13.html poster-ref-blue400x300.html
== poster-15.html poster-ref-green70x30.html
random-if(Android) == poster-13.html poster-ref-blue400x300.html
random-if(Android) == poster-15.html poster-ref-green70x30.html
random-if(winWidget) random-if(cocoaWidget) skip-if(Android) == bug686957.html bug686957-ref.html # bug 922951 for OS X
== webm-alpha.html webm-alpha-ref.html

View file

@ -57,6 +57,9 @@ function testInheritedProperty(property, info) {
// is different (normal vs. 19px).
if (property == "line-height")
return;
// Ongoing debugging in bug 1533392.
if (property == "font-family")
return;
const div = kInheritedDiv;
const initial = getInitialValue(div, property);

View file

@ -535,9 +535,13 @@ pref("layers.low-precision-opacity", "1.0");
// work harder keep scrolling smooth and memory low.
pref("layers.max-active", 20);
// On Fennec we need containerful scrolling to support zooming. Bug 1459312
// tracks zooming with containerless scrolling.
// Use containerless scrolling in nightly builds on Fennec.
// Bug 1137890 tracks letting containerless scrolling ride the trains.
#ifdef NIGHTLY_BUILD
pref("layout.scroll.root-frame-containers", 0);
#else
pref("layout.scroll.root-frame-containers", 1);
#endif
pref("notification.feature.enabled", true);
pref("dom.webnotifications.enabled", true);

View file

@ -515,10 +515,10 @@
<!-- New child services must also be added to the GeckoView AndroidManifest.xml -->
<service
android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$geckomediaplugin"
android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$gmplugin"
android:enabled="true"
android:exported="false"
android:process=":geckomediaplugin"
android:process=":gmplugin"
android:isolatedProcess="false">
</service>

View file

@ -48,11 +48,11 @@
android:process=":media">
</service>
<service
android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$geckomediaplugin"
android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$gmplugin"
android:enabled="true"
android:exported="false"
android:isolatedProcess="false"
android:process=":geckomediaplugin">
android:process=":gmplugin">
</service>
<service
android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$tab"
@ -69,4 +69,4 @@
</service>
</application>
</manifest>
</manifest>

View file

@ -141,7 +141,7 @@ public class GeckoServiceChildProcess extends Service {
return false;
}
public static final class geckomediaplugin extends GeckoServiceChildProcess {}
public static final class gmplugin extends GeckoServiceChildProcess {}
public static final class tab extends GeckoServiceChildProcess {}
}

View file

@ -4672,6 +4672,7 @@ pref("font.name-list.monospace.x-unicode", "dt-interface user-ucs2.cjk_japan-0")
pref("signon.rememberSignons", true);
pref("signon.rememberSignons.visibilityToggle", true);
pref("signon.autofillForms", true);
pref("signon.autofillForms.autocompleteOff", true);
pref("signon.autofillForms.http", false);
pref("signon.autologin.proxy", false);
pref("signon.formlessCapture.enabled", true);

View file

@ -638,22 +638,6 @@ static const StaticFingerprints kPinset_swehackCom = {
kPinset_swehackCom_Data
};
static const char* const kPinset_ncsccs_Data[] = {
kCOMODO_ECC_Certification_AuthorityFingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kBaltimore_CyberTrust_RootFingerprint,
kLet_s_Encrypt_Authority_X3Fingerprint,
kCOMODO_RSA_Certification_AuthorityFingerprint,
kAddTrust_External_RootFingerprint,
kDigiCert_Global_Root_CAFingerprint,
kLet_s_Encrypt_Authority_X4Fingerprint,
};
static const StaticFingerprints kPinset_ncsccs = {
sizeof(kPinset_ncsccs_Data) / sizeof(const char*),
kPinset_ncsccs_Data
};
static const char* const kPinset_tumblr_Data[] = {
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kTumblrBackupFingerprint,
@ -677,7 +661,6 @@ struct TransportSecurityPreload {
/* Sort hostnames for binary search. */
static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "0.me.uk", true, false, false, -1, &kPinset_ncsccs },
{ "2mdn.net", true, false, false, -1, &kPinset_google_root_pems },
{ "accounts.firefox.com", true, false, true, 4, &kPinset_mozilla_services },
{ "accounts.google.com", true, false, false, -1, &kPinset_google_root_pems },
@ -1059,7 +1042,6 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "mx.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
{ "myaccount.google.com", true, false, false, -1, &kPinset_google_root_pems },
{ "myactivity.google.com", true, false, false, -1, &kPinset_google_root_pems },
{ "ncsccs.com", true, false, false, -1, &kPinset_ncsccs },
{ "ni.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
{ "nl.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
{ "no.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
@ -1096,7 +1078,6 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "security.google.com", true, false, false, -1, &kPinset_google_root_pems },
{ "services.mozilla.com", true, false, true, 6, &kPinset_mozilla_services },
{ "sg.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
{ "sirburton.com", true, false, false, -1, &kPinset_ncsccs },
{ "sites.google.com", true, false, false, -1, &kPinset_google_root_pems },
{ "spideroak.com", true, false, false, -1, &kPinset_spideroak },
{ "spreadsheets.google.com", true, false, false, -1, &kPinset_google_root_pems },
@ -1113,7 +1094,6 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "test-mode.pinning.example.com", true, true, false, -1, &kPinset_mozilla_test },
{ "testpilot.firefox.com", false, false, true, 9, &kPinset_mozilla_services },
{ "th.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
{ "themathematician.uk", true, false, false, -1, &kPinset_ncsccs },
{ "torproject.org", false, false, false, -1, &kPinset_tor },
{ "touch.facebook.com", true, false, false, -1, &kPinset_facebook },
{ "tr.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
@ -1167,8 +1147,8 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "zh.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
};
// Pinning Preload List Length = 488;
// Pinning Preload List Length = 484;
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1559823648419000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1560431526439000);

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -7,7 +7,6 @@
from __future__ import absolute_import, print_function, unicode_literals
import logging
import sys
from taskgraph.util.taskcluster import (
status_task,
@ -54,9 +53,9 @@ def rerun_action(parameters, graph_config, input, task_group_id, task_id):
status = status_task(task_id)
if status not in RERUN_STATES:
logger.error(
"Refusing to rerun {}: state {} not in {}!".format(label, status, RERUN_STATES)
logger.warning(
"No need to to rerun {}: state '{}' not in {}!".format(label, status, RERUN_STATES)
)
sys.exit(1)
return
rerun_task(task_id)
logger.info('Reran {}'.format(label))

View file

@ -128,6 +128,3 @@ skip-if = asan || manage_instance == false || appname == 'fennec' # Bug 1298921
[test_reftest.py]
skip-if = appname == 'fennec' # Bug 1519552
[test_startup_caches.py]
skip-if = appname == 'fennec'

View file

@ -0,0 +1,3 @@
[transform-flattening-001.html]
expected:
if webrender: FAIL

View file

@ -1,8 +1,4 @@
[RTCPeerConnection-setLocalDescription.html]
[Switching role from answerer to offerer after going back to stable state should succeed]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531143
[onsignalingstatechange fires before setLocalDescription resolves]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531075

View file

@ -0,0 +1,10 @@
<!doctype html>
<title>CSS Transforms: Transforms are flattened if transform-style is flat.</title>
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<link rel="author" href="https://mozilla.org" title="Mozilla">
<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#3d-rendering-context">
<link rel="mismatch" href="about:blank">
<!-- Should see a green rectangle, not white -->
<div style="transform: rotateX(45deg)">
<div style="transform: rotateX(45deg); background: green; width: 100px; height: 100px"></div>
</div>

View file

@ -72,29 +72,55 @@
})));
}, 'Calling createOffer() and setLocalDescription() again after one round of local-offer/remote-answer should succeed');
promise_test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
promise_test(async t => {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc2.close());
const states = [];
pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
pc1.addEventListener('signalingstatechange', () => states.push(pc1.signalingState));
return generateDataChannelOffer(pc)
.then(offer => pc.setRemoteDescription(offer))
.then(() => pc.createAnswer())
.then(answer =>
pc.setLocalDescription(answer)
.then(() => generateVideoReceiveOnlyOffer(pc))
.then(offer =>
pc.setLocalDescription(offer)
.then(() => {
assert_equals(pc.signalingState, 'have-local-offer');
assert_session_desc_similar(pc.localDescription, offer);
assert_session_desc_similar(pc.currentLocalDescription, answer);
assert_session_desc_similar(pc.pendingLocalDescription, offer);
assert_equals(pc1.localDescription, null);
assert_equals(pc1.currentLocalDescription, null);
assert_equals(pc1.pendingLocalDescription, null);
assert_array_equals(states, ['have-remote-offer', 'stable', 'have-local-offer']);
})));
pc1.createDataChannel('test');
const offer = await pc1.createOffer();
assert_equals(pc1.localDescription, null);
assert_equals(pc1.currentLocalDescription, null);
assert_equals(pc1.pendingLocalDescription, null);
await pc1.setLocalDescription(offer);
assert_session_desc_similar(pc1.localDescription, offer);
assert_equals(pc1.currentLocalDescription, null);
assert_session_desc_similar(pc1.pendingLocalDescription, offer);
await pc2.setRemoteDescription(offer);
const answer = await pc2.createAnswer();
await pc2.setLocalDescription(answer);
await pc1.setRemoteDescription(answer);
assert_equals(pc1.signalingState, 'stable');
assert_session_desc_similar(pc1.localDescription, offer);
assert_session_desc_similar(pc1.currentLocalDescription, offer);
assert_equals(pc1.pendingLocalDescription, null);
const stream = await getNoiseStream({audio:true});
pc2.addTrack(stream.getTracks()[0], stream);
const reoffer = await pc2.createOffer();
await pc2.setLocalDescription(reoffer);
await pc1.setRemoteDescription(reoffer);
const reanswer = await pc1.createAnswer();
await pc1.setLocalDescription(reanswer);
assert_session_desc_similar(pc1.localDescription, reanswer);
assert_session_desc_similar(pc1.currentLocalDescription, reanswer);
assert_equals(pc1.pendingLocalDescription, null);
}, 'Switching role from answerer to offerer after going back to stable state should succeed');
promise_test(async t => {

View file

@ -0,0 +1,122 @@
/* 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/. */
/**
* A factory to generate LoginForm objects that represent a set of login fields
* which aren't necessarily marked up with a <form> element.
*/
"use strict";
var EXPORTED_SYMBOLS = ["LoginFormFactory"];
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "FormLikeFactory",
"resource://gre/modules/FormLikeFactory.jsm");
ChromeUtils.defineModuleGetter(this, "LoginHelper",
"resource://gre/modules/LoginHelper.jsm");
XPCOMUtils.defineLazyGetter(this, "log", () => {
return LoginHelper.createLogger("LoginFormFactory");
});
var LoginFormFactory = {
/**
* WeakMap of the root element of a LoginForm to the LoginForm representing its fields.
*
* This is used to be able to lookup an existing LoginForm for a given root element since multiple
* calls to LoginFormFactory.createFrom* won't give the exact same object. When batching fills we don't always
* want to use the most recent list of elements for a LoginForm since we may end up doing multiple
* fills for the same set of elements when a field gets added between arming and running the
* DeferredTask.
*
* @type {WeakMap}
*/
_loginFormsByRootElement: new WeakMap(),
/**
* Maps all DOM content documents in this content process, including those in
* frames, to a WeakSet of LoginForm for the document.
*/
_loginFormRootElementsByDocument: new WeakMap(),
/**
* Create a LoginForm object from a <form>.
*
* @param {HTMLFormElement} aForm
* @return {LoginForm}
* @throws Error if aForm isn't an HTMLFormElement
*/
createFromForm(aForm) {
let formLike = FormLikeFactory.createFromForm(aForm);
formLike.action = LoginHelper.getFormActionOrigin(aForm);
let rootElementsSet = this.getRootElementsWeakSetForDocument(formLike.ownerDocument);
rootElementsSet.add(formLike.rootElement);
log.debug("adding", formLike.rootElement, "to root elements for", formLike.ownerDocument);
this._loginFormsByRootElement.set(formLike.rootElement, formLike);
return formLike;
},
/**
* Create a LoginForm object from a password or username field.
*
* If the field is in a <form>, construct the LoginForm from the form.
* Otherwise, create a LoginForm with a rootElement (wrapper) according to
* heuristics. Currently all <input> not in a <form> are one LoginForm but this
* shouldn't be relied upon as the heuristics may change to detect multiple
* "forms" (e.g. registration and login) on one page with a <form>.
*
* Note that two LoginForms created from the same field won't return the same LoginForm object.
* Use the `rootElement` property on the LoginForm as a key instead.
*
* @param {HTMLInputElement} aField - a password or username field in a document
* @return {LoginForm}
* @throws Error if aField isn't a password or username field in a document
*/
createFromField(aField) {
if (ChromeUtils.getClassName(aField) !== "HTMLInputElement" ||
(aField.type != "password" && !LoginHelper.isUsernameFieldType(aField)) ||
!aField.ownerDocument) {
throw new Error("createFromField requires a password or username field in a document");
}
if (aField.form) {
return this.createFromForm(aField.form);
}
let formLike = FormLikeFactory.createFromField(aField);
formLike.action = LoginHelper.getLoginOrigin(aField.ownerDocument.baseURI);
log.debug("Created non-form LoginForm for rootElement:", aField.ownerDocument.documentElement);
let rootElementsSet = this.getRootElementsWeakSetForDocument(formLike.ownerDocument);
rootElementsSet.add(formLike.rootElement);
log.debug("adding", formLike.rootElement, "to root elements for", formLike.ownerDocument);
this._loginFormsByRootElement.set(formLike.rootElement, formLike);
return formLike;
},
getRootElementsWeakSetForDocument(aDocument) {
let rootElementsSet = this._loginFormRootElementsByDocument.get(aDocument);
if (!rootElementsSet) {
rootElementsSet = new WeakSet();
this._loginFormRootElementsByDocument.set(aDocument, rootElementsSet);
}
return rootElementsSet;
},
getForRootElement(aRootElement) {
return this._loginFormsByRootElement.get(aRootElement);
},
setForRootElement(aRootElement, aLoginForm) {
return this._loginFormsByRootElement.set(aRootElement, aLoginForm);
},
};

View file

@ -40,6 +40,7 @@ var LoginHelper = {
updateSignonPrefs() {
this.autofillForms = Services.prefs.getBoolPref("signon.autofillForms");
this.autofillAutocompleteOff = Services.prefs.getBoolPref("signon.autofillForms.autocompleteOff");
this.debug = Services.prefs.getBoolPref("signon.debug");
this.enabled = Services.prefs.getBoolPref("signon.rememberSignons");
this.formlessCaptureEnabled = Services.prefs.getBoolPref("signon.formlessCapture.enabled");

View file

@ -14,7 +14,7 @@ ChromeUtils.defineModuleGetter(this, "BrowserUtils",
ChromeUtils.defineModuleGetter(this, "LoginHelper",
"resource://gre/modules/LoginHelper.jsm");
ChromeUtils.defineModuleGetter(this, "LoginFormFactory",
"resource://gre/modules/LoginManagerContent.jsm");
"resource://gre/modules/LoginFormFactory.jsm");
ChromeUtils.defineModuleGetter(this, "LoginManagerContent",
"resource://gre/modules/LoginManagerContent.jsm");
ChromeUtils.defineModuleGetter(this, "LoginAutoCompleteResult",

View file

@ -6,15 +6,12 @@
* Module doing most of the content process work for the password manager.
*/
// Disable use-ownerGlobal since FormLike don't have it.
// Disable use-ownerGlobal since LoginForm doesn't have it.
/* eslint-disable mozilla/use-ownerGlobal */
"use strict";
var EXPORTED_SYMBOLS = [
"LoginManagerContent",
"LoginFormFactory",
];
var EXPORTED_SYMBOLS = ["LoginManagerContent"];
const PASSWORD_INPUT_ADDED_COALESCING_THRESHOLD_MS = 1;
const AUTOCOMPLETE_AFTER_RIGHT_CLICK_THRESHOLD_MS = 400;
@ -28,6 +25,8 @@ const {PromiseUtils} = ChromeUtils.import("resource://gre/modules/PromiseUtils.j
ChromeUtils.defineModuleGetter(this, "DeferredTask", "resource://gre/modules/DeferredTask.jsm");
ChromeUtils.defineModuleGetter(this, "FormLikeFactory",
"resource://gre/modules/FormLikeFactory.jsm");
ChromeUtils.defineModuleGetter(this, "LoginFormFactory",
"resource://gre/modules/LoginFormFactory.jsm");
ChromeUtils.defineModuleGetter(this, "LoginRecipesContent",
"resource://gre/modules/LoginRecipes.jsm");
ChromeUtils.defineModuleGetter(this, "LoginHelper",
@ -152,24 +151,11 @@ var LoginManagerContent = {
],
/**
* WeakMap of the root element of a FormLike to the FormLike representing its fields.
* WeakMap of the root element of a LoginForm to the DeferredTask to fill its fields.
*
* This is used to be able to lookup an existing FormLike for a given root element since multiple
* calls to LoginFormFactory won't give the exact same object. When batching fills we don't always
* want to use the most recent list of elements for a FormLike since we may end up doing multiple
* fills for the same set of elements when a field gets added between arming and running the
* DeferredTask.
*
* @type {WeakMap}
*/
_formLikeByRootElement: new WeakMap(),
/**
* WeakMap of the root element of a FormLike to the DeferredTask to fill its fields.
*
* This is used to be able to throttle fills for a FormLike since onDOMInputPasswordAdded gets
* This is used to be able to throttle fills for a LoginForm since onDOMInputPasswordAdded gets
* dispatched for each password field added to a document but we only want to fill once per
* FormLike when multiple fields are added at once.
* LoginForm when multiple fields are added at once.
*
* @type {WeakMap}
*/
@ -212,8 +198,7 @@ var LoginManagerContent = {
return request;
},
_sendRequest(messageManager, requestData,
name, messageData) {
_sendRequest(messageManager, requestData, name, messageData) {
let count;
if (!(count = this._managers.get(messageManager))) {
this._managers.set(messageManager, 1);
@ -451,12 +436,12 @@ var LoginManagerContent = {
let deferredTask = this._deferredPasswordAddedTasksByRootElement.get(formLike.rootElement);
if (!deferredTask) {
log("Creating a DeferredTask to call _fetchLoginsFromParentAndFillForm soon");
this._formLikeByRootElement.set(formLike.rootElement, formLike);
LoginFormFactory.setForRootElement(formLike.rootElement, formLike);
deferredTask = new DeferredTask(() => {
// Get the updated formLike instead of the one at the time of creating the DeferredTask via
// a closure since it could be stale since FormLike.elements isn't live.
let formLike2 = this._formLikeByRootElement.get(formLike.rootElement);
// Get the updated LoginForm instead of the one at the time of creating the DeferredTask via
// a closure since it could be stale since LoginForm.elements isn't live.
let formLike2 = LoginFormFactory.getForRootElement(formLike.rootElement);
log("Running deferred processing of onDOMInputPasswordAdded", formLike2);
this._deferredPasswordAddedTasksByRootElement.delete(formLike2.rootElement);
this._fetchLoginsFromParentAndFillForm(formLike2);
@ -467,10 +452,10 @@ var LoginManagerContent = {
let window = pwField.ownerGlobal;
if (deferredTask.isArmed) {
log("DeferredTask is already armed so just updating the FormLike");
// We update the FormLike so it (most important .elements) is fresh when the task eventually
log("DeferredTask is already armed so just updating the LoginForm");
// We update the LoginForm so it (most important .elements) is fresh when the task eventually
// runs since changes to the elements could affect our field heuristics.
this._formLikeByRootElement.set(formLike.rootElement, formLike);
LoginFormFactory.setForRootElement(formLike.rootElement, formLike);
} else if (window.document.readyState == "complete") {
log("Arming the DeferredTask we just created since document.readyState == 'complete'");
deferredTask.arm();
@ -485,7 +470,7 @@ var LoginManagerContent = {
/**
* Fetch logins from the parent for a given form and then attempt to fill it.
*
* @param {FormLike} form to fetch the logins for then try autofill.
* @param {LoginForm} form to fetch the logins for then try autofill.
*/
_fetchLoginsFromParentAndFillForm(form) {
let window = form.ownerDocument.defaultView;
@ -526,7 +511,6 @@ var LoginManagerContent = {
* Keeps track of filled fields and values.
*/
fillsByRootElement: new WeakMap(),
loginFormRootElements: new WeakSet(),
};
this.loginFormStateByDocument.set(document, loginFormState);
}
@ -543,7 +527,7 @@ var LoginManagerContent = {
// Returns true if this window or any subframes have insecure login forms.
let hasInsecureLoginForms = (thisWindow) => {
let doc = thisWindow.document;
let rootElsWeakSet = this.stateForDocument(doc).loginFormRootElements;
let rootElsWeakSet = LoginFormFactory.getRootElementsWeakSetForDocument(doc);
let hasLoginForm = ChromeUtils.nondeterministicGetWeakSetKeys(rootElsWeakSet)
.filter(el => el.isConnected).length > 0;
return (hasLoginForm && !thisWindow.isSecureContext) ||
@ -726,7 +710,7 @@ var LoginManagerContent = {
},
/**
* @param {FormLike} form - the FormLike to look for password fields in.
* @param {LoginForm} form - the LoginForm to look for password fields in.
* @param {Object} options
* @param {bool} [options.skipEmptyFields=false] - Whether to ignore password fields with no value.
* Used at capture time since saving empty values isn't
@ -785,7 +769,7 @@ var LoginManagerContent = {
* Can handle complex forms by trying to figure out what the
* relevant fields are.
*
* @param {FormLike} form
* @param {LoginForm} form
* @param {bool} isSubmission
* @param {Set} recipes
* @return {Array} [usernameField, newPasswordField, oldPasswordField]
@ -797,9 +781,9 @@ var LoginManagerContent = {
* change-password field, with oldPasswordField containing the password
* that is being changed.
*
* Note that even though we can create a FormLike from a text field,
* Note that even though we can create a LoginForm from a text field,
* this method will only return a non-null usernameField if the
* FormLike has a password field.
* LoginForm has a password field.
*/
_getFormFields(form, isSubmission, recipes) {
var usernameField = null;
@ -811,7 +795,7 @@ var LoginManagerContent = {
fieldOverrideRecipe.passwordSelector
);
if (pwOverrideField) {
// The field from the password override may be in a different FormLike.
// The field from the password override may be in a different LoginForm.
let formLike = LoginFormFactory.createFromField(pwOverrideField);
pwFields = [{
index: [...formLike.elements].indexOf(pwOverrideField),
@ -937,22 +921,21 @@ var LoginManagerContent = {
},
/**
* Trigger capture on any relevant FormLikes due to a navigation alone (not
* Trigger capture on any relevant LoginForms due to a navigation alone (not
* necessarily due to an actual form submission). This method is used to
* capture logins for cases where form submit events are not used.
*
* To avoid multiple notifications for the same FormLike, this currently
* To avoid multiple notifications for the same LoginForm, this currently
* avoids capturing when dealing with a real <form> which are ideally already
* using a submit event.
*
* @param {Document} document being navigated
*/
_onNavigation(aDocument) {
let state = this.stateForDocument(aDocument);
let rootElsWeakSet = state.loginFormRootElements;
let rootElsWeakSet = LoginFormFactory.getRootElementsWeakSetForDocument(aDocument);
let weakLoginFormRootElements = ChromeUtils.nondeterministicGetWeakSetKeys(rootElsWeakSet);
log("_onNavigation: state:", state, "loginFormRootElements approx size:", weakLoginFormRootElements.length,
log("_onNavigation: root elements approx size:", weakLoginFormRootElements.length,
"document:", aDocument);
for (let formRoot of weakLoginFormRootElements) {
@ -961,14 +944,14 @@ var LoginManagerContent = {
}
if (ChromeUtils.getClassName(formRoot) === "HTMLFormElement") {
// For now only perform capture upon navigation for FormLike's without
// For now only perform capture upon navigation for LoginForm's without
// a <form> to avoid capture from both a DOMFormBeforeSubmit event and
// navigation for the same "form".
log("Ignoring navigation for the form root to avoid multiple prompts " +
"since it was for a real <form>");
continue;
}
let formLike = this._formLikeByRootElement.get(formRoot);
let formLike = LoginFormFactory.getForRootElement(formRoot);
this._onFormSubmit(formLike);
}
},
@ -979,7 +962,7 @@ var LoginManagerContent = {
* Looks for a password change in the submitted form, so we can update
* our stored password.
*
* @param {FormLike} form
* @param {LoginForm} form
*/
_onFormSubmit(form) {
log("_onFormSubmit", form);
@ -1118,11 +1101,10 @@ var LoginManagerContent = {
userTriggered = false,
} = {}) {
if (ChromeUtils.getClassName(form) === "HTMLFormElement") {
throw new Error("_fillForm should only be called with FormLike objects");
throw new Error("_fillForm should only be called with LoginForm objects");
}
log("_fillForm", form.elements);
let ignoreAutocomplete = true;
// Will be set to one of AUTOFILL_RESULT in the `try` block.
let autofillResult = -1;
const AUTOFILL_RESULT = {
@ -1214,13 +1196,6 @@ var LoginManagerContent = {
return;
}
var isAutocompleteOff = false;
if (this._isAutocompleteDisabled(form) ||
this._isAutocompleteDisabled(usernameField) ||
this._isAutocompleteDisabled(passwordField)) {
isAutocompleteOff = true;
}
// Discard logins which have username/password values that don't
// fit into the fields (as specified by the maxlength attribute).
// The user couldn't enter these values anyway, and it helps
@ -1252,9 +1227,11 @@ var LoginManagerContent = {
return;
}
const passwordACFieldName = passwordField.getAutocompleteInfo().fieldName;
// If the password field has the autocomplete value of "new-password"
// and we're autofilling without user interaction, there's nothing to do.
if (!userTriggered && passwordField.getAutocompleteInfo().fieldName == "new-password") {
if (!userTriggered && passwordACFieldName == "new-password") {
log("not filling form, password field has the autocomplete new-password value");
autofillResult = AUTOFILL_RESULT.PASSWORD_AUTOCOMPLETE_NEW_PASSWORD;
return;
@ -1325,8 +1302,8 @@ var LoginManagerContent = {
return;
}
if (isAutocompleteOff && !ignoreAutocomplete) {
log("Not filling the login because we're respecting autocomplete=off");
if (!userTriggered && passwordACFieldName == "off" && !LoginHelper.autofillAutocompleteOff) {
log("Not autofilling the login because we're respecting autocomplete=off");
autofillResult = AUTOFILL_RESULT.AUTOCOMPLETE_OFF;
return;
}
@ -1334,7 +1311,7 @@ var LoginManagerContent = {
// Fill the form
if (usernameField) {
// Don't modify the username field if it's disabled or readOnly so we preserve its case.
// Don't modify the username field if it's disabled or readOnly so we preserve its case.
let disabledOrReadOnly = usernameField.disabled || usernameField.readOnly;
let userNameDiffers = selectedLogin.username != usernameField.value;
@ -1415,21 +1392,21 @@ var LoginManagerContent = {
* method doesn't need to since it's only returning a boolean based upon the
* recipes used for the last fill (in _fillForm).
*
* @param {HTMLInputElement} aUsernameField element contained in a FormLike
* cached in _formLikeByRootElement.
* @param {HTMLInputElement} aUsernameField element contained in a LoginForm
* cached in LoginFormFactory.
* @returns {Boolean} whether the username and password fields still have the
* last-filled values, if previously filled.
*/
_isLoginAlreadyFilled(aUsernameField) {
let formLikeRoot = FormLikeFactory.findRootForField(aUsernameField);
// Look for the existing FormLike.
let existingFormLike = this._formLikeByRootElement.get(formLikeRoot);
if (!existingFormLike) {
// Look for the existing LoginForm.
let existingLoginForm = LoginFormFactory.getForRootElement(formLikeRoot);
if (!existingLoginForm) {
throw new Error("_isLoginAlreadyFilled called with a username field with " +
"no rootElement FormLike");
"no rootElement LoginForm");
}
log("_isLoginAlreadyFilled: existingFormLike", existingFormLike);
log("_isLoginAlreadyFilled: existingLoginForm", existingLoginForm);
let filledLogin = this.stateForDocument(aUsernameField.ownerDocument).fillsByRootElement.get(formLikeRoot);
if (!filledLogin) {
return false;
@ -1480,13 +1457,13 @@ var LoginManagerContent = {
/**
* Verify if a field is a valid login form field and
* returns some information about it's FormLike.
* returns some information about it's LoginForm.
*
* @param {Element} aField
* A form field we want to verify.
*
* @returns {Object} an object with information about the
* FormLike username and password field
* LoginForm username and password field
* or null if the passed field is invalid.
*/
getFieldContext(aField) {
@ -1498,8 +1475,7 @@ var LoginManagerContent = {
return null;
}
let [usernameField, newPasswordField] =
this.getUserNameAndPasswordFields(aField);
let [usernameField, newPasswordField] = this.getUserNameAndPasswordFields(aField);
// If we are not verifying a password field, we want
// to use aField as the username field.
@ -1519,70 +1495,3 @@ var LoginManagerContent = {
};
},
};
/**
* A factory to generate FormLike objects that represent a set of login fields
* which aren't necessarily marked up with a <form> element.
*/
var LoginFormFactory = {
/**
* Create a LoginForm object from a <form>.
*
* @param {HTMLFormElement} aForm
* @return {LoginForm}
* @throws Error if aForm isn't an HTMLFormElement
*/
createFromForm(aForm) {
let formLike = FormLikeFactory.createFromForm(aForm);
formLike.action = LoginHelper.getFormActionOrigin(aForm);
let state = LoginManagerContent.stateForDocument(formLike.ownerDocument);
state.loginFormRootElements.add(formLike.rootElement);
log("adding", formLike.rootElement, "to loginFormRootElements for", formLike.ownerDocument);
LoginManagerContent._formLikeByRootElement.set(formLike.rootElement, formLike);
return formLike;
},
/**
* Create a LoginForm object from a password or username field.
*
* If the field is in a <form>, construct the LoginForm from the form.
* Otherwise, create a LoginForm with a rootElement (wrapper) according to
* heuristics. Currently all <input> not in a <form> are one LoginForm but this
* shouldn't be relied upon as the heuristics may change to detect multiple
* "forms" (e.g. registration and login) on one page with a <form>.
*
* Note that two LoginForms created from the same field won't return the same LoginForm object.
* Use the `rootElement` property on the LoginForm as a key instead.
*
* @param {HTMLInputElement} aField - a password or username field in a document
* @return {LoginForm}
* @throws Error if aField isn't a password or username field in a document
*/
createFromField(aField) {
if (ChromeUtils.getClassName(aField) !== "HTMLInputElement" ||
(aField.type != "password" && !LoginHelper.isUsernameFieldType(aField)) ||
!aField.ownerDocument) {
throw new Error("createFromField requires a password or username field in a document");
}
if (aField.form) {
return this.createFromForm(aField.form);
}
let formLike = FormLikeFactory.createFromField(aField);
formLike.action = LoginHelper.getLoginOrigin(aField.ownerDocument.baseURI);
log("Created non-form FormLike for rootElement:", aField.ownerDocument.documentElement);
let state = LoginManagerContent.stateForDocument(formLike.ownerDocument);
state.loginFormRootElements.add(formLike.rootElement);
log("adding", formLike.rootElement, "to loginFormRootElements for", formLike.ownerDocument);
LoginManagerContent._formLikeByRootElement.set(formLike.rootElement, formLike);
return formLike;
},
};

View file

@ -32,6 +32,7 @@ EXTRA_JS_MODULES += [
'crypto-SDR.js',
'InsecurePasswordUtils.jsm',
'LoginAutoCompleteResult.jsm',
'LoginFormFactory.jsm',
'LoginHelper.jsm',
'LoginInfo.jsm',
'LoginManager.jsm',

View file

@ -36,7 +36,8 @@ add_task(async function test() {
// Convert the login object to a plain JS object for passing across process boundaries.
login = LoginHelper.loginToVanillaObject(login);
ContentTask.spawn(tab.linkedBrowser, {login, usernameRequested}, async ({login: addedLogin, usernameRequested: aUsernameRequested}) => {
const { LoginManagerContent, LoginFormFactory } = ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm");
const { LoginFormFactory } = ChromeUtils.import("resource://gre/modules/LoginFormFactory.jsm");
const { LoginManagerContent } = ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm");
const { LoginHelper } = ChromeUtils.import("resource://gre/modules/LoginHelper.jsm");
let password = content.document.querySelector("#form-basic-password");

View file

@ -51,6 +51,9 @@ skip-if = toolkit == 'android' # autocomplete
[test_basic_form_3pw_1.html]
[test_basic_form_autocomplete.html]
skip-if = toolkit == 'android' # android:autocomplete.
[test_basic_form_honor_autocomplete_off.html]
scheme = https
skip-if = toolkit == 'android' # android:autocomplete.
[test_insecure_form_field_autocomplete.html]
skip-if = toolkit == 'android' || os == 'linux' # android:autocomplete., linux: bug 1325778
[test_password_field_autocomplete.html]

View file

@ -0,0 +1,165 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test login autofill autocomplete when signon.autofillForms.autocompleteOff is false</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/AddTask.js"></script>
<script type="text/javascript" src="../../../satchel/test/satchel_common.js"></script>
<script type="text/javascript" src="pwmgr_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
Login Manager test: autofilling when autocomplete=off
<script>
let readyPromise = registerRunTests();
runInParent(function setup() {
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
// Create some logins just for this form, since we'll be deleting them.
const nsLoginInfo = Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
Ci.nsILoginInfo, "init");
assert.ok(nsLoginInfo != null, "nsLoginInfo constructor");
const login = new nsLoginInfo("https://example.com", "https://autocomplete2", null,
"singleuser", "singlepass", "uname", "pword");
Services.logins.addLogin(login);
});
</script>
<p id="display"></p>
<!-- we presumably can't hide the content for this test. -->
<div id="content">
<!-- test single logins, with autocomplete=off set -->
<form id="form1" action="https://autocomplete2" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="off">
<button type="submit">Submit</button>
</form>
<form id="form2" action="https://autocomplete2" onsubmit="return false;">
<input type="text" name="uname" autocomplete="off">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<form id="form3" action="https://autocomplete2" onsubmit="return false;" autocomplete="off">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<form id="form4" action="https://autocomplete2" onsubmit="return false;">
<input type="text" name="uname" autocomplete="off">
<input type="password" name="pword" autocomplete="off">
<button type="submit">Submit</button>
</form>
<!-- control -->
<form id="form5" action="https://autocomplete2" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Login Manager: multiple login autocomplete. **/
let {ContentTaskUtils} = SpecialPowers.Cu.import("resource://testing-common/ContentTaskUtils.jsm", {});
// Set the pref before the document loads.
SpecialPowers.setBoolPref("signon.autofillForms.autocompleteOff", false);
SimpleTest.registerCleanupFunction(() => {
SpecialPowers.clearUserPref("signon.autofillForms.autocompleteOff");
});
// Check for expected username/password in form.
function checkFormValues(form, expectedUsername, expectedPassword) {
let uname = form.querySelector("[name='uname']");
let pword = form.querySelector("[name='pword']");
is(uname.value, expectedUsername, `Checking ${form.id} username is: ${expectedUsername}`);
is(pword.value, expectedPassword, `Checking ${form.id} password is: ${expectedPassword}`);
}
async function autoCompleteFieldsFromFirstMatch(form) {
// trigger autocomplete from the username field
await SimpleTest.promiseFocus(form.ownerGlobal);
let uname = form.querySelector("[name='uname']");
let shownPromise = promiseACShown();
uname.focus();
await shownPromise;
let formFilled = promiseFormsProcessed();
await synthesizeKey("KEY_ArrowDown"); // open
await synthesizeKey("KEY_Enter");
await formFilled;
await Promise.resolve();
}
add_task(async function setup() {
ok(readyPromise, "check promise is available");
await readyPromise;
listenForUnexpectedPopupShown();
});
/* Tests for autofill of single-user forms for when we honor autocomplete=off on password fields */
add_task(async function test_form1_honor_password_autocomplete_off() {
await SimpleTest.promiseFocus(window);
// With the pref toggled off, and with autocomplete=off on the password field,
// we expect not to have autofilled this form
let form = document.getElementById("form1");
ok(form, "found form under test");
checkFormValues(form, "", "");
// ..but it should autocomplete just fine
await autoCompleteFieldsFromFirstMatch(form);
checkFormValues(form, "singleuser", "singlepass");
});
add_task(async function test_form2_honor_password_autocomplete_off() {
await SimpleTest.promiseFocus(window);
// With the pref toggled off, and with autocomplete=off on the username field,
// we expect to have autofilled this form
let form = document.getElementById("form2");
ok(form, "found form under test");
checkFormValues(form, "singleuser", "singlepass");
});
add_task(async function test_form3_honor_password_autocomplete_off() {
await SimpleTest.promiseFocus(window);
// With the pref toggled off, and with autocomplete=off on the form,
// we expect to have autofilled this form
let form = document.getElementById("form3");
ok(form, "found form under test");
checkFormValues(form, "singleuser", "singlepass");
});
add_task(async function test_form4_honor_password_autocomplete_off() {
await SimpleTest.promiseFocus(window);
// With the pref toggled off, and autocomplete=off on the username and password field,
// we expect not to have autofilled this form
let form = document.getElementById("form4");
ok(form, "found form under test");
checkFormValues(form, "", "");
// ..but it should autocomplete just fine
await autoCompleteFieldsFromFirstMatch(form);
checkFormValues(form, "singleuser", "singlepass");
});
add_task(async function test_form5() {
await SimpleTest.promiseFocus(window);
// (this is a control, w/o autocomplete=off, to ensure the login
// that was being suppressed would have been filled in otherwise)
let form = document.getElementById("form5");
ok(form, "found form under test");
checkFormValues(form, "singleuser", "singlepass");
});
</script>
</pre>
</body>
</html>

View file

@ -10,8 +10,9 @@
</head>
<body>
<script type="application/javascript">
const {LoginFormFactory} = SpecialPowers.Cu.import("resource://gre/modules/LoginFormFactory.jsm");
const LMCBackstagePass = SpecialPowers.Cu.import("resource://gre/modules/LoginManagerContent.jsm");
const { LoginManagerContent, LoginFormFactory } = LMCBackstagePass;
const { LoginManagerContent } = LMCBackstagePass;
let loadPromise = new Promise(resolve => {
document.addEventListener("DOMContentLoaded", () => {

View file

@ -11,7 +11,7 @@
<body>
<script type="application/javascript">
const LMCBackstagePass = SpecialPowers.Cu.import("resource://gre/modules/LoginManagerContent.jsm");
const { LoginManagerContent, LoginFormFactory } = LMCBackstagePass;
const { LoginManagerContent } = LMCBackstagePass;
let loadPromise = new Promise(resolve => {
document.addEventListener("DOMContentLoaded", () => {

View file

@ -11,7 +11,7 @@
<body>
<script type="application/javascript">
const LMCBackstagePass = SpecialPowers.Cu.import("resource://gre/modules/LoginManagerContent.jsm");
const { LoginManagerContent, LoginFormFactory } = LMCBackstagePass;
const { LoginManagerContent } = LMCBackstagePass;
SimpleTest.requestFlakyTimeout("Testing that a message doesn't arrive");

View file

@ -8,8 +8,9 @@
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
const {LoginFormFactory} = ChromeUtils.import("resource://gre/modules/LoginFormFactory.jsm");
const LMCBackstagePass = ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm", null);
const { LoginManagerContent, LoginFormFactory } = LMCBackstagePass;
const { LoginManagerContent } = LMCBackstagePass;
const TESTCASES = [
{
description: "1 password field outside of a <form>",

View file

@ -4,8 +4,9 @@
"use strict";
const {LoginFormFactory} = ChromeUtils.import("resource://gre/modules/LoginFormFactory.jsm");
const LMCBackstagePass = ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm", null);
const { LoginManagerContent, LoginFormFactory } = LMCBackstagePass;
const { LoginManagerContent } = LMCBackstagePass;
const TESTCASES = [
{
description: "Empty document",

View file

@ -7,7 +7,7 @@
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
const LMCBackstagePass = ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm", null);
const { LoginManagerContent, LoginFormFactory } = LMCBackstagePass;
const { LoginManagerContent } = LMCBackstagePass;
const TESTCASES = [
{
description: "1 password field outside of a <form>",

View file

@ -331,5 +331,26 @@ function restart(safeMode) {
}
window.addEventListener("DOMContentLoaded", function() {
// Check if any profiles are missing on the disk and if so remove them.
// We cannot remove profiles while iterating the list returned from the
// profile service, so convert it to a new array first.
try {
let changed = false;
for (let profile of [...ProfileService.profiles]) {
if (!profile.rootDir.exists() || !profile.rootDir.isDirectory()) {
profile.remove(false);
changed = true;
}
}
if (changed) {
ProfileService.flush();
}
} catch (e) {
// There shouldn't be any failures to catch here, but just in case let the
// UI build itself properly.
Cu.reportError(e);
}
refreshUI();
}, {once: true});

View file

@ -8,7 +8,8 @@
// a block to prevent accidentally leaking globals onto `window`.
{
class MozWizardPage extends MozXULElement {
connectedCallback() {
constructor() {
super();
this.pageIndex = -1;
}
get pageid() {

View file

@ -24,6 +24,23 @@ function startup() {
gProfileService = C[ToolkitProfileService].getService(I.nsIToolkitProfileService);
// Check if any profiles are missing on the disk and if so remove them.
// We cannot remove profiles while iterating the list returned from the
// profile service, so convert it to a new array first.
try {
for (let profile of [...gProfileService.profiles]) {
if (!profile.rootDir.exists() || !profile.rootDir.isDirectory()) {
profile.remove(false);
}
}
// The profile service is always flushed after this dialog completes.
} catch (e) {
// There shouldn't be any failures to catch here, but just in case let the
// UI build itself properly.
Cu.reportError(e);
}
gProfileManagerBundle = document.getElementById("bundle_profileManager");
gBrandBundle = document.getElementById("bundle_brand");

View file

@ -125,7 +125,6 @@
"log.js": ["Log"],
"logger.jsm": ["Logger"],
"logging.js": ["getTestLogger", "initTestLogging"],
"LoginManagerContent.jsm": ["LoginManagerContent", "LoginFormFactory"],
"LoginRecipes.jsm": ["LoginRecipesContent", "LoginRecipesParent"],
"logmanager.js": ["LogManager"],
"lz4.js": ["Lz4"],