Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-04-21 12:51:15 +02:00
commit f96cc582eb
232 changed files with 3033 additions and 2793 deletions

View File

@ -371,29 +371,30 @@ exports.testTabMove = function(assert, done) {
};
exports.testIgnoreClosing = function(assert, done) {
let originalWindow = browserWindows.activeWindow;
let originalWindow = viewFor(browserWindows.activeWindow);
openBrowserWindow(function(window, browser) {
let url = "data:text/html;charset=utf-8,foobar";
onFocus(window).then(() => {
let url = "data:text/html;charset=utf-8,foobar";
assert.equal(tabs.length, 2, "should be two windows open each with one tab");
assert.equal(tabs.length, 2, "should be two windows open each with one tab");
tabs.on('ready', function onReady(tab) {
tabs.removeListener('ready', onReady);
tabs.on('ready', function onReady(tab) {
tabs.removeListener('ready', onReady);
let win = tab.window;
assert.equal(win.tabs.length, 2, "should be two tabs in the new window");
assert.equal(tabs.length, 3, "should be three tabs in total");
let win = tab.window;
assert.equal(win.tabs.length, 2, "should be two tabs in the new window");
assert.equal(tabs.length, 3, "should be three tabs in total");
tab.close(function() {
assert.equal(win.tabs.length, 1, "should be one tab in the new window");
assert.equal(tabs.length, 2, "should be two tabs in total");
tab.close(function() {
assert.equal(win.tabs.length, 1, "should be one tab in the new window");
assert.equal(tabs.length, 2, "should be two tabs in total");
originalWindow.once("activate", done);
close(window);
close(window).then(onFocus(originalWindow)).then(done).then(null, assert.fail);
});
});
});
tabs.open(url);
tabs.open(url);
});
});
};

View File

@ -252,7 +252,7 @@ pref("browser.uitour.requireSecure", true);
pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/themes/");
pref("browser.uitour.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tour/");
// This is used as a regexp match against the page's URL.
pref("browser.uitour.readerViewTrigger", "^https:\/\/www\.mozilla\.org\/[^\/]+\/firefox\/reading\/start");
pref("browser.uitour.readerViewTrigger", "^https:\\/\\/www\\.mozilla\\.org\\/[^\\/]+\\/firefox\\/reading\\/start");
pref("browser.customizemode.tip0.shown", false);
pref("browser.customizemode.tip0.learnMoreUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/customize");
@ -1880,12 +1880,9 @@ pref("dom.ipc.reportProcessHangs", false);
pref("dom.ipc.reportProcessHangs", true);
#endif
// Enable ReadingList browser UI by default.
pref("browser.readinglist.enabled", true);
pref("browser.readinglist.enabled", false);
pref("browser.readinglist.sidebarEverOpened", false);
// Enable the readinglist engine by default.
pref("readinglist.scheduler.enabled", true);
pref("readinglist.scheduler.enabled", false);
pref("readinglist.server", "https://readinglist.services.mozilla.com/v1");
// Don't limit how many nodes we care about on desktop:

View File

@ -8,9 +8,16 @@
* Tests that we build a working leftpane in various corruption situations.
*/
function run_test() {
// Used to store the original leftPaneFolderId getter.
let gLeftPaneFolderIdGetter;
let gAllBookmarksFolderIdGetter;
// Used to store the original left Pane status as a JSON string.
let gReferenceHierarchy;
let gLeftPaneFolderId;
add_task(function* () {
// We want empty roots.
remove_all_bookmarks();
yield PlacesUtils.bookmarks.eraseEverything();
// Sanity check.
Assert.ok(!!PlacesUIUtils);
@ -21,17 +28,8 @@ function run_test() {
gAllBookmarksFolderIdGetter = Object.getOwnPropertyDescriptor(PlacesUIUtils, "allBookmarksFolderId");
Assert.equal(typeof(gAllBookmarksFolderIdGetter.get), "function");
run_next_test();
}
do_register_cleanup(remove_all_bookmarks);
// Used to store the original leftPaneFolderId getter.
let gLeftPaneFolderIdGetter;
let gAllBookmarksFolderIdGetter;
// Used to store the original left Pane status as a JSON string.
let gReferenceHierarchy;
let gLeftPaneFolderId;
do_register_cleanup(() => PlacesUtils.bookmarks.eraseEverything());
});
add_task(function* () {
// Add a third party bogus annotated item. Should not be removed.

View File

@ -15,6 +15,7 @@ Cu.import("resource://gre/modules/Timer.jsm");
do_get_profile();
let prefs = new Preferences("readinglist.scheduler.");
prefs.set("enabled", true);
function promiseObserver(topic) {
return new Promise(resolve => {

View File

@ -1829,6 +1829,7 @@ MarkupContainer.prototype = {
this.hovered = false;
this.markup.navigate(this);
event.stopPropagation();
event.preventDefault();
// Start dragging the container after a delay.
this.markup._dragStartEl = target;
@ -2145,7 +2146,7 @@ MarkupElementContainer.prototype = Heritage.extend(MarkupContainer.prototype, {
this.tooltipData.data = promise.resolve(res);
});
}, () => {
this.tooltipData.data = promise.reject();
this.tooltipData.data = promise.resolve({});
});
}
},
@ -2165,9 +2166,11 @@ MarkupElementContainer.prototype = Heritage.extend(MarkupContainer.prototype, {
}
return this.tooltipData.data.then(({data, size}) => {
tooltip.setImageContent(data, size);
}, () => {
tooltip.setBrokenImageContent();
if (data && size) {
tooltip.setImageContent(data, size);
} else {
tooltip.setBrokenImageContent();
}
});
},

View File

@ -68,12 +68,14 @@ skip-if = e10s # Bug 1040751 - CodeMirror editor.destroy() isn't e10s compatible
skip-if = e10s # Bug 1040751 - CodeMirror editor.destroy() isn't e10s compatible
[browser_markupview_events_jquery_2.1.1.js]
skip-if = e10s # Bug 1040751 - CodeMirror editor.destroy() isn't e10s compatible
[browser_markupview_load_01.js]
[browser_markupview_html_edit_01.js]
[browser_markupview_html_edit_02.js]
[browser_markupview_html_edit_03.js]
[browser_markupview_image_tooltip.js]
[browser_markupview_keybindings_01.js]
[browser_markupview_keybindings_02.js]
[browser_markupview_keybindings_03.js]
[browser_markupview_mutation_01.js]
[browser_markupview_mutation_02.js]
[browser_markupview_navigation.js]

View File

@ -21,7 +21,8 @@ add_task(function*() {
target: el.tagLine,
pageX: rect.x,
pageY: rect.y,
stopPropagation: function() {}
stopPropagation: function() {},
preventDefault: function() {}
});
is(el.isDragging, false, "isDragging should not be set to true immedietly");

View File

@ -64,7 +64,8 @@ function* dragContainer(selector, targetOffset, inspector) {
target: container.tagLine,
pageX: rect.x,
pageY: rect.y,
stopPropagation: function() {}
stopPropagation: function() {},
preventDefault: function() {}
});
let targetX = rect.x + targetOffset.x,

View File

@ -157,16 +157,6 @@ const TEST_DATA = [
" alert(8);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "click",
filename: TEST_URL_ROOT + TEST_LIB + ":894",
@ -197,6 +187,16 @@ const TEST_DATA = [
" return returnValue;\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL_ROOT + TEST_LIB + ":894",

View File

@ -171,16 +171,6 @@ const TEST_DATA = [
" alert(8);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "click",
filename: TEST_URL_ROOT + TEST_LIB + ":1224",
@ -221,6 +211,16 @@ const TEST_DATA = [
" return returnValue;\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL_ROOT + TEST_LIB + ":1224",

View File

@ -103,16 +103,6 @@ const TEST_DATA = [
" alert(8);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "click",
filename: TEST_URL_ROOT + TEST_LIB + ":3",
@ -124,6 +114,16 @@ const TEST_DATA = [
" return typeof m === K || a && m.event.triggered === a.type ? void 0 : m.event.dispatch.apply(k.elem, arguments)\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL_ROOT + TEST_LIB + ":3",
@ -141,17 +141,6 @@ const TEST_DATA = [
{
selector: "#livediv",
expected: [
{
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
type: "dragend",
filename: TEST_URL + ":31",
@ -164,14 +153,14 @@ const TEST_DATA = [
"}"
},
{
type: "drop",
filename: TEST_URL + ":32",
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
@ -184,6 +173,17 @@ const TEST_DATA = [
handler: "var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
"}"
},
{
type: "drop",
filename: TEST_URL + ":32",
attributes: [
"jQuery",
"Live"
],
handler: "var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
"}"
}
]
},

View File

@ -142,16 +142,6 @@ const TEST_DATA = [
" alert(8);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "click",
filename: TEST_URL_ROOT + TEST_LIB + ":24",
@ -166,6 +156,16 @@ const TEST_DATA = [
" return val;\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL_ROOT + TEST_LIB + ":24",

View File

@ -16,17 +16,6 @@ const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "unload",
filename: TEST_URL_ROOT + TEST_LIB + ":19",
attributes: [
"jQuery"
],
handler: "function(H) {\n" +
" n(this).unbind(H, D);\n" +
" return (E || G).apply(this, arguments)\n" +
"}"
},
{
type: "load",
filename: TEST_URL_ROOT + TEST_LIB + ":19",
@ -108,7 +97,7 @@ const TEST_DATA = [
"}"
},
{
type: "unload",
type: "load",
filename: TEST_URL_ROOT + TEST_LIB + ":19",
attributes: [
"Bubbling",
@ -119,7 +108,18 @@ const TEST_DATA = [
"}"
},
{
type: "load",
type: "unload",
filename: TEST_URL_ROOT + TEST_LIB + ":19",
attributes: [
"jQuery"
],
handler: "function(H) {\n" +
" n(this).unbind(H, D);\n" +
" return (E || G).apply(this, arguments)\n" +
"}"
},
{
type: "unload",
filename: TEST_URL_ROOT + TEST_LIB + ":19",
attributes: [
"Bubbling",
@ -154,16 +154,6 @@ const TEST_DATA = [
" alert(8);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "click",
filename: TEST_URL_ROOT + TEST_LIB + ":19",
@ -175,6 +165,16 @@ const TEST_DATA = [
" return typeof n !== \"undefined\" && !n.event.triggered ? n.event.handle.apply(arguments.callee.elem, arguments) : g\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL_ROOT + TEST_LIB + ":19",

View File

@ -121,16 +121,6 @@ const TEST_DATA = [
" alert(8);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "click",
filename: TEST_URL_ROOT + TEST_LIB + ":48",
@ -142,6 +132,16 @@ const TEST_DATA = [
" return typeof c !== \"undefined\" && !c.event.triggered ? c.event.handle.apply(j.elem, arguments) : w\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL_ROOT + TEST_LIB + ":48",
@ -169,17 +169,6 @@ const TEST_DATA = [
" alert(1);\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL + ":29",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
"}"
},
{
type: "dblclick",
filename: TEST_URL_ROOT + TEST_LIB + ":17",
@ -228,6 +217,17 @@ const TEST_DATA = [
" return b\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL + ":29",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL_ROOT + TEST_LIB + ":17",

View File

@ -118,16 +118,6 @@ const TEST_DATA = [
" alert(8);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "click",
filename: TEST_URL_ROOT + TEST_LIB + ":16",
@ -139,6 +129,16 @@ const TEST_DATA = [
" return typeof f != \"undefined\" && (!a || f.event.triggered !== a.type) ? f.event.handle.apply(k.elem, arguments) : b\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL_ROOT + TEST_LIB + ":16",
@ -166,39 +166,6 @@ const TEST_DATA = [
" alert(1);\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL + ":29",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
"}"
},
{
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
type: "dragend",
filename: TEST_URL + ":31",
attributes: [
"jQuery",
"Live"
],
handler: "var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
"}"
},
{
type: "dblclick",
filename: TEST_URL_ROOT + TEST_LIB + ":16",
@ -244,7 +211,18 @@ const TEST_DATA = [
"}"
},
{
type: "dragstart",
type: "dragend",
filename: TEST_URL + ":31",
attributes: [
"jQuery",
"Live"
],
handler: "var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
"}"
},
{
type: "dragend",
filename: TEST_URL_ROOT + TEST_LIB + ":16",
attributes: [
"jQuery",
@ -287,6 +265,17 @@ const TEST_DATA = [
" }\n" +
"}"
},
{
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
type: "dragleave",
filename: TEST_URL_ROOT + TEST_LIB + ":16",
@ -332,7 +321,18 @@ const TEST_DATA = [
"}"
},
{
type: "dragend",
type: "dragstart",
filename: TEST_URL + ":29",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL_ROOT + TEST_LIB + ":16",
attributes: [
"jQuery",

View File

@ -118,16 +118,6 @@ const TEST_DATA = [
" alert(8);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "click",
filename: TEST_URL_ROOT + TEST_LIB + ":3",
@ -139,6 +129,16 @@ const TEST_DATA = [
" return typeof f != \"undefined\" && (!a || f.event.triggered !== a.type) ? f.event.dispatch.apply(i.elem, arguments) : b\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL_ROOT + TEST_LIB + ":3",
@ -167,14 +167,14 @@ const TEST_DATA = [
"}"
},
{
type: "dragstart",
filename: TEST_URL + ":29",
type: "dragend",
filename: TEST_URL + ":31",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
handler: "var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
"}"
},
{
@ -189,14 +189,25 @@ const TEST_DATA = [
"}"
},
{
type: "dragend",
filename: TEST_URL + ":31",
type: "dragover",
filename: TEST_URL + ":33",
attributes: [
"jQuery",
"Live"
],
handler: "var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
handler: "var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL + ":29",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
"}"
},
{
@ -209,17 +220,6 @@ const TEST_DATA = [
handler: "var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
"}"
},
{
type: "dragover",
filename: TEST_URL + ":33",
attributes: [
"jQuery",
"Live"
],
handler: "var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
"}"
}
]
},

View File

@ -102,16 +102,6 @@ const TEST_DATA = [
" alert(8);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "click",
filename: TEST_URL_ROOT + TEST_LIB + ":3",
@ -123,6 +113,16 @@ const TEST_DATA = [
" return typeof n !== U && n.event.triggered !== b.type ? n.event.dispatch.apply(a, arguments) : void 0\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL_ROOT + TEST_LIB + ":3",
@ -139,17 +139,6 @@ const TEST_DATA = [
{
selector: "#livediv",
expected: [
{
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
type: "dragend",
filename: TEST_URL + ":31",
@ -162,14 +151,14 @@ const TEST_DATA = [
"}"
},
{
type: "drop",
filename: TEST_URL + ":32",
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
@ -182,6 +171,17 @@ const TEST_DATA = [
handler: "var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
"}"
},
{
type: "drop",
filename: TEST_URL + ":32",
attributes: [
"jQuery",
"Live"
],
handler: "var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
"}"
}
]
},

View File

@ -0,0 +1,34 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that selecting a node with the mouse (by clicking on the line) focuses
// the first focusable element in the corresponding MarkupContainer so that the
// keyboard can be used immediately.
const TEST_URL = "data:text/html;charset=utf8,<div></div>Text node";
add_task(function*() {
let {inspector, toolbox} = yield addTab(TEST_URL).then(openInspector);
let {walker} = inspector;
info("Select the test node to have the 2 test containers visible");
yield selectNode("div", inspector);
let divFront = yield walker.querySelector(walker.rootNode, "div");
let textFront = yield walker.nextSibling(divFront);
info("Click on the MarkupContainer element for the text node");
yield clickContainer(textFront, inspector);
is(inspector.markup.doc.activeElement,
getContainerForNodeFront(textFront, inspector).editor.value,
"The currently focused element is the node's text content");
info("Click on the MarkupContainer element for the <div> node");
yield clickContainer(divFront, inspector);
is(inspector.markup.doc.activeElement,
getContainerForNodeFront(divFront, inspector).editor.tag,
"The currently focused element is the div's tagname");
});

View File

@ -0,0 +1,70 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that selecting an element with the 'Inspect Element' context
// menu during a page reload doesn't cause the markup view to become empty.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1036324
const server = createTestHTTPServer();
// Register a slow image handler so we can simulate a long time between
// a reload and the load event firing.
server.registerContentType("gif", "image/gif");
server.registerPathHandler("/slow.gif", function (metadata, response) {
info ("Image has been requested");
response.processAsync();
setTimeout(() => {
info ("Image is responding");
response.finish();
}, 500);
});
// Test page load events.
const TEST_URL = "data:text/html," +
"<!DOCTYPE html>" +
"<head><meta charset='utf-8' /></head>" +
"<body>" +
"<p>Slow script</p>" +
"<img src='http://localhost:" + server.identity.primaryPort + "/slow.gif' /></script>" +
"</body>" +
"</html>";
add_task(function*() {
let tab = yield addTab(TEST_URL);
let {inspector} = yield openInspector();
let domContentLoaded = waitForLinkedBrowserEvent(tab, "DOMContentLoaded");
let pageLoaded = waitForLinkedBrowserEvent(tab, "load");
ok (inspector.markup, "There is a markup view");
// Select an element while the tab is in the middle of a slow reload.
reloadTab();
yield domContentLoaded;
yield chooseWithInspectElementContextMenu("img");
yield pageLoaded;
yield inspector.once("markuploaded");
ok (inspector.markup, "There is a markup view");
is (inspector.markup._elt.children.length, 1, "The markup view is rendering");
});
function* chooseWithInspectElementContextMenu(selector) {
yield executeInContent("Test:SynthesizeMouse", {
center: true,
selector: selector,
options: {type: "contextmenu", button: 2}
});
executeInContent("Test:SynthesizeKey", {key: "Q", options: {}});
}
function waitForLinkedBrowserEvent(tab, event) {
let def = promise.defer();
tab.linkedBrowser.addEventListener(event, function cb() {
tab.linkedBrowser.removeEventListener(event, cb, true);
def.resolve();
}, true);
return def.promise;
}

View File

@ -172,6 +172,13 @@ function executeInContent(name, data={}, objects={}, expectResponse=true) {
}
}
/**
* Reload the current tab location.
*/
function reloadTab() {
return executeInContent("devtools:test:reload", {}, {}, false);
}
/**
* Simple DOM node accesor function that takes either a node or a string css
* selector as argument and returns the corresponding node
@ -647,3 +654,34 @@ function* waitForMultipleChildrenUpdates(inspector) {
return yield waitForMultipleChildrenUpdates(inspector);
}
}
/**
* Create an HTTP server that can be used to simulate custom requests within
* a test. It is automatically cleaned up when the test ends, so no need to
* call `destroy`.
*
* See https://developer.mozilla.org/en-US/docs/Httpd.js/HTTP_server_for_unit_tests
* for more information about how to register handlers.
*
* The server can be accessed like:
*
* const server = createTestHTTPServer();
* let url = "http://localhost: " + server.identity.primaryPort + "/path";
*
* @returns {HttpServer}
*/
function createTestHTTPServer() {
const {HttpServer} = Cu.import("resource://testing-common/httpd.js", {});
let server = new HttpServer();
registerCleanupFunction(function* cleanup() {
let destroyed = promise.defer();
server.stop(() => {
destroyed.resolve();
});
yield destroyed.promise;
});
server.start(-1);
return server;
}

View File

@ -1230,6 +1230,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
break;
case "remoteAddress":
requestItem.attachment.remoteAddress = value;
this.updateMenuView(requestItem, key, value);
break;
case "remotePort":
requestItem.attachment.remotePort = value;
@ -1382,6 +1383,11 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
domain.setAttribute("tooltiptext", hostPort);
break;
}
case "remoteAddress":
let domain = $(".requests-menu-domain", target);
let tooltip = domain.getAttribute("value") + " (" + aValue + ")";
domain.setAttribute("tooltiptext", tooltip);
break;
case "securityState": {
let tooltip = L10N.getStr("netmonitor.security.state." + aValue);
let icon = $(".requests-security-state-icon", target);

View File

@ -275,34 +275,37 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
let name = uri.fileName || "/";
let query = uri.query;
let hostPort = uri.hostPort;
let remoteAddress = attachment.remoteAddress;
if (fuzzyUrl) {
ok(attachment.method.startsWith(aMethod), "The attached method is incorrect.");
ok(attachment.url.startsWith(aUrl), "The attached url is incorrect.");
ok(attachment.method.startsWith(aMethod), "The attached method is correct.");
ok(attachment.url.startsWith(aUrl), "The attached url is correct.");
} else {
is(attachment.method, aMethod, "The attached method is incorrect.");
is(attachment.url, aUrl, "The attached url is incorrect.");
is(attachment.method, aMethod, "The attached method is correct.");
is(attachment.url, aUrl, "The attached url is correct.");
}
is(target.querySelector(".requests-menu-method").getAttribute("value"),
aMethod, "The displayed method is incorrect.");
aMethod, "The displayed method is correct.");
if (fuzzyUrl) {
ok(target.querySelector(".requests-menu-file").getAttribute("value").startsWith(
name + (query ? "?" + query : "")), "The displayed file is incorrect.");
name + (query ? "?" + query : "")), "The displayed file is correct.");
ok(target.querySelector(".requests-menu-file").getAttribute("tooltiptext").startsWith(
name + (query ? "?" + query : "")), "The tooltip file is incorrect.");
name + (query ? "?" + query : "")), "The tooltip file is correct.");
} else {
is(target.querySelector(".requests-menu-file").getAttribute("value"),
name + (query ? "?" + query : ""), "The displayed file is incorrect.");
name + (query ? "?" + query : ""), "The displayed file is correct.");
is(target.querySelector(".requests-menu-file").getAttribute("tooltiptext"),
name + (query ? "?" + query : ""), "The tooltip file is incorrect.");
name + (query ? "?" + query : ""), "The tooltip file is correct.");
}
is(target.querySelector(".requests-menu-domain").getAttribute("value"),
hostPort, "The displayed domain is incorrect.");
hostPort, "The displayed domain is correct.");
let domainTooltip = hostPort + (remoteAddress ? " (" + remoteAddress + ")" : "");
is(target.querySelector(".requests-menu-domain").getAttribute("tooltiptext"),
hostPort, "The tooltip domain is incorrect.");
domainTooltip, "The tooltip domain is correct.");
if (status !== undefined) {
let value = target.querySelector(".requests-menu-status").getAttribute("code");
@ -311,54 +314,54 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
info("Displayed status: " + value);
info("Displayed code: " + codeValue);
info("Tooltip status: " + tooltip);
is(value, status, "The displayed status is incorrect.");
is(codeValue, status, "The displayed status code is incorrect.");
is(tooltip, status + " " + statusText, "The tooltip status is incorrect.");
is(value, status, "The displayed status is correct.");
is(codeValue, status, "The displayed status code is correct.");
is(tooltip, status + " " + statusText, "The tooltip status is correct.");
}
if (type !== undefined) {
let value = target.querySelector(".requests-menu-type").getAttribute("value");
let tooltip = target.querySelector(".requests-menu-type").getAttribute("tooltiptext");
info("Displayed type: " + value);
info("Tooltip type: " + tooltip);
is(value, type, "The displayed type is incorrect.");
is(tooltip, fullMimeType, "The tooltip type is incorrect.");
is(value, type, "The displayed type is correct.");
is(tooltip, fullMimeType, "The tooltip type is correct.");
}
if (transferred !== undefined) {
let value = target.querySelector(".requests-menu-transferred").getAttribute("value");
let tooltip = target.querySelector(".requests-menu-transferred").getAttribute("tooltiptext");
info("Displayed transferred size: " + value);
info("Tooltip transferred size: " + tooltip);
is(value, transferred, "The displayed transferred size is incorrect.");
is(tooltip, transferred, "The tooltip transferred size is incorrect.");
is(value, transferred, "The displayed transferred size is correct.");
is(tooltip, transferred, "The tooltip transferred size is correct.");
}
if (size !== undefined) {
let value = target.querySelector(".requests-menu-size").getAttribute("value");
let tooltip = target.querySelector(".requests-menu-size").getAttribute("tooltiptext");
info("Displayed size: " + value);
info("Tooltip size: " + tooltip);
is(value, size, "The displayed size is incorrect.");
is(tooltip, size, "The tooltip size is incorrect.");
is(value, size, "The displayed size is correct.");
is(tooltip, size, "The tooltip size is correct.");
}
if (time !== undefined) {
let value = target.querySelector(".requests-menu-timings-total").getAttribute("value");
let tooltip = target.querySelector(".requests-menu-timings-total").getAttribute("tooltiptext");
info("Displayed time: " + value);
info("Tooltip time: " + tooltip);
ok(~~(value.match(/[0-9]+/)) >= 0, "The displayed time is incorrect.");
ok(~~(tooltip.match(/[0-9]+/)) >= 0, "The tooltip time is incorrect.");
ok(~~(value.match(/[0-9]+/)) >= 0, "The displayed time is correct.");
ok(~~(tooltip.match(/[0-9]+/)) >= 0, "The tooltip time is correct.");
}
if (visibleIndex != -1) {
if (visibleIndex % 2 == 0) {
ok(aRequestItem.target.hasAttribute("even"),
"Unexpected 'even' attribute for " + aRequestItem.value);
aRequestItem.value + " should have 'even' attribute.");
ok(!aRequestItem.target.hasAttribute("odd"),
"Unexpected 'odd' attribute for " + aRequestItem.value);
aRequestItem.value + " shouldn't have 'odd' attribute.");
} else {
ok(!aRequestItem.target.hasAttribute("even"),
"Unexpected 'even' attribute for " + aRequestItem.value);
aRequestItem.value + " shouldn't have 'even' attribute.");
ok(aRequestItem.target.hasAttribute("odd"),
"Unexpected 'odd' attribute for " + aRequestItem.value);
aRequestItem.value + " should have 'odd' attribute.");
}
}
}

View File

@ -3,11 +3,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cu = Components.utils;
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
devtools.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
devtools.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm", "Task");
const loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
let EventUtils = {};
loader.loadSubScript("chrome://marionette/content/EventUtils.js", EventUtils);
addMessageListener("devtools:test:history", function ({ data }) {
content.history[data.direction]();
@ -189,6 +192,55 @@ addMessageListener("devtools:test:setAttribute", function(msg) {
sendAsyncMessage("devtools:test:setAttribute");
});
/**
* Synthesize a mouse event on an element. This handler doesn't send a message
* back. Consumers should listen to specific events on the inspector/highlighter
* to know when the event got synthesized.
* @param {Object} msg The msg.data part expects the following properties:
* - {Number} x
* - {Number} y
* - {Boolean} center If set to true, x/y will be ignored and
* synthesizeMouseAtCenter will be used instead
* - {Object} options Other event options
* - {String} selector An optional selector that will be used to find the node to
* synthesize the event on, if msg.objects doesn't contain the CPOW.
* The msg.objects part should be the element.
* @param {Object} data Event detail properties:
*/
addMessageListener("Test:SynthesizeMouse", function(msg) {
let {x, y, center, options, selector} = msg.data;
let {node} = msg.objects;
if (!node && selector) {
node = superQuerySelector(selector);
}
if (center) {
EventUtils.synthesizeMouseAtCenter(node, options, node.ownerDocument.defaultView);
} else {
EventUtils.synthesizeMouse(node, x, y, options, node.ownerDocument.defaultView);
}
// Most consumers won't need to listen to this message, unless they want to
// wait for the mouse event to be synthesized and don't have another event
// to listen to instead.
sendAsyncMessage("Test:SynthesizeMouse");
});
/**
* Synthesize a key event for an element. This handler doesn't send a message
* back. Consumers should listen to specific events on the inspector/highlighter
* to know when the event got synthesized.
* @param {Object} msg The msg.data part expects the following properties:
* - {String} key
* - {Object} options
*/
addMessageListener("Test:SynthesizeKey", function(msg) {
let {key, options} = msg.data;
EventUtils.synthesizeKey(key, options, content);
});
/**
* Like document.querySelector but can go into iframes too.
* ".container iframe || .sub-container div" will first try to find the node

View File

@ -307,7 +307,6 @@ skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug intermittent)
[browser_webconsole_certificate_messages.js]
skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
[browser_webconsole_show_subresource_security_errors.js]
skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
[browser_webconsole_cached_autocomplete.js]
[browser_webconsole_change_font_size.js]
[browser_webconsole_chrome.js]

View File

@ -3,37 +3,37 @@
* 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 "AnimationPlayer.h"
#include "Animation.h"
#include "AnimationUtils.h"
#include "mozilla/dom/AnimationPlayerBinding.h"
#include "mozilla/dom/AnimationBinding.h"
#include "mozilla/AutoRestore.h"
#include "AnimationCommon.h" // For AnimationPlayerCollection,
#include "AnimationCommon.h" // For AnimationCollection,
// CommonAnimationManager
#include "nsIDocument.h" // For nsIDocument
#include "nsIPresShell.h" // For nsIPresShell
#include "nsLayoutUtils.h" // For PostRestyleEvent (remove after bug 1073336)
#include "PendingPlayerTracker.h" // For PendingPlayerTracker
#include "PendingAnimationTracker.h" // For PendingAnimationTracker
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationPlayer, mTimeline,
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Animation, mTimeline,
mEffect, mReady, mFinished)
NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationPlayer)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationPlayer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationPlayer)
NS_IMPL_CYCLE_COLLECTING_ADDREF(Animation)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Animation)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Animation)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
AnimationPlayer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
Animation::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return dom::AnimationPlayerBinding::Wrap(aCx, this, aGivenProto);
return dom::AnimationBinding::Wrap(aCx, this, aGivenProto);
}
void
AnimationPlayer::SetStartTime(const Nullable<TimeDuration>& aNewStartTime)
Animation::SetStartTime(const Nullable<TimeDuration>& aNewStartTime)
{
#if 1
// Bug 1096776: once we support inactive/missing timelines we'll want to take
@ -74,7 +74,7 @@ AnimationPlayer::SetStartTime(const Nullable<TimeDuration>& aNewStartTime)
}
Nullable<TimeDuration>
AnimationPlayer::GetCurrentTime() const
Animation::GetCurrentTime() const
{
Nullable<TimeDuration> result;
if (!mHoldTime.IsNull()) {
@ -94,7 +94,7 @@ AnimationPlayer::GetCurrentTime() const
// Implements http://w3c.github.io/web-animations/#silently-set-the-current-time
void
AnimationPlayer::SilentlySetCurrentTime(const TimeDuration& aSeekTime)
Animation::SilentlySetCurrentTime(const TimeDuration& aSeekTime)
{
if (!mHoldTime.IsNull() ||
!mTimeline ||
@ -115,7 +115,7 @@ AnimationPlayer::SilentlySetCurrentTime(const TimeDuration& aSeekTime)
// Implements http://w3c.github.io/web-animations/#set-the-current-time
void
AnimationPlayer::SetCurrentTime(const TimeDuration& aSeekTime)
Animation::SetCurrentTime(const TimeDuration& aSeekTime)
{
SilentlySetCurrentTime(aSeekTime);
@ -132,7 +132,7 @@ AnimationPlayer::SetCurrentTime(const TimeDuration& aSeekTime)
}
void
AnimationPlayer::SetPlaybackRate(double aPlaybackRate)
Animation::SetPlaybackRate(double aPlaybackRate)
{
Nullable<TimeDuration> previousTime = GetCurrentTime();
mPlaybackRate = aPlaybackRate;
@ -144,7 +144,7 @@ AnimationPlayer::SetPlaybackRate(double aPlaybackRate)
}
void
AnimationPlayer::SilentlySetPlaybackRate(double aPlaybackRate)
Animation::SilentlySetPlaybackRate(double aPlaybackRate)
{
Nullable<TimeDuration> previousTime = GetCurrentTime();
mPlaybackRate = aPlaybackRate;
@ -156,7 +156,7 @@ AnimationPlayer::SilentlySetPlaybackRate(double aPlaybackRate)
}
AnimationPlayState
AnimationPlayer::PlayState() const
Animation::PlayState() const
{
if (mPendingState != PendingState::NotPending) {
return AnimationPlayState::Pending;
@ -190,7 +190,7 @@ CreatePromise(DocumentTimeline* aTimeline, ErrorResult& aRv)
}
Promise*
AnimationPlayer::GetReady(ErrorResult& aRv)
Animation::GetReady(ErrorResult& aRv)
{
if (!mReady) {
mReady = CreatePromise(mTimeline, aRv); // Lazily create on demand
@ -204,7 +204,7 @@ AnimationPlayer::GetReady(ErrorResult& aRv)
}
Promise*
AnimationPlayer::GetFinished(ErrorResult& aRv)
Animation::GetFinished(ErrorResult& aRv)
{
if (!mFinished) {
mFinished = CreatePromise(mTimeline, aRv); // Lazily create on demand
@ -218,14 +218,14 @@ AnimationPlayer::GetFinished(ErrorResult& aRv)
}
void
AnimationPlayer::Play(LimitBehavior aLimitBehavior)
Animation::Play(LimitBehavior aLimitBehavior)
{
DoPlay(aLimitBehavior);
PostUpdate();
}
void
AnimationPlayer::Pause()
Animation::Pause()
{
// TODO: The DoPause() call should not be synchronous (bug 1109390). See
// http://w3c.github.io/web-animations/#pausing-an-animation-section
@ -234,25 +234,25 @@ AnimationPlayer::Pause()
}
Nullable<double>
AnimationPlayer::GetStartTimeAsDouble() const
Animation::GetStartTimeAsDouble() const
{
return AnimationUtils::TimeDurationToDouble(mStartTime);
}
void
AnimationPlayer::SetStartTimeAsDouble(const Nullable<double>& aStartTime)
Animation::SetStartTimeAsDouble(const Nullable<double>& aStartTime)
{
return SetStartTime(AnimationUtils::DoubleToTimeDuration(aStartTime));
}
Nullable<double>
AnimationPlayer::GetCurrentTimeAsDouble() const
Animation::GetCurrentTimeAsDouble() const
{
return AnimationUtils::TimeDurationToDouble(GetCurrentTime());
}
void
AnimationPlayer::SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime,
Animation::SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime,
ErrorResult& aRv)
{
if (aCurrentTime.IsNull()) {
@ -266,7 +266,7 @@ AnimationPlayer::SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime,
}
void
AnimationPlayer::SetEffect(KeyframeEffectReadonly* aEffect)
Animation::SetEffect(KeyframeEffectReadonly* aEffect)
{
if (mEffect) {
mEffect->SetParentTime(Nullable<TimeDuration>());
@ -279,7 +279,7 @@ AnimationPlayer::SetEffect(KeyframeEffectReadonly* aEffect)
}
void
AnimationPlayer::Tick()
Animation::Tick()
{
// Since we are not guaranteed to get only one call per refresh driver tick,
// it's possible that mPendingReadyTime is set to a time in the future.
@ -292,9 +292,9 @@ AnimationPlayer::Tick()
mPendingReadyTime.SetNull();
}
if (IsPossiblyOrphanedPendingPlayer()) {
if (IsPossiblyOrphanedPendingAnimation()) {
MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(),
"Orphaned pending players should have an active timeline");
"Orphaned pending animtaions should have an active timeline");
FinishPendingAt(mTimeline->GetCurrentTime().Value());
}
@ -302,25 +302,26 @@ AnimationPlayer::Tick()
}
void
AnimationPlayer::TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime)
Animation::TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime)
{
// Normally we expect the play state to be pending but it's possible that,
// due to the handling of possibly orphaned players in Tick(), this player got
// started whilst still being in another document's pending player map.
// due to the handling of possibly orphaned animations in Tick(), this
// animation got started whilst still being in another document's pending
// animation map.
if (PlayState() != AnimationPlayState::Pending) {
return;
}
// If aReadyTime.IsNull() we'll detect this in Tick() where we check for
// orphaned players and trigger this animation anyway
// orphaned animations and trigger this animation anyway
mPendingReadyTime = aReadyTime;
}
void
AnimationPlayer::TriggerNow()
Animation::TriggerNow()
{
MOZ_ASSERT(PlayState() == AnimationPlayState::Pending,
"Expected to start a pending player");
"Expected to start a pending animation");
MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(),
"Expected an active timeline");
@ -328,7 +329,7 @@ AnimationPlayer::TriggerNow()
}
Nullable<TimeDuration>
AnimationPlayer::GetCurrentOrPendingStartTime() const
Animation::GetCurrentOrPendingStartTime() const
{
Nullable<TimeDuration> result;
@ -349,7 +350,7 @@ AnimationPlayer::GetCurrentOrPendingStartTime() const
}
void
AnimationPlayer::Cancel()
Animation::Cancel()
{
if (mPendingState != PendingState::NotPending) {
CancelPendingTasks();
@ -371,7 +372,7 @@ AnimationPlayer::Cancel()
}
void
AnimationPlayer::UpdateRelevance()
Animation::UpdateRelevance()
{
bool wasRelevant = mIsRelevant;
mIsRelevant = HasCurrentEffect() || IsInEffect();
@ -385,7 +386,7 @@ AnimationPlayer::UpdateRelevance()
}
bool
AnimationPlayer::CanThrottle() const
Animation::CanThrottle() const
{
if (!mEffect ||
mEffect->IsFinishedTransition() ||
@ -410,9 +411,9 @@ AnimationPlayer::CanThrottle() const
}
void
AnimationPlayer::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties,
bool& aNeedsRefreshes)
Animation::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties,
bool& aNeedsRefreshes)
{
if (!mEffect || mEffect->IsFinishedTransition()) {
return;
@ -493,7 +494,7 @@ AnimationPlayer::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
}
void
AnimationPlayer::DoPlay(LimitBehavior aLimitBehavior)
Animation::DoPlay(LimitBehavior aLimitBehavior)
{
bool abortedPause = mPendingState == PendingState::PausePending;
@ -548,7 +549,7 @@ AnimationPlayer::DoPlay(LimitBehavior aLimitBehavior)
return;
}
PendingPlayerTracker* tracker = doc->GetOrCreatePendingPlayerTracker();
PendingAnimationTracker* tracker = doc->GetOrCreatePendingAnimationTracker();
tracker->AddPlayPending(*this);
// We may have updated the current time when we set the hold time above.
@ -556,7 +557,7 @@ AnimationPlayer::DoPlay(LimitBehavior aLimitBehavior)
}
void
AnimationPlayer::DoPause()
Animation::DoPause()
{
if (IsPausedOrPausing()) {
return;
@ -586,22 +587,22 @@ AnimationPlayer::DoPause()
return;
}
PendingPlayerTracker* tracker = doc->GetOrCreatePendingPlayerTracker();
PendingAnimationTracker* tracker = doc->GetOrCreatePendingAnimationTracker();
tracker->AddPausePending(*this);
UpdateFinishedState();
}
void
AnimationPlayer::ResumeAt(const TimeDuration& aReadyTime)
Animation::ResumeAt(const TimeDuration& aReadyTime)
{
// This method is only expected to be called for a player that is
// This method is only expected to be called for an animation that is
// waiting to play. We can easily adapt it to handle other states
// but it's currently not necessary.
MOZ_ASSERT(mPendingState == PendingState::PlayPending,
"Expected to resume a play-pending player");
"Expected to resume a play-pending animation");
MOZ_ASSERT(mHoldTime.IsNull() != mStartTime.IsNull(),
"A player in the play-pending state should have either a"
"An animation in the play-pending state should have either a"
" resolved hold time or resolved start time (but not both)");
// If we aborted a pending pause operation we will already have a start time
@ -625,10 +626,10 @@ AnimationPlayer::ResumeAt(const TimeDuration& aReadyTime)
}
void
AnimationPlayer::PauseAt(const TimeDuration& aReadyTime)
Animation::PauseAt(const TimeDuration& aReadyTime)
{
MOZ_ASSERT(mPendingState == PendingState::PausePending,
"Expected to pause a pause-pending player");
"Expected to pause a pause-pending animation");
if (!mStartTime.IsNull()) {
mHoldTime.SetValue((aReadyTime - mStartTime.Value())
@ -645,7 +646,7 @@ AnimationPlayer::PauseAt(const TimeDuration& aReadyTime)
}
void
AnimationPlayer::UpdateTiming()
Animation::UpdateTiming()
{
// We call UpdateFinishedState before UpdateEffect because the former
// can change the current time, which is used by the latter.
@ -654,7 +655,7 @@ AnimationPlayer::UpdateTiming()
}
void
AnimationPlayer::UpdateFinishedState(bool aSeekFlag)
Animation::UpdateFinishedState(bool aSeekFlag)
{
Nullable<TimeDuration> currentTime = GetCurrentTime();
TimeDuration effectEnd = TimeDuration(EffectEnd());
@ -697,6 +698,9 @@ AnimationPlayer::UpdateFinishedState(bool aSeekFlag)
} else if (!currentFinishedState && mIsPreviousStateFinished) {
// Clear finished promise. We'll create a new one lazily.
mFinished = nullptr;
if (mEffect->AsTransition()) {
mEffect->SetIsFinishedTransition(false);
}
}
mIsPreviousStateFinished = currentFinishedState;
// We must recalculate the current time to take account of any mHoldTime
@ -705,7 +709,7 @@ AnimationPlayer::UpdateFinishedState(bool aSeekFlag)
}
void
AnimationPlayer::UpdateEffect()
Animation::UpdateEffect()
{
if (mEffect) {
mEffect->SetParentTime(GetCurrentTime());
@ -714,7 +718,7 @@ AnimationPlayer::UpdateEffect()
}
void
AnimationPlayer::FlushStyle() const
Animation::FlushStyle() const
{
nsIDocument* doc = GetRenderedDocument();
if (doc) {
@ -723,16 +727,16 @@ AnimationPlayer::FlushStyle() const
}
void
AnimationPlayer::PostUpdate()
Animation::PostUpdate()
{
AnimationPlayerCollection* collection = GetCollection();
AnimationCollection* collection = GetCollection();
if (collection) {
collection->NotifyPlayerUpdated();
collection->NotifyAnimationUpdated();
}
}
void
AnimationPlayer::CancelPendingTasks()
Animation::CancelPendingTasks()
{
if (mPendingState == PendingState::NotPending) {
return;
@ -740,7 +744,7 @@ AnimationPlayer::CancelPendingTasks()
nsIDocument* doc = GetRenderedDocument();
if (doc) {
PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker();
PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker();
if (tracker) {
if (mPendingState == PendingState::PlayPending) {
tracker->RemovePlayPending(*this);
@ -755,7 +759,7 @@ AnimationPlayer::CancelPendingTasks()
}
bool
AnimationPlayer::IsFinished() const
Animation::IsFinished() const
{
// Unfortunately there's some weirdness in the spec at the moment where if
// you're finished and paused, the playState is paused. This prevents us
@ -768,7 +772,7 @@ AnimationPlayer::IsFinished() const
}
bool
AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const
Animation::IsPossiblyOrphanedPendingAnimation() const
{
// Check if we are pending but might never start because we are not being
// tracked.
@ -780,9 +784,9 @@ AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const
// (note that for the case of our effect changing we should handle
// that in SetEffect)
// * We started playing but our timeline became inactive.
// In this case the pending player tracker will drop us from its hashmap
// In this case the pending animation tracker will drop us from its hashmap
// when we have been painted.
// * When we started playing we couldn't find a PendingPlayerTracker to
// * When we started playing we couldn't find a PendingAnimationTracker to
// register with (perhaps the effect had no document) so we simply
// set mPendingState in DoPlay and relied on this method to catch us on the
// next tick.
@ -805,7 +809,7 @@ AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const
}
// If we have no rendered document, or we're not in our rendered document's
// PendingPlayerTracker then there's a good chance no one is tracking us.
// PendingAnimationTracker then there's a good chance no one is tracking us.
//
// If we're wrong and another document is tracking us then, at worst, we'll
// simply start/pause the animation one tick too soon. That's better than
@ -815,14 +819,14 @@ AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const
return false;
}
PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker();
PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker();
return !tracker ||
(!tracker->IsWaitingToPlay(*this) &&
!tracker->IsWaitingToPause(*this));
}
StickyTimeDuration
AnimationPlayer::EffectEnd() const
Animation::EffectEnd() const
{
if (!mEffect) {
return StickyTimeDuration(0);
@ -833,7 +837,7 @@ AnimationPlayer::EffectEnd() const
}
nsIDocument*
AnimationPlayer::GetRenderedDocument() const
Animation::GetRenderedDocument() const
{
if (!mEffect) {
return nullptr;
@ -850,7 +854,7 @@ AnimationPlayer::GetRenderedDocument() const
}
nsPresContext*
AnimationPlayer::GetPresContext() const
Animation::GetPresContext() const
{
nsIDocument* doc = GetRenderedDocument();
if (!doc) {
@ -863,20 +867,21 @@ AnimationPlayer::GetPresContext() const
return shell->GetPresContext();
}
AnimationPlayerCollection*
AnimationPlayer::GetCollection() const
AnimationCollection*
Animation::GetCollection() const
{
css::CommonAnimationManager* manager = GetAnimationManager();
if (!manager) {
return nullptr;
}
MOZ_ASSERT(mEffect, "A player with an animation manager must have an effect");
MOZ_ASSERT(mEffect,
"An animation with an animation manager must have an effect");
Element* targetElement;
nsCSSPseudoElements::Type targetPseudoType;
mEffect->GetTarget(targetElement, targetPseudoType);
MOZ_ASSERT(targetElement,
"A player with an animation manager must have a target");
"An animation with an animation manager must have a target");
return manager->GetAnimations(targetElement, targetPseudoType, false);
}

View File

@ -3,14 +3,14 @@
* 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_AnimationPlayer_h
#define mozilla_dom_AnimationPlayer_h
#ifndef mozilla_dom_Animation_h
#define mozilla_dom_Animation_h
#include "nsWrapperCache.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
#include "mozilla/dom/AnimationPlayerBinding.h" // for AnimationPlayState
#include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState
#include "mozilla/dom/DocumentTimeline.h" // for DocumentTimeline
#include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadonly
#include "mozilla/dom/Promise.h" // for Promise
@ -33,25 +33,26 @@ class nsIDocument;
class nsPresContext;
namespace mozilla {
struct AnimationPlayerCollection;
struct AnimationCollection;
namespace css {
class AnimValuesStyleRule;
class CommonAnimationManager;
} // namespace css
class CSSAnimationPlayer;
class CSSTransitionPlayer;
class CSSAnimation;
class CSSTransition;
namespace dom {
class AnimationPlayer : public nsISupports,
public nsWrapperCache
class Animation
: public nsISupports
, public nsWrapperCache
{
protected:
virtual ~AnimationPlayer() {}
virtual ~Animation() {}
public:
explicit AnimationPlayer(DocumentTimeline* aTimeline)
explicit Animation(DocumentTimeline* aTimeline)
: mTimeline(aTimeline)
, mPlaybackRate(1.0)
, mPendingState(PendingState::NotPending)
@ -63,14 +64,14 @@ public:
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationPlayer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Animation)
DocumentTimeline* GetParentObject() const { return mTimeline; }
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
virtual CSSAnimationPlayer* AsCSSAnimationPlayer() { return nullptr; }
virtual CSSTransitionPlayer* AsCSSTransitionPlayer() { return nullptr; }
virtual CSSAnimation* AsCSSAnimation() { return nullptr; }
virtual CSSTransition* AsCSSTransition() { return nullptr; }
// Flag to pass to DoPlay to indicate that it should not carry out finishing
// behavior (reset the current time to the beginning of the active duration).
@ -79,7 +80,7 @@ public:
Continue = 1
};
// AnimationPlayer methods
// Animation methods
KeyframeEffectReadonly* GetEffect() const { return mEffect; }
DocumentTimeline* Timeline() const { return mTimeline; }
Nullable<TimeDuration> GetStartTime() const { return mStartTime; }
@ -97,7 +98,7 @@ public:
virtual void Pause();
bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; }
// Wrapper functions for AnimationPlayer DOM methods when called
// Wrapper functions for Animation DOM methods when called
// from script. We often use the same methods internally and from
// script but when called from script we (or one of our subclasses) perform
// extra steps such as flushing style or converting the return type.
@ -110,31 +111,31 @@ public:
virtual void PlayFromJS() { Play(LimitBehavior::AutoRewind); }
// PauseFromJS is currently only here for symmetry with PlayFromJS but
// in future we will likely have to flush style in
// CSSAnimationPlayer::PauseFromJS so we leave it for now.
// CSSAnimation::PauseFromJS so we leave it for now.
void PauseFromJS() { Pause(); }
void SetEffect(KeyframeEffectReadonly* aEffect);
void Tick();
/**
* Set the time to use for starting or pausing a pending player.
* Set the time to use for starting or pausing a pending animation.
*
* Typically, when a player is played, it does not start immediately but is
* added to a table of pending players on the document of its effect.
* Typically, when an animation is played, it does not start immediately but
* is added to a table of pending animations on the document of its effect.
* In the meantime it sets its hold time to the time from which playback
* should begin.
*
* When the document finishes painting, any pending players in its table
* When the document finishes painting, any pending animations in its table
* are marked as being ready to start by calling StartOnNextTick.
* The moment when the paint completed is also recorded, converted to a
* timeline time, and passed to StartOnTick. This is so that when these
* players do start, they can be timed from the point when painting
* animations do start, they can be timed from the point when painting
* completed.
*
* After calling TriggerOnNextTick, players remain in the pending state until
* the next refresh driver tick. At that time they transition out of the
* pending state using the time passed to TriggerOnNextTick as the effective
* time at which they resumed.
* After calling TriggerOnNextTick, animations remain in the pending state
* until the next refresh driver tick. At that time they transition out of
* the pending state using the time passed to TriggerOnNextTick as the
* effective time at which they resumed.
*
* This approach means that any setup time required for performing the
* initial paint of an animation such as layerization is not deducted from
@ -144,14 +145,14 @@ public:
*
* Furthermore:
*
* - Starting the player immediately when painting finishes is problematic
* because the start time of the player will be ahead of its timeline
* - Starting the animation immediately when painting finishes is problematic
* because the start time of the animation will be ahead of its timeline
* (since the timeline time is based on the refresh driver time).
* That's a problem because the player is playing but its timing suggests
* it starts in the future. We could update the timeline to match the start
* time of the player but then we'd also have to update the timing and style
* of all animations connected to that timeline or else be stuck in an
* inconsistent state until the next refresh driver tick.
* That's a problem because the animation is playing but its timing
* suggests it starts in the future. We could update the timeline to match
* the start time of the animation but then we'd also have to update the
* timing and style of all animations connected to that timeline or else be
* stuck in an inconsistent state until the next refresh driver tick.
*
* - If we simply use the refresh driver time on its next tick, the lag
* between triggering an animation and its effective start is unacceptably
@ -164,19 +165,19 @@ public:
* animations could be paused immediately, we do it asynchronously for
* consistency and so that animations paused together end up in step.
*
* Note that the caller of this method is responsible for removing the player
* from any PendingPlayerTracker it may have been added to.
* Note that the caller of this method is responsible for removing the
* animation from any PendingAnimationTracker it may have been added to.
*/
void TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime);
// Testing only: Start or pause a pending player using the current timeline
// Testing only: Start or pause a pending animation using the current timeline
// time. This is used to support existing tests that expect animations to
// begin immediately. Ideally we would rewrite the those tests and get rid of
// this method, but there are a lot of them.
//
// As with TriggerOnNextTick, the caller of this method is responsible for
// removing the player from any PendingPlayerTracker it may have been added
// to.
// removing the animation from any PendingAnimationTracker it may have been
// added to.
void TriggerNow();
/**
@ -253,11 +254,11 @@ public:
// running on the compositor).
bool CanThrottle() const;
// Updates |aStyleRule| with the animation values of this player's effect,
// Updates |aStyleRule| with the animation values of this animation's effect,
// if any.
// Any properties already contained in |aSetProperties| are not changed. Any
// properties that are changed are added to |aSetProperties|.
// |aNeedsRefreshes| will be set to true if this player expects to update
// |aNeedsRefreshes| will be set to true if this animation expects to update
// the style rule on the next refresh driver tick as well (because it
// is running and has an effect to sample).
void ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
@ -286,7 +287,7 @@ protected:
void FlushStyle() const;
void PostUpdate();
/**
* Remove this player from the pending player tracker and reset
* Remove this animation from the pending animation tracker and reset
* mPendingState as necessary. The caller is responsible for resolving or
* aborting the mReady promise as necessary.
*/
@ -294,21 +295,21 @@ protected:
bool IsFinished() const;
bool IsPossiblyOrphanedPendingPlayer() const;
bool IsPossiblyOrphanedPendingAnimation() const;
StickyTimeDuration EffectEnd() const;
nsIDocument* GetRenderedDocument() const;
nsPresContext* GetPresContext() const;
virtual css::CommonAnimationManager* GetAnimationManager() const = 0;
AnimationPlayerCollection* GetCollection() const;
AnimationCollection* GetCollection() const;
nsRefPtr<DocumentTimeline> mTimeline;
nsRefPtr<KeyframeEffectReadonly> mEffect;
// The beginning of the delay period.
Nullable<TimeDuration> mStartTime; // Timeline timescale
Nullable<TimeDuration> mHoldTime; // Player timescale
Nullable<TimeDuration> mHoldTime; // Animation timescale
Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
Nullable<TimeDuration> mPreviousCurrentTime; // Player timescale
Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
double mPlaybackRate;
// A Promise that is replaced on each call to Play() (and in future Pause())
@ -324,11 +325,11 @@ protected:
// See http://w3c.github.io/web-animations/#current-finished-promise
nsRefPtr<Promise> mFinished;
// Indicates if the player is in the pending state (and what state it is
// Indicates if the animation is in the pending state (and what state it is
// waiting to enter when it finished pending). We use this rather than
// checking if this player is tracked by a PendingPlayerTracker because the
// player will continue to be pending even after it has been removed from the
// PendingPlayerTracker while it is waiting for the next tick
// checking if this animation is tracked by a PendingAnimationTracker because
// the animation will continue to be pending even after it has been removed
// from the PendingAnimationTracker while it is waiting for the next tick
// (see TriggerOnNextTick for details).
enum class PendingState { NotPending, PlayPending, PausePending };
PendingState mPendingState;
@ -346,4 +347,4 @@ protected:
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_AnimationPlayer_h
#endif // mozilla_dom_Animation_h

View File

@ -234,10 +234,10 @@ KeyframeEffectReadonly::ActiveDuration(const AnimationTiming& aTiming)
// http://w3c.github.io/web-animations/#in-play
bool
KeyframeEffectReadonly::IsInPlay(const AnimationPlayer& aPlayer) const
KeyframeEffectReadonly::IsInPlay(const Animation& aAnimation) const
{
if (IsFinishedTransition() ||
aPlayer.PlayState() == AnimationPlayState::Finished) {
aAnimation.PlayState() == AnimationPlayState::Finished) {
return false;
}
@ -246,10 +246,10 @@ KeyframeEffectReadonly::IsInPlay(const AnimationPlayer& aPlayer) const
// http://w3c.github.io/web-animations/#current
bool
KeyframeEffectReadonly::IsCurrent(const AnimationPlayer& aPlayer) const
KeyframeEffectReadonly::IsCurrent(const Animation& aAnimation) const
{
if (IsFinishedTransition() ||
aPlayer.PlayState() == AnimationPlayState::Finished) {
aAnimation.PlayState() == AnimationPlayState::Finished) {
return false;
}
@ -325,7 +325,7 @@ KeyframeEffectReadonly::ComposeStyle(
"incorrect last to key");
if (aSetProperties.HasProperty(prop.mProperty)) {
// Animations are composed by AnimationPlayerCollection by iterating
// Animations are composed by AnimationCollection by iterating
// from the last animation to first. For animations targetting the
// same property, the later one wins. So if this property is already set,
// we should not override it.

View File

@ -300,14 +300,14 @@ public:
return mIsFinishedTransition;
}
void SetIsFinishedTransition() {
void SetIsFinishedTransition(bool aIsFinished) {
MOZ_ASSERT(AsTransition(),
"Calling SetIsFinishedTransition but it's not a transition");
mIsFinishedTransition = true;
mIsFinishedTransition = aIsFinished;
}
bool IsInPlay(const AnimationPlayer& aPlayer) const;
bool IsCurrent(const AnimationPlayer& aPlayer) const;
bool IsInPlay(const Animation& aAnimation) const;
bool IsCurrent(const Animation& aAnimation) const;
bool IsInEffect() const;
const AnimationProperty*

View File

@ -3,7 +3,7 @@
* 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 "PendingPlayerTracker.h"
#include "PendingAnimationTracker.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "nsIFrame.h"
@ -13,19 +13,19 @@ using namespace mozilla;
namespace mozilla {
NS_IMPL_CYCLE_COLLECTION(PendingPlayerTracker,
NS_IMPL_CYCLE_COLLECTION(PendingAnimationTracker,
mPlayPendingSet,
mPausePendingSet,
mDocument)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PendingPlayerTracker, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PendingPlayerTracker, Release)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PendingAnimationTracker, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PendingAnimationTracker, Release)
void
PendingPlayerTracker::AddPending(dom::AnimationPlayer& aPlayer,
AnimationPlayerSet& aSet)
PendingAnimationTracker::AddPending(dom::Animation& aAnimation,
AnimationSet& aSet)
{
aSet.PutEntry(&aPlayer);
aSet.PutEntry(&aAnimation);
// Schedule a paint. Otherwise animations that don't trigger a paint by
// themselves (e.g. CSS animations with an empty keyframes rule) won't
@ -34,70 +34,70 @@ PendingPlayerTracker::AddPending(dom::AnimationPlayer& aPlayer,
}
void
PendingPlayerTracker::RemovePending(dom::AnimationPlayer& aPlayer,
AnimationPlayerSet& aSet)
PendingAnimationTracker::RemovePending(dom::Animation& aAnimation,
AnimationSet& aSet)
{
aSet.RemoveEntry(&aPlayer);
aSet.RemoveEntry(&aAnimation);
}
bool
PendingPlayerTracker::IsWaiting(const dom::AnimationPlayer& aPlayer,
const AnimationPlayerSet& aSet) const
PendingAnimationTracker::IsWaiting(const dom::Animation& aAnimation,
const AnimationSet& aSet) const
{
return aSet.Contains(const_cast<dom::AnimationPlayer*>(&aPlayer));
return aSet.Contains(const_cast<dom::Animation*>(&aAnimation));
}
PLDHashOperator
TriggerPlayerAtTime(nsRefPtrHashKey<dom::AnimationPlayer>* aKey,
TriggerAnimationAtTime(nsRefPtrHashKey<dom::Animation>* aKey,
void* aReadyTime)
{
dom::AnimationPlayer* player = aKey->GetKey();
dom::DocumentTimeline* timeline = player->Timeline();
dom::Animation* animation = aKey->GetKey();
dom::DocumentTimeline* timeline = animation->Timeline();
// When the timeline's refresh driver is under test control, its values
// have no correspondance to wallclock times so we shouldn't try to convert
// aReadyTime (which is a wallclock time) to a timeline value. Instead, the
// animation player will be started/paused when the refresh driver is next
// advanced since this will trigger a call to TriggerPendingPlayersNow.
// animation will be started/paused when the refresh driver is next
// advanced since this will trigger a call to TriggerPendingAnimationsNow.
if (timeline->IsUnderTestControl()) {
return PL_DHASH_NEXT;
}
Nullable<TimeDuration> readyTime =
timeline->ToTimelineTime(*static_cast<const TimeStamp*>(aReadyTime));
player->TriggerOnNextTick(readyTime);
animation->TriggerOnNextTick(readyTime);
return PL_DHASH_REMOVE;
}
void
PendingPlayerTracker::TriggerPendingPlayersOnNextTick(const TimeStamp&
PendingAnimationTracker::TriggerPendingAnimationsOnNextTick(const TimeStamp&
aReadyTime)
{
mPlayPendingSet.EnumerateEntries(TriggerPlayerAtTime,
mPlayPendingSet.EnumerateEntries(TriggerAnimationAtTime,
const_cast<TimeStamp*>(&aReadyTime));
mPausePendingSet.EnumerateEntries(TriggerPlayerAtTime,
mPausePendingSet.EnumerateEntries(TriggerAnimationAtTime,
const_cast<TimeStamp*>(&aReadyTime));
}
PLDHashOperator
TriggerPlayerNow(nsRefPtrHashKey<dom::AnimationPlayer>* aKey, void*)
TriggerAnimationNow(nsRefPtrHashKey<dom::Animation>* aKey, void*)
{
aKey->GetKey()->TriggerNow();
return PL_DHASH_NEXT;
}
void
PendingPlayerTracker::TriggerPendingPlayersNow()
PendingAnimationTracker::TriggerPendingAnimationsNow()
{
mPlayPendingSet.EnumerateEntries(TriggerPlayerNow, nullptr);
mPlayPendingSet.EnumerateEntries(TriggerAnimationNow, nullptr);
mPlayPendingSet.Clear();
mPausePendingSet.EnumerateEntries(TriggerPlayerNow, nullptr);
mPausePendingSet.EnumerateEntries(TriggerAnimationNow, nullptr);
mPausePendingSet.Clear();
}
void
PendingPlayerTracker::EnsurePaintIsScheduled()
PendingAnimationTracker::EnsurePaintIsScheduled()
{
if (!mDocument) {
return;

View File

@ -0,0 +1,83 @@
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* 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_PendingAnimationTracker_h
#define mozilla_dom_PendingAnimationTracker_h
#include "mozilla/dom/Animation.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDocument.h"
#include "nsTHashtable.h"
class nsIFrame;
namespace mozilla {
class PendingAnimationTracker final
{
public:
explicit PendingAnimationTracker(nsIDocument* aDocument)
: mDocument(aDocument)
{ }
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PendingAnimationTracker)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(PendingAnimationTracker)
void AddPlayPending(dom::Animation& aAnimation)
{
MOZ_ASSERT(!IsWaitingToPause(aAnimation),
"Animation is already waiting to pause");
AddPending(aAnimation, mPlayPendingSet);
}
void RemovePlayPending(dom::Animation& aAnimation)
{
RemovePending(aAnimation, mPlayPendingSet);
}
bool IsWaitingToPlay(const dom::Animation& aAnimation) const
{
return IsWaiting(aAnimation, mPlayPendingSet);
}
void AddPausePending(dom::Animation& aAnimation)
{
MOZ_ASSERT(!IsWaitingToPlay(aAnimation),
"Animation is already waiting to play");
AddPending(aAnimation, mPausePendingSet);
}
void RemovePausePending(dom::Animation& aAnimation)
{
RemovePending(aAnimation, mPausePendingSet);
}
bool IsWaitingToPause(const dom::Animation& aAnimation) const
{
return IsWaiting(aAnimation, mPausePendingSet);
}
void TriggerPendingAnimationsOnNextTick(const TimeStamp& aReadyTime);
void TriggerPendingAnimationsNow();
bool HasPendingAnimations() const {
return mPlayPendingSet.Count() > 0 || mPausePendingSet.Count() > 0;
}
private:
~PendingAnimationTracker() { }
void EnsurePaintIsScheduled();
typedef nsTHashtable<nsRefPtrHashKey<dom::Animation>> AnimationSet;
void AddPending(dom::Animation& aAnimation, AnimationSet& aSet);
void RemovePending(dom::Animation& aAnimation, AnimationSet& aSet);
bool IsWaiting(const dom::Animation& aAnimation,
const AnimationSet& aSet) const;
AnimationSet mPlayPendingSet;
AnimationSet mPausePendingSet;
nsCOMPtr<nsIDocument> mDocument;
};
} // namespace mozilla
#endif // mozilla_dom_PendingAnimationTracker_h

View File

@ -1,86 +0,0 @@
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* 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_PendingPlayerTracker_h
#define mozilla_dom_PendingPlayerTracker_h
#include "mozilla/dom/AnimationPlayer.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDocument.h"
#include "nsTHashtable.h"
class nsIFrame;
namespace mozilla {
class PendingPlayerTracker final
{
public:
explicit PendingPlayerTracker(nsIDocument* aDocument)
: mDocument(aDocument)
{ }
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PendingPlayerTracker)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(PendingPlayerTracker)
void AddPlayPending(dom::AnimationPlayer& aPlayer)
{
MOZ_ASSERT(!IsWaitingToPause(aPlayer),
"Player is already waiting to pause");
AddPending(aPlayer, mPlayPendingSet);
}
void RemovePlayPending(dom::AnimationPlayer& aPlayer)
{
RemovePending(aPlayer, mPlayPendingSet);
}
bool IsWaitingToPlay(const dom::AnimationPlayer& aPlayer) const
{
return IsWaiting(aPlayer, mPlayPendingSet);
}
void AddPausePending(dom::AnimationPlayer& aPlayer)
{
MOZ_ASSERT(!IsWaitingToPlay(aPlayer),
"Player is already waiting to play");
AddPending(aPlayer, mPausePendingSet);
}
void RemovePausePending(dom::AnimationPlayer& aPlayer)
{
RemovePending(aPlayer, mPausePendingSet);
}
bool IsWaitingToPause(const dom::AnimationPlayer& aPlayer) const
{
return IsWaiting(aPlayer, mPausePendingSet);
}
void TriggerPendingPlayersOnNextTick(const TimeStamp& aReadyTime);
void TriggerPendingPlayersNow();
bool HasPendingPlayers() const {
return mPlayPendingSet.Count() > 0 || mPausePendingSet.Count() > 0;
}
private:
~PendingPlayerTracker() { }
void EnsurePaintIsScheduled();
typedef nsTHashtable<nsRefPtrHashKey<dom::AnimationPlayer>>
AnimationPlayerSet;
void AddPending(dom::AnimationPlayer& aPlayer,
AnimationPlayerSet& aSet);
void RemovePending(dom::AnimationPlayer& aPlayer,
AnimationPlayerSet& aSet);
bool IsWaiting(const dom::AnimationPlayer& aPlayer,
const AnimationPlayerSet& aSet) const;
AnimationPlayerSet mPlayPendingSet;
AnimationPlayerSet mPausePendingSet;
nsCOMPtr<nsIDocument> mDocument;
};
} // namespace mozilla
#endif // mozilla_dom_PendingPlayerTracker_h

View File

@ -8,8 +8,8 @@ MOCHITEST_MANIFESTS += ['test/mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
EXPORTS.mozilla.dom += [
'Animation.h',
'AnimationEffectReadonly.h',
'AnimationPlayer.h',
'AnimationTimeline.h',
'DocumentTimeline.h',
'KeyframeEffect.h',
@ -17,16 +17,16 @@ EXPORTS.mozilla.dom += [
EXPORTS.mozilla += [
'AnimationUtils.h',
'PendingPlayerTracker.h',
'PendingAnimationTracker.h',
]
UNIFIED_SOURCES += [
'Animation.cpp',
'AnimationEffectReadonly.cpp',
'AnimationPlayer.cpp',
'AnimationTimeline.cpp',
'DocumentTimeline.cpp',
'KeyframeEffect.cpp',
'PendingPlayerTracker.cpp',
'PendingAnimationTracker.cpp',
]
FAIL_ON_WARNINGS = True

View File

@ -193,11 +193,10 @@ function EventWatcher(watchedNode, eventTypes)
// terms used in the Web Animations specification for specific phases of an
// animation. The terms can be found here:
//
// http://w3c.github.io/web-animations/#animation-node-phases-and-states
// https://w3c.github.io/web-animations/#animation-effect-phases-and-states
//
// Note the distinction between "player start time" and "animation start time".
// The former is the start of the start delay. The latter is the start of the
// active interval. (If there is no delay, they are the same.)
// Note the distinction between the "animation start time" which occurs before
// the start delay and the start of the active interval which occurs after it.
// Called when currentTime is set to zero (the beginning of the start delay).
function checkStateOnSettingCurrentTimeToZero(animation)

View File

@ -193,11 +193,10 @@ function EventWatcher(watchedNode, eventTypes)
// terms used in the Web Animations specification for specific phases of an
// animation. The terms can be found here:
//
// http://w3c.github.io/web-animations/#animation-node-phases-and-states
// https://w3c.github.io/web-animations/#animation-effect-phases-and-states
//
// Note the distinction between "player start time" and "animation start time".
// The former is the start of the start delay. The latter is the start of the
// active interval. (If there is no delay, they are the same.)
// Note the distinction between the "animation start time" which occurs before
// the start delay and the start of the active interval which occurs after it.
// Called when the ready Promise's callbacks should happen
function checkStateOnReadyPromiseResolved(animation)

View File

@ -183,11 +183,10 @@ function EventWatcher(watchedNode, eventTypes)
// terms used in the Web Animations specification for specific phases of an
// animation. The terms can be found here:
//
// http://w3c.github.io/web-animations/#animation-effect-phases-and-states
// https://w3c.github.io/web-animations/#animation-effect-phases-and-states
//
// Note the distinction between "player start time" and "animation start time".
// The former is the start of the start delay. The latter is the start of the
// active interval. (If there is no delay, they are the same.)
// Note the distinction between the "animation start time" which occurs before
// the start delay and the start of the active interval which occurs after it.
// Called when the ready Promise's callbacks should happen
function checkStateOnReadyPromiseResolved(animation)

View File

@ -4,22 +4,22 @@ support-files =
[css-animations/test_animations-dynamic-changes.html]
[css-animations/test_animation-pausing.html]
[css-animations/test_animation-player-currenttime.html]
[css-animations/test_animation-player-finished.html]
[css-animations/test_animation-player-playstate.html]
[css-animations/test_animation-player-ready.html]
[css-animations/test_animation-player-starttime.html]
[css-animations/test_animation-currenttime.html]
[css-animations/test_animation-finished.html]
[css-animations/test_animation-playstate.html]
[css-animations/test_animation-ready.html]
[css-animations/test_animation-starttime.html]
[css-animations/test_effect-name.html]
[css-animations/test_effect-target.html]
[css-animations/test_element-get-animation-players.html]
[css-animations/test_element-get-animations.html]
skip-if = buildapp == 'mulet'
[css-transitions/test_animation-pausing.html]
[css-transitions/test_animation-player-currenttime.html]
[css-transitions/test_animation-player-ready.html]
[css-transitions/test_animation-player-starttime.html]
[css-transitions/test_animation-currenttime.html]
[css-transitions/test_animation-ready.html]
[css-transitions/test_animation-starttime.html]
[css-transitions/test_effect-name.html]
[css-transitions/test_effect-target.html]
[css-transitions/test_element-get-animation-players.html]
[css-transitions/test_element-get-animations.html]
skip-if = buildapp == 'mulet'
[document-timeline/test_document-timeline.html]
[document-timeline/test_request_animation_frame.html]

View File

@ -1004,7 +1004,12 @@ MainProcessRunnable::Run()
case eFailedToReadMetadata: {
MOZ_ASSERT(NS_IsMainThread());
CacheMiss();
if (mOpenMode == eOpenForRead) {
CacheMiss();
return NS_OK;
}
Fail();
return NS_OK;
}

View File

@ -14,7 +14,7 @@
#include "AnimationCommon.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/AnimationPlayer.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Attr.h"
#include "nsDOMAttributeMap.h"
#include "nsIAtom.h"
@ -3186,7 +3186,7 @@ Element::MozRequestPointerLock()
}
void
Element::GetAnimations(nsTArray<nsRefPtr<AnimationPlayer> >& aAnimations)
Element::GetAnimations(nsTArray<nsRefPtr<Animation>>& aAnimations)
{
nsIDocument* doc = GetComposedDoc();
if (doc) {
@ -3197,18 +3197,18 @@ Element::GetAnimations(nsTArray<nsRefPtr<AnimationPlayer> >& aAnimations)
nsGkAtoms::animationsProperty };
for (size_t propIdx = 0; propIdx < MOZ_ARRAY_LENGTH(properties);
propIdx++) {
AnimationPlayerCollection* collection =
static_cast<AnimationPlayerCollection*>(
AnimationCollection* collection =
static_cast<AnimationCollection*>(
GetProperty(properties[propIdx]));
if (!collection) {
continue;
}
for (size_t playerIdx = 0;
playerIdx < collection->mPlayers.Length();
playerIdx++) {
AnimationPlayer* player = collection->mPlayers[playerIdx];
if (player->IsRelevant()) {
aAnimations.AppendElement(player);
for (size_t animIdx = 0;
animIdx < collection->mAnimations.Length();
animIdx++) {
Animation* anim = collection->mAnimations[animIdx];
if (anim->IsRelevant()) {
aAnimations.AppendElement(anim);
}
}
}

View File

@ -121,7 +121,7 @@ class EventStateManager;
namespace dom {
class AnimationPlayer;
class Animation;
class Link;
class UndoManager;
class DOMRect;
@ -808,7 +808,7 @@ public:
{
}
void GetAnimations(nsTArray<nsRefPtr<AnimationPlayer> >& aAnimations);
void GetAnimations(nsTArray<nsRefPtr<Animation>>& aAnimations);
NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
virtual void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);

View File

@ -14,7 +14,7 @@
#include "nsIDOMMutationEvent.h"
#include "nsTextFragment.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/dom/AnimationPlayer.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/KeyframeEffect.h"
nsAutoTArray<nsRefPtr<nsDOMMutationObserver>, 4>*
@ -325,10 +325,10 @@ void nsMutationReceiver::NodeWillBeDestroyed(const nsINode *aNode)
}
void
nsAnimationReceiver::RecordAnimationMutation(AnimationPlayer* aPlayer,
nsAnimationReceiver::RecordAnimationMutation(Animation* aAnimation,
AnimationMutation aMutationType)
{
KeyframeEffectReadonly* effect = aPlayer->GetEffect();
KeyframeEffectReadonly* effect = aAnimation->GetEffect();
if (!effect) {
return;
}
@ -350,13 +350,13 @@ nsAnimationReceiver::RecordAnimationMutation(AnimationPlayer* aPlayer,
switch (aMutationType) {
case eAnimationMutation_Added:
nsAutoAnimationMutationBatch::AnimationAdded(aPlayer);
nsAutoAnimationMutationBatch::AnimationAdded(aAnimation);
break;
case eAnimationMutation_Changed:
nsAutoAnimationMutationBatch::AnimationChanged(aPlayer);
nsAutoAnimationMutationBatch::AnimationChanged(aAnimation);
break;
case eAnimationMutation_Removed:
nsAutoAnimationMutationBatch::AnimationRemoved(aPlayer);
nsAutoAnimationMutationBatch::AnimationRemoved(aAnimation);
break;
}
@ -373,33 +373,33 @@ nsAnimationReceiver::RecordAnimationMutation(AnimationPlayer* aPlayer,
switch (aMutationType) {
case eAnimationMutation_Added:
m->mAddedAnimations.AppendElement(aPlayer);
m->mAddedAnimations.AppendElement(aAnimation);
break;
case eAnimationMutation_Changed:
m->mChangedAnimations.AppendElement(aPlayer);
m->mChangedAnimations.AppendElement(aAnimation);
break;
case eAnimationMutation_Removed:
m->mRemovedAnimations.AppendElement(aPlayer);
m->mRemovedAnimations.AppendElement(aAnimation);
break;
}
}
void
nsAnimationReceiver::AnimationAdded(AnimationPlayer* aPlayer)
nsAnimationReceiver::AnimationAdded(Animation* aAnimation)
{
RecordAnimationMutation(aPlayer, eAnimationMutation_Added);
RecordAnimationMutation(aAnimation, eAnimationMutation_Added);
}
void
nsAnimationReceiver::AnimationChanged(AnimationPlayer* aPlayer)
nsAnimationReceiver::AnimationChanged(Animation* aAnimation)
{
RecordAnimationMutation(aPlayer, eAnimationMutation_Changed);
RecordAnimationMutation(aAnimation, eAnimationMutation_Changed);
}
void
nsAnimationReceiver::AnimationRemoved(AnimationPlayer* aPlayer)
nsAnimationReceiver::AnimationRemoved(Animation* aAnimation)
{
RecordAnimationMutation(aPlayer, eAnimationMutation_Removed);
RecordAnimationMutation(aAnimation, eAnimationMutation_Removed);
}
NS_IMPL_ISUPPORTS_INHERITED(nsAnimationReceiver, nsMutationReceiver,
@ -1020,11 +1020,11 @@ nsAutoAnimationMutationBatch::Done()
for (const Entry& e : mEntries) {
if (e.mState == eState_Added) {
m->mAddedAnimations.AppendElement(e.mPlayer);
m->mAddedAnimations.AppendElement(e.mAnimation);
} else if (e.mState == eState_Removed) {
m->mRemovedAnimations.AppendElement(e.mPlayer);
m->mRemovedAnimations.AppendElement(e.mAnimation);
} else if (e.mState == eState_RemainedPresent && e.mChanged) {
m->mChangedAnimations.AppendElement(e.mPlayer);
m->mChangedAnimations.AppendElement(e.mAnimation);
}
}

View File

@ -24,7 +24,7 @@
#include "nsWrapperCache.h"
#include "mozilla/dom/MutationObserverBinding.h"
#include "nsIDocument.h"
#include "mozilla/dom/AnimationPlayer.h"
#include "mozilla/dom/Animation.h"
#include "nsIAnimationObserver.h"
class nsDOMMutationObserver;
@ -36,7 +36,7 @@ class nsDOMMutationRecord final : public nsISupports,
virtual ~nsDOMMutationRecord() {}
public:
typedef nsTArray<nsRefPtr<mozilla::dom::AnimationPlayer>> AnimationPlayerArray;
typedef nsTArray<nsRefPtr<mozilla::dom::Animation>> AnimationArray;
nsDOMMutationRecord(nsIAtom* aType, nsISupports* aOwner)
: mType(aType), mAttrNamespace(NullString()), mPrevValue(NullString()), mOwner(aOwner)
@ -95,17 +95,17 @@ public:
aRetVal.SetOwnedString(mPrevValue);
}
void GetAddedAnimations(AnimationPlayerArray& aRetVal) const
void GetAddedAnimations(AnimationArray& aRetVal) const
{
aRetVal = mAddedAnimations;
}
void GetRemovedAnimations(AnimationPlayerArray& aRetVal) const
void GetRemovedAnimations(AnimationArray& aRetVal) const
{
aRetVal = mRemovedAnimations;
}
void GetChangedAnimations(AnimationPlayerArray& aRetVal) const
void GetChangedAnimations(AnimationArray& aRetVal) const
{
aRetVal = mChangedAnimations;
}
@ -119,9 +119,9 @@ public:
nsRefPtr<nsSimpleContentList> mRemovedNodes;
nsCOMPtr<nsINode> mPreviousSibling;
nsCOMPtr<nsINode> mNextSibling;
AnimationPlayerArray mAddedAnimations;
AnimationPlayerArray mRemovedAnimations;
AnimationPlayerArray mChangedAnimations;
AnimationArray mAddedAnimations;
AnimationArray mRemovedAnimations;
AnimationArray mChangedAnimations;
nsRefPtr<nsDOMMutationRecord> mNext;
nsCOMPtr<nsISupports> mOwner;
@ -434,7 +434,7 @@ private:
eAnimationMutation_Removed
};
void RecordAnimationMutation(mozilla::dom::AnimationPlayer* aPlayer,
void RecordAnimationMutation(mozilla::dom::Animation* aAnimation,
AnimationMutation aMutationType);
};
@ -756,13 +756,13 @@ public:
return sCurrentBatch->mBatchTarget;
}
static void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer)
static void AnimationAdded(mozilla::dom::Animation* aAnimation)
{
if (!IsBatching()) {
return;
}
Entry* entry = sCurrentBatch->FindEntry(aPlayer);
Entry* entry = sCurrentBatch->FindEntry(aAnimation);
if (entry) {
switch (entry->mState) {
case eState_RemainedAbsent:
@ -777,15 +777,15 @@ public:
}
} else {
entry = sCurrentBatch->mEntries.AppendElement();
entry->mPlayer = aPlayer;
entry->mAnimation = aAnimation;
entry->mState = eState_Added;
entry->mChanged = false;
}
}
static void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer)
static void AnimationChanged(mozilla::dom::Animation* aAnimation)
{
Entry* entry = sCurrentBatch->FindEntry(aPlayer);
Entry* entry = sCurrentBatch->FindEntry(aAnimation);
if (entry) {
NS_ASSERTION(entry->mState == eState_RemainedPresent ||
entry->mState == eState_Added,
@ -794,15 +794,15 @@ public:
entry->mChanged = true;
} else {
entry = sCurrentBatch->mEntries.AppendElement();
entry->mPlayer = aPlayer;
entry->mAnimation = aAnimation;
entry->mState = eState_RemainedPresent;
entry->mChanged = true;
}
}
static void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer)
static void AnimationRemoved(mozilla::dom::Animation* aAnimation)
{
Entry* entry = sCurrentBatch->FindEntry(aPlayer);
Entry* entry = sCurrentBatch->FindEntry(aAnimation);
if (entry) {
switch (entry->mState) {
case eState_RemainedPresent:
@ -817,17 +817,17 @@ public:
}
} else {
entry = sCurrentBatch->mEntries.AppendElement();
entry->mPlayer = aPlayer;
entry->mAnimation = aAnimation;
entry->mState = eState_Removed;
entry->mChanged = false;
}
}
private:
Entry* FindEntry(mozilla::dom::AnimationPlayer* aPlayer)
Entry* FindEntry(mozilla::dom::Animation* aAnimation)
{
for (Entry& e : mEntries) {
if (e.mPlayer == aPlayer) {
if (e.mAnimation == aAnimation) {
return &e;
}
}
@ -843,7 +843,7 @@ private:
struct Entry
{
nsRefPtr<mozilla::dom::AnimationPlayer> mPlayer;
nsRefPtr<mozilla::dom::Animation> mAnimation;
State mState;
bool mChanged;
};

View File

@ -19,7 +19,7 @@
#include "nsFrameManager.h"
#include "nsRefreshDriver.h"
#include "mozilla/dom/Touch.h"
#include "mozilla/PendingPlayerTracker.h"
#include "mozilla/PendingAnimationTracker.h"
#include "nsIObjectLoadingContent.h"
#include "nsFrame.h"
#include "mozilla/layers/ShadowLayers.h"
@ -2342,16 +2342,15 @@ nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds)
// Before we advance the time, we should trigger any animations that are
// waiting to start. This is because there are many tests that call this
// which expect animations to start immediately. Ideally, we should make
// all these tests do an asynchronous wait on the corresponding animation
// player's 'ready' promise before continuing. Then we could remove the
// special handling here and the code path followed when testing would
// more closely match the code path during regular operation. Filed as
// bug 1112957.
// all these tests do an asynchronous wait on the corresponding animation's
// 'ready' promise before continuing. Then we could remove the special
// handling here and the code path followed when testing would more closely
// match the code path during regular operation. Filed as bug 1112957.
nsCOMPtr<nsIDocument> doc = GetDocument();
if (doc) {
PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker();
PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker();
if (tracker) {
tracker->TriggerPendingPlayersNow();
tracker->TriggerPendingAnimationsNow();
}
}

View File

@ -2019,7 +2019,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUndoManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentTimeline)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPlayerTracker)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingAnimationTracker)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRegistry)
@ -2103,7 +2103,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mUndoManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentTimeline)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingPlayerTracker)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry)
@ -7492,14 +7492,14 @@ nsDocument::GetAnimationController()
return mAnimationController;
}
PendingPlayerTracker*
nsDocument::GetOrCreatePendingPlayerTracker()
PendingAnimationTracker*
nsDocument::GetOrCreatePendingAnimationTracker()
{
if (!mPendingPlayerTracker) {
mPendingPlayerTracker = new PendingPlayerTracker(this);
if (!mPendingAnimationTracker) {
mPendingAnimationTracker = new PendingAnimationTracker(this);
}
return mPendingPlayerTracker;
return mPendingAnimationTracker;
}
/**

View File

@ -59,7 +59,7 @@
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventStates.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PendingPlayerTracker.h"
#include "mozilla/PendingAnimationTracker.h"
#include "mozilla/dom/DOMImplementation.h"
#include "mozilla/dom/StyleSheetList.h"
#include "nsDataHashtable.h"
@ -1050,14 +1050,14 @@ public:
// If HasAnimationController is true, this is guaranteed to return non-null.
nsSMILAnimationController* GetAnimationController() override;
virtual mozilla::PendingPlayerTracker*
GetPendingPlayerTracker() final override
virtual mozilla::PendingAnimationTracker*
GetPendingAnimationTracker() final override
{
return mPendingPlayerTracker;
return mPendingAnimationTracker;
}
virtual mozilla::PendingPlayerTracker*
GetOrCreatePendingPlayerTracker() override;
virtual mozilla::PendingAnimationTracker*
GetOrCreatePendingAnimationTracker() override;
void SetImagesNeedAnimating(bool aAnimating) override;
@ -1540,9 +1540,9 @@ protected:
// Array of observers
nsTObserverArray<nsIDocumentObserver*> mObservers;
// Tracker for animation players that are waiting to start.
// nullptr until GetOrCreatePendingPlayerTracker is called.
nsRefPtr<mozilla::PendingPlayerTracker> mPendingPlayerTracker;
// Tracker for animations that are waiting to start.
// nullptr until GetOrCreatePendingAnimationTracker is called.
nsRefPtr<mozilla::PendingAnimationTracker> mPendingAnimationTracker;
// Weak reference to the scope object (aka the script global object)
// that, unlike mScriptGlobalObject, is never unset once set. This

View File

@ -9,7 +9,7 @@
namespace mozilla {
namespace dom {
class AnimationPlayer;
class Animation;
}
}
@ -22,36 +22,36 @@ class nsIAnimationObserver : public nsIMutationObserver
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IANIMATION_OBSERVER_IID)
virtual void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) = 0;
virtual void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) = 0;
virtual void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) = 0;
virtual void AnimationAdded(mozilla::dom::Animation* aAnimation) = 0;
virtual void AnimationChanged(mozilla::dom::Animation* aAnimation) = 0;
virtual void AnimationRemoved(mozilla::dom::Animation* aAnimation) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIAnimationObserver, NS_IANIMATION_OBSERVER_IID)
#define NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONADDED \
virtual void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) \
virtual void AnimationAdded(mozilla::dom::Animation* aAnimation) \
override;
#define NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONCHANGED \
virtual void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) \
virtual void AnimationChanged(mozilla::dom::Animation* aAnimation) \
override;
#define NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONREMOVED \
virtual void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) \
virtual void AnimationRemoved(mozilla::dom::Animation* aAnimation) \
override;
#define NS_IMPL_NSIANIMATIONOBSERVER_STUB(class_) \
void \
class_::AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) \
class_::AnimationAdded(mozilla::dom::Animation* aAnimation) \
{ \
} \
void \
class_::AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) \
class_::AnimationChanged(mozilla::dom::Animation* aAnimation) \
{ \
} \
void \
class_::AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) \
class_::AnimationRemoved(mozilla::dom::Animation* aAnimation) \
{ \
} \
NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(class_) \

View File

@ -88,7 +88,7 @@ namespace mozilla {
class CSSStyleSheet;
class ErrorResult;
class EventStates;
class PendingPlayerTracker;
class PendingAnimationTracker;
class SVGAttrAnimationRuleProcessor;
namespace css {
@ -1837,16 +1837,17 @@ public:
// mAnimationController isn't yet initialized.
virtual nsSMILAnimationController* GetAnimationController() = 0;
// Gets the tracker for animation players that are waiting to start.
// Returns nullptr if there is no pending player tracker for this document
// Gets the tracker for animations that are waiting to start.
// Returns nullptr if there is no pending animation tracker for this document
// which will be the case if there have never been any CSS animations or
// transitions on elements in the document.
virtual mozilla::PendingPlayerTracker* GetPendingPlayerTracker() = 0;
virtual mozilla::PendingAnimationTracker* GetPendingAnimationTracker() = 0;
// Gets the tracker for animation players that are waiting to start and
// Gets the tracker for animations that are waiting to start and
// creates it if it doesn't already exist. As a result, the return value
// will never be nullptr.
virtual mozilla::PendingPlayerTracker* GetOrCreatePendingPlayerTracker() = 0;
virtual mozilla::PendingAnimationTracker*
GetOrCreatePendingAnimationTracker() = 0;
// Makes the images on this document capable of having their animation
// active or suspended. An Image will animate as long as at least one of its

View File

@ -1971,7 +1971,10 @@ protected:
nsRefPtr<mozilla::dom::NodeInfo> mNodeInfo;
nsINode* mParent;
// mParent is an owning ref most of the time, except for the case of document
// nodes, so it cannot be represented by nsCOMPtr, so mark is as
// MOZ_OWNING_REF.
nsINode* MOZ_OWNING_REF mParent;
private:
// Boolean flags.

View File

@ -24,7 +24,7 @@
#include "nsBindingManager.h"
#include "nsGenericHTMLElement.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/AnimationPlayer.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/KeyframeEffect.h"
@ -216,9 +216,9 @@ nsNodeUtils::ContentRemoved(nsINode* aContainer,
}
static inline Element*
GetTarget(AnimationPlayer* aPlayer)
GetTarget(Animation* aAnimation)
{
KeyframeEffectReadonly* effect = aPlayer->GetEffect();
KeyframeEffectReadonly* effect = aAnimation->GetEffect();
if (!effect) {
return nullptr;
}
@ -238,44 +238,44 @@ GetTarget(AnimationPlayer* aPlayer)
}
void
nsNodeUtils::AnimationAdded(AnimationPlayer* aPlayer)
nsNodeUtils::AnimationAdded(Animation* aAnimation)
{
Element* target = GetTarget(aPlayer);
Element* target = GetTarget(aAnimation);
if (!target) {
return;
}
nsIDocument* doc = target->OwnerDoc();
if (doc->MayHaveAnimationObservers()) {
IMPL_ANIMATION_NOTIFICATION(AnimationAdded, target, (aPlayer));
IMPL_ANIMATION_NOTIFICATION(AnimationAdded, target, (aAnimation));
}
}
void
nsNodeUtils::AnimationChanged(AnimationPlayer* aPlayer)
nsNodeUtils::AnimationChanged(Animation* aAnimation)
{
Element* target = GetTarget(aPlayer);
Element* target = GetTarget(aAnimation);
if (!target) {
return;
}
nsIDocument* doc = target->OwnerDoc();
if (doc->MayHaveAnimationObservers()) {
IMPL_ANIMATION_NOTIFICATION(AnimationChanged, target, (aPlayer));
IMPL_ANIMATION_NOTIFICATION(AnimationChanged, target, (aAnimation));
}
}
void
nsNodeUtils::AnimationRemoved(AnimationPlayer* aPlayer)
nsNodeUtils::AnimationRemoved(Animation* aAnimation)
{
Element* target = GetTarget(aPlayer);
Element* target = GetTarget(aAnimation);
if (!target) {
return;
}
nsIDocument* doc = target->OwnerDoc();
if (doc->MayHaveAnimationObservers()) {
IMPL_ANIMATION_NOTIFICATION(AnimationRemoved, target, (aPlayer));
IMPL_ANIMATION_NOTIFICATION(AnimationRemoved, target, (aAnimation));
}
}

View File

@ -18,7 +18,7 @@ template<class E> class nsCOMArray;
class nsCycleCollectionTraversalCallback;
namespace mozilla {
namespace dom {
class AnimationPlayer;
class Animation;
}
}
@ -127,9 +127,9 @@ public:
}
}
static void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer);
static void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer);
static void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer);
static void AnimationAdded(mozilla::dom::Animation* aAnimation);
static void AnimationChanged(mozilla::dom::Animation* aAnimation);
static void AnimationRemoved(mozilla::dom::Animation* aAnimation);
/**
* To be called when reference count of aNode drops to zero.

View File

@ -2733,8 +2733,10 @@ nsObjectLoadingContent::PluginDestroyed()
// plugins in plugin host. Invalidate instance owner / prototype but otherwise
// don't take any action.
TeardownProtoChain();
mInstanceOwner->Destroy();
mInstanceOwner = nullptr;
if (mInstanceOwner) {
mInstanceOwner->Destroy();
mInstanceOwner = nullptr;
}
return NS_OK;
}

View File

@ -8604,6 +8604,26 @@ class CGStaticMethodJitinfo(CGGeneric):
IDLToCIdentifier(method.identifier.name))))
class CGMethodIdentityTest(CGAbstractMethod):
"""
A class to generate a method-identity test for a given IDL operation.
"""
def __init__(self, descriptor, method):
self.method = method
name = "Is%sMethod" % MakeNativeName(method.identifier.name)
CGAbstractMethod.__init__(self, descriptor, name, 'bool',
[Argument('JS::Handle<JSObject*>', 'aObj')])
def definition_body(self):
return dedent(
"""
MOZ_ASSERT(aObj);
return js::IsFunctionObject(aObj) &&
js::FunctionObjectIsNative(aObj) &&
FUNCTION_VALUE_TO_JITINFO(JS::ObjectValue(*aObj)) == &%s_methodinfo;
""" % IDLToCIdentifier(self.method.identifier.name))
def getEnumValueName(value):
# Some enum values can be empty strings. Others might have weird
# characters in them. Deal with the former by returning "_empty",
@ -11200,6 +11220,8 @@ class CGDescriptor(CGThing):
cgThings.append(CGMemberJITInfo(descriptor, m))
if props.isCrossOriginMethod:
crossOriginMethods.add(m.identifier.name)
if m.getExtendedAttribute("MethodIdentityTestable"):
cgThings.append(CGMethodIdentityTest(descriptor, m))
elif m.isAttr():
if m.stringifier:
raise TypeError("Stringifier attributes not supported yet. "

View File

@ -2776,7 +2776,7 @@ class IDLBuiltinType(IDLType):
self._typeTag == IDLBuiltinType.Types.unrestricted_double
def isSerializable(self):
return self.isPrimitive() or self.isDOMString() or self.isDate()
return self.isPrimitive() or self.isString() or self.isDate()
def includesRestrictedFloat(self):
return self.isFloat() and not self.isUnrestricted()
@ -4163,7 +4163,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
identifier == "Func" or
identifier == "AvailableIn" or
identifier == "CheckPermissions" or
identifier == "BinaryName"):
identifier == "BinaryName" or
identifier == "MethodIdentityTestable"):
# Known attributes that we don't need to do anything with here
pass
else:

68
dom/cache/Context.cpp vendored
View File

@ -701,18 +701,19 @@ Context::ThreadsafeHandle::ContextDestroyed(Context* aContext)
// static
already_AddRefed<Context>
Context::Create(Manager* aManager, Action* aQuotaIOThreadAction)
Context::Create(Manager* aManager, Action* aQuotaIOThreadAction,
Context* aOldContext)
{
nsRefPtr<Context> context = new Context(aManager);
// Do this here to avoid doing an AddRef() in the constructor
context->mInitRunnable = new QuotaInitRunnable(context, aManager,
aQuotaIOThreadAction);
nsresult rv = context->mInitRunnable->Dispatch();
if (NS_FAILED(rv)) {
// Shutdown must be delayed until all Contexts are destroyed. Shutdown
// must also prevent any new Contexts from being constructed. Crash
// for this invariant violation.
MOZ_CRASH("Failed to dispatch QuotaInitRunnable.");
if (aOldContext) {
aOldContext->SetNextContext(context);
} else {
context->Start();
}
return context.forget();
@ -720,7 +721,7 @@ Context::Create(Manager* aManager, Action* aQuotaIOThreadAction)
Context::Context(Manager* aManager)
: mManager(aManager)
, mState(STATE_CONTEXT_INIT)
, mState(STATE_CONTEXT_PREINIT)
{
MOZ_ASSERT(mManager);
}
@ -735,7 +736,8 @@ Context::Dispatch(nsIEventTarget* aTarget, Action* aAction)
MOZ_ASSERT(mState != STATE_CONTEXT_CANCELED);
if (mState == STATE_CONTEXT_CANCELED) {
return;
} else if (mState == STATE_CONTEXT_INIT) {
} else if (mState == STATE_CONTEXT_INIT ||
mState == STATE_CONTEXT_PREINIT) {
PendingAction* pending = mPendingActions.AppendElement();
pending->mTarget = aTarget;
pending->mAction = aAction;
@ -751,8 +753,15 @@ Context::CancelAll()
{
NS_ASSERT_OWNINGTHREAD(Context);
if (mInitRunnable) {
MOZ_ASSERT(mState == STATE_CONTEXT_INIT);
// In PREINIT state we have not dispatch the init runnable yet. Just
// forget it.
if (mState == STATE_CONTEXT_PREINIT) {
mInitRunnable = nullptr;
// In INIT state we have dispatched the runnable, but not received the
// async completion yet. Cancel the runnable, but don't forget about it
// until we get OnQuotaInit() callback.
} else if (mState == STATE_CONTEXT_INIT) {
mInitRunnable->Cancel();
}
@ -823,6 +832,34 @@ Context::~Context()
}
mManager->RemoveContext(this);
if (mNextContext) {
mNextContext->Start();
}
}
void
Context::Start()
{
NS_ASSERT_OWNINGTHREAD(Context);
// Previous context closing delayed our start, but then we were canceled.
// In this case, just do nothing here.
if (mState == STATE_CONTEXT_CANCELED) {
MOZ_ASSERT(!mInitRunnable);
return;
}
MOZ_ASSERT(mState == STATE_CONTEXT_PREINIT);
mState = STATE_CONTEXT_INIT;
nsresult rv = mInitRunnable->Dispatch();
if (NS_FAILED(rv)) {
// Shutdown must be delayed until all Contexts are destroyed. Shutdown
// must also prevent any new Contexts from being constructed. Crash
// for this invariant violation.
MOZ_CRASH("Failed to dispatch QuotaInitRunnable.");
}
}
void
@ -905,6 +942,15 @@ Context::CreateThreadsafeHandle()
return ref.forget();
}
void
Context::SetNextContext(Context* aNextContext)
{
NS_ASSERT_OWNINGTHREAD(Context);
MOZ_ASSERT(aNextContext);
MOZ_ASSERT(!mNextContext);
mNextContext = aNextContext;
}
} // namespace cache
} // namespace dom
} // namespace mozilla

8
dom/cache/Context.h vendored
View File

@ -111,7 +111,7 @@ public:
// will run on the QuotaManager IO thread. Note, this Action must
// be execute synchronously.
static already_AddRefed<Context>
Create(Manager* aManager, Action* aQuotaIOThreadAction);
Create(Manager* aManager, Action* aQuotaIOThreadAction, Context* aOldContext);
// Execute given action on the target once the quota manager has been
// initialized.
@ -157,6 +157,7 @@ private:
enum State
{
STATE_CONTEXT_PREINIT,
STATE_CONTEXT_INIT,
STATE_CONTEXT_READY,
STATE_CONTEXT_CANCELED
@ -170,6 +171,7 @@ private:
explicit Context(Manager* aManager);
~Context();
void Start();
void DispatchAction(nsIEventTarget* aTarget, Action* aAction);
void OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo,
nsMainThreadPtrHandle<OfflineStorage>& aOfflineStorage);
@ -177,6 +179,9 @@ private:
already_AddRefed<ThreadsafeHandle>
CreateThreadsafeHandle();
void
SetNextContext(Context* aNextContext);
nsRefPtr<Manager> mManager;
State mState;
QuotaInfo mQuotaInfo;
@ -194,6 +199,7 @@ private:
nsRefPtr<ThreadsafeHandle> mThreadsafeHandle;
nsMainThreadPtrHandle<OfflineStorage> mOfflineStorage;
nsRefPtr<Context> mNextContext;
public:
NS_INLINE_DECL_REFCOUNTING(cache::Context)

48
dom/cache/Manager.cpp vendored
View File

@ -157,7 +157,12 @@ public:
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
ref = new Manager(aManagerId, ioThread);
ref->Init();
// There may be an old manager for this origin in the process of
// cleaning up. We need to tell the new manager about this so
// that it won't actually start until the old manager is done.
nsRefPtr<Manager> oldManager = Get(aManagerId, Closing);
ref->Init(oldManager);
MOZ_ASSERT(!sFactory->mManagerList.Contains(ref));
sFactory->mManagerList.AppendElement(ref);
@ -169,20 +174,20 @@ public:
}
static already_AddRefed<Manager>
Get(ManagerId* aManagerId)
Get(ManagerId* aManagerId, State aState = Open)
{
mozilla::ipc::AssertIsOnBackgroundThread();
nsresult rv = MaybeCreateInstance();
if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; }
ManagerList::ForwardIterator iter(sFactory->mManagerList);
// Iterate in reverse to find the most recent, matching Manager. This
// is important when looking for a Closing Manager. If a new Manager
// chains to an old Manager we want it to be the most recent one.
ManagerList::BackwardIterator iter(sFactory->mManagerList);
while (iter.HasMore()) {
nsRefPtr<Manager> manager = iter.GetNext();
// If there is an invalid Manager finishing up and a new Manager
// is created for the same origin, then the new Manager will
// be blocked until QuotaManager finishes clearing the origin.
if (!manager->IsClosing() && *manager->mManagerId == *aManagerId) {
if (aState == manager->GetState() && *manager->mManagerId == *aManagerId) {
return manager.forget();
}
}
@ -1450,7 +1455,7 @@ Manager::RemoveContext(Context* aContext)
// Whether the Context destruction was triggered from the Manager going
// idle or the underlying storage being invalidated, we should know we
// are closing before the Conext is destroyed.
MOZ_ASSERT(mClosing);
MOZ_ASSERT(mState == Closing);
mContext = nullptr;
@ -1465,14 +1470,14 @@ Manager::NoteClosing()
{
NS_ASSERT_OWNINGTHREAD(Manager);
// This can be called more than once legitimately through different paths.
mClosing = true;
mState = Closing;
}
bool
Manager::IsClosing() const
Manager::State
Manager::GetState() const
{
NS_ASSERT_OWNINGTHREAD(Manager);
return mClosing;
return mState;
}
void
@ -1593,7 +1598,7 @@ Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs);
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs);
if (mClosing) {
if (mState == Closing) {
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
return;
}
@ -1637,7 +1642,7 @@ Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mClosing) {
if (mState == Closing) {
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
return;
}
@ -1686,7 +1691,7 @@ Manager::ExecutePutAll(Listener* aListener, CacheId aCacheId,
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mClosing) {
if (mState == Closing) {
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), CachePutAllResult());
return;
}
@ -1708,7 +1713,7 @@ Manager::Manager(ManagerId* aManagerId, nsIThread* aIOThread)
, mIOThread(aIOThread)
, mContext(nullptr)
, mShuttingDown(false)
, mClosing(false)
, mState(Open)
{
MOZ_ASSERT(mManagerId);
MOZ_ASSERT(mIOThread);
@ -1717,7 +1722,7 @@ Manager::Manager(ManagerId* aManagerId, nsIThread* aIOThread)
Manager::~Manager()
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(mClosing);
MOZ_ASSERT(mState == Closing);
MOZ_ASSERT(!mContext);
nsCOMPtr<nsIThread> ioThread;
@ -1731,15 +1736,20 @@ Manager::~Manager()
}
void
Manager::Init()
Manager::Init(Manager* aOldManager)
{
NS_ASSERT_OWNINGTHREAD(Manager);
nsRefPtr<Context> oldContext;
if (aOldManager) {
oldContext = aOldManager->mContext;
}
// Create the context immediately. Since there can at most be one Context
// per Manager now, this lets us cleanly call Factory::Remove() once the
// Context goes away.
nsRefPtr<Action> setupAction = new SetupAction();
nsRefPtr<Context> ref = Context::Create(this, setupAction);
nsRefPtr<Context> ref = Context::Create(this, setupAction, oldContext);
mContext = ref;
}

13
dom/cache/Manager.h vendored
View File

@ -119,6 +119,12 @@ public:
~Listener() { }
};
enum State
{
Open,
Closing
};
static nsresult GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut);
static already_AddRefed<Manager> Get(ManagerId* aManagerId);
@ -134,7 +140,8 @@ public:
// Marks the Manager "invalid". Once the Context completes no new operations
// will be permitted with this Manager. New actors will get a new Manager.
void NoteClosing();
bool IsClosing() const;
State GetState() const;
// If an actor represents a long term reference to a cache or body stream,
// then they must call AddRefCacheId() or AddRefBodyId(). This will
@ -185,7 +192,7 @@ private:
Manager(ManagerId* aManagerId, nsIThread* aIOThread);
~Manager();
void Init();
void Init(Manager* aOldManager);
void Shutdown();
already_AddRefed<Context> CurrentContext();
@ -249,7 +256,7 @@ private:
nsTArray<StreamList*> mStreamLists;
bool mShuttingDown;
bool mClosing;
State mState;
struct CacheIdRefCounter
{

View File

@ -38,16 +38,7 @@ function serviceWorkerTestExec(testFile) {
document.body.appendChild(iframe);
}
navigator.serviceWorker.register("worker_wrapper.js", {scope: "."})
.then(function(registration) {
if (registration.installing) {
registration.installing.onstatechange = function(e) {
e.target.onstatechange = null;
setupSW(registration);
};
} else {
setupSW(registration);
}
});
navigator.serviceWorker.ready.then(setupSW);
navigator.serviceWorker.register("worker_wrapper.js", {scope: "."});
});
}

View File

@ -4269,7 +4269,10 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
}
bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), mVideoTexture, LOCAL_GL_TEXTURE_2D, 1);
const gl::OriginPos destOrigin = gl::OriginPos::TopLeft;
bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(),
mVideoTexture, LOCAL_GL_TEXTURE_2D,
destOrigin);
if (ok) {
NativeSurface texSurf;
texSurf.mType = NativeSurfaceType::OPENGL_TEXTURE;

View File

@ -1837,11 +1837,13 @@ WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
0, format, type, nullptr);
}
const gl::OriginPos destOrigin = mPixelStoreFlipY ? gl::OriginPos::BottomLeft
: gl::OriginPos::TopLeft;
bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(),
srcImage->GetSize(),
tex->GLName(),
texImageTarget.get(),
mPixelStoreFlipY);
destOrigin);
if (ok) {
TexInternalFormat effectiveInternalFormat =
EffectiveInternalFormatFromInternalFormatAndType(internalFormat,

View File

@ -198,29 +198,20 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
if (aPath.IsFile()) {
file = aPath.GetAsFile().Impl();
goto parameters_check_done;
}
if (aPath.IsString()) {
} else if (aPath.IsString()) {
if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
goto parameters_check_done;
}
if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) {
} else if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) {
error = NS_ERROR_DOM_SECURITY_ERR;
goto parameters_check_done;
} else {
realPath = aPath.GetAsDirectory().mPath;
// The target must be a descendant of this directory.
if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
}
}
realPath = aPath.GetAsDirectory().mPath;
// The target must be a descendant of this directory.
if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
}
parameters_check_done:
nsRefPtr<RemoveTask> task = new RemoveTask(mFileSystem, mPath, file, realPath,
aRecursive, aRv);
if (aRv.Failed()) {

View File

@ -1461,15 +1461,7 @@ HTMLTextAreaElement::IsPasswordTextControl() const
NS_IMETHODIMP_(int32_t)
HTMLTextAreaElement::GetCols()
{
const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::cols);
if (attr) {
int32_t cols = attr->Type() == nsAttrValue::eInteger ?
attr->GetIntegerValue() : 0;
// XXX why a default of 1 char, why hide it
return (cols <= 0) ? 1 : cols;
}
return DEFAULT_COLS;
return Cols();
}
NS_IMETHODIMP_(int32_t)

View File

@ -2360,6 +2360,13 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
bool aSetupOffMainThreadCompositing,
bool aSendRegisteredChrome)
{
if (aSendRegisteredChrome) {
nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
nsChromeRegistryChrome* chromeRegistry =
static_cast<nsChromeRegistryChrome*>(registrySvc.get());
chromeRegistry->SendRegisteredChrome(this);
}
// Initialize the message manager (and load delayed scripts) now that we
// have established communications with the child.
mMessageManager->InitWithCallback(this);
@ -2402,13 +2409,6 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
#endif
}
if (aSendRegisteredChrome) {
nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
nsChromeRegistryChrome* chromeRegistry =
static_cast<nsChromeRegistryChrome*>(registrySvc.get());
chromeRegistry->SendRegisteredChrome(this);
}
if (gAppData) {
nsCString version(gAppData->version);
nsCString buildID(gAppData->buildID);

View File

@ -72,10 +72,14 @@ public:
EGLImage CopySurface(layers::Image* img) {
mGLContext->MakeCurrent();
GLuint tex = CreateTextureForOffscreen(mGLContext, mGLContext->GetGLFormats(), img->GetSize());
GLuint tex = CreateTextureForOffscreen(mGLContext, mGLContext->GetGLFormats(),
img->GetSize());
GLBlitHelper helper(mGLContext);
if (!helper.BlitImageToTexture(img, img->GetSize(), tex, LOCAL_GL_TEXTURE_2D)) {
auto helper = mGLContext->BlitHelper();
const gl::OriginPos destOrigin = gl::OriginPos::TopLeft;
if (!helper->BlitImageToTexture(img, img->GetSize(), tex, LOCAL_GL_TEXTURE_2D,
destOrigin))
{
mGLContext->fDeleteTextures(1, &tex);
return nullptr;
}
@ -134,7 +138,7 @@ public:
data.mSync = eglSync;
data.mOwns = true;
data.mSize = mConfig.mDisplay;
data.mOriginPos = gl::OriginPos::BottomLeft;
data.mOriginPos = gl::OriginPos::TopLeft;
layers::EGLImageImage* typedImg = static_cast<layers::EGLImageImage*>(img.get());
typedImg->SetData(data);

View File

@ -32,6 +32,7 @@ namespace gmp {
GMPAudioDecoderParent::GMPAudioDecoderParent(GMPContentParent* aPlugin)
: mIsOpen(false)
, mShuttingDown(false)
, mActorDestroyed(false)
, mPlugin(aPlugin)
, mCallback(nullptr)
{
@ -174,7 +175,9 @@ GMPAudioDecoderParent::Shutdown()
}
mIsOpen = false;
unused << SendDecodingComplete();
if (!mActorDestroyed) {
unused << SendDecodingComplete();
}
return NS_OK;
}
@ -184,6 +187,7 @@ void
GMPAudioDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
{
mIsOpen = false;
mActorDestroyed = true;
if (mCallback) {
// May call Close() (and Shutdown()) immediately or with a delay
mCallback->Terminated();

View File

@ -55,6 +55,7 @@ private:
bool mIsOpen;
bool mShuttingDown;
bool mActorDestroyed;
nsRefPtr<GMPContentParent> mPlugin;
GMPAudioDecoderCallbackProxy* mCallback;
};

View File

@ -14,6 +14,7 @@ namespace gmp {
GMPDecryptorParent::GMPDecryptorParent(GMPContentParent* aPlugin)
: mIsOpen(false)
, mShuttingDown(false)
, mActorDestroyed(false)
, mPlugin(aPlugin)
, mCallback(nullptr)
#ifdef DEBUG
@ -347,7 +348,9 @@ GMPDecryptorParent::Shutdown()
}
mIsOpen = false;
unused << SendDecryptingComplete();
if (!mActorDestroyed) {
unused << SendDecryptingComplete();
}
}
// Note: Keep this sync'd up with Shutdown
@ -355,6 +358,7 @@ void
GMPDecryptorParent::ActorDestroy(ActorDestroyReason aWhy)
{
mIsOpen = false;
mActorDestroyed = true;
if (mCallback) {
// May call Close() (and Shutdown()) immediately or with a delay
mCallback->Terminated();

View File

@ -111,6 +111,7 @@ private:
bool mIsOpen;
bool mShuttingDown;
bool mActorDestroyed;
nsRefPtr<GMPContentParent> mPlugin;
nsCString mPluginId;
GMPDecryptorProxyCallback* mCallback;

View File

@ -47,6 +47,7 @@ GMPVideoDecoderParent::GMPVideoDecoderParent(GMPContentParent* aPlugin)
: GMPSharedMemManager(aPlugin)
, mIsOpen(false)
, mShuttingDown(false)
, mActorDestroyed(false)
, mPlugin(aPlugin)
, mCallback(nullptr)
, mVideoHost(this)
@ -213,7 +214,9 @@ GMPVideoDecoderParent::Shutdown()
}
mIsOpen = false;
unused << SendDecodingComplete();
if (!mActorDestroyed) {
unused << SendDecodingComplete();
}
return NS_OK;
}
@ -223,6 +226,7 @@ void
GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
{
mIsOpen = false;
mActorDestroyed = true;
mVideoHost.DoneWithAPI();
if (mCallback) {

View File

@ -81,6 +81,7 @@ private:
bool mIsOpen;
bool mShuttingDown;
bool mActorDestroyed;
nsRefPtr<GMPContentParent> mPlugin;
GMPVideoDecoderCallbackProxy* mCallback;
GMPVideoHostImpl mVideoHost;

View File

@ -54,6 +54,7 @@ GMPVideoEncoderParent::GMPVideoEncoderParent(GMPContentParent *aPlugin)
: GMPSharedMemManager(aPlugin),
mIsOpen(false),
mShuttingDown(false),
mActorDestroyed(false),
mPlugin(aPlugin),
mCallback(nullptr),
mVideoHost(this)
@ -235,7 +236,9 @@ GMPVideoEncoderParent::Shutdown()
mVideoHost.DoneWithAPI();
mIsOpen = false;
unused << SendEncodingComplete();
if (!mActorDestroyed) {
unused << SendEncodingComplete();
}
}
static void
@ -250,6 +253,7 @@ GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy)
{
LOGD(("%s::%s: %p (%d)", __CLASS__, __FUNCTION__, this, (int) aWhy));
mIsOpen = false;
mActorDestroyed = true;
if (mCallback) {
// May call Close() (and Shutdown()) immediately or with a delay
mCallback->Terminated();

View File

@ -77,6 +77,7 @@ private:
bool mIsOpen;
bool mShuttingDown;
bool mActorDestroyed;
nsRefPtr<GMPContentParent> mPlugin;
GMPVideoEncoderCallbackProxy* mCallback;
GMPVideoHostImpl mVideoHost;

View File

@ -170,7 +170,7 @@ GetPromise(JSContext* aCx, JS::Handle<JSObject*> aFunc)
}
};
// Main thread runnable to resolve thenables.
// Runnable to resolve thenables.
// Equivalent to the specification's ResolvePromiseViaThenableTask.
class ThenableResolverTask final : public nsRunnable
{
@ -201,6 +201,8 @@ protected:
ThreadsafeAutoJSContext cx;
JS::Rooted<JSObject*> wrapper(cx, mPromise->GetWrapper());
MOZ_ASSERT(wrapper); // It was preserved!
// If we ever change which compartment we're working in here, make sure to
// fix the fast-path for resolved-with-a-Promise in ResolveInternal.
JSAutoCompartment ac(cx, wrapper);
JS::Rooted<JSObject*> resolveFunc(cx,
@ -271,6 +273,48 @@ private:
NS_DECL_OWNINGTHREAD;
};
// Fast version of ThenableResolverTask for use in the cases when we know we're
// calling the canonical Promise.prototype.then on an actual DOM Promise. In
// that case we can just bypass the jumping into and out of JS and call
// AppendCallbacks on that promise directly.
class FastThenableResolverTask final : public nsRunnable
{
public:
FastThenableResolverTask(PromiseCallback* aResolveCallback,
PromiseCallback* aRejectCallback,
Promise* aNextPromise)
: mResolveCallback(aResolveCallback)
, mRejectCallback(aRejectCallback)
, mNextPromise(aNextPromise)
{
MOZ_ASSERT(aResolveCallback);
MOZ_ASSERT(aRejectCallback);
MOZ_ASSERT(aNextPromise);
MOZ_COUNT_CTOR(FastThenableResolverTask);
}
virtual
~FastThenableResolverTask()
{
NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask);
MOZ_COUNT_DTOR(FastThenableResolverTask);
}
protected:
NS_IMETHOD
Run() override
{
NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask);
mNextPromise->AppendCallbacks(mResolveCallback, mRejectCallback);
return NS_OK;
}
private:
nsRefPtr<PromiseCallback> mResolveCallback;
nsRefPtr<PromiseCallback> mRejectCallback;
nsRefPtr<Promise> mNextPromise;
};
// Promise
NS_IMPL_CYCLE_COLLECTION_CLASS(Promise)
@ -1198,6 +1242,37 @@ Promise::ResolveInternal(JSContext* aCx,
if (then.isObject() && JS::IsCallable(&then.toObject())) {
// This is the then() function of the thenable aValueObj.
JS::Rooted<JSObject*> thenObj(aCx, &then.toObject());
// Add a fast path for the case when we're resolved with an actual
// Promise. This has two requirements:
//
// 1) valueObj is a Promise.
// 2) thenObj is a JSFunction backed by our actual Promise::Then
// implementation.
//
// If those requirements are satisfied, then we know exactly what
// thenObj.call(valueObj) will do, so we can optimize a bit and avoid ever
// entering JS for this stuff.
Promise* nextPromise;
if (PromiseBinding::IsThenMethod(thenObj) &&
NS_SUCCEEDED(UNWRAP_OBJECT(Promise, valueObj, nextPromise))) {
// If we were taking the codepath that involves ThenableResolverTask and
// PromiseInit below, then eventually, in ThenableResolverTask::Run, we
// would create some JSFunctions in the compartment of
// this->GetWrapper() and pass them to the PromiseInit. So by the time
// we'd see the resolution value it would be wrapped into the
// compartment of this->GetWrapper(). The global of that compartment is
// this->GetGlobalJSObject(), so use that as the global for
// ResolvePromiseCallback/RejectPromiseCallback.
JS::Rooted<JSObject*> glob(aCx, GlobalJSObject());
nsRefPtr<PromiseCallback> resolveCb = new ResolvePromiseCallback(this, glob);
nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(this, glob);
nsRefPtr<FastThenableResolverTask> task =
new FastThenableResolverTask(resolveCb, rejectCb, nextPromise);
DispatchToMicroTask(task);
return;
}
nsRefPtr<PromiseInit> thenCallback =
new PromiseInit(thenObj, mozilla::dom::GetIncumbentGlobal());
nsRefPtr<ThenableResolverTask> task =

View File

@ -85,6 +85,7 @@ class Promise : public nsISupports,
friend class RejectPromiseCallback;
friend class ResolvePromiseCallback;
friend class ThenableResolverTask;
friend class FastThenableResolverTask;
friend class WrapperPromiseCallback;
public:

View File

@ -6,3 +6,4 @@
[test_promise_utils.html]
[test_resolve.html]
[test_resolver_return_value.html]
[test_thenable_vs_promise_ordering.html]

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for promise resolution ordering with thenables and promises</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
var t = async_test("A promise resolved first (with a thenable) should trigger its callbacks before a promise resolved second (with a promise).");
t.step(function() {
var customThenCalled = false;
var p0 = Promise.resolve();
p0.then = function(resolved, rejected) {
customThenCalled = true;
Promise.prototype.then.call(this, resolved, rejected);
}
var p1 = new Promise(function(r) { r(p0); });
delete p0.then;
var p2 = new Promise(function(r) { r(p0); });
var resolutionOrder = "";
Promise.all([ p1.then(function() { resolutionOrder += "1"; }),
p2.then(function() { resolutionOrder += "2"; }) ])
.then(t.step_func_done(function() {
assert_true(customThenCalled, "Should have called custom then");
assert_equals(resolutionOrder, "12");
}));
});
</script>

View File

@ -35,6 +35,8 @@ http://creativecommons.org/licenses/publicdomain/
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
}

View File

@ -35,6 +35,8 @@ http://creativecommons.org/licenses/publicdomain/
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
}

View File

@ -35,6 +35,8 @@ http://creativecommons.org/licenses/publicdomain/
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
}

View File

@ -67,6 +67,8 @@ http://creativecommons.org/licenses/publicdomain/
function unregister() {
return registration.unregister().then(function(result) {
ok(result, "Unregister should return true.");
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
}

View File

@ -129,12 +129,12 @@ var interfaceNamesInGlobalScope =
{name: "AlarmsManager", pref: "dom.mozAlarms.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"AnalyserNode",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "Animation", pref: "dom.animations-api.core.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "AnimationEffectReadonly", pref: "dom.animations-api.core.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"AnimationEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "AnimationPlayer", pref: "dom.animations-api.core.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "AnimationTimeline", pref: "dom.animations-api.core.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -13,5 +13,5 @@
[NoInterfaceObject]
interface Animatable {
[Func="nsDocument::IsWebAnimationsEnabled"]
sequence<AnimationPlayer> getAnimations();
sequence<Animation> getAnimations();
};

View File

@ -4,16 +4,16 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://dev.w3.org/fxtf/web-animations/#idl-def-AnimationPlayer
* http://w3c.github.io/web-animations/#the-animation-interface
*
* Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" };
[Func="nsDocument::IsWebAnimationsEnabled"]
interface AnimationPlayer {
interface Animation {
// Bug 1049975: Make 'effect' writeable
[Pure]
readonly attribute AnimationEffectReadonly? effect;
@ -27,9 +27,9 @@ interface AnimationPlayer {
[BinaryName="playStateFromJS"]
readonly attribute AnimationPlayState playState;
[Throws]
readonly attribute Promise<AnimationPlayer> ready;
readonly attribute Promise<Animation> ready;
[Throws]
readonly attribute Promise<AnimationPlayer> finished;
readonly attribute Promise<Animation> finished;
/*
void cancel ();
void finish ();
@ -44,6 +44,6 @@ interface AnimationPlayer {
};
// Non-standard extensions
partial interface AnimationPlayer {
partial interface Animation {
[ChromeOnly] readonly attribute boolean isRunningOnCompositor;
};

View File

@ -15,6 +15,6 @@ interface AnimationTimeline {
[BinaryName="currentTimeAsDouble"]
readonly attribute double? currentTime;
// Not yet implemented:
// AnimationPlayer play (optional TimedItem? source = null);
// sequence<AnimationPlayer> getAnimations ();
// Animation play (optional TimedItem? source = null);
// sequence<Animation> getAnimations ();
};

View File

@ -29,11 +29,11 @@ interface MutationRecord {
[Constant]
readonly attribute DOMString? oldValue;
[Constant,Cached,ChromeOnly]
readonly attribute sequence<AnimationPlayer> addedAnimations;
readonly attribute sequence<Animation> addedAnimations;
[Constant,Cached,ChromeOnly]
readonly attribute sequence<AnimationPlayer> changedAnimations;
readonly attribute sequence<Animation> changedAnimations;
[Constant,Cached,ChromeOnly]
readonly attribute sequence<AnimationPlayer> removedAnimations;
readonly attribute sequence<Animation> removedAnimations;
};
[Constructor(MutationCallback mutationCallback)]

View File

@ -34,7 +34,7 @@ interface _Promise {
// The [TreatNonCallableAsNull] annotation is required since then() should do
// nothing instead of throwing errors when non-callable arguments are passed.
[NewObject]
[NewObject, MethodIdentityTestable]
Promise<any> then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
[TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);

View File

@ -22,9 +22,9 @@ WEBIDL_FILES = [
'AlarmsManager.webidl',
'AnalyserNode.webidl',
'Animatable.webidl',
'Animation.webidl',
'AnimationEffectReadonly.webidl',
'AnimationEvent.webidl',
'AnimationPlayer.webidl',
'AnimationTimeline.webidl',
'AnonymousContent.webidl',
'AppInfo.webidl',

View File

@ -50,7 +50,13 @@
my_ok(navigator.serviceWorker.controller.scriptURL.match(/worker\.js$/),
"Controller is still worker.js");
finish();
e.unregister().then(function(result) {
my_ok(result, "Unregistering the SW should succeed");
finish();
}, function(e) {
dump("Error unregistering the SW: " + e + "\n");
});
});
} else {
my_ok(false, "Should've been controlled!");

View File

@ -4,23 +4,11 @@
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
}
var isDone = false;
function done(reg) {
if (!isDone) {
ok(reg.waiting || reg.active, "Either active or waiting worker should be available.");
window.parent.postMessage({status: "registrationdone"}, "*");
isDone = true;
}
ok(reg.active, "The active worker should be available.");
window.parent.postMessage({status: "registrationdone"}, "*");
}
navigator.serviceWorker.register("context_test.js", {scope: "."})
.then(function(registration) {
if (registration.installing) {
registration.installing.onstatechange = function(e) {
done(registration);
};
} else {
done(registration);
}
});
navigator.serviceWorker.ready.then(done);
navigator.serviceWorker.register("context_test.js", {scope: "."});
</script>

View File

@ -5,6 +5,8 @@
if (success) {
window.parent.postMessage({status: "unregistrationdone"}, "*");
}
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
});
</script>

View File

@ -110,10 +110,10 @@ fetchXHR('hello.gz', function(xhr) {
});
fetchXHR('hello-after-extracting.gz', function(xhr) {
my_ok(xhr.status == 200, "gzip load should be successful");
my_ok(xhr.responseText == expectedUncompressedResponse, "gzip load should have synthesized response.");
my_ok(xhr.getResponseHeader("Content-Encoding") == "gzip", "Content-Encoding should be gzip.");
my_ok(xhr.getResponseHeader("Content-Length") == "35", "Content-Length should be of original gzipped file.");
my_ok(xhr.status == 200, "gzip load after extracting should be successful");
my_ok(xhr.responseText == expectedUncompressedResponse, "gzip load after extracting should have synthesized response.");
my_ok(xhr.getResponseHeader("Content-Encoding") == "gzip", "Content-Encoding after extracting should be gzip.");
my_ok(xhr.getResponseHeader("Content-Length") == "35", "Content-Length after extracting should be of original gzipped file.");
finish();
});

View File

@ -4,23 +4,11 @@
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
}
var isDone = false;
function done(reg) {
if (!isDone) {
ok(reg.waiting || reg.active, "Either active or waiting worker should be available.");
window.parent.postMessage({status: "registrationdone"}, "*");
isDone = true;
}
ok(reg.active, "The active worker should be available.");
window.parent.postMessage({status: "registrationdone"}, "*");
}
navigator.serviceWorker.register("https_test.js", {scope: "."})
.then(function(registration) {
if (registration.installing) {
registration.installing.onstatechange = function(e) {
done(registration);
};
} else {
done(registration);
}
});
navigator.serviceWorker.ready.then(done);
navigator.serviceWorker.register("https_test.js", {scope: "."});
</script>

View File

@ -5,6 +5,8 @@
if (success) {
window.parent.postMessage({status: "unregistrationdone"}, "*");
}
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
});
</script>

View File

@ -4,23 +4,11 @@
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
}
var isDone = false;
function done(reg) {
if (!isDone) {
ok(reg.waiting || reg.active, "Either active or waiting worker should be available.");
window.parent.postMessage({status: "registrationdone"}, "*");
isDone = true;
}
ok(reg.active, "The active worker should be available.");
window.parent.postMessage({status: "registrationdone"}, "*");
}
navigator.serviceWorker.register("https_test.js", {scope: "."})
.then(function(registration) {
if (registration.installing) {
registration.installing.onstatechange = function(e) {
done(registration);
};
} else {
done(registration);
}
});
navigator.serviceWorker.ready.then(done);
navigator.serviceWorker.register("https_test.js", {scope: "."});
</script>

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