This commit is contained in:
Ryan VanderMeulen 2016-04-02 14:00:14 -04:00
Родитель bffbcbb869 1bb567e688
Коммит 5e7b5cb82f
167 изменённых файлов: 3960 добавлений и 2050 удалений

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

@ -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"
@ -39,7 +35,7 @@ namespace {
nsresult
GetPermissionState(nsIPrincipal* aPrincipal,
PushPermissionState& aState)
PushPermissionState& aState)
{
nsCOMPtr<nsIPermissionManager> permManager =
mozilla::services::GetPermissionManager();
@ -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,30 +7,23 @@
* 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);
Promise<PushSubscription> subscribe();
Promise<PushSubscription?> getSubscription();
Promise<PushPermissionState> permissionState();
};
[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();
Promise<PushSubscription> subscribe();
[Throws]
Promise<PushSubscription?> getSubscription();
Promise<PushSubscription?> getSubscription();
[Throws]
Promise<PushPermissionState> permissionState();
};

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

@ -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,32 +769,17 @@ 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;
return ret.forget();
#endif /* ! MOZ_SIMPLEPUSH */
#endif /* ! MOZ_SIMPLEPUSH */
}
////////////////////////////////////////////////////
@ -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,13 +1211,13 @@ 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 */
#endif /* ! MOZ_SIMPLEPUSH */
}
} // dom namespace

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

@ -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, &paramType::SetIsRootContent) &&
ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::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
@ -152,7 +144,8 @@ public:
virtual void NotifyFlushComplete() = 0;
virtual void UpdateOverscrollVelocity(const float aX, const float aY) {}
virtual void UpdateOverscrollOffset(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,21 +2396,25 @@ 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();
}
// Adjust the start point to reflect the consumed portion of the scroll.
aStartPoint = aEndPoint + overscroll;
} else {
overscroll = displacement;
}
// Adjust the start point to reflect the consumed portion of the scroll.
aStartPoint = aEndPoint + overscroll;
// If we consumed the entire displacement as a normal scroll, great.
if (IsZero(overscroll)) {
return true;
@ -2510,51 +2527,18 @@ void AsyncPanZoomController::AcceptFling(FlingHandoffState& aHandoffState) {
mY.SetVelocity(mY.GetVelocity() + aHandoffState.mVelocity.y);
aHandoffState.mVelocity.y = 0;
}
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);
}
// 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);
StartAnimation(fling);
}
}
@ -2597,21 +2581,28 @@ void AsyncPanZoomController::HandleSmoothScrollOverscroll(const ParentLayerPoint
HandleFlingOverscroll(aVelocity, BuildOverscrollHandoffChain(), nullptr);
}
void AsyncPanZoomController::StartSmoothScroll(ScrollSource aSource) {
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());
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(aDestination);
StartAnimation(new SmoothScrollAnimation(*this,
aSource,
initialPosition, initialVelocity,
destination,
gfxPrefs::ScrollBehaviorSpringConstant(),
gfxPrefs::ScrollBehaviorDampingRatio()));
StartAnimation(new SmoothScrollAnimation(*this,
initialPosition, initialVelocity,
destination,
gfxPrefs::ScrollBehaviorSpringConstant(),
gfxPrefs::ScrollBehaviorDampingRatio()));
}
}
void AsyncPanZoomController::StartOverscrollAnimation(const ParentLayerPoint& aVelocity) {
@ -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(),
md.decl.type.priority,
md.prettyMsgName(p.name+'::'),
md.decl.type.compress),
Whitespace.NL ])
decls = []
mfDecl, mfDefn = _splitFuncDeclDefn(
_generateMessageConstructor(md.msgClass(), md.msgId(),
md.decl.type.priority,
md.prettyMsgName(p.name+'::'),
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'),
ExprVar(priorityEnum),
compression,
ExprLiteral.String(prettyName) ]) ])
cls.addstmts([ ctor, Whitespace.NL ])
# 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)))
func.addstmt(
StmtReturn(ExprNew(Type('IPC::Message'),
args=[ routingId,
ExprVar(msgid),
ExprVar(priorityEnum),
compression,
ExprLiteral.String(prettyName) ])))
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,9 +5107,9 @@ 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()),
args=[ routingId ])) ]
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))
for p in md.params ]
@ -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),
self.protocol.callOtherPid(actor),
ExprLiteral.TRUE if receiving else ExprLiteral.FALSE ])) ])
return _ifLogging(ExprLiteral.String(actorname),
[ StmtExpr(ExprCall(
ExprVar('mozilla::ipc::LogMessageForProtocol'),
args=[ ExprLiteral.String(actorname),
self.protocol.callOtherPid(actor),
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,
const ContainerLayerParameters& aContainerParameters)
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,9 +4989,9 @@ nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
return LAYER_ACTIVE_EMPTY;
}
UniquePtr<FrameMetrics>
nsDisplayScrollInfoLayer::ComputeFrameMetrics(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters)
UniquePtr<ScrollMetadata>
nsDisplayScrollInfoLayer::ComputeScrollMetadata(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters)
{
ContainerLayerParameters params = aContainerParameters;
if (mScrolledFrame->GetContent() &&
@ -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,8 +3551,8 @@ public:
NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT)
mozilla::UniquePtr<FrameMetrics> ComputeFrameMetrics(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters);
mozilla::UniquePtr<ScrollMetadata> ComputeScrollMetadata(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters);
protected:
ViewID mScrollParentId;
@ -3691,8 +3692,8 @@ public:
virtual void WriteDebugInfo(std::stringstream& aStream) override;
mozilla::UniquePtr<FrameMetrics> ComputeFrameMetrics(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters);
mozilla::UniquePtr<ScrollMetadata> ComputeScrollMetadata(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters);
protected:
nsIFrame* mScrollFrame;

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

@ -8583,23 +8583,24 @@ nsLayoutUtils::CanScrollOriginClobberApz(nsIAtom* aScrollOrigin)
&& aScrollOrigin != nsGkAtoms::restore;
}
/* static */ FrameMetrics
nsLayoutUtils::ComputeFrameMetrics(nsIFrame* aForFrame,
nsIFrame* aScrollFrame,
nsIContent* aContent,
const nsIFrame* aReferenceFrame,
Layer* aLayer,
ViewID aScrollParentId,
const nsRect& aViewport,
const Maybe<nsRect>& aClipRect,
bool aIsRootContent,
const ContainerLayerParameters& aContainerParameters)
/* static */ ScrollMetadata
nsLayoutUtils::ComputeScrollMetadata(nsIFrame* aForFrame,
nsIFrame* aScrollFrame,
nsIContent* aContent,
const nsIFrame* aReferenceFrame,
Layer* aLayer,
ViewID aScrollParentId,
const nsRect& aViewport,
const Maybe<nsRect>& aClipRect,
bool aIsRootContent,
const ContainerLayerParameters& aContainerParameters)
{
nsPresContext* presContext = aForFrame->PresContext();
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,16 +2722,16 @@ public:
*/
static bool CanScrollOriginClobberApz(nsIAtom* aScrollOrigin);
static FrameMetrics ComputeFrameMetrics(nsIFrame* aForFrame,
nsIFrame* aScrollFrame,
nsIContent* aContent,
const nsIFrame* aReferenceFrame,
Layer* aLayer,
ViewID aScrollParentId,
const nsRect& aViewport,
const mozilla::Maybe<nsRect>& aClipRect,
bool aIsRoot,
const ContainerLayerParameters& aContainerParameters);
static ScrollMetadata ComputeScrollMetadata(nsIFrame* aForFrame,
nsIFrame* aScrollFrame,
nsIContent* aContent,
const nsIFrame* aReferenceFrame,
Layer* aLayer,
ViewID aScrollParentId,
const nsRect& aViewport,
const mozilla::Maybe<nsRect>& aClipRect,
bool aIsRoot,
const ContainerLayerParameters& aContainerParameters);
/**
* If the given scroll frame needs an area excluded from its composition

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

@ -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);
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, 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,11 +3554,11 @@ ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
}
Maybe<FrameMetrics>
ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer,
nsIFrame* aContainerReferenceFrame,
const ContainerLayerParameters& aParameters,
const DisplayItemClip* aClip) const
Maybe<ScrollMetadata>
ScrollFrameHelper::ComputeScrollMetadata(Layer* aLayer,
nsIFrame* aContainerReferenceFrame,
const ContainerLayerParameters& aParameters,
const DisplayItemClip* aClip) const
{
if (!mWillBuildScrollableLayer || mIsScrollableLayerInRootContainer) {
return Nothing();
@ -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,77 +5805,82 @@ 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) {
return false;
Maybe<nsPoint> snapPoint = ScrollSnapUtils::GetSnapPointForDestination(
GetScrollSnapInfo(), aUnit, mScrollPort.Size(),
GetScrollRangeForClamping(), aStartPos, aDestination);
if (snapPoint) {
aDestination = snapPoint.ref();
return true;
}
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;
return false;
}
bool

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

@ -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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше