зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team. a=merge
This commit is contained in:
Коммит
5e7b5cb82f
|
@ -8,8 +8,7 @@ add_task(function* () {
|
|||
|
||||
ok(historyButton && devButton, "Draggable elements should exist");
|
||||
simulateItemDrag(historyButton, devButton);
|
||||
gCustomizeMode.reset();
|
||||
yield waitForCondition(() => !gCustomizeMode.resetting);
|
||||
yield gCustomizeMode.reset();
|
||||
ok(CustomizableUI.inDefaultState, "Should be back in default state");
|
||||
|
||||
historyButton = document.getElementById("wrapper-history-panelmenu");
|
||||
|
|
|
@ -14,8 +14,7 @@ add_task(function*() {
|
|||
ok(devButton && downloadsButton && searchBox && palette, "Stuff should exist");
|
||||
simulateItemDrag(devButton, downloadsButton);
|
||||
simulateItemDrag(searchBox, palette);
|
||||
gCustomizeMode.reset();
|
||||
yield waitForCondition(() => !gCustomizeMode.resetting);
|
||||
yield gCustomizeMode.reset();
|
||||
ok(CustomizableUI.inDefaultState, "Should be back in default state");
|
||||
yield endCustomizing();
|
||||
});
|
||||
|
|
|
@ -37,8 +37,7 @@ add_task(function*() {
|
|||
is(CustomizableUI.inDefaultState, false, "Should no longer be in default state");
|
||||
|
||||
yield startCustomizing();
|
||||
gCustomizeMode.reset();
|
||||
yield waitForCondition(() => !gCustomizeMode.resetting);
|
||||
yield gCustomizeMode.reset();
|
||||
yield endCustomizing();
|
||||
|
||||
is(bookmarksToolbar.collapsed, true, "Customization reset should restore collapsed-state to the bookmarks toolbar");
|
||||
|
@ -61,8 +60,7 @@ add_task(function*() {
|
|||
isnot(menubar.getBoundingClientRect().height, 0, "menubar should be visible now");
|
||||
|
||||
yield startCustomizing();
|
||||
gCustomizeMode.reset();
|
||||
yield waitForCondition(() => !gCustomizeMode.resetting);
|
||||
yield gCustomizeMode.reset();
|
||||
|
||||
is(menubar.getAttribute("autohide"), "true", "The menubar should have autohide=true after reset in customization mode");
|
||||
is(menubar.getBoundingClientRect().height, 0, "The menubar should have height=0 after reset in customization mode");
|
||||
|
@ -89,8 +87,7 @@ add_task(function*() {
|
|||
ok(!navbar.collapsed, "The navbar should be visible before reset");
|
||||
ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
|
||||
|
||||
gCustomizeMode.reset();
|
||||
yield waitForCondition(() => !gCustomizeMode.resetting);
|
||||
yield gCustomizeMode.reset();
|
||||
|
||||
ok(bookmarksToolbar.collapsed, "The bookmarksToolbar should be collapsed after reset");
|
||||
ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
|
||||
|
|
|
@ -21,9 +21,9 @@ add_task(function*() {
|
|||
ok(CustomizableUI.inDefaultState, "In default state after reset");
|
||||
is(undoResetButton.hidden, false, "The undo button is visible after reset");
|
||||
|
||||
undoResetButton.click();
|
||||
yield waitForCondition(() => !gCustomizeMode.resetting);
|
||||
ok(!CustomizableUI.inDefaultState, "Not in default state after reset-undo");
|
||||
yield gCustomizeMode.undoReset()
|
||||
|
||||
ok(!CustomizableUI.inDefaultState, "Not in default state after undo-reset");
|
||||
is(undoResetButton.hidden, true, "The undo button is hidden after clicking on the undo button");
|
||||
is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ const {utils: Cu} = Components;
|
|||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PreviewProvider",
|
||||
"resource:///modules/PreviewProvider.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
|
||||
|
@ -28,8 +30,13 @@ const ACTIONS = {
|
|||
prefs: {
|
||||
inPrefs: "REQUEST_PREFS",
|
||||
outPrefs: "RECEIVE_PREFS",
|
||||
action_types: new Set(["REQUEST_PREFS", "RECEIVE_PREFS"]),
|
||||
}
|
||||
action_types: new Set(["REQUEST_PREFS"]),
|
||||
},
|
||||
preview: {
|
||||
inThumb: "REQUEST_THUMB",
|
||||
outThumb: "RECEIVE_THUMB",
|
||||
action_types: new Set(["REQUEST_THUMB"]),
|
||||
},
|
||||
};
|
||||
|
||||
let NewTabMessages = {
|
||||
|
@ -42,12 +49,20 @@ let NewTabMessages = {
|
|||
* Return to the originator all newtabpage prefs. A point-to-point request.
|
||||
*/
|
||||
handlePrefRequest(actionName, {target}) {
|
||||
if (ACTIONS.prefs.action_types.has(actionName)) {
|
||||
if (ACTIONS.prefs.inPrefs === actionName) {
|
||||
let results = NewTabPrefsProvider.prefs.newtabPagePrefs;
|
||||
NewTabWebChannel.send(ACTIONS.prefs.outPrefs, results, target);
|
||||
}
|
||||
},
|
||||
|
||||
handlePreviewRequest(actionName, {data, target}) {
|
||||
if (ACTIONS.preview.inThumb === actionName) {
|
||||
PreviewProvider.getThumbnail(data).then(imgData => {
|
||||
NewTabWebChannel.send(ACTIONS.preview.outThumb, {url: data, imgData}, target);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Broadcast preference changes to all open newtab pages
|
||||
*/
|
||||
|
@ -68,14 +83,24 @@ let NewTabMessages = {
|
|||
},
|
||||
|
||||
init() {
|
||||
this.handlePrefRequest = this.handlePrefRequest.bind(this);
|
||||
this.handlePreviewRequest = this.handlePreviewRequest.bind(this);
|
||||
this.handlePrefChange = this.handlePrefChange.bind(this);
|
||||
this._handleEnabledChange = this._handleEnabledChange.bind(this);
|
||||
|
||||
NewTabPrefsProvider.prefs.init();
|
||||
NewTabWebChannel.init();
|
||||
|
||||
this._prefs.enabled = Preferences.get(PREF_ENABLED, false);
|
||||
|
||||
if (this._prefs.enabled) {
|
||||
NewTabWebChannel.on(ACTIONS.prefs.inPrefs, this.handlePrefRequest.bind(this));
|
||||
NewTabPrefsProvider.prefs.on(PREF_ENABLED, this._handleEnabledChange.bind(this));
|
||||
NewTabWebChannel.on(ACTIONS.prefs.inPrefs, this.handlePrefRequest);
|
||||
NewTabWebChannel.on(ACTIONS.preview.inThumb, this.handlePreviewRequest);
|
||||
|
||||
NewTabPrefsProvider.prefs.on(PREF_ENABLED, this._handleEnabledChange);
|
||||
|
||||
for (let pref of NewTabPrefsProvider.newtabPagePrefSet) {
|
||||
NewTabPrefsProvider.prefs.on(pref, this.handlePrefChange.bind(this));
|
||||
NewTabPrefsProvider.prefs.on(pref, this.handlePrefChange);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -87,9 +112,13 @@ let NewTabMessages = {
|
|||
NewTabPrefsProvider.prefs.off(PREF_ENABLED, this._handleEnabledChange);
|
||||
|
||||
NewTabWebChannel.off(ACTIONS.prefs.inPrefs, this.handlePrefRequest);
|
||||
NewTabWebChannel.off(ACTIONS.prefs.inThumb, this.handlePreviewRequest);
|
||||
for (let pref of NewTabPrefsProvider.newtabPagePrefSet) {
|
||||
NewTabPrefsProvider.prefs.off(pref, this.handlePrefChange);
|
||||
}
|
||||
}
|
||||
|
||||
NewTabPrefsProvider.prefs.uninit();
|
||||
NewTabWebChannel.uninit();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/* global XPCOMUtils, BackgroundPageThumbs, FileUtils, PageThumbsStorage, Task, MIMEService */
|
||||
/* exported PreviewProvider */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PreviewProvider"];
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/PageThumbs.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
const {OS} = Cu.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BackgroundPageThumbs",
|
||||
"resource://gre/modules/BackgroundPageThumbs.jsm");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "MIMEService",
|
||||
"@mozilla.org/mime;1", "nsIMIMEService");
|
||||
|
||||
let PreviewProvider = {
|
||||
/**
|
||||
* Returns a thumbnail as a data URI for a url, creating it if necessary
|
||||
*
|
||||
* @param {String} url
|
||||
* a url to obtain a thumbnail for
|
||||
* @return {Promise} A Promise that resolves with a base64 encoded thumbnail
|
||||
*/
|
||||
getThumbnail: Task.async(function* PreviewProvider_getThumbnail(url) {
|
||||
try {
|
||||
yield BackgroundPageThumbs.captureIfMissing(url);
|
||||
let imgPath = PageThumbsStorage.getFilePathForURL(url);
|
||||
|
||||
// OS.File object used to easily read off-thread
|
||||
let file = yield OS.File.open(imgPath, {read: true, existing: true});
|
||||
|
||||
// nsIFile object needed for MIMEService
|
||||
let nsFile = FileUtils.File(imgPath);
|
||||
|
||||
let contentType = MIMEService.getTypeFromFile(nsFile);
|
||||
let bytes = yield file.read();
|
||||
let encodedData = btoa(String.fromCharCode.apply(null, bytes));
|
||||
file.close();
|
||||
return `data:${contentType};base64,${encodedData}`;
|
||||
} catch (err) {
|
||||
Cu.reportError(`PreviewProvider_getThumbnail error: ${err}`);
|
||||
throw err;
|
||||
}
|
||||
})
|
||||
};
|
|
@ -16,7 +16,8 @@ EXTRA_JS_MODULES += [
|
|||
'NewTabRemoteResources.jsm',
|
||||
'NewTabURL.jsm',
|
||||
'NewTabWebChannel.jsm',
|
||||
'PlacesProvider.jsm'
|
||||
'PlacesProvider.jsm',
|
||||
'PreviewProvider.jsm'
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body style="background-color: blue">
|
||||
</body>
|
||||
</html>
|
|
@ -1,9 +1,12 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
blue_page.html
|
||||
dummy_page.html
|
||||
newtabwebchannel_basic.html
|
||||
newtabmessages_prefs.html
|
||||
newtabmessages_preview.html
|
||||
|
||||
[browser_PreviewProvider.js]
|
||||
[browser_remotenewtab_pageloads.js]
|
||||
[browser_newtab_overrides.js]
|
||||
[browser_newtabmessages.js]
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* globals XPCOMUtils, Services, PreviewProvider, registerCleanupFunction */
|
||||
"use strict";
|
||||
|
||||
let Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PreviewProvider",
|
||||
"resource:///modules/PreviewProvider.jsm");
|
||||
|
||||
var oldEnabledPref = Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled");
|
||||
Services.prefs.setBoolPref("browser.pagethumbnails.capturing_disabled", false);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
}
|
||||
Services.prefs.setBoolPref("browser.pagethumbnails.capturing_disabled", oldEnabledPref);
|
||||
});
|
||||
|
||||
const TEST_URL = "https://example.com/browser/browser/components/newtab/tests/browser/blue_page.html";
|
||||
|
||||
function pixelsForDataURI(dataURI, options) {
|
||||
return new Promise(resolve => {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
let {width, height} = options;
|
||||
if (!width) {
|
||||
width = 100;
|
||||
}
|
||||
if (!height) {
|
||||
height = 100;
|
||||
}
|
||||
|
||||
let htmlns = "http://www.w3.org/1999/xhtml";
|
||||
let img = document.createElementNS(htmlns, "img");
|
||||
img.setAttribute("src", dataURI);
|
||||
|
||||
img.addEventListener("load", function onLoad() {
|
||||
img.removeEventListener("load", onLoad, true);
|
||||
let canvas = document.createElementNS(htmlns, "canvas");
|
||||
canvas.setAttribute("width", width);
|
||||
canvas.setAttribute("height", height);
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
let result = ctx.getImageData(0, 0, width, height).data;
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function* chunk_four(listData) {
|
||||
let index = 0;
|
||||
while (index < listData.length) {
|
||||
yield listData.slice(index, index + 5);
|
||||
index += 4;
|
||||
}
|
||||
}
|
||||
|
||||
add_task(function* open_page() {
|
||||
let dataURI = yield PreviewProvider.getThumbnail(TEST_URL);
|
||||
let pixels = yield pixelsForDataURI(dataURI, {width: 10, height: 10});
|
||||
let rgbCount = {r: 0, g: 0, b: 0, a: 0};
|
||||
for (let [r, g, b, a] of chunk_four(pixels)) {
|
||||
if (r === 255) {
|
||||
rgbCount.r += 1;
|
||||
}
|
||||
if (g === 255) {
|
||||
rgbCount.g += 1;
|
||||
}
|
||||
if (b === 255) {
|
||||
rgbCount.b += 1;
|
||||
}
|
||||
if (a === 255) {
|
||||
rgbCount.a += 1;
|
||||
}
|
||||
}
|
||||
Assert.equal(`${rgbCount.r},${rgbCount.g},${rgbCount.b},${rgbCount.a}`,
|
||||
"0,0,100,100", "there should be 100 blue-only pixels at full opacity");
|
||||
});
|
||||
|
||||
add_task(function* invalid_url() {
|
||||
try {
|
||||
yield PreviewProvider.getThumbnail("invalid:URL");
|
||||
} catch (err) {
|
||||
Assert.ok(true, "URL Failed");
|
||||
}
|
||||
});
|
|
@ -17,7 +17,6 @@ function setup() {
|
|||
|
||||
function cleanup() {
|
||||
NewTabMessages.uninit();
|
||||
NewTabWebChannel.tearDownState();
|
||||
Preferences.set("browser.newtabpage.remote", false);
|
||||
Preferences.set("browser.newtabpage.remote.mode", "production");
|
||||
}
|
||||
|
@ -55,3 +54,32 @@ add_task(function* prefMessages_request() {
|
|||
});
|
||||
cleanup();
|
||||
});
|
||||
|
||||
/*
|
||||
* Sanity tests for preview messages
|
||||
*/
|
||||
add_task(function* previewMessages_request() {
|
||||
setup();
|
||||
var oldEnabledPref = Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled");
|
||||
Services.prefs.setBoolPref("browser.pagethumbnails.capturing_disabled", false);
|
||||
|
||||
let testURL = "https://example.com/browser/browser/components/newtab/tests/browser/newtabmessages_preview.html";
|
||||
|
||||
let tabOptions = {
|
||||
gBrowser,
|
||||
url: testURL
|
||||
};
|
||||
|
||||
let previewResponseAck = new Promise(resolve => {
|
||||
NewTabWebChannel.once("responseAck", () => {
|
||||
ok(true, "a request response has been received");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.withNewTab(tabOptions, function*() {
|
||||
yield previewResponseAck;
|
||||
});
|
||||
cleanup();
|
||||
Services.prefs.setBoolPref("browser.pagethumbnails.capturing_disabled", oldEnabledPref);
|
||||
});
|
||||
|
|
|
@ -7,12 +7,22 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
|
||||
"resource:///modules/NewTabWebChannel.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabMessages",
|
||||
"resource:///modules/NewTabMessages.jsm");
|
||||
|
||||
const TEST_URL = "https://example.com/browser/browser/components/newtab/tests/browser/newtabwebchannel_basic.html";
|
||||
const TEST_URL_2 = "http://mochi.test:8888/browser/browser/components/newtab/tests/browser/newtabwebchannel_basic.html";
|
||||
|
||||
function setup(mode = "test") {
|
||||
Preferences.set("browser.newtabpage.remote.mode", mode);
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
NewTabWebChannel.init();
|
||||
NewTabMessages.init();
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
NewTabWebChannel.tearDownState();
|
||||
NewTabMessages.uninit();
|
||||
NewTabWebChannel.uninit();
|
||||
Preferences.set("browser.newtabpage.remote", false);
|
||||
Preferences.set("browser.newtabpage.remote.mode", "production");
|
||||
}
|
||||
|
@ -22,8 +32,7 @@ registerCleanupFunction(cleanup);
|
|||
* Tests flow of messages from newtab to chrome and chrome to newtab
|
||||
*/
|
||||
add_task(function* open_webchannel_basic() {
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test");
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
setup();
|
||||
|
||||
let tabOptions = {
|
||||
gBrowser,
|
||||
|
@ -72,8 +81,7 @@ add_task(function* open_webchannel_basic() {
|
|||
* Tests message broadcast reaches all open newtab pages
|
||||
*/
|
||||
add_task(function* webchannel_broadcast() {
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test");
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
setup();
|
||||
|
||||
let countingMessagePromise = new Promise(resolve => {
|
||||
let count = 0;
|
||||
|
@ -133,8 +141,7 @@ add_task(function* webchannel_broadcast() {
|
|||
* Tests switching modes
|
||||
*/
|
||||
add_task(function* webchannel_switch() {
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test");
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
setup();
|
||||
|
||||
function newMessagePromise() {
|
||||
return new Promise(resolve => {
|
||||
|
@ -195,8 +202,7 @@ add_task(function* webchannel_switch() {
|
|||
});
|
||||
|
||||
add_task(function* open_webchannel_reload() {
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test");
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
setup();
|
||||
|
||||
let tabOptions = {
|
||||
gBrowser,
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Newtab WebChannel test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
let thumbURL = "https://example.com/browser/browser/components/newtab/tests/browser/blue_page.html";
|
||||
|
||||
window.addEventListener("WebChannelMessageToContent", function(e) {
|
||||
if (e.detail.message && e.detail.message.type === "RECEIVE_THUMB") {
|
||||
if (e.detail.message.data.imgData && e.detail.message.data.url === thumbURL) {
|
||||
let reply = new window.CustomEvent("WebChannelMessageToChrome", {
|
||||
detail: {
|
||||
id: "newtab",
|
||||
message: JSON.stringify({type: "responseAck"}),
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(reply);
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
document.onreadystatechange = function () {
|
||||
if (document.readyState === "complete") {
|
||||
let msg = new window.CustomEvent("WebChannelMessageToChrome", {
|
||||
detail: {
|
||||
id: "newtab",
|
||||
message: JSON.stringify({type: "REQUEST_THUMB", data: thumbURL}),
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -27,12 +27,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "DirectoryLinksProvider",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
|
||||
"resource://gre/modules/NewTabUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
|
||||
"resource:///modules/NewTabWebChannel.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabMessages",
|
||||
"resource:///modules/NewTabMessages.jsm");
|
||||
|
||||
|
@ -759,8 +753,6 @@ BrowserGlue.prototype = {
|
|||
NewTabUtils.links.addProvider(DirectoryLinksProvider);
|
||||
AboutNewTab.init();
|
||||
|
||||
NewTabPrefsProvider.prefs.init();
|
||||
NewTabWebChannel.init();
|
||||
NewTabMessages.init();
|
||||
|
||||
SessionStore.init();
|
||||
|
@ -1066,8 +1058,6 @@ BrowserGlue.prototype = {
|
|||
}
|
||||
|
||||
SelfSupportBackend.uninit();
|
||||
NewTabPrefsProvider.prefs.uninit();
|
||||
NewTabWebChannel.uninit();
|
||||
NewTabMessages.uninit();
|
||||
|
||||
AboutNewTab.uninit();
|
||||
|
|
|
@ -218,13 +218,17 @@ const Tree = module.exports = createClass({
|
|||
this.props.onExpand(item);
|
||||
this.state.seen.add(item);
|
||||
|
||||
for (let child of this.props.getChildren(item)) {
|
||||
autoExpand(child, currentDepth + 1);
|
||||
const children = this.props.getChildren(item);
|
||||
const length = children.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
autoExpand(children[i], currentDepth + 1);
|
||||
}
|
||||
};
|
||||
|
||||
for (let root of this.props.getRoots()) {
|
||||
autoExpand(root, 0);
|
||||
const roots = this.props.getRoots();
|
||||
const length = roots.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
autoExpand(roots[i], 0);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -315,8 +319,10 @@ const Tree = module.exports = createClass({
|
|||
return traversal;
|
||||
}
|
||||
|
||||
for (let child of this.props.getChildren(item)) {
|
||||
this._dfs(child, maxDepth, traversal, nextDepth);
|
||||
const children = this.props.getChildren(item);
|
||||
const length = children.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
this._dfs(children[i], maxDepth, traversal, nextDepth);
|
||||
}
|
||||
|
||||
return traversal;
|
||||
|
@ -328,8 +334,10 @@ const Tree = module.exports = createClass({
|
|||
_dfsFromRoots(maxDepth = Infinity) {
|
||||
const traversal = [];
|
||||
|
||||
for (let root of this.props.getRoots()) {
|
||||
this._dfs(root, maxDepth, traversal);
|
||||
const roots = this.props.getRoots();
|
||||
const length = roots.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
this._dfs(roots[i], maxDepth, traversal);
|
||||
}
|
||||
|
||||
return traversal;
|
||||
|
@ -346,8 +354,10 @@ const Tree = module.exports = createClass({
|
|||
this.props.onExpand(item);
|
||||
|
||||
if (expandAllChildren) {
|
||||
for (let { item: child } of this._dfs(item)) {
|
||||
this.props.onExpand(child);
|
||||
const children = this._dfs(item);
|
||||
const length = children.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
this.props.onExpand(children[i].item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +463,11 @@ const Tree = module.exports = createClass({
|
|||
// doesn't exist, we're at the first node already.
|
||||
|
||||
let prev;
|
||||
for (let { item } of this._dfsFromRoots()) {
|
||||
|
||||
const traversal = this._dfsFromRoots();
|
||||
const length = traversal.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const item = traversal[i].item;
|
||||
if (item === this.props.focused) {
|
||||
break;
|
||||
}
|
||||
|
@ -477,10 +491,11 @@ const Tree = module.exports = createClass({
|
|||
// doesn't exist, we're at the last node already.
|
||||
|
||||
const traversal = this._dfsFromRoots();
|
||||
|
||||
const length = traversal.length;
|
||||
let i = 0;
|
||||
for (let { item } of traversal) {
|
||||
if (item === this.props.focused) {
|
||||
|
||||
while (i < length) {
|
||||
if (traversal[i].item === this.props.focused) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
|
|
|
@ -1071,7 +1071,7 @@ nsDefaultURIFixup::KeywordURIFixup(const nsACString& aURIString,
|
|||
}
|
||||
|
||||
bool
|
||||
nsDefaultURIFixup::IsDomainWhitelisted(const nsAutoCString aAsciiHost,
|
||||
nsDefaultURIFixup::IsDomainWhitelisted(const nsACString& aAsciiHost,
|
||||
const uint32_t aDotLoc)
|
||||
{
|
||||
if (sDNSFirstForSingleWords) {
|
||||
|
@ -1098,7 +1098,7 @@ nsDefaultURIFixup::IsDomainWhitelisted(const nsACString& aDomain,
|
|||
const uint32_t aDotLoc,
|
||||
bool* aResult)
|
||||
{
|
||||
*aResult = IsDomainWhitelisted(nsAutoCString(aDomain), aDotLoc);
|
||||
*aResult = IsDomainWhitelisted(aDomain, aDotLoc);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ private:
|
|||
bool PossiblyHostPortUrl(const nsACString& aUrl);
|
||||
bool MakeAlternateURI(nsIURI* aURI);
|
||||
bool IsLikelyFTP(const nsCString& aHostSpec);
|
||||
bool IsDomainWhitelisted(const nsAutoCString aAsciiHost,
|
||||
bool IsDomainWhitelisted(const nsACString& aAsciiHost,
|
||||
const uint32_t aDotLoc);
|
||||
};
|
||||
|
||||
|
|
|
@ -69,6 +69,8 @@ using namespace mozilla;
|
|||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::ipc;
|
||||
|
||||
static const int kMinTelemetryMessageSize = 8192;
|
||||
|
||||
nsFrameMessageManager::nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
|
||||
nsFrameMessageManager* aParentManager,
|
||||
/* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags)
|
||||
|
@ -730,6 +732,12 @@ nsFrameMessageManager::SendMessage(const nsAString& aMessageName,
|
|||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
|
||||
if (data.DataLength() >= kMinTelemetryMessageSize) {
|
||||
Telemetry::Accumulate(Telemetry::MESSAGE_MANAGER_MESSAGE_SIZE,
|
||||
NS_ConvertUTF16toUTF8(aMessageName),
|
||||
data.DataLength());
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> objects(aCx);
|
||||
if (aArgc >= 3 && aObjects.isObject()) {
|
||||
objects = &aObjects.toObject();
|
||||
|
@ -810,6 +818,12 @@ nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
|
|||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
|
||||
if (data.DataLength() >= kMinTelemetryMessageSize) {
|
||||
Telemetry::Accumulate(Telemetry::MESSAGE_MANAGER_MESSAGE_SIZE,
|
||||
NS_ConvertUTF16toUTF8(aMessageName),
|
||||
data.DataLength());
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> objects(aCx);
|
||||
if (aArgc >= 3 && aObjects.isObject()) {
|
||||
objects = &aObjects.toObject();
|
||||
|
|
|
@ -1364,7 +1364,6 @@ GK_ATOM(cy, "cy")
|
|||
GK_ATOM(d, "d")
|
||||
GK_ATOM(darken, "darken")
|
||||
GK_ATOM(defs, "defs")
|
||||
GK_ATOM(definition_src, "definition-src")
|
||||
GK_ATOM(deg, "deg")
|
||||
GK_ATOM(desc, "desc")
|
||||
GK_ATOM(diffuseConstant, "diffuseConstant")
|
||||
|
@ -1438,15 +1437,11 @@ GK_ATOM(g, "g")
|
|||
GK_ATOM(gamma, "gamma")
|
||||
// 'generic' conflicts with msvc11 winrt compiler extensions
|
||||
GK_ATOM(generic_, "generic")
|
||||
GK_ATOM(glyph, "glyph")
|
||||
GK_ATOM(glyphRef, "glyphRef")
|
||||
GK_ATOM(glyph_orientation_horizontal, "glyph-orientation-horizontal")
|
||||
GK_ATOM(glyph_orientation_vertical, "glyph-orientation-vertical")
|
||||
GK_ATOM(grad, "grad")
|
||||
GK_ATOM(gradientTransform, "gradientTransform")
|
||||
GK_ATOM(gradientUnits, "gradientUnits")
|
||||
GK_ATOM(hardLight, "hard-light")
|
||||
GK_ATOM(hkern, "hkern")
|
||||
GK_ATOM(hue, "hue")
|
||||
GK_ATOM(hueRotate, "hueRotate")
|
||||
GK_ATOM(identity, "identity")
|
||||
|
@ -1458,7 +1453,6 @@ GK_ATOM(k1, "k1")
|
|||
GK_ATOM(k2, "k2")
|
||||
GK_ATOM(k3, "k3")
|
||||
GK_ATOM(k4, "k4")
|
||||
GK_ATOM(kerning, "kerning")
|
||||
GK_ATOM(kernelMatrix, "kernelMatrix")
|
||||
GK_ATOM(kernelUnitLength, "kernelUnitLength")
|
||||
GK_ATOM(lengthAdjust, "lengthAdjust")
|
||||
|
@ -1587,9 +1581,9 @@ GK_ATOM(userSpaceOnUse, "userSpaceOnUse")
|
|||
GK_ATOM(view, "view")
|
||||
GK_ATOM(viewBox, "viewBox")
|
||||
GK_ATOM(viewTarget, "viewTarget")
|
||||
GK_ATOM(vkern, "vkern")
|
||||
GK_ATOM(white_space, "white-space")
|
||||
GK_ATOM(word_spacing, "word-spacing")
|
||||
GK_ATOM(writing_mode, "writing-mode")
|
||||
GK_ATOM(x, "x")
|
||||
GK_ATOM(x1, "x1")
|
||||
GK_ATOM(x2, "x2")
|
||||
|
|
|
@ -6450,10 +6450,7 @@ nsGlobalWindow::CanMoveResizeWindows(bool aCallerIsChrome)
|
|||
}
|
||||
}
|
||||
|
||||
// The preference is useful for the webapp runtime. Webapps should be able
|
||||
// to resize or move their window.
|
||||
if (mDocShell && !Preferences::GetBool("dom.always_allow_move_resize_window",
|
||||
false)) {
|
||||
if (mDocShell) {
|
||||
bool allow;
|
||||
nsresult rv = mDocShell->GetAllowWindowControl(&allow);
|
||||
if (NS_SUCCEEDED(rv) && !allow)
|
||||
|
|
|
@ -330,9 +330,9 @@ nsIAtom** const kElementsSVG[] = {
|
|||
&nsGkAtoms::font_face_uri, // font-face-uri
|
||||
&nsGkAtoms::foreignObject, // foreignObject
|
||||
&nsGkAtoms::g, // g
|
||||
&nsGkAtoms::glyph, // glyph
|
||||
// glyph
|
||||
&nsGkAtoms::glyphRef, // glyphRef
|
||||
&nsGkAtoms::hkern, // hkern
|
||||
// hkern
|
||||
&nsGkAtoms::image, // image
|
||||
&nsGkAtoms::line, // line
|
||||
&nsGkAtoms::linearGradient, // linearGradient
|
||||
|
@ -358,7 +358,7 @@ nsIAtom** const kElementsSVG[] = {
|
|||
&nsGkAtoms::tspan, // tspan
|
||||
&nsGkAtoms::use, // use
|
||||
&nsGkAtoms::view, // view
|
||||
&nsGkAtoms::vkern, // vkern
|
||||
// vkern
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
@ -431,8 +431,8 @@ nsIAtom** const kAttributesSVG[] = {
|
|||
// g2
|
||||
// glyph-name
|
||||
// glyphRef
|
||||
&nsGkAtoms::glyph_orientation_horizontal, // glyph-orientation-horizontal
|
||||
&nsGkAtoms::glyph_orientation_vertical, // glyph-orientation-vertical
|
||||
// glyph-orientation-horizontal
|
||||
// glyph-orientation-vertical
|
||||
&nsGkAtoms::gradientTransform, // gradientTransform
|
||||
&nsGkAtoms::gradientUnits, // gradientUnits
|
||||
&nsGkAtoms::height, // height
|
||||
|
@ -450,7 +450,7 @@ nsIAtom** const kAttributesSVG[] = {
|
|||
&nsGkAtoms::k2, // k2
|
||||
&nsGkAtoms::k3, // k3
|
||||
&nsGkAtoms::k4, // k4
|
||||
&nsGkAtoms::kerning, // kerning
|
||||
// kerning
|
||||
&nsGkAtoms::kernelMatrix, // kernelMatrix
|
||||
&nsGkAtoms::kernelUnitLength, // kernelUnitLength
|
||||
&nsGkAtoms::keyPoints, // keyPoints
|
||||
|
@ -580,7 +580,7 @@ nsIAtom** const kAttributesSVG[] = {
|
|||
&nsGkAtoms::width, // width
|
||||
// widths
|
||||
&nsGkAtoms::word_spacing, // word-spacing
|
||||
// writing-mode
|
||||
&nsGkAtoms::writing_mode, // writing-mode
|
||||
&nsGkAtoms::x, // x
|
||||
// x-height
|
||||
&nsGkAtoms::x1, // x1
|
||||
|
|
|
@ -3003,9 +3003,6 @@ struct CreateGlobalOptions
|
|||
{
|
||||
static MOZ_CONSTEXPR_VAR ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
|
||||
ProtoAndIfaceCache::NonWindowLike;
|
||||
// Intl API is broken and makes JS_InitStandardClasses fail intermittently,
|
||||
// see bug 934889.
|
||||
static MOZ_CONSTEXPR_VAR bool ForceInitStandardClassesToFalse = true;
|
||||
static void TraceGlobal(JSTracer* aTrc, JSObject* aObj)
|
||||
{
|
||||
mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
|
||||
|
@ -3023,7 +3020,6 @@ struct CreateGlobalOptions<nsGlobalWindow>
|
|||
{
|
||||
static MOZ_CONSTEXPR_VAR ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
|
||||
ProtoAndIfaceCache::WindowLike;
|
||||
static MOZ_CONSTEXPR_VAR bool ForceInitStandardClassesToFalse = false;
|
||||
static void TraceGlobal(JSTracer* aTrc, JSObject* aObj);
|
||||
static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
|
||||
};
|
||||
|
@ -3074,7 +3070,6 @@ CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
|
|||
}
|
||||
|
||||
if (aInitStandardClasses &&
|
||||
!CreateGlobalOptions<T>::ForceInitStandardClassesToFalse &&
|
||||
!JS_InitStandardClasses(aCx, aGlobal)) {
|
||||
NS_WARNING("Failed to init standard classes");
|
||||
return nullptr;
|
||||
|
|
|
@ -955,25 +955,6 @@ DOMInterfaces = {
|
|||
'nativeType': 'mozilla::dom::workers::PushMessageData',
|
||||
},
|
||||
|
||||
'PushManager': [{
|
||||
'workers': False,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
'nativeType': 'mozilla::dom::PushManager',
|
||||
}, {
|
||||
'workers': True,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
'nativeType': 'mozilla::dom::WorkerPushManager',
|
||||
}],
|
||||
|
||||
'PushSubscription': [{
|
||||
'workers': False,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
}, {
|
||||
'workers': True,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
'nativeType': 'mozilla::dom::WorkerPushSubscription',
|
||||
}],
|
||||
|
||||
'Range': {
|
||||
'nativeType': 'nsRange',
|
||||
'binaryNames': {
|
||||
|
@ -1017,6 +998,7 @@ DOMInterfaces = {
|
|||
'ServiceWorkerRegistration': [{
|
||||
'nativeType': 'mozilla::dom::ServiceWorkerRegistrationMainThread',
|
||||
'headerFile': 'mozilla/dom/ServiceWorkerRegistration.h',
|
||||
'implicitJSContext': [ 'pushManager' ],
|
||||
}, {
|
||||
'workers': True,
|
||||
'nativeType': 'mozilla::dom::ServiceWorkerRegistrationWorkerThread',
|
||||
|
|
|
@ -67,7 +67,7 @@ public:
|
|||
}
|
||||
|
||||
static void
|
||||
DumpLocalizedMessage(const nsCString& aMessageName,
|
||||
DumpLocalizedMessage(const nsACString& aMessageName,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
|
@ -81,7 +81,7 @@ public:
|
|||
nsXPIDLString localizedMessage;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
aMessageName.get(),
|
||||
aMessageName.BeginReading(),
|
||||
localizedMessage)))) {
|
||||
return;
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ ScriptErrorHelper::DumpLocalizedMessage(const nsACString& aMessageName,
|
|||
uint64_t aInnerWindowID)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
ScriptErrorRunnable::DumpLocalizedMessage(nsAutoCString(aMessageName),
|
||||
ScriptErrorRunnable::DumpLocalizedMessage(aMessageName,
|
||||
aFilename,
|
||||
aLineNumber,
|
||||
aColumnNumber,
|
||||
|
|
|
@ -56,8 +56,7 @@ Push.prototype = {
|
|||
this._principal = aWindow.document.nodePrincipal;
|
||||
},
|
||||
|
||||
setScope: function(scope){
|
||||
console.debug("setScope()", scope);
|
||||
__init: function(scope) {
|
||||
this._scope = scope;
|
||||
},
|
||||
|
||||
|
@ -209,7 +208,6 @@ PushSubscriptionCallback.prototype = {
|
|||
pushManager._scope,
|
||||
publicKey,
|
||||
authSecret);
|
||||
sub.setPrincipal(pushManager._principal);
|
||||
this.resolve(sub);
|
||||
},
|
||||
|
||||
|
|
|
@ -6,13 +6,10 @@
|
|||
|
||||
#include "mozilla/dom/PushManager.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/PushManagerBinding.h"
|
||||
#include "mozilla/dom/PushSubscriptionBinding.h"
|
||||
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/PushSubscription.h"
|
||||
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
|
@ -23,8 +20,7 @@
|
|||
#include "nsIPushService.h"
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsFrameMessageManager.h"
|
||||
#include "nsContentCID.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
@ -63,523 +59,27 @@ GetPermissionState(nsIPrincipal* aPrincipal,
|
|||
} else {
|
||||
aState = PushPermissionState::Prompt;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SubscriptionToJSON(PushSubscriptionJSON& aJSON, const nsString& aEndpoint,
|
||||
const nsTArray<uint8_t>& aRawP256dhKey,
|
||||
const nsTArray<uint8_t>& aAuthSecret)
|
||||
{
|
||||
aJSON.mEndpoint.Construct();
|
||||
aJSON.mEndpoint.Value() = aEndpoint;
|
||||
|
||||
aJSON.mKeys.mP256dh.Construct();
|
||||
nsresult rv = Base64URLEncode(aRawP256dhKey.Length(),
|
||||
aRawP256dhKey.Elements(),
|
||||
aJSON.mKeys.mP256dh.Value());
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
aJSON.mKeys.mAuth.Construct();
|
||||
rv = Base64URLEncode(aAuthSecret.Length(), aAuthSecret.Elements(),
|
||||
aJSON.mKeys.mAuth.Value());
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class UnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit UnsubscribeResultCallback(Promise* aPromise)
|
||||
: mPromise(aPromise)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnUnsubscribe(nsresult aStatus, bool aSuccess) override
|
||||
{
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
mPromise->MaybeResolve(aSuccess);
|
||||
} else {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~UnsubscribeResultCallback()
|
||||
{}
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(UnsubscribeResultCallback, nsIUnsubscribeResultCallback)
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PushSubscription::Unsubscribe(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mPrincipal);
|
||||
|
||||
nsCOMPtr<nsIPushService> service =
|
||||
do_GetService("@mozilla.org/push/Service;1");
|
||||
if (NS_WARN_IF(!service)) {
|
||||
aRv = NS_ERROR_FAILURE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Promise> p = Promise::Create(mGlobal, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<UnsubscribeResultCallback> callback =
|
||||
new UnsubscribeResultCallback(p);
|
||||
Unused << NS_WARN_IF(NS_FAILED(
|
||||
service->Unsubscribe(mScope, mPrincipal, callback)));
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
void
|
||||
PushSubscription::ToJSON(PushSubscriptionJSON& aJSON)
|
||||
{
|
||||
SubscriptionToJSON(aJSON, mEndpoint, mRawP256dhKey, mAuthSecret);
|
||||
}
|
||||
|
||||
PushSubscription::PushSubscription(nsIGlobalObject* aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const nsTArray<uint8_t>& aRawP256dhKey,
|
||||
const nsTArray<uint8_t>& aAuthSecret)
|
||||
: mGlobal(aGlobal)
|
||||
, mEndpoint(aEndpoint)
|
||||
, mScope(aScope)
|
||||
, mRawP256dhKey(aRawP256dhKey)
|
||||
, mAuthSecret(aAuthSecret)
|
||||
{
|
||||
}
|
||||
|
||||
PushSubscription::~PushSubscription()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
PushSubscription::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return PushSubscriptionBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
PushSubscription::GetKey(JSContext* aCx,
|
||||
PushEncryptionKeyName aType,
|
||||
JS::MutableHandle<JSObject*> aKey)
|
||||
{
|
||||
if (aType == PushEncryptionKeyName::P256dh && !mRawP256dhKey.IsEmpty()) {
|
||||
aKey.set(ArrayBuffer::Create(aCx,
|
||||
mRawP256dhKey.Length(),
|
||||
mRawP256dhKey.Elements()));
|
||||
} else if (aType == PushEncryptionKeyName::Auth && !mAuthSecret.IsEmpty()) {
|
||||
aKey.set(ArrayBuffer::Create(aCx,
|
||||
mAuthSecret.Length(),
|
||||
mAuthSecret.Elements()));
|
||||
} else {
|
||||
aKey.set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PushSubscription::SetPrincipal(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
MOZ_ASSERT(!mPrincipal);
|
||||
mPrincipal = aPrincipal;
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<PushSubscription>
|
||||
PushSubscription::Constructor(GlobalObject& aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const Nullable<ArrayBuffer>& aP256dhKey,
|
||||
const Nullable<ArrayBuffer>& aAuthSecret,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!aEndpoint.IsEmpty());
|
||||
MOZ_ASSERT(!aScope.IsEmpty());
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
|
||||
nsTArray<uint8_t> rawKey;
|
||||
if (!aP256dhKey.IsNull()) {
|
||||
const ArrayBuffer& key = aP256dhKey.Value();
|
||||
key.ComputeLengthAndData();
|
||||
rawKey.InsertElementsAt(0, key.Data(), key.Length());
|
||||
}
|
||||
|
||||
nsTArray<uint8_t> authSecret;
|
||||
if (!aAuthSecret.IsNull()) {
|
||||
const ArrayBuffer& sekrit = aAuthSecret.Value();
|
||||
sekrit.ComputeLengthAndData();
|
||||
authSecret.InsertElementsAt(0, sekrit.Data(), sekrit.Length());
|
||||
}
|
||||
RefPtr<PushSubscription> sub = new PushSubscription(global,
|
||||
aEndpoint,
|
||||
aScope,
|
||||
rawKey,
|
||||
authSecret);
|
||||
|
||||
return sub.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushSubscription, mGlobal, mPrincipal)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(PushSubscription)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(PushSubscription)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushSubscription)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
PushManager::PushManager(nsIGlobalObject* aGlobal, const nsAString& aScope)
|
||||
: mGlobal(aGlobal), mScope(aScope)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
PushManager::~PushManager()
|
||||
{}
|
||||
|
||||
JSObject*
|
||||
PushManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
// XXXnsm I don't know if this is the right way to do it, but I want to assert
|
||||
// that an implementation has been set before this object gets exposed to JS.
|
||||
MOZ_ASSERT(mImpl);
|
||||
return PushManagerBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
PushManager::SetPushManagerImpl(PushManagerImpl& foo, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mImpl);
|
||||
mImpl = &foo;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PushManager::Subscribe(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
return mImpl->Subscribe(aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PushManager::GetSubscription(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
return mImpl->GetSubscription(aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PushManager::PermissionState(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
return mImpl->PermissionState(aRv);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushManager, mGlobal, mImpl)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(PushManager)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(PushManager)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushManager)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// WorkerPushSubscription
|
||||
|
||||
WorkerPushSubscription::WorkerPushSubscription(const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const nsTArray<uint8_t>& aRawP256dhKey,
|
||||
const nsTArray<uint8_t>& aAuthSecret)
|
||||
: mEndpoint(aEndpoint)
|
||||
, mScope(aScope)
|
||||
, mRawP256dhKey(aRawP256dhKey)
|
||||
, mAuthSecret(aAuthSecret)
|
||||
{
|
||||
MOZ_ASSERT(!aScope.IsEmpty());
|
||||
MOZ_ASSERT(!aEndpoint.IsEmpty());
|
||||
}
|
||||
|
||||
WorkerPushSubscription::~WorkerPushSubscription()
|
||||
{}
|
||||
|
||||
JSObject*
|
||||
WorkerPushSubscription::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return PushSubscriptionBinding_workers::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<WorkerPushSubscription>
|
||||
WorkerPushSubscription::Constructor(GlobalObject& aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const Nullable<ArrayBuffer>& aP256dhKey,
|
||||
const Nullable<ArrayBuffer>& aAuthSecret,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
||||
nsTArray<uint8_t> rawKey;
|
||||
if (!aP256dhKey.IsNull()) {
|
||||
const ArrayBuffer& key = aP256dhKey.Value();
|
||||
key.ComputeLengthAndData();
|
||||
rawKey.SetLength(key.Length());
|
||||
rawKey.ReplaceElementsAt(0, key.Length(), key.Data(), key.Length());
|
||||
}
|
||||
|
||||
nsTArray<uint8_t> authSecret;
|
||||
if (!aAuthSecret.IsNull()) {
|
||||
const ArrayBuffer& sekrit = aAuthSecret.Value();
|
||||
sekrit.ComputeLengthAndData();
|
||||
authSecret.SetLength(sekrit.Length());
|
||||
authSecret.ReplaceElementsAt(0, sekrit.Length(),
|
||||
sekrit.Data(), sekrit.Length());
|
||||
}
|
||||
RefPtr<WorkerPushSubscription> sub = new WorkerPushSubscription(aEndpoint,
|
||||
aScope,
|
||||
rawKey,
|
||||
authSecret);
|
||||
|
||||
return sub.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPushSubscription::GetKey(JSContext* aCx,
|
||||
PushEncryptionKeyName aType,
|
||||
JS::MutableHandle<JSObject*> aKey)
|
||||
{
|
||||
if (aType == mozilla::dom::PushEncryptionKeyName::P256dh &&
|
||||
!mRawP256dhKey.IsEmpty()) {
|
||||
aKey.set(ArrayBuffer::Create(aCx,
|
||||
mRawP256dhKey.Length(),
|
||||
mRawP256dhKey.Elements()));
|
||||
} else if (aType == mozilla::dom::PushEncryptionKeyName::Auth &&
|
||||
!mAuthSecret.IsEmpty()) {
|
||||
aKey.set(ArrayBuffer::Create(aCx,
|
||||
mAuthSecret.Length(),
|
||||
mAuthSecret.Elements()));
|
||||
} else {
|
||||
aKey.set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
class UnsubscribeResultRunnable final : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
UnsubscribeResultRunnable(PromiseWorkerProxy* aProxy,
|
||||
nsresult aStatus,
|
||||
bool aSuccess)
|
||||
: WorkerRunnable(aProxy->GetWorkerPrivate(), WorkerThreadModifyBusyCount)
|
||||
, mProxy(aProxy)
|
||||
, mStatus(aStatus)
|
||||
, mSuccess(aSuccess)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
RefPtr<Promise> promise = mProxy->WorkerPromise();
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
promise->MaybeResolve(mSuccess);
|
||||
} else {
|
||||
promise->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
|
||||
}
|
||||
|
||||
mProxy->CleanUp();
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
~UnsubscribeResultRunnable()
|
||||
{}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
nsresult mStatus;
|
||||
bool mSuccess;
|
||||
};
|
||||
|
||||
class WorkerUnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit WorkerUnsubscribeResultCallback(PromiseWorkerProxy* aProxy)
|
||||
: mProxy(aProxy)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnUnsubscribe(nsresult aStatus, bool aSuccess) override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mProxy, "OnUnsubscribe() called twice?");
|
||||
|
||||
RefPtr<PromiseWorkerProxy> proxy = mProxy.forget();
|
||||
|
||||
MutexAutoLock lock(proxy->Lock());
|
||||
if (proxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<UnsubscribeResultRunnable> r =
|
||||
new UnsubscribeResultRunnable(proxy, aStatus, aSuccess);
|
||||
r->Dispatch();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~WorkerUnsubscribeResultCallback()
|
||||
{
|
||||
}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WorkerUnsubscribeResultCallback, nsIUnsubscribeResultCallback)
|
||||
|
||||
class UnsubscribeRunnable final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
UnsubscribeRunnable(PromiseWorkerProxy* aProxy,
|
||||
const nsAString& aScope)
|
||||
: mProxy(aProxy)
|
||||
, mScope(aScope)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
MOZ_ASSERT(!aScope.IsEmpty());
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
{
|
||||
MutexAutoLock lock(mProxy->Lock());
|
||||
if (mProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
principal = mProxy->GetWorkerPrivate()->GetPrincipal();
|
||||
}
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
RefPtr<WorkerUnsubscribeResultCallback> callback =
|
||||
new WorkerUnsubscribeResultCallback(mProxy);
|
||||
|
||||
nsCOMPtr<nsIPushService> service =
|
||||
do_GetService("@mozilla.org/push/Service;1");
|
||||
if (!service) {
|
||||
callback->OnUnsubscribe(NS_ERROR_FAILURE, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(service->Unsubscribe(mScope, principal, callback)))) {
|
||||
callback->OnUnsubscribe(NS_ERROR_FAILURE, false);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~UnsubscribeRunnable()
|
||||
{}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
nsString mScope;
|
||||
};
|
||||
|
||||
already_AddRefed<Promise>
|
||||
WorkerPushSubscription::Unsubscribe(ErrorResult &aRv)
|
||||
{
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
|
||||
RefPtr<Promise> p = Promise::Create(global, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
|
||||
if (!proxy) {
|
||||
p->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
RefPtr<UnsubscribeRunnable> r =
|
||||
new UnsubscribeRunnable(proxy, mScope);
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
|
||||
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPushSubscription::ToJSON(PushSubscriptionJSON& aJSON)
|
||||
{
|
||||
SubscriptionToJSON(aJSON, mEndpoint, mRawP256dhKey, mAuthSecret);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerPushSubscription)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerPushSubscription)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkerPushSubscription)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerPushSubscription)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// WorkerPushManager
|
||||
|
||||
WorkerPushManager::WorkerPushManager(const nsAString& aScope)
|
||||
: mScope(aScope)
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WorkerPushManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return PushManagerBinding_workers::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
class GetSubscriptionResultRunnable final : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
GetSubscriptionResultRunnable(PromiseWorkerProxy* aProxy,
|
||||
GetSubscriptionResultRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
already_AddRefed<PromiseWorkerProxy>&& aProxy,
|
||||
nsresult aStatus,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const nsTArray<uint8_t>& aRawP256dhKey,
|
||||
const nsTArray<uint8_t>& aAuthSecret)
|
||||
: WorkerRunnable(aProxy->GetWorkerPrivate(), WorkerThreadModifyBusyCount)
|
||||
, mProxy(aProxy)
|
||||
nsTArray<uint8_t>&& aRawP256dhKey,
|
||||
nsTArray<uint8_t>&& aAuthSecret)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
, mProxy(Move(aProxy))
|
||||
, mStatus(aStatus)
|
||||
, mEndpoint(aEndpoint)
|
||||
, mScope(aScope)
|
||||
, mRawP256dhKey(aRawP256dhKey)
|
||||
, mAuthSecret(aAuthSecret)
|
||||
, mRawP256dhKey(Move(aRawP256dhKey))
|
||||
, mAuthSecret(Move(aAuthSecret))
|
||||
{ }
|
||||
|
||||
bool
|
||||
|
@ -590,9 +90,9 @@ public:
|
|||
if (mEndpoint.IsEmpty()) {
|
||||
promise->MaybeResolve(JS::NullHandleValue);
|
||||
} else {
|
||||
RefPtr<WorkerPushSubscription> sub =
|
||||
new WorkerPushSubscription(mEndpoint, mScope,
|
||||
mRawP256dhKey, mAuthSecret);
|
||||
RefPtr<PushSubscription> sub =
|
||||
new PushSubscription(nullptr, mEndpoint, mScope,
|
||||
Move(mRawP256dhKey), Move(mAuthSecret));
|
||||
promise->MaybeResolve(sub);
|
||||
}
|
||||
} else if (NS_ERROR_GET_MODULE(mStatus) == NS_ERROR_MODULE_DOM_PUSH ) {
|
||||
|
@ -602,6 +102,7 @@ public:
|
|||
}
|
||||
|
||||
mProxy->CleanUp();
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
|
@ -634,10 +135,8 @@ public:
|
|||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mProxy, "OnPushSubscription() called twice?");
|
||||
|
||||
RefPtr<PromiseWorkerProxy> proxy = mProxy.forget();
|
||||
|
||||
MutexAutoLock lock(proxy->Lock());
|
||||
if (proxy->CleanedUp()) {
|
||||
MutexAutoLock lock(mProxy->Lock());
|
||||
if (mProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -648,14 +147,17 @@ public:
|
|||
authSecret);
|
||||
}
|
||||
|
||||
WorkerPrivate* worker = mProxy->GetWorkerPrivate();
|
||||
RefPtr<GetSubscriptionResultRunnable> r =
|
||||
new GetSubscriptionResultRunnable(proxy,
|
||||
new GetSubscriptionResultRunnable(worker,
|
||||
mProxy.forget(),
|
||||
aStatus,
|
||||
endpoint,
|
||||
mScope,
|
||||
rawP256dhKey,
|
||||
authSecret);
|
||||
r->Dispatch();
|
||||
Move(rawP256dhKey),
|
||||
Move(authSecret));
|
||||
MOZ_ALWAYS_TRUE(r->Dispatch());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -677,6 +179,7 @@ private:
|
|||
{
|
||||
NS_Free(aKey);
|
||||
NS_Free(aAuthSecret);
|
||||
|
||||
return aStatus;
|
||||
}
|
||||
|
||||
|
@ -734,7 +237,7 @@ class GetSubscriptionRunnable final : public nsRunnable
|
|||
public:
|
||||
GetSubscriptionRunnable(PromiseWorkerProxy* aProxy,
|
||||
const nsAString& aScope,
|
||||
WorkerPushManager::SubscriptionAction aAction)
|
||||
PushManager::SubscriptionAction aAction)
|
||||
: mProxy(aProxy)
|
||||
, mScope(aScope), mAction(aAction)
|
||||
{}
|
||||
|
@ -745,6 +248,7 @@ public:
|
|||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
|
||||
{
|
||||
// Bug 1228723: If permission is revoked or an error occurs, the
|
||||
// subscription callback will be called synchronously. This causes
|
||||
|
@ -756,6 +260,7 @@ public:
|
|||
}
|
||||
principal = mProxy->GetWorkerPrivate()->GetPrincipal();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
RefPtr<GetSubscriptionCallback> callback = new GetSubscriptionCallback(mProxy, mScope);
|
||||
|
@ -768,7 +273,7 @@ public:
|
|||
}
|
||||
|
||||
if (state != PushPermissionState::Granted) {
|
||||
if (mAction == WorkerPushManager::GetSubscriptionAction) {
|
||||
if (mAction == PushManager::GetSubscriptionAction) {
|
||||
callback->OnPushSubscriptionError(NS_OK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -778,15 +283,15 @@ public:
|
|||
|
||||
nsCOMPtr<nsIPushService> service =
|
||||
do_GetService("@mozilla.org/push/Service;1");
|
||||
if (!service) {
|
||||
if (NS_WARN_IF(!service)) {
|
||||
callback->OnPushSubscriptionError(NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mAction == WorkerPushManager::SubscribeAction) {
|
||||
if (mAction == PushManager::SubscribeAction) {
|
||||
rv = service->Subscribe(mScope, principal, callback);
|
||||
} else {
|
||||
MOZ_ASSERT(mAction == WorkerPushManager::GetSubscriptionAction);
|
||||
MOZ_ASSERT(mAction == PushManager::GetSubscriptionAction);
|
||||
rv = service->GetSubscription(mScope, principal, callback);
|
||||
}
|
||||
|
||||
|
@ -804,47 +309,9 @@ private:
|
|||
|
||||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
nsString mScope;
|
||||
WorkerPushManager::SubscriptionAction mAction;
|
||||
PushManager::SubscriptionAction mAction;
|
||||
};
|
||||
|
||||
already_AddRefed<Promise>
|
||||
WorkerPushManager::PerformSubscriptionAction(SubscriptionAction aAction, ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
|
||||
RefPtr<Promise> p = Promise::Create(global, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
|
||||
if (!proxy) {
|
||||
p->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
RefPtr<GetSubscriptionRunnable> r =
|
||||
new GetSubscriptionRunnable(proxy, mScope, aAction);
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
|
||||
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
WorkerPushManager::Subscribe(ErrorResult& aRv)
|
||||
{
|
||||
return PerformSubscriptionAction(SubscribeAction, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
WorkerPushManager::GetSubscription(ErrorResult& aRv)
|
||||
{
|
||||
return PerformSubscriptionAction(GetSubscriptionAction, aRv);
|
||||
}
|
||||
|
||||
class PermissionResultRunnable final : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
|
@ -873,6 +340,7 @@ public:
|
|||
}
|
||||
|
||||
mProxy->CleanUp();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -909,7 +377,8 @@ public:
|
|||
|
||||
RefPtr<PermissionResultRunnable> r =
|
||||
new PermissionResultRunnable(mProxy, rv, state);
|
||||
r->Dispatch();
|
||||
MOZ_ALWAYS_TRUE(r->Dispatch());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -920,9 +389,99 @@ private:
|
|||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
};
|
||||
|
||||
already_AddRefed<Promise>
|
||||
WorkerPushManager::PermissionState(ErrorResult& aRv)
|
||||
} // anonymous namespace
|
||||
|
||||
PushManager::PushManager(nsIGlobalObject* aGlobal, PushManagerImpl* aImpl)
|
||||
: mGlobal(aGlobal)
|
||||
, mImpl(aImpl)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aImpl);
|
||||
}
|
||||
|
||||
PushManager::PushManager(const nsAString& aScope)
|
||||
: mScope(aScope)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// There's only one global on a worker, so we don't need to pass a global
|
||||
// object to the constructor.
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
PushManager::~PushManager()
|
||||
{}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushManager, mGlobal, mImpl)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(PushManager)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(PushManager)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushManager)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
JSObject*
|
||||
PushManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return PushManagerBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<PushManager>
|
||||
PushManager::Constructor(GlobalObject& aGlobal,
|
||||
const nsAString& aScope,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
RefPtr<PushManager> ret = new PushManager(aScope);
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
RefPtr<PushManagerImpl> impl = PushManagerImpl::Constructor(aGlobal,
|
||||
aGlobal.Context(),
|
||||
aScope, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
RefPtr<PushManager> ret = new PushManager(global, impl);
|
||||
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PushManager::Subscribe(ErrorResult& aRv)
|
||||
{
|
||||
if (mImpl) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mImpl->Subscribe(aRv);
|
||||
}
|
||||
|
||||
return PerformSubscriptionActionFromWorker(SubscribeAction, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PushManager::GetSubscription(ErrorResult& aRv)
|
||||
{
|
||||
if (mImpl) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mImpl->GetSubscription(aRv);
|
||||
}
|
||||
|
||||
return PerformSubscriptionActionFromWorker(GetSubscriptionAction, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PushManager::PermissionState(ErrorResult& aRv)
|
||||
{
|
||||
if (mImpl) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mImpl->PermissionState(aRv);
|
||||
}
|
||||
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
@ -946,15 +505,32 @@ WorkerPushManager::PermissionState(ErrorResult& aRv)
|
|||
return p.forget();
|
||||
}
|
||||
|
||||
WorkerPushManager::~WorkerPushManager()
|
||||
{}
|
||||
already_AddRefed<Promise>
|
||||
PushManager::PerformSubscriptionActionFromWorker(
|
||||
SubscriptionAction aAction, ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
|
||||
RefPtr<Promise> p = Promise::Create(global, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
|
||||
if (!proxy) {
|
||||
p->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
RefPtr<GetSubscriptionRunnable> r =
|
||||
new GetSubscriptionRunnable(proxy, mScope, aAction);
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
|
||||
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerPushManager)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerPushManager)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkerPushManager)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerPushManager)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -5,24 +5,19 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* We would like to expose PushManager and PushSubscription on window and
|
||||
* workers. Parts of the Push API is implemented in JS out of necessity due to:
|
||||
* 1) Using frame message managers, in which
|
||||
* nsIMessageListener::receiveMessage() must be in JS.
|
||||
* 2) It is easier to use certain APIs like the permission prompt and Promises
|
||||
* from JS.
|
||||
* PushManager and PushSubscription are exposed on the main and worker threads.
|
||||
* The main thread version is implemented in Push.js. The JS implementation
|
||||
* makes it easier to use certain APIs like the permission prompt and Promises.
|
||||
*
|
||||
* Unfortunately, JS-implemented WebIDL is not supported off the main thread. To
|
||||
* aid in fixing this, the nsIPushClient is introduced which deals with part (1)
|
||||
* above. Part (2) is handled by PushManagerImpl on the main thread. PushManager
|
||||
* wraps this in C++ since our bindings code cannot accomodate "JS-implemented
|
||||
* on the main thread, C++ on the worker" bindings. PushManager simply forwards
|
||||
* the calls to the JS component.
|
||||
* Unfortunately, JS-implemented WebIDL is not supported off the main thread.
|
||||
* To work around this, we use a chain of runnables to query the JS-implemented
|
||||
* nsIPushService component for subscription information, and return the
|
||||
* results to the worker. We don't have to deal with permission prompts, since
|
||||
* we just reject calls if the principal does not have permission.
|
||||
*
|
||||
* On the worker threads, we don't have to deal with permission prompts, instead
|
||||
* we just reject calls if the principal does not have permission. On workers
|
||||
* WorkerPushManager dispatches runnables to the main thread which directly call
|
||||
* nsIPushClient.
|
||||
* On the main thread, PushManager wraps a JS-implemented PushManagerImpl
|
||||
* instance. The C++ wrapper is necessary because our bindings code cannot
|
||||
* accomodate "JS-implemented on the main thread, C++ on the worker" bindings.
|
||||
*
|
||||
* PushSubscription is in C++ on both threads since it isn't particularly
|
||||
* verbose to implement in C++ compared to JS.
|
||||
|
@ -40,13 +35,10 @@
|
|||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
class nsIPrincipal;
|
||||
|
||||
#include "mozilla/dom/PushSubscriptionBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -57,68 +49,6 @@ class WorkerPrivate;
|
|||
class Promise;
|
||||
class PushManagerImpl;
|
||||
|
||||
class PushSubscription final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PushSubscription)
|
||||
|
||||
explicit PushSubscription(nsIGlobalObject* aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const nsTArray<uint8_t>& aP256dhKey,
|
||||
const nsTArray<uint8_t>& aAuthSecret);
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsIGlobalObject*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mGlobal;
|
||||
}
|
||||
|
||||
void
|
||||
GetEndpoint(nsAString& aEndpoint) const
|
||||
{
|
||||
aEndpoint = mEndpoint;
|
||||
}
|
||||
|
||||
void
|
||||
GetKey(JSContext* cx,
|
||||
PushEncryptionKeyName aType,
|
||||
JS::MutableHandle<JSObject*> aKey);
|
||||
|
||||
static already_AddRefed<PushSubscription>
|
||||
Constructor(GlobalObject& aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const Nullable<ArrayBuffer>& aP256dhKey,
|
||||
const Nullable<ArrayBuffer>& aAuthSecret,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
SetPrincipal(nsIPrincipal* aPrincipal);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Unsubscribe(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToJSON(PushSubscriptionJSON& aJSON);
|
||||
|
||||
protected:
|
||||
~PushSubscription();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsString mEndpoint;
|
||||
nsString mScope;
|
||||
nsTArray<uint8_t> mRawP256dhKey;
|
||||
nsTArray<uint8_t> mAuthSecret;
|
||||
};
|
||||
|
||||
class PushManager final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
|
@ -126,7 +56,16 @@ public:
|
|||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PushManager)
|
||||
|
||||
explicit PushManager(nsIGlobalObject* aGlobal, const nsAString& aScope);
|
||||
enum SubscriptionAction {
|
||||
SubscribeAction,
|
||||
GetSubscriptionAction,
|
||||
};
|
||||
|
||||
// The main thread constructor.
|
||||
PushManager(nsIGlobalObject* aGlobal, PushManagerImpl* aImpl);
|
||||
|
||||
// The worker thread constructor.
|
||||
explicit PushManager(const nsAString& aScope);
|
||||
|
||||
nsIGlobalObject*
|
||||
GetParentObject() const
|
||||
|
@ -137,6 +76,14 @@ public:
|
|||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static already_AddRefed<PushManager>
|
||||
Constructor(GlobalObject& aGlobal, const nsAString& aScope,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PerformSubscriptionActionFromWorker(SubscriptionAction aAction,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Subscribe(ErrorResult& aRv);
|
||||
|
||||
|
@ -146,112 +93,15 @@ public:
|
|||
already_AddRefed<Promise>
|
||||
PermissionState(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
SetPushManagerImpl(PushManagerImpl& foo, ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
~PushManager();
|
||||
|
||||
private:
|
||||
// The following are only set and accessed on the main thread.
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<PushManagerImpl> mImpl;
|
||||
nsString mScope;
|
||||
};
|
||||
|
||||
class WorkerPushSubscription final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WorkerPushSubscription)
|
||||
|
||||
explicit WorkerPushSubscription(const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const nsTArray<uint8_t>& aRawP256dhKey,
|
||||
const nsTArray<uint8_t>& aAuthSecret);
|
||||
|
||||
nsIGlobalObject*
|
||||
GetParentObject() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static already_AddRefed<WorkerPushSubscription>
|
||||
Constructor(GlobalObject& aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const Nullable<ArrayBuffer>& aP256dhKey,
|
||||
const Nullable<ArrayBuffer>& aAuthSecret,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
GetEndpoint(nsAString& aEndpoint) const
|
||||
{
|
||||
aEndpoint = mEndpoint;
|
||||
}
|
||||
|
||||
void
|
||||
GetKey(JSContext* cx, PushEncryptionKeyName aType,
|
||||
JS::MutableHandle<JSObject*> aP256dhKey);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Unsubscribe(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToJSON(PushSubscriptionJSON& aJSON);
|
||||
|
||||
protected:
|
||||
~WorkerPushSubscription();
|
||||
|
||||
private:
|
||||
nsString mEndpoint;
|
||||
nsString mScope;
|
||||
nsTArray<uint8_t> mRawP256dhKey;
|
||||
nsTArray<uint8_t> mAuthSecret;
|
||||
};
|
||||
|
||||
class WorkerPushManager final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WorkerPushManager)
|
||||
|
||||
enum SubscriptionAction {
|
||||
SubscribeAction,
|
||||
GetSubscriptionAction,
|
||||
};
|
||||
|
||||
explicit WorkerPushManager(const nsAString& aScope);
|
||||
|
||||
nsIGlobalObject*
|
||||
GetParentObject() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PerformSubscriptionAction(SubscriptionAction aAction, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Subscribe(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetSubscription(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PermissionState(ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
~WorkerPushManager();
|
||||
|
||||
private:
|
||||
// Only used on the worker thread.
|
||||
nsString mScope;
|
||||
};
|
||||
} // namespace dom
|
||||
|
|
|
@ -0,0 +1,378 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/PushSubscription.h"
|
||||
|
||||
#include "nsIPushService.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/WorkerScope.h"
|
||||
#include "mozilla/dom/workers/Workers.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace workers;
|
||||
|
||||
namespace {
|
||||
|
||||
class UnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit UnsubscribeResultCallback(Promise* aPromise)
|
||||
: mPromise(aPromise)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnUnsubscribe(nsresult aStatus, bool aSuccess) override
|
||||
{
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
mPromise->MaybeResolve(aSuccess);
|
||||
} else {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~UnsubscribeResultCallback()
|
||||
{}
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(UnsubscribeResultCallback, nsIUnsubscribeResultCallback)
|
||||
|
||||
class UnsubscribeResultRunnable final : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
UnsubscribeResultRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
already_AddRefed<PromiseWorkerProxy>&& aProxy,
|
||||
nsresult aStatus,
|
||||
bool aSuccess)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
, mProxy(Move(aProxy))
|
||||
, mStatus(aStatus)
|
||||
, mSuccess(aSuccess)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
RefPtr<Promise> promise = mProxy->WorkerPromise();
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
promise->MaybeResolve(mSuccess);
|
||||
} else {
|
||||
promise->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
|
||||
}
|
||||
|
||||
mProxy->CleanUp();
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
~UnsubscribeResultRunnable()
|
||||
{}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
nsresult mStatus;
|
||||
bool mSuccess;
|
||||
};
|
||||
|
||||
class WorkerUnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit WorkerUnsubscribeResultCallback(PromiseWorkerProxy* aProxy)
|
||||
: mProxy(aProxy)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnUnsubscribe(nsresult aStatus, bool aSuccess) override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mProxy, "OnUnsubscribe() called twice?");
|
||||
|
||||
MutexAutoLock lock(mProxy->Lock());
|
||||
if (mProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
WorkerPrivate* worker = mProxy->GetWorkerPrivate();
|
||||
RefPtr<UnsubscribeResultRunnable> r =
|
||||
new UnsubscribeResultRunnable(worker, mProxy.forget(), aStatus, aSuccess);
|
||||
MOZ_ALWAYS_TRUE(r->Dispatch());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~WorkerUnsubscribeResultCallback()
|
||||
{
|
||||
}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WorkerUnsubscribeResultCallback, nsIUnsubscribeResultCallback)
|
||||
|
||||
class UnsubscribeRunnable final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
UnsubscribeRunnable(PromiseWorkerProxy* aProxy,
|
||||
const nsAString& aScope)
|
||||
: mProxy(aProxy)
|
||||
, mScope(aScope)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
MOZ_ASSERT(!aScope.IsEmpty());
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mProxy->Lock());
|
||||
if (mProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
principal = mProxy->GetWorkerPrivate()->GetPrincipal();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
RefPtr<WorkerUnsubscribeResultCallback> callback =
|
||||
new WorkerUnsubscribeResultCallback(mProxy);
|
||||
|
||||
nsCOMPtr<nsIPushService> service =
|
||||
do_GetService("@mozilla.org/push/Service;1");
|
||||
if (NS_WARN_IF(!service)) {
|
||||
callback->OnUnsubscribe(NS_ERROR_FAILURE, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(service->Unsubscribe(mScope, principal, callback)))) {
|
||||
callback->OnUnsubscribe(NS_ERROR_FAILURE, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~UnsubscribeRunnable()
|
||||
{}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
nsString mScope;
|
||||
};
|
||||
|
||||
bool
|
||||
CopyArrayBufferToArray(const ArrayBuffer& aBuffer,
|
||||
nsTArray<uint8_t>& aArray)
|
||||
{
|
||||
aBuffer.ComputeLengthAndData();
|
||||
if (!aArray.SetLength(aBuffer.Length(), fallible) ||
|
||||
!aArray.ReplaceElementsAt(0, aBuffer.Length(), aBuffer.Data(),
|
||||
aBuffer.Length(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
PushSubscription::PushSubscription(nsIGlobalObject* aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
nsTArray<uint8_t>&& aRawP256dhKey,
|
||||
nsTArray<uint8_t>&& aAuthSecret)
|
||||
: mEndpoint(aEndpoint)
|
||||
, mScope(aScope)
|
||||
, mRawP256dhKey(Move(aRawP256dhKey))
|
||||
, mAuthSecret(Move(aAuthSecret))
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
mGlobal = aGlobal;
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
// There's only one global on a worker, so we don't need to pass a global
|
||||
// object to the constructor.
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
PushSubscription::~PushSubscription()
|
||||
{}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushSubscription, mGlobal)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(PushSubscription)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(PushSubscription)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushSubscription)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
JSObject*
|
||||
PushSubscription::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return PushSubscriptionBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<PushSubscription>
|
||||
PushSubscription::Constructor(GlobalObject& aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const Nullable<ArrayBuffer>& aP256dhKey,
|
||||
const Nullable<ArrayBuffer>& aAuthSecret,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
|
||||
nsTArray<uint8_t> rawKey, authSecret;
|
||||
if ((!aP256dhKey.IsNull() && !CopyArrayBufferToArray(aP256dhKey.Value(),
|
||||
rawKey)) ||
|
||||
(!aAuthSecret.IsNull() && !CopyArrayBufferToArray(aAuthSecret.Value(),
|
||||
authSecret))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PushSubscription> sub = new PushSubscription(global,
|
||||
aEndpoint,
|
||||
aScope,
|
||||
Move(rawKey),
|
||||
Move(authSecret));
|
||||
|
||||
return sub.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PushSubscription::Unsubscribe(ErrorResult& aRv)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
RefPtr<Promise> p = UnsubscribeFromWorker(aRv);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mGlobal);
|
||||
|
||||
nsCOMPtr<nsIPushService> service =
|
||||
do_GetService("@mozilla.org/push/Service;1");
|
||||
if (NS_WARN_IF(!service)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mGlobal);
|
||||
if (!sop) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Promise> p = Promise::Create(mGlobal, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<UnsubscribeResultCallback> callback =
|
||||
new UnsubscribeResultCallback(p);
|
||||
Unused << NS_WARN_IF(NS_FAILED(
|
||||
service->Unsubscribe(mScope, sop->GetPrincipal(), callback)));
|
||||
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
void
|
||||
PushSubscription::GetKey(JSContext* aCx,
|
||||
PushEncryptionKeyName aType,
|
||||
JS::MutableHandle<JSObject*> aKey)
|
||||
{
|
||||
if (aType == PushEncryptionKeyName::P256dh && !mRawP256dhKey.IsEmpty()) {
|
||||
aKey.set(ArrayBuffer::Create(aCx,
|
||||
mRawP256dhKey.Length(),
|
||||
mRawP256dhKey.Elements()));
|
||||
} else if (aType == PushEncryptionKeyName::Auth && !mAuthSecret.IsEmpty()) {
|
||||
aKey.set(ArrayBuffer::Create(aCx,
|
||||
mAuthSecret.Length(),
|
||||
mAuthSecret.Elements()));
|
||||
} else {
|
||||
aKey.set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PushSubscription::ToJSON(PushSubscriptionJSON& aJSON)
|
||||
{
|
||||
aJSON.mEndpoint.Construct();
|
||||
aJSON.mEndpoint.Value() = mEndpoint;
|
||||
|
||||
aJSON.mKeys.mP256dh.Construct();
|
||||
nsresult rv = Base64URLEncode(mRawP256dhKey.Length(),
|
||||
mRawP256dhKey.Elements(),
|
||||
aJSON.mKeys.mP256dh.Value());
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
aJSON.mKeys.mAuth.Construct();
|
||||
rv = Base64URLEncode(mAuthSecret.Length(), mAuthSecret.Elements(),
|
||||
aJSON.mKeys.mAuth.Value());
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PushSubscription::UnsubscribeFromWorker(ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
|
||||
RefPtr<Promise> p = Promise::Create(global, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
|
||||
if (!proxy) {
|
||||
p->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
RefPtr<UnsubscribeRunnable> r =
|
||||
new UnsubscribeRunnable(proxy, mScope);
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
|
||||
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,95 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_PushSubscription_h
|
||||
#define mozilla_dom_PushSubscription_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/PushSubscriptionBinding.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace workers {
|
||||
class WorkerPrivate;
|
||||
}
|
||||
|
||||
class Promise;
|
||||
|
||||
class PushSubscription final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PushSubscription)
|
||||
|
||||
PushSubscription(nsIGlobalObject* aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
nsTArray<uint8_t>&& aP256dhKey,
|
||||
nsTArray<uint8_t>&& aAuthSecret);
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsIGlobalObject*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mGlobal;
|
||||
}
|
||||
|
||||
void
|
||||
GetEndpoint(nsAString& aEndpoint) const
|
||||
{
|
||||
aEndpoint = mEndpoint;
|
||||
}
|
||||
|
||||
void
|
||||
GetKey(JSContext* cx,
|
||||
PushEncryptionKeyName aType,
|
||||
JS::MutableHandle<JSObject*> aKey);
|
||||
|
||||
static already_AddRefed<PushSubscription>
|
||||
Constructor(GlobalObject& aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
const Nullable<ArrayBuffer>& aP256dhKey,
|
||||
const Nullable<ArrayBuffer>& aAuthSecret,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Unsubscribe(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToJSON(PushSubscriptionJSON& aJSON);
|
||||
|
||||
protected:
|
||||
~PushSubscription();
|
||||
|
||||
private:
|
||||
already_AddRefed<Promise>
|
||||
UnsubscribeFromWorker(ErrorResult& aRv);
|
||||
|
||||
nsString mEndpoint;
|
||||
nsString mScope;
|
||||
nsTArray<uint8_t> mRawP256dhKey;
|
||||
nsTArray<uint8_t> mAuthSecret;
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_PushSubscription_h
|
|
@ -39,11 +39,13 @@ XPCSHELL_TESTS_MANIFESTS += [
|
|||
EXPORTS.mozilla.dom += [
|
||||
'PushManager.h',
|
||||
'PushNotifier.h',
|
||||
'PushSubscription.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'PushManager.cpp',
|
||||
'PushNotifier.cpp',
|
||||
'PushSubscription.cpp',
|
||||
]
|
||||
|
||||
TEST_DIRS += ['test/xpcshell']
|
||||
|
|
|
@ -995,14 +995,12 @@ nsSVGElement::sTextContentElementsMap[] = {
|
|||
// { &nsGkAtoms::baseline_shift },
|
||||
{ &nsGkAtoms::direction },
|
||||
{ &nsGkAtoms::dominant_baseline },
|
||||
// { &nsGkAtoms::glyph_orientation_horizontal },
|
||||
// { &nsGkAtoms::glyph_orientation_vertical },
|
||||
// { &nsGkAtoms::kerning },
|
||||
{ &nsGkAtoms::letter_spacing },
|
||||
{ &nsGkAtoms::text_anchor },
|
||||
{ &nsGkAtoms::text_decoration },
|
||||
{ &nsGkAtoms::unicode_bidi },
|
||||
{ &nsGkAtoms::word_spacing },
|
||||
{ &nsGkAtoms::writing_mode },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
|
|
|
@ -7,26 +7,19 @@
|
|||
* https://w3c.github.io/push-api/
|
||||
*/
|
||||
|
||||
// Please see comments in dom/push/PushManager.h for the split between
|
||||
// PushManagerImpl and PushManager.
|
||||
// The main thread JS implementation. Please see comments in
|
||||
// dom/push/PushManager.h for the split between PushManagerImpl and PushManager.
|
||||
[JSImplementation="@mozilla.org/push/PushManager;1",
|
||||
NoInterfaceObject]
|
||||
ChromeOnly, Constructor(DOMString scope)]
|
||||
interface PushManagerImpl {
|
||||
Promise<PushSubscription> subscribe();
|
||||
Promise<PushSubscription?> getSubscription();
|
||||
Promise<PushPermissionState> permissionState();
|
||||
|
||||
// We need a setter in the bindings so that the C++ can use it,
|
||||
// but we don't want it exposed to client JS. WebPushMethodHider
|
||||
// always returns false.
|
||||
[Func="ServiceWorkerRegistration::WebPushMethodHider"] void setScope(DOMString scope);
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled"]
|
||||
[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled",
|
||||
ChromeConstructor(DOMString scope)]
|
||||
interface PushManager {
|
||||
[ChromeOnly, Throws, Exposed=Window]
|
||||
void setPushManagerImpl(PushManagerImpl store);
|
||||
|
||||
[Throws, UseCounter]
|
||||
Promise<PushSubscription> subscribe();
|
||||
[Throws]
|
||||
|
|
|
@ -39,8 +39,4 @@ interface PushSubscription
|
|||
|
||||
// Implements the custom serializer specified in Push API, section 9.
|
||||
PushSubscriptionJSON toJSON();
|
||||
|
||||
// Used to set the principal from the JS implemented PushManager.
|
||||
[Exposed=Window,ChromeOnly]
|
||||
void setPrincipal(Principal principal);
|
||||
};
|
||||
|
|
|
@ -752,7 +752,8 @@ ServiceWorkerRegistrationMainThread::GetNotifications(const GetNotificationOptio
|
|||
}
|
||||
|
||||
already_AddRefed<PushManager>
|
||||
ServiceWorkerRegistrationMainThread::GetPushManager(ErrorResult& aRv)
|
||||
ServiceWorkerRegistrationMainThread::GetPushManager(JSContext* aCx,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
|
@ -768,26 +769,11 @@ ServiceWorkerRegistrationMainThread::GetPushManager(ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: bug 1148117. This will fail when swr is exposed on workers
|
||||
JS::Rooted<JSObject*> jsImplObj(nsContentUtils::RootingCxForThread());
|
||||
ConstructJSImplementation("@mozilla.org/push/PushManager;1",
|
||||
globalObject, &jsImplObj, aRv);
|
||||
GlobalObject global(aCx, globalObject->GetGlobalJSObject());
|
||||
mPushManager = PushManager::Constructor(global, mScope, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
mPushManager = new PushManager(globalObject, mScope);
|
||||
|
||||
RefPtr<PushManagerImpl> impl = new PushManagerImpl(jsImplObj, globalObject);
|
||||
impl->SetScope(mScope, aRv);
|
||||
if (aRv.Failed()) {
|
||||
mPushManager = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
mPushManager->SetPushManagerImpl(*impl, aRv);
|
||||
if (aRv.Failed()) {
|
||||
mPushManager = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<PushManager> ret = mPushManager;
|
||||
|
@ -1217,7 +1203,7 @@ ServiceWorkerRegistrationWorkerThread::GetNotifications(const GetNotificationOpt
|
|||
return Notification::WorkerGet(mWorkerPrivate, aOptions, mScope, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<WorkerPushManager>
|
||||
already_AddRefed<PushManager>
|
||||
ServiceWorkerRegistrationWorkerThread::GetPushManager(ErrorResult& aRv)
|
||||
{
|
||||
#ifdef MOZ_SIMPLEPUSH
|
||||
|
@ -1225,10 +1211,10 @@ ServiceWorkerRegistrationWorkerThread::GetPushManager(ErrorResult& aRv)
|
|||
#else
|
||||
|
||||
if (!mPushManager) {
|
||||
mPushManager = new WorkerPushManager(mScope);
|
||||
mPushManager = new PushManager(mScope);
|
||||
}
|
||||
|
||||
RefPtr<WorkerPushManager> ret = mPushManager;
|
||||
RefPtr<PushManager> ret = mPushManager;
|
||||
return ret.forget();
|
||||
|
||||
#endif /* ! MOZ_SIMPLEPUSH */
|
||||
|
|
|
@ -22,7 +22,6 @@ namespace dom {
|
|||
|
||||
class Promise;
|
||||
class PushManager;
|
||||
class WorkerPushManager;
|
||||
class WorkerListener;
|
||||
|
||||
namespace workers {
|
||||
|
@ -36,21 +35,6 @@ ServiceWorkerRegistrationVisible(JSContext* aCx, JSObject* aObj);
|
|||
bool
|
||||
ServiceWorkerNotificationAPIVisible(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
// This class exists solely so that we can satisfy some WebIDL Func= attribute
|
||||
// constraints. Func= converts the function name to a header file to include, in
|
||||
// this case "ServiceWorkerRegistration.h".
|
||||
class ServiceWorkerRegistration final
|
||||
{
|
||||
public:
|
||||
// Something that we can feed into the Func webidl property to ensure that
|
||||
// SetScope is never exposed to the user.
|
||||
static bool
|
||||
WebPushMethodHider(JSContext* unusedContext, JSObject* unusedObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Used by ServiceWorkerManager to notify ServiceWorkerRegistrations of
|
||||
// updatefound event and invalidating ServiceWorker instances.
|
||||
class ServiceWorkerRegistrationListener
|
||||
|
@ -139,7 +123,7 @@ public:
|
|||
GetActive() override;
|
||||
|
||||
already_AddRefed<PushManager>
|
||||
GetPushManager(ErrorResult& aRv);
|
||||
GetPushManager(JSContext* aCx, ErrorResult& aRv);
|
||||
|
||||
// DOMEventTargethelper
|
||||
void DisconnectFromOwner() override
|
||||
|
@ -241,7 +225,7 @@ public:
|
|||
bool
|
||||
Notify(workers::Status aStatus) override;
|
||||
|
||||
already_AddRefed<WorkerPushManager>
|
||||
already_AddRefed<PushManager>
|
||||
GetPushManager(ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
|
@ -263,7 +247,7 @@ private:
|
|||
RefPtr<WorkerListener> mListener;
|
||||
|
||||
#ifndef MOZ_SIMPLEPUSH
|
||||
RefPtr<WorkerPushManager> mPushManager;
|
||||
RefPtr<PushManager> mPushManager;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -703,8 +703,6 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
|||
WriteParam(aMsg, aParam.GetContentDescription());
|
||||
WriteParam(aMsg, aParam.mLineScrollAmount);
|
||||
WriteParam(aMsg, aParam.mPageScrollAmount);
|
||||
WriteParam(aMsg, aParam.mClipRect);
|
||||
WriteParam(aMsg, aParam.mMaskLayerIndex);
|
||||
WriteParam(aMsg, aParam.mPaintRequestTime);
|
||||
WriteParam(aMsg, aParam.mIsRootContent);
|
||||
WriteParam(aMsg, aParam.mHasScrollgrab);
|
||||
|
@ -765,8 +763,6 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
|||
ReadContentDescription(aMsg, aIter, aResult) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mLineScrollAmount) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mPageScrollAmount) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mClipRect) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mPaintRequestTime) &&
|
||||
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetIsRootContent) &&
|
||||
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetHasScrollgrab) &&
|
||||
|
@ -780,6 +776,54 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::layers::ScrollSnapInfo>
|
||||
{
|
||||
typedef mozilla::layers::ScrollSnapInfo paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mScrollSnapTypeX);
|
||||
WriteParam(aMsg, aParam.mScrollSnapTypeY);
|
||||
WriteParam(aMsg, aParam.mScrollSnapIntervalX);
|
||||
WriteParam(aMsg, aParam.mScrollSnapIntervalY);
|
||||
WriteParam(aMsg, aParam.mScrollSnapDestination);
|
||||
WriteParam(aMsg, aParam.mScrollSnapCoordinates);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
return (ReadParam(aMsg, aIter, &aResult->mScrollSnapTypeX) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollSnapTypeY) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalX) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalY) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollSnapDestination) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollSnapCoordinates));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::layers::ScrollMetadata>
|
||||
{
|
||||
typedef mozilla::layers::ScrollMetadata paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mMetrics);
|
||||
WriteParam(aMsg, aParam.mSnapInfo);
|
||||
WriteParam(aMsg, aParam.mMaskLayerIndex);
|
||||
WriteParam(aMsg, aParam.mClipRect);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
return (ReadParam(aMsg, aIter, &aResult->mMetrics) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mSnapInfo) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mClipRect));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
|
||||
{
|
||||
|
|
|
@ -10,7 +10,6 @@ namespace mozilla {
|
|||
namespace layers {
|
||||
|
||||
const FrameMetrics::ViewID FrameMetrics::NULL_SCROLL_ID = 0;
|
||||
const FrameMetrics FrameMetrics::sNullMetrics;
|
||||
|
||||
void
|
||||
FrameMetrics::SetUsesContainerScrolling(bool aValue) {
|
||||
|
@ -18,5 +17,7 @@ FrameMetrics::SetUsesContainerScrolling(bool aValue) {
|
|||
mUsesContainerScrolling = aValue;
|
||||
}
|
||||
|
||||
StaticAutoPtr<const ScrollMetadata> ScrollMetadata::sNullMetadata;
|
||||
|
||||
}
|
||||
}
|
|
@ -14,8 +14,10 @@
|
|||
#include "mozilla/gfx/Rect.h" // for RoundedIn
|
||||
#include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
|
||||
#include "mozilla/gfx/Logging.h" // for Log
|
||||
#include "mozilla/StaticPtr.h" // for StaticAutoPtr
|
||||
#include "mozilla/TimeStamp.h" // for TimeStamp
|
||||
#include "nsString.h"
|
||||
#include "nsStyleCoord.h" // for nsStyleCoord
|
||||
|
||||
namespace IPC {
|
||||
template <typename T> struct ParamTraits;
|
||||
|
@ -38,7 +40,6 @@ public:
|
|||
static const ViewID NULL_SCROLL_ID; // This container layer does not scroll.
|
||||
static const ViewID START_SCROLL_ID = 2; // This is the ID that scrolling subframes
|
||||
// will begin at.
|
||||
static const FrameMetrics sNullMetrics; // We often need an empty metrics
|
||||
|
||||
FrameMetrics()
|
||||
: mScrollId(NULL_SCROLL_ID)
|
||||
|
@ -63,8 +64,6 @@ public:
|
|||
, mContentDescription()
|
||||
, mLineScrollAmount(0, 0)
|
||||
, mPageScrollAmount(0, 0)
|
||||
, mClipRect()
|
||||
, mMaskLayerIndex()
|
||||
, mPaintRequestTime()
|
||||
, mIsRootContent(false)
|
||||
, mHasScrollgrab(false)
|
||||
|
@ -105,8 +104,6 @@ public:
|
|||
// don't compare mContentDescription
|
||||
mLineScrollAmount == aOther.mLineScrollAmount &&
|
||||
mPageScrollAmount == aOther.mPageScrollAmount &&
|
||||
mClipRect == aOther.mClipRect &&
|
||||
mMaskLayerIndex == aOther.mMaskLayerIndex &&
|
||||
mPaintRequestTime == aOther.mPaintRequestTime &&
|
||||
mIsRootContent == aOther.mIsRootContent &&
|
||||
mHasScrollgrab == aOther.mHasScrollgrab &&
|
||||
|
@ -124,14 +121,6 @@ public:
|
|||
return !operator==(aOther);
|
||||
}
|
||||
|
||||
bool IsDefault() const
|
||||
{
|
||||
FrameMetrics def;
|
||||
|
||||
def.mPresShellId = mPresShellId;
|
||||
return (def == *this);
|
||||
}
|
||||
|
||||
bool IsScrollable() const
|
||||
{
|
||||
return mScrollId != NULL_SCROLL_ID;
|
||||
|
@ -205,6 +194,15 @@ public:
|
|||
return size;
|
||||
}
|
||||
|
||||
CSSRect CalculateScrollRange() const
|
||||
{
|
||||
CSSSize scrollPortSize = CalculateCompositedSizeInCssPixels();
|
||||
CSSRect scrollRange = mScrollableRect;
|
||||
scrollRange.width = std::max(scrollRange.width - scrollPortSize.width, 0.0f);
|
||||
scrollRange.height = std::max(scrollRange.height - scrollPortSize.height, 0.0f);
|
||||
return scrollRange;
|
||||
}
|
||||
|
||||
void ScrollBy(const CSSPoint& aPoint)
|
||||
{
|
||||
mScrollOffset += aPoint;
|
||||
|
@ -528,28 +526,6 @@ public:
|
|||
mAllowVerticalScrollWithWheel = aValue;
|
||||
}
|
||||
|
||||
void SetClipRect(const Maybe<ParentLayerIntRect>& aClipRect)
|
||||
{
|
||||
mClipRect = aClipRect;
|
||||
}
|
||||
const Maybe<ParentLayerIntRect>& GetClipRect() const
|
||||
{
|
||||
return mClipRect;
|
||||
}
|
||||
bool HasClipRect() const {
|
||||
return mClipRect.isSome();
|
||||
}
|
||||
const ParentLayerIntRect& ClipRect() const {
|
||||
return mClipRect.ref();
|
||||
}
|
||||
|
||||
void SetMaskLayerIndex(const Maybe<size_t>& aIndex) {
|
||||
mMaskLayerIndex = aIndex;
|
||||
}
|
||||
const Maybe<size_t>& GetMaskLayerIndex() const {
|
||||
return mMaskLayerIndex;
|
||||
}
|
||||
|
||||
void SetPaintRequestTime(const TimeStamp& aTime) {
|
||||
mPaintRequestTime = aTime;
|
||||
}
|
||||
|
@ -731,14 +707,6 @@ private:
|
|||
// The value of GetPageScrollAmount(), for scroll frames.
|
||||
LayoutDeviceIntSize mPageScrollAmount;
|
||||
|
||||
// The clip rect to use when compositing a layer with this FrameMetrics.
|
||||
Maybe<ParentLayerIntRect> mClipRect;
|
||||
|
||||
// An extra clip mask layer to use when compositing a layer with this
|
||||
// FrameMetrics. This is an index into the MetricsMaskLayers array on
|
||||
// the Layer.
|
||||
Maybe<size_t> mMaskLayerIndex;
|
||||
|
||||
// The time at which the APZC last requested a repaint for this scrollframe.
|
||||
TimeStamp mPaintRequestTime;
|
||||
|
||||
|
@ -794,6 +762,114 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
struct ScrollSnapInfo {
|
||||
ScrollSnapInfo()
|
||||
: mScrollSnapTypeX(NS_STYLE_SCROLL_SNAP_TYPE_NONE)
|
||||
, mScrollSnapTypeY(NS_STYLE_SCROLL_SNAP_TYPE_NONE)
|
||||
{}
|
||||
|
||||
// The scroll frame's scroll-snap-type.
|
||||
// One of NS_STYLE_SCROLL_SNAP_{NONE, MANDATORY, PROXIMITY}.
|
||||
uint8_t mScrollSnapTypeX;
|
||||
uint8_t mScrollSnapTypeY;
|
||||
|
||||
// The intervals derived from the scroll frame's scroll-snap-points.
|
||||
Maybe<nscoord> mScrollSnapIntervalX;
|
||||
Maybe<nscoord> mScrollSnapIntervalY;
|
||||
|
||||
// The scroll frame's scroll-snap-destination, in cooked form (to avoid
|
||||
// shipping the raw nsStyleCoord::CalcValue over IPC).
|
||||
nsPoint mScrollSnapDestination;
|
||||
|
||||
// The scroll-snap-coordinates of any descendant frames of the scroll frame,
|
||||
// relative to the origin of the scrolled frame.
|
||||
nsTArray<nsPoint> mScrollSnapCoordinates;
|
||||
};
|
||||
|
||||
/**
|
||||
* Metadata about a scroll frame that's stored in the layer tree for use by
|
||||
* the compositor (including APZ). This includes the scroll frame's FrameMetrics,
|
||||
* as well as other metadata. We don't put the other metadata into FrameMetrics
|
||||
* to avoid FrameMetrics becoming too bloated (as a FrameMetrics is e.g. sent
|
||||
* over IPC for every repaint request for every active scroll frame).
|
||||
*/
|
||||
struct ScrollMetadata {
|
||||
friend struct IPC::ParamTraits<mozilla::layers::ScrollMetadata>;
|
||||
public:
|
||||
static StaticAutoPtr<const ScrollMetadata> sNullMetadata; // We sometimes need an empty metadata
|
||||
|
||||
ScrollMetadata()
|
||||
: mMetrics()
|
||||
, mSnapInfo()
|
||||
, mMaskLayerIndex()
|
||||
, mClipRect()
|
||||
{}
|
||||
|
||||
bool operator==(const ScrollMetadata& aOther) const
|
||||
{
|
||||
// TODO(botond): Should we include mSnapInfo in the comparison?
|
||||
return mMetrics == aOther.mMetrics &&
|
||||
mMaskLayerIndex == aOther.mMaskLayerIndex &&
|
||||
mClipRect == aOther.mClipRect;
|
||||
}
|
||||
|
||||
bool operator!=(const ScrollMetadata& aOther) const
|
||||
{
|
||||
return !operator==(aOther);
|
||||
}
|
||||
|
||||
bool IsDefault() const
|
||||
{
|
||||
ScrollMetadata def;
|
||||
|
||||
def.mMetrics.SetPresShellId(mMetrics.GetPresShellId());
|
||||
return (def == *this);
|
||||
}
|
||||
|
||||
FrameMetrics& GetMetrics() { return mMetrics; }
|
||||
const FrameMetrics& GetMetrics() const { return mMetrics; }
|
||||
|
||||
void SetSnapInfo(ScrollSnapInfo&& aSnapInfo) {
|
||||
mSnapInfo = Move(aSnapInfo);
|
||||
}
|
||||
const ScrollSnapInfo& GetSnapInfo() const { return mSnapInfo; }
|
||||
|
||||
void SetMaskLayerIndex(const Maybe<size_t>& aIndex) {
|
||||
mMaskLayerIndex = aIndex;
|
||||
}
|
||||
const Maybe<size_t>& GetMaskLayerIndex() const {
|
||||
return mMaskLayerIndex;
|
||||
}
|
||||
|
||||
void SetClipRect(const Maybe<ParentLayerIntRect>& aClipRect)
|
||||
{
|
||||
mClipRect = aClipRect;
|
||||
}
|
||||
const Maybe<ParentLayerIntRect>& GetClipRect() const
|
||||
{
|
||||
return mClipRect;
|
||||
}
|
||||
bool HasClipRect() const {
|
||||
return mClipRect.isSome();
|
||||
}
|
||||
const ParentLayerIntRect& ClipRect() const {
|
||||
return mClipRect.ref();
|
||||
}
|
||||
private:
|
||||
FrameMetrics mMetrics;
|
||||
|
||||
// Information used to determine where to snap to for a given scroll.
|
||||
ScrollSnapInfo mSnapInfo;
|
||||
|
||||
// An extra clip mask layer to use when compositing a layer with this
|
||||
// FrameMetrics. This is an index into the MetricsMaskLayers array on
|
||||
// the Layer.
|
||||
Maybe<size_t> mMaskLayerIndex;
|
||||
|
||||
// The clip rect to use when compositing a layer with this FrameMetrics.
|
||||
Maybe<ParentLayerIntRect> mClipRect;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class allows us to uniquely identify a scrollable layer. The
|
||||
* mLayersId identifies the layer tree (corresponding to a child process
|
||||
|
|
|
@ -142,7 +142,7 @@ public:
|
|||
|
||||
switch (aStart) {
|
||||
case StartAt::TOP:
|
||||
mIndex = mLayer->GetFrameMetricsCount();
|
||||
mIndex = mLayer->GetScrollMetadataCount();
|
||||
if (mIndex > 0) {
|
||||
mIndex--;
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ public:
|
|||
, mIndex(aMetricsIndex)
|
||||
{
|
||||
MOZ_ASSERT(mLayer);
|
||||
MOZ_ASSERT(mIndex == 0 || mIndex < mLayer->GetFrameMetricsCount());
|
||||
MOZ_ASSERT(mIndex == 0 || mIndex < mLayer->GetScrollMetadataCount());
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
|
@ -240,21 +240,26 @@ public:
|
|||
return LayerMetricsWrapper(nullptr);
|
||||
}
|
||||
|
||||
const FrameMetrics& Metrics() const
|
||||
const ScrollMetadata& Metadata() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (mIndex >= mLayer->GetFrameMetricsCount()) {
|
||||
return FrameMetrics::sNullMetrics;
|
||||
if (mIndex >= mLayer->GetScrollMetadataCount()) {
|
||||
return *ScrollMetadata::sNullMetadata;
|
||||
}
|
||||
return mLayer->GetFrameMetrics(mIndex);
|
||||
return mLayer->GetScrollMetadata(mIndex);
|
||||
}
|
||||
|
||||
const FrameMetrics& Metrics() const
|
||||
{
|
||||
return Metadata().GetMetrics();
|
||||
}
|
||||
|
||||
AsyncPanZoomController* GetApzc() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (mIndex >= mLayer->GetFrameMetricsCount()) {
|
||||
if (mIndex >= mLayer->GetScrollMetadataCount()) {
|
||||
return nullptr;
|
||||
}
|
||||
return mLayer->GetAsyncPanZoomController(mIndex);
|
||||
|
@ -264,12 +269,12 @@ public:
|
|||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
if (mLayer->GetFrameMetricsCount() == 0) {
|
||||
if (mLayer->GetScrollMetadataCount() == 0) {
|
||||
MOZ_ASSERT(mIndex == 0);
|
||||
MOZ_ASSERT(aApzc == nullptr);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mIndex < mLayer->GetFrameMetricsCount());
|
||||
MOZ_ASSERT(mIndex < mLayer->GetScrollMetadataCount());
|
||||
mLayer->SetAsyncPanZoomController(mIndex, aApzc);
|
||||
}
|
||||
|
||||
|
@ -441,30 +446,30 @@ public:
|
|||
|
||||
static const FrameMetrics& TopmostScrollableMetrics(Layer* aLayer)
|
||||
{
|
||||
for (uint32_t i = aLayer->GetFrameMetricsCount(); i > 0; i--) {
|
||||
for (uint32_t i = aLayer->GetScrollMetadataCount(); i > 0; i--) {
|
||||
if (aLayer->GetFrameMetrics(i - 1).IsScrollable()) {
|
||||
return aLayer->GetFrameMetrics(i - 1);
|
||||
}
|
||||
}
|
||||
return FrameMetrics::sNullMetrics;
|
||||
return ScrollMetadata::sNullMetadata->GetMetrics();
|
||||
}
|
||||
|
||||
static const FrameMetrics& BottommostScrollableMetrics(Layer* aLayer)
|
||||
{
|
||||
for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
|
||||
for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
|
||||
if (aLayer->GetFrameMetrics(i).IsScrollable()) {
|
||||
return aLayer->GetFrameMetrics(i);
|
||||
}
|
||||
}
|
||||
return FrameMetrics::sNullMetrics;
|
||||
return ScrollMetadata::sNullMetadata->GetMetrics();
|
||||
}
|
||||
|
||||
static const FrameMetrics& BottommostMetrics(Layer* aLayer)
|
||||
{
|
||||
if (aLayer->GetFrameMetricsCount() > 0) {
|
||||
if (aLayer->GetScrollMetadataCount() > 0) {
|
||||
return aLayer->GetFrameMetrics(0);
|
||||
}
|
||||
return FrameMetrics::sNullMetrics;
|
||||
return ScrollMetadata::sNullMetadata->GetMetrics();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -475,7 +480,7 @@ private:
|
|||
|
||||
bool AtTopLayer() const
|
||||
{
|
||||
return mLayer->GetFrameMetricsCount() == 0 || mIndex == mLayer->GetFrameMetricsCount() - 1;
|
||||
return mLayer->GetScrollMetadataCount() == 0 || mIndex == mLayer->GetScrollMetadataCount() - 1;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -538,14 +538,14 @@ Layer::StartPendingAnimations(const TimeStamp& aReadyTime)
|
|||
void
|
||||
Layer::SetAsyncPanZoomController(uint32_t aIndex, AsyncPanZoomController *controller)
|
||||
{
|
||||
MOZ_ASSERT(aIndex < GetFrameMetricsCount());
|
||||
MOZ_ASSERT(aIndex < GetScrollMetadataCount());
|
||||
mApzcs[aIndex] = controller;
|
||||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
Layer::GetAsyncPanZoomController(uint32_t aIndex) const
|
||||
{
|
||||
MOZ_ASSERT(aIndex < GetFrameMetricsCount());
|
||||
MOZ_ASSERT(aIndex < GetScrollMetadataCount());
|
||||
#ifdef DEBUG
|
||||
if (mApzcs[aIndex]) {
|
||||
MOZ_ASSERT(GetFrameMetrics(aIndex).IsScrollable());
|
||||
|
@ -555,9 +555,9 @@ Layer::GetAsyncPanZoomController(uint32_t aIndex) const
|
|||
}
|
||||
|
||||
void
|
||||
Layer::FrameMetricsChanged()
|
||||
Layer::ScrollMetadataChanged()
|
||||
{
|
||||
mApzcs.SetLength(GetFrameMetricsCount());
|
||||
mApzcs.SetLength(GetScrollMetadataCount());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -846,17 +846,23 @@ Layer::CalculateScissorRect(const RenderTargetIntRect& aCurrentScissorRect)
|
|||
return currentClip.Intersect(scissor);
|
||||
}
|
||||
|
||||
const ScrollMetadata&
|
||||
Layer::GetScrollMetadata(uint32_t aIndex) const
|
||||
{
|
||||
MOZ_ASSERT(aIndex < GetScrollMetadataCount());
|
||||
return mScrollMetadata[aIndex];
|
||||
}
|
||||
|
||||
const FrameMetrics&
|
||||
Layer::GetFrameMetrics(uint32_t aIndex) const
|
||||
{
|
||||
MOZ_ASSERT(aIndex < GetFrameMetricsCount());
|
||||
return mFrameMetrics[aIndex];
|
||||
return GetScrollMetadata(aIndex).GetMetrics();
|
||||
}
|
||||
|
||||
bool
|
||||
Layer::HasScrollableFrameMetrics() const
|
||||
{
|
||||
for (uint32_t i = 0; i < GetFrameMetricsCount(); i++) {
|
||||
for (uint32_t i = 0; i < GetScrollMetadataCount(); i++) {
|
||||
if (GetFrameMetrics(i).IsScrollable()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1088,12 +1094,12 @@ Layer::GetCombinedClipRect() const
|
|||
{
|
||||
Maybe<ParentLayerIntRect> clip = GetClipRect();
|
||||
|
||||
for (size_t i = 0; i < mFrameMetrics.Length(); i++) {
|
||||
if (!mFrameMetrics[i].HasClipRect()) {
|
||||
for (size_t i = 0; i < mScrollMetadata.Length(); i++) {
|
||||
if (!mScrollMetadata[i].HasClipRect()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ParentLayerIntRect& other = mFrameMetrics[i].ClipRect();
|
||||
const ParentLayerIntRect& other = mScrollMetadata[i].ClipRect();
|
||||
if (clip) {
|
||||
clip = Some(clip.value().Intersect(other));
|
||||
} else {
|
||||
|
@ -1968,10 +1974,10 @@ Layer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
|||
if (mMaskLayer) {
|
||||
aStream << nsPrintfCString(" [mMaskLayer=%p]", mMaskLayer.get()).get();
|
||||
}
|
||||
for (uint32_t i = 0; i < mFrameMetrics.Length(); i++) {
|
||||
if (!mFrameMetrics[i].IsDefault()) {
|
||||
for (uint32_t i = 0; i < mScrollMetadata.Length(); i++) {
|
||||
if (!mScrollMetadata[i].IsDefault()) {
|
||||
aStream << nsPrintfCString(" [metrics%d=", i).get();
|
||||
AppendToString(aStream, mFrameMetrics[i], "", "]");
|
||||
AppendToString(aStream, mScrollMetadata[i], "", "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -855,12 +855,12 @@ public:
|
|||
* them with the provided FrameMetrics. See the documentation for
|
||||
* SetFrameMetrics(const nsTArray<FrameMetrics>&) for more details.
|
||||
*/
|
||||
void SetFrameMetrics(const FrameMetrics& aFrameMetrics)
|
||||
void SetScrollMetadata(const ScrollMetadata& aScrollMetadata)
|
||||
{
|
||||
if (mFrameMetrics.Length() != 1 || mFrameMetrics[0] != aFrameMetrics) {
|
||||
if (mScrollMetadata.Length() != 1 || mScrollMetadata[0] != aScrollMetadata) {
|
||||
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) FrameMetrics", this));
|
||||
mFrameMetrics.ReplaceElementsAt(0, mFrameMetrics.Length(), aFrameMetrics);
|
||||
FrameMetricsChanged();
|
||||
mScrollMetadata.ReplaceElementsAt(0, mScrollMetadata.Length(), aScrollMetadata);
|
||||
ScrollMetadataChanged();
|
||||
Mutated();
|
||||
}
|
||||
}
|
||||
|
@ -871,23 +871,23 @@ public:
|
|||
* rooted at this. There might be multiple metrics on this layer
|
||||
* because the layer may, for example, be contained inside multiple
|
||||
* nested scrolling subdocuments. In general a Layer having multiple
|
||||
* FrameMetrics objects is conceptually equivalent to having a stack
|
||||
* ScrollMetadata objects is conceptually equivalent to having a stack
|
||||
* of ContainerLayers that have been flattened into this Layer.
|
||||
* See the documentation in LayerMetricsWrapper.h for a more detailed
|
||||
* explanation of this conceptual equivalence.
|
||||
*
|
||||
* Note also that there is actually a many-to-many relationship between
|
||||
* Layers and FrameMetrics, because multiple Layers may have identical
|
||||
* FrameMetrics objects. This happens when those layers belong to the
|
||||
* Layers and ScrollMetadata, because multiple Layers may have identical
|
||||
* ScrollMetadata objects. This happens when those layers belong to the
|
||||
* same scrolling subdocument and therefore end up with the same async
|
||||
* transform when they are scrolled by the APZ code.
|
||||
*/
|
||||
void SetFrameMetrics(const nsTArray<FrameMetrics>& aMetricsArray)
|
||||
void SetScrollMetadata(const nsTArray<ScrollMetadata>& aMetadataArray)
|
||||
{
|
||||
if (mFrameMetrics != aMetricsArray) {
|
||||
if (mScrollMetadata != aMetadataArray) {
|
||||
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) FrameMetrics", this));
|
||||
mFrameMetrics = aMetricsArray;
|
||||
FrameMetricsChanged();
|
||||
mScrollMetadata = aMetadataArray;
|
||||
ScrollMetadataChanged();
|
||||
Mutated();
|
||||
}
|
||||
}
|
||||
|
@ -1254,9 +1254,10 @@ public:
|
|||
uint32_t GetContentFlags() { return mContentFlags; }
|
||||
const gfx::IntRect& GetLayerBounds() const { return mLayerBounds; }
|
||||
const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; }
|
||||
const ScrollMetadata& GetScrollMetadata(uint32_t aIndex) const;
|
||||
const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const;
|
||||
uint32_t GetFrameMetricsCount() const { return mFrameMetrics.Length(); }
|
||||
const nsTArray<FrameMetrics>& GetAllFrameMetrics() { return mFrameMetrics; }
|
||||
uint32_t GetScrollMetadataCount() const { return mScrollMetadata.Length(); }
|
||||
const nsTArray<ScrollMetadata>& GetAllScrollMetadata() { return mScrollMetadata; }
|
||||
bool HasScrollableFrameMetrics() const;
|
||||
bool IsScrollInfoLayer() const;
|
||||
const EventRegions& GetEventRegions() const { return mEventRegions; }
|
||||
|
@ -1667,10 +1668,10 @@ public:
|
|||
// The aIndex for these functions must be less than GetFrameMetricsCount().
|
||||
void SetAsyncPanZoomController(uint32_t aIndex, AsyncPanZoomController *controller);
|
||||
AsyncPanZoomController* GetAsyncPanZoomController(uint32_t aIndex) const;
|
||||
// The FrameMetricsChanged function is used internally to ensure the APZC array length
|
||||
// The ScrollMetadataChanged function is used internally to ensure the APZC array length
|
||||
// matches the frame metrics array length.
|
||||
private:
|
||||
void FrameMetricsChanged();
|
||||
void ScrollMetadataChanged();
|
||||
public:
|
||||
|
||||
void ApplyPendingUpdatesForThisTransaction();
|
||||
|
@ -1791,7 +1792,7 @@ protected:
|
|||
gfx::UserData mUserData;
|
||||
gfx::IntRect mLayerBounds;
|
||||
LayerIntRegion mVisibleRegion;
|
||||
nsTArray<FrameMetrics> mFrameMetrics;
|
||||
nsTArray<ScrollMetadata> mScrollMetadata;
|
||||
EventRegions mEventRegions;
|
||||
gfx::Matrix4x4 mTransform;
|
||||
// A mutation of |mTransform| that we've queued to be applied at the
|
||||
|
@ -2498,8 +2499,6 @@ private:
|
|||
virtual bool RepositionChild(Layer* aChild, Layer* aAfter) override
|
||||
{ MOZ_CRASH(); return false; }
|
||||
|
||||
using Layer::SetFrameMetrics;
|
||||
|
||||
public:
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
|
|
|
@ -144,6 +144,18 @@ AppendToString(std::stringstream& aStream, const EventRegions& e,
|
|||
aStream << "}" << sfx;
|
||||
}
|
||||
|
||||
void
|
||||
AppendToString(std::stringstream& aStream, const ScrollMetadata& m,
|
||||
const char* pfx, const char* sfx)
|
||||
{
|
||||
aStream << pfx;
|
||||
AppendToString(aStream, m.GetMetrics(), "{ [metrics=", "]");
|
||||
if (m.HasClipRect()) {
|
||||
AppendToString(aStream, m.ClipRect(), " [clip=", "]");
|
||||
}
|
||||
aStream << "}" << sfx;
|
||||
}
|
||||
|
||||
void
|
||||
AppendToString(std::stringstream& aStream, const FrameMetrics& m,
|
||||
const char* pfx, const char* sfx, bool detailed)
|
||||
|
@ -166,9 +178,6 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
|
|||
if (m.IsRootContent()) {
|
||||
aStream << "] [rcd";
|
||||
}
|
||||
if (m.HasClipRect()) {
|
||||
AppendToString(aStream, m.ClipRect(), "] [clip=");
|
||||
}
|
||||
AppendToString(aStream, m.GetZoom(), "] [z=", "] }");
|
||||
} else {
|
||||
AppendToString(aStream, m.GetDisplayPortMargins(), " [dpm=");
|
||||
|
|
|
@ -114,6 +114,10 @@ void
|
|||
AppendToString(std::stringstream& aStream, const EventRegions& e,
|
||||
const char* pfx="", const char* sfx="");
|
||||
|
||||
void
|
||||
AppendToString(std::stringstream& aStream, const ScrollMetadata& m,
|
||||
const char* pfx="", const char* sfx="");
|
||||
|
||||
void
|
||||
AppendToString(std::stringstream& aStream, const FrameMetrics& m,
|
||||
const char* pfx="", const char* sfx="", bool detailed = false);
|
||||
|
|
|
@ -36,14 +36,6 @@ public:
|
|||
*/
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
|
||||
|
||||
/**
|
||||
* Requests handling of a scroll snapping at the end of a fling gesture for
|
||||
* the scrollable frame with the given scroll id. aDestination specifies the
|
||||
* expected landing position of the fling if no snapping were to be performed.
|
||||
*/
|
||||
virtual void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination) = 0;
|
||||
|
||||
/**
|
||||
* Acknowledges the recipt of a scroll offset update for the scrollable
|
||||
* frame with the given scroll id. This is used to maintain consistency
|
||||
|
@ -153,6 +145,7 @@ public:
|
|||
|
||||
virtual void UpdateOverscrollVelocity(const float aX, const float aY) {}
|
||||
virtual void UpdateOverscrollOffset(const float aX, const float aY) {}
|
||||
virtual void SetScrollingRootContent(const bool isRootContent) {}
|
||||
|
||||
GeckoContentController() {}
|
||||
virtual void ChildAdopted() {}
|
||||
|
|
|
@ -457,7 +457,7 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
|||
|
||||
APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId());
|
||||
|
||||
apzc->NotifyLayersUpdated(aMetrics, aState.mIsFirstPaint,
|
||||
apzc->NotifyLayersUpdated(aLayer.Metadata(), aState.mIsFirstPaint,
|
||||
aLayersId == aState.mOriginatingLayersId);
|
||||
|
||||
// Since this is the first time we are encountering an APZC with this guid,
|
||||
|
|
|
@ -25,7 +25,7 @@ enum HitTestResult {
|
|||
enum CancelAnimationFlags : uint32_t {
|
||||
Default = 0x0, /* Cancel all animations */
|
||||
ExcludeOverscroll = 0x1, /* Don't clear overscroll */
|
||||
RequestSnap = 0x2 /* Request snapping to snap points */
|
||||
ScrollSnap = 0x2 /* Snap to snap points */
|
||||
};
|
||||
|
||||
inline CancelAnimationFlags
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#include "nsThreadUtils.h" // for NS_IsMainThread
|
||||
#include "prsystem.h" // for PR_GetPhysicalMemorySize
|
||||
#include "SharedMemoryBasic.h" // for SharedMemoryBasic
|
||||
#include "ScrollSnap.h" // for ScrollSnapUtils
|
||||
#include "WheelScrollAnimation.h"
|
||||
|
||||
#define ENABLE_APZC_LOGGING 0
|
||||
|
@ -691,7 +692,13 @@ public:
|
|||
// snap point, so we request one now. If there are no snap points, this will
|
||||
// do nothing. If there are snap points, we'll get a scrollTo that snaps us
|
||||
// back to the nearest valid snap point.
|
||||
mApzc.RequestSnap();
|
||||
// The scroll snapping is done in a deferred task, otherwise the state
|
||||
// change to NOTHING caused by the overscroll animation ending would
|
||||
// clobber a possible state change to SMOOTH_SCROLL in ScrollSnap().
|
||||
if (!mDeferredTasks.append(NewRunnableMethod(&mApzc,
|
||||
&AsyncPanZoomController::ScrollSnap))) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -709,7 +716,6 @@ private:
|
|||
class SmoothScrollAnimation : public AsyncPanZoomAnimation {
|
||||
public:
|
||||
SmoothScrollAnimation(AsyncPanZoomController& aApzc,
|
||||
ScrollSource aSource,
|
||||
const nsPoint &aInitialPosition,
|
||||
const nsPoint &aInitialVelocity,
|
||||
const nsPoint& aDestination, double aSpringConstant,
|
||||
|
@ -860,6 +866,7 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
|
|||
// mTreeManager must be initialized before GetFrameTime() is called
|
||||
mTreeManager(aTreeManager),
|
||||
mSharingFrameMetricsAcrossProcesses(false),
|
||||
mFrameMetrics(mScrollMetadata.GetMetrics()),
|
||||
mMonitor("AsyncPanZoomController"),
|
||||
mX(this),
|
||||
mY(this),
|
||||
|
@ -924,7 +931,7 @@ AsyncPanZoomController::Destroy()
|
|||
{
|
||||
APZThreadUtils::AssertOnCompositorThread();
|
||||
|
||||
CancelAnimation(CancelAnimationFlags::RequestSnap);
|
||||
CancelAnimation(CancelAnimationFlags::ScrollSnap);
|
||||
|
||||
{ // scope the lock
|
||||
MonitorAutoLock lock(mRefPtrMonitor);
|
||||
|
@ -1319,6 +1326,11 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
|
|||
nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) {
|
||||
APZC_LOG("%p got a touch-end in state %d\n", this, mState);
|
||||
|
||||
RefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
controller->SetScrollingRootContent(false);
|
||||
}
|
||||
|
||||
OnTouchEndOrCancel();
|
||||
|
||||
// In case no touch behavior triggered previously we can avoid sending
|
||||
|
@ -1545,6 +1557,20 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
|
|||
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
ScheduleComposite();
|
||||
RequestContentRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
|
||||
// Non-negative focus point would indicate that one finger is still down
|
||||
if (aEvent.mFocusPoint.x != -1 && aEvent.mFocusPoint.y != -1) {
|
||||
mPanDirRestricted = false;
|
||||
mX.StartTouch(aEvent.mFocusPoint.x, aEvent.mTime);
|
||||
mY.StartTouch(aEvent.mFocusPoint.y, aEvent.mTime);
|
||||
SetState(TOUCHING);
|
||||
} else {
|
||||
// Otherwise, handle the fingers being lifted.
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
// We can get into a situation where we are overscrolled at the end of a
|
||||
// pinch if we go into overscroll with a two-finger pan, and then turn
|
||||
|
@ -1560,21 +1586,8 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
|
|||
ClearOverscroll();
|
||||
}
|
||||
// Along with clearing the overscroll, we also want to snap to the nearest
|
||||
// snap point as appropriate, so ask the main thread (which knows about such
|
||||
// things) to handle it.
|
||||
RequestSnap();
|
||||
|
||||
ScheduleComposite();
|
||||
RequestContentRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
|
||||
// Non-negative focus point would indicate that one finger is still down
|
||||
if (aEvent.mFocusPoint.x != -1 && aEvent.mFocusPoint.y != -1) {
|
||||
mPanDirRestricted = false;
|
||||
mX.StartTouch(aEvent.mFocusPoint.x, aEvent.mTime);
|
||||
mY.StartTouch(aEvent.mFocusPoint.y, aEvent.mTime);
|
||||
SetState(TOUCHING);
|
||||
// snap point as appropriate.
|
||||
ScrollSnap();
|
||||
}
|
||||
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
@ -1998,7 +2011,7 @@ nsEventStatus AsyncPanZoomController::OnPanEnd(const PanGestureInput& aEvent) {
|
|||
RequestContentRepaint();
|
||||
|
||||
if (!aEvent.mFollowedByMomentum) {
|
||||
RequestSnap();
|
||||
ScrollSnap();
|
||||
}
|
||||
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
@ -2013,7 +2026,7 @@ nsEventStatus AsyncPanZoomController::OnPanMomentumStart(const PanGestureInput&
|
|||
}
|
||||
|
||||
SetState(PAN_MOMENTUM);
|
||||
RequestSnapToDestination();
|
||||
ScrollSnapToDestination();
|
||||
|
||||
// Call into OnPan in order to process any delta included in this event.
|
||||
OnPan(aEvent, false);
|
||||
|
@ -2360,11 +2373,11 @@ bool AsyncPanZoomController::AttemptScroll(ParentLayerPoint& aStartPoint,
|
|||
// a later event in the block could potentially scroll an APZC earlier
|
||||
// in the handoff chain, than an earlier event in the block (because
|
||||
// the earlier APZC was scrolled to its extent in the original direction).
|
||||
// If immediate handoff is disallowed, we want to disallow this (to
|
||||
// preserve the property that a single input block only scrolls one APZC),
|
||||
// so we skip the earlier APZC.
|
||||
bool scrollThisApzc = gfxPrefs::APZAllowImmediateHandoff() ||
|
||||
(CurrentInputBlock() && (!CurrentInputBlock()->GetScrolledApzc() || this == CurrentInputBlock()->GetScrolledApzc()));
|
||||
// We want to disallow this.
|
||||
bool scrollThisApzc = false;
|
||||
if (InputBlockState* block = CurrentInputBlock()) {
|
||||
scrollThisApzc = !block->GetScrolledApzc() || block->IsDownchainOfScrolledApzc(this);
|
||||
}
|
||||
|
||||
if (scrollThisApzc) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
@ -2383,20 +2396,24 @@ bool AsyncPanZoomController::AttemptScroll(ParentLayerPoint& aStartPoint,
|
|||
|
||||
if (!IsZero(adjustedDisplacement)) {
|
||||
ScrollBy(adjustedDisplacement / mFrameMetrics.GetZoom());
|
||||
if (!gfxPrefs::APZAllowImmediateHandoff()) {
|
||||
if (InputBlockState* block = CurrentInputBlock()) {
|
||||
block->SetScrolledApzc(this);
|
||||
if (CancelableBlockState* block = CurrentInputBlock()) {
|
||||
if (block->AsTouchBlock() && (block->GetScrolledApzc() != this)) {
|
||||
RefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
controller->SetScrollingRootContent(IsRootContent());
|
||||
}
|
||||
}
|
||||
block->SetScrolledApzc(this);
|
||||
}
|
||||
ScheduleCompositeAndMaybeRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
} else {
|
||||
overscroll = displacement;
|
||||
}
|
||||
|
||||
// Adjust the start point to reflect the consumed portion of the scroll.
|
||||
aStartPoint = aEndPoint + overscroll;
|
||||
} else {
|
||||
overscroll = displacement;
|
||||
}
|
||||
|
||||
// If we consumed the entire displacement as a normal scroll, great.
|
||||
if (IsZero(overscroll)) {
|
||||
|
@ -2510,52 +2527,19 @@ void AsyncPanZoomController::AcceptFling(FlingHandoffState& aHandoffState) {
|
|||
mY.SetVelocity(mY.GetVelocity() + aHandoffState.mVelocity.y);
|
||||
aHandoffState.mVelocity.y = 0;
|
||||
}
|
||||
|
||||
// If there's a scroll snap point near the predicted fling destination,
|
||||
// scroll there using a smooth scroll animation. Otherwise, start a
|
||||
// fling animation.
|
||||
ScrollSnapToDestination();
|
||||
if (mState != SMOOTH_SCROLL) {
|
||||
SetState(FLING);
|
||||
FlingAnimation *fling = new FlingAnimation(*this,
|
||||
aHandoffState.mChain,
|
||||
!aHandoffState.mIsHandoff, // only apply acceleration if this is an initial fling
|
||||
aHandoffState.mScrolledApzc);
|
||||
RequestSnapToDestination();
|
||||
StartAnimation(fling);
|
||||
}
|
||||
|
||||
void
|
||||
AsyncPanZoomController::RequestSnapToDestination()
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
float friction = gfxPrefs::APZFlingFriction();
|
||||
ParentLayerPoint velocity(mX.GetVelocity(), mY.GetVelocity());
|
||||
ParentLayerPoint predictedDelta;
|
||||
// "-velocity / log(1.0 - friction)" is the integral of the deceleration
|
||||
// curve modeled for flings in the "Axis" class.
|
||||
if (velocity.x != 0.0f) {
|
||||
predictedDelta.x = -velocity.x / log(1.0 - friction);
|
||||
}
|
||||
if (velocity.y != 0.0f) {
|
||||
predictedDelta.y = -velocity.y / log(1.0 - friction);
|
||||
}
|
||||
CSSPoint predictedDestination = mFrameMetrics.GetScrollOffset() + predictedDelta / mFrameMetrics.GetZoom();
|
||||
|
||||
// If the fling will overscroll, don't request a fling snap, because the
|
||||
// resulting content scrollTo() would unnecessarily cancel the overscroll
|
||||
// animation.
|
||||
bool flingWillOverscroll = IsOverscrolled() && ((velocity.x * mX.GetOverscroll() >= 0) ||
|
||||
(velocity.y * mY.GetOverscroll() >= 0));
|
||||
if (!flingWillOverscroll) {
|
||||
RefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
APZC_LOG("%p fling snapping. friction: %f velocity: %f, %f "
|
||||
"predictedDelta: %f, %f position: %f, %f "
|
||||
"predictedDestination: %f, %f\n",
|
||||
this, friction, velocity.x, velocity.y, (float)predictedDelta.x,
|
||||
(float)predictedDelta.y, (float)mFrameMetrics.GetScrollOffset().x,
|
||||
(float)mFrameMetrics.GetScrollOffset().y,
|
||||
(float)predictedDestination.x, (float)predictedDestination.y);
|
||||
controller->RequestFlingSnap(mFrameMetrics.GetScrollId(),
|
||||
predictedDestination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AsyncPanZoomController::AttemptFling(FlingHandoffState& aHandoffState) {
|
||||
|
@ -2597,22 +2581,29 @@ void AsyncPanZoomController::HandleSmoothScrollOverscroll(const ParentLayerPoint
|
|||
HandleFlingOverscroll(aVelocity, BuildOverscrollHandoffChain(), nullptr);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::StartSmoothScroll(ScrollSource aSource) {
|
||||
void AsyncPanZoomController::SmoothScrollTo(const CSSPoint& aDestination) {
|
||||
if (mState == SMOOTH_SCROLL && mAnimation) {
|
||||
APZC_LOG("%p updating destination on existing animation\n", this);
|
||||
RefPtr<SmoothScrollAnimation> animation(
|
||||
static_cast<SmoothScrollAnimation*>(mAnimation.get()));
|
||||
animation->SetDestination(CSSPoint::ToAppUnits(aDestination));
|
||||
} else {
|
||||
CancelAnimation();
|
||||
SetState(SMOOTH_SCROLL);
|
||||
nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset());
|
||||
// Cast velocity from ParentLayerPoints/ms to CSSPoints/ms then convert to
|
||||
// appunits/second
|
||||
nsPoint initialVelocity = CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(),
|
||||
mY.GetVelocity())) * 1000.0f;
|
||||
nsPoint destination = CSSPoint::ToAppUnits(mFrameMetrics.GetSmoothScrollOffset());
|
||||
nsPoint destination = CSSPoint::ToAppUnits(aDestination);
|
||||
|
||||
StartAnimation(new SmoothScrollAnimation(*this,
|
||||
aSource,
|
||||
initialPosition, initialVelocity,
|
||||
destination,
|
||||
gfxPrefs::ScrollBehaviorSpringConstant(),
|
||||
gfxPrefs::ScrollBehaviorDampingRatio()));
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::StartOverscrollAnimation(const ParentLayerPoint& aVelocity) {
|
||||
SetState(OVERSCROLL_ANIMATION);
|
||||
|
@ -2692,9 +2683,9 @@ void AsyncPanZoomController::CancelAnimation(CancelAnimationFlags aFlags) {
|
|||
repaint = true;
|
||||
}
|
||||
// Similar to relieving overscroll, we also need to snap to any snap points
|
||||
// if appropriate, so ask the main thread to do that.
|
||||
if (aFlags & CancelAnimationFlags::RequestSnap) {
|
||||
RequestSnap();
|
||||
// if appropriate.
|
||||
if (aFlags & CancelAnimationFlags::ScrollSnap) {
|
||||
ScrollSnap();
|
||||
}
|
||||
if (repaint) {
|
||||
RequestContentRepaint();
|
||||
|
@ -2894,7 +2885,7 @@ bool AsyncPanZoomController::SnapBackIfOverscrolled() {
|
|||
// main thread to snap to any nearby snap points, assuming we haven't already
|
||||
// done so when we started this fling
|
||||
if (mState != FLING) {
|
||||
RequestSnap();
|
||||
ScrollSnap();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -3289,14 +3280,16 @@ bool AsyncPanZoomController::IsCurrentlyCheckerboarding() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics,
|
||||
void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMetadata,
|
||||
bool aIsFirstPaint,
|
||||
bool aThisLayerTreeUpdated)
|
||||
{
|
||||
APZThreadUtils::AssertOnCompositorThread();
|
||||
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
bool isDefault = mFrameMetrics.IsDefault();
|
||||
bool isDefault = mScrollMetadata.IsDefault();
|
||||
|
||||
const FrameMetrics& aLayerMetrics = aScrollMetadata.GetMetrics();
|
||||
|
||||
if ((aLayerMetrics == mLastContentPaintMetrics) && !isDefault) {
|
||||
// No new information here, skip it. Note that this is not just an
|
||||
|
@ -3381,7 +3374,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||
// that was just painted is something we knew nothing about previously
|
||||
CancelAnimation();
|
||||
|
||||
mFrameMetrics = aLayerMetrics;
|
||||
mScrollMetadata = aScrollMetadata;
|
||||
if (scrollOffsetUpdated) {
|
||||
AcknowledgeScrollUpdate();
|
||||
}
|
||||
|
@ -3437,8 +3430,9 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||
mFrameMetrics.SetHasScrollgrab(aLayerMetrics.GetHasScrollgrab());
|
||||
mFrameMetrics.SetLineScrollAmount(aLayerMetrics.GetLineScrollAmount());
|
||||
mFrameMetrics.SetPageScrollAmount(aLayerMetrics.GetPageScrollAmount());
|
||||
mFrameMetrics.SetClipRect(aLayerMetrics.GetClipRect());
|
||||
mFrameMetrics.SetMaskLayerIndex(aLayerMetrics.GetMaskLayerIndex());
|
||||
mScrollMetadata.SetSnapInfo(ScrollSnapInfo(aScrollMetadata.GetSnapInfo()));
|
||||
mScrollMetadata.SetClipRect(aScrollMetadata.GetClipRect());
|
||||
mScrollMetadata.SetMaskLayerIndex(aScrollMetadata.GetMaskLayerIndex());
|
||||
mFrameMetrics.SetIsLayersIdRoot(aLayerMetrics.IsLayersIdRoot());
|
||||
mFrameMetrics.SetUsesContainerScrolling(aLayerMetrics.UsesContainerScrolling());
|
||||
mFrameMetrics.SetIsScrollInfoLayer(aLayerMetrics.IsScrollInfoLayer());
|
||||
|
@ -3491,16 +3485,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||
AcknowledgeScrollUpdate();
|
||||
mExpectedGeckoMetrics = aLayerMetrics;
|
||||
|
||||
if (mState == SMOOTH_SCROLL && mAnimation) {
|
||||
APZC_LOG("%p updating destination on existing animation\n", this);
|
||||
RefPtr<SmoothScrollAnimation> animation(
|
||||
static_cast<SmoothScrollAnimation*>(mAnimation.get()));
|
||||
animation->SetDestination(
|
||||
CSSPoint::ToAppUnits(aLayerMetrics.GetSmoothScrollOffset()));
|
||||
} else {
|
||||
CancelAnimation();
|
||||
StartSmoothScroll(ScrollSource::DOM);
|
||||
}
|
||||
SmoothScrollTo(mFrameMetrics.GetSmoothScrollOffset());
|
||||
}
|
||||
|
||||
if (needContentRepaint) {
|
||||
|
@ -3742,7 +3727,7 @@ AsyncPanZoomController::CancelAnimationAndGestureState()
|
|||
{
|
||||
mX.CancelGesture();
|
||||
mY.CancelGesture();
|
||||
CancelAnimation(CancelAnimationFlags::RequestSnap);
|
||||
CancelAnimation(CancelAnimationFlags::ScrollSnap);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3919,12 +3904,62 @@ void AsyncPanZoomController::ShareCompositorFrameMetrics() {
|
|||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::RequestSnap() {
|
||||
if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
|
||||
APZC_LOG("%p requesting snap near %s\n", this,
|
||||
Stringify(mFrameMetrics.GetScrollOffset()).c_str());
|
||||
controller->RequestFlingSnap(mFrameMetrics.GetScrollId(),
|
||||
mFrameMetrics.GetScrollOffset());
|
||||
void AsyncPanZoomController::ScrollSnapNear(const CSSPoint& aDestination) {
|
||||
mMonitor.AssertCurrentThreadIn();
|
||||
APZC_LOG("%p scroll snapping near %s\n", this, Stringify(aDestination).c_str());
|
||||
CSSRect scrollRange = mFrameMetrics.CalculateScrollRange();
|
||||
if (Maybe<nsPoint> snapPoint = ScrollSnapUtils::GetSnapPointForDestination(
|
||||
mScrollMetadata.GetSnapInfo(),
|
||||
nsIScrollableFrame::DEVICE_PIXELS,
|
||||
CSSSize::ToAppUnits(mFrameMetrics.CalculateCompositedSizeInCssPixels()),
|
||||
CSSRect::ToAppUnits(scrollRange),
|
||||
CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset()),
|
||||
CSSPoint::ToAppUnits(aDestination))) {
|
||||
CSSPoint cssSnapPoint = CSSPoint::FromAppUnits(snapPoint.ref());
|
||||
// GetSnapPointForDestination() can produce a destination that's outside
|
||||
// of the scroll frame's scroll range. Clamp it here (this matches the
|
||||
// behaviour of the main-thread code path, which clamps it in
|
||||
// nsGfxScrollFrame::ScrollTo()).
|
||||
cssSnapPoint = scrollRange.ClampPoint(cssSnapPoint);
|
||||
SmoothScrollTo(cssSnapPoint);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ScrollSnap() {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
ScrollSnapNear(mFrameMetrics.GetScrollOffset());
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ScrollSnapToDestination() {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
float friction = gfxPrefs::APZFlingFriction();
|
||||
ParentLayerPoint velocity(mX.GetVelocity(), mY.GetVelocity());
|
||||
ParentLayerPoint predictedDelta;
|
||||
// "-velocity / log(1.0 - friction)" is the integral of the deceleration
|
||||
// curve modeled for flings in the "Axis" class.
|
||||
if (velocity.x != 0.0f) {
|
||||
predictedDelta.x = -velocity.x / log(1.0 - friction);
|
||||
}
|
||||
if (velocity.y != 0.0f) {
|
||||
predictedDelta.y = -velocity.y / log(1.0 - friction);
|
||||
}
|
||||
CSSPoint predictedDestination = mFrameMetrics.GetScrollOffset() + predictedDelta / mFrameMetrics.GetZoom();
|
||||
|
||||
// If the fling will overscroll, don't scroll snap, because then the user
|
||||
// user would not see any overscroll animation.
|
||||
bool flingWillOverscroll = IsOverscrolled() && ((velocity.x * mX.GetOverscroll() >= 0) ||
|
||||
(velocity.y * mY.GetOverscroll() >= 0));
|
||||
if (!flingWillOverscroll) {
|
||||
APZC_LOG("%p fling snapping. friction: %f velocity: %f, %f "
|
||||
"predictedDelta: %f, %f position: %f, %f "
|
||||
"predictedDestination: %f, %f\n",
|
||||
this, friction, velocity.x, velocity.y, (float)predictedDelta.x,
|
||||
(float)predictedDelta.y, (float)mFrameMetrics.GetScrollOffset().x,
|
||||
(float)mFrameMetrics.GetScrollOffset().y,
|
||||
(float)predictedDestination.x, (float)predictedDestination.y);
|
||||
|
||||
ScrollSnapNear(predictedDestination);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -178,13 +178,13 @@ public:
|
|||
AsyncTransformComponentMatrix GetOverscrollTransform() const;
|
||||
|
||||
/**
|
||||
* A shadow layer update has arrived. |aLayerMetrics| is the new FrameMetrics
|
||||
* A shadow layer update has arrived. |aScrollMetdata| is the new ScrollMetadata
|
||||
* for the container layer corresponding to this APZC.
|
||||
* |aIsFirstPaint| is a flag passed from the shadow
|
||||
* layers code indicating that the frame metrics being sent with this call are
|
||||
* the initial metrics and the initial paint of the frame has just happened.
|
||||
* layers code indicating that the scroll metadata being sent with this call are
|
||||
* the initial metadata and the initial paint of the frame has just happened.
|
||||
*/
|
||||
void NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint,
|
||||
void NotifyLayersUpdated(const ScrollMetadata& aScrollMetadata, bool aIsFirstPaint,
|
||||
bool aThisLayerTreeUpdated);
|
||||
|
||||
/**
|
||||
|
@ -643,13 +643,14 @@ protected:
|
|||
// Common processing at the end of a touch block.
|
||||
void OnTouchEndOrCancel();
|
||||
|
||||
// This is called to request that the main thread snap the scroll position
|
||||
// to a nearby snap position if appropriate. The current scroll position is
|
||||
// used as the final destination.
|
||||
void RequestSnap();
|
||||
// Same as above, but takes into account the current velocity to find a
|
||||
// predicted destination.
|
||||
void RequestSnapToDestination();
|
||||
// Snap to a snap position nearby the current scroll position, if appropriate.
|
||||
void ScrollSnap();
|
||||
// Snap to a snap position nearby the destination predicted based on the
|
||||
// current velocity, if appropriate.
|
||||
void ScrollSnapToDestination();
|
||||
|
||||
// Helper function for ScrollSnap() and ScrollSnapToDestination().
|
||||
void ScrollSnapNear(const CSSPoint& aDestination);
|
||||
|
||||
uint64_t mLayersId;
|
||||
RefPtr<CompositorBridgeParent> mCompositorBridgeParent;
|
||||
|
@ -681,7 +682,8 @@ protected:
|
|||
protected:
|
||||
// Both |mFrameMetrics| and |mLastContentPaintMetrics| are protected by the
|
||||
// monitor. Do not read from or modify either of them without locking.
|
||||
FrameMetrics mFrameMetrics;
|
||||
ScrollMetadata mScrollMetadata;
|
||||
FrameMetrics& mFrameMetrics; // for convenience, refers to mScrollMetadata.mMetrics
|
||||
|
||||
// Protects |mFrameMetrics|, |mLastContentPaintMetrics|, and |mState|.
|
||||
// Before manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the
|
||||
|
@ -878,7 +880,7 @@ private:
|
|||
// Start an overscroll animation with the given initial velocity.
|
||||
void StartOverscrollAnimation(const ParentLayerPoint& aVelocity);
|
||||
|
||||
void StartSmoothScroll(ScrollSource aSource);
|
||||
void SmoothScrollTo(const CSSPoint& aDestination);
|
||||
|
||||
// Returns whether overscroll is allowed during an event.
|
||||
bool AllowScrollHandoffInCurrentBlock() const;
|
||||
|
|
|
@ -88,7 +88,7 @@ InputBlockState::IsTargetConfirmed() const
|
|||
}
|
||||
|
||||
bool
|
||||
InputBlockState::IsAncestorOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB)
|
||||
InputBlockState::IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const
|
||||
{
|
||||
if (aA == aB) {
|
||||
return true;
|
||||
|
@ -112,7 +112,7 @@ void
|
|||
InputBlockState::SetScrolledApzc(AsyncPanZoomController* aApzc)
|
||||
{
|
||||
// An input block should only have one scrolled APZC.
|
||||
MOZ_ASSERT(!mScrolledApzc || mScrolledApzc == aApzc);
|
||||
MOZ_ASSERT(!mScrolledApzc || (gfxPrefs::APZAllowImmediateHandoff() ? IsDownchainOf(mScrolledApzc, aApzc) : mScrolledApzc == aApzc));
|
||||
|
||||
mScrolledApzc = aApzc;
|
||||
}
|
||||
|
@ -123,6 +123,14 @@ InputBlockState::GetScrolledApzc() const
|
|||
return mScrolledApzc;
|
||||
}
|
||||
|
||||
bool
|
||||
InputBlockState::IsDownchainOfScrolledApzc(AsyncPanZoomController* aApzc) const
|
||||
{
|
||||
MOZ_ASSERT(aApzc && mScrolledApzc);
|
||||
|
||||
return IsDownchainOf(mScrolledApzc, aApzc);
|
||||
}
|
||||
|
||||
CancelableBlockState::CancelableBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
bool aTargetConfirmed)
|
||||
: InputBlockState(aTargetApzc, aTargetConfirmed)
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
|
||||
void SetScrolledApzc(AsyncPanZoomController* aApzc);
|
||||
AsyncPanZoomController* GetScrolledApzc() const;
|
||||
bool IsDownchainOfScrolledApzc(AsyncPanZoomController* aApzc) const;
|
||||
|
||||
protected:
|
||||
virtual void UpdateTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc);
|
||||
|
@ -59,7 +60,7 @@ protected:
|
|||
private:
|
||||
// Checks whether |aA| is an ancestor of |aB| (or the same as |aB|) in
|
||||
// |mOverscrollHandoffChain|.
|
||||
bool IsAncestorOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB);
|
||||
bool IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const;
|
||||
|
||||
private:
|
||||
RefPtr<AsyncPanZoomController> mTargetApzc;
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
*/
|
||||
|
||||
#include "APZTestCommon.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
class APZCTreeManagerTester : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
gfxPrefs::GetSingleton();
|
||||
gfxPlatform::GetPlatform();
|
||||
APZThreadUtils::SetThreadAssertionsEnabled(false);
|
||||
APZThreadUtils::SetControllerThread(MessageLoop::current());
|
||||
|
||||
|
@ -57,7 +59,8 @@ protected:
|
|||
protected:
|
||||
static void SetScrollableFrameMetrics(Layer* aLayer, FrameMetrics::ViewID aScrollId,
|
||||
CSSRect aScrollableRect = CSSRect(-1, -1, -1, -1)) {
|
||||
FrameMetrics metrics;
|
||||
ScrollMetadata metadata;
|
||||
FrameMetrics& metrics = metadata.GetMetrics();
|
||||
metrics.SetScrollId(aScrollId);
|
||||
// By convention in this test file, START_SCROLL_ID is the root, so mark it as such.
|
||||
if (aScrollId == FrameMetrics::START_SCROLL_ID) {
|
||||
|
@ -70,7 +73,7 @@ protected:
|
|||
metrics.SetScrollOffset(CSSPoint(0, 0));
|
||||
metrics.SetPageScrollAmount(LayoutDeviceIntSize(50, 100));
|
||||
metrics.SetAllowVerticalScrollWithWheel(true);
|
||||
aLayer->SetFrameMetrics(metrics);
|
||||
aLayer->SetScrollMetadata(metadata);
|
||||
aLayer->SetClipRect(Some(ViewAs<ParentLayerPixel>(layerBound)));
|
||||
if (!aScrollableRect.IsEqualEdges(CSSRect(-1, -1, -1, -1))) {
|
||||
// The purpose of this is to roughly mimic what layout would do in the
|
||||
|
@ -84,13 +87,13 @@ protected:
|
|||
}
|
||||
|
||||
void SetScrollHandoff(Layer* aChild, Layer* aParent) {
|
||||
FrameMetrics metrics = aChild->GetFrameMetrics(0);
|
||||
metrics.SetScrollParentId(aParent->GetFrameMetrics(0).GetScrollId());
|
||||
aChild->SetFrameMetrics(metrics);
|
||||
ScrollMetadata metadata = aChild->GetScrollMetadata(0);
|
||||
metadata.GetMetrics().SetScrollParentId(aParent->GetFrameMetrics(0).GetScrollId());
|
||||
aChild->SetScrollMetadata(metadata);
|
||||
}
|
||||
|
||||
static TestAsyncPanZoomController* ApzcOf(Layer* aLayer) {
|
||||
EXPECT_EQ(1u, aLayer->GetFrameMetricsCount());
|
||||
EXPECT_EQ(1u, aLayer->GetScrollMetadataCount());
|
||||
return (TestAsyncPanZoomController*)aLayer->GetAsyncPanZoomController(0);
|
||||
}
|
||||
|
||||
|
@ -151,9 +154,9 @@ protected:
|
|||
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1);
|
||||
|
||||
// Make layers[1] the root content
|
||||
FrameMetrics childMetrics = layers[1]->GetFrameMetrics(0);
|
||||
childMetrics.SetIsRootContent(true);
|
||||
layers[1]->SetFrameMetrics(childMetrics);
|
||||
ScrollMetadata childMetadata = layers[1]->GetScrollMetadata(0);
|
||||
childMetadata.GetMetrics().SetIsRootContent(true);
|
||||
layers[1]->SetScrollMetadata(childMetadata);
|
||||
|
||||
// Both layers are fully dispatch-to-content
|
||||
EventRegions regions;
|
||||
|
|
|
@ -78,7 +78,8 @@ TEST_F(APZCBasicTester, ComplexTransform) {
|
|||
RefPtr<LayerManager> lm;
|
||||
RefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
|
||||
|
||||
FrameMetrics metrics;
|
||||
ScrollMetadata metadata;
|
||||
FrameMetrics& metrics = metadata.GetMetrics();
|
||||
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 24, 24));
|
||||
metrics.SetDisplayPort(CSSRect(-1, -1, 6, 6));
|
||||
metrics.SetScrollOffset(CSSPoint(10, 10));
|
||||
|
@ -89,11 +90,12 @@ TEST_F(APZCBasicTester, ComplexTransform) {
|
|||
metrics.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale(3));
|
||||
metrics.SetScrollId(FrameMetrics::START_SCROLL_ID);
|
||||
|
||||
FrameMetrics childMetrics = metrics;
|
||||
ScrollMetadata childMetadata = metadata;
|
||||
FrameMetrics& childMetrics = childMetadata.GetMetrics();
|
||||
childMetrics.SetScrollId(FrameMetrics::START_SCROLL_ID + 1);
|
||||
|
||||
layers[0]->SetFrameMetrics(metrics);
|
||||
layers[1]->SetFrameMetrics(childMetrics);
|
||||
layers[0]->SetScrollMetadata(metadata);
|
||||
layers[1]->SetScrollMetadata(childMetadata);
|
||||
|
||||
ParentLayerPoint pointOut;
|
||||
AsyncTransform viewTransformOut;
|
||||
|
@ -103,13 +105,13 @@ TEST_F(APZCBasicTester, ComplexTransform) {
|
|||
|
||||
// initial transform
|
||||
apzc->SetFrameMetrics(metrics);
|
||||
apzc->NotifyLayersUpdated(metrics, true, true);
|
||||
apzc->NotifyLayersUpdated(metadata, true, true);
|
||||
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut);
|
||||
EXPECT_EQ(ParentLayerPoint(60, 60), pointOut);
|
||||
|
||||
childApzc->SetFrameMetrics(childMetrics);
|
||||
childApzc->NotifyLayersUpdated(childMetrics, true, true);
|
||||
childApzc->NotifyLayersUpdated(childMetadata, true, true);
|
||||
childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
||||
EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut);
|
||||
EXPECT_EQ(ParentLayerPoint(60, 60), pointOut);
|
||||
|
|
|
@ -331,46 +331,6 @@ APZCCallbackHelper::InitializeRootDisplayport(nsIPresShell* aPresShell)
|
|||
}
|
||||
}
|
||||
|
||||
class FlingSnapEvent : public nsRunnable
|
||||
{
|
||||
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
|
||||
|
||||
public:
|
||||
FlingSnapEvent(const ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
: mScrollId(aScrollId)
|
||||
, mDestination(aDestination)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId);
|
||||
if (sf) {
|
||||
sf->FlingSnap(mDestination);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
ViewID mScrollId;
|
||||
mozilla::CSSPoint mDestination;
|
||||
};
|
||||
|
||||
void
|
||||
APZCCallbackHelper::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r1 = new FlingSnapEvent(aScrollId, aDestination);
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(r1);
|
||||
} else {
|
||||
r1->Run();
|
||||
}
|
||||
}
|
||||
|
||||
class AcknowledgeScrollUpdateEvent : public nsRunnable
|
||||
{
|
||||
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
|
||||
|
|
|
@ -66,14 +66,6 @@ public:
|
|||
given presShell. */
|
||||
static void InitializeRootDisplayport(nsIPresShell* aPresShell);
|
||||
|
||||
/* Tell layout to perform scroll snapping for the scrollable frame with the
|
||||
* given scroll id. aDestination specifies the expected landing position of
|
||||
* a current fling or scrolling animation that should be used to select
|
||||
* the scroll snap point.
|
||||
*/
|
||||
static void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination);
|
||||
|
||||
/* Tell layout that we received the scroll offset update for the given view ID, so
|
||||
that it accepts future scroll offset updates from APZ. */
|
||||
static void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
|
|
|
@ -68,13 +68,6 @@ ChromeProcessController::PostDelayedTask(Task* aTask, int aDelayMs)
|
|||
MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
APZCCallbackHelper::RequestFlingSnap(aScrollId, aDestination);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
|
|
|
@ -40,8 +40,6 @@ public:
|
|||
// GeckoContentController interface
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
|
||||
virtual void PostDelayedTask(Task* aTask, int aDelayMs) override;
|
||||
virtual void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination) override;
|
||||
virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) override;
|
||||
|
||||
|
|
|
@ -330,7 +330,7 @@ IntervalOverlap(gfxFloat aTranslation, gfxFloat aMin, gfxFloat aMax)
|
|||
static LayerMetricsWrapper
|
||||
FindMetricsWithScrollId(Layer* aLayer, FrameMetrics::ViewID aScrollId)
|
||||
{
|
||||
for (uint64_t i = 0; i < aLayer->GetFrameMetricsCount(); ++i) {
|
||||
for (uint64_t i = 0; i < aLayer->GetScrollMetadataCount(); ++i) {
|
||||
if (aLayer->GetFrameMetrics(i).GetScrollId() == aScrollId) {
|
||||
return LayerMetricsWrapper(aLayer, i);
|
||||
}
|
||||
|
@ -687,7 +687,7 @@ AsyncCompositionManager::RecordShadowTransforms(Layer* aLayer)
|
|||
RecordShadowTransforms(child);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
|
||||
for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
|
||||
AsyncPanZoomController* apzc = aLayer->GetAsyncPanZoomController(i);
|
||||
if (!apzc) {
|
||||
continue;
|
||||
|
@ -837,7 +837,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
// of all scroll frames inside the current one.
|
||||
nsTArray<Layer*> ancestorMaskLayers;
|
||||
|
||||
for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
|
||||
for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
|
||||
AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(i);
|
||||
if (!controller) {
|
||||
continue;
|
||||
|
@ -858,7 +858,8 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
controller->MarkAsyncTransformAppliedToContent();
|
||||
}
|
||||
|
||||
const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
|
||||
const ScrollMetadata& scrollMetadata = aLayer->GetScrollMetadata(i);
|
||||
const FrameMetrics& metrics = scrollMetadata.GetMetrics();
|
||||
|
||||
#if defined(MOZ_ANDROID_APZ)
|
||||
// If we find a metrics which is the root content doc, use that. If not, use
|
||||
|
@ -870,7 +871,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
if (!(*aOutFoundRoot)) {
|
||||
*aOutFoundRoot = metrics.IsRootContent() || /* RCD */
|
||||
(aLayer->GetParent() == nullptr && /* rootmost metrics */
|
||||
i + 1 >= aLayer->GetFrameMetricsCount());
|
||||
i + 1 >= aLayer->GetScrollMetadataCount());
|
||||
if (*aOutFoundRoot) {
|
||||
mRootScrollableId = metrics.GetScrollId();
|
||||
CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor();
|
||||
|
@ -939,8 +940,8 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
// Combine the local clip with the ancestor scrollframe clip. This is not
|
||||
// included in the async transform above, since the ancestor clip should not
|
||||
// move with this APZC.
|
||||
if (metrics.HasClipRect()) {
|
||||
ParentLayerIntRect clip = metrics.ClipRect();
|
||||
if (scrollMetadata.HasClipRect()) {
|
||||
ParentLayerIntRect clip = scrollMetadata.ClipRect();
|
||||
if (aLayer->GetParent() && aLayer->GetParent()->GetTransformIsPerspective()) {
|
||||
// If our parent layer has a perspective transform, we want to apply
|
||||
// our scroll clip to it instead of to this layer (see bug 1168263).
|
||||
|
@ -962,8 +963,8 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
|
|||
}
|
||||
|
||||
// Append the ancestor mask layer for this scroll frame to ancestorMaskLayers.
|
||||
if (metrics.GetMaskLayerIndex()) {
|
||||
size_t maskLayerIndex = metrics.GetMaskLayerIndex().value();
|
||||
if (scrollMetadata.GetMaskLayerIndex()) {
|
||||
size_t maskLayerIndex = scrollMetadata.GetMaskLayerIndex().value();
|
||||
Layer* ancestorMaskLayer = aLayer->GetAncestorMaskLayerAt(maskLayerIndex);
|
||||
ancestorMaskLayers.AppendElement(ancestorMaskLayer);
|
||||
}
|
||||
|
|
|
@ -360,7 +360,8 @@ ContainerRenderVR(ContainerT* aContainer,
|
|||
static bool
|
||||
NeedToDrawCheckerboardingForLayer(Layer* aLayer, Color* aOutCheckerboardingColor)
|
||||
{
|
||||
return (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
|
||||
return (aLayer->Manager()->AsyncPanZoomEnabled() &&
|
||||
aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
|
||||
aLayer->IsOpaqueForVisibility() &&
|
||||
LayerHasCheckerboardingAPZC(aLayer, aOutCheckerboardingColor);
|
||||
}
|
||||
|
@ -478,7 +479,7 @@ RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager,
|
|||
{
|
||||
Compositor* compositor = aManager->GetCompositor();
|
||||
|
||||
if (aLayer->GetFrameMetricsCount() < 1) {
|
||||
if (aLayer->GetScrollMetadataCount() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -654,7 +655,7 @@ RenderLayers(ContainerT* aContainer,
|
|||
// frames higher up, so loop from the top down, and accumulate an async
|
||||
// transform as we go along.
|
||||
Matrix4x4 asyncTransform;
|
||||
for (uint32_t i = layer->GetFrameMetricsCount(); i > 0; --i) {
|
||||
for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; --i) {
|
||||
if (layer->GetFrameMetrics(i - 1).IsScrollable()) {
|
||||
// Since the composition bounds are in the parent layer's coordinates,
|
||||
// use the parent's effective transform rather than the layer's own.
|
||||
|
|
|
@ -94,14 +94,6 @@ APZChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||
return mBrowser->UpdateFrame(aFrameMetrics);
|
||||
}
|
||||
|
||||
bool
|
||||
APZChild::RecvRequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
APZCCallbackHelper::RequestFlingSnap(aScrollId, aDestination);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
APZChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
|
|
|
@ -28,9 +28,6 @@ public:
|
|||
|
||||
virtual bool RecvUpdateFrame(const FrameMetrics& frame) override;
|
||||
|
||||
virtual bool RecvRequestFlingSnap(const ViewID& aScrollID,
|
||||
const CSSPoint& aDestination) override;
|
||||
|
||||
virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) override;
|
||||
|
||||
|
|
|
@ -367,7 +367,7 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
|
|||
layer->SetMaskLayer(nullptr);
|
||||
}
|
||||
layer->SetAnimations(common.animations());
|
||||
layer->SetFrameMetrics(common.metrics());
|
||||
layer->SetScrollMetadata(common.scrollMetadata());
|
||||
layer->SetDisplayListLog(common.displayListLog().get());
|
||||
|
||||
// The updated invalid region is added to the existing one, since we can
|
||||
|
@ -792,7 +792,7 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
|
|||
static AsyncPanZoomController*
|
||||
GetAPZCForViewID(Layer* aLayer, FrameMetrics::ViewID aScrollID)
|
||||
{
|
||||
for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
|
||||
for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
|
||||
if (aLayer->GetFrameMetrics(i).GetScrollId() == aScrollID) {
|
||||
return aLayer->GetAsyncPanZoomController(i);
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
|
|||
using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h";
|
||||
using mozilla::layers::EventRegionsOverride from "mozilla/layers/LayersTypes.h";
|
||||
using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
|
||||
using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
|
||||
using struct mozilla::layers::ScrollMetadata from "FrameMetrics.h";
|
||||
using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
|
||||
using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
|
||||
using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
|
||||
|
@ -237,7 +237,7 @@ struct CommonLayerAttributes {
|
|||
// Animated colors will only honored for ColorLayers.
|
||||
Animation[] animations;
|
||||
nsIntRegion invalidRegion;
|
||||
FrameMetrics[] metrics;
|
||||
ScrollMetadata[] scrollMetadata;
|
||||
nsCString displayListLog;
|
||||
};
|
||||
|
||||
|
|
|
@ -89,7 +89,6 @@ child:
|
|||
// The following methods correspond to functions on the GeckoContentController
|
||||
// interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
|
||||
// in that file for these functions.
|
||||
async RequestFlingSnap(ViewID aScrollID, CSSPoint aDestination);
|
||||
async AcknowledgeScrollUpdate(ViewID aScrollId, uint32_t aScrollGeneration);
|
||||
async HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
|
||||
async HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid, bool aCallTakeFocusForClickFromTap);
|
||||
|
|
|
@ -51,24 +51,6 @@ RemoteContentController::RequestContentRepaint(const FrameMetrics& aFrameMetrics
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
RemoteContentController::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
if (MessageLoop::current() != mUILoop) {
|
||||
// We have to send this message from the "UI thread" (main
|
||||
// thread).
|
||||
mUILoop->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &RemoteContentController::RequestFlingSnap,
|
||||
aScrollId, aDestination));
|
||||
return;
|
||||
}
|
||||
if (CanSend()) {
|
||||
Unused << SendRequestFlingSnap(aScrollId, aDestination);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RemoteContentController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
|
|
|
@ -42,9 +42,6 @@ public:
|
|||
// Needs to be called on the main thread.
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
|
||||
|
||||
virtual void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination) override;
|
||||
|
||||
virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) override;
|
||||
|
||||
|
|
|
@ -844,7 +844,7 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
|
|||
common.maskLayerParent() = nullptr;
|
||||
common.animations() = mutant->GetAnimations();
|
||||
common.invalidRegion() = mutant->GetInvalidRegion();
|
||||
common.metrics() = mutant->GetAllFrameMetrics();
|
||||
common.scrollMetadata() = mutant->GetAllScrollMetadata();
|
||||
for (size_t i = 0; i < mutant->GetAncestorMaskLayerCount(); i++) {
|
||||
auto layer = Shadow(mutant->GetAncestorMaskLayerAt(i)->AsShadowableLayer());
|
||||
common.ancestorMaskLayersChild().AppendElement(layer);
|
||||
|
|
|
@ -144,7 +144,7 @@ nsFontCache::GetMetricsFor(const nsFont& aFont,
|
|||
mFontMetrics.AppendElement(fm);
|
||||
}
|
||||
fm->GetThebesFontGroup()->UpdateUserFonts();
|
||||
return do_AddRef(Move(fm));
|
||||
return do_AddRef(fm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -352,7 +352,15 @@ TEST(Layers, RepositionChild) {
|
|||
ASSERT_EQ(nullptr, layers[1]->GetNextSibling());
|
||||
}
|
||||
|
||||
TEST(LayerMetricsWrapper, SimpleTree) {
|
||||
class LayerMetricsWrapperTester : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
// This ensures ScrollMetadata::sNullMetadata is initialized.
|
||||
gfxPlatform::GetPlatform();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(LayerMetricsWrapperTester, SimpleTree) {
|
||||
nsTArray<RefPtr<Layer> > layers;
|
||||
RefPtr<LayerManager> lm;
|
||||
RefPtr<Layer> root = CreateLayerTree("c(c(c(tt)c(t)))", nullptr, nullptr, lm, layers);
|
||||
|
@ -389,43 +397,43 @@ TEST(LayerMetricsWrapper, SimpleTree) {
|
|||
ASSERT_TRUE(rootWrapper == wrapper.GetParent());
|
||||
}
|
||||
|
||||
static FrameMetrics
|
||||
MakeMetrics(FrameMetrics::ViewID aId) {
|
||||
FrameMetrics metrics;
|
||||
metrics.SetScrollId(aId);
|
||||
return metrics;
|
||||
static ScrollMetadata
|
||||
MakeMetadata(FrameMetrics::ViewID aId) {
|
||||
ScrollMetadata metadata;
|
||||
metadata.GetMetrics().SetScrollId(aId);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
TEST(LayerMetricsWrapper, MultiFramemetricsTree) {
|
||||
TEST_F(LayerMetricsWrapperTester, MultiFramemetricsTree) {
|
||||
nsTArray<RefPtr<Layer> > layers;
|
||||
RefPtr<LayerManager> lm;
|
||||
RefPtr<Layer> root = CreateLayerTree("c(c(c(tt)c(t)))", nullptr, nullptr, lm, layers);
|
||||
|
||||
nsTArray<FrameMetrics> metrics;
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 0)); // topmost of root layer
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::NULL_SCROLL_ID));
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 1));
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 2));
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::NULL_SCROLL_ID));
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::NULL_SCROLL_ID)); // bottom of root layer
|
||||
root->SetFrameMetrics(metrics);
|
||||
nsTArray<ScrollMetadata> metadata;
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 0)); // topmost of root layer
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID));
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 1));
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 2));
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID));
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID)); // bottom of root layer
|
||||
root->SetScrollMetadata(metadata);
|
||||
|
||||
metrics.Clear();
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 3));
|
||||
layers[1]->SetFrameMetrics(metrics);
|
||||
metadata.Clear();
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 3));
|
||||
layers[1]->SetScrollMetadata(metadata);
|
||||
|
||||
metrics.Clear();
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::NULL_SCROLL_ID));
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 4));
|
||||
layers[2]->SetFrameMetrics(metrics);
|
||||
metadata.Clear();
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID));
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 4));
|
||||
layers[2]->SetScrollMetadata(metadata);
|
||||
|
||||
metrics.Clear();
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 5));
|
||||
layers[4]->SetFrameMetrics(metrics);
|
||||
metadata.Clear();
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 5));
|
||||
layers[4]->SetScrollMetadata(metadata);
|
||||
|
||||
metrics.Clear();
|
||||
metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 6));
|
||||
layers[5]->SetFrameMetrics(metrics);
|
||||
metadata.Clear();
|
||||
metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 6));
|
||||
layers[5]->SetScrollMetadata(metadata);
|
||||
|
||||
LayerMetricsWrapper wrapper(root, LayerMetricsWrapper::StartAt::TOP);
|
||||
nsTArray<Layer*> expectedLayers;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/SharedBufferManagerChild.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
|
@ -67,6 +68,7 @@
|
|||
#include "nsILocaleService.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIScreenManager.h"
|
||||
#include "FrameMetrics.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
|
@ -757,6 +759,9 @@ gfxPlatform::Init()
|
|||
SkGraphics::SetFontCacheLimit(skiaCacheSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
ScrollMetadata::sNullMetadata = new ScrollMetadata();
|
||||
ClearOnShutdown(&ScrollMetadata::sNullMetadata);
|
||||
}
|
||||
|
||||
static bool sLayersIPCIsUp = false;
|
||||
|
|
|
@ -398,6 +398,7 @@ private:
|
|||
DECL_GFX_PREF(Live, "layout.css.scroll-behavior.spring-constant", ScrollBehaviorSpringConstant, float, 250.0f);
|
||||
DECL_GFX_PREF(Live, "layout.css.scroll-snap.prediction-max-velocity", ScrollSnapPredictionMaxVelocity, int32_t, 2000);
|
||||
DECL_GFX_PREF(Live, "layout.css.scroll-snap.prediction-sensitivity", ScrollSnapPredictionSensitivity, float, 0.750f);
|
||||
DECL_GFX_PREF(Live, "layout.css.scroll-snap.proximity-threshold", ScrollSnapProximityThreshold, int32_t, 200);
|
||||
DECL_GFX_PREF(Once, "layout.css.touch_action.enabled", TouchActionEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "layout.display-list.dump", LayoutDumpDisplayList, bool, false);
|
||||
DECL_GFX_PREF(Live, "layout.event-regions.enabled", LayoutEventRegionsEnabledDoNotUseDirectly, bool, false);
|
||||
|
|
|
@ -203,12 +203,6 @@ void MessageLoop::Run() {
|
|||
RunHandler();
|
||||
}
|
||||
|
||||
void MessageLoop::RunAllPending() {
|
||||
AutoRunState save_state(this);
|
||||
state_->quit_received = true; // Means run until we would otherwise block.
|
||||
RunHandler();
|
||||
}
|
||||
|
||||
// Runs the loop in two different SEH modes:
|
||||
// enable_SEH_restoration_ = false : any unhandled exception goes to the last
|
||||
// one that calls SetUnhandledExceptionFilter().
|
||||
|
@ -266,22 +260,12 @@ void MessageLoop::Quit() {
|
|||
|
||||
void MessageLoop::PostTask(
|
||||
const tracked_objects::Location& from_here, Task* task) {
|
||||
PostTask_Helper(from_here, task, 0, true);
|
||||
PostTask_Helper(from_here, task, 0);
|
||||
}
|
||||
|
||||
void MessageLoop::PostDelayedTask(
|
||||
const tracked_objects::Location& from_here, Task* task, int delay_ms) {
|
||||
PostTask_Helper(from_here, task, delay_ms, true);
|
||||
}
|
||||
|
||||
void MessageLoop::PostNonNestableTask(
|
||||
const tracked_objects::Location& from_here, Task* task) {
|
||||
PostTask_Helper(from_here, task, 0, false);
|
||||
}
|
||||
|
||||
void MessageLoop::PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here, Task* task, int delay_ms) {
|
||||
PostTask_Helper(from_here, task, delay_ms, false);
|
||||
PostTask_Helper(from_here, task, delay_ms);
|
||||
}
|
||||
|
||||
void MessageLoop::PostIdleTask(
|
||||
|
@ -300,8 +284,7 @@ void MessageLoop::PostIdleTask(
|
|||
|
||||
// Possibly called on a background thread!
|
||||
void MessageLoop::PostTask_Helper(
|
||||
const tracked_objects::Location& from_here, Task* task, int delay_ms,
|
||||
bool nestable) {
|
||||
const tracked_objects::Location& from_here, Task* task, int delay_ms) {
|
||||
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
task = mozilla::tasktracer::CreateTracedTask(task);
|
||||
|
@ -310,7 +293,7 @@ void MessageLoop::PostTask_Helper(
|
|||
|
||||
task->SetBirthPlace(from_here);
|
||||
|
||||
PendingTask pending_task(task, nestable);
|
||||
PendingTask pending_task(task, true);
|
||||
|
||||
if (delay_ms > 0) {
|
||||
pending_task.delayed_run_time =
|
||||
|
|
|
@ -117,52 +117,13 @@ public:
|
|||
void PostDelayedTask(
|
||||
const tracked_objects::Location& from_here, Task* task, int delay_ms);
|
||||
|
||||
void PostNonNestableTask(
|
||||
const tracked_objects::Location& from_here, Task* task);
|
||||
|
||||
void PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here, Task* task, int delay_ms);
|
||||
|
||||
// PostIdleTask is not thread safe and should be called on this thread
|
||||
void PostIdleTask(
|
||||
const tracked_objects::Location& from_here, Task* task);
|
||||
|
||||
// A variant on PostTask that deletes the given object. This is useful
|
||||
// if the object needs to live until the next run of the MessageLoop (for
|
||||
// example, deleting a RenderProcessHost from within an IPC callback is not
|
||||
// good).
|
||||
//
|
||||
// NOTE: This method may be called on any thread. The object will be deleted
|
||||
// on the thread that executes MessageLoop::Run(). If this is not the same
|
||||
// as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit
|
||||
// from RefCountedThreadSafe<T>!
|
||||
template <class T>
|
||||
void DeleteSoon(const tracked_objects::Location& from_here, T* object) {
|
||||
PostNonNestableTask(from_here, new DeleteTask<T>(object));
|
||||
}
|
||||
|
||||
// A variant on PostTask that releases the given reference counted object
|
||||
// (by calling its Release method). This is useful if the object needs to
|
||||
// live until the next run of the MessageLoop, or if the object needs to be
|
||||
// released on a particular thread.
|
||||
//
|
||||
// NOTE: This method may be called on any thread. The object will be
|
||||
// released (and thus possibly deleted) on the thread that executes
|
||||
// MessageLoop::Run(). If this is not the same as the thread that calls
|
||||
// PostDelayedTask(FROM_HERE, ), then T MUST inherit from
|
||||
// RefCountedThreadSafe<T>!
|
||||
template <class T>
|
||||
void ReleaseSoon(const tracked_objects::Location& from_here, T* object) {
|
||||
PostNonNestableTask(from_here, new ReleaseTask<T>(object));
|
||||
}
|
||||
|
||||
// Run the message loop.
|
||||
void Run();
|
||||
|
||||
// Process all pending tasks, windows messages, etc., but don't wait/sleep.
|
||||
// Return as soon as all items that can be run are taken care of.
|
||||
void RunAllPending();
|
||||
|
||||
// Signals the Run method to return after it is done processing all pending
|
||||
// messages. This method may only be called on the same thread that called
|
||||
// Run, and Run must still be on the call stack.
|
||||
|
@ -395,7 +356,7 @@ public:
|
|||
|
||||
// Post a task to our incomming queue.
|
||||
void PostTask_Helper(const tracked_objects::Location& from_here, Task* task,
|
||||
int delay_ms, bool nestable);
|
||||
int delay_ms);
|
||||
|
||||
// base::MessagePump::Delegate methods:
|
||||
virtual bool DoWork() override;
|
||||
|
|
|
@ -214,24 +214,6 @@ class DeleteTask : public CancelableTask {
|
|||
"external factors.") obj_;
|
||||
};
|
||||
|
||||
// Task to Release() an object
|
||||
template<class T>
|
||||
class ReleaseTask : public CancelableTask {
|
||||
public:
|
||||
explicit ReleaseTask(T* obj) : obj_(obj) {
|
||||
}
|
||||
virtual void Run() {
|
||||
if (obj_)
|
||||
obj_->Release();
|
||||
}
|
||||
virtual void Cancel() {
|
||||
obj_ = NULL;
|
||||
}
|
||||
private:
|
||||
T* MOZ_UNSAFE_REF("The validity of this pointer must be enforced by "
|
||||
"external factors.") obj_;
|
||||
};
|
||||
|
||||
// RunnableMethodTraits --------------------------------------------------------
|
||||
//
|
||||
// This traits-class is used by RunnableMethod to manage the lifetime of the
|
||||
|
|
|
@ -118,6 +118,8 @@ static MessageChannel* gParentProcessBlocker;
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
static const int kMinTelemetryMessageSize = 8192;
|
||||
|
||||
const int32_t MessageChannel::kNoTimeout = INT32_MIN;
|
||||
|
||||
// static
|
||||
|
@ -749,6 +751,10 @@ MessageChannel::Echo(Message* aMsg)
|
|||
bool
|
||||
MessageChannel::Send(Message* aMsg)
|
||||
{
|
||||
if (aMsg->size() >= kMinTelemetryMessageSize) {
|
||||
Telemetry::Accumulate(Telemetry::IPC_MESSAGE_SIZE, nsCString(aMsg->name()), aMsg->size());
|
||||
}
|
||||
|
||||
CxxStackFrame frame(*this, OUT_MESSAGE, aMsg);
|
||||
|
||||
nsAutoPtr<Message> msg(aMsg);
|
||||
|
@ -1045,6 +1051,10 @@ MessageChannel::ProcessPendingRequests(AutoEnterTransaction& aTransaction)
|
|||
bool
|
||||
MessageChannel::Send(Message* aMsg, Message* aReply)
|
||||
{
|
||||
if (aMsg->size() >= kMinTelemetryMessageSize) {
|
||||
Telemetry::Accumulate(Telemetry::IPC_MESSAGE_SIZE, nsCString(aMsg->name()), aMsg->size());
|
||||
}
|
||||
|
||||
nsAutoPtr<Message> msg(aMsg);
|
||||
|
||||
// Sanity checks.
|
||||
|
|
|
@ -315,6 +315,24 @@ void AnnotateSystemError()
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid,
|
||||
const char* aContextDescription,
|
||||
const char* aMessageDescription,
|
||||
MessageDirection aDirection)
|
||||
{
|
||||
nsPrintfCString logMessage("[time: %" PRId64 "][%d%s%d] [%s] %s %s\n",
|
||||
PR_Now(), base::GetCurrentProcId(),
|
||||
aDirection == MessageDirection::eReceiving ? "<-" : "->",
|
||||
aOtherPid, aTopLevelProtocol,
|
||||
aContextDescription,
|
||||
aMessageDescription);
|
||||
#ifdef ANDROID
|
||||
__android_log_write(ANDROID_LOG_INFO, "GeckoIPC", logMessage.get());
|
||||
#endif
|
||||
fputs(logMessage.get(), stderr);
|
||||
}
|
||||
|
||||
void
|
||||
ProtocolErrorBreakpoint(const char* aMsg)
|
||||
{
|
||||
|
|
|
@ -296,6 +296,17 @@ LoggingEnabledFor(const char *aTopLevelProtocol)
|
|||
#endif
|
||||
}
|
||||
|
||||
enum class MessageDirection {
|
||||
eSending,
|
||||
eReceiving,
|
||||
};
|
||||
|
||||
MOZ_NEVER_INLINE void
|
||||
LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid,
|
||||
const char* aContextDescription,
|
||||
const char* aMessageDescription,
|
||||
MessageDirection aDirection);
|
||||
|
||||
MOZ_NEVER_INLINE void
|
||||
ProtocolErrorBreakpoint(const char* aMsg);
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ Types = (
|
|||
|
||||
HeaderIncludes = (
|
||||
'mozilla/Attributes.h',
|
||||
'prtime.h',
|
||||
'IPCMessageStart.h',
|
||||
'ipc/IPCMessageUtils.h',
|
||||
'mozilla/RefPtr.h',
|
||||
|
|
|
@ -924,12 +924,6 @@ class MessageDecl(ipdl.ast.MessageDecl):
|
|||
def pqMsgClass(self):
|
||||
return '%s::%s'% (self.namespace, self.msgClass())
|
||||
|
||||
def msgCast(self, msgexpr):
|
||||
return ExprCast(msgexpr, self.msgCxxType(const=1, ptr=1), static=1)
|
||||
|
||||
def msgCxxType(self, const=0, ref=0, ptr=0):
|
||||
return Type(self.pqMsgClass(), const=const, ref=ref, ptr=ptr)
|
||||
|
||||
def msgId(self): return self.msgClass()+ '__ID'
|
||||
def pqMsgId(self):
|
||||
return '%s::%s'% (self.namespace, self.msgId())
|
||||
|
@ -940,10 +934,6 @@ class MessageDecl(ipdl.ast.MessageDecl):
|
|||
def pqReplyClass(self):
|
||||
return '%s::%s'% (self.namespace, self.replyClass())
|
||||
|
||||
def replyCast(self, replyexpr):
|
||||
return ExprCast(replyexpr, Type(self.pqReplyClass(), const=1, ptr=1),
|
||||
static=1)
|
||||
|
||||
def replyId(self): return self.replyClass()+ '__ID'
|
||||
def pqReplyId(self):
|
||||
return '%s::%s'% (self.namespace, self.replyId())
|
||||
|
@ -1662,20 +1652,28 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
|
|||
self.funcDefns.append(tfDefn)
|
||||
|
||||
for md in p.messageDecls:
|
||||
ns.addstmts([
|
||||
_generateMessageClass(md.msgClass(), md.msgId(),
|
||||
decls = []
|
||||
|
||||
mfDecl, mfDefn = _splitFuncDeclDefn(
|
||||
_generateMessageConstructor(md.msgClass(), md.msgId(),
|
||||
md.decl.type.priority,
|
||||
md.prettyMsgName(p.name+'::'),
|
||||
md.decl.type.compress),
|
||||
Whitespace.NL ])
|
||||
md.decl.type.compress))
|
||||
decls.append(mfDecl)
|
||||
self.funcDefns.append(mfDefn)
|
||||
|
||||
if md.hasReply():
|
||||
ns.addstmts([
|
||||
_generateMessageClass(
|
||||
rfDecl, rfDefn = _splitFuncDeclDefn(
|
||||
_generateMessageConstructor(
|
||||
md.replyClass(), md.replyId(),
|
||||
md.decl.type.priority,
|
||||
md.prettyReplyName(p.name+'::'),
|
||||
md.decl.type.compress),
|
||||
Whitespace.NL ])
|
||||
md.decl.type.compress))
|
||||
decls.append(rfDecl)
|
||||
self.funcDefns.append(rfDefn)
|
||||
|
||||
decls.append(Whitespace.NL)
|
||||
ns.addstmts(decls)
|
||||
|
||||
ns.addstmts([ Whitespace.NL, Whitespace.NL ])
|
||||
|
||||
|
@ -1897,22 +1895,21 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
|
|||
|
||||
##--------------------------------------------------
|
||||
|
||||
def _generateMessageClass(clsname, msgid, priority, prettyName, compress):
|
||||
cls = Class(name=clsname, inherits=[ Inherit(Type('IPC::Message')) ])
|
||||
cls.addstmt(Label.PUBLIC)
|
||||
def _generateMessageConstructor(clsname, msgid, priority, prettyName, compress):
|
||||
routingId = ExprVar('routingId')
|
||||
|
||||
idenum = TypeEnum()
|
||||
idenum.addId('ID', msgid)
|
||||
cls.addstmt(StmtDecl(Decl(idenum, '')))
|
||||
func = FunctionDefn(FunctionDecl(
|
||||
clsname,
|
||||
params=[ Decl(Type('int32_t'), routingId.name) ],
|
||||
ret=Type('IPC::Message', ptr=1)))
|
||||
|
||||
# make the message constructor
|
||||
if compress == 'compress':
|
||||
compression = ExprVar('COMPRESSION_ENABLED')
|
||||
compression = ExprVar('IPC::Message::COMPRESSION_ENABLED')
|
||||
elif compress:
|
||||
assert compress == 'compressall'
|
||||
compression = ExprVar('COMPRESSION_ALL')
|
||||
compression = ExprVar('IPC::Message::COMPRESSION_ALL')
|
||||
else:
|
||||
compression = ExprVar('COMPRESSION_NONE')
|
||||
compression = ExprVar('IPC::Message::COMPRESSION_NONE')
|
||||
if priority == ipdl.ast.NORMAL_PRIORITY:
|
||||
priorityEnum = 'IPC::Message::PRIORITY_NORMAL'
|
||||
elif priority == ipdl.ast.HIGH_PRIORITY:
|
||||
|
@ -1920,74 +1917,16 @@ def _generateMessageClass(clsname, msgid, priority, prettyName, compress):
|
|||
else:
|
||||
assert priority == ipdl.ast.URGENT_PRIORITY
|
||||
priorityEnum = 'IPC::Message::PRIORITY_URGENT'
|
||||
routingId = ExprVar('routingId')
|
||||
ctor = ConstructorDefn(
|
||||
ConstructorDecl(clsname, params=[ Decl(Type('int32_t'), routingId.name) ]),
|
||||
memberinits=[ ExprMemberInit(ExprVar('IPC::Message'),
|
||||
[ routingId,
|
||||
ExprVar('ID'),
|
||||
|
||||
func.addstmt(
|
||||
StmtReturn(ExprNew(Type('IPC::Message'),
|
||||
args=[ routingId,
|
||||
ExprVar(msgid),
|
||||
ExprVar(priorityEnum),
|
||||
compression,
|
||||
ExprLiteral.String(prettyName) ]) ])
|
||||
cls.addstmts([ ctor, Whitespace.NL ])
|
||||
ExprLiteral.String(prettyName) ])))
|
||||
|
||||
# generate a logging function
|
||||
# 'pfx' will be something like "[FooParent] sent"
|
||||
pfxvar = ExprVar('pfx__')
|
||||
otherpid = ExprVar('otherPid__')
|
||||
receiving = ExprVar('receiving__')
|
||||
logger = MethodDefn(MethodDecl(
|
||||
'Log',
|
||||
params=([ Decl(Type('std::string', const=1, ref=1), pfxvar.name),
|
||||
Decl(Type('base::ProcessId'), otherpid.name),
|
||||
Decl(Type('bool'), receiving.name) ]),
|
||||
const=1))
|
||||
# TODO/cjones: allow selecting what information is printed to
|
||||
# the log
|
||||
msgvar = ExprVar('logmsg__')
|
||||
logger.addstmt(StmtDecl(Decl(Type('std::string'), msgvar.name)))
|
||||
|
||||
def appendToMsg(thing):
|
||||
return StmtExpr(ExprCall(ExprSelect(msgvar, '.', 'append'),
|
||||
args=[ thing ]))
|
||||
logger.addstmts([
|
||||
StmtExpr(ExprCall(
|
||||
ExprVar('StringAppendF'),
|
||||
args=[ ExprAddrOf(msgvar),
|
||||
ExprLiteral.String('[time:%" PRId64 "][%d%s%d]'),
|
||||
ExprCall(ExprVar('PR_Now')),
|
||||
ExprCall(ExprVar('base::GetCurrentProcId')),
|
||||
ExprConditional(receiving, ExprLiteral.String('<-'),
|
||||
ExprLiteral.String('->')),
|
||||
otherpid ])),
|
||||
appendToMsg(pfxvar),
|
||||
appendToMsg(ExprLiteral.String(clsname +'(')),
|
||||
Whitespace.NL
|
||||
])
|
||||
|
||||
# TODO turn this back on when string stuff is sorted
|
||||
|
||||
logger.addstmt(appendToMsg(ExprLiteral.String('[TODO])\\n')))
|
||||
|
||||
logger.addstmts([
|
||||
CppDirective('ifdef', 'ANDROID'),
|
||||
StmtExpr(ExprCall(
|
||||
ExprVar('__android_log_write'),
|
||||
args=[ ExprVar('ANDROID_LOG_INFO'),
|
||||
ExprLiteral.String('GeckoIPC'),
|
||||
ExprCall(ExprSelect(msgvar, '.', 'c_str')) ])),
|
||||
CppDirective('endif')
|
||||
])
|
||||
|
||||
# and actually print the log message
|
||||
logger.addstmt(StmtExpr(ExprCall(
|
||||
ExprVar('fputs'),
|
||||
args=[ ExprCall(ExprSelect(msgvar, '.', 'c_str')),
|
||||
ExprVar('stderr') ])))
|
||||
|
||||
cls.addstmt(logger)
|
||||
|
||||
return cls
|
||||
return func
|
||||
|
||||
##--------------------------------------------------
|
||||
|
||||
|
@ -5168,8 +5107,8 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
|||
this = None
|
||||
if md.decl.type.isDtor(): this = md.actorDecl().var()
|
||||
|
||||
stmts = ([ StmtDecl(Decl(Type(md.pqMsgClass(), ptr=1), msgvar.name),
|
||||
init=ExprNew(Type(md.pqMsgClass()),
|
||||
stmts = ([ StmtDecl(Decl(Type('IPC::Message', ptr=1), msgvar.name),
|
||||
init=ExprCall(ExprVar(md.pqMsgClass()),
|
||||
args=[ routingId ])) ]
|
||||
+ [ Whitespace.NL ]
|
||||
+ [ StmtExpr(self.write(p.ipdltype, p.var(), msgvar, this))
|
||||
|
@ -5189,12 +5128,12 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
|||
replyvar = self.replyvar
|
||||
return (
|
||||
[ StmtExpr(ExprAssn(
|
||||
replyvar, ExprNew(Type(md.pqReplyClass()), args=[ routingId ]))),
|
||||
replyvar, ExprCall(ExprVar(md.pqReplyClass()), args=[ routingId ]))),
|
||||
Whitespace.NL ]
|
||||
+ [ StmtExpr(self.write(r.ipdltype, r.var(), replyvar))
|
||||
for r in md.returns ]
|
||||
+ self.setMessageFlags(md, replyvar, reply=1)
|
||||
+ [ self.logMessage(md, md.replyCast(replyvar), 'Sending reply ') ])
|
||||
+ [ self.logMessage(md, replyvar, 'Sending reply ') ])
|
||||
|
||||
|
||||
def setMessageFlags(self, md, var, reply):
|
||||
|
@ -5229,7 +5168,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
|||
'.', 'set_name'),
|
||||
args=[ ExprLiteral.String(md.prettyMsgName(self.protocol.name
|
||||
+'::')) ])),
|
||||
self.logMessage(md, md.msgCast(msgexpr), 'Received ',
|
||||
self.logMessage(md, msgexpr, 'Received ',
|
||||
receiving=True),
|
||||
self.profilerLabel('Recv', md.decl.progname),
|
||||
Whitespace.NL
|
||||
|
@ -5267,7 +5206,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
|||
|
||||
def deserializeReply(self, md, replyexpr, side, errfn, actor=None):
|
||||
stmts = [ Whitespace.NL,
|
||||
self.logMessage(md, md.replyCast(replyexpr),
|
||||
self.logMessage(md, replyexpr,
|
||||
'Received reply ', actor, receiving=True) ]
|
||||
if 0 == len(md.returns):
|
||||
return stmts
|
||||
|
@ -5380,12 +5319,16 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
|||
def logMessage(self, md, msgptr, pfx, actor=None, receiving=False):
|
||||
actorname = _actorName(self.protocol.name, self.side)
|
||||
|
||||
topLevel = self.protocol.decl.type.toplevel().name()
|
||||
return _ifLogging(ExprLiteral.String(topLevel), [ StmtExpr(ExprCall(
|
||||
ExprSelect(msgptr, '->', 'Log'),
|
||||
args=[ ExprLiteral.String('['+ actorname +'] '+ pfx),
|
||||
return _ifLogging(ExprLiteral.String(actorname),
|
||||
[ StmtExpr(ExprCall(
|
||||
ExprVar('mozilla::ipc::LogMessageForProtocol'),
|
||||
args=[ ExprLiteral.String(actorname),
|
||||
self.protocol.callOtherPid(actor),
|
||||
ExprLiteral.TRUE if receiving else ExprLiteral.FALSE ])) ])
|
||||
ExprLiteral.String(pfx),
|
||||
ExprCall(ExprSelect(msgptr, '->', 'name')),
|
||||
ExprVar('mozilla::ipc::MessageDirection::eReceiving'
|
||||
if receiving
|
||||
else 'mozilla::ipc::MessageDirection::eSending') ])) ])
|
||||
|
||||
def profilerLabel(self, tag, msgname):
|
||||
return StmtExpr(ExprCall(ExprVar('PROFILER_LABEL'),
|
||||
|
|
|
@ -686,9 +686,9 @@ struct NewLayerEntry {
|
|||
RefPtr<Layer> mLayer;
|
||||
AnimatedGeometryRoot* mAnimatedGeometryRoot;
|
||||
const DisplayItemScrollClip* mScrollClip;
|
||||
// If non-null, this FrameMetrics is set to the be the first FrameMetrics
|
||||
// If non-null, this ScrollMetadata is set to the be the first ScrollMetadata
|
||||
// on the layer.
|
||||
UniquePtr<FrameMetrics> mBaseFrameMetrics;
|
||||
UniquePtr<ScrollMetadata> mBaseScrollMetadata;
|
||||
// The following are only used for retained layers (for occlusion
|
||||
// culling of those layers). These regions are all relative to the
|
||||
// container reference frame.
|
||||
|
@ -4160,15 +4160,15 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
|||
if (itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) {
|
||||
nsDisplayScrollInfoLayer* scrollItem = static_cast<nsDisplayScrollInfoLayer*>(item);
|
||||
newLayerEntry->mOpaqueForAnimatedGeometryRootParent = false;
|
||||
newLayerEntry->mBaseFrameMetrics =
|
||||
scrollItem->ComputeFrameMetrics(ownLayer, mParameters);
|
||||
newLayerEntry->mBaseScrollMetadata =
|
||||
scrollItem->ComputeScrollMetadata(ownLayer, mParameters);
|
||||
} else if ((itemType == nsDisplayItem::TYPE_SUBDOCUMENT ||
|
||||
itemType == nsDisplayItem::TYPE_ZOOM ||
|
||||
itemType == nsDisplayItem::TYPE_RESOLUTION) &&
|
||||
gfxPrefs::LayoutUseContainersForRootFrames())
|
||||
{
|
||||
newLayerEntry->mBaseFrameMetrics =
|
||||
static_cast<nsDisplaySubDocument*>(item)->ComputeFrameMetrics(ownLayer, mParameters);
|
||||
newLayerEntry->mBaseScrollMetadata =
|
||||
static_cast<nsDisplaySubDocument*>(item)->ComputeScrollMetadata(ownLayer, mParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4714,13 +4714,13 @@ ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
|
|||
return;
|
||||
}
|
||||
|
||||
AutoTArray<FrameMetrics,2> metricsArray;
|
||||
if (aEntry->mBaseFrameMetrics) {
|
||||
metricsArray.AppendElement(*aEntry->mBaseFrameMetrics);
|
||||
AutoTArray<ScrollMetadata,2> metricsArray;
|
||||
if (aEntry->mBaseScrollMetadata) {
|
||||
metricsArray.AppendElement(*aEntry->mBaseScrollMetadata);
|
||||
|
||||
// The base FrameMetrics was not computed by the nsIScrollableframe, so it
|
||||
// should not have a mask layer.
|
||||
MOZ_ASSERT(!aEntry->mBaseFrameMetrics->GetMaskLayerIndex());
|
||||
MOZ_ASSERT(!aEntry->mBaseScrollMetadata->GetMaskLayerIndex());
|
||||
}
|
||||
|
||||
// Any extra mask layers we need to attach to FrameMetrics.
|
||||
|
@ -4739,9 +4739,9 @@ ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
|
|||
nsIScrollableFrame* scrollFrame = scrollClip->mScrollableFrame;
|
||||
const DisplayItemClip* clip = scrollClip->mClip;
|
||||
|
||||
Maybe<FrameMetrics> metrics =
|
||||
scrollFrame->ComputeFrameMetrics(aEntry->mLayer, mContainerReferenceFrame, mParameters, clip);
|
||||
if (!metrics) {
|
||||
Maybe<ScrollMetadata> metadata =
|
||||
scrollFrame->ComputeScrollMetadata(aEntry->mLayer, mContainerReferenceFrame, mParameters, clip);
|
||||
if (!metadata) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -4757,16 +4757,16 @@ ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
|
|||
RefPtr<Layer> maskLayer =
|
||||
CreateMaskLayer(aEntry->mLayer, *clip, nextIndex, clip->GetRoundedRectCount());
|
||||
if (maskLayer) {
|
||||
metrics->SetMaskLayerIndex(nextIndex);
|
||||
metadata->SetMaskLayerIndex(nextIndex);
|
||||
maskLayers.AppendElement(maskLayer);
|
||||
}
|
||||
}
|
||||
|
||||
metricsArray.AppendElement(*metrics);
|
||||
metricsArray.AppendElement(*metadata);
|
||||
}
|
||||
|
||||
// Watch out for FrameMetrics copies in profiles
|
||||
aEntry->mLayer->SetFrameMetrics(metricsArray);
|
||||
aEntry->mLayer->SetScrollMetadata(metricsArray);
|
||||
aEntry->mLayer->SetAncestorMaskLayers(maskLayers);
|
||||
}
|
||||
|
||||
|
@ -4806,8 +4806,8 @@ InvalidateVisibleBoundsChangesForScrolledLayer(PaintedLayer* aLayer)
|
|||
static inline const Maybe<ParentLayerIntRect>&
|
||||
GetStationaryClipInContainer(Layer* aLayer)
|
||||
{
|
||||
if (size_t metricsCount = aLayer->GetFrameMetricsCount()) {
|
||||
return aLayer->GetFrameMetrics(metricsCount - 1).GetClipRect();
|
||||
if (size_t metricsCount = aLayer->GetScrollMetadataCount()) {
|
||||
return aLayer->GetScrollMetadata(metricsCount - 1).GetClipRect();
|
||||
}
|
||||
return aLayer->GetClipRect();
|
||||
}
|
||||
|
|
|
@ -248,6 +248,11 @@ struct CSSPixel {
|
|||
NSToCoordRoundWithClamp(float(aPoint.y) * float(AppUnitsPerCSSPixel())));
|
||||
}
|
||||
|
||||
static nsSize ToAppUnits(const CSSSize& aSize) {
|
||||
return nsSize(NSToCoordRoundWithClamp(aSize.width * float(AppUnitsPerCSSPixel())),
|
||||
NSToCoordRoundWithClamp(aSize.height * float(AppUnitsPerCSSPixel())));
|
||||
}
|
||||
|
||||
static nsSize ToAppUnits(const CSSIntSize& aSize) {
|
||||
return nsSize(NSToCoordRoundWithClamp(float(aSize.width) * float(AppUnitsPerCSSPixel())),
|
||||
NSToCoordRoundWithClamp(float(aSize.height) * float(AppUnitsPerCSSPixel())));
|
||||
|
|
|
@ -2366,7 +2366,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
|||
nsFrameConstructorState state(mPresShell,
|
||||
GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
|
||||
nullptr,
|
||||
nullptr, do_AddRef(Move(aFrameState)));
|
||||
nullptr, do_AddRef(aFrameState));
|
||||
// Initialize the ancestor filter with null for now; we'll push
|
||||
// aDocElement once we finish resolving style for it.
|
||||
state.mTreeMatchContext.InitAncestors(nullptr);
|
||||
|
@ -7779,7 +7779,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
|
|||
GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
|
||||
GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
|
||||
GetFloatContainingBlock(insertion.mParentFrame),
|
||||
do_AddRef(Move(aFrameState)));
|
||||
do_AddRef(aFrameState));
|
||||
state.mTreeMatchContext.InitAncestors(aContainer ?
|
||||
aContainer->AsElement() :
|
||||
nullptr);
|
||||
|
|
|
@ -1691,11 +1691,11 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
|
|||
props = Move(LayerProperties::CloneFrom(layerManager->GetRoot()));
|
||||
}
|
||||
|
||||
// Clear any FrameMetrics that may have been set on the root layer on a
|
||||
// Clear any ScrollMetadata that may have been set on the root layer on a
|
||||
// previous paint. This paint will set new metrics if necessary, and if we
|
||||
// don't clear the old one here, we may be left with extra metrics.
|
||||
if (Layer* root = layerManager->GetRoot()) {
|
||||
root->SetFrameMetrics(nsTArray<FrameMetrics>());
|
||||
root->SetScrollMetadata(nsTArray<ScrollMetadata>());
|
||||
}
|
||||
|
||||
ContainerLayerParameters containerParameters
|
||||
|
@ -1767,8 +1767,8 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
|
|||
|
||||
nsRect viewport(aBuilder->ToReferenceFrame(frame), frame->GetSize());
|
||||
|
||||
root->SetFrameMetrics(
|
||||
nsLayoutUtils::ComputeFrameMetrics(frame,
|
||||
root->SetScrollMetadata(
|
||||
nsLayoutUtils::ComputeScrollMetadata(frame,
|
||||
rootScrollFrame, content,
|
||||
aBuilder->FindReferenceFrameFor(frame),
|
||||
root, FrameMetrics::NULL_SCROLL_ID, viewport, Nothing(),
|
||||
|
@ -4580,12 +4580,12 @@ nsDisplaySubDocument::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
return layer.forget();
|
||||
}
|
||||
|
||||
UniquePtr<FrameMetrics>
|
||||
nsDisplaySubDocument::ComputeFrameMetrics(Layer* aLayer,
|
||||
UniquePtr<ScrollMetadata>
|
||||
nsDisplaySubDocument::ComputeScrollMetadata(Layer* aLayer,
|
||||
const ContainerLayerParameters& aContainerParameters)
|
||||
{
|
||||
if (!(mFlags & GENERATE_SCROLLABLE_LAYER)) {
|
||||
return UniquePtr<FrameMetrics>(nullptr);
|
||||
return UniquePtr<ScrollMetadata>(nullptr);
|
||||
}
|
||||
|
||||
nsPresContext* presContext = mFrame->PresContext();
|
||||
|
@ -4606,8 +4606,8 @@ nsDisplaySubDocument::ComputeFrameMetrics(Layer* aLayer,
|
|||
mFrame->GetPosition() +
|
||||
mFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
||||
|
||||
return MakeUnique<FrameMetrics>(
|
||||
nsLayoutUtils::ComputeFrameMetrics(
|
||||
return MakeUnique<ScrollMetadata>(
|
||||
nsLayoutUtils::ComputeScrollMetadata(
|
||||
mFrame, rootScrollFrame, rootScrollFrame->GetContent(), ReferenceFrame(),
|
||||
aLayer, mScrollParentId, viewport, Nothing(),
|
||||
isRootContentDocument, params));
|
||||
|
@ -4989,8 +4989,8 @@ nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|||
return LAYER_ACTIVE_EMPTY;
|
||||
}
|
||||
|
||||
UniquePtr<FrameMetrics>
|
||||
nsDisplayScrollInfoLayer::ComputeFrameMetrics(Layer* aLayer,
|
||||
UniquePtr<ScrollMetadata>
|
||||
nsDisplayScrollInfoLayer::ComputeScrollMetadata(Layer* aLayer,
|
||||
const ContainerLayerParameters& aContainerParameters)
|
||||
{
|
||||
ContainerLayerParameters params = aContainerParameters;
|
||||
|
@ -5003,13 +5003,13 @@ nsDisplayScrollInfoLayer::ComputeFrameMetrics(Layer* aLayer,
|
|||
mScrollFrame->GetPosition() +
|
||||
mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
||||
|
||||
FrameMetrics metrics = nsLayoutUtils::ComputeFrameMetrics(
|
||||
ScrollMetadata metadata = nsLayoutUtils::ComputeScrollMetadata(
|
||||
mScrolledFrame, mScrollFrame, mScrollFrame->GetContent(),
|
||||
ReferenceFrame(), aLayer,
|
||||
mScrollParentId, viewport, Nothing(), false, params);
|
||||
metrics.SetIsScrollInfoLayer(true);
|
||||
metadata.GetMetrics().SetIsScrollInfoLayer(true);
|
||||
|
||||
return UniquePtr<FrameMetrics>(new FrameMetrics(metrics));
|
||||
return UniquePtr<ScrollMetadata>(new ScrollMetadata(metadata));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1308,6 +1308,7 @@ public:
|
|||
typedef mozilla::DisplayItemClip DisplayItemClip;
|
||||
typedef mozilla::DisplayItemScrollClip DisplayItemScrollClip;
|
||||
typedef mozilla::layers::FrameMetrics FrameMetrics;
|
||||
typedef mozilla::layers::ScrollMetadata ScrollMetadata;
|
||||
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
|
||||
typedef mozilla::layers::Layer Layer;
|
||||
typedef mozilla::layers::LayerManager LayerManager;
|
||||
|
@ -3550,7 +3551,7 @@ public:
|
|||
|
||||
NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT)
|
||||
|
||||
mozilla::UniquePtr<FrameMetrics> ComputeFrameMetrics(Layer* aLayer,
|
||||
mozilla::UniquePtr<ScrollMetadata> ComputeScrollMetadata(Layer* aLayer,
|
||||
const ContainerLayerParameters& aContainerParameters);
|
||||
|
||||
protected:
|
||||
|
@ -3691,7 +3692,7 @@ public:
|
|||
|
||||
virtual void WriteDebugInfo(std::stringstream& aStream) override;
|
||||
|
||||
mozilla::UniquePtr<FrameMetrics> ComputeFrameMetrics(Layer* aLayer,
|
||||
mozilla::UniquePtr<ScrollMetadata> ComputeScrollMetadata(Layer* aLayer,
|
||||
const ContainerLayerParameters& aContainerParameters);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -8583,8 +8583,8 @@ nsLayoutUtils::CanScrollOriginClobberApz(nsIAtom* aScrollOrigin)
|
|||
&& aScrollOrigin != nsGkAtoms::restore;
|
||||
}
|
||||
|
||||
/* static */ FrameMetrics
|
||||
nsLayoutUtils::ComputeFrameMetrics(nsIFrame* aForFrame,
|
||||
/* static */ ScrollMetadata
|
||||
nsLayoutUtils::ComputeScrollMetadata(nsIFrame* aForFrame,
|
||||
nsIFrame* aScrollFrame,
|
||||
nsIContent* aContent,
|
||||
const nsIFrame* aReferenceFrame,
|
||||
|
@ -8599,7 +8599,8 @@ nsLayoutUtils::ComputeFrameMetrics(nsIFrame* aForFrame,
|
|||
int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
|
||||
nsIPresShell* presShell = presContext->GetPresShell();
|
||||
FrameMetrics metrics;
|
||||
ScrollMetadata metadata;
|
||||
FrameMetrics& metrics = metadata.GetMetrics();
|
||||
metrics.SetViewport(CSSRect::FromAppUnits(aViewport));
|
||||
|
||||
ViewID scrollId = FrameMetrics::NULL_SCROLL_ID;
|
||||
|
@ -8667,6 +8668,8 @@ nsLayoutUtils::ComputeFrameMetrics(nsIFrame* aForFrame,
|
|||
}
|
||||
|
||||
metrics.SetUsesContainerScrolling(scrollableFrame->UsesContainerScrolling());
|
||||
|
||||
metadata.SetSnapInfo(scrollableFrame->GetScrollSnapInfo());
|
||||
}
|
||||
|
||||
// If we have the scrollparent being the same as the scroll id, the
|
||||
|
@ -8734,7 +8737,7 @@ nsLayoutUtils::ComputeFrameMetrics(nsIFrame* aForFrame,
|
|||
ParentLayerRect rect = LayoutDeviceRect::FromAppUnits(*aClipRect, auPerDevPixel)
|
||||
* metrics.GetCumulativeResolution()
|
||||
* layerToParentLayerScale;
|
||||
metrics.SetClipRect(Some(RoundedToInt(rect)));
|
||||
metadata.SetClipRect(Some(RoundedToInt(rect)));
|
||||
}
|
||||
|
||||
// For the root scroll frame of the root content document (RCD-RSF), the above calculation
|
||||
|
@ -8798,13 +8801,13 @@ nsLayoutUtils::ComputeFrameMetrics(nsIFrame* aForFrame,
|
|||
}
|
||||
}
|
||||
|
||||
return metrics;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsLayoutUtils::ContainsMetricsWithId(const Layer* aLayer, const ViewID& aScrollId)
|
||||
{
|
||||
for (uint32_t i = aLayer->GetFrameMetricsCount(); i > 0; i--) {
|
||||
for (uint32_t i = aLayer->GetScrollMetadataCount(); i > 0; i--) {
|
||||
if (aLayer->GetFrameMetrics(i-1).GetScrollId() == aScrollId) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -143,6 +143,7 @@ class nsLayoutUtils
|
|||
|
||||
public:
|
||||
typedef mozilla::layers::FrameMetrics FrameMetrics;
|
||||
typedef mozilla::layers::ScrollMetadata ScrollMetadata;
|
||||
typedef FrameMetrics::ViewID ViewID;
|
||||
typedef mozilla::CSSPoint CSSPoint;
|
||||
typedef mozilla::CSSSize CSSSize;
|
||||
|
@ -2721,7 +2722,7 @@ public:
|
|||
*/
|
||||
static bool CanScrollOriginClobberApz(nsIAtom* aScrollOrigin);
|
||||
|
||||
static FrameMetrics ComputeFrameMetrics(nsIFrame* aForFrame,
|
||||
static ScrollMetadata ComputeScrollMetadata(nsIFrame* aForFrame,
|
||||
nsIFrame* aScrollFrame,
|
||||
nsIContent* aContent,
|
||||
const nsIFrame* aReferenceFrame,
|
||||
|
|
|
@ -89,6 +89,11 @@ nsHTMLButtonControlFrame::HandleEvent(nsPresContext* aPresContext,
|
|||
return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLButtonControlFrame::ShouldClipPaintingToBorderBox()
|
||||
{
|
||||
return IsInput() || StyleDisplay()->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
|
@ -117,7 +122,7 @@ nsHTMLButtonControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
if (!isForEventDelivery) {
|
||||
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
||||
|
||||
if (IsInput() || StyleDisplay()->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE) {
|
||||
if (ShouldClipPaintingToBorderBox()) {
|
||||
nsMargin border = StyleBorder()->GetComputedBorder();
|
||||
nsRect rect(aBuilder->ToReferenceFrame(this), GetSize());
|
||||
rect.Deflate(border);
|
||||
|
@ -214,7 +219,11 @@ nsHTMLButtonControlFrame::Reflow(nsPresContext* aPresContext,
|
|||
ReflowButtonContents(aPresContext, aDesiredSize,
|
||||
aReflowState, firstKid);
|
||||
|
||||
if (!ShouldClipPaintingToBorderBox()) {
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, firstKid);
|
||||
}
|
||||
// else, we ignore child overflow -- anything that overflows beyond our
|
||||
// own border-box will get clipped when painting.
|
||||
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize,
|
||||
|
|
|
@ -92,6 +92,12 @@ public:
|
|||
|
||||
protected:
|
||||
virtual bool IsInput() { return false; }
|
||||
|
||||
// Indicates whether we should clip our children's painting to our
|
||||
// border-box (either because of "overflow" or because of legacy reasons
|
||||
// about how <input>-flavored buttons work).
|
||||
bool ShouldClipPaintingToBorderBox();
|
||||
|
||||
// Reflows the button's sole child frame, and computes the desired size
|
||||
// of the button itself from the results.
|
||||
void ReflowButtonContents(nsPresContext* aPresContext,
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FrameMetrics.h"
|
||||
#include "ScrollSnap.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsLineLayout.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using layers::ScrollSnapInfo;
|
||||
|
||||
/**
|
||||
* Stores candidate snapping edges.
|
||||
*/
|
||||
class SnappingEdgeCallback {
|
||||
public:
|
||||
virtual void AddHorizontalEdge(nscoord aEdge) = 0;
|
||||
virtual void AddVerticalEdge(nscoord aEdge) = 0;
|
||||
virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval,
|
||||
nscoord aOffset) = 0;
|
||||
virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval,
|
||||
nscoord aOffset) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Keeps track of the current best edge to snap to. The criteria for
|
||||
* adding an edge depends on the scrolling unit.
|
||||
*/
|
||||
class CalcSnapPoints : public SnappingEdgeCallback {
|
||||
public:
|
||||
CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit,
|
||||
const nsPoint& aDestination,
|
||||
const nsPoint& aStartPos);
|
||||
virtual void AddHorizontalEdge(nscoord aEdge) override;
|
||||
virtual void AddVerticalEdge(nscoord aEdge) override;
|
||||
virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
override;
|
||||
virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
override;
|
||||
void AddEdge(nscoord aEdge,
|
||||
nscoord aDestination,
|
||||
nscoord aStartPos,
|
||||
nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge,
|
||||
bool* aEdgeFound);
|
||||
void AddEdgeInterval(nscoord aInterval,
|
||||
nscoord aMinPos,
|
||||
nscoord aMaxPos,
|
||||
nscoord aOffset,
|
||||
nscoord aDestination,
|
||||
nscoord aStartPos,
|
||||
nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge,
|
||||
bool* aEdgeFound);
|
||||
nsPoint GetBestEdge() const;
|
||||
protected:
|
||||
nsIScrollableFrame::ScrollUnit mUnit;
|
||||
nsPoint mDestination; // gives the position after scrolling but before snapping
|
||||
nsPoint mStartPos; // gives the position before scrolling
|
||||
nsIntPoint mScrollingDirection; // always -1, 0, or 1
|
||||
nsPoint mBestEdge; // keeps track of the position of the current best edge
|
||||
bool mHorizontalEdgeFound; // true if mBestEdge.x is storing a valid horizontal edge
|
||||
bool mVerticalEdgeFound; // true if mBestEdge.y is storing a valid vertical edge
|
||||
};
|
||||
|
||||
CalcSnapPoints::CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit,
|
||||
const nsPoint& aDestination,
|
||||
const nsPoint& aStartPos)
|
||||
{
|
||||
mUnit = aUnit;
|
||||
mDestination = aDestination;
|
||||
mStartPos = aStartPos;
|
||||
|
||||
nsPoint direction = aDestination - aStartPos;
|
||||
mScrollingDirection = nsIntPoint(0,0);
|
||||
if (direction.x < 0) {
|
||||
mScrollingDirection.x = -1;
|
||||
}
|
||||
if (direction.x > 0) {
|
||||
mScrollingDirection.x = 1;
|
||||
}
|
||||
if (direction.y < 0) {
|
||||
mScrollingDirection.y = -1;
|
||||
}
|
||||
if (direction.y > 0) {
|
||||
mScrollingDirection.y = 1;
|
||||
}
|
||||
mBestEdge = aDestination;
|
||||
mHorizontalEdgeFound = false;
|
||||
mVerticalEdgeFound = false;
|
||||
}
|
||||
|
||||
nsPoint
|
||||
CalcSnapPoints::GetBestEdge() const
|
||||
{
|
||||
return nsPoint(mVerticalEdgeFound ? mBestEdge.x : mStartPos.x,
|
||||
mHorizontalEdgeFound ? mBestEdge.y : mStartPos.y);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddHorizontalEdge(nscoord aEdge)
|
||||
{
|
||||
AddEdge(aEdge, mDestination.y, mStartPos.y, mScrollingDirection.y, &mBestEdge.y,
|
||||
&mHorizontalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddVerticalEdge(nscoord aEdge)
|
||||
{
|
||||
AddEdge(aEdge, mDestination.x, mStartPos.x, mScrollingDirection.x, &mBestEdge.x,
|
||||
&mVerticalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddHorizontalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
{
|
||||
AddEdgeInterval(aInterval, aScrollRange.y, aScrollRange.YMost(), aOffset,
|
||||
mDestination.y, mStartPos.y, mScrollingDirection.y,
|
||||
&mBestEdge.y, &mHorizontalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddVerticalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
{
|
||||
AddEdgeInterval(aInterval, aScrollRange.x, aScrollRange.XMost(), aOffset,
|
||||
mDestination.x, mStartPos.x, mScrollingDirection.x,
|
||||
&mBestEdge.x, &mVerticalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination, nscoord aStartPos,
|
||||
nscoord aScrollingDirection, nscoord* aBestEdge,
|
||||
bool *aEdgeFound)
|
||||
{
|
||||
// nsIScrollableFrame::DEVICE_PIXELS indicates that we are releasing a drag
|
||||
// gesture or any other user input event that sets an absolute scroll
|
||||
// position. In this case, scroll snapping is expected to travel in any
|
||||
// direction. Otherwise, we will restrict the direction of the scroll
|
||||
// snapping movement based on aScrollingDirection.
|
||||
if (mUnit != nsIScrollableFrame::DEVICE_PIXELS) {
|
||||
// Unless DEVICE_PIXELS, we only want to snap to points ahead of the
|
||||
// direction we are scrolling
|
||||
if (aScrollingDirection == 0) {
|
||||
// The scroll direction is neutral - will not hit a snap point.
|
||||
return;
|
||||
}
|
||||
// nsIScrollableFrame::WHOLE indicates that we are navigating to "home" or
|
||||
// "end". In this case, we will always select the first or last snap point
|
||||
// regardless of the direction of the scroll. Otherwise, we will select
|
||||
// scroll snapping points only in the direction specified by
|
||||
// aScrollingDirection.
|
||||
if (mUnit != nsIScrollableFrame::WHOLE) {
|
||||
// Direction of the edge from the current position (before scrolling) in
|
||||
// the direction of scrolling
|
||||
nscoord direction = (aEdge - aStartPos) * aScrollingDirection;
|
||||
if (direction <= 0) {
|
||||
// The edge is not in the direction we are scrolling, skip it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!*aEdgeFound) {
|
||||
*aBestEdge = aEdge;
|
||||
*aEdgeFound = true;
|
||||
return;
|
||||
}
|
||||
if (mUnit == nsIScrollableFrame::DEVICE_PIXELS ||
|
||||
mUnit == nsIScrollableFrame::LINES) {
|
||||
if (std::abs(aEdge - aDestination) < std::abs(*aBestEdge - aDestination)) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
} else if (mUnit == nsIScrollableFrame::PAGES) {
|
||||
// distance to the edge from the scrolling destination in the direction of scrolling
|
||||
nscoord overshoot = (aEdge - aDestination) * aScrollingDirection;
|
||||
// distance to the current best edge from the scrolling destination in the direction of scrolling
|
||||
nscoord curOvershoot = (*aBestEdge - aDestination) * aScrollingDirection;
|
||||
|
||||
// edges between the current position and the scrolling destination are favoured
|
||||
// to preserve context
|
||||
if (overshoot < 0 && (overshoot > curOvershoot || curOvershoot >= 0)) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
// if there are no edges between the current position and the scrolling destination
|
||||
// the closest edge beyond the destination is used
|
||||
if (overshoot > 0 && overshoot < curOvershoot) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
} else if (mUnit == nsIScrollableFrame::WHOLE) {
|
||||
// the edge closest to the top/bottom/left/right is used, depending on scrolling direction
|
||||
if (aScrollingDirection > 0 && aEdge > *aBestEdge) {
|
||||
*aBestEdge = aEdge;
|
||||
} else if (aScrollingDirection < 0 && aEdge < *aBestEdge) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
} else {
|
||||
NS_ERROR("Invalid scroll mode");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddEdgeInterval(nscoord aInterval, nscoord aMinPos,
|
||||
nscoord aMaxPos, nscoord aOffset,
|
||||
nscoord aDestination, nscoord aStartPos,
|
||||
nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge, bool *aEdgeFound)
|
||||
{
|
||||
if (aInterval == 0) {
|
||||
// When interval is 0, there are no scroll snap points.
|
||||
// Avoid division by zero and bail.
|
||||
return;
|
||||
}
|
||||
|
||||
// The only possible candidate interval snap points are the edges immediately
|
||||
// surrounding aDestination.
|
||||
|
||||
// aDestination must be clamped to the scroll
|
||||
// range in order to handle cases where the best matching snap point would
|
||||
// result in scrolling out of bounds. This clamping must be prior to
|
||||
// selecting the two interval edges.
|
||||
nscoord clamped = std::max(std::min(aDestination, aMaxPos), aMinPos);
|
||||
|
||||
// Add each edge in the interval immediately before aTarget and after aTarget
|
||||
// Do not add edges that are out of range.
|
||||
nscoord r = (clamped + aOffset) % aInterval;
|
||||
if (r < aMinPos) {
|
||||
r += aInterval;
|
||||
}
|
||||
nscoord edge = clamped - r;
|
||||
if (edge >= aMinPos && edge <= aMaxPos) {
|
||||
AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge,
|
||||
aEdgeFound);
|
||||
}
|
||||
edge += aInterval;
|
||||
if (edge >= aMinPos && edge <= aMaxPos) {
|
||||
AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge,
|
||||
aEdgeFound);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ProcessScrollSnapCoordinates(SnappingEdgeCallback& aCallback,
|
||||
const nsTArray<nsPoint>& aScrollSnapCoordinates,
|
||||
const nsPoint& aScrollSnapDestination) {
|
||||
for (nsPoint snapCoords : aScrollSnapCoordinates) {
|
||||
// Make them relative to the scroll snap destination.
|
||||
snapCoords -= aScrollSnapDestination;
|
||||
|
||||
aCallback.AddVerticalEdge(snapCoords.x);
|
||||
aCallback.AddHorizontalEdge(snapCoords.y);
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<nsPoint> ScrollSnapUtils::GetSnapPointForDestination(
|
||||
const ScrollSnapInfo& aSnapInfo,
|
||||
nsIScrollableFrame::ScrollUnit aUnit,
|
||||
const nsSize& aScrollPortSize,
|
||||
const nsRect& aScrollRange,
|
||||
const nsPoint& aStartPos,
|
||||
const nsPoint& aDestination)
|
||||
{
|
||||
if (aSnapInfo.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_NONE &&
|
||||
aSnapInfo.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_NONE) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
nsPoint destPos = aSnapInfo.mScrollSnapDestination;
|
||||
|
||||
CalcSnapPoints calcSnapPoints(aUnit, aDestination, aStartPos);
|
||||
|
||||
if (aSnapInfo.mScrollSnapIntervalX.isSome()) {
|
||||
nscoord interval = aSnapInfo.mScrollSnapIntervalX.value();
|
||||
calcSnapPoints.AddVerticalEdgeInterval(aScrollRange, interval, destPos.x);
|
||||
}
|
||||
if (aSnapInfo.mScrollSnapIntervalY.isSome()) {
|
||||
nscoord interval = aSnapInfo.mScrollSnapIntervalY.value();
|
||||
calcSnapPoints.AddHorizontalEdgeInterval(aScrollRange, interval, destPos.y);
|
||||
}
|
||||
|
||||
ProcessScrollSnapCoordinates(calcSnapPoints, aSnapInfo.mScrollSnapCoordinates, destPos);
|
||||
bool snapped = false;
|
||||
nsPoint finalPos = calcSnapPoints.GetBestEdge();
|
||||
nscoord proximityThreshold = gfxPrefs::ScrollSnapProximityThreshold();
|
||||
proximityThreshold = nsPresContext::CSSPixelsToAppUnits(proximityThreshold);
|
||||
if (aSnapInfo.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY &&
|
||||
std::abs(aDestination.y - finalPos.y) > proximityThreshold) {
|
||||
finalPos.y = aDestination.y;
|
||||
} else {
|
||||
snapped = true;
|
||||
}
|
||||
if (aSnapInfo.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY &&
|
||||
std::abs(aDestination.x - finalPos.x) > proximityThreshold) {
|
||||
finalPos.x = aDestination.x;
|
||||
} else {
|
||||
snapped = true;
|
||||
}
|
||||
return snapped ? Some(finalPos) : Nothing();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_layout_ScrollSnap_h_
|
||||
#define mozilla_layout_ScrollSnap_h_
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
struct ScrollSnapInfo;
|
||||
}
|
||||
|
||||
struct ScrollSnapUtils {
|
||||
/**
|
||||
* GetSnapPointForDestination determines which point to snap to after
|
||||
* scrolling. |aStartPos| gives the position before scrolling and
|
||||
* |aDestination| gives the position after scrolling, with no snapping.
|
||||
* Behaviour is dependent on the value of |aUnit|.
|
||||
* |aSnapInfo|, |aScrollPortSize|, and |aScrollRange| are characteristics
|
||||
* of the scroll frame for which snapping is being performed.
|
||||
* If a suitable snap point could be found, it is returned. Otherwise, an
|
||||
* empty Maybe is returned.
|
||||
* IMPORTANT NOTE: This function is designed to be called both on and off
|
||||
* the main thread. If modifying its implementation, be sure
|
||||
* not to touch main-thread-only data structures without
|
||||
* appropriate locking.
|
||||
*/
|
||||
static Maybe<nsPoint> GetSnapPointForDestination(
|
||||
const layers::ScrollSnapInfo& aSnapInfo,
|
||||
nsIScrollableFrame::ScrollUnit aUnit,
|
||||
const nsSize& aScrollPortSize,
|
||||
const nsRect& aScrollRange,
|
||||
const nsPoint& aStartPos,
|
||||
const nsPoint& aDestination);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_layout_ScrollSnap_h_
|
|
@ -96,6 +96,7 @@ EXPORTS += [
|
|||
'nsTextRunTransformations.h',
|
||||
'RubyUtils.h',
|
||||
'ScrollbarActivity.h',
|
||||
'ScrollSnap.h',
|
||||
'Visibility.h',
|
||||
]
|
||||
|
||||
|
@ -166,6 +167,7 @@ UNIFIED_SOURCES += [
|
|||
'nsViewportFrame.cpp',
|
||||
'RubyUtils.cpp',
|
||||
'ScrollbarActivity.cpp',
|
||||
'ScrollSnap.cpp',
|
||||
'ScrollVelocityQueue.cpp',
|
||||
'StickyScrollContainer.cpp',
|
||||
'SummaryFrame.cpp',
|
||||
|
|
|
@ -5474,7 +5474,7 @@ nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
|
|||
static bool
|
||||
DoesLayerHaveOutOfDateFrameMetrics(Layer* aLayer)
|
||||
{
|
||||
for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
|
||||
for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
|
||||
const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
|
||||
if (!metrics.IsScrollable()) {
|
||||
continue;
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "gfxPlatform.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "AsyncScrollBase.h"
|
||||
#include "ScrollSnap.h"
|
||||
#include "UnitTransforms.h"
|
||||
#include "nsPluginFrame.h"
|
||||
#include <mozilla/layers/AxisPhysicsModel.h>
|
||||
|
@ -3553,8 +3554,8 @@ ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
|
||||
|
||||
Maybe<FrameMetrics>
|
||||
ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer,
|
||||
Maybe<ScrollMetadata>
|
||||
ScrollFrameHelper::ComputeScrollMetadata(Layer* aLayer,
|
||||
nsIFrame* aContainerReferenceFrame,
|
||||
const ContainerLayerParameters& aParameters,
|
||||
const DisplayItemClip* aClip) const
|
||||
|
@ -3609,7 +3610,7 @@ ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer,
|
|||
|
||||
nsRect scrollport = mScrollPort + toReferenceFrame;
|
||||
|
||||
return Some(nsLayoutUtils::ComputeFrameMetrics(
|
||||
return Some(nsLayoutUtils::ComputeScrollMetadata(
|
||||
mScrolledFrame, mOuter, mOuter->GetContent(),
|
||||
aContainerReferenceFrame, aLayer, mScrollParentID,
|
||||
scrollport, parentLayerClip, isRootContent, aParameters));
|
||||
|
@ -3914,12 +3915,6 @@ ScrollFrameHelper::ScrollSnap(nsIScrollableFrame::ScrollMode aMode)
|
|||
ScrollSnap(destinationPos, aMode);
|
||||
}
|
||||
|
||||
void
|
||||
ScrollFrameHelper::FlingSnap(const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
ScrollSnap(CSSPoint::ToAppUnits(aDestination));
|
||||
}
|
||||
|
||||
void
|
||||
ScrollFrameHelper::ScrollSnap(const nsPoint &aDestination,
|
||||
nsIScrollableFrame::ScrollMode aMode)
|
||||
|
@ -5775,244 +5770,13 @@ nsIScrollableFrame::GetPerceivedScrollingDirections() const
|
|||
}
|
||||
|
||||
/**
|
||||
* Stores candidate snapping edges.
|
||||
* Collect the scroll-snap-coordinates of frames in the subtree rooted at
|
||||
* |aFrame|, relative to |aScrolledFrame|, into |aOutCoords|.
|
||||
*/
|
||||
class SnappingEdgeCallback {
|
||||
public:
|
||||
virtual void AddHorizontalEdge(nscoord aEdge) = 0;
|
||||
virtual void AddVerticalEdge(nscoord aEdge) = 0;
|
||||
virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval,
|
||||
nscoord aOffset) = 0;
|
||||
virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval,
|
||||
nscoord aOffset) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Keeps track of the current best edge to snap to. The criteria for
|
||||
* adding an edge depends on the scrolling unit.
|
||||
*/
|
||||
class CalcSnapPoints : public SnappingEdgeCallback {
|
||||
public:
|
||||
CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit,
|
||||
const nsPoint& aDestination,
|
||||
const nsPoint& aStartPos);
|
||||
virtual void AddHorizontalEdge(nscoord aEdge) override;
|
||||
virtual void AddVerticalEdge(nscoord aEdge) override;
|
||||
virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
override;
|
||||
virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
override;
|
||||
void AddEdge(nscoord aEdge,
|
||||
nscoord aDestination,
|
||||
nscoord aStartPos,
|
||||
nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge,
|
||||
bool* aEdgeFound);
|
||||
void AddEdgeInterval(nscoord aInterval,
|
||||
nscoord aMinPos,
|
||||
nscoord aMaxPos,
|
||||
nscoord aOffset,
|
||||
nscoord aDestination,
|
||||
nscoord aStartPos,
|
||||
nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge,
|
||||
bool* aEdgeFound);
|
||||
nsPoint GetBestEdge() const;
|
||||
protected:
|
||||
nsIScrollableFrame::ScrollUnit mUnit;
|
||||
nsPoint mDestination; // gives the position after scrolling but before snapping
|
||||
nsPoint mStartPos; // gives the position before scrolling
|
||||
nsIntPoint mScrollingDirection; // always -1, 0, or 1
|
||||
nsPoint mBestEdge; // keeps track of the position of the current best edge
|
||||
bool mHorizontalEdgeFound; // true if mBestEdge.x is storing a valid horizontal edge
|
||||
bool mVerticalEdgeFound; // true if mBestEdge.y is storing a valid vertical edge
|
||||
};
|
||||
|
||||
CalcSnapPoints::CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit,
|
||||
const nsPoint& aDestination,
|
||||
const nsPoint& aStartPos)
|
||||
{
|
||||
mUnit = aUnit;
|
||||
mDestination = aDestination;
|
||||
mStartPos = aStartPos;
|
||||
|
||||
nsPoint direction = aDestination - aStartPos;
|
||||
mScrollingDirection = nsIntPoint(0,0);
|
||||
if (direction.x < 0) {
|
||||
mScrollingDirection.x = -1;
|
||||
}
|
||||
if (direction.x > 0) {
|
||||
mScrollingDirection.x = 1;
|
||||
}
|
||||
if (direction.y < 0) {
|
||||
mScrollingDirection.y = -1;
|
||||
}
|
||||
if (direction.y > 0) {
|
||||
mScrollingDirection.y = 1;
|
||||
}
|
||||
mBestEdge = aDestination;
|
||||
mHorizontalEdgeFound = false;
|
||||
mVerticalEdgeFound = false;
|
||||
}
|
||||
|
||||
nsPoint
|
||||
CalcSnapPoints::GetBestEdge() const
|
||||
{
|
||||
return nsPoint(mVerticalEdgeFound ? mBestEdge.x : mStartPos.x,
|
||||
mHorizontalEdgeFound ? mBestEdge.y : mStartPos.y);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddHorizontalEdge(nscoord aEdge)
|
||||
CollectScrollSnapCoordinates(nsIFrame* aFrame, nsIFrame* aScrolledFrame,
|
||||
nsTArray<nsPoint>& aOutCoords)
|
||||
{
|
||||
AddEdge(aEdge, mDestination.y, mStartPos.y, mScrollingDirection.y, &mBestEdge.y,
|
||||
&mHorizontalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddVerticalEdge(nscoord aEdge)
|
||||
{
|
||||
AddEdge(aEdge, mDestination.x, mStartPos.x, mScrollingDirection.x, &mBestEdge.x,
|
||||
&mVerticalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddHorizontalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
{
|
||||
AddEdgeInterval(aInterval, aScrollRange.y, aScrollRange.YMost(), aOffset,
|
||||
mDestination.y, mStartPos.y, mScrollingDirection.y,
|
||||
&mBestEdge.y, &mHorizontalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddVerticalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
{
|
||||
AddEdgeInterval(aInterval, aScrollRange.x, aScrollRange.XMost(), aOffset,
|
||||
mDestination.x, mStartPos.x, mScrollingDirection.x,
|
||||
&mBestEdge.x, &mVerticalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination, nscoord aStartPos,
|
||||
nscoord aScrollingDirection, nscoord* aBestEdge,
|
||||
bool *aEdgeFound)
|
||||
{
|
||||
// nsIScrollableFrame::DEVICE_PIXELS indicates that we are releasing a drag
|
||||
// gesture or any other user input event that sets an absolute scroll
|
||||
// position. In this case, scroll snapping is expected to travel in any
|
||||
// direction. Otherwise, we will restrict the direction of the scroll
|
||||
// snapping movement based on aScrollingDirection.
|
||||
if (mUnit != nsIScrollableFrame::DEVICE_PIXELS) {
|
||||
// Unless DEVICE_PIXELS, we only want to snap to points ahead of the
|
||||
// direction we are scrolling
|
||||
if (aScrollingDirection == 0) {
|
||||
// The scroll direction is neutral - will not hit a snap point.
|
||||
return;
|
||||
}
|
||||
// nsIScrollableFrame::WHOLE indicates that we are navigating to "home" or
|
||||
// "end". In this case, we will always select the first or last snap point
|
||||
// regardless of the direction of the scroll. Otherwise, we will select
|
||||
// scroll snapping points only in the direction specified by
|
||||
// aScrollingDirection.
|
||||
if (mUnit != nsIScrollableFrame::WHOLE) {
|
||||
// Direction of the edge from the current position (before scrolling) in
|
||||
// the direction of scrolling
|
||||
nscoord direction = (aEdge - aStartPos) * aScrollingDirection;
|
||||
if (direction <= 0) {
|
||||
// The edge is not in the direction we are scrolling, skip it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!*aEdgeFound) {
|
||||
*aBestEdge = aEdge;
|
||||
*aEdgeFound = true;
|
||||
return;
|
||||
}
|
||||
if (mUnit == nsIScrollableFrame::DEVICE_PIXELS ||
|
||||
mUnit == nsIScrollableFrame::LINES) {
|
||||
if (std::abs(aEdge - aDestination) < std::abs(*aBestEdge - aDestination)) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
} else if (mUnit == nsIScrollableFrame::PAGES) {
|
||||
// distance to the edge from the scrolling destination in the direction of scrolling
|
||||
nscoord overshoot = (aEdge - aDestination) * aScrollingDirection;
|
||||
// distance to the current best edge from the scrolling destination in the direction of scrolling
|
||||
nscoord curOvershoot = (*aBestEdge - aDestination) * aScrollingDirection;
|
||||
|
||||
// edges between the current position and the scrolling destination are favoured
|
||||
// to preserve context
|
||||
if (overshoot < 0 && (overshoot > curOvershoot || curOvershoot >= 0)) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
// if there are no edges between the current position and the scrolling destination
|
||||
// the closest edge beyond the destination is used
|
||||
if (overshoot > 0 && overshoot < curOvershoot) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
} else if (mUnit == nsIScrollableFrame::WHOLE) {
|
||||
// the edge closest to the top/bottom/left/right is used, depending on scrolling direction
|
||||
if (aScrollingDirection > 0 && aEdge > *aBestEdge) {
|
||||
*aBestEdge = aEdge;
|
||||
} else if (aScrollingDirection < 0 && aEdge < *aBestEdge) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
} else {
|
||||
NS_ERROR("Invalid scroll mode");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddEdgeInterval(nscoord aInterval, nscoord aMinPos,
|
||||
nscoord aMaxPos, nscoord aOffset,
|
||||
nscoord aDestination, nscoord aStartPos,
|
||||
nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge, bool *aEdgeFound)
|
||||
{
|
||||
if (aInterval == 0) {
|
||||
// When interval is 0, there are no scroll snap points.
|
||||
// Avoid division by zero and bail.
|
||||
return;
|
||||
}
|
||||
|
||||
// The only possible candidate interval snap points are the edges immediately
|
||||
// surrounding aDestination.
|
||||
|
||||
// aDestination must be clamped to the scroll
|
||||
// range in order to handle cases where the best matching snap point would
|
||||
// result in scrolling out of bounds. This clamping must be prior to
|
||||
// selecting the two interval edges.
|
||||
nscoord clamped = std::max(std::min(aDestination, aMaxPos), aMinPos);
|
||||
|
||||
// Add each edge in the interval immediately before aTarget and after aTarget
|
||||
// Do not add edges that are out of range.
|
||||
nscoord r = (clamped + aOffset) % aInterval;
|
||||
if (r < aMinPos) {
|
||||
r += aInterval;
|
||||
}
|
||||
nscoord edge = clamped - r;
|
||||
if (edge >= aMinPos && edge <= aMaxPos) {
|
||||
AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge,
|
||||
aEdgeFound);
|
||||
}
|
||||
edge += aInterval;
|
||||
if (edge >= aMinPos && edge <= aMaxPos) {
|
||||
AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge,
|
||||
aEdgeFound);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ScrollSnapHelper(SnappingEdgeCallback& aCallback, nsIFrame* aFrame,
|
||||
nsIFrame* aScrolledFrame,
|
||||
const nsPoint &aScrollSnapDestination) {
|
||||
nsIFrame::ChildListIterator childLists(aFrame);
|
||||
for (; !childLists.IsDone(); childLists.Next()) {
|
||||
nsFrameList::Enumerator childFrames(childLists.CurrentList());
|
||||
|
@ -6029,7 +5793,7 @@ ScrollSnapHelper(SnappingEdgeCallback& aCallback, nsIFrame* aFrame,
|
|||
for (size_t coordNum = 0; coordNum < coordCount; coordNum++) {
|
||||
const nsStyleImageLayers::Position &coordPosition =
|
||||
f->StyleDisplay()->mScrollSnapCoordinate[coordNum];
|
||||
nsPoint coordPoint = edgesRect.TopLeft() - aScrollSnapDestination;
|
||||
nsPoint coordPoint = edgesRect.TopLeft();
|
||||
coordPoint += nsPoint(coordPosition.mXPosition.mLength,
|
||||
coordPosition.mYPosition.mLength);
|
||||
if (coordPosition.mXPosition.mHasPercent) {
|
||||
|
@ -6041,79 +5805,84 @@ ScrollSnapHelper(SnappingEdgeCallback& aCallback, nsIFrame* aFrame,
|
|||
frameRect.height);
|
||||
}
|
||||
|
||||
aCallback.AddVerticalEdge(coordPoint.x);
|
||||
aCallback.AddHorizontalEdge(coordPoint.y);
|
||||
aOutCoords.AppendElement(coordPoint);
|
||||
}
|
||||
}
|
||||
|
||||
ScrollSnapHelper(aCallback, f, aScrolledFrame, aScrollSnapDestination);
|
||||
CollectScrollSnapCoordinates(f, aScrolledFrame, aOutCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layers::ScrollSnapInfo
|
||||
ComputeScrollSnapInfo(const ScrollFrameHelper& aScrollFrame)
|
||||
{
|
||||
ScrollSnapInfo result;
|
||||
|
||||
ScrollbarStyles styles = aScrollFrame.GetScrollbarStylesFromFrame();
|
||||
|
||||
if (styles.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_NONE &&
|
||||
styles.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_NONE) {
|
||||
// We won't be snapping, short-circuit the computation.
|
||||
return result;
|
||||
}
|
||||
|
||||
result.mScrollSnapTypeX = styles.mScrollSnapTypeX;
|
||||
result.mScrollSnapTypeY = styles.mScrollSnapTypeY;
|
||||
|
||||
nsSize scrollPortSize = aScrollFrame.GetScrollPortRect().Size();
|
||||
|
||||
result.mScrollSnapDestination = nsPoint(styles.mScrollSnapDestinationX.mLength,
|
||||
styles.mScrollSnapDestinationY.mLength);
|
||||
if (styles.mScrollSnapDestinationX.mHasPercent) {
|
||||
result.mScrollSnapDestination.x +=
|
||||
NSToCoordFloorClamped(styles.mScrollSnapDestinationX.mPercent *
|
||||
scrollPortSize.width);
|
||||
}
|
||||
if (styles.mScrollSnapDestinationY.mHasPercent) {
|
||||
result.mScrollSnapDestination.y +=
|
||||
NSToCoordFloorClamped(styles.mScrollSnapDestinationY.mPercent *
|
||||
scrollPortSize.height);
|
||||
}
|
||||
|
||||
if (styles.mScrollSnapPointsX.GetUnit() != eStyleUnit_None) {
|
||||
result.mScrollSnapIntervalX = Some(nsRuleNode::ComputeCoordPercentCalc(
|
||||
styles.mScrollSnapPointsX, scrollPortSize.width));
|
||||
}
|
||||
if (styles.mScrollSnapPointsY.GetUnit() != eStyleUnit_None) {
|
||||
result.mScrollSnapIntervalY = Some(nsRuleNode::ComputeCoordPercentCalc(
|
||||
styles.mScrollSnapPointsY, scrollPortSize.height));
|
||||
}
|
||||
|
||||
CollectScrollSnapCoordinates(aScrollFrame.GetScrolledFrame(),
|
||||
aScrollFrame.GetScrolledFrame(),
|
||||
result.mScrollSnapCoordinates);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
layers::ScrollSnapInfo
|
||||
ScrollFrameHelper::GetScrollSnapInfo() const
|
||||
{
|
||||
// TODO(botond): Should we cache it?
|
||||
return ComputeScrollSnapInfo(*this);
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollFrameHelper::GetSnapPointForDestination(nsIScrollableFrame::ScrollUnit aUnit,
|
||||
nsPoint aStartPos,
|
||||
nsPoint &aDestination)
|
||||
{
|
||||
ScrollbarStyles styles = GetScrollbarStylesFromFrame();
|
||||
if (styles.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_NONE &&
|
||||
styles.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_NONE) {
|
||||
Maybe<nsPoint> snapPoint = ScrollSnapUtils::GetSnapPointForDestination(
|
||||
GetScrollSnapInfo(), aUnit, mScrollPort.Size(),
|
||||
GetScrollRangeForClamping(), aStartPos, aDestination);
|
||||
if (snapPoint) {
|
||||
aDestination = snapPoint.ref();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsSize scrollPortSize = mScrollPort.Size();
|
||||
nsRect scrollRange = GetScrollRangeForClamping();
|
||||
|
||||
nsPoint destPos = nsPoint(styles.mScrollSnapDestinationX.mLength,
|
||||
styles.mScrollSnapDestinationY.mLength);
|
||||
if (styles.mScrollSnapDestinationX.mHasPercent) {
|
||||
destPos.x += NSToCoordFloorClamped(styles.mScrollSnapDestinationX.mPercent
|
||||
* scrollPortSize.width);
|
||||
}
|
||||
|
||||
if (styles.mScrollSnapDestinationY.mHasPercent) {
|
||||
destPos.y += NSToCoordFloorClamped(styles.mScrollSnapDestinationY.mPercent
|
||||
* scrollPortSize.height);
|
||||
}
|
||||
|
||||
CalcSnapPoints calcSnapPoints(aUnit, aDestination, aStartPos);
|
||||
|
||||
if (styles.mScrollSnapPointsX.GetUnit() != eStyleUnit_None) {
|
||||
nscoord interval = nsRuleNode::ComputeCoordPercentCalc(styles.mScrollSnapPointsX,
|
||||
scrollPortSize.width);
|
||||
calcSnapPoints.AddVerticalEdgeInterval(scrollRange, interval, destPos.x);
|
||||
}
|
||||
if (styles.mScrollSnapPointsY.GetUnit() != eStyleUnit_None) {
|
||||
nscoord interval = nsRuleNode::ComputeCoordPercentCalc(styles.mScrollSnapPointsY,
|
||||
scrollPortSize.height);
|
||||
calcSnapPoints.AddHorizontalEdgeInterval(scrollRange, interval, destPos.y);
|
||||
}
|
||||
|
||||
ScrollSnapHelper(calcSnapPoints, mScrolledFrame, mScrolledFrame, destPos);
|
||||
bool snapped = false;
|
||||
nsPoint finalPos = calcSnapPoints.GetBestEdge();
|
||||
nscoord proximityThreshold =
|
||||
Preferences::GetInt("layout.css.scroll-snap.proximity-threshold", 0);
|
||||
proximityThreshold = nsPresContext::CSSPixelsToAppUnits(proximityThreshold);
|
||||
if (styles.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY &&
|
||||
std::abs(aDestination.y - finalPos.y) > proximityThreshold) {
|
||||
finalPos.y = aDestination.y;
|
||||
} else {
|
||||
snapped = true;
|
||||
}
|
||||
if (styles.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY &&
|
||||
std::abs(aDestination.x - finalPos.x) > proximityThreshold) {
|
||||
finalPos.x = aDestination.x;
|
||||
} else {
|
||||
snapped = true;
|
||||
}
|
||||
if (snapped) {
|
||||
aDestination = finalPos;
|
||||
}
|
||||
return snapped;
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollFrameHelper::UsesContainerScrolling() const
|
||||
{
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
typedef mozilla::CSSIntPoint CSSIntPoint;
|
||||
typedef mozilla::layout::ScrollbarActivity ScrollbarActivity;
|
||||
typedef mozilla::layers::FrameMetrics FrameMetrics;
|
||||
typedef mozilla::layers::ScrollSnapInfo ScrollSnapInfo;
|
||||
typedef mozilla::layers::Layer Layer;
|
||||
|
||||
class AsyncScroll;
|
||||
|
@ -203,7 +204,6 @@ public:
|
|||
// Get the scroll range assuming the scrollport has size (aWidth, aHeight).
|
||||
nsRect GetScrollRange(nscoord aWidth, nscoord aHeight) const;
|
||||
nsSize GetScrollPositionClampingScrollPortSize() const;
|
||||
void FlingSnap(const mozilla::CSSPoint& aDestination);
|
||||
void ScrollSnap(nsIScrollableFrame::ScrollMode aMode = nsIScrollableFrame::SMOOTH_MSD);
|
||||
void ScrollSnap(const nsPoint &aDestination,
|
||||
nsIScrollableFrame::ScrollMode aMode = nsIScrollableFrame::SMOOTH_MSD);
|
||||
|
@ -390,6 +390,8 @@ public:
|
|||
|
||||
bool UsesContainerScrolling() const;
|
||||
|
||||
ScrollSnapInfo GetScrollSnapInfo() const;
|
||||
|
||||
bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRect* aDirtyRect,
|
||||
bool aAllowCreateDisplayPort);
|
||||
|
@ -416,7 +418,7 @@ public:
|
|||
}
|
||||
}
|
||||
bool WantAsyncScroll() const;
|
||||
Maybe<mozilla::layers::FrameMetrics> ComputeFrameMetrics(
|
||||
Maybe<mozilla::layers::ScrollMetadata> ComputeScrollMetadata(
|
||||
Layer* aLayer, nsIFrame* aContainerReferenceFrame,
|
||||
const ContainerLayerParameters& aParameters,
|
||||
const mozilla::DisplayItemClip* aClip) const;
|
||||
|
@ -838,9 +840,6 @@ public:
|
|||
override {
|
||||
mHelper.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin, aMomentum, aSnap);
|
||||
}
|
||||
virtual void FlingSnap(const mozilla::CSSPoint& aDestination) override {
|
||||
mHelper.FlingSnap(aDestination);
|
||||
}
|
||||
virtual void ScrollSnap() override {
|
||||
mHelper.ScrollSnap();
|
||||
}
|
||||
|
@ -905,12 +904,12 @@ public:
|
|||
virtual bool WantAsyncScroll() const override {
|
||||
return mHelper.WantAsyncScroll();
|
||||
}
|
||||
virtual mozilla::Maybe<mozilla::layers::FrameMetrics> ComputeFrameMetrics(
|
||||
virtual mozilla::Maybe<mozilla::layers::ScrollMetadata> ComputeScrollMetadata(
|
||||
Layer* aLayer, nsIFrame* aContainerReferenceFrame,
|
||||
const ContainerLayerParameters& aParameters,
|
||||
const mozilla::DisplayItemClip* aClip) const override
|
||||
{
|
||||
return mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame, aParameters, aClip);
|
||||
return mHelper.ComputeScrollMetadata(aLayer, aContainerReferenceFrame, aParameters, aClip);
|
||||
}
|
||||
virtual bool IsIgnoringViewportClipping() const override {
|
||||
return mHelper.IsIgnoringViewportClipping();
|
||||
|
@ -1010,6 +1009,10 @@ public:
|
|||
mHelper.SetZoomableByAPZ(aZoomable);
|
||||
}
|
||||
|
||||
ScrollSnapInfo GetScrollSnapInfo() const override {
|
||||
return mHelper.GetScrollSnapInfo();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override;
|
||||
#endif
|
||||
|
@ -1249,9 +1252,6 @@ public:
|
|||
override {
|
||||
mHelper.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin, aMomentum, aSnap);
|
||||
}
|
||||
virtual void FlingSnap(const mozilla::CSSPoint& aDestination) override {
|
||||
mHelper.FlingSnap(aDestination);
|
||||
}
|
||||
virtual void ScrollSnap() override {
|
||||
mHelper.ScrollSnap();
|
||||
}
|
||||
|
@ -1316,12 +1316,12 @@ public:
|
|||
virtual bool WantAsyncScroll() const override {
|
||||
return mHelper.WantAsyncScroll();
|
||||
}
|
||||
virtual mozilla::Maybe<mozilla::layers::FrameMetrics> ComputeFrameMetrics(
|
||||
virtual mozilla::Maybe<mozilla::layers::ScrollMetadata> ComputeScrollMetadata(
|
||||
Layer* aLayer, nsIFrame* aContainerReferenceFrame,
|
||||
const ContainerLayerParameters& aParameters,
|
||||
const mozilla::DisplayItemClip* aClip) const override
|
||||
{
|
||||
return mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame, aParameters, aClip);
|
||||
return mHelper.ComputeScrollMetadata(aLayer, aContainerReferenceFrame, aParameters, aClip);
|
||||
}
|
||||
virtual bool IsIgnoringViewportClipping() const override {
|
||||
return mHelper.IsIgnoringViewportClipping();
|
||||
|
@ -1429,6 +1429,10 @@ public:
|
|||
mHelper.TriggerDisplayPortExpiration();
|
||||
}
|
||||
|
||||
ScrollSnapInfo GetScrollSnapInfo() const override {
|
||||
return mHelper.GetScrollSnapInfo();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override;
|
||||
#endif
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
typedef mozilla::CSSIntPoint CSSIntPoint;
|
||||
typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
|
||||
typedef mozilla::layers::FrameMetrics FrameMetrics;
|
||||
typedef mozilla::layers::ScrollSnapInfo ScrollSnapInfo;
|
||||
|
||||
NS_DECL_QUERYFRAME_TARGET(nsIScrollableFrame)
|
||||
|
||||
|
@ -269,16 +270,6 @@ public:
|
|||
nsIScrollbarMediator::ScrollSnapMode aSnap
|
||||
= nsIScrollbarMediator::DISABLE_SNAP) = 0;
|
||||
|
||||
/**
|
||||
* Perform scroll snapping, possibly resulting in a smooth scroll to
|
||||
* maintain the scroll snap position constraints. A predicted landing
|
||||
* position determined by the APZC is used to select the best matching
|
||||
* snap point, allowing touchscreen fling gestures to navigate between
|
||||
* snap points.
|
||||
* @param aDestination The desired landing position of the fling, which
|
||||
* is used to select the best matching snap point.
|
||||
*/
|
||||
virtual void FlingSnap(const mozilla::CSSPoint& aDestination) = 0;
|
||||
/**
|
||||
* Perform scroll snapping, possibly resulting in a smooth scroll to
|
||||
* maintain the scroll snap position constraints. Velocity sampled from
|
||||
|
@ -400,9 +391,9 @@ public:
|
|||
virtual bool WantAsyncScroll() const = 0;
|
||||
/**
|
||||
* aLayer's animated geometry root is this frame. If there needs to be a
|
||||
* FrameMetrics contributed by this frame, append it to aOutput.
|
||||
* ScrollMetadata contributed by this frame, append it to aOutput.
|
||||
*/
|
||||
virtual mozilla::Maybe<mozilla::layers::FrameMetrics> ComputeFrameMetrics(
|
||||
virtual mozilla::Maybe<mozilla::layers::ScrollMetadata> ComputeScrollMetadata(
|
||||
mozilla::layers::Layer* aLayer,
|
||||
nsIFrame* aContainerReferenceFrame,
|
||||
const ContainerLayerParameters& aParameters,
|
||||
|
@ -470,6 +461,11 @@ public:
|
|||
* own displayport and schedule a timer to do that if it is safe.
|
||||
*/
|
||||
virtual void TriggerDisplayPortExpiration() = 0;
|
||||
|
||||
/**
|
||||
* Returns information required to determine where to snap to after a scroll.
|
||||
*/
|
||||
virtual ScrollSnapInfo GetScrollSnapInfo() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsStyleContext.h"
|
||||
|
||||
|
|
|
@ -135,6 +135,7 @@ nsSubDocumentFrame::Init(nsIContent* aContent,
|
|||
nsCOMPtr<nsIDocument> oldContainerDoc;
|
||||
nsView* detachedViews =
|
||||
frameloader->GetDetachedSubdocView(getter_AddRefs(oldContainerDoc));
|
||||
frameloader->SetDetachedSubdocView(nullptr, nullptr);
|
||||
if (detachedViews) {
|
||||
if (oldContainerDoc == aContent->OwnerDoc()) {
|
||||
// Restore stashed presentation.
|
||||
|
@ -145,7 +146,6 @@ nsSubDocumentFrame::Init(nsIContent* aContent,
|
|||
frameloader->Hide();
|
||||
}
|
||||
}
|
||||
frameloader->SetDetachedSubdocView(nullptr, nullptr);
|
||||
}
|
||||
|
||||
nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
|
||||
|
@ -945,13 +945,16 @@ public:
|
|||
if (!mPresShell->IsDestroying()) {
|
||||
mPresShell->FlushPendingNotifications(Flush_Frames);
|
||||
}
|
||||
|
||||
// Either the frame has been constructed by now, or it never will be,
|
||||
// either way we want to clear the stashed views.
|
||||
mFrameLoader->SetDetachedSubdocView(nullptr, nullptr);
|
||||
|
||||
nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame());
|
||||
if ((!frame && mHideViewerIfFrameless) ||
|
||||
mPresShell->IsDestroying()) {
|
||||
// Either the frame element has no nsIFrame or the presshell is being
|
||||
// destroyed. Hide the nsFrameLoader, which destroys the presentation,
|
||||
// and clear our references to the stashed presentation.
|
||||
mFrameLoader->SetDetachedSubdocView(nullptr, nullptr);
|
||||
// destroyed. Hide the nsFrameLoader, which destroys the presentation.
|
||||
mFrameLoader->Hide();
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -977,7 +980,7 @@ nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
|||
// Detach the subdocument's views and stash them in the frame loader.
|
||||
// We can then reattach them if we're being reframed (for example if
|
||||
// the frame has been made position:fixed).
|
||||
nsFrameLoader* frameloader = FrameLoader();
|
||||
RefPtr<nsFrameLoader> frameloader = FrameLoader();
|
||||
if (frameloader) {
|
||||
nsView* detachedViews = ::BeginSwapDocShellsForViews(mInnerView->GetFirstChild());
|
||||
frameloader->SetDetachedSubdocView(detachedViews, mContent->OwnerDoc());
|
||||
|
@ -986,7 +989,7 @@ nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
|||
// safely determine whether the frame is being reframed or destroyed.
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new nsHideViewer(mContent,
|
||||
mFrameLoader,
|
||||
frameloader,
|
||||
PresContext()->PresShell(),
|
||||
(mDidCreateDoc || mCallingShow)));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference case</title>
|
||||
<style>
|
||||
input, button {
|
||||
border: 0; /* Combined, these mean the gray area is the */
|
||||
background: lightgray; /* border-box size. */
|
||||
|
||||
outline: 2px solid black; /* The outlined area is the overflow area. */
|
||||
width: 1px; /* (To attempt to trigger overflow) */
|
||||
|
||||
display: block; /* Put each button on its own line, w/ some margin, */
|
||||
margin-bottom: 5px; /* so that any overflow doesn't get stomped on. */
|
||||
|
||||
font: 8px serif; /* (This just lets the testcase fit better on mobile.) */
|
||||
}
|
||||
|
||||
.oh { overflow: hidden }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- For the reference case, we just put "overflow:hidden" on everything. -->
|
||||
<input class="oh" type="reset">
|
||||
<input class="oh" type="submit">
|
||||
<input class="oh" type="button" value="InputTypeButton">
|
||||
<!-- ...with one exception: button with (default) overflow:visible.
|
||||
Such buttons *do* actually allow their contents to overflow. -->
|
||||
<button>ActualButton</button>
|
||||
|
||||
<input class="oh" type="reset">
|
||||
<input class="oh" type="submit">
|
||||
<input class="oh" type="button" value="InputTypeButton">
|
||||
<button class="oh">ActualButton</button>
|
||||
|
||||
<input class="oh" type="reset">
|
||||
<input class="oh" type="submit">
|
||||
<input class="oh" type="button" value="InputTypeButton">
|
||||
<button class="oh">ActualButton</button>
|
||||
|
||||
<input class="oh" type="reset">
|
||||
<input class="oh" type="submit">
|
||||
<input class="oh" type="button" value="InputTypeButton">
|
||||
<button class="oh">ActualButton</button>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<html>
|
||||
<!-- For buttons whose painting gets clipped to their border-box area,
|
||||
we should *also* clip their overflow area (as exposed via 'outline').
|
||||
This test exposes these areas so they can be visualized, and checks that
|
||||
they match when we expect them to. -->
|
||||
<head>
|
||||
<title>Testcase for bug 1261284</title>
|
||||
<style>
|
||||
input, button {
|
||||
border: 0; /* Combined, these mean the gray area is the */
|
||||
background: lightgray; /* border-box size. */
|
||||
|
||||
outline: 2px solid black; /* The outlined area is the overflow area. */
|
||||
width: 1px; /* (To attempt to trigger overflow) */
|
||||
|
||||
display: block; /* Put each button on its own line, w/ some margin, */
|
||||
margin-bottom: 5px; /* so that any overflow doesn't get stomped on. */
|
||||
|
||||
font: 8px serif; /* (This just lets the testcase fit better on mobile.) */
|
||||
}
|
||||
|
||||
.oh { overflow: hidden }
|
||||
.oa { overflow: auto }
|
||||
.os { overflow: scroll }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<input type="reset">
|
||||
<input type="submit">
|
||||
<input type="button" value="InputTypeButton">
|
||||
<button>ActualButton</button>
|
||||
|
||||
<input class="oh" type="reset">
|
||||
<input class="oh" type="submit">
|
||||
<input class="oh" type="button" value="InputTypeButton">
|
||||
<button class="oh">ActualButton</button>
|
||||
|
||||
<input class="oa" type="reset">
|
||||
<input class="oa" type="submit">
|
||||
<input class="oa" type="button" value="InputTypeButton">
|
||||
<button class="oa">ActualButton</button>
|
||||
|
||||
<input class="os" type="reset">
|
||||
<input class="os" type="submit">
|
||||
<input class="os" type="button" value="InputTypeButton">
|
||||
<button class="os">ActualButton</button>
|
||||
</body>
|
||||
</html>
|
|
@ -2,6 +2,7 @@
|
|||
!= first-letter-1.html first-letter-1-noref.html
|
||||
== max-height.html max-height-ref.html
|
||||
== min-height.html min-height-ref.html
|
||||
== overflow-areas-1.html overflow-areas-1-ref.html
|
||||
|
||||
# The buttons in these tests have some fancy shading applied to their corners
|
||||
# on B2G, despite their "-moz-appearance: none; background: gray", so they
|
||||
|
|
|
@ -130,6 +130,9 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.[12]/
|
|||
# text-shadow
|
||||
== text-shadow.svg text-shadow-ref.svg
|
||||
|
||||
# vertical text
|
||||
pref(layout.css.vertical-text.enabled,true) == vertical-01.svg vertical-01-ref.svg
|
||||
|
||||
# tests for ignoring various properties
|
||||
== ignore-border.svg ignore-prop-ref.svg
|
||||
== ignore-display.svg ignore-display-ref.svg
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче