зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. r=merge a=merge CLOSED TREE
This commit is contained in:
Коммит
48e5c9892f
|
@ -68,6 +68,7 @@ toolbar[customizable="true"] {
|
|||
}
|
||||
|
||||
panelmultiview {
|
||||
-moz-box-align: start;
|
||||
-moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelmultiview");
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,21 @@ add_task(async function() {
|
|||
BrowserTestUtils.addTab(gBrowser);
|
||||
BrowserTestUtils.addTab(gBrowser);
|
||||
|
||||
// While doing this test, we should make sure the selected tab in the tab
|
||||
// preview is not changed by mouse events. That may happen after closing
|
||||
// the selected tab with ctrl+W. Disable all mouse events to prevent it.
|
||||
for (let node of ctrlTab.previews) {
|
||||
node.style.pointerEvents = "none";
|
||||
}
|
||||
registerCleanupFunction(function() {
|
||||
for (let node of ctrlTab.previews) {
|
||||
try {
|
||||
node.style.removeProperty("pointer-events");
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
checkTabs(4);
|
||||
|
||||
await ctrlTabTest([2], 1, 0);
|
||||
|
|
|
@ -75,7 +75,7 @@ add_task(async function testExceptionAddition() {
|
|||
await UrlClassifierTestUtils.addTestTrackers();
|
||||
let privateWin = await promiseOpenAndLoadWindow({private: true}, true);
|
||||
browser = privateWin.gBrowser;
|
||||
let tab = browser.selectedTab = browser.addTab();
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab({ gBrowser: browser, waitForLoad: true, waitForStateStop: true });
|
||||
|
||||
TrackingProtection = browser.ownerGlobal.TrackingProtection;
|
||||
await pushPrefs([PB_PREF, true]);
|
||||
|
@ -109,7 +109,7 @@ add_task(async function testExceptionPersistence() {
|
|||
info("Open another private browsing window");
|
||||
let privateWin = await promiseOpenAndLoadWindow({private: true}, true);
|
||||
browser = privateWin.gBrowser;
|
||||
let tab = browser.selectedTab = browser.addTab();
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab({ gBrowser: browser, waitForLoad: true, waitForStateStop: true });
|
||||
|
||||
TrackingProtection = browser.ownerGlobal.TrackingProtection;
|
||||
ok(TrackingProtection.enabled, "TP is still enabled");
|
||||
|
|
|
@ -223,7 +223,7 @@ function promiseWindowWillBeClosed(win) {
|
|||
Services.obs.addObserver(function observe(subject, topic) {
|
||||
if (subject == win) {
|
||||
Services.obs.removeObserver(observe, topic);
|
||||
resolve();
|
||||
executeSoon(resolve);
|
||||
}
|
||||
}, "domwindowclosed");
|
||||
});
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
[DEFAULT]
|
||||
# to avoid overhead when running the browser normally, startupRecorder.js will
|
||||
# do almost nothing unless browser.startup.record is true.
|
||||
# gfx.canvas.willReadFrequently.enable is just an optimization, but needs to be
|
||||
# set during early startup to have an impact as a canvas will be used by
|
||||
# startupRecorder.js
|
||||
prefs =
|
||||
browser.startup.record=true
|
||||
gfx.canvas.willReadFrequently.enable=true
|
||||
support-files =
|
||||
head.js
|
||||
[browser_appmenu_reflows.js]
|
||||
|
@ -9,6 +15,7 @@ skip-if = asan || debug # Bug 1382809, bug 1369959
|
|||
[browser_startup.js]
|
||||
[browser_startup_content.js]
|
||||
skip-if = !e10s
|
||||
[browser_startup_flicker.js]
|
||||
[browser_tabclose_grow_reflows.js]
|
||||
[browser_tabclose_reflows.js]
|
||||
[browser_tabopen_reflows.js]
|
||||
|
@ -20,5 +27,7 @@ skip-if = !e10s
|
|||
skip-if = (os == 'linux') || (os == 'win' && debug) # Disabled on Linux and Windows debug due to perma failures. Bug 1392320.
|
||||
[browser_urlbar_search_reflows.js]
|
||||
[browser_windowclose_reflows.js]
|
||||
[browser_windowopen_flicker.js]
|
||||
skip-if = (debug && os == 'win') # Disabled on windows debug for intermittent leaks
|
||||
[browser_windowopen_reflows.js]
|
||||
skip-if = os == 'linux' # Disabled due to frequent failures. Bug 1380465.
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* This test ensures that there is no unexpected flicker
|
||||
* on the first window opened during startup.
|
||||
*/
|
||||
|
||||
add_task(async function() {
|
||||
let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
|
||||
await startupRecorder.done;
|
||||
|
||||
// Ensure all the frame data is in the test compartment to avoid traversing
|
||||
// a cross compartment wrapper for each pixel.
|
||||
let frames = Cu.cloneInto(startupRecorder.data.frames, {});
|
||||
|
||||
let unexpectedRects = 0;
|
||||
let alreadyFocused = false;
|
||||
for (let i = 1; i < frames.length; ++i) {
|
||||
let frame = frames[i], previousFrame = frames[i - 1];
|
||||
let rects = compareFrames(frame, previousFrame);
|
||||
|
||||
// The first screenshot we get shows an unfocused browser window for some
|
||||
// reason. This is likely due to the test harness, so we want to ignore it.
|
||||
// We'll assume the changes we are seeing are due to this focus change if
|
||||
// there are at least 5 areas that changed near the top of the screen, but
|
||||
// will only ignore this once (hence the alreadyFocused variable).
|
||||
if (!alreadyFocused && rects.length > 5 && rects.every(r => r.y2 < 100)) {
|
||||
alreadyFocused = true;
|
||||
// This is likely an issue caused by the test harness, but log it anyway.
|
||||
todo(false,
|
||||
"the window should be focused at first paint, " + rects.toSource());
|
||||
continue;
|
||||
}
|
||||
|
||||
rects = rects.filter(rect => {
|
||||
let inRange = (val, min, max) => min <= val && val <= max;
|
||||
let width = frame.width;
|
||||
|
||||
let exceptions = [
|
||||
{name: "bug 1403648 - urlbar down arrow shouldn't flicker",
|
||||
condition: r => r.h == 5 && inRange(r.w, 8, 9) && // 5x9px area
|
||||
inRange(r.y1, 40, 80) && // in the toolbar
|
||||
// at ~80% of the window width
|
||||
inRange(r.x1, width * .75, width * .9)
|
||||
},
|
||||
|
||||
{name: "bug 1394914 - sidebar toolbar icon should be visible at first paint",
|
||||
condition: r => r.h == 13 && inRange(r.w, 14, 16) && // icon size
|
||||
inRange(r.y1, 40, 80) && // in the toolbar
|
||||
// near the right end of screen
|
||||
inRange(r.x1, width - 100, width - 50)
|
||||
},
|
||||
|
||||
{name: "bug 1403648 - urlbar should be focused at first paint",
|
||||
condition: r => inRange(r.y2, 60, 80) && // in the toolbar
|
||||
// taking 50% to 75% of the window width
|
||||
inRange(r.w, width * .5, width * .75) &&
|
||||
// starting at 15 to 25% of the window width
|
||||
inRange(r.x1, width * .15, width * .25)
|
||||
},
|
||||
|
||||
{name: "bug 1421460 - restore icon should be visible at first paint",
|
||||
condition: r => r.w == 9 && r.h == 9 && // 9x9 icon
|
||||
AppConstants.platform == "win" &&
|
||||
// near the right end of the screen
|
||||
inRange(r.x1, width - 80, width - 70)
|
||||
},
|
||||
];
|
||||
|
||||
let rectText = `${rect.toSource()}, window width: ${width}`;
|
||||
for (let e of exceptions) {
|
||||
if (e.condition(rect)) {
|
||||
todo(false, e.name + ", " + rectText);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ok(false, "unexpected changed rect: " + rectText);
|
||||
return true;
|
||||
});
|
||||
if (!rects.length) {
|
||||
info("ignoring identical frame");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Before dumping a frame with unexpected differences for the first time,
|
||||
// ensure at least one previous frame has been logged so that it's possible
|
||||
// to see the differences when examining the log.
|
||||
if (!unexpectedRects) {
|
||||
dumpFrame(previousFrame);
|
||||
}
|
||||
unexpectedRects += rects.length;
|
||||
dumpFrame(frame);
|
||||
}
|
||||
is(unexpectedRects, 0, "should have 0 unknown flickering areas");
|
||||
});
|
|
@ -0,0 +1,151 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* This test ensures that there is no unexpected flicker
|
||||
* when opening new windows.
|
||||
*/
|
||||
|
||||
add_task(async function() {
|
||||
// Flushing all caches helps to ensure that we get consistent
|
||||
// behaviour when opening a new window, even if windows have been
|
||||
// opened in previous tests.
|
||||
Services.obs.notifyObservers(null, "startupcache-invalidate");
|
||||
Services.obs.notifyObservers(null, "chrome-flush-skin-caches");
|
||||
Services.obs.notifyObservers(null, "chrome-flush-caches");
|
||||
|
||||
let win = window.openDialog("chrome://browser/content/", "_blank",
|
||||
"chrome,all,dialog=no,remote,suppressanimation",
|
||||
"about:home");
|
||||
|
||||
// Avoid showing the remotecontrol UI.
|
||||
await new Promise(resolve => {
|
||||
win.addEventListener("DOMContentLoaded", () => {
|
||||
delete win.Marionette;
|
||||
win.Marionette = {running: false};
|
||||
resolve();
|
||||
}, {once: true});
|
||||
});
|
||||
|
||||
let canvas = win.document.createElementNS("http://www.w3.org/1999/xhtml",
|
||||
"canvas");
|
||||
canvas.mozOpaque = true;
|
||||
let ctx = canvas.getContext("2d", {alpha: false, willReadFrequently: true});
|
||||
|
||||
let frames = [];
|
||||
|
||||
let afterPaintListener = event => {
|
||||
let width, height;
|
||||
canvas.width = width = win.innerWidth;
|
||||
canvas.height = height = win.innerHeight;
|
||||
ctx.drawWindow(win, 0, 0, width, height, "white",
|
||||
ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_VIEW |
|
||||
ctx.DRAWWINDOW_ASYNC_DECODE_IMAGES |
|
||||
ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
|
||||
frames.push({data: Cu.cloneInto(ctx.getImageData(0, 0, width, height).data, {}),
|
||||
width, height});
|
||||
};
|
||||
win.addEventListener("MozAfterPaint", afterPaintListener);
|
||||
|
||||
await TestUtils.topicObserved("browser-delayed-startup-finished",
|
||||
subject => subject == win);
|
||||
|
||||
await BrowserTestUtils.firstBrowserLoaded(win, false);
|
||||
await BrowserTestUtils.browserStopped(win.gBrowser.selectedBrowser, "about:home");
|
||||
|
||||
await new Promise(resolve => {
|
||||
// 10 is an arbitrary value here, it needs to be at least 2 to avoid
|
||||
// races with code initializing itself using idle callbacks.
|
||||
(function waitForIdle(count = 10) {
|
||||
if (!count) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
waitForIdle(count - 1);
|
||||
});
|
||||
})();
|
||||
});
|
||||
win.removeEventListener("MozAfterPaint", afterPaintListener);
|
||||
|
||||
let unexpectedRects = 0;
|
||||
let foundTinyPaint = false;
|
||||
for (let i = 1; i < frames.length; ++i) {
|
||||
let frame = frames[i], previousFrame = frames[i - 1];
|
||||
if (!foundTinyPaint &&
|
||||
previousFrame.width == 1 && previousFrame.height == 1) {
|
||||
foundTinyPaint = true;
|
||||
todo(false, "shouldn't first paint a 1x1px window");
|
||||
continue;
|
||||
}
|
||||
|
||||
let rects = compareFrames(frame, previousFrame).filter(rect => {
|
||||
let inRange = (val, min, max) => min <= val && val <= max;
|
||||
let width = frame.width;
|
||||
|
||||
const spaceBeforeFirstTab = AppConstants.platform == "macosx" ? 100 : 0;
|
||||
let inFirstTab = r =>
|
||||
inRange(r.x1, spaceBeforeFirstTab, spaceBeforeFirstTab + 50) && r.y1 < 30;
|
||||
|
||||
let exceptions = [
|
||||
{name: "bug 1403648 - urlbar down arrow shouldn't flicker",
|
||||
condition: r => r.h == 5 && inRange(r.w, 8, 9) && // 5x9px area
|
||||
inRange(r.y1, 40, 80) && // in the toolbar
|
||||
// at ~80% of the window width
|
||||
inRange(r.x1, width * .75, width * .9)
|
||||
},
|
||||
|
||||
{name: "bug 1394914 - sidebar toolbar icon should be visible at first paint",
|
||||
condition: r => r.h == 13 && inRange(r.w, 14, 16) && // icon size
|
||||
inRange(r.y1, 40, 80) && // in the toolbar
|
||||
// near the right end of screen
|
||||
inRange(r.x1, width - 100, width - 50)
|
||||
},
|
||||
|
||||
{name: "bug 1421463 - reload toolbar icon shouldn't flicker",
|
||||
condition: r => r.h == 13 && inRange(r.w, 14, 16) && // icon size
|
||||
inRange(r.y1, 40, 80) && // in the toolbar
|
||||
// near the left side of the screen
|
||||
inRange(r.x1, 65, 100)
|
||||
},
|
||||
|
||||
{name: "bug 1401955 - about:home favicon should be visible at first paint",
|
||||
condition: r => inFirstTab(r) && inRange(r.h, 14, 15) && inRange(r.w, 14, 15)
|
||||
},
|
||||
|
||||
{name: "bug 1401955 - space for about:home favicon should be there at first paint",
|
||||
condition: r => inFirstTab(r) && inRange(r.w, 60, 80) && inRange(r.h, 8, 15)
|
||||
},
|
||||
];
|
||||
|
||||
let rectText = `${rect.toSource()}, window width: ${width}`;
|
||||
for (let e of exceptions) {
|
||||
if (e.condition(rect)) {
|
||||
todo(false, e.name + ", " + rectText);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ok(false, "unexpected changed rect: " + rectText);
|
||||
return true;
|
||||
});
|
||||
if (!rects.length) {
|
||||
info("ignoring identical frame");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Before dumping a frame with unexpected differences for the first time,
|
||||
// ensure at least one previous frame has been logged so that it's possible
|
||||
// to see the differences when examining the log.
|
||||
if (!unexpectedRects) {
|
||||
dumpFrame(previousFrame);
|
||||
}
|
||||
unexpectedRects += rects.length;
|
||||
dumpFrame(frame);
|
||||
}
|
||||
is(unexpectedRects, 0, "should have 0 unknown flickering areas");
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
|
@ -269,3 +269,107 @@ async function addDummyHistoryEntries(searchStr = "") {
|
|||
await PlacesUtils.history.clear();
|
||||
});
|
||||
}
|
||||
|
||||
function compareFrames(frame, previousFrame) {
|
||||
// Accessing the Math global is expensive as the test executes in a
|
||||
// non-syntactic scope. Accessing it as a lexical variable is enough
|
||||
// to make the code JIT well.
|
||||
const M = Math;
|
||||
|
||||
function expandRect(x, y, rect) {
|
||||
if (rect.x2 < x)
|
||||
rect.x2 = x;
|
||||
else if (rect.x1 > x)
|
||||
rect.x1 = x;
|
||||
if (rect.y2 < y)
|
||||
rect.y2 = y;
|
||||
}
|
||||
|
||||
function isInRect(x, y, rect) {
|
||||
return (rect.y2 == y || rect.y2 == y - 1) && rect.x1 - 1 <= x && x <= rect.x2 + 1;
|
||||
}
|
||||
|
||||
if (frame.height != previousFrame.height ||
|
||||
frame.width != previousFrame.width) {
|
||||
// If the frames have different sizes, assume the whole window has
|
||||
// been repainted when the window was resized.
|
||||
return [{x1: 0, x2: frame.width, y1: 0, y2: frame.height}];
|
||||
}
|
||||
|
||||
let l = frame.data.length;
|
||||
let different = [];
|
||||
let rects = [];
|
||||
for (let i = 0; i < l; i += 4) {
|
||||
let x = (i / 4) % frame.width;
|
||||
let y = M.floor((i / 4) / frame.width);
|
||||
for (let j = 0; j < 4; ++j) {
|
||||
let index = i + j;
|
||||
|
||||
if (frame.data[index] != previousFrame.data[index]) {
|
||||
let found = false;
|
||||
for (let rect of rects) {
|
||||
if (isInRect(x, y, rect)) {
|
||||
expandRect(x, y, rect);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
rects.unshift({x1: x, x2: x, y1: y, y2: y});
|
||||
|
||||
different.push(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rects.reverse();
|
||||
|
||||
// The following code block merges rects that are close to each other
|
||||
// (less than maxEmptyPixels away).
|
||||
// This is needed to avoid having a rect for each letter when a label moves.
|
||||
const maxEmptyPixels = 3;
|
||||
let areRectsContiguous = function(r1, r2) {
|
||||
return r1.y2 >= r2.y1 - 1 - maxEmptyPixels &&
|
||||
r2.x1 - 1 - maxEmptyPixels <= r1.x2 &&
|
||||
r2.x2 >= r1.x1 - 1 - maxEmptyPixels;
|
||||
};
|
||||
let hasMergedRects;
|
||||
do {
|
||||
hasMergedRects = false;
|
||||
for (let r = rects.length - 1; r > 0; --r) {
|
||||
let rr = rects[r];
|
||||
for (let s = r - 1; s >= 0; --s) {
|
||||
let rs = rects[s];
|
||||
if (areRectsContiguous(rs, rr)) {
|
||||
rs.x1 = Math.min(rs.x1, rr.x1);
|
||||
rs.y1 = Math.min(rs.y1, rr.y1);
|
||||
rs.x2 = Math.max(rs.x2, rr.x2);
|
||||
rs.y2 = Math.max(rs.y2, rr.y2);
|
||||
rects.splice(r, 1);
|
||||
hasMergedRects = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (hasMergedRects);
|
||||
|
||||
// For convenience, pre-compute the width and height of each rect.
|
||||
rects.forEach(r => {
|
||||
r.w = r.x2 - r.x1;
|
||||
r.h = r.y2 - r.y1;
|
||||
});
|
||||
|
||||
return rects;
|
||||
}
|
||||
|
||||
function dumpFrame({data, width, height}) {
|
||||
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
canvas.mozOpaque = true;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
canvas.getContext("2d", {alpha: false, willReadFrequently: true})
|
||||
.putImageData(new ImageData(data, width, height), 0, 0);
|
||||
|
||||
info(canvas.toDataURL());
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ skip-if = debug # bug 1369731
|
|||
[browser_devices_get_user_media_multi_process.js]
|
||||
skip-if = debug && (os == "win" || os == "mac") # bug 1393761
|
||||
[browser_devices_get_user_media_screen.js]
|
||||
skip-if = (os == "win" && ccov) # bug 1421724
|
||||
[browser_devices_get_user_media_tear_off_tab.js]
|
||||
[browser_devices_get_user_media_unprompted_access.js]
|
||||
[browser_devices_get_user_media_unprompted_access_in_frame.js]
|
||||
|
|
|
@ -589,7 +589,9 @@ this.PanelMultiView = class {
|
|||
this._panel.setAttribute("height", rect.height);
|
||||
|
||||
let viewRect;
|
||||
if (viewNode.__lastKnownBoundingRect) {
|
||||
if (reverse && viewNode.__lastKnownBoundingRect) {
|
||||
// Use the cached size when going back to a previous view, but not when
|
||||
// reopening a subview, because its contents may have changed.
|
||||
viewRect = viewNode.__lastKnownBoundingRect;
|
||||
viewNode.setAttribute("in-transition", true);
|
||||
} else if (viewNode.customRectGetter) {
|
||||
|
@ -604,6 +606,8 @@ this.PanelMultiView = class {
|
|||
viewNode.setAttribute("in-transition", true);
|
||||
} else {
|
||||
let oldSibling = viewNode.nextSibling || null;
|
||||
this._offscreenViewStack.style.minHeight =
|
||||
this._viewContainer.style.height;
|
||||
this._offscreenViewStack.appendChild(viewNode);
|
||||
viewNode.setAttribute("in-transition", true);
|
||||
|
||||
|
@ -620,6 +624,8 @@ this.PanelMultiView = class {
|
|||
} catch (ex) {
|
||||
this._viewStack.appendChild(viewNode);
|
||||
}
|
||||
|
||||
this._offscreenViewStack.style.removeProperty("min-height");
|
||||
}
|
||||
|
||||
this._transitioning = true;
|
||||
|
@ -643,7 +649,8 @@ this.PanelMultiView = class {
|
|||
this._viewStack.style.transition = "transform var(--animation-easing-function)" +
|
||||
" var(--panelui-subview-transition-duration)";
|
||||
this._viewStack.style.willChange = "transform";
|
||||
deepestNode.style.borderInlineStart = "1px solid var(--panel-separator-color)";
|
||||
// Use an outline instead of a border so that the size is not affected.
|
||||
deepestNode.style.outline = "1px solid var(--panel-separator-color)";
|
||||
|
||||
// Now set the viewContainer dimensions to that of the new view, which
|
||||
// kicks of the height animation.
|
||||
|
@ -734,7 +741,7 @@ this.PanelMultiView = class {
|
|||
if (reverse)
|
||||
this._viewStack.style.removeProperty("margin-inline-start");
|
||||
let deepestNode = reverse ? previousViewNode : viewNode;
|
||||
deepestNode.style.removeProperty("border-inline-start");
|
||||
deepestNode.style.removeProperty("outline");
|
||||
this._viewStack.style.removeProperty("transition");
|
||||
}
|
||||
if (phase >= TRANSITION_PHASES.TRANSITION) {
|
||||
|
@ -857,6 +864,7 @@ this.PanelMultiView = class {
|
|||
if (this._panel.state == "showing") {
|
||||
let maxHeight = this._calculateMaxHeight();
|
||||
this._viewStack.style.maxHeight = maxHeight + "px";
|
||||
this._offscreenViewStack.style.maxHeight = maxHeight + "px";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -24,12 +24,4 @@ panelmultiview[transitioning] {
|
|||
|
||||
.panel-viewcontainer.offscreen {
|
||||
position: absolute;
|
||||
top: 100000px;
|
||||
left: 100000px;
|
||||
}
|
||||
|
||||
.panel-viewcontainer.offscreen,
|
||||
.panel-viewcontainer.offscreen > .panel-viewstack {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
|
|
@ -630,10 +630,12 @@
|
|||
label="&appMenuRemoteTabs.label;"
|
||||
closemenu="none"
|
||||
oncommand="PanelUI.showSubView('PanelUI-remotetabs', this)"/>
|
||||
<toolbarseparator/>
|
||||
<toolbarseparator hidden="true"/>
|
||||
<label value="&appMenuRecentHighlights.label;"
|
||||
hidden="true"
|
||||
class="subview-subheader"/>
|
||||
<toolbaritem id="appMenu-library-recentHighlights"
|
||||
hidden="true"
|
||||
orient="vertical"
|
||||
smoothscroll="false"
|
||||
flatList="true"
|
||||
|
|
|
@ -28,6 +28,7 @@ const PanelUI = {
|
|||
multiView: "appMenu-multiView",
|
||||
helpView: "PanelUI-helpView",
|
||||
libraryView: "appMenu-libraryView",
|
||||
libraryRecentHighlights: "appMenu-library-recentHighlights",
|
||||
menuButton: "PanelUI-menu-button",
|
||||
panel: "appMenu-popup",
|
||||
notificationPanel: "appMenu-notification-popup",
|
||||
|
@ -305,7 +306,7 @@ const PanelUI = {
|
|||
break;
|
||||
case "ViewShowing":
|
||||
if (aEvent.target == this.libraryView) {
|
||||
this.onLibraryViewShowing(aEvent.target);
|
||||
this.onLibraryViewShowing(aEvent.target).catch(Cu.reportError);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -507,32 +508,51 @@ const PanelUI = {
|
|||
* @param {panelview} viewNode The library view.
|
||||
*/
|
||||
async onLibraryViewShowing(viewNode) {
|
||||
if (this._loadingRecentHighlights) {
|
||||
return;
|
||||
}
|
||||
this._loadingRecentHighlights = true;
|
||||
|
||||
// Since the library is the first view shown, we don't want to add a blocker
|
||||
// to the event, which would make PanelMultiView wait to show it.
|
||||
let container = this.clearLibraryRecentHighlights();
|
||||
if (!this.libraryRecentHighlightsEnabled) {
|
||||
this._loadingRecentHighlights = false;
|
||||
// to the event, which would make PanelMultiView wait to show it. Instead,
|
||||
// we keep the space currently reserved for the items, but we hide them.
|
||||
if (this._loadingRecentHighlights || !this.libraryRecentHighlightsEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make the elements invisible synchronously, before the view is shown.
|
||||
this.makeLibraryRecentHighlightsInvisible();
|
||||
|
||||
// Perform the rest asynchronously while protecting from re-entrancy.
|
||||
this._loadingRecentHighlights = true;
|
||||
try {
|
||||
await this.fetchAndPopulateLibraryRecentHighlights();
|
||||
} finally {
|
||||
this._loadingRecentHighlights = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetches the list of Recent Highlights and replaces the items in the Library
|
||||
* view with the results.
|
||||
*/
|
||||
async fetchAndPopulateLibraryRecentHighlights() {
|
||||
let highlights = await NewTabUtils.activityStreamLinks.getHighlights({
|
||||
// As per bug 1402023, hard-coded limit, until Activity Stream develops a
|
||||
// richer list.
|
||||
numItems: 6,
|
||||
withFavicons: true
|
||||
}).catch(ex => {
|
||||
// Just hide the section if we can't retrieve the items from the database.
|
||||
Cu.reportError(ex);
|
||||
return [];
|
||||
});
|
||||
// If there's nothing to display, or the panel is already hidden, get out.
|
||||
let multiView = viewNode.panelMultiView;
|
||||
if (!highlights.length || (multiView && multiView.getAttribute("panelopen") != "true")) {
|
||||
this._loadingRecentHighlights = false;
|
||||
|
||||
// Since the call above is asynchronous, the panel may be already hidden
|
||||
// at this point, but we still prepare the items for the next time the
|
||||
// panel is shown, so their space is reserved. The part of this function
|
||||
// that adds the elements is the least expensive anyways.
|
||||
this.clearLibraryRecentHighlights();
|
||||
if (!highlights.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let container = this.libraryRecentHighlights;
|
||||
container.hidden = container.previousSibling.hidden =
|
||||
container.previousSibling.previousSibling.hidden = false;
|
||||
let fragment = document.createDocumentFragment();
|
||||
|
@ -551,21 +571,29 @@ const PanelUI = {
|
|||
fragment.appendChild(button);
|
||||
}
|
||||
container.appendChild(fragment);
|
||||
},
|
||||
|
||||
this._loadingRecentHighlights = false;
|
||||
/**
|
||||
* Make all nodes from the 'Recent Highlights' section invisible while we
|
||||
* refresh its contents. This is done while the Library view is opening to
|
||||
* avoid showing potentially stale items, but still keep the space reserved.
|
||||
*/
|
||||
makeLibraryRecentHighlightsInvisible() {
|
||||
for (let button of this.libraryRecentHighlights.children) {
|
||||
button.style.visibility = "hidden";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all the nodes from the 'Recent Highlights' section and hide it as well.
|
||||
*/
|
||||
clearLibraryRecentHighlights() {
|
||||
let container = document.getElementById("appMenu-library-recentHighlights");
|
||||
let container = this.libraryRecentHighlights;
|
||||
while (container.firstChild) {
|
||||
container.firstChild.remove();
|
||||
}
|
||||
container.hidden = container.previousSibling.hidden =
|
||||
container.previousSibling.previousSibling.hidden = true;
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -55,7 +55,9 @@ add_task(async function test_tab_options_modals() {
|
|||
}
|
||||
|
||||
aboutAddonsBrowser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true);
|
||||
resolve();
|
||||
// Wait for the next event tick to make sure the remaining part of the
|
||||
// testcase runs after the dialog gets opened.
|
||||
SimpleTest.executeSoon(resolve);
|
||||
}, true);
|
||||
});
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ function promiseLoadedSidebar(cmd) {
|
|||
return new Promise(resolve => {
|
||||
let sidebar = document.getElementById("sidebar");
|
||||
sidebar.addEventListener("load", function() {
|
||||
resolve(sidebar);
|
||||
executeSoon(() => resolve(sidebar));
|
||||
}, {capture: true, once: true});
|
||||
|
||||
SidebarUI.show(cmd);
|
||||
|
|
|
@ -63,7 +63,7 @@ function promiseLibraryClosed(organizer) {
|
|||
return new Promise(resolve => {
|
||||
// Wait for the Organizer window to actually be closed
|
||||
organizer.addEventListener("unload", function() {
|
||||
resolve();
|
||||
executeSoon(resolve);
|
||||
}, {once: true});
|
||||
|
||||
// Close Library window.
|
||||
|
@ -413,7 +413,7 @@ var withSidebarTree = async function(type, taskFn) {
|
|||
info("withSidebarTree: waiting sidebar load");
|
||||
let sidebarLoadedPromise = new Promise(resolve => {
|
||||
sidebar.addEventListener("load", function() {
|
||||
resolve();
|
||||
executeSoon(resolve);
|
||||
}, {capture: true, once: true});
|
||||
});
|
||||
let sidebarId = type == "bookmarks" ? "viewBookmarksSidebar"
|
||||
|
|
|
@ -1,347 +1,316 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
requestLongerTimeout(2);
|
||||
requestLongerTimeout(3);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(3);
|
||||
testRunner.runTests();
|
||||
add_task(async function testAllow() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
is(params.tree.view.rowCount, 0, "no cookie exceptions");
|
||||
|
||||
params.url.value = "test.com";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission text should be set correctly");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "http://test.com", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testBlock() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "test.com";
|
||||
params.btnBlock.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
|
||||
"permission should change to deny in UI");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "http://test.com", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testAllowAgain() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "test.com";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission should revert back to allow");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "http://test.com", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testRemove() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "test.com";
|
||||
params.btnRemove.doCommand();
|
||||
is(params.tree.view.rowCount, 0, "exception should be removed");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "http://test.com", data: "deleted" }]);
|
||||
});
|
||||
|
||||
add_task(async function testAdd() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
let uri = Services.io.newURI("http://test.com");
|
||||
Services.perms.add(uri, "popup", Ci.nsIPermissionManager.DENY_ACTION);
|
||||
is(params.tree.view.rowCount, 0, "adding unrelated permission should not change display");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
|
||||
Services.perms.remove(uri, "popup");
|
||||
}, [{ type: "popup", origin: "http://test.com", data: "added",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testAllowHTTPSWithPort() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission text should be set correctly");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "https://test.com:12345", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testBlockHTTPSWithPort() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnBlock.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
|
||||
"permission should change to deny in UI");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "https://test.com:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testAllowAgainHTTPSWithPort() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission should revert back to allow");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "https://test.com:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testRemoveHTTPSWithPort() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnRemove.doCommand();
|
||||
is(params.tree.view.rowCount, 0, "exception should be removed");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "https://test.com:12345", data: "deleted" }]);
|
||||
});
|
||||
|
||||
add_task(async function testAllowPort() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "localhost:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://localhost:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission text should be set correctly");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "http://localhost:12345", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testBlockPort() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "localhost:12345";
|
||||
params.btnBlock.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://localhost:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
|
||||
"permission should change to deny in UI");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "http://localhost:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testAllowAgainPort() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "localhost:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://localhost:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission should revert back to allow");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "http://localhost:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }]);
|
||||
});
|
||||
|
||||
add_task(async function testRemovePort() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
params.url.value = "localhost:12345";
|
||||
params.btnRemove.doCommand();
|
||||
is(params.tree.view.rowCount, 0, "exception should be removed");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
}, [{ type: "cookie", origin: "http://localhost:12345", data: "deleted" }]);
|
||||
});
|
||||
|
||||
add_task(async function testSort() {
|
||||
await runTest(async (params, observeAllPromise, apply) => {
|
||||
for (let URL of ["http://a", "http://z", "http://b"]) {
|
||||
let URI = Services.io.newURI(URL);
|
||||
Services.perms.add(URI, "cookie", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
|
||||
is(params.tree.view.rowCount, 3, "Three permissions should be present");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://a",
|
||||
"site should be sorted. 'a' should be first");
|
||||
is(params.tree.view.getCellText(1, params.nameCol), "http://b",
|
||||
"site should be sorted. 'b' should be second");
|
||||
is(params.tree.view.getCellText(2, params.nameCol), "http://z",
|
||||
"site should be sorted. 'z' should be third");
|
||||
|
||||
// Sort descending then check results in cleanup since sorting isn't synchronous.
|
||||
EventUtils.synthesizeMouseAtCenter(params.doc.getElementById("siteCol"), {},
|
||||
params.doc.defaultView);
|
||||
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://z",
|
||||
"site should be sorted. 'z' should be first");
|
||||
is(params.tree.view.getCellText(1, params.nameCol), "http://b",
|
||||
"site should be sorted. 'b' should be second");
|
||||
is(params.tree.view.getCellText(2, params.nameCol), "http://a",
|
||||
"site should be sorted. 'a' should be third");
|
||||
|
||||
apply();
|
||||
await observeAllPromise;
|
||||
|
||||
for (let URL of ["http://a", "http://z", "http://b"]) {
|
||||
let uri = Services.io.newURI(URL);
|
||||
Services.perms.remove(uri, "cookie");
|
||||
}
|
||||
}, [{ type: "cookie", origin: "http://a", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION },
|
||||
{ type: "cookie", origin: "http://z", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION },
|
||||
{ type: "cookie", origin: "http://b", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }]);
|
||||
});
|
||||
|
||||
async function runTest(test, observances) {
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("privacy.history.custom");
|
||||
});
|
||||
|
||||
await openPreferencesViaOpenPreferencesAPI("panePrivacy", {leaveOpen: true});
|
||||
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
let doc = gBrowser.contentDocument;
|
||||
let historyMode = doc.getElementById("historyMode");
|
||||
historyMode.value = "custom";
|
||||
historyMode.doCommand();
|
||||
|
||||
let promiseSubDialogLoaded =
|
||||
promiseLoadSubDialog("chrome://browser/content/preferences/permissions.xul");
|
||||
doc.getElementById("cookieExceptions").doCommand();
|
||||
|
||||
let win = await promiseSubDialogLoaded;
|
||||
|
||||
doc = win.document;
|
||||
let params = {
|
||||
doc,
|
||||
tree: doc.getElementById("permissionsTree"),
|
||||
nameCol: doc.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(0),
|
||||
statusCol: doc.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(1),
|
||||
url: doc.getElementById("url"),
|
||||
btnAllow: doc.getElementById("btnAllow"),
|
||||
btnBlock: doc.getElementById("btnBlock"),
|
||||
btnRemove: doc.getElementById("removePermission"),
|
||||
allowText: win.gPermissionManager._getCapabilityString(
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION),
|
||||
denyText: win.gPermissionManager._getCapabilityString(
|
||||
Ci.nsIPermissionManager.DENY_ACTION),
|
||||
allow: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
deny: Ci.nsIPermissionManager.DENY_ACTION,
|
||||
};
|
||||
let btnApplyChanges = doc.getElementById("btnApplyChanges");
|
||||
let observeAllPromise = createObserveAllPromise(observances);
|
||||
|
||||
await test(params, observeAllPromise, () => btnApplyChanges.doCommand());
|
||||
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
|
||||
var testRunner = {
|
||||
function createObserveAllPromise(observances) {
|
||||
return new Promise(resolve => {
|
||||
let permObserver = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic != "perm-changed")
|
||||
return;
|
||||
|
||||
tests:
|
||||
[
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission text should be set correctly");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "http://test.com", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnBlock.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
|
||||
"permission should change to deny in UI");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "http://test.com", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission should revert back to allow");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "http://test.com", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnRemove.doCommand();
|
||||
is(params.tree.view.rowCount, 0, "exception should be removed");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "http://test.com", data: "deleted" }],
|
||||
},
|
||||
{
|
||||
expectPermObservancesDuringTestFunction: true,
|
||||
test(params) {
|
||||
let uri = Services.io.newURI("http://test.com");
|
||||
Services.perms.add(uri, "popup", Ci.nsIPermissionManager.DENY_ACTION);
|
||||
is(params.tree.view.rowCount, 0, "adding unrelated permission should not change display");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "popup", origin: "http://test.com", data: "added",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }],
|
||||
cleanUp(params) {
|
||||
let uri = Services.io.newURI("http://test.com");
|
||||
Services.perms.remove(uri, "popup");
|
||||
},
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission text should be set correctly");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "https://test.com:12345", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnBlock.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
|
||||
"permission should change to deny in UI");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "https://test.com:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission should revert back to allow");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "https://test.com:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "https://test.com:12345";
|
||||
params.btnRemove.doCommand();
|
||||
is(params.tree.view.rowCount, 0, "exception should be removed");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "https://test.com:12345", data: "deleted" }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "localhost:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://localhost:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission text should be set correctly");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "http://localhost:12345", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "localhost:12345";
|
||||
params.btnBlock.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://localhost:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
|
||||
"permission should change to deny in UI");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "http://localhost:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "localhost:12345";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://localhost:12345",
|
||||
"origin name should be set correctly");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission should revert back to allow");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "http://localhost:12345", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test(params) {
|
||||
params.url.value = "localhost:12345";
|
||||
params.btnRemove.doCommand();
|
||||
is(params.tree.view.rowCount, 0, "exception should be removed");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "http://localhost:12345", data: "deleted" }],
|
||||
},
|
||||
{
|
||||
expectPermObservancesDuringTestFunction: true,
|
||||
test(params) {
|
||||
for (let URL of ["http://a", "http://z", "http://b"]) {
|
||||
let URI = Services.io.newURI(URL);
|
||||
Services.perms.add(URI, "cookie", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
if (observances.length == 0) {
|
||||
// Should fail here as we are not expecting a notification, but we
|
||||
// don't. See bug 1063410.
|
||||
return;
|
||||
}
|
||||
|
||||
is(params.tree.view.rowCount, 3, "Three permissions should be present");
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://a",
|
||||
"site should be sorted. 'a' should be first");
|
||||
is(params.tree.view.getCellText(1, params.nameCol), "http://b",
|
||||
"site should be sorted. 'b' should be second");
|
||||
is(params.tree.view.getCellText(2, params.nameCol), "http://z",
|
||||
"site should be sorted. 'z' should be third");
|
||||
info(`observed perm-changed (remaining ${observances.length - 1})`);
|
||||
|
||||
// Sort descending then check results in cleanup since sorting isn't synchronous.
|
||||
EventUtils.synthesizeMouseAtCenter(params.doc.getElementById("siteCol"), {},
|
||||
params.doc.defaultView);
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", origin: "http://a", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION },
|
||||
{ type: "cookie", origin: "http://z", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION },
|
||||
{ type: "cookie", origin: "http://b", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
cleanUp(params) {
|
||||
is(params.tree.view.getCellText(0, params.nameCol), "http://z",
|
||||
"site should be sorted. 'z' should be first");
|
||||
is(params.tree.view.getCellText(1, params.nameCol), "http://b",
|
||||
"site should be sorted. 'b' should be second");
|
||||
is(params.tree.view.getCellText(2, params.nameCol), "http://a",
|
||||
"site should be sorted. 'a' should be third");
|
||||
let permission = aSubject.QueryInterface(Ci.nsIPermission);
|
||||
let expected = observances.shift();
|
||||
|
||||
for (let URL of ["http://a", "http://z", "http://b"]) {
|
||||
let uri = Services.io.newURI(URL);
|
||||
Services.perms.remove(uri, "cookie");
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
is(aData, expected.data, "type of message should be the same");
|
||||
for (let prop of ["type", "capability"]) {
|
||||
if (expected[prop])
|
||||
is(permission[prop], expected[prop],
|
||||
"property: \"" + prop + "\" should be equal");
|
||||
}
|
||||
|
||||
_currentTest: -1,
|
||||
if (expected.origin) {
|
||||
is(permission.principal.origin, expected.origin,
|
||||
"property: \"origin\" should be equal");
|
||||
}
|
||||
|
||||
runTests() {
|
||||
this._currentTest++;
|
||||
|
||||
info("Running test #" + (this._currentTest + 1) + "\n");
|
||||
let that = this;
|
||||
let p = this.runCurrentTest(this._currentTest + 1);
|
||||
p.then(function() {
|
||||
if (that._currentTest == that.tests.length - 1) {
|
||||
finish();
|
||||
} else {
|
||||
that.runTests();
|
||||
if (observances.length == 0) {
|
||||
Services.obs.removeObserver(permObserver, "perm-changed");
|
||||
executeSoon(resolve);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
runCurrentTest(testNumber) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
let helperFunctions = {
|
||||
windowLoad(win) {
|
||||
let doc = win.document;
|
||||
let params = {
|
||||
doc,
|
||||
tree: doc.getElementById("permissionsTree"),
|
||||
nameCol: doc.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(0),
|
||||
statusCol: doc.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(1),
|
||||
url: doc.getElementById("url"),
|
||||
btnAllow: doc.getElementById("btnAllow"),
|
||||
btnBlock: doc.getElementById("btnBlock"),
|
||||
btnApplyChanges: doc.getElementById("btnApplyChanges"),
|
||||
btnRemove: doc.getElementById("removePermission"),
|
||||
allowText: win.gPermissionManager._getCapabilityString(
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION),
|
||||
denyText: win.gPermissionManager._getCapabilityString(
|
||||
Ci.nsIPermissionManager.DENY_ACTION),
|
||||
allow: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
deny: Ci.nsIPermissionManager.DENY_ACTION,
|
||||
};
|
||||
|
||||
let permObserver = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic != "perm-changed")
|
||||
return;
|
||||
|
||||
if (testRunner.tests[testRunner._currentTest].observances.length == 0) {
|
||||
// Should fail here as we are not expecting a notification, but we don't.
|
||||
// See bug 1063410.
|
||||
return;
|
||||
}
|
||||
|
||||
let permission = aSubject.QueryInterface(Ci.nsIPermission);
|
||||
let expected = testRunner.tests[testRunner._currentTest].observances.shift();
|
||||
|
||||
is(aData, expected.data, "type of message should be the same");
|
||||
for (let prop of ["type", "capability"]) {
|
||||
if (expected[prop])
|
||||
is(permission[prop], expected[prop],
|
||||
"property: \"" + prop + "\" should be equal");
|
||||
}
|
||||
|
||||
if (expected.origin) {
|
||||
is(permission.principal.origin, expected.origin,
|
||||
"property: \"origin\" should be equal");
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(permObserver, "perm-changed");
|
||||
|
||||
let testCase = testRunner.tests[testRunner._currentTest];
|
||||
if (!testCase.expectPermObservancesDuringTestFunction) {
|
||||
if (testCase.cleanUp) {
|
||||
testCase.cleanUp(params);
|
||||
}
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Services.obs.addObserver(permObserver, "perm-changed");
|
||||
|
||||
if (testRunner._currentTest == 0) {
|
||||
is(params.tree.view.rowCount, 0, "no cookie exceptions");
|
||||
}
|
||||
|
||||
try {
|
||||
let testCase = testRunner.tests[testRunner._currentTest];
|
||||
testCase.test(params);
|
||||
if (testCase.expectPermObservancesDuringTestFunction) {
|
||||
if (testCase.cleanUp) {
|
||||
testCase.cleanUp(params);
|
||||
}
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
resolve();
|
||||
}
|
||||
} catch (ex) {
|
||||
ok(false, "exception while running test #" +
|
||||
testNumber + ": " + ex);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("privacy.history.custom");
|
||||
});
|
||||
|
||||
openPreferencesViaOpenPreferencesAPI("panePrivacy", {leaveOpen: true}).then(function() {
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
let doc = gBrowser.contentDocument;
|
||||
let historyMode = doc.getElementById("historyMode");
|
||||
historyMode.value = "custom";
|
||||
historyMode.doCommand();
|
||||
|
||||
let promiseSubDialogLoaded =
|
||||
promiseLoadSubDialog("chrome://browser/content/preferences/permissions.xul");
|
||||
doc.getElementById("cookieExceptions").doCommand();
|
||||
|
||||
promiseSubDialogLoaded.then(function(win) {
|
||||
helperFunctions.windowLoad(win);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
Services.obs.addObserver(permObserver, "perm-changed");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,7 +21,13 @@ function open_subdialog_and_test_generic_start_state(browser, domcontentloadedFn
|
|||
let subdialog = content.gSubDialog._topDialog;
|
||||
|
||||
info("waiting for subdialog DOMFrameContentLoaded");
|
||||
await ContentTaskUtils.waitForEvent(win, "DOMFrameContentLoaded", true);
|
||||
let dialogOpenPromise;
|
||||
await new Promise(resolve => {
|
||||
win.addEventListener("DOMFrameContentLoaded", () => {
|
||||
dialogOpenPromise = ContentTaskUtils.waitForEvent(subdialog._overlay, "dialogopen");
|
||||
resolve();
|
||||
}, { once: true, capture: true });
|
||||
});
|
||||
let result;
|
||||
if (args.domcontentloadedFnStr) {
|
||||
// eslint-disable-next-line no-eval
|
||||
|
@ -29,7 +35,7 @@ function open_subdialog_and_test_generic_start_state(browser, domcontentloadedFn
|
|||
}
|
||||
|
||||
info("waiting for subdialog load");
|
||||
await ContentTaskUtils.waitForEvent(subdialog._overlay, "dialogopen");
|
||||
await dialogOpenPromise;
|
||||
info("subdialog window is loaded");
|
||||
|
||||
let expectedStyleSheetURLs = subdialog._injectedStyleSheets.slice(0);
|
||||
|
|
|
@ -67,7 +67,9 @@ function promiseLoadSubDialog(aURL) {
|
|||
}
|
||||
is(expectedStyleSheetURLs.length, 0, "All expectedStyleSheetURLs should have been found");
|
||||
|
||||
resolve(aEvent.detail.dialog._frame.contentWindow);
|
||||
// Wait for the next event tick to make sure the remaining part of the
|
||||
// testcase runs after the dialog gets ready for input.
|
||||
executeSoon(() => resolve(aEvent.detail.dialog._frame.contentWindow));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ function synthesizeNativeMouseMove(aElement) {
|
|||
return new Promise((resolve, reject) => {
|
||||
function eventOccurred(e) {
|
||||
aElement.removeEventListener("mousemove", eventOccurred, true);
|
||||
resolve();
|
||||
SimpleTest.executeSoon(resolve);
|
||||
}
|
||||
|
||||
aElement.addEventListener("mousemove", eventOccurred, true);
|
||||
|
|
|
@ -14,6 +14,24 @@ let firstPaintNotification = "widget-first-paint";
|
|||
if (AppConstants.platform == "linux")
|
||||
firstPaintNotification = "xul-window-visible";
|
||||
|
||||
let win, canvas;
|
||||
let paints = [];
|
||||
let afterPaintListener = () => {
|
||||
let width, height;
|
||||
canvas.width = width = win.innerWidth;
|
||||
canvas.height = height = win.innerHeight;
|
||||
if (width < 1 || height < 1)
|
||||
return;
|
||||
let ctx = canvas.getContext("2d", {alpha: false, willReadFrequently: true});
|
||||
|
||||
ctx.drawWindow(win, 0, 0, width, height, "white",
|
||||
ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_VIEW |
|
||||
ctx.DRAWWINDOW_ASYNC_DECODE_IMAGES |
|
||||
ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
|
||||
paints.push({data: ctx.getImageData(0, 0, width, height).data,
|
||||
width, height});
|
||||
};
|
||||
|
||||
/**
|
||||
* The startupRecorder component observes notifications at various stages of
|
||||
* startup and records the set of JS components and modules that were already
|
||||
|
@ -83,6 +101,16 @@ startupRecorder.prototype = {
|
|||
|
||||
Services.obs.removeObserver(this, topic);
|
||||
|
||||
if (topic == firstPaintNotification &&
|
||||
Services.prefs.getBoolPref("browser.startup.record", false)) {
|
||||
win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
canvas = win.document.createElementNS("http://www.w3.org/1999/xhtml",
|
||||
"canvas");
|
||||
canvas.mozOpaque = true;
|
||||
afterPaintListener();
|
||||
win.addEventListener("MozAfterPaint", afterPaintListener);
|
||||
}
|
||||
|
||||
if (topic == "sessionstore-windows-restored") {
|
||||
if (!Services.prefs.getBoolPref("browser.startup.record", false)) {
|
||||
this._resolve();
|
||||
|
@ -107,6 +135,10 @@ startupRecorder.prototype = {
|
|||
this.record("before becoming idle");
|
||||
Services.obs.removeObserver(this, "image-drawing");
|
||||
Services.obs.removeObserver(this, "image-loading");
|
||||
win.removeEventListener("MozAfterPaint", afterPaintListener);
|
||||
win = null;
|
||||
this.data.frames = paints;
|
||||
paints = null;
|
||||
this._resolve();
|
||||
this._resolve = null;
|
||||
});
|
||||
|
|
|
@ -32,6 +32,8 @@ build-clang.py accepts a JSON config format with the following fields:
|
|||
* stages: Use 1, 2, or 3 to select different compiler stages. The default is 3.
|
||||
* llvm_repo: SVN path to the LLVM repo.
|
||||
* clang_repo: SVN path to the Clang repo.
|
||||
* extra_repo: SVN path to the clang-tools-extra repo.
|
||||
* lld_repo: SVN path to the lld repo.
|
||||
* compiler_repo: SVN path to the compiler-rt repo.
|
||||
* libcxx_repo: SVN path to the libcxx repo.
|
||||
* libcxxabi_repo: SVN path to the libcxxabi repo.
|
||||
|
|
|
@ -343,6 +343,7 @@ if __name__ == "__main__":
|
|||
llvm_source_dir = source_dir + "/llvm"
|
||||
clang_source_dir = source_dir + "/clang"
|
||||
extra_source_dir = source_dir + "/extra"
|
||||
lld_source_dir = source_dir + "/lld"
|
||||
compiler_rt_source_dir = source_dir + "/compiler-rt"
|
||||
libcxx_source_dir = source_dir + "/libcxx"
|
||||
libcxxabi_source_dir = source_dir + "/libcxxabi"
|
||||
|
@ -379,6 +380,7 @@ if __name__ == "__main__":
|
|||
llvm_repo = config["llvm_repo"]
|
||||
clang_repo = config["clang_repo"]
|
||||
extra_repo = config.get("extra_repo")
|
||||
lld_repo = config.get("lld_repo")
|
||||
compiler_repo = config["compiler_repo"]
|
||||
libcxx_repo = config["libcxx_repo"]
|
||||
libcxxabi_repo = config.get("libcxxabi_repo")
|
||||
|
@ -449,6 +451,8 @@ if __name__ == "__main__":
|
|||
checkout_or_update(clang_repo, clang_source_dir)
|
||||
checkout_or_update(compiler_repo, compiler_rt_source_dir)
|
||||
checkout_or_update(libcxx_repo, libcxx_source_dir)
|
||||
if lld_repo:
|
||||
checkout_or_update(lld_repo, lld_source_dir)
|
||||
if libcxxabi_repo:
|
||||
checkout_or_update(libcxxabi_repo, libcxxabi_source_dir)
|
||||
if extra_repo:
|
||||
|
@ -460,6 +464,8 @@ if __name__ == "__main__":
|
|||
llvm_source_dir + "/tools/clang"),
|
||||
(extra_source_dir,
|
||||
llvm_source_dir + "/tools/clang/tools/extra"),
|
||||
(lld_source_dir,
|
||||
llvm_source_dir + "/tools/lld"),
|
||||
(compiler_rt_source_dir,
|
||||
llvm_source_dir + "/projects/compiler-rt"),
|
||||
(libcxx_source_dir,
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
"r315677.patch",
|
||||
"r316048.patch",
|
||||
"r317705.patch",
|
||||
"r317709.patch"
|
||||
"r317709.patch",
|
||||
"hide-gcda-profiling-symbols.patch",
|
||||
"fflush-before-unlocking.patch"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
|
||||
index f0c05075a..11b1c4557 100644
|
||||
--- a/compiler-rt/lib/profile/GCDAProfiling.c
|
||||
+++ b/compiler-rt/lib/profile/GCDAProfiling.c
|
||||
@@ -468,6 +468,7 @@ void llvm_gcda_end_file() {
|
||||
unmap_file();
|
||||
}
|
||||
|
||||
+ fflush(output_file);
|
||||
flock(fd, LOCK_UN);
|
||||
fclose(output_file);
|
||||
output_file = NULL;
|
|
@ -9,7 +9,6 @@
|
|||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/SubtleCryptoBinding.h"
|
||||
#include "mozilla/dom/WebCryptoTask.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -26,7 +25,6 @@ NS_INTERFACE_MAP_END
|
|||
|
||||
SubtleCrypto::SubtleCrypto(nsIGlobalObject* aParent)
|
||||
: mParent(aParent)
|
||||
, mRecordedTelemetry(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -36,25 +34,12 @@ SubtleCrypto::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
return SubtleCryptoBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
SubtleCrypto::RecordTelemetryOnce() {
|
||||
if (mRecordedTelemetry) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRecordedTelemetry = true;
|
||||
JSObject* global = mParent->GetGlobalJSObject();
|
||||
bool isSecure = JS_GetIsSecureContext(js::GetObjectCompartment(global));
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD_SECURE, isSecure);
|
||||
}
|
||||
|
||||
#define SUBTLECRYPTO_METHOD_BODY(Operation, aRv, ...) \
|
||||
MOZ_ASSERT(mParent); \
|
||||
RefPtr<Promise> p = Promise::Create(mParent, aRv); \
|
||||
if (aRv.Failed()) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
RecordTelemetryOnce(); \
|
||||
RefPtr<WebCryptoTask> task = \
|
||||
WebCryptoTask::Create ## Operation ## Task(__VA_ARGS__); \
|
||||
if (!task) { \
|
||||
|
|
|
@ -119,10 +119,7 @@ public:
|
|||
ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
void RecordTelemetryOnce();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mParent;
|
||||
bool mRecordedTelemetry;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -92,8 +93,8 @@ protected:
|
|||
int32_t aDepth);
|
||||
nsresult SerializeRangeContextStart(const nsTArray<nsINode*>& aAncestorArray,
|
||||
nsAString& aString);
|
||||
nsresult SerializeRangeContextEnd(const nsTArray<nsINode*>& aAncestorArray,
|
||||
nsAString& aString);
|
||||
nsresult SerializeRangeContextEnd(nsAString& aString);
|
||||
|
||||
virtual int32_t
|
||||
GetImmediateContextCount(const nsTArray<nsINode*>& aAncestorArray)
|
||||
{
|
||||
|
@ -185,6 +186,7 @@ protected:
|
|||
AutoTArray<int32_t, 8> mStartOffsets;
|
||||
AutoTArray<nsIContent*, 8> mEndNodes;
|
||||
AutoTArray<int32_t, 8> mEndOffsets;
|
||||
AutoTArray<AutoTArray<nsINode*, 8>, 8> mRangeContexts;
|
||||
// Whether the serializer cares about being notified to scan elements to
|
||||
// keep track of whether they are preformatted. This stores the out
|
||||
// argument of nsIContentSerializer::Init().
|
||||
|
@ -874,6 +876,9 @@ nsDocumentEncoder::SerializeRangeContextStart(const nsTArray<nsINode*>& aAncesto
|
|||
if (mDisableContextSerialize) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AutoTArray<nsINode*, 8>* serializedContext = mRangeContexts.AppendElement();
|
||||
|
||||
int32_t i = aAncestorArray.Length(), j;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -889,7 +894,7 @@ nsDocumentEncoder::SerializeRangeContextStart(const nsTArray<nsINode*>& aAncesto
|
|||
// Either a general inclusion or as immediate context
|
||||
if (IncludeInContext(node) || i < j) {
|
||||
rv = SerializeNodeStart(node, 0, -1, aString);
|
||||
|
||||
serializedContext->AppendElement(node);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
}
|
||||
|
@ -899,34 +904,24 @@ nsDocumentEncoder::SerializeRangeContextStart(const nsTArray<nsINode*>& aAncesto
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsDocumentEncoder::SerializeRangeContextEnd(const nsTArray<nsINode*>& aAncestorArray,
|
||||
nsAString& aString)
|
||||
nsDocumentEncoder::SerializeRangeContextEnd(nsAString& aString)
|
||||
{
|
||||
if (mDisableContextSerialize) {
|
||||
return NS_OK;
|
||||
}
|
||||
int32_t i = 0, j;
|
||||
int32_t count = aAncestorArray.Length();
|
||||
|
||||
MOZ_RELEASE_ASSERT(!mRangeContexts.IsEmpty(), "Tried to end context without starting one.");
|
||||
AutoTArray<nsINode*, 8>& serializedContext = mRangeContexts.LastElement();
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
for (nsINode* node : Reversed(serializedContext)) {
|
||||
rv = SerializeNodeEnd(node, aString);
|
||||
|
||||
// currently only for table-related elements
|
||||
j = GetImmediateContextCount(aAncestorArray);
|
||||
|
||||
while (i < count) {
|
||||
nsINode *node = aAncestorArray.ElementAt(i++);
|
||||
|
||||
if (!node)
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
// Either a general inclusion or as immediate context
|
||||
if (IncludeInContext(node) || i - 1 < j) {
|
||||
rv = SerializeNodeEnd(node, aString);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mRangeContexts.RemoveElementAt(mRangeContexts.Length() - 1);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -992,7 +987,7 @@ nsDocumentEncoder::SerializeRangeToString(nsRange *aRange,
|
|||
rv = SerializeRangeNodes(aRange, mCommonParent, aOutputString, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
rv = SerializeRangeContextEnd(mCommonAncestors, aOutputString);
|
||||
rv = SerializeRangeContextEnd(aOutputString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return rv;
|
||||
|
@ -1029,6 +1024,11 @@ NS_IMETHODIMP
|
|||
nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||
nsAString& aOutputString)
|
||||
{
|
||||
MOZ_ASSERT(mRangeContexts.IsEmpty(), "Re-entrant call to nsDocumentEncoder.");
|
||||
auto rangeContextGuard = MakeScopeExit([&] {
|
||||
mRangeContexts.Clear();
|
||||
});
|
||||
|
||||
if (!mDocument)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
|
@ -1112,10 +1112,8 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
|||
prevNode = node;
|
||||
} else if (prevNode) {
|
||||
// Went from a <tr> to a non-<tr>
|
||||
mCommonAncestors.Clear();
|
||||
nsContentUtils::GetAncestors(p->GetParentNode(), mCommonAncestors);
|
||||
mDisableContextSerialize = false;
|
||||
rv = SerializeRangeContextEnd(mCommonAncestors, output);
|
||||
rv = SerializeRangeContextEnd(output);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
prevNode = nullptr;
|
||||
}
|
||||
|
@ -1134,10 +1132,8 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
|||
nsCOMPtr<nsINode> p = do_QueryInterface(prevNode);
|
||||
rv = SerializeNodeEnd(p, output);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mCommonAncestors.Clear();
|
||||
nsContentUtils::GetAncestors(p->GetParentNode(), mCommonAncestors);
|
||||
mDisableContextSerialize = false;
|
||||
rv = SerializeRangeContextEnd(mCommonAncestors, output);
|
||||
rv = SerializeRangeContextEnd(output);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -1196,6 +1192,10 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
|||
NS_IMETHODIMP
|
||||
nsDocumentEncoder::EncodeToStream(nsIOutputStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(mRangeContexts.IsEmpty(), "Re-entrant call to nsDocumentEncoder.");
|
||||
auto rangeContextGuard = MakeScopeExit([&] {
|
||||
mRangeContexts.Clear();
|
||||
});
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mDocument)
|
||||
|
|
|
@ -388,6 +388,7 @@ nsPlainTextSerializer::ScanElementForPreformat(Element* aElement)
|
|||
NS_IMETHODIMP
|
||||
nsPlainTextSerializer::ForgetElementForPreformat(Element* aElement)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!mPreformatStack.empty(), "Tried to pop without previous push.");
|
||||
mPreformatStack.pop();
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -175,6 +175,7 @@ nsStaticAtom** const kAttributesHTML[] = {
|
|||
&nsGkAtoms::contextmenu,
|
||||
&nsGkAtoms::controls,
|
||||
&nsGkAtoms::coords,
|
||||
&nsGkAtoms::crossorigin,
|
||||
&nsGkAtoms::datetime,
|
||||
&nsGkAtoms::dir,
|
||||
&nsGkAtoms::disabled,
|
||||
|
@ -191,6 +192,7 @@ nsStaticAtom** const kAttributesHTML[] = {
|
|||
&nsGkAtoms::hreflang,
|
||||
&nsGkAtoms::icon,
|
||||
&nsGkAtoms::id,
|
||||
&nsGkAtoms::integrity,
|
||||
&nsGkAtoms::ismap,
|
||||
&nsGkAtoms::itemid,
|
||||
&nsGkAtoms::itemprop,
|
||||
|
|
|
@ -2,67 +2,43 @@
|
|||
* Mixed Content Block frame navigates for target="_top" - Test for Bug 902350
|
||||
*/
|
||||
|
||||
add_task(async function mixed_content_block_for_target_top_test() {
|
||||
const PREF_ACTIVE = "security.mixed_content.block_active_content";
|
||||
const httpsTestRoot = getRootDirectory(gTestPath)
|
||||
.replace("chrome://mochitests/content", "https://example.com");
|
||||
|
||||
const PREF_ACTIVE = "security.mixed_content.block_active_content";
|
||||
const gHttpTestRoot = "https://example.com/browser/dom/base/test/";
|
||||
var origBlockActive;
|
||||
var gTestBrowser = null;
|
||||
await SpecialPowers.pushPrefEnv({ set: [[ PREF_ACTIVE, true ]] });
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// Set preferences back to their original values
|
||||
Services.prefs.setBoolPref(PREF_ACTIVE, origBlockActive);
|
||||
});
|
||||
let newTab = await BrowserTestUtils.openNewForegroundTab({ gBrowser,
|
||||
waitForLoad: true });
|
||||
let testBrowser = newTab.linkedBrowser;
|
||||
|
||||
function MixedTestsCompleted() {
|
||||
gBrowser.removeCurrentTab();
|
||||
window.focus();
|
||||
finish();
|
||||
}
|
||||
var url = httpsTestRoot + "file_bug902350.html";
|
||||
var frameUrl = httpsTestRoot + "file_bug902350_frame.html";
|
||||
let loadPromise = BrowserTestUtils.browserLoaded(testBrowser, false, url);
|
||||
let frameLoadPromise = BrowserTestUtils.browserLoaded(testBrowser, true,
|
||||
frameUrl);
|
||||
testBrowser.loadURI(url);
|
||||
await loadPromise;
|
||||
await frameLoadPromise;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
origBlockActive = Services.prefs.getBoolPref(PREF_ACTIVE);
|
||||
|
||||
Services.prefs.setBoolPref(PREF_ACTIVE, true);
|
||||
|
||||
var newTab = BrowserTestUtils.addTab(gBrowser);
|
||||
gBrowser.selectedTab = newTab;
|
||||
gTestBrowser = gBrowser.selectedBrowser;
|
||||
|
||||
BrowserTestUtils.browserLoaded(gTestBrowser).then(() => {
|
||||
// about:blank is expected to be loaded here.
|
||||
var url = gHttpTestRoot + "file_bug902350.html";
|
||||
BrowserTestUtils.browserLoaded(gTestBrowser, true /*includeSubFrames*/).then(MixedTest1A);
|
||||
gTestBrowser.loadURI(url);
|
||||
});
|
||||
}
|
||||
|
||||
// Need to capture 2 loads, one for the main page and one for the iframe
|
||||
function MixedTest1A() {
|
||||
BrowserTestUtils.browserLoaded(gTestBrowser, true /*includeSubFrames*/).then(MixedTest1B);
|
||||
}
|
||||
|
||||
// Find the iframe and click the link in it
|
||||
function MixedTest1B() {
|
||||
BrowserTestUtils.browserLoaded(gTestBrowser).then(MixedTest1C);
|
||||
|
||||
ContentTask.spawn(gTestBrowser, null, function() {
|
||||
// Find the iframe and click the link in it.
|
||||
let insecureUrl = "http://example.com/";
|
||||
let insecureLoadPromise = BrowserTestUtils.browserLoaded(testBrowser, false,
|
||||
insecureUrl);
|
||||
ContentTask.spawn(testBrowser, null, function() {
|
||||
var frame = content.document.getElementById("testing_frame");
|
||||
var topTarget = frame.contentWindow.document.getElementById("topTarget");
|
||||
topTarget.click();
|
||||
});
|
||||
|
||||
// The link click should have caused a load and should not invoke the Mixed Content Blocker
|
||||
let {gIdentityHandler} = gTestBrowser.ownerGlobal;
|
||||
// Navigating to insecure domain through target='_top' should succeed.
|
||||
await insecureLoadPromise;
|
||||
|
||||
// The link click should not invoke the Mixed Content Blocker.
|
||||
let {gIdentityHandler} = testBrowser.ownerGlobal;
|
||||
ok (!gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"),
|
||||
"Mixed Content Doorhanger did not appear when trying to navigate top");
|
||||
}
|
||||
|
||||
function MixedTest1C() {
|
||||
ContentTask.spawn(gTestBrowser, null, function() {
|
||||
Assert.equal(content.location.href, "http://example.com/",
|
||||
"Navigating to insecure domain through target='_top' failed.")
|
||||
}).then(MixedTestsCompleted);
|
||||
}
|
||||
|
||||
await BrowserTestUtils.removeTab(newTab);
|
||||
});
|
||||
|
|
|
@ -37,5 +37,12 @@ DeallocClientManagerParent(PClientManagerParent* aActor)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
InitClientManagerParent(PClientManagerParent* aActor)
|
||||
{
|
||||
auto actor = static_cast<ClientManagerParent*>(aActor);
|
||||
actor->Init();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -24,6 +24,9 @@ AllocClientManagerParent();
|
|||
bool
|
||||
DeallocClientManagerParent(PClientManagerParent* aActor);
|
||||
|
||||
void
|
||||
InitClientManagerParent(PClientManagerParent* aActor);
|
||||
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -117,6 +117,13 @@ ClientManagerParent::ClientManagerParent()
|
|||
|
||||
ClientManagerParent::~ClientManagerParent()
|
||||
{
|
||||
mService->RemoveManager(this);
|
||||
}
|
||||
|
||||
void
|
||||
ClientManagerParent::Init()
|
||||
{
|
||||
mService->AddManager(this);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -63,6 +63,9 @@ class ClientManagerParent final : public PClientManagerParent
|
|||
public:
|
||||
ClientManagerParent();
|
||||
~ClientManagerParent();
|
||||
|
||||
void
|
||||
Init();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -6,9 +6,13 @@
|
|||
|
||||
#include "ClientManagerService.h"
|
||||
|
||||
#include "ClientManagerParent.h"
|
||||
#include "ClientSourceParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/SystemGroup.h"
|
||||
#include "nsIAsyncShutdown.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -56,22 +60,137 @@ MatchPrincipalInfo(const PrincipalInfo& aLeft, const PrincipalInfo& aRight)
|
|||
MOZ_CRASH("unexpected principal type!");
|
||||
}
|
||||
|
||||
class ClientShutdownBlocker final : public nsIAsyncShutdownBlocker
|
||||
{
|
||||
RefPtr<GenericPromise::Private> mPromise;
|
||||
|
||||
~ClientShutdownBlocker() = default;
|
||||
|
||||
public:
|
||||
explicit ClientShutdownBlocker(GenericPromise::Private* aPromise)
|
||||
: mPromise(aPromise)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(mPromise);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetName(nsAString& aNameOut) override
|
||||
{
|
||||
aNameOut =
|
||||
NS_LITERAL_STRING("ClientManagerService: start destroying IPC actors early");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
BlockShutdown(nsIAsyncShutdownClient* aClient) override
|
||||
{
|
||||
mPromise->Resolve(true, __func__);
|
||||
aClient->RemoveBlocker(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetState(nsIPropertyBag**) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ClientShutdownBlocker, nsIAsyncShutdownBlocker)
|
||||
|
||||
// Helper function the resolves a MozPromise when we detect that the browser
|
||||
// has begun to shutdown.
|
||||
RefPtr<GenericPromise>
|
||||
OnShutdown()
|
||||
{
|
||||
RefPtr<GenericPromise::Private> ref = new GenericPromise::Private(__func__);
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("ClientManagerServer::OnShutdown",
|
||||
[ref] () {
|
||||
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
|
||||
if (!svc) {
|
||||
ref->Resolve(true, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncShutdownClient> phase;
|
||||
MOZ_ALWAYS_SUCCEEDS(svc->GetXpcomWillShutdown(getter_AddRefs(phase)));
|
||||
if (!phase) {
|
||||
ref->Resolve(true, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncShutdownBlocker> blocker = new ClientShutdownBlocker(ref);
|
||||
nsresult rv =
|
||||
phase->AddBlocker(blocker, NS_LITERAL_STRING(__FILE__), __LINE__,
|
||||
NS_LITERAL_STRING("ClientManagerService shutdown"));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
ref->Resolve(true, __func__);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
|
||||
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ClientManagerService::ClientManagerService()
|
||||
: mShutdown(false)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// While the ClientManagerService will be gracefully terminated as windows
|
||||
// and workers are naturally killed, this can cause us to do extra work
|
||||
// relatively late in the shutdown process. To avoid this we eagerly begin
|
||||
// shutdown at the first sign it has begun. Since we handle normal shutdown
|
||||
// gracefully we don't really need to block anything here. We just begin
|
||||
// destroying our IPC actors immediately.
|
||||
OnShutdown()->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[] () {
|
||||
RefPtr<ClientManagerService> svc = ClientManagerService::GetInstance();
|
||||
if (svc) {
|
||||
svc->Shutdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ClientManagerService::~ClientManagerService()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_DIAGNOSTIC_ASSERT(mSourceTable.Count() == 0);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mManagerList.IsEmpty());
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(sClientManagerServiceInstance == this);
|
||||
sClientManagerServiceInstance = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ClientManagerService::Shutdown()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// If many ClientManagerService are created and destroyed quickly we can
|
||||
// in theory get more than one shutdown listener calling us.
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
mShutdown = true;
|
||||
|
||||
// Begin destroying our various manager actors which will in turn destroy
|
||||
// all source, handle, and operation actors.
|
||||
AutoTArray<ClientManagerParent*, 16> list(mManagerList);
|
||||
for (auto actor : list) {
|
||||
Unused << PClientManagerParent::Send__delete__(actor);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<ClientManagerService>
|
||||
ClientManagerService::GetOrCreateInstance()
|
||||
|
@ -86,6 +205,20 @@ ClientManagerService::GetOrCreateInstance()
|
|||
return ref.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<ClientManagerService>
|
||||
ClientManagerService::GetInstance()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (!sClientManagerServiceInstance) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ClientManagerService> ref(sClientManagerServiceInstance);
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
ClientManagerService::AddSource(ClientSourceParent* aSource)
|
||||
{
|
||||
|
@ -134,5 +267,28 @@ ClientManagerService::FindSource(const nsID& aID, const PrincipalInfo& aPrincipa
|
|||
return source;
|
||||
}
|
||||
|
||||
void
|
||||
ClientManagerService::AddManager(ClientManagerParent* aManager)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_DIAGNOSTIC_ASSERT(aManager);
|
||||
MOZ_ASSERT(!mManagerList.Contains(aManager));
|
||||
mManagerList.AppendElement(aManager);
|
||||
|
||||
// If shutdown has already begun then immediately destroy the actor.
|
||||
if (mShutdown) {
|
||||
Unused << PClientManagerParent::Send__delete__(aManager);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientManagerService::RemoveManager(ClientManagerParent* aManager)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_DIAGNOSTIC_ASSERT(aManager);
|
||||
DebugOnly<bool> removed = mManagerList.RemoveElement(aManager);
|
||||
MOZ_ASSERT(removed);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
#define _mozilla_dom_ClientManagerService_h
|
||||
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
||||
class ClientManagerParent;
|
||||
class ClientSourceParent;
|
||||
|
||||
// Define a singleton service to manage client activity throughout the
|
||||
|
@ -24,13 +26,24 @@ class ClientManagerService final
|
|||
// optimize for insertion, removal, and lookup by UUID.
|
||||
nsDataHashtable<nsIDHashKey, ClientSourceParent*> mSourceTable;
|
||||
|
||||
nsTArray<ClientManagerParent*> mManagerList;
|
||||
|
||||
bool mShutdown;
|
||||
|
||||
ClientManagerService();
|
||||
~ClientManagerService();
|
||||
|
||||
void
|
||||
Shutdown();
|
||||
|
||||
public:
|
||||
static already_AddRefed<ClientManagerService>
|
||||
GetOrCreateInstance();
|
||||
|
||||
// Returns nullptr if the service is not already created.
|
||||
static already_AddRefed<ClientManagerService>
|
||||
GetInstance();
|
||||
|
||||
bool
|
||||
AddSource(ClientSourceParent* aSource);
|
||||
|
||||
|
@ -41,6 +54,12 @@ public:
|
|||
FindSource(const nsID& aID,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
|
||||
|
||||
void
|
||||
AddManager(ClientManagerParent* aManager);
|
||||
|
||||
void
|
||||
RemoveManager(ClientManagerParent* aManager);
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManagerService)
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "nsContentUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsHostObjectURI.h"
|
||||
#include "nsIAsyncShutdown.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
|
@ -437,6 +438,7 @@ NS_IMPL_ISUPPORTS(BlobURLsReporter, nsIMemoryReporter)
|
|||
|
||||
class ReleasingTimerHolder final : public nsITimerCallback
|
||||
, public nsINamed
|
||||
, public nsIAsyncShutdownBlocker
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -444,27 +446,98 @@ public:
|
|||
static void
|
||||
Create(const nsACString& aURI, bool aBroadcastToOtherProcesses)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<ReleasingTimerHolder> holder =
|
||||
new ReleasingTimerHolder(aURI, aBroadcastToOtherProcesses);
|
||||
|
||||
auto raii = mozilla::MakeScopeExit([&] {
|
||||
holder->CancelTimerAndRevokeURI();
|
||||
});
|
||||
|
||||
nsresult rv = NS_NewTimerWithCallback(getter_AddRefs(holder->mTimer),
|
||||
holder, RELEASING_TIMER,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
SystemGroup::EventTargetFor(TaskCategory::Other));
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
nsCOMPtr<nsIAsyncShutdownClient> phase = GetShutdownPhase();
|
||||
NS_ENSURE_TRUE_VOID(!!phase);
|
||||
|
||||
rv = phase->AddBlocker(holder, NS_LITERAL_STRING(__FILE__), __LINE__,
|
||||
NS_LITERAL_STRING("ReleasingTimerHolder shutdown"));
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
raii.release();
|
||||
}
|
||||
|
||||
// nsITimerCallback interface
|
||||
|
||||
NS_IMETHOD
|
||||
Notify(nsITimer* aTimer) override
|
||||
{
|
||||
RevokeURI(mBroadcastToOtherProcesses);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsINamed interface
|
||||
|
||||
NS_IMETHOD
|
||||
GetName(nsACString& aName) override
|
||||
{
|
||||
aName.AssignLiteral("ReleasingTimerHolder");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIAsyncShutdownBlocker interface
|
||||
|
||||
NS_IMETHOD
|
||||
GetName(nsAString& aName) override
|
||||
{
|
||||
aName.AssignLiteral("ReleasingTimerHolder");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
BlockShutdown(nsIAsyncShutdownClient* aClient) override
|
||||
{
|
||||
CancelTimerAndRevokeURI();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetState(nsIPropertyBag**) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
ReleasingTimerHolder(const nsACString& aURI, bool aBroadcastToOtherProcesses)
|
||||
: mURI(aURI)
|
||||
, mBroadcastToOtherProcesses(aBroadcastToOtherProcesses)
|
||||
{}
|
||||
|
||||
~ReleasingTimerHolder()
|
||||
{}
|
||||
|
||||
void
|
||||
RevokeURI(bool aBroadcastToOtherProcesses)
|
||||
{
|
||||
// Remove the shutting down blocker
|
||||
nsCOMPtr<nsIAsyncShutdownClient> phase = GetShutdownPhase();
|
||||
if (phase) {
|
||||
phase->RemoveBlocker(this);
|
||||
}
|
||||
|
||||
// If we have to broadcast the unregistration, let's do it now.
|
||||
if (mBroadcastToOtherProcesses) {
|
||||
if (aBroadcastToOtherProcesses) {
|
||||
BroadcastBlobURLUnregistration(mURI);
|
||||
}
|
||||
|
||||
DataInfo* info = GetDataInfo(mURI, true /* We care about revoked dataInfo */);
|
||||
if (!info) {
|
||||
// Already gone!
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(info->mRevoked);
|
||||
|
@ -481,25 +554,31 @@ public:
|
|||
delete gDataTable;
|
||||
gDataTable = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetName(nsACString& aName) override
|
||||
void
|
||||
CancelTimerAndRevokeURI()
|
||||
{
|
||||
aName.AssignLiteral("ReleasingTimerHolder");
|
||||
return NS_OK;
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
|
||||
RevokeURI(false /* aBroadcastToOtherProcesses */);
|
||||
}
|
||||
|
||||
private:
|
||||
ReleasingTimerHolder(const nsACString& aURI, bool aBroadcastToOtherProcesses)
|
||||
: mURI(aURI)
|
||||
, mBroadcastToOtherProcesses(aBroadcastToOtherProcesses)
|
||||
{}
|
||||
static nsCOMPtr<nsIAsyncShutdownClient>
|
||||
GetShutdownPhase()
|
||||
{
|
||||
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
|
||||
NS_ENSURE_TRUE(!!svc, nullptr);
|
||||
|
||||
~ReleasingTimerHolder()
|
||||
{}
|
||||
nsCOMPtr<nsIAsyncShutdownClient> phase;
|
||||
nsresult rv = svc->GetXpcomWillShutdown(getter_AddRefs(phase));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return Move(phase);
|
||||
}
|
||||
|
||||
nsCString mURI;
|
||||
bool mBroadcastToOtherProcesses;
|
||||
|
@ -507,7 +586,8 @@ private:
|
|||
nsCOMPtr<nsITimer> mTimer;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ReleasingTimerHolder, nsITimerCallback, nsINamed)
|
||||
NS_IMPL_ISUPPORTS(ReleasingTimerHolder, nsITimerCallback, nsINamed,
|
||||
nsIAsyncShutdownBlocker)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -5237,11 +5237,14 @@ public:
|
|||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
if (!mElement) {
|
||||
return;
|
||||
}
|
||||
mElement->NotifyMediaStreamTracksAvailable(aStream);
|
||||
}
|
||||
|
||||
private:
|
||||
HTMLMediaElement* mElement;
|
||||
WeakPtr<HTMLMediaElement> mElement;
|
||||
};
|
||||
|
||||
class HTMLMediaElement::MediaStreamTrackListener :
|
||||
|
|
|
@ -155,7 +155,9 @@ HTMLOutputElement::SetDefaultValue(const nsAString& aDefaultValue, ErrorResult&
|
|||
{
|
||||
mDefaultValue = aDefaultValue;
|
||||
if (mValueModeFlag == eModeDefault) {
|
||||
aRv = nsContentUtils::SetNodeTextContent(this, mDefaultValue, true);
|
||||
// We can't pass mDefaultValue, because it'll be truncated when
|
||||
// the element's descendants are changed.
|
||||
aRv = nsContentUtils::SetNodeTextContent(this, aDefaultValue, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -323,8 +323,7 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
// We disable this code path on Windows version earlier of Windows 8 due to
|
||||
// intermittent crashes with old drivers. See bug 1405110.
|
||||
if (IsWin8OrLater() && !XRE_IsParentProcess() &&
|
||||
aAllocator && aAllocator->GetCompositorBackendType()
|
||||
== layers::LayersBackend::LAYERS_D3D11) {
|
||||
aAllocator && aAllocator->SupportsD3D11()) {
|
||||
RefPtr<layers::D3D11YCbCrImage> d3d11Image = new layers::D3D11YCbCrImage();
|
||||
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
|
||||
if (d3d11Image->SetData(layers::ImageBridgeChild::GetSingleton()
|
||||
|
|
|
@ -532,11 +532,7 @@ WMFVideoMFTManager::InitializeDXVA()
|
|||
return false;
|
||||
}
|
||||
MOZ_ASSERT(!mDXVA2Manager);
|
||||
LayersBackend backend = GetCompositorBackendType(mKnowsCompositor);
|
||||
bool useANGLE =
|
||||
mKnowsCompositor ? mKnowsCompositor->GetCompositorUseANGLE() : false;
|
||||
bool wrWithANGLE = (backend == LayersBackend::LAYERS_WR) && useANGLE;
|
||||
if (backend != LayersBackend::LAYERS_D3D11 && !wrWithANGLE) {
|
||||
if (!mKnowsCompositor || !mKnowsCompositor->SupportsD3D11()) {
|
||||
mDXVAFailureReason.AssignLiteral("Unsupported layers backend");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,11 +21,11 @@ using namespace mozilla::dom;
|
|||
NS_IMETHODIMP
|
||||
ScriptElement::ScriptAvailable(nsresult aResult,
|
||||
nsIScriptElement* aElement,
|
||||
bool aIsInline,
|
||||
bool aIsInlineClassicScript,
|
||||
nsIURI* aURI,
|
||||
int32_t aLineNo)
|
||||
{
|
||||
if (!aIsInline && NS_FAILED(aResult)) {
|
||||
if (!aIsInlineClassicScript && NS_FAILED(aResult)) {
|
||||
nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
|
||||
if (parser) {
|
||||
parser->PushDefinedInsertionPoint();
|
||||
|
|
|
@ -69,7 +69,9 @@ public:
|
|||
|
||||
void FireScriptAvailable(nsresult aResult)
|
||||
{
|
||||
mElement->ScriptAvailable(aResult, mElement, mIsInline, mURI, mLineNo);
|
||||
bool isInlineClassicScript = mIsInline && !IsModuleRequest();
|
||||
mElement->ScriptAvailable(aResult, mElement, isInlineClassicScript, mURI,
|
||||
mLineNo);
|
||||
}
|
||||
void FireScriptEvaluated(nsresult aResult)
|
||||
{
|
||||
|
|
|
@ -1860,6 +1860,8 @@ ScriptLoader::GetScriptSource(ScriptLoadRequest* aRequest, nsAutoString& inlineD
|
|||
nsresult
|
||||
ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest)
|
||||
{
|
||||
LOG(("ScriptLoadRequest (%p): Process request", aRequest));
|
||||
|
||||
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
|
||||
"Processing requests when running scripts is unsafe.");
|
||||
NS_ASSERTION(aRequest->IsReadyToRun(),
|
||||
|
@ -1871,6 +1873,7 @@ ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest)
|
|||
!aRequest->AsModuleRequest()->mModuleScript)
|
||||
{
|
||||
// There was an error fetching a module script. Nothing to do here.
|
||||
LOG(("ScriptLoadRequest (%p): Error loading request, firing error", aRequest));
|
||||
FireScriptAvailable(NS_ERROR_FAILURE, aRequest);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2892,7 +2895,7 @@ ScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
|||
MOZ_ASSERT(!modReq->IsTopLevel());
|
||||
MOZ_ASSERT(!modReq->isInList());
|
||||
modReq->Cancel();
|
||||
FireScriptAvailable(rv, aRequest);
|
||||
// A single error is fired for the top level module.
|
||||
} else if (mParserBlockingRequest == aRequest) {
|
||||
MOZ_ASSERT(!aRequest->isInList());
|
||||
mParserBlockingRequest = nullptr;
|
||||
|
|
|
@ -10,7 +10,7 @@ interface nsIURI;
|
|||
|
||||
[scriptable, uuid(7b787204-76fb-4764-96f1-fb7a666db4f4)]
|
||||
interface nsIScriptLoaderObserver : nsISupports {
|
||||
|
||||
|
||||
/**
|
||||
* The script is available for evaluation. For inline scripts, this
|
||||
* method will be called synchronously. For externally loaded scripts,
|
||||
|
@ -20,15 +20,16 @@ interface nsIScriptLoaderObserver : nsISupports {
|
|||
* a script. If this is a failure code, script evaluation
|
||||
* will not occur.
|
||||
* @param aElement The element being processed.
|
||||
* @param aIsInline Is this an inline script or externally loaded?
|
||||
* @param aIsInline Is this an inline classic script (as opposed to an
|
||||
* externally loaded classic script or module script)?
|
||||
* @param aURI What is the URI of the script (the document URI if
|
||||
* it is inline).
|
||||
* @param aLineNo At what line does the script appear (generally 1
|
||||
* if it is a loaded script).
|
||||
*/
|
||||
void scriptAvailable(in nsresult aResult,
|
||||
void scriptAvailable(in nsresult aResult,
|
||||
in nsIScriptElement aElement,
|
||||
in boolean aIsInline,
|
||||
in boolean aIsInlineClassicScript,
|
||||
in nsIURI aURI,
|
||||
in int32_t aLineNo);
|
||||
|
||||
|
@ -40,8 +41,7 @@ interface nsIScriptLoaderObserver : nsISupports {
|
|||
* @param aElement The element being processed.
|
||||
* @param aIsInline Is this an inline script or externally loaded?
|
||||
*/
|
||||
void scriptEvaluated(in nsresult aResult,
|
||||
void scriptEvaluated(in nsresult aResult,
|
||||
in nsIScriptElement aElement,
|
||||
in boolean aIsInline);
|
||||
|
||||
};
|
||||
|
|
|
@ -954,7 +954,7 @@ NS_IMPL_ISUPPORTS(txTransformNotifier,
|
|||
NS_IMETHODIMP
|
||||
txTransformNotifier::ScriptAvailable(nsresult aResult,
|
||||
nsIScriptElement *aElement,
|
||||
bool aIsInline,
|
||||
bool aIsInlineClassicScript,
|
||||
nsIURI *aURI,
|
||||
int32_t aLineNo)
|
||||
{
|
||||
|
|
12
gfx/2d/2D.h
12
gfx/2d/2D.h
|
@ -558,6 +558,18 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates how many times the surface has been invalidated.
|
||||
*/
|
||||
virtual int32_t Invalidations() const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the invalidation counter.
|
||||
*/
|
||||
virtual void Invalidate() { }
|
||||
|
||||
protected:
|
||||
bool mIsMapped;
|
||||
};
|
||||
|
|
|
@ -477,8 +477,7 @@ ImageContainer::GetD3D11YCbCrRecycleAllocator(KnowsCompositor* aAllocator)
|
|||
device = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
|
||||
}
|
||||
|
||||
LayersBackend backend = aAllocator->GetCompositorBackendType();
|
||||
if (!device || backend != LayersBackend::LAYERS_D3D11) {
|
||||
if (!device || !aAllocator->SupportsD3D11()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -128,6 +128,7 @@ public:
|
|||
, mStride(0)
|
||||
, mMapCount(0)
|
||||
, mHandleCount(0)
|
||||
, mInvalidations(0)
|
||||
, mFormat(SurfaceFormat::UNKNOWN)
|
||||
, mClosed(false)
|
||||
, mFinalized(false)
|
||||
|
@ -248,6 +249,25 @@ public:
|
|||
return mFinalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates how many times the surface has been invalidated.
|
||||
*/
|
||||
int32_t Invalidations() const override
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mInvalidations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the invalidation counter.
|
||||
*/
|
||||
void Invalidate() override
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
++mInvalidations;
|
||||
MOZ_ASSERT(mInvalidations >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* While a HandleLock exists for the given surface, the shared memory handle
|
||||
* cannot be released.
|
||||
|
@ -314,6 +334,7 @@ private:
|
|||
int32_t mStride;
|
||||
int32_t mMapCount;
|
||||
int32_t mHandleCount;
|
||||
int32_t mInvalidations;
|
||||
IntSize mSize;
|
||||
RefPtr<SharedMemoryBasic> mBuf;
|
||||
RefPtr<SharedMemoryBasic> mOldBuf;
|
||||
|
|
|
@ -94,6 +94,12 @@ public:
|
|||
return mTextureFactoryIdentifier.mSupportsComponentAlpha;
|
||||
}
|
||||
|
||||
bool SupportsD3D11() const
|
||||
{
|
||||
return GetCompositorBackendType() == layers::LayersBackend::LAYERS_D3D11 ||
|
||||
(GetCompositorBackendType() == layers::LayersBackend::LAYERS_WR && GetCompositorUseANGLE());
|
||||
}
|
||||
|
||||
bool GetCompositorUseANGLE() const
|
||||
{
|
||||
return mTextureFactoryIdentifier.mCompositorUseANGLE;
|
||||
|
|
|
@ -22,23 +22,23 @@ class SharedSurfacesChild::ImageKeyData final
|
|||
public:
|
||||
ImageKeyData(WebRenderLayerManager* aManager,
|
||||
const wr::ImageKey& aImageKey,
|
||||
uint32_t aGenerationId)
|
||||
int32_t aInvalidations)
|
||||
: mManager(aManager)
|
||||
, mImageKey(aImageKey)
|
||||
, mGenerationId(aGenerationId)
|
||||
, mInvalidations(aInvalidations)
|
||||
{ }
|
||||
|
||||
ImageKeyData(ImageKeyData&& aOther)
|
||||
: mManager(Move(aOther.mManager))
|
||||
, mImageKey(aOther.mImageKey)
|
||||
, mGenerationId(aOther.mGenerationId)
|
||||
, mInvalidations(aOther.mInvalidations)
|
||||
{ }
|
||||
|
||||
ImageKeyData& operator=(ImageKeyData&& aOther)
|
||||
{
|
||||
mManager = Move(aOther.mManager);
|
||||
mImageKey = aOther.mImageKey;
|
||||
mGenerationId = aOther.mGenerationId;
|
||||
mInvalidations = aOther.mInvalidations;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ public:
|
|||
|
||||
RefPtr<WebRenderLayerManager> mManager;
|
||||
wr::ImageKey mImageKey;
|
||||
uint32_t mGenerationId;
|
||||
int32_t mInvalidations;
|
||||
};
|
||||
|
||||
class SharedSurfacesChild::SharedUserData final
|
||||
|
@ -117,7 +117,7 @@ public:
|
|||
|
||||
wr::ImageKey UpdateKey(WebRenderLayerManager* aManager,
|
||||
wr::IpcResourceUpdateQueue& aResources,
|
||||
uint32_t aGenerationId)
|
||||
int32_t aInvalidations)
|
||||
{
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(!aManager->IsDestroyed());
|
||||
|
@ -138,9 +138,9 @@ public:
|
|||
mKeys.RemoveElementAt(i);
|
||||
} else if (entry.mManager == aManager) {
|
||||
found = true;
|
||||
if (entry.mGenerationId != aGenerationId) {
|
||||
if (entry.mInvalidations != aInvalidations) {
|
||||
aManager->AddImageKeyForDiscard(entry.mImageKey);
|
||||
entry.mGenerationId = aGenerationId;
|
||||
entry.mInvalidations = aInvalidations;
|
||||
entry.mImageKey = aManager->WrBridge()->GetNextImageKey();
|
||||
aResources.AddExternalImage(mId, entry.mImageKey);
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ public:
|
|||
|
||||
if (!found) {
|
||||
key = aManager->WrBridge()->GetNextImageKey();
|
||||
ImageKeyData data(aManager, key, aGenerationId);
|
||||
ImageKeyData data(aManager, key, aInvalidations);
|
||||
mKeys.AppendElement(Move(data));
|
||||
aResources.AddExternalImage(mId, key);
|
||||
}
|
||||
|
@ -176,7 +176,6 @@ SharedSurfacesChild::DestroySharedUserData(void* aClosure)
|
|||
SharedSurfacesChild::Share(SourceSurfaceSharedData* aSurface,
|
||||
WebRenderLayerManager* aManager,
|
||||
wr::IpcResourceUpdateQueue& aResources,
|
||||
uint32_t aGenerationId,
|
||||
wr::ImageKey& aKey)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -188,6 +187,12 @@ SharedSurfacesChild::Share(SourceSurfaceSharedData* aSurface,
|
|||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// Each time the surface changes, the producers of SourceSurfaceSharedData
|
||||
// surfaces promise to increment the invalidation counter each time the
|
||||
// surface has changed. We can use this counter to determine whether or not
|
||||
// we should upate our paired ImageKey.
|
||||
int32_t invalidations = aSurface->Invalidations();
|
||||
|
||||
static UserDataKey sSharedKey;
|
||||
SharedUserData* data =
|
||||
static_cast<SharedUserData*>(aSurface->GetUserData(&sSharedKey));
|
||||
|
@ -200,7 +205,7 @@ SharedSurfacesChild::Share(SourceSurfaceSharedData* aSurface,
|
|||
data->SetId(manager->GetNextExternalImageId());
|
||||
} else if (data->IsShared()) {
|
||||
// It has already been shared with the GPU process, reuse the id.
|
||||
aKey = data->UpdateKey(aManager, aResources, aGenerationId);
|
||||
aKey = data->UpdateKey(aManager, aResources, invalidations);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -218,7 +223,7 @@ SharedSurfacesChild::Share(SourceSurfaceSharedData* aSurface,
|
|||
if (pid == base::GetCurrentProcId()) {
|
||||
SharedSurfacesParent::AddSameProcess(data->Id(), aSurface);
|
||||
data->MarkShared();
|
||||
aKey = data->UpdateKey(aManager, aResources, aGenerationId);
|
||||
aKey = data->UpdateKey(aManager, aResources, invalidations);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -253,7 +258,7 @@ SharedSurfacesChild::Share(SourceSurfaceSharedData* aSurface,
|
|||
SurfaceDescriptorShared(aSurface->GetSize(),
|
||||
aSurface->Stride(),
|
||||
format, handle));
|
||||
aKey = data->UpdateKey(aManager, aResources, aGenerationId);
|
||||
aKey = data->UpdateKey(aManager, aResources, invalidations);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -271,9 +276,8 @@ SharedSurfacesChild::Share(ImageContainer* aContainer,
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
uint32_t generation = 0;
|
||||
AutoTArray<ImageContainer::OwningImage,4> images;
|
||||
aContainer->GetCurrentImages(&images, &generation);
|
||||
aContainer->GetCurrentImages(&images);
|
||||
if (images.IsEmpty()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
@ -288,8 +292,7 @@ SharedSurfacesChild::Share(ImageContainer* aContainer,
|
|||
}
|
||||
|
||||
auto sharedSurface = static_cast<SourceSurfaceSharedData*>(surface.get());
|
||||
return Share(sharedSurface, aManager, aResources,
|
||||
generation, aKey);
|
||||
return Share(sharedSurface, aManager, aResources, aKey);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
|
|
@ -33,7 +33,6 @@ public:
|
|||
static nsresult Share(gfx::SourceSurfaceSharedData* aSurface,
|
||||
WebRenderLayerManager* aManager,
|
||||
wr::IpcResourceUpdateQueue& aResources,
|
||||
uint32_t aGenerationId,
|
||||
wr::ImageKey& aKey);
|
||||
|
||||
static nsresult Share(ImageContainer* aContainer,
|
||||
|
|
|
@ -40,7 +40,8 @@ StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParen
|
|||
// Compute scale for fallback rendering.
|
||||
gfx::Matrix transform2d;
|
||||
if (aBoundTransform && aBoundTransform->CanDraw2D(&transform2d)) {
|
||||
mScale = transform2d.ScaleFactors(true) * aParentSC.mScale;
|
||||
mInheritedTransform = transform2d * aParentSC.mInheritedTransform;
|
||||
mScale = mInheritedTransform.ScaleFactors(true);
|
||||
}
|
||||
|
||||
mBuilder->PushStackingContext(wr::LayoutRect(),
|
||||
|
|
|
@ -68,12 +68,18 @@ public:
|
|||
// Export the inherited scale
|
||||
gfx::Size GetInheritedScale() const { return mScale; }
|
||||
|
||||
const gfx::Matrix& GetInheritedTransform() const
|
||||
{
|
||||
return mInheritedTransform;
|
||||
}
|
||||
|
||||
bool IsBackfaceVisible() const { return mTransform.IsBackfaceVisible(); }
|
||||
|
||||
private:
|
||||
wr::DisplayListBuilder* mBuilder;
|
||||
gfx::Matrix4x4 mTransform;
|
||||
gfx::Size mScale;
|
||||
gfx::Matrix mInheritedTransform;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_FONTCONFIG_FONTS_H
|
||||
#define GFX_FONTCONFIG_FONTS_H
|
||||
|
||||
#include "cairo.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxTextRun.h"
|
||||
|
||||
#include "nsAutoRef.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include <pango/pango.h>
|
||||
|
||||
class gfxFcFontSet;
|
||||
class gfxFcFont;
|
||||
typedef struct _FcPattern FcPattern;
|
||||
typedef struct FT_FaceRec_* FT_Face;
|
||||
typedef struct FT_LibraryRec_ *FT_Library;
|
||||
|
||||
#endif /* GFX_FONTCONFIG_FONTS_H */
|
|
@ -13,13 +13,13 @@
|
|||
#include "nsUnicodeProperties.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxFcPlatformFontList.h"
|
||||
#include "gfxFontconfigFonts.h"
|
||||
#include "gfxConfig.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "gfxFT2FontBase.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "VsyncSource.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
|
|
@ -460,6 +460,7 @@ private:
|
|||
DECL_GFX_PREF(Once, "gfx.direct3d11.enable-debug-layer", Direct3D11EnableDebugLayer, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.direct3d11.break-on-error", Direct3D11BreakOnError, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.direct3d11.sleep-on-create-device", Direct3D11SleepOnCreateDevice, int32_t, 0);
|
||||
DECL_GFX_PREF(Live, "gfx.downloadable_fonts.keep_color_bitmaps", KeepColorBitmaps, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.downloadable_fonts.keep_variation_tables", KeepVariationTables, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.downloadable_fonts.otl_validation", ValidateOTLTables, bool, true);
|
||||
DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false);
|
||||
|
|
|
@ -180,6 +180,8 @@ public:
|
|||
mCheckOTLTables = gfxPrefs::ValidateOTLTables();
|
||||
// Whether to preserve Variation tables in downloaded fonts
|
||||
mKeepVariationTables = gfxPrefs::KeepVariationTables();
|
||||
// Whether to preserve color bitmap glyphs
|
||||
mKeepColorBitmaps = gfxPrefs::KeepColorBitmaps();
|
||||
}
|
||||
|
||||
virtual ots::TableAction GetTableAction(uint32_t aTag) override {
|
||||
|
@ -199,7 +201,11 @@ public:
|
|||
aTag == TRUETYPE_TAG('V', 'V', 'A', 'R'))) ||
|
||||
aTag == TRUETYPE_TAG('S', 'V', 'G', ' ') ||
|
||||
aTag == TRUETYPE_TAG('C', 'O', 'L', 'R') ||
|
||||
aTag == TRUETYPE_TAG('C', 'P', 'A', 'L')) {
|
||||
aTag == TRUETYPE_TAG('C', 'P', 'A', 'L') ||
|
||||
(mKeepColorBitmaps &&
|
||||
(aTag == TRUETYPE_TAG('C', 'B', 'D', 'T') ||
|
||||
aTag == TRUETYPE_TAG('C', 'B', 'L', 'C'))) ||
|
||||
false) {
|
||||
return ots::TABLE_ACTION_PASSTHRU;
|
||||
}
|
||||
return ots::TABLE_ACTION_DEFAULT;
|
||||
|
@ -232,6 +238,7 @@ private:
|
|||
nsTHashtable<nsCStringHashKey> mWarningsIssued;
|
||||
bool mCheckOTLTables;
|
||||
bool mKeepVariationTables;
|
||||
bool mKeepColorBitmaps;
|
||||
};
|
||||
|
||||
// Call the OTS library to sanitize an sfnt before attempting to use it.
|
||||
|
|
|
@ -101,7 +101,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
|||
]
|
||||
elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
||||
EXPORTS += [
|
||||
'gfxFontconfigFonts.h',
|
||||
'gfxFT2FontBase.h',
|
||||
'gfxGdkNativeRenderer.h',
|
||||
'gfxPlatformGtk.h',
|
||||
|
|
|
@ -27,3 +27,5 @@ win64.patch: SSE2 optimization for Microsoft Visual C++ x64 version
|
|||
TypeFromSize.patch: Bug 656185 - Add a method to detect YUVType from plane sizes.
|
||||
|
||||
QuellGccWarnings.patch: Bug 711895 - Avoid some GCC compilation warnings.
|
||||
|
||||
clang-cl-workaround.patch: Bug 1422368 - Work around a clang-cl unresolved symbol bug.
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
diff --git a/gfx/ycbcr/yuv_row_win.cpp b/gfx/ycbcr/yuv_row_win.cpp
|
||||
--- a/gfx/ycbcr/yuv_row_win.cpp
|
||||
+++ b/gfx/ycbcr/yuv_row_win.cpp
|
||||
@@ -6,16 +6,22 @@
|
||||
#include "mozilla/SSE.h"
|
||||
|
||||
#define kCoefficientsRgbU kCoefficientsRgbY + 2048
|
||||
#define kCoefficientsRgbV kCoefficientsRgbY + 4096
|
||||
|
||||
extern "C" {
|
||||
|
||||
#if defined(MOZILLA_MAY_SUPPORT_SSE) && defined(_M_IX86)
|
||||
+#if defined(__clang__)
|
||||
+// clang-cl may erroneously discard the symbol `kCoefficientsRgbY`
|
||||
+// https://bugs.llvm.org/show_bug.cgi?id=35290
|
||||
+volatile auto keep_kCoefficientsRgbY_alive = &kCoefficientsRgbY;
|
||||
+#endif
|
||||
+
|
||||
__declspec(naked)
|
||||
void FastConvertYUVToRGB32Row_SSE(const uint8* y_buf,
|
||||
const uint8* u_buf,
|
||||
const uint8* v_buf,
|
||||
uint8* rgb_buf,
|
||||
int width) {
|
||||
__asm {
|
||||
pushad
|
|
@ -10,3 +10,4 @@ patch -p3 <convert.patch
|
|||
patch -p3 <win64.patch
|
||||
patch -p3 <TypeFromSize.patch
|
||||
patch -p3 <QuellGccWarnings.patch
|
||||
patch -p3 <clang-cl-workaround.patch
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
extern "C" {
|
||||
|
||||
#if defined(MOZILLA_MAY_SUPPORT_SSE) && defined(_M_IX86)
|
||||
#if defined(__clang__)
|
||||
// clang-cl may erroneously discard the symbol `kCoefficientsRgbY`
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=35290
|
||||
volatile auto keep_kCoefficientsRgbY_alive = &kCoefficientsRgbY;
|
||||
#endif
|
||||
|
||||
__declspec(naked)
|
||||
void FastConvertYUVToRGB32Row_SSE(const uint8* y_buf,
|
||||
const uint8* u_buf,
|
||||
|
|
|
@ -684,7 +684,10 @@ RasterImage::GetImageContainerAtSize(LayerManager* aManager,
|
|||
const Maybe<SVGImageContext>& aSVGContext,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
return GetImageContainerImpl(aManager, aSize, aSVGContext, aFlags);
|
||||
// We do not pass in the given SVG context because in theory it could differ
|
||||
// between calls, but actually have no impact on the actual contents of the
|
||||
// image container.
|
||||
return GetImageContainerImpl(aManager, aSize, Nothing(), aFlags);
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
|
@ -610,6 +610,14 @@ imgFrame::ImageUpdatedInternal(const nsIntRect& aUpdateRect)
|
|||
// decoded rect that extends outside the bounds of the frame rect.
|
||||
mDecoded.IntersectRect(mDecoded, mFrameRect);
|
||||
|
||||
// Update our invalidation counters for any consumers watching for changes
|
||||
// in the surface.
|
||||
if (mRawSurface) {
|
||||
mRawSurface->Invalidate();
|
||||
}
|
||||
if (mLockedSurface && mRawSurface != mLockedSurface) {
|
||||
mLockedSurface->Invalidate();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -980,6 +980,13 @@ BackgroundParentImpl::DeallocPClientManagerParent(mozilla::dom::PClientManagerPa
|
|||
return mozilla::dom::DeallocClientManagerParent(aActor);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundParentImpl::RecvPClientManagerConstructor(mozilla::dom::PClientManagerParent* aActor)
|
||||
{
|
||||
mozilla::dom::InitClientManagerParent(aActor);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -268,6 +268,9 @@ protected:
|
|||
|
||||
virtual bool
|
||||
DeallocPClientManagerParent(PClientManagerParent* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvPClientManagerConstructor(PClientManagerParent* aActor) override;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
|
|
@ -2688,7 +2688,7 @@ js::LoadScalar##T::Func(JSContext* cx, unsigned argc, Value* vp)
|
|||
\
|
||||
JS::AutoCheckCannotGC nogc(cx); \
|
||||
T* target = reinterpret_cast<T*>(typedObj.typedMem(offset, nogc)); \
|
||||
args.rval().setNumber((double) *target); \
|
||||
args.rval().setNumber(JS::CanonicalizeNaN((double) *target)); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
var Uint32Array = TypedObject.float32.array(3);
|
||||
const ONE_MINUS_EPSILON = 1 - Math.pow(2, -53);
|
||||
const f = new Float64Array([0, 0]);
|
||||
const u = new Uint32Array(f.buffer);
|
||||
const diff = function(a, b) {
|
||||
f[1] = b;
|
||||
u[3 - ENDIAN];
|
||||
};
|
||||
ENDIAN = 1;
|
||||
diff(1, ONE_MINUS_EPSILON)
|
|
@ -96,7 +96,7 @@
|
|||
assertEq(runningInBrowser, false, "Only called when running in the shell.");
|
||||
|
||||
// Return early if no options are set.
|
||||
var currentOptions = options();
|
||||
var currentOptions = options ? options() : "";
|
||||
if (currentOptions === "")
|
||||
return;
|
||||
|
||||
|
|
|
@ -26,13 +26,13 @@ SUPPORT_FILES = set(["browser.js", "shell.js", "template.js", "user.js",
|
|||
FRONTMATTER_WRAPPER_PATTERN = re.compile(
|
||||
r'/\*\---\n([\s]*)((?:\s|\S)*)[\n\s*]---\*/', flags=re.DOTALL)
|
||||
|
||||
def convertTestFile(source):
|
||||
def convertTestFile(source, includes):
|
||||
"""
|
||||
Convert a jstest test to a compatible Test262 test file.
|
||||
"""
|
||||
|
||||
source = convertReportCompare(source)
|
||||
source = updateMeta(source)
|
||||
source = updateMeta(source, includes)
|
||||
source = insertCopyrightLines(source)
|
||||
|
||||
return source
|
||||
|
@ -153,7 +153,7 @@ def extractMeta(source):
|
|||
|
||||
return yaml.safe_load(unindented)
|
||||
|
||||
def updateMeta(source):
|
||||
def updateMeta(source, includes):
|
||||
"""
|
||||
Captures the reftest meta and a pre-existing meta if any and merge them
|
||||
into a single dict.
|
||||
|
@ -166,13 +166,14 @@ def updateMeta(source):
|
|||
frontmatter = extractMeta(source)
|
||||
|
||||
# Merge the reftest and frontmatter
|
||||
merged = mergeMeta(reftest, frontmatter)
|
||||
merged = mergeMeta(reftest, frontmatter, includes)
|
||||
|
||||
# Cleanup the metadata
|
||||
properData = cleanupMeta(merged)
|
||||
|
||||
return insertMeta(source, properData)
|
||||
|
||||
|
||||
def cleanupMeta(meta):
|
||||
"""
|
||||
Clean up all the frontmatter meta tags. This is not a lint tool, just a
|
||||
|
@ -206,7 +207,7 @@ def cleanupMeta(meta):
|
|||
|
||||
return meta
|
||||
|
||||
def mergeMeta(reftest, frontmatter):
|
||||
def mergeMeta(reftest, frontmatter, includes):
|
||||
"""
|
||||
Merge the metadata from reftest and an existing frontmatter and populate
|
||||
required frontmatter fields properly.
|
||||
|
@ -250,6 +251,10 @@ def mergeMeta(reftest, frontmatter):
|
|||
"frontmatter error. %s != %s" % (error,
|
||||
frontmatter["negative"]["type"]))
|
||||
|
||||
# Add the shell specific includes
|
||||
if includes:
|
||||
frontmatter["includes"] = list(includes)
|
||||
|
||||
return frontmatter
|
||||
|
||||
def insertCopyrightLines(source):
|
||||
|
@ -295,53 +300,117 @@ def insertMeta(source, frontmatter):
|
|||
else:
|
||||
return "\n".join(lines) + source
|
||||
|
||||
|
||||
|
||||
def findAndCopyIncludes(dirPath, baseDir, includeDir):
|
||||
relPath = os.path.relpath(dirPath, baseDir)
|
||||
includes = []
|
||||
|
||||
# Recurse down all folders in the relative path until
|
||||
# we reach the base directory of shell.js include files.
|
||||
# Each directory will have a shell.js file to copy.
|
||||
while (relPath):
|
||||
|
||||
# find the shell.js
|
||||
shellFile = os.path.join(baseDir, relPath, "shell.js")
|
||||
|
||||
# create new shell.js file name
|
||||
includeFileName = relPath.replace("/", "-") + "-shell.js"
|
||||
includesPath = os.path.join(includeDir, includeFileName)
|
||||
|
||||
if os.path.exists(shellFile):
|
||||
# if the file exists, include in includes
|
||||
includes.append(includeFileName)
|
||||
|
||||
if not os.path.exists(includesPath):
|
||||
shutil.copyfile(shellFile, includesPath)
|
||||
|
||||
relPath = os.path.split(relPath)[0]
|
||||
|
||||
|
||||
shellFile = os.path.join(baseDir, "shell.js")
|
||||
includesPath = os.path.join(includeDir, "shell.js")
|
||||
if not os.path.exists(includesPath):
|
||||
shutil.copyfile(shellFile, includesPath)
|
||||
|
||||
includes.append("shell.js")
|
||||
|
||||
if not os.path.exists(includesPath):
|
||||
shutil.copyfile(shellFile, includesPath)
|
||||
|
||||
return includes
|
||||
|
||||
def exportTest262(args):
|
||||
src = os.path.abspath(args.src[0])
|
||||
|
||||
outDir = os.path.abspath(args.out)
|
||||
providedSrcs = args.src
|
||||
includeShell = args.exportshellincludes
|
||||
baseDir = os.getcwd()
|
||||
|
||||
# Create the output directory from scratch.
|
||||
if os.path.isdir(outDir):
|
||||
shutil.rmtree(outDir)
|
||||
|
||||
# Process all test directories recursively.
|
||||
for (dirPath, _, fileNames) in os.walk(src):
|
||||
relPath = os.path.relpath(dirPath, src)
|
||||
# only make the includes directory if requested
|
||||
includeDir = os.path.join(outDir, "harness-includes")
|
||||
if includeShell:
|
||||
os.makedirs(includeDir)
|
||||
|
||||
relOutDir = os.path.join(outDir, relPath)
|
||||
# Go through each source path
|
||||
for providedSrc in providedSrcs:
|
||||
|
||||
# This also creates the own outDir folder
|
||||
if not os.path.exists(relOutDir):
|
||||
os.makedirs(relOutDir)
|
||||
src = os.path.abspath(providedSrc)
|
||||
# the basename of the path will be used in case multiple "src" arguments
|
||||
# are passed in to create an output directory for each "src".
|
||||
basename = os.path.basename(src)
|
||||
|
||||
for fileName in fileNames:
|
||||
# Skip browser.js and shell.js files
|
||||
if fileName == "browser.js" or fileName == "shell.js":
|
||||
continue
|
||||
# Process all test directories recursively.
|
||||
for (dirPath, _, fileNames) in os.walk(src):
|
||||
|
||||
filePath = os.path.join(dirPath, fileName)
|
||||
testName = os.path.relpath(filePath, src) # captures folder/fileName
|
||||
# we need to make and get the unique set of includes for this filepath
|
||||
includes = []
|
||||
if includeShell:
|
||||
includes = findAndCopyIncludes(dirPath, baseDir, includeDir)
|
||||
|
||||
# Copy non-test files as is.
|
||||
(_, fileExt) = os.path.splitext(fileName)
|
||||
if fileExt != ".js":
|
||||
shutil.copyfile(filePath, os.path.join(outDir, testName))
|
||||
print("C %s" % testName)
|
||||
continue
|
||||
relPath = os.path.relpath(dirPath, src)
|
||||
fullRelPath = os.path.join(basename, relPath)
|
||||
|
||||
# Read the original test source and preprocess it for Test262
|
||||
with open(filePath, "rb") as testFile:
|
||||
testSource = testFile.read()
|
||||
# Make new test subdirectory to seperate from includes
|
||||
currentOutDir = os.path.join(outDir, "tests", fullRelPath)
|
||||
|
||||
if not testSource:
|
||||
print("SKIPPED %s" % testName)
|
||||
continue
|
||||
# This also creates the own outDir folder
|
||||
if not os.path.exists(currentOutDir):
|
||||
os.makedirs(currentOutDir)
|
||||
|
||||
newSource = convertTestFile(testSource)
|
||||
for fileName in fileNames:
|
||||
# Skip browser.js files
|
||||
if fileName == "browser.js" or fileName == "shell.js" :
|
||||
continue
|
||||
|
||||
with open(os.path.join(outDir, testName), "wb") as output:
|
||||
output.write(newSource)
|
||||
filePath = os.path.join(dirPath, fileName)
|
||||
testName = os.path.join(fullRelPath, fileName) # captures folder(s)+filename
|
||||
|
||||
print("SAVED %s" % testName)
|
||||
# Copy non-test files as is.
|
||||
(_, fileExt) = os.path.splitext(fileName)
|
||||
if fileExt != ".js":
|
||||
shutil.copyfile(filePath, os.path.join(currentOutDir, fileName))
|
||||
print("C %s" % testName)
|
||||
continue
|
||||
|
||||
# Read the original test source and preprocess it for Test262
|
||||
with open(filePath, "rb") as testFile:
|
||||
testSource = testFile.read()
|
||||
|
||||
if not testSource:
|
||||
print("SKIPPED %s" % testName)
|
||||
continue
|
||||
|
||||
newSource = convertTestFile(testSource, includes)
|
||||
|
||||
with open(os.path.join(currentOutDir, fileName), "wb") as output:
|
||||
output.write(newSource)
|
||||
|
||||
print("SAVED %s" % testName)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
@ -353,6 +422,8 @@ if __name__ == "__main__":
|
|||
parser = argparse.ArgumentParser(description="Export tests to match Test262 file compliance.")
|
||||
parser.add_argument("--out", default="test262/export",
|
||||
help="Output directory. Any existing directory will be removed! (default: %(default)s)")
|
||||
parser.add_argument("--exportshellincludes", action="store_true",
|
||||
help="Optionally export shell.js files as includes in exported tests. Only use for testing, do not use for exporting to test262 (test262 tests should have as few dependencies as possible).")
|
||||
parser.add_argument("src", nargs="+", help="Source folder with test files to export")
|
||||
parser.set_defaults(func=exportTest262)
|
||||
args = parser.parse_args()
|
||||
|
|
|
@ -6766,6 +6766,8 @@ ComputeSnappedImageDrawingParameters(gfxContext* aCtx,
|
|||
// Snap even if we have a scale in the context. But don't snap if
|
||||
// we have something that's not translation+scale, or if the scale flips in
|
||||
// the X or Y direction, because snapped image drawing can't handle that yet.
|
||||
// Any changes to this algorithm will need to be reflected in
|
||||
// ComputeImageContainerDrawingParameters.
|
||||
if (!currentMatrix.HasNonAxisAlignedTransform() &&
|
||||
currentMatrix._11 > 0.0 && currentMatrix._22 > 0.0 &&
|
||||
aCtx->UserToDevicePixelSnapped(fill, true) &&
|
||||
|
@ -7191,15 +7193,49 @@ nsLayoutUtils::ComputeImageContainerDrawingParameters(imgIContainer*
|
|||
viewportSize.height)));
|
||||
}
|
||||
|
||||
// Compute our size in layer pixels.
|
||||
const LayerIntSize layerSize =
|
||||
RoundedToInt(LayerSize(aDestRect.Width() * scaleFactors.width,
|
||||
aDestRect.Height() * scaleFactors.height));
|
||||
// Attempt to snap pixels, the same as ComputeSnappedImageDrawingParameters.
|
||||
// Any changes to the algorithm here will need to be reflected there.
|
||||
bool snapped = false;
|
||||
gfxSize gfxLayerSize;
|
||||
const gfx::Matrix& itm = aSc.GetInheritedTransform();
|
||||
if (!itm.HasNonAxisAlignedTransform() &&
|
||||
itm._11 > 0.0 &&
|
||||
itm._22 > 0.0) {
|
||||
gfxRect rect(gfxPoint(aDestRect.X(), aDestRect.Y()),
|
||||
gfxSize(aDestRect.Width(), aDestRect.Height()));
|
||||
|
||||
gfxPoint p1 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopLeft())));
|
||||
gfxPoint p2 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopRight())));
|
||||
gfxPoint p3 = ThebesPoint(itm.TransformPoint(ToPoint(rect.BottomRight())));
|
||||
|
||||
if (p2 == gfxPoint(p1.x, p3.y) || p2 == gfxPoint(p3.x, p1.y)) {
|
||||
p1.Round();
|
||||
p3.Round();
|
||||
|
||||
rect.MoveTo(gfxPoint(std::min(p1.x, p3.x), std::min(p1.y, p3.y)));
|
||||
rect.SizeTo(gfxSize(std::max(p1.x, p3.x) - rect.X(),
|
||||
std::max(p1.y, p3.y) - rect.Y()));
|
||||
|
||||
// An empty size is unacceptable so we ensure our suggested size is at
|
||||
// least 1 pixel wide/tall.
|
||||
gfxLayerSize = gfxSize(std::max(rect.Width(), 1.0),
|
||||
std::max(rect.Height(), 1.0));
|
||||
snapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!snapped) {
|
||||
// Compute our size in layer pixels.
|
||||
const LayerIntSize layerSize =
|
||||
RoundedToInt(LayerSize(aDestRect.Width() * scaleFactors.width,
|
||||
aDestRect.Height() * scaleFactors.height));
|
||||
|
||||
// An empty size is unacceptable so we ensure our suggested size is at least
|
||||
// 1 pixel wide/tall.
|
||||
gfxLayerSize = gfxSize(std::max(layerSize.width, 1),
|
||||
std::max(layerSize.height, 1));
|
||||
}
|
||||
|
||||
// Determine the optimal image size to use. An empty size is unacceptable so
|
||||
// we ensure our suggested size is at least 1 pixel wide/tall.
|
||||
gfxSize gfxLayerSize = gfxSize(std::max(layerSize.width, 1),
|
||||
std::max(layerSize.height, 1));
|
||||
return aImage->OptimalImageSizeForDest(gfxLayerSize,
|
||||
imgIContainer::FRAME_CURRENT,
|
||||
samplingFilter, aFlags);
|
||||
|
|
|
@ -2829,7 +2829,6 @@ static nsresult
|
|||
pref_LoadPrefsInDirList(const char* aListId);
|
||||
|
||||
static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
|
||||
static const char kOldTelemetryPref[] = "toolkit.telemetry.enabledPreRelease";
|
||||
static const char kChannelPref[] = "app.update.channel";
|
||||
|
||||
// clang-format off
|
||||
|
@ -3485,12 +3484,6 @@ Preferences::InitializeUserPrefs()
|
|||
// Don't set mCurrentFile until we're done so that dirty flags work properly.
|
||||
sPreferences->mCurrentFile = prefsFile.forget();
|
||||
|
||||
// Migrate the old prerelease telemetry pref.
|
||||
if (!Preferences::GetBool(kOldTelemetryPref, true)) {
|
||||
Preferences::SetBoolInAnyProcess(kTelemetryPref, false);
|
||||
Preferences::ClearUser(kOldTelemetryPref);
|
||||
}
|
||||
|
||||
sPreferences->NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
|
||||
}
|
||||
|
||||
|
|
|
@ -791,6 +791,11 @@ pref("gfx.downloadable_fonts.otl_validation", false);
|
|||
pref("gfx.downloadable_fonts.otl_validation", true);
|
||||
#endif
|
||||
|
||||
// Whether to preserve color bitmap tables in fonts (bypassing OTS).
|
||||
// Currently these are supported only on platforms where we use Freetype
|
||||
// to render fonts (Linux/Gtk and Android).
|
||||
pref("gfx.downloadable_fonts.keep_color_bitmaps", false);
|
||||
|
||||
// Whether to preserve OpenType variation tables in fonts (bypassing OTS)
|
||||
pref("gfx.downloadable_fonts.keep_variation_tables", false);
|
||||
|
||||
|
|
|
@ -866,6 +866,10 @@ nsHostResolver::ResolveHost(const char *host,
|
|||
LOG_HOST(host, netInterface),
|
||||
(af == PR_AF_INET) ? "AF_INET" : "AF_INET6"));
|
||||
|
||||
// We need to lock in case any other thread is reading
|
||||
// addr_info.
|
||||
MutexAutoLock lock(he->rec->addr_info_lock);
|
||||
|
||||
he->rec->addr_info = nullptr;
|
||||
if (unspecHe->rec->negative) {
|
||||
he->rec->negative = unspecHe->rec->negative;
|
||||
|
|
|
@ -6949,7 +6949,13 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
// earlier in ReadFromCache, so this must be a response from the network.
|
||||
MOZ_ASSERT(request == mTransactionPump);
|
||||
LOG((" First response from network\n"));
|
||||
mFirstResponseSource = RESPONSE_FROM_NETWORK;
|
||||
{
|
||||
// Race condition with OnCacheEntryCheck, which is not limited
|
||||
// to main thread.
|
||||
mozilla::MutexAutoLock lock(mRCWNLock);
|
||||
mFirstResponseSource = RESPONSE_FROM_NETWORK;
|
||||
mOnStartRequestTimestamp = TimeStamp::Now();
|
||||
}
|
||||
mAvailableCachedAltDataType.Truncate();
|
||||
} else if (WRONG_RACING_RESPONSE_SOURCE(request)) {
|
||||
LOG((" Early return when racing. This response not needed."));
|
||||
|
@ -6965,7 +6971,9 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
"If we have both pumps, the cache content must be partial");
|
||||
|
||||
mAfterOnStartRequestBegun = true;
|
||||
mOnStartRequestTimestamp = TimeStamp::Now();
|
||||
if (mOnStartRequestTimestamp.IsNull()) {
|
||||
mOnStartRequestTimestamp = TimeStamp::Now();
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::HTTP_ONSTART_SUSPEND_TOTAL_TIME,
|
||||
mSuspendTotalTime);
|
||||
|
|
|
@ -105,14 +105,14 @@ this.ContentTaskUtils = {
|
|||
return;
|
||||
}
|
||||
subject.removeEventListener(eventName, listener, capture);
|
||||
resolve(event);
|
||||
setTimeout(() => resolve(event), 0);
|
||||
} catch (ex) {
|
||||
try {
|
||||
subject.removeEventListener(eventName, listener, capture);
|
||||
} catch (ex2) {
|
||||
// Maybe the provided object does not support removeEventListener.
|
||||
}
|
||||
reject(ex);
|
||||
setTimeout(() => reject(ex), 0);
|
||||
}
|
||||
}, capture, wantsUntrusted);
|
||||
});
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[HTMLOutputElement.html]
|
||||
type: testharness
|
||||
[defaultValue on HTMLOutputElement must enqueue disconnectedCallback when removing a custom element]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[fetch-error-2.html]
|
||||
type: testharness
|
||||
[Test that failure to fetch dependency leads to error event on script.]
|
||||
expected: FAIL
|
||||
|
|
@ -11149,14 +11149,6 @@
|
|||
"n_values": 20,
|
||||
"description": "Methods invoked under window.crypto.subtle (0=encrypt, 1=decrypt, 2=sign, 3=verify, 4=digest, 5=generateKey, 6=deriveKey, 7=deriveBits, 8=importKey, 9=exportKey, 10=wrapKey, 11=unwrapKey)"
|
||||
},
|
||||
"WEBCRYPTO_METHOD_SECURE": {
|
||||
"alert_emails": ["seceng-telemetry@mozilla.com"],
|
||||
"record_in_processes": ["main", "content"],
|
||||
"expires_in_version": "60",
|
||||
"kind": "boolean",
|
||||
"bug_numbers": [1333140],
|
||||
"description": "Whether a method invoked under window.crypto.subtle is in a secure context"
|
||||
},
|
||||
"WEBCRYPTO_ALG": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"expires_in_version": "never",
|
||||
|
|
Загрузка…
Ссылка в новой задаче