author | Csoregi Natalia <ncsoregi@mozilla.com> |
Tue, 10 Apr 2018 12:56:48 +0300 | |
changeset 466079 | a8061a09cd7064a8783ca9e67979d77fb52e001e |
parent 466023 | db03e2cdae9ab05482f98e3c567896234c66e226 (current diff) |
parent 466078 | 73a3eabd2bd29d2ef8945648615f49ed29b326c9 (diff) |
child 466080 | 50b945170f334bb5c7c3dad5a8e975251a369b3b |
child 466090 | 42a2db5c685491852db3561e7e06661adbf0ab0d |
child 466107 | 7e2492c45ab41d26f131d64ebc9a3e10fae65e9f |
push id | 9165 |
push user | asasaki@mozilla.com |
push date | Thu, 26 Apr 2018 21:04:54 +0000 |
treeherder | mozilla-beta@064c3804de2e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 61.0a1 |
first release with | nightly linux32
a8061a09cd70
/
61.0a1
/
20180410100115
/
files
nightly linux64
a8061a09cd70
/
61.0a1
/
20180410100115
/
files
nightly mac
a8061a09cd70
/
61.0a1
/
20180410100115
/
files
nightly win32
a8061a09cd70
/
61.0a1
/
20180410100115
/
files
nightly win64
a8061a09cd70
/
61.0a1
/
20180410100115
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
61.0a1
/
20180410100115
/
pushlog to previous
nightly linux64
61.0a1
/
20180410100115
/
pushlog to previous
nightly mac
61.0a1
/
20180410100115
/
pushlog to previous
nightly win32
61.0a1
/
20180410100115
/
pushlog to previous
nightly win64
61.0a1
/
20180410100115
/
pushlog to previous
|
dom/base/nsIDOMSerializer.idl | file | annotate | diff | comparison | revisions | |
dom/interfaces/core/nsIDOMXMLDocument.idl | file | annotate | diff | comparison | revisions | |
dom/interfaces/xul/nsIDOMXULElement.idl | file | annotate | diff | comparison | revisions | |
dom/media/test/dynamic_redirect.sjs | file | annotate | diff | comparison | revisions | |
dom/webbrowserpersist/nsIWebBrowserPersistable.idl | file | annotate | diff | comparison | revisions | |
layout/painting/nsDisplayList.cpp | file | annotate | diff | comparison | revisions | |
modules/libpref/init/all.js | file | annotate | diff | comparison | revisions | |
testing/web-platform/meta/css/css-grid/alignment/grid-gutters-010.html.ini | file | annotate | diff | comparison | revisions |
--- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -27,17 +27,16 @@ #include "StyleInfo.h" #include "TableAccessible.h" #include "TableCellAccessible.h" #include "TreeWalker.h" #include "XULDocument.h" #include "nsIDOMElement.h" #include "nsIDOMXULButtonElement.h" -#include "nsIDOMXULElement.h" #include "nsIDOMXULLabelElement.h" #include "nsIDOMXULSelectCntrlEl.h" #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsINodeList.h" #include "nsPIDOMWindow.h" #include "nsIDocument.h" #include "nsIContent.h"
--- a/accessible/generic/FormControlAccessible.cpp +++ b/accessible/generic/FormControlAccessible.cpp @@ -4,17 +4,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // NOTE: alphabetically ordered #include "FormControlAccessible.h" #include "Role.h" #include "mozilla/FloatingPoint.h" -#include "nsIDOMXULElement.h" #include "nsIDOMXULControlElement.h" using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // ProgressMeterAccessible ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/tests/mochitest/common.js +++ b/accessible/tests/mochitest/common.js @@ -43,17 +43,16 @@ const nsIAccessibleTraversalRule = Ci.ns const nsIAccessibleValue = Ci.nsIAccessibleValue; const nsIObserverService = Ci.nsIObserverService; const nsIDOMDocument = Ci.nsIDOMDocument; const nsIDOMEvent = Ci.nsIDOMEvent; const nsIDOMNode = Ci.nsIDOMNode; const nsIDOMWindow = Ci.nsIDOMWindow; -const nsIDOMXULElement = Ci.nsIDOMXULElement; const nsIPropertyElement = Ci.nsIPropertyElement; // ////////////////////////////////////////////////////////////////////////////// // OS detect const MAC = (navigator.platform.includes("Mac")); const LINUX = (navigator.platform.includes("Linux"));
--- a/accessible/tests/mochitest/events.js +++ b/accessible/tests/mochitest/events.js @@ -1064,26 +1064,26 @@ function synthClick(aNodeOrID, aCheckerO if (targetNode instanceof nsIDOMDocument) { targetNode = this.DOMNode.body ? this.DOMNode.body : this.DOMNode.documentElement; } // Scroll the node into view, otherwise synth click may fail. if (isHTMLElement(targetNode)) { targetNode.scrollIntoView(true); - } else if (targetNode instanceof nsIDOMXULElement) { + } else if (ChromeUtils.getClassName(targetNode) == "XULElement") { var targetAcc = getAccessible(targetNode); targetAcc.scrollTo(SCROLL_TYPE_ANYWHERE); } var x = 1, y = 1; if (aArgs && ("where" in aArgs) && aArgs.where == "right") { if (isHTMLElement(targetNode)) x = targetNode.offsetWidth - 1; - else if (targetNode instanceof nsIDOMXULElement) + else if (ChromeUtils.getClassName(targetNode) == "XULElement") x = targetNode.boxObject.width - 1; } synthesizeMouse(targetNode, x, y, aArgs ? aArgs : {}); }; this.finalCheck = function synthClick_finalCheck() { // Scroll top window back. window.top.scrollTo(0, 0);
--- a/accessible/xul/XULMenuAccessible.cpp +++ b/accessible/xul/XULMenuAccessible.cpp @@ -9,17 +9,16 @@ #include "nsAccessibilityService.h" #include "nsAccUtils.h" #include "DocAccessible.h" #include "Role.h" #include "States.h" #include "XULFormControlAccessible.h" #include "nsIDOMElement.h" -#include "nsIDOMXULElement.h" #include "nsIMutableArray.h" #include "nsIDOMXULContainerElement.h" #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsIDOMXULMultSelectCntrlEl.h" #include "nsIServiceManager.h" #include "nsIPresShell.h" #include "nsIContent.h" #include "nsMenuBarFrame.h"
--- a/accessible/xul/XULSelectControlAccessible.cpp +++ b/accessible/xul/XULSelectControlAccessible.cpp @@ -8,17 +8,16 @@ #include "nsAccessibilityService.h" #include "DocAccessible.h" #include "nsIDOMXULContainerElement.h" #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsIDOMXULMultSelectCntrlEl.h" #include "nsIDOMElement.h" -#include "nsIDOMXULElement.h" #include "nsIMutableArray.h" #include "nsIServiceManager.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/KeyboardEventBinding.h" using namespace mozilla; using namespace mozilla::a11y;
--- a/accessible/xul/XULTreeAccessible.cpp +++ b/accessible/xul/XULTreeAccessible.cpp @@ -19,17 +19,16 @@ #include "XULTreeGridAccessible.h" #include "nsQueryObject.h" #include "nsComponentManagerUtils.h" #include "nsIAccessibleRelation.h" #include "nsIAutoCompleteInput.h" #include "nsIAutoCompletePopup.h" #include "nsIBoxObject.h" -#include "nsIDOMXULElement.h" #include "nsIDOMXULMenuListElement.h" #include "nsIDOMXULMultSelectCntrlEl.h" #include "nsIDOMXULTreeElement.h" #include "nsITreeSelection.h" #include "nsIMutableArray.h" #include "nsTreeBodyFrame.h" #include "nsTreeColumns.h" #include "nsTreeUtils.h"
--- a/browser/base/content/test/contextMenu/browser_contextmenu_linkopen.js +++ b/browser/base/content/test/contextMenu/browser_contextmenu_linkopen.js @@ -13,25 +13,25 @@ async function activateContextAndWaitFor switch (where) { case "tab": contextMenuItem += "intab"; openPromise = BrowserTestUtils.waitForNewTab(gBrowser, TEST_LINK, false); closeMethod = async (tab) => BrowserTestUtils.removeTab(tab); break; case "privatewindow": contextMenuItem += "private"; - openPromise = BrowserTestUtils.waitForNewWindow(TEST_LINK).then(win => { + openPromise = BrowserTestUtils.waitForNewWindow({url: TEST_LINK}).then(win => { ok(PrivateBrowsingUtils.isWindowPrivate(win), "Should have opened a private window."); return win; }); closeMethod = async (win) => BrowserTestUtils.closeWindow(win); break; case "window": // No contextMenuItem suffix for normal new windows; - openPromise = BrowserTestUtils.waitForNewWindow(TEST_LINK).then(win => { + openPromise = BrowserTestUtils.waitForNewWindow({url: TEST_LINK}).then(win => { ok(!PrivateBrowsingUtils.isWindowPrivate(win), "Should have opened a normal window."); return win; }); closeMethod = async (win) => BrowserTestUtils.closeWindow(win); break; } let contextMenu = document.getElementById("contentAreaContextMenu"); is(contextMenu.state, "closed", "checking if popup is closed");
--- a/browser/base/content/test/general/browser_newTabDrop.js +++ b/browser/base/content/test/general/browser_newTabDrop.js @@ -1,166 +1,219 @@ +const ANY_URL = undefined; + registerCleanupFunction(async function cleanup() { while (gBrowser.tabs.length > 1) { BrowserTestUtils.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]); } Services.search.currentEngine = originalEngine; let engine = Services.search.getEngineByName("MozSearch"); Services.search.removeEngine(engine); }); let originalEngine; add_task(async function test_setup() { + // This test opens multiple tabs and some confirm dialogs, that takes long. + requestLongerTimeout(2); + // Stop search-engine loads from hitting the network Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET", "http://example.com/?q={searchTerms}"); let engine = Services.search.getEngineByName("MozSearch"); originalEngine = Services.search.currentEngine; Services.search.currentEngine = engine; }); // New Tab Button opens any link. -add_task(async function() { await dropText("mochi.test/first", 1); }); -add_task(async function() { await dropText("javascript:'bad'", 1); }); -add_task(async function() { await dropText("jAvascript:'bad'", 1); }); -add_task(async function() { await dropText("mochi.test/second", 1); }); -add_task(async function() { await dropText("data:text/html,bad", 1); }); -add_task(async function() { await dropText("mochi.test/third", 1); }); +add_task(async function single_url() { + await dropText("mochi.test/first", + ["http://www.mochi.test/first"]); +}); +add_task(async function single_javascript() { + await dropText("javascript:'bad'", + ["javascript:'bad'"]); +}); +add_task(async function single_javascript_capital() { + await dropText("jAvascript:'bad'", + ["javascript:'bad'"]); +}); +add_task(async function single_url2() { + await dropText("mochi.test/second", + ["http://www.mochi.test/second"]); +}); +add_task(async function single_data_url() { + await dropText("data:text/html,bad", + ["data:text/html,bad"]); +}); +add_task(async function single_url3() { + await dropText("mochi.test/third", + ["http://www.mochi.test/third"]); +}); // Single text/plain item, with multiple links. -add_task(async function() { await dropText("mochi.test/1\nmochi.test/2", 2); }); -add_task(async function() { await dropText("javascript:'bad1'\nmochi.test/3", 2); }); -add_task(async function() { await dropText("mochi.test/4\ndata:text/html,bad1", 2); }); +add_task(async function multiple_urls() { + await dropText("mochi.test/1\nmochi.test/2", + [ + "http://www.mochi.test/1", + "http://www.mochi.test/2", + ]); +}); +add_task(async function multiple_urls_javascript() { + await dropText("javascript:'bad1'\nmochi.test/3", + [ + "javascript:'bad1'", + "http://www.mochi.test/3", + ]); +}); +add_task(async function multiple_urls_data() { + await dropText("mochi.test/4\ndata:text/html,bad1", + [ + "http://www.mochi.test/4", + "data:text/html,bad1", + ]); +}); // Multiple text/plain items, with single and multiple links. -add_task(async function() { +add_task(async function multiple_items_single_and_multiple_links() { await drop([[{type: "text/plain", data: "mochi.test/5"}], [{type: "text/plain", - data: "mochi.test/6\nmochi.test/7"}]], 3); + data: "mochi.test/6\nmochi.test/7"}]], + [ + "http://www.mochi.test/5", + "http://www.mochi.test/6", + "http://www.mochi.test/7", + ]); }); // Single text/x-moz-url item, with multiple links. // "text/x-moz-url" has titles in even-numbered lines. -add_task(async function() { +add_task(async function single_moz_url_multiple_links() { await drop([[{type: "text/x-moz-url", - data: "mochi.test/8\nTITLE8\nmochi.test/9\nTITLE9"}]], 2); + data: "mochi.test/8\nTITLE8\nmochi.test/9\nTITLE9"}]], + [ + "http://www.mochi.test/8", + "http://www.mochi.test/9", + ]); }); // Single item with multiple types. -add_task(async function() { +add_task(async function single_item_multiple_types() { await drop([[{type: "text/plain", data: "mochi.test/10"}, {type: "text/x-moz-url", - data: "mochi.test/11\nTITLE11"}]], 1); + data: "mochi.test/11\nTITLE11"}]], + ["http://www.mochi.test/11"]); }); // Warn when too many URLs are dropped. add_task(async function multiple_tabs_under_max() { let urls = []; for (let i = 0; i < 5; i++) { urls.push("mochi.test/multi" + i); } - await dropText(urls.join("\n"), 5); + await dropText(urls.join("\n"), + [ + "http://www.mochi.test/multi0", + "http://www.mochi.test/multi1", + "http://www.mochi.test/multi2", + "http://www.mochi.test/multi3", + "http://www.mochi.test/multi4", + ]); }); add_task(async function multiple_tabs_over_max_accept() { await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]); let confirmPromise = BrowserTestUtils.promiseAlertDialog("accept"); let urls = []; for (let i = 0; i < 5; i++) { urls.push("mochi.test/accept" + i); } - await dropText(urls.join("\n"), 5); + await dropText(urls.join("\n"), + [ + "http://www.mochi.test/accept0", + "http://www.mochi.test/accept1", + "http://www.mochi.test/accept2", + "http://www.mochi.test/accept3", + "http://www.mochi.test/accept4", + ]); await confirmPromise; await popPrefs(); }); add_task(async function multiple_tabs_over_max_cancel() { await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]); let confirmPromise = BrowserTestUtils.promiseAlertDialog("cancel"); let urls = []; for (let i = 0; i < 5; i++) { urls.push("mochi.test/cancel" + i); } - await dropText(urls.join("\n"), 0); + await dropText(urls.join("\n"), []); await confirmPromise; await popPrefs(); }); // Open URLs ignoring non-URL. add_task(async function multiple_urls() { await dropText(` mochi.test/urls0 mochi.test/urls1 mochi.test/urls2 non url0 mochi.test/urls3 non url1 non url2 -`, 4); +`, [ + "http://www.mochi.test/urls0", + "http://www.mochi.test/urls1", + "http://www.mochi.test/urls2", + "http://www.mochi.test/urls3", +]); }); // Open single search if there's no URL. add_task(async function multiple_text() { await dropText(` non url0 non url1 non url2 -`, 1); +`, [ + ANY_URL +]); }); -function dropText(text, expectedTabOpenCount = 0) { - return drop([[{type: "text/plain", data: text}]], expectedTabOpenCount); +function dropText(text, expectedURLs) { + return drop([[{type: "text/plain", data: text}]], expectedURLs); } -async function drop(dragData, expectedTabOpenCount = 0) { +async function drop(dragData, expectedURLs) { let dragDataString = JSON.stringify(dragData); - info(`Starting test for datagData:${dragDataString}; expectedTabOpenCount:${expectedTabOpenCount}`); + info(`Starting test for dragData:${dragDataString}; expectedURLs.length:${expectedURLs.length}`); let EventUtils = {}; Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils); // Since synthesizeDrop triggers the srcElement, need to use another button. let dragSrcElement = document.getElementById("downloads-button"); ok(dragSrcElement, "Downloads button exists"); let newTabButton = document.getElementById("new-tab-button"); ok(newTabButton, "New Tab button exists"); let awaitDrop = BrowserTestUtils.waitForEvent(newTabButton, "drop"); - let actualTabOpenCount = 0; - let openedTabs = []; - let promiseTabsOpen = null; - let resolve = null; - let handler = function(event) { - openedTabs.push(event.target); - actualTabOpenCount++; - if (actualTabOpenCount == expectedTabOpenCount && resolve) { - resolve(); - } - }; - gBrowser.tabContainer.addEventListener("TabOpen", handler); - if (expectedTabOpenCount) { - promiseTabsOpen = new Promise(r => { resolve = r; }); - } + + let loadedPromises = expectedURLs.map( + url => BrowserTestUtils.waitForNewTab(gBrowser, url, false, true)); EventUtils.synthesizeDrop(dragSrcElement, newTabButton, dragData, "link", window); - if (promiseTabsOpen) { - await promiseTabsOpen; - info("Got TabOpen event"); - for (let tab of openedTabs) { - BrowserTestUtils.removeTab(tab); - } + let tabs = await Promise.all(loadedPromises); + for (let tab of tabs) { + BrowserTestUtils.removeTab(tab); } await awaitDrop; ok(true, "Got drop event"); - - gBrowser.tabContainer.removeEventListener("TabOpen", handler); - is(actualTabOpenCount, expectedTabOpenCount, - "No other tabs are opened"); }
--- a/browser/base/content/test/general/browser_newWindowDrop.js +++ b/browser/base/content/test/general/browser_newWindowDrop.js @@ -26,143 +26,184 @@ add_task(async function test_setup() { CustomizableUI.ensureWidgetPlacedInWindow("new-window-button", window); registerCleanupFunction(function() { CustomizableUI.removeWidgetFromArea("new-window-button"); }); } }); // New Window Button opens any link. -add_task(async function() { await dropText("mochi.test/first", 1); }); -add_task(async function() { await dropText("javascript:'bad'", 1); }); -add_task(async function() { await dropText("jAvascript:'bad'", 1); }); -add_task(async function() { await dropText("mochi.test/second", 1); }); -add_task(async function() { await dropText("data:text/html,bad", 1); }); -add_task(async function() { await dropText("mochi.test/third", 1); }); +add_task(async function single_url() { + await dropText("mochi.test/first", + ["http://www.mochi.test/first"]); +}); +add_task(async function single_javascript() { + await dropText("javascript:'bad'", + ["about:blank"]); +}); +add_task(async function single_javascript_capital() { + await dropText("jAvascript:'bad'", + ["about:blank"]); +}); +add_task(async function single_url2() { + await dropText("mochi.test/second", + ["http://www.mochi.test/second"]); +}); +add_task(async function single_data_url() { + await dropText("data:text/html,bad", + ["data:text/html,bad"]); +}); +add_task(async function single_url3() { + await dropText("mochi.test/third", + ["http://www.mochi.test/third"]); +}); // Single text/plain item, with multiple links. -add_task(async function() { await dropText("mochi.test/1\nmochi.test/2", 2); }); -add_task(async function() { await dropText("javascript:'bad1'\nmochi.test/3", 2); }); -add_task(async function() { await dropText("mochi.test/4\ndata:text/html,bad1", 2); }); +add_task(async function multiple_urls() { + await dropText("mochi.test/1\nmochi.test/2", + [ + "http://www.mochi.test/1", + "http://www.mochi.test/2", + ]); +}); +add_task(async function multiple_urls_javascript() { + await dropText("javascript:'bad1'\nmochi.test/3", + [ + "javascript:'bad1'", + "http://www.mochi.test/3", + ]); +}); +add_task(async function multiple_urls_data() { + await dropText("mochi.test/4\ndata:text/html,bad1", + [ + "http://www.mochi.test/4", + "data:text/html,bad1", + ]); +}); // Multiple text/plain items, with single and multiple links. -add_task(async function() { +add_task(async function multiple_items_single_and_multiple_links() { await drop([[{type: "text/plain", data: "mochi.test/5"}], [{type: "text/plain", - data: "mochi.test/6\nmochi.test/7"}]], 3); + data: "mochi.test/6\nmochi.test/7"}]], + [ + "http://www.mochi.test/5", + "http://www.mochi.test/6", + "http://www.mochi.test/7", + ]); }); // Single text/x-moz-url item, with multiple links. // "text/x-moz-url" has titles in even-numbered lines. -add_task(async function() { +add_task(async function single_moz_url_multiple_links() { await drop([[{type: "text/x-moz-url", - data: "mochi.test/8\nTITLE8\nmochi.test/9\nTITLE9"}]], 2); + data: "mochi.test/8\nTITLE8\nmochi.test/9\nTITLE9"}]], + [ + "http://www.mochi.test/8", + "http://www.mochi.test/9", + ]); }); // Single item with multiple types. -add_task(async function() { +add_task(async function single_item_multiple_types() { await drop([[{type: "text/plain", data: "mochi.test/10"}, {type: "text/x-moz-url", - data: "mochi.test/11\nTITLE11"}]], 1); + data: "mochi.test/11\nTITLE11"}]], + ["http://www.mochi.test/11"]); }); // Warn when too many URLs are dropped. add_task(async function multiple_tabs_under_max() { let urls = []; for (let i = 0; i < 5; i++) { urls.push("mochi.test/multi" + i); } - await dropText(urls.join("\n"), 5); + await dropText(urls.join("\n"), + [ + "http://www.mochi.test/multi0", + "http://www.mochi.test/multi1", + "http://www.mochi.test/multi2", + "http://www.mochi.test/multi3", + "http://www.mochi.test/multi4", + ]); }); add_task(async function multiple_tabs_over_max_accept() { await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]); let confirmPromise = BrowserTestUtils.promiseAlertDialog("accept"); let urls = []; for (let i = 0; i < 5; i++) { urls.push("mochi.test/accept" + i); } - await dropText(urls.join("\n"), 5, true); + await dropText(urls.join("\n"), + [ + "http://www.mochi.test/accept0", + "http://www.mochi.test/accept1", + "http://www.mochi.test/accept2", + "http://www.mochi.test/accept3", + "http://www.mochi.test/accept4", + ], + true); await confirmPromise; await popPrefs(); }); add_task(async function multiple_tabs_over_max_cancel() { await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]); let confirmPromise = BrowserTestUtils.promiseAlertDialog("cancel"); let urls = []; for (let i = 0; i < 5; i++) { urls.push("mochi.test/cancel" + i); } - await dropText(urls.join("\n"), 0, true); + await dropText(urls.join("\n"), [], true); await confirmPromise; await popPrefs(); }); -function dropText(text, expectedWindowOpenCount = 0, +function dropText(text, expectedURLs, ignoreFirstWindow = false) { - return drop([[{type: "text/plain", data: text}]], expectedWindowOpenCount, + return drop([[{type: "text/plain", data: text}]], expectedURLs, ignoreFirstWindow); } -async function drop(dragData, expectedWindowOpenCount = 0, +async function drop(dragData, expectedURLs, ignoreFirstWindow = false) { let dragDataString = JSON.stringify(dragData); - info(`Starting test for datagData:${dragDataString}; expectedWindowOpenCount:${expectedWindowOpenCount}`); + info(`Starting test for dragData:${dragDataString}; expectedURLs.length:${expectedURLs.length}`); let EventUtils = {}; Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils); // Since synthesizeDrop triggers the srcElement, need to use another button. let dragSrcElement = document.getElementById("downloads-button"); ok(dragSrcElement, "Downloads button exists"); let newWindowButton = document.getElementById("new-window-button"); ok(newWindowButton, "New Window button exists"); let tmp = {}; ChromeUtils.import("resource://testing-common/TestUtils.jsm", tmp); let awaitDrop = BrowserTestUtils.waitForEvent(newWindowButton, "drop"); - let actualWindowOpenCount = 0; - let openedWindows = []; - let checkCount = function(window) { - if (ignoreFirstWindow) { - // When dropping too many dialog, the confirm dialog is opened and - // domwindowopened notification is dispatched for it, before opening - // windows for dropped items. Ignore it. - ignoreFirstWindow = false; - return false; - } - // Add observer as soon as domWindow is opened to avoid missing the topic. - let awaitStartup = tmp.TestUtils.topicObserved("browser-delayed-startup-finished", - subject => subject == window); - openedWindows.push([window, awaitStartup]); - actualWindowOpenCount++; - return actualWindowOpenCount == expectedWindowOpenCount; - }; - let awaitWindowOpen = expectedWindowOpenCount && BrowserTestUtils.domWindowOpened(null, checkCount); + let loadedPromises = expectedURLs.map( + url => BrowserTestUtils.waitForNewWindow({ + url, + anyWindow: true, + maybeErrorPage: true, + })); EventUtils.synthesizeDrop(dragSrcElement, newWindowButton, dragData, "link", window); - let windowsOpened = false; - if (awaitWindowOpen) { - await awaitWindowOpen; - info("Got Window opened"); - windowsOpened = true; - for (let [window, awaitStartup] of openedWindows.reverse()) { - // Wait for startup before closing, to properly close the browser window. - await awaitStartup; - await BrowserTestUtils.closeWindow(window); - } + let windows = await Promise.all(loadedPromises); + for (let window of windows) { + await BrowserTestUtils.closeWindow(window); } - is(windowsOpened, !!expectedWindowOpenCount, `Windows for ${dragDataString} should only open if any of dropped items are valid`); await awaitDrop; ok(true, "Got drop event"); }
--- a/browser/base/content/test/general/browser_new_http_window_opened_from_file_tab.js +++ b/browser/base/content/test/general/browser_new_http_window_opened_from_file_tab.js @@ -19,33 +19,33 @@ add_task(async function() { // Set pref to open in new window. Services.prefs.setIntPref("browser.link.open_newwindow", 2); registerCleanupFunction(function() { Services.prefs.clearUserPref("browser.link.open_newwindow"); }); // Open new http window from JavaScript in file:// page and check that we get // a new window with the correct page and features. - let promiseNewWindow = BrowserTestUtils.waitForNewWindow(TEST_HTTP); + let promiseNewWindow = BrowserTestUtils.waitForNewWindow({url: TEST_HTTP}); await ContentTask.spawn(browser, TEST_HTTP, uri => { content.open(uri, "_blank"); }); let win = await promiseNewWindow; registerCleanupFunction(async function() { await BrowserTestUtils.closeWindow(win); }); ok(win, "Check that an http window loaded when using window.open."); ok(win.menubar.visible, "Check that the menu bar on the new window is visible."); ok(win.toolbar.visible, "Check that the tool bar on the new window is visible."); // Open new http window from a link in file:// page and check that we get a // new window with the correct page and features. - promiseNewWindow = BrowserTestUtils.waitForNewWindow(TEST_HTTP); + promiseNewWindow = BrowserTestUtils.waitForNewWindow({url: TEST_HTTP}); await BrowserTestUtils.synthesizeMouseAtCenter("#linkToExample", {}, browser); let win2 = await promiseNewWindow; registerCleanupFunction(async function() { await BrowserTestUtils.closeWindow(win2); }); ok(win2, "Check that an http window loaded when using link."); ok(win2.menubar.visible, "Check that the menu bar on the new window is visible.");
--- a/browser/base/content/test/general/browser_tabDrop.js +++ b/browser/base/content/test/general/browser_tabDrop.js @@ -1,8 +1,10 @@ +const ANY_URL = undefined; + registerCleanupFunction(async function cleanup() { while (gBrowser.tabs.length > 1) { BrowserTestUtils.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]); } Services.search.currentEngine = originalEngine; let engine = Services.search.getEngineByName("MozSearch"); Services.search.removeEngine(engine); }); @@ -12,129 +14,172 @@ add_task(async function test_setup() { // Stop search-engine loads from hitting the network Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET", "http://example.com/?q={searchTerms}"); let engine = Services.search.getEngineByName("MozSearch"); originalEngine = Services.search.currentEngine; Services.search.currentEngine = engine; }); -add_task(async function() { await dropText("mochi.test/first", 1); }); -add_task(async function() { await dropText("javascript:'bad'"); }); -add_task(async function() { await dropText("jAvascript:'bad'"); }); -add_task(async function() { await dropText("search this", 1); }); -add_task(async function() { await dropText("mochi.test/second", 1); }); -add_task(async function() { await dropText("data:text/html,bad"); }); -add_task(async function() { await dropText("mochi.test/third", 1); }); +add_task(async function single_url() { + await dropText("mochi.test/first", + ["http://www.mochi.test/first"]); +}); +add_task(async function single_javascript() { + await dropText("javascript:'bad'", []); +}); +add_task(async function single_javascript_capital() { + await dropText("jAvascript:'bad'", []); +}); +add_task(async function single_search() { + await dropText("search this", + [ANY_URL]); +}); +add_task(async function single_url2() { + await dropText("mochi.test/second", + ["http://www.mochi.test/second"]); +}); +add_task(async function single_data_url() { + await dropText("data:text/html,bad", []); +}); +add_task(async function single_url3() { + await dropText("mochi.test/third", + ["http://www.mochi.test/third"]); +}); // Single text/plain item, with multiple links. -add_task(async function() { await dropText("mochi.test/1\nmochi.test/2", 2); }); -add_task(async function() { await dropText("javascript:'bad1'\nmochi.test/3", 0); }); -add_task(async function() { await dropText("mochi.test/4\ndata:text/html,bad1", 0); }); +add_task(async function multiple_urls() { + await dropText("mochi.test/1\nmochi.test/2", + [ + "http://www.mochi.test/1", + "http://www.mochi.test/2", + ]); +}); +add_task(async function multiple_urls_javascript() { + await dropText("javascript:'bad1'\nmochi.test/3", []); +}); +add_task(async function multiple_urls_data() { + await dropText("mochi.test/4\ndata:text/html,bad1", []); +}); // Multiple text/plain items, with single and multiple links. -add_task(async function() { +add_task(async function multiple_items_single_and_multiple_links() { await drop([[{type: "text/plain", data: "mochi.test/5"}], [{type: "text/plain", - data: "mochi.test/6\nmochi.test/7"}]], 3); + data: "mochi.test/6\nmochi.test/7"}]], + [ + "http://www.mochi.test/5", + "http://www.mochi.test/6", + "http://www.mochi.test/7", + ]); }); // Single text/x-moz-url item, with multiple links. // "text/x-moz-url" has titles in even-numbered lines. -add_task(async function() { +add_task(async function single_moz_url_multiple_links() { await drop([[{type: "text/x-moz-url", - data: "mochi.test/8\nTITLE8\nmochi.test/9\nTITLE9"}]], 2); + data: "mochi.test/8\nTITLE8\nmochi.test/9\nTITLE9"}]], + [ + "http://www.mochi.test/8", + "http://www.mochi.test/9", + ]); }); // Single item with multiple types. -add_task(async function() { +add_task(async function single_item_multiple_types() { await drop([[{type: "text/plain", data: "mochi.test/10"}, {type: "text/x-moz-url", - data: "mochi.test/11\nTITLE11"}]], 1); + data: "mochi.test/11\nTITLE11"}]], + ["http://www.mochi.test/11"]); }); // Warn when too many URLs are dropped. add_task(async function multiple_tabs_under_max() { let urls = []; for (let i = 0; i < 5; i++) { urls.push("mochi.test/multi" + i); } - await dropText(urls.join("\n"), 5); + await dropText(urls.join("\n"), + [ + "http://www.mochi.test/multi0", + "http://www.mochi.test/multi1", + "http://www.mochi.test/multi2", + "http://www.mochi.test/multi3", + "http://www.mochi.test/multi4", + ]); }); add_task(async function multiple_tabs_over_max_accept() { await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]); let confirmPromise = BrowserTestUtils.promiseAlertDialog("accept"); let urls = []; for (let i = 0; i < 5; i++) { urls.push("mochi.test/accept" + i); } - await dropText(urls.join("\n"), 5, true); + await dropText(urls.join("\n"), + [ + "http://www.mochi.test/accept0", + "http://www.mochi.test/accept1", + "http://www.mochi.test/accept2", + "http://www.mochi.test/accept3", + "http://www.mochi.test/accept4", + ]); await confirmPromise; await popPrefs(); }); add_task(async function multiple_tabs_over_max_cancel() { await pushPrefs(["browser.tabs.maxOpenBeforeWarn", 4]); let confirmPromise = BrowserTestUtils.promiseAlertDialog("cancel"); let urls = []; for (let i = 0; i < 5; i++) { urls.push("mochi.test/cancel" + i); } - await dropText(urls.join("\n"), 0, true); + await dropText(urls.join("\n"), []); await confirmPromise; await popPrefs(); }); -function dropText(text, expectedTabOpenCount = 0) { - return drop([[{type: "text/plain", data: text}]], expectedTabOpenCount); +function dropText(text, expectedURLs) { + return drop([[{type: "text/plain", data: text}]], expectedURLs); } -async function drop(dragData, expectedTabOpenCount = 0) { +async function drop(dragData, expectedURLs) { let dragDataString = JSON.stringify(dragData); - info(`Starting test for datagData:${dragDataString}; expectedTabOpenCount:${expectedTabOpenCount}`); + info(`Starting test for dragData:${dragDataString}; expectedURLs.length:${expectedURLs.length}`); let EventUtils = {}; Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils); let awaitDrop = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "drop"); - let actualTabOpenCount = 0; - let openedTabs = []; - let checkCount = function(event) { - openedTabs.push(event.target); - actualTabOpenCount++; - return actualTabOpenCount == expectedTabOpenCount; - }; - let awaitTabOpen = expectedTabOpenCount && BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen", false, checkCount); + + let loadedPromises = expectedURLs.map( + url => BrowserTestUtils.waitForNewTab(gBrowser, url, false, true)); + // A drop type of "link" onto an existing tab would normally trigger a // load in that same tab, but tabbrowser code in _getDragTargetTab treats // drops on the outer edges of a tab differently (loading a new tab // instead). Make events created by synthesizeDrop have all of their // coordinates set to 0 (screenX/screenY), so they're treated as drops // on the outer edge of the tab, thus they open new tabs. var event = { clientX: 0, clientY: 0, screenX: 0, screenY: 0, }; EventUtils.synthesizeDrop(gBrowser.selectedTab, gBrowser.selectedTab, dragData, "link", window, undefined, event); - let tabsOpened = false; - if (awaitTabOpen) { - await awaitTabOpen; - info("Got TabOpen event"); - tabsOpened = true; - for (let tab of openedTabs) { - BrowserTestUtils.removeTab(tab); - } + + let tabs = await Promise.all(loadedPromises); + for (let tab of tabs) { + BrowserTestUtils.removeTab(tab); } - is(tabsOpened, !!expectedTabOpenCount, `Tabs for ${dragDataString} should only open if any of dropped items are valid`); await awaitDrop; ok(true, "Got drop event"); }
--- a/browser/base/content/test/popups/browser_popupUI.js +++ b/browser/base/content/test/popups/browser_popupUI.js @@ -1,13 +1,13 @@ function test() { waitForExplicitFinish(); SpecialPowers.pushPrefEnv({ set: [[ "dom.disable_open_during_load", false ]] }); - let popupOpened = BrowserTestUtils.waitForNewWindow("about:blank"); + let popupOpened = BrowserTestUtils.waitForNewWindow({url: "about:blank"}); BrowserTestUtils.openNewForegroundTab(gBrowser, "data:text/html,<html><script>popup=open('about:blank','','width=300,height=200')</script>" ); popupOpened.then((win) => testPopupUI(win)); } function testPopupUI(win) { var doc = win.document;
--- a/browser/components/extensions/parent/ext-browser.js +++ b/browser/components/extensions/parent/ext-browser.js @@ -26,17 +26,17 @@ let windowTracker; const getSender = (extension, target, sender) => { let tabId; if ("tabId" in sender) { // The message came from a privileged extension page running in a tab. In // that case, it should include a tabId property (which is filled in by the // page-open listener below). tabId = sender.tabId; delete sender.tabId; - } else if (target instanceof Ci.nsIDOMXULElement || + } else if (ExtensionUtils.instanceOf(target, "XULElement") || ExtensionUtils.instanceOf(target, "HTMLIFrameElement")) { tabId = tabTracker.getBrowserData(target).tabId; } if (tabId) { let tab = extension.tabManager.get(tabId, null); if (tab) { sender.tab = tab.convert();
--- a/browser/components/extensions/test/browser/browser_ext_windows.js +++ b/browser/components/extensions/test/browser/browser_ext_windows.js @@ -89,17 +89,17 @@ add_task(async function testWindowTitle( permissions: ["tabs"], }, }); await extension.startup(); let {Management: {global: {windowTracker}}} = ChromeUtils.import("resource://gre/modules/Extension.jsm", {}); async function createApiWin(options) { - let promiseLoaded = BrowserTestUtils.waitForNewWindow(START_URL); + let promiseLoaded = BrowserTestUtils.waitForNewWindow({url: START_URL}); extension.sendMessage("create", options); let apiWin = await extension.awaitMessage("created"); let realWin = windowTracker.getWindow(apiWin.id); await promiseLoaded; let expectedPreface = options.titlePreface ? options.titlePreface : ""; ok(realWin.document.title.startsWith(expectedPreface), "Created window has the expected title preface."); ok(realWin.document.title.includes(START_TITLE),
--- a/browser/components/privatebrowsing/test/browser/browser_oa_private_browsing_window.js +++ b/browser/components/privatebrowsing/test/browser/browser_oa_private_browsing_window.js @@ -1,17 +1,17 @@ "use strict"; const PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com"); const TEST_PAGE = PATH + "file_triggeringprincipal_oa.html"; const DUMMY_PAGE = PATH + "empty_file.html"; add_task(async function test_principal_right_click_open_link_in_new_private_win() { await BrowserTestUtils.withNewTab(TEST_PAGE, async function(browser) { - let promiseNewWindow = BrowserTestUtils.waitForNewWindow(DUMMY_PAGE); + let promiseNewWindow = BrowserTestUtils.waitForNewWindow({url: DUMMY_PAGE}); // simulate right-click open link in new private window BrowserTestUtils.waitForEvent(document, "popupshown", false, event => { document.getElementById("context-openlinkprivate").doCommand(); event.target.hidePopup(); return true; }); BrowserTestUtils.synthesizeMouseAtCenter("#checkPrincipalOA",
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js @@ -35,17 +35,17 @@ add_task(async function test_private_pop // First, open a private browsing window, and load our // testing page. let privBrowser = privWin.gBrowser.selectedBrowser; await BrowserTestUtils.loadURI(privBrowser, WINDOW_BODY); await BrowserTestUtils.browserLoaded(privBrowser); // Next, click on the link in the testing page, and ensure // that a private popup window is opened. - let openedPromise = BrowserTestUtils.waitForNewWindow(POPUP_LINK); + let openedPromise = BrowserTestUtils.waitForNewWindow({url: POPUP_LINK}); await BrowserTestUtils.synthesizeMouseAtCenter("#first", {}, privBrowser); let popupWin = await openedPromise; ok(PrivateBrowsingUtils.isWindowPrivate(popupWin), "Popup window was private."); // Now click on the link in the popup, and ensure that a new // tab is opened in the original private browsing window.
--- a/browser/components/sessionstore/test/browser_394759_behavior.js +++ b/browser/components/sessionstore/test/browser_394759_behavior.js @@ -21,17 +21,17 @@ */ function testWindows(windowsToOpen, expectedResults) { return (async function() { for (let winData of windowsToOpen) { let features = "chrome,dialog=no," + (winData.isPopup ? "all=no" : "all"); let url = "http://example.com/?window=" + windowsToOpen.length; - let openWindowPromise = BrowserTestUtils.waitForNewWindow(url); + let openWindowPromise = BrowserTestUtils.waitForNewWindow({url}); openDialog(getBrowserURL(), "", features, url); let win = await openWindowPromise; await BrowserTestUtils.closeWindow(win); } let closedWindowData = JSON.parse(ss.getClosedWindowData()); let numPopups = closedWindowData.filter(function(el, i, arr) { return el.isPopup;
new file mode 100644 --- /dev/null +++ b/dom/base/crashtests/1449601.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> + <body> + <script> + var blob = new Blob(["foo"], { type: "text/plain" }); + var url = URL.createObjectURL(blob); + var ifr = document.createElement("iframe"); + ifr.src = url; + document.body.appendChild(ifr); + + onload = function() { + try { window.find('foo',false,true,true,true,true) } catch(e) { } + } + </script> + </body> +</html>
--- a/dom/base/crashtests/crashtests.list +++ b/dom/base/crashtests/crashtests.list @@ -233,9 +233,10 @@ load 1405771.html load 1406109-1.html pref(dom.webcomponents.shadowdom.enabled,true) load 1324463.html pref(dom.webcomponents.customelements.enabled,true) load 1413815.html load 1411473.html pref(dom.webcomponents.shadowdom.enabled,false) load 1422931.html pref(dom.webcomponents.shadowdom.enabled,true) load 1419799.html skip-if(!browserIsRemote) pref(dom.webcomponents.customelements.enabled,true) pref(dom.disable_open_during_load,false) load 1419902.html # skip on non e10s loads, Bug 1419902 pref(dom.webcomponents.shadowdom.enabled,true) load 1428053.html +load 1449601.html load 1445670.html
--- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -13,17 +13,16 @@ with Files("**"): TEST_DIRS += ['test'] XPIDL_SOURCES += [ 'mozIDOMWindow.idl', 'nsIContentPolicy.idl', 'nsIDocumentEncoder.idl', 'nsIDOMDOMRequest.idl', 'nsIDOMParser.idl', - 'nsIDOMSerializer.idl', 'nsIDroppedLinkHandler.idl', 'nsIFrameLoaderOwner.idl', 'nsIImageLoadingContent.idl', 'nsIMessageManager.idl', 'nsIObjectLoadingContent.idl', 'nsIPerformanceMetrics.idl', 'nsIRemoteWindowContext.idl', 'nsIScriptChannel.idl',
--- a/dom/base/nsDOMSerializer.cpp +++ b/dom/base/nsDOMSerializer.cpp @@ -17,130 +17,106 @@ #include "nsINode.h" using namespace mozilla; nsDOMSerializer::nsDOMSerializer() { } -nsDOMSerializer::~nsDOMSerializer() +static already_AddRefed<nsIDocumentEncoder> +SetUpEncoder(nsINode& aRoot, const nsAString& aCharset, ErrorResult& aRv) { -} - -// QueryInterface implementation for nsDOMSerializer -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMSerializer) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) - NS_INTERFACE_MAP_ENTRY(nsIDOMSerializer) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMSerializer, mOwner) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMSerializer) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMSerializer) - - -static nsresult -SetUpEncoder(nsIDOMNode *aRoot, const nsACString& aCharset, - nsIDocumentEncoder **aEncoder) -{ - *aEncoder = nullptr; - nsresult rv; nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "application/xhtml+xml", &rv); - if (NS_FAILED(rv)) - return rv; + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } - nsCOMPtr<nsINode> root = do_QueryInterface(aRoot); - MOZ_ASSERT(root); - - nsIDocument* doc = root->OwnerDoc(); - bool entireDocument = (doc == root); - nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc)); + nsIDocument* doc = aRoot.OwnerDoc(); + bool entireDocument = (doc == &aRoot); // This method will fail if no document - rv = encoder->Init(domDoc, NS_LITERAL_STRING("application/xhtml+xml"), - nsIDocumentEncoder::OutputRaw | - nsIDocumentEncoder::OutputDontRewriteEncodingDeclaration); + rv = encoder-> + NativeInit(doc, NS_LITERAL_STRING("application/xhtml+xml"), + nsIDocumentEncoder::OutputRaw | + nsIDocumentEncoder::OutputDontRewriteEncodingDeclaration); - if (NS_FAILED(rv)) - return rv; + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } - nsAutoCString charset(aCharset); + NS_ConvertUTF16toUTF8 charset(aCharset); if (charset.IsEmpty()) { - nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); - NS_ASSERTION(doc, "Need a document"); doc->GetDocumentCharacterSet()->Name(charset); } rv = encoder->SetCharset(charset); - if (NS_FAILED(rv)) - return rv; + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } // If we are working on the entire document we do not need to // specify which part to serialize if (!entireDocument) { - rv = encoder->SetNode(aRoot); + rv = encoder->SetNativeNode(&aRoot); } - if (NS_SUCCEEDED(rv)) { - encoder.forget(aEncoder); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; } - return rv; + return encoder.forget(); } void nsDOMSerializer::SerializeToString(nsINode& aRoot, nsAString& aStr, - ErrorResult& rv) + ErrorResult& aRv) { - rv = nsDOMSerializer::SerializeToString(aRoot.AsDOMNode(), aStr); -} + aStr.Truncate(); -NS_IMETHODIMP -nsDOMSerializer::SerializeToString(nsIDOMNode *aRoot, nsAString& _retval) -{ - NS_ENSURE_ARG_POINTER(aRoot); - - _retval.Truncate(); - - if (!nsContentUtils::CanCallerAccess(aRoot)) { - return NS_ERROR_DOM_SECURITY_ERR; + if (!nsContentUtils::CanCallerAccess(&aRoot)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; } - nsCOMPtr<nsIDocumentEncoder> encoder; - nsresult rv = SetUpEncoder(aRoot, EmptyCString(), getter_AddRefs(encoder)); - if (NS_FAILED(rv)) - return rv; + nsCOMPtr<nsIDocumentEncoder> encoder = + SetUpEncoder(aRoot, EmptyString(), aRv); + if (aRv.Failed()) { + return; + } - return encoder->EncodeToString(_retval); + nsresult rv = encoder->EncodeToString(aStr); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } } void nsDOMSerializer::SerializeToStream(nsINode& aRoot, nsIOutputStream* aStream, - const nsAString& aCharset, ErrorResult& rv) + const nsAString& aCharset, + ErrorResult& aRv) { - rv = nsDOMSerializer::SerializeToStream(aRoot.AsDOMNode(), aStream, - NS_ConvertUTF16toUTF8(aCharset)); -} + if (NS_WARN_IF(!aStream)) { + aRv.Throw(NS_ERROR_INVALID_ARG); + return; + } -NS_IMETHODIMP -nsDOMSerializer::SerializeToStream(nsIDOMNode *aRoot, - nsIOutputStream *aStream, - const nsACString& aCharset) -{ - NS_ENSURE_ARG_POINTER(aRoot); - NS_ENSURE_ARG_POINTER(aStream); // The charset arg can be empty, in which case we get the document's // charset and use that when serializing. - if (!nsContentUtils::CanCallerAccess(aRoot)) { - return NS_ERROR_DOM_SECURITY_ERR; + // No point doing a CanCallerAccess check, because we can only be + // called by system JS or C++. + nsCOMPtr<nsIDocumentEncoder> encoder = + SetUpEncoder(aRoot, aCharset, aRv); + if (aRv.Failed()) { + return; } - nsCOMPtr<nsIDocumentEncoder> encoder; - nsresult rv = SetUpEncoder(aRoot, aCharset, getter_AddRefs(encoder)); - if (NS_FAILED(rv)) - return rv; - - return encoder->EncodeToStream(aStream); + nsresult rv = encoder->EncodeToStream(aStream); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } }
--- a/dom/base/nsDOMSerializer.h +++ b/dom/base/nsDOMSerializer.h @@ -2,68 +2,48 @@ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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 nsDOMSerializer_h_ #define nsDOMSerializer_h_ -#include "nsIDOMSerializer.h" -#include "nsWrapperCache.h" +#include "mozilla/dom/NonRefcountedDOMObject.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/XMLSerializerBinding.h" class nsINode; +class nsIOutputStream; -class nsDOMSerializer final : public nsIDOMSerializer, - public nsWrapperCache +class nsDOMSerializer final : public mozilla::dom::NonRefcountedDOMObject { public: nsDOMSerializer(); - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMSerializer) - - // nsIDOMSerializer - NS_DECL_NSIDOMSERIALIZER - // WebIDL API - static already_AddRefed<nsDOMSerializer> + static nsDOMSerializer* Constructor(const mozilla::dom::GlobalObject& aOwner, mozilla::ErrorResult& rv) { - RefPtr<nsDOMSerializer> domSerializer = new nsDOMSerializer(aOwner.GetAsSupports()); - return domSerializer.forget(); + return new nsDOMSerializer(); } void SerializeToString(nsINode& aRoot, nsAString& aStr, mozilla::ErrorResult& rv); void SerializeToStream(nsINode& aRoot, nsIOutputStream* aStream, - const nsAString& aCharset, mozilla::ErrorResult& rv); + const nsAString& aCharset, + mozilla::ErrorResult& aRv); - nsISupports* GetParentObject() const + bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, + JS::MutableHandle<JSObject*> aReflector) { - return mOwner; - } - - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override - { - return mozilla::dom::XMLSerializerBinding::Wrap(aCx, this, aGivenProto); + return mozilla::dom::XMLSerializerBinding::Wrap(aCx, this, aGivenProto, + aReflector); } - -private: - virtual ~nsDOMSerializer(); - - explicit nsDOMSerializer(nsISupports* aOwner) : mOwner(aOwner) - { - MOZ_ASSERT(aOwner); - } - - nsCOMPtr<nsISupports> mOwner; }; #endif
--- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -152,18 +152,18 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrame NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY if (aIID.Equals(NS_GET_IID(nsFrameLoader))) { // We want to end up with a pointer that can then be reinterpret_cast // from nsISupports* to nsFrameLoader* and end up with |this|. foundInterface = reinterpret_cast<nsISupports*>(this); } else - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserPersistable) - NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPersistable) + NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) + NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END nsFrameLoader::nsFrameLoader(Element* aOwner, nsPIDOMWindowOuter* aOpener, bool aNetworkCreated, int32_t aJSPluginID) : mOwnerContent(aOwner) , mDetachedSubdocFrame(nullptr) , mOpener(aOpener) , mRemoteBrowser(nullptr) @@ -3225,32 +3225,21 @@ nsFrameLoader::DestroyBrowserFrameScript } } void nsFrameLoader::StartPersistence(uint64_t aOuterWindowID, nsIWebBrowserPersistDocumentReceiver* aRecv, ErrorResult& aRv) { - nsresult rv = StartPersistence(aOuterWindowID, aRecv); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - } -} - -NS_IMETHODIMP -nsFrameLoader::StartPersistence(uint64_t aOuterWindowID, - nsIWebBrowserPersistDocumentReceiver* aRecv) -{ - if (!aRecv) { - return NS_ERROR_INVALID_POINTER; - } + MOZ_ASSERT(aRecv); if (mRemoteBrowser) { - return mRemoteBrowser->StartPersistence(aOuterWindowID, aRecv); + mRemoteBrowser->StartPersistence(aOuterWindowID, aRecv, aRv); + return; } nsCOMPtr<nsIDocument> rootDoc = mDocShell ? mDocShell->GetDocument() : nullptr; nsCOMPtr<nsIDocument> foundDoc; if (aOuterWindowID) { foundDoc = nsContentUtils::GetSubdocumentWithOuterWindowId(rootDoc, aOuterWindowID); } else { @@ -3259,17 +3248,16 @@ nsFrameLoader::StartPersistence(uint64_t if (!foundDoc) { aRecv->OnError(NS_ERROR_NO_CONTENT); } else { nsCOMPtr<nsIWebBrowserPersistDocument> pdoc = new mozilla::WebBrowserPersistLocalDocument(foundDoc); aRecv->OnDocumentReady(pdoc); } - return NS_OK; } void nsFrameLoader::MaybeUpdatePrimaryTabParent(TabParentChange aChange) { if (mRemoteBrowser && mOwnerContent) { nsCOMPtr<nsIDocShell> docShell = mOwnerContent->OwnerDoc()->GetDocShell(); if (!docShell) {
--- a/dom/base/nsFrameLoader.h +++ b/dom/base/nsFrameLoader.h @@ -20,32 +20,32 @@ #include "nsWrapperCache.h" #include "nsIURI.h" #include "nsFrameMessageManager.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/Element.h" #include "mozilla/Attributes.h" #include "nsStubMutationObserver.h" #include "Units.h" -#include "nsIWebBrowserPersistable.h" #include "nsIFrame.h" #include "nsPluginTags.h" class nsIURI; class nsSubDocumentFrame; class nsView; class nsInProcessTabChildGlobal; class AutoResetInShow; class AutoResetInFrameSwap; class nsITabParent; class nsIDocShellTreeItem; class nsIDocShellTreeOwner; class nsILoadContext; class nsIMessageSender; class nsIPrintSettings; +class nsIWebBrowserPersistDocumentReceiver; class nsIWebProgressListener; namespace mozilla { class OriginAttributes; namespace dom { class ChromeMessageSender; @@ -71,18 +71,17 @@ class RenderFrameParent; typedef struct _GtkWidget GtkWidget; #endif // IID for nsFrameLoader, because some places want to QI to it. #define NS_FRAMELOADER_IID \ { 0x297fd0ea, 0x1b4a, 0x4c9a, \ { 0xa4, 0x04, 0xe5, 0x8b, 0xe8, 0x95, 0x10, 0x50 } } -class nsFrameLoader final : public nsIWebBrowserPersistable, - public nsStubMutationObserver, +class nsFrameLoader final : public nsStubMutationObserver, public mozilla::dom::ipc::MessageManagerCallback, public nsWrapperCache { friend class AutoResetInShow; friend class AutoResetInFrameSwap; typedef mozilla::dom::PBrowserParent PBrowserParent; typedef mozilla::dom::TabParent TabParent; typedef mozilla::layout::RenderFrameParent RenderFrameParent; @@ -91,20 +90,19 @@ public: static nsFrameLoader* Create(mozilla::dom::Element* aOwner, nsPIDOMWindowOuter* aOpener, bool aNetworkCreated, int32_t aJSPluginID = nsFakePluginTag::NOT_JSPLUGIN); NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAMELOADER_IID) NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsFrameLoader, - nsIWebBrowserPersistable) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsFrameLoader) + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED - NS_DECL_NSIWEBBROWSERPERSISTABLE nsresult CheckForRecursiveLoad(nsIURI* aURI); nsresult ReallyStartLoading(); void StartDestroy(); void DestroyDocShell(); void DestroyComplete(); nsIDocShell* GetExistingDocShell() { return mDocShell; } mozilla::dom::EventTarget* GetTabChildGlobalAsEventTarget(); nsresult CreateStaticClone(nsFrameLoader* aDest); @@ -506,12 +504,12 @@ private: bool mFreshProcess : 1; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsFrameLoader, NS_FRAMELOADER_IID) inline nsISupports* ToSupports(nsFrameLoader* aFrameLoader) { - return static_cast<nsIWebBrowserPersistable*>(aFrameLoader); + return aFrameLoader; } #endif
deleted file mode 100644 --- a/dom/base/nsIDOMSerializer.idl +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIOutputStream; -interface nsIDOMNode; - -/** - * The nsIDOMSerializer interface is really a placeholder till the W3C - * DOM Working Group defines a mechanism for serializing DOM nodes. - * An instance of this interface can be used to serialize a DOM document - * or any DOM subtree. - */ - -[uuid(9fd4ba15-e67c-4c98-b52c-7715f62c9196)] -interface nsIDOMSerializer : nsISupports -{ - /** - * The subtree rooted by the specified element is serialized to - * a string. - * - * @param root The root of the subtree to be serialized. This could - * be any node, including a Document. - * @returns The serialized subtree in the form of a Unicode string - */ - AString serializeToString(in nsIDOMNode root); - - /** - * The subtree rooted by the specified element is serialized to - * a byte stream using the character set specified. - * @param root The root of the subtree to be serialized. This could - * be any node, including a Document. - * @param stream The byte stream to which the subtree is serialized. - * @param charset The name of the character set to use for the encoding - * to a byte stream. If this string is empty and root is - * a document, the document's character set will be used. - */ - void serializeToStream(in nsIDOMNode root, in nsIOutputStream stream, - in AUTF8String charset); -}; - -%{ C++ -#define NS_XMLSERIALIZER_CID \ - { /* a6cf9124-15b3-11d2-932e-00805f8add32 */ \ - 0xa6cf9124, 0x15b3, 0x11d2, \ - {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } -#define NS_XMLSERIALIZER_CONTRACTID \ -"@mozilla.org/xmlextras/xmlserializer;1" -%} -
--- a/dom/base/test/chrome/test_domparsing.xul +++ b/dom/base/test/chrome/test_domparsing.xul @@ -65,18 +65,17 @@ runTest(new DOMParser(), new XMLSerializ parser.init(); throws(function() { parser.init(); }, "NS_ERROR_UNEXPECTED", "init method should throw when called twice"); } runTest(Cc["@mozilla.org/xmlextras/domparser;1"] .createInstance(Ci.nsIDOMParser), - Cc["@mozilla.org/xmlextras/xmlserializer;1"] - .createInstance(Ci.nsIDOMSerializer)); + new XMLSerializer()); function runTest(parser, serializer) { is(typeof parser.parseFromString, "function", "parseFromString should exist"); is(typeof parser.parseFromBuffer, "function", "parseFromBuffer should exist"); is(typeof parser.parseFromStream, "function", "parseFromStream should exist"); is(typeof parser.init, "function", "init should exist"); is(typeof serializer.serializeToString, "function", "serializeToString should exist");
--- a/dom/base/test/unit/head_xml.js +++ b/dom/base/test/unit/head_xml.js @@ -8,22 +8,22 @@ const I = Ci; const C = Cc; const nsIFile = I.nsIFile; const nsIProperties = I.nsIProperties; const nsIFileInputStream = I.nsIFileInputStream; const nsIInputStream = I.nsIInputStream; const nsIDOMParser = I.nsIDOMParser; -const nsIDOMSerializer = I.nsIDOMSerializer; const nsIDOMDocument = I.nsIDOMDocument; const nsIDOMElement = I.nsIDOMElement; const nsIDOMNode = I.nsIDOMNode; const nsIDOMNodeList = I.nsIDOMNodeList; -const nsIDOMXULElement = I.nsIDOMXULElement; + +Cu.importGlobalProperties(["XMLSerializer"]); function DOMParser() { var parser = C["@mozilla.org/xmlextras/domparser;1"].createInstance(nsIDOMParser); parser.init(); return parser; } var __testsDirectory = null; @@ -54,18 +54,17 @@ function ParseXML(data) { Assert.equal(data instanceof nsIInputStream, true); return DOMParser().parseFromStream(data, "UTF-8", data.available(), "application/xml"); } function DOMSerializer() { - return C["@mozilla.org/xmlextras/xmlserializer;1"] - .createInstance(nsIDOMSerializer); + return new XMLSerializer(); } function SerializeXML(node) { return DOMSerializer().serializeToString(node); } function roundtrip(obj) { if (typeof(obj) == "string") {
--- a/dom/base/test/unit/test_nodelist.js +++ b/dom/base/test/unit/test_nodelist.js @@ -170,30 +170,30 @@ function test_getElementsByTagNameNS() function test_getElementsByAttribute() { var doc = ParseFile("nodelist_data_2.xul"); var root = doc.documentElement; // Sadly, DOMParser can't create XULDocument objects. But at least we have a // XULElement! - Assert.ok(root instanceof nsIDOMXULElement); + Assert.equal(ChromeUtils.getClassName(root), "XULElement"); Assert.ok(root.getElementsByAttribute("foo", "foo") instanceof nsIDOMNodeList); var master1 = doc.getElementById("master1"); var master2 = doc.getElementById("master2"); var master3 = doc.getElementById("master3"); var external = doc.getElementById("external"); - Assert.ok(master1 instanceof nsIDOMXULElement); - Assert.ok(master2 instanceof nsIDOMXULElement); - Assert.ok(master3 instanceof nsIDOMXULElement); - Assert.ok(external instanceof nsIDOMXULElement); + Assert.equal(ChromeUtils.getClassName(master1), "XULElement"); + Assert.equal(ChromeUtils.getClassName(master2), "XULElement"); + Assert.equal(ChromeUtils.getClassName(master3), "XULElement"); + Assert.equal(ChromeUtils.getClassName(external), "XULElement"); // Basic tests Assert.equal(root.getElementsByAttribute("foo", "foo").length, 14); Assert.equal(master1.getElementsByAttribute("foo", "foo").length, 4); Assert.equal(root.getElementsByAttribute("foo", "bar").length, @@ -287,31 +287,31 @@ function test_getElementsByAttribute() function test_getElementsByAttributeNS() { var doc = ParseFile("nodelist_data_2.xul"); var root = doc.documentElement; // Sadly, DOMParser can't create XULDocument objects. But at least we have a // XULElement! - Assert.ok(root instanceof nsIDOMXULElement); + Assert.equal(ChromeUtils.getClassName(root), "XULElement"); // Check that getElementsByAttributeNS returns a nodelist. Assert.ok(root.getElementsByAttributeNS("*", "*", "*") instanceof nsIDOMNodeList); var master1 = doc.getElementById("master1"); var master2 = doc.getElementById("master2"); var master3 = doc.getElementById("master3"); var external = doc.getElementById("external"); - Assert.ok(master1 instanceof nsIDOMXULElement); - Assert.ok(master2 instanceof nsIDOMXULElement); - Assert.ok(master3 instanceof nsIDOMXULElement); - Assert.ok(external instanceof nsIDOMXULElement); + Assert.equal(ChromeUtils.getClassName(master1), "XULElement"); + Assert.equal(ChromeUtils.getClassName(master2), "XULElement"); + Assert.equal(ChromeUtils.getClassName(master3), "XULElement"); + Assert.equal(ChromeUtils.getClassName(external), "XULElement"); // Test wildcard namespace Assert.equal(root.getElementsByAttributeNS("*", "foo", "foo").length, 38); Assert.equal(master1.getElementsByAttributeNS("*", "foo", "foo").length, 11); Assert.equal(master2.getElementsByAttributeNS("*", "foo", "foo").length, 10);
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1381,16 +1381,17 @@ DOMInterfaces = { }, 'XMLHttpRequestEventTarget': { 'concrete': False }, 'XMLSerializer': { 'nativeType': 'nsDOMSerializer', + 'wrapperCache': False }, 'XPathEvaluator': { 'wrapperCache': False }, 'XPathExpression': { 'wrapperCache': False,
--- a/dom/events/EventDispatcher.cpp +++ b/dom/events/EventDispatcher.cpp @@ -744,20 +744,39 @@ EventDispatcher::Dispatch(nsISupports* a } } #ifdef DEBUG if (NS_IsMainThread() && aEvent->mMessage != eVoidEvent && !nsContentUtils::IsSafeToRunScript()) { nsCOMPtr<nsINode> node = do_QueryInterface(target); - if (node && nsContentUtils::IsChromeDoc(node->OwnerDoc())) { - NS_WARNING("Fix the caller!"); + if (!node) { + // If the target is not a node, just go ahead and assert that this is + // unsafe. There really shouldn't be any other event targets in documents + // that are not being rendered or scripted. + NS_ERROR("This is unsafe! Fix the caller!"); } else { - NS_ERROR("This is unsafe! Fix the caller!"); + // If this is a node, it's possible that this is some sort of DOM tree + // that is never accessed by script (for example an SVG image or XBL + // binding document or whatnot). We really only want to warn/assert here + // if there might be actual scripted listeners for this event, so restrict + // the warnings/asserts to the case when script can or once could touch + // this node's document. + nsIDocument* doc = node->OwnerDoc(); + bool hasHadScriptHandlingObject; + nsIGlobalObject* global = + doc->GetScriptHandlingObject(hasHadScriptHandlingObject); + if (global || hasHadScriptHandlingObject) { + if (nsContentUtils::IsChromeDoc(doc)) { + NS_WARNING("Fix the caller!"); + } else { + NS_ERROR("This is unsafe! Fix the caller!"); + } + } } } if (aDOMEvent) { WidgetEvent* innerEvent = aDOMEvent->WidgetEventPtr(); NS_ASSERTION(innerEvent == aEvent, "The inner event of aDOMEvent is not the same as aEvent!"); }
--- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -681,33 +681,49 @@ EventListenerManager::ListenerCanHandle( if (!aEvent->mFlags.mInSystemGroup && !aListener->mIsChrome) { return false; } } MOZ_ASSERT(mIsMainThreadELM); return aListener->mEventMessage == aEventMessage; } +static bool +DefaultToPassiveTouchListeners() +{ + static bool sDefaultToPassiveTouchListeners = false; + static bool sIsPrefCached = false; + + if (!sIsPrefCached) { + sIsPrefCached = true; + Preferences::AddBoolVarCache(&sDefaultToPassiveTouchListeners, + "dom.event.default_to_passive_touch_listeners"); + } + + return sDefaultToPassiveTouchListeners; +} + void EventListenerManager::AddEventListenerByType( EventListenerHolder aListenerHolder, const nsAString& aType, const EventListenerFlags& aFlags, const Optional<bool>& aPassive) { RefPtr<nsAtom> atom; EventMessage message = mIsMainThreadELM ? nsContentUtils::GetEventMessageAndAtomForListener(aType, getter_AddRefs(atom)) : eUnidentifiedEvent; EventListenerFlags flags = aFlags; if (aPassive.WasPassed()) { flags.mPassive = aPassive.Value(); - } else if (message == eTouchStart || message == eTouchMove) { + } else if ((message == eTouchStart || message == eTouchMove) && + mIsMainThreadELM && DefaultToPassiveTouchListeners()) { nsCOMPtr<nsINode> node; nsCOMPtr<nsPIDOMWindowInner> win; if ((win = GetTargetAsInnerWindow()) || ((node = do_QueryInterface(mTarget)) && (node == node->OwnerDoc() || node == node->OwnerDoc()->GetRootElement() || node == node->OwnerDoc()->GetBody()))) { flags.mPassive = true;
--- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -53,17 +53,16 @@ #include "nsPIWindowRoot.h" #include "nsIWebNavigation.h" #include "nsIContentViewer.h" #include "nsFrameManager.h" #include "nsITabChild.h" #include "nsPluginFrame.h" #include "nsMenuPopupFrame.h" -#include "nsIDOMXULElement.h" #include "nsIObserverService.h" #include "nsIDocShell.h" #include "nsIMozBrowserFrame.h" #include "nsSubDocumentFrame.h" #include "nsLayoutUtils.h" #include "nsIInterfaceRequestorUtils.h" #include "nsUnicharUtils.h"
--- a/dom/fetch/BodyExtractor.cpp +++ b/dom/fetch/BodyExtractor.cpp @@ -5,19 +5,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "BodyExtractor.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FormData.h" #include "mozilla/dom/TypedArray.h" #include "mozilla/dom/URLSearchParams.h" #include "mozilla/dom/XMLHttpRequest.h" +#include "mozilla/UniquePtr.h" #include "nsContentUtils.h" -#include "nsIDOMDocument.h" -#include "nsIDOMSerializer.h" +#include "nsDOMSerializer.h" #include "nsIGlobalObject.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" #include "nsIStorageStream.h" #include "nsStringStream.h" namespace mozilla { namespace dom { @@ -68,18 +68,17 @@ BodyExtractor<const ArrayBufferView>::Ge } template<> nsresult BodyExtractor<nsIDocument>::GetAsStream(nsIInputStream** aResult, uint64_t* aContentLength, nsACString& aContentTypeWithCharset, nsACString& aCharset) const { - nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(mBody)); - NS_ENSURE_STATE(domdoc); + NS_ENSURE_STATE(mBody); aCharset.AssignLiteral("UTF-8"); nsresult rv; nsCOMPtr<nsIStorageStream> storStream; rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIOutputStream> output; @@ -102,23 +101,25 @@ BodyExtractor<nsIDocument>::GetAsStream( uint32_t written; rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written); NS_ENSURE_SUCCESS(rv, rv); MOZ_ASSERT(written == utf8Serialized.Length()); } else { aContentTypeWithCharset.AssignLiteral("application/xml;charset=UTF-8"); - nsCOMPtr<nsIDOMSerializer> serializer = - do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + auto serializer = MakeUnique<nsDOMSerializer>(); // Make sure to use the encoding we'll send - rv = serializer->SerializeToStream(domdoc, output, aCharset); - NS_ENSURE_SUCCESS(rv, rv); + ErrorResult res; + serializer->SerializeToStream(*mBody, output, NS_LITERAL_STRING("UTF-8"), + res); + if (NS_WARN_IF(res.Failed())) { + return res.StealNSResult(); + } } output->Close(); uint32_t length; rv = storStream->GetLength(&length); NS_ENSURE_SUCCESS(rv, rv); *aContentLength = length;
--- a/dom/fetch/moz.build +++ b/dom/fetch/moz.build @@ -43,16 +43,18 @@ UNIFIED_SOURCES += [ ] IPDL_SOURCES += [ 'ChannelInfo.ipdlh', 'FetchTypes.ipdlh', ] LOCAL_INCLUDES += [ + # For nsDOMSerializer + '/dom/base', # For HttpBaseChannel.h dependencies '/netwerk/base', # For nsDataHandler.h '/netwerk/protocol/data', # For HttpBaseChannel.h '/netwerk/protocol/http', ]
--- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -1803,16 +1803,17 @@ void HTMLMediaElement::AbortExistingLoad mHaveQueuedSelectResource = false; mSuspendedForPreloadNone = false; mDownloadSuspendedByCache = false; mMediaInfo = MediaInfo(); mIsEncrypted = false; mPendingEncryptedInitData.Reset(); mWaitingForKey = NOT_WAITING_FOR_KEY; mSourcePointer = nullptr; + mAttemptPlayUponLoadedMetadata = false; mTags = nullptr; if (mNetworkState != NETWORK_EMPTY) { NS_ASSERTION(!mDecoder && !mSrcStream, "How did someone setup a new stream/decoder already?"); // ChangeNetworkState() will call UpdateAudioChannelPlayingState() // indirectly which depends on mPaused. So we need to update mPaused first. if (!mPaused) { @@ -3951,17 +3952,17 @@ void HTMLMediaElement::NotifyXPCOMShutdown() { ShutdownDecoder(); } already_AddRefed<Promise> HTMLMediaElement::Play(ErrorResult& aRv) { - LOG(LogLevel::Debug, ("%p Play() called by JS", this)); + LOG(LogLevel::Debug, ("%p Play() called by JS readyState=%d", this, mReadyState)); if (mAudioChannelWrapper && mAudioChannelWrapper->IsPlaybackBlocked()) { MaybeDoLoad(); // A blocked media element will be resumed later, so we return a pending // promise which might be resolved/rejected depends on the result of // resuming the blocked media element. RefPtr<Promise> promise = CreateDOMPromise(aRv); @@ -3990,17 +3991,22 @@ HTMLMediaElement::PlayInternal(ErrorResu // 4.8.12.8 // When the play() method on a media element is invoked, the user agent must // run the following steps. // 4.8.12.8 - Step 1: // If the media element is not allowed to play, return a promise rejected // with a "NotAllowedError" DOMException and abort these steps. - if (!IsAllowedToPlay()) { + // Note: IsAllowedToPlay() needs to know whether there is an audio track + // in the resource, and for that we need to be at readyState HAVE_METADATA + // or above. So only reject here if we're at readyState HAVE_METADATA. If + // we're below that, we'll we delay fulfilling the play promise until we've + // reached readyState >= HAVE_METADATA below. + if (mReadyState >= HAVE_METADATA && !IsAllowedToPlay()) { // NOTE: for promise-based-play, will return a rejected promise here. LOG(LogLevel::Debug, ("%p Play() promise rejected because not allowed to play.", this)); aRv.Throw(NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR); return nullptr; } // 4.8.12.8 - Step 2: @@ -4048,31 +4054,40 @@ HTMLMediaElement::PlayInternal(ErrorResu // Even if we just did Load() or ResumeLoad(), we could already have a decoder // here if we managed to clone an existing decoder. if (mDecoder) { if (mDecoder->IsEnded()) { SetCurrentTime(0); } if (!mPausedForInactiveDocumentOrChannel) { - nsresult rv = mDecoder->Play(); - if (NS_FAILED(rv)) { - // We don't need to remove the _promise_ from _mPendingPlayPromises_ here. - // If something wrong between |mPendingPlayPromises.AppendElement(promise);| - // and here, the _promise_ should already have been rejected. Otherwise, - // the _promise_ won't be returned to JS at all, so just leave it in the - // _mPendingPlayPromises_ and let it be resolved/rejected with the - // following actions and the promise-resolution won't be observed at all. - LOG(LogLevel::Debug, - ("%p Play() promise rejected because failed to play MediaDecoder.", - this)); - aRv.Throw(rv); - return nullptr; + if (mReadyState < HAVE_METADATA) { + // We don't know whether the autoplay policy will allow us to play yet, + // as we don't yet know whether the media has audio tracks. So delay + // starting playback until we've loaded metadata. + mAttemptPlayUponLoadedMetadata = true; + } else { + nsresult rv = mDecoder->Play(); + if (NS_FAILED(rv)) { + // We don't need to remove the _promise_ from _mPendingPlayPromises_ here. + // If something wrong between |mPendingPlayPromises.AppendElement(promise);| + // and here, the _promise_ should already have been rejected. Otherwise, + // the _promise_ won't be returned to JS at all, so just leave it in the + // _mPendingPlayPromises_ and let it be resolved/rejected with the + // following actions and the promise-resolution won't be observed at all. + LOG(LogLevel::Debug, + ("%p Play() promise rejected because failed to play MediaDecoder.", + this)); + aRv.Throw(rv); + return nullptr; + } } } + } else if (mReadyState < HAVE_METADATA) { + mAttemptPlayUponLoadedMetadata = true; } if (mCurrentPlayRangeStart == -1.0) { mCurrentPlayRangeStart = CurrentTime(); } const bool oldPaused = mPaused; mPaused = false; @@ -4921,17 +4936,17 @@ HTMLMediaElement::FinishDecoderSetup(Med // This will also do an AddRemoveSelfReference. NotifyOwnerDocumentActivityChanged(); if (mPausedForInactiveDocumentOrChannel) { mDecoder->Suspend(); } nsresult rv = NS_OK; - if (!mPaused) { + if (!mPaused && !mAttemptPlayUponLoadedMetadata) { SetPlayedOrSeeked(true); if (!mPausedForInactiveDocumentOrChannel) { rv = mDecoder->Play(); } } if (NS_FAILED(rv)) { ShutdownDecoder(); @@ -5925,16 +5940,25 @@ HTMLMediaElement::ChangeReadyState(nsMed DispatchAsyncEvent(NS_LITERAL_STRING("loadeddata")); mLoadedDataFired = true; } if (oldState < HAVE_FUTURE_DATA && mReadyState >= HAVE_FUTURE_DATA) { DispatchAsyncEvent(NS_LITERAL_STRING("canplay")); if (!mPaused) { + if (mAttemptPlayUponLoadedMetadata && mDecoder) { + mAttemptPlayUponLoadedMetadata = false; + if (IsAllowedToPlay()) { + mDecoder->Play(); + } else { + AsyncRejectPendingPlayPromises(NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR); + mPaused = true; + } + } NotifyAboutPlaying(); } } CheckAutoplayDataReady(); if (oldState < HAVE_ENOUGH_DATA && mReadyState >= HAVE_ENOUGH_DATA) { @@ -6045,16 +6069,17 @@ void HTMLMediaElement::CheckAutoplayData UpdateSrcMediaStreamPlaying(); UpdateAudioChannelPlayingState(); if (mDecoder) { SetPlayedOrSeeked(true); if (mCurrentPlayRangeStart == -1.0) { mCurrentPlayRangeStart = CurrentTime(); } + MOZ_ASSERT(!mAttemptPlayUponLoadedMetadata); mDecoder->Play(); } else if (mSrcStream) { SetPlayedOrSeeked(true); } // For blocked media, the event would be pending until it is resumed. DispatchAsyncEvent(NS_LITERAL_STRING("play")); @@ -6382,16 +6407,17 @@ void HTMLMediaElement::SuspendOrResumeEl mDecoder->Pause(); mDecoder->Suspend(); } mEventDeliveryPaused = aSuspendEvents; } else { if (mDecoder) { mDecoder->Resume(); if (!mPaused && !mDecoder->IsEnded()) { + MOZ_ASSERT(!mAttemptPlayUponLoadedMetadata); mDecoder->Play(); } } if (mEventDeliveryPaused) { mEventDeliveryPaused = false; DispatchPendingMediaEvents(); } }
--- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -1814,16 +1814,23 @@ private: // True if media element has been marked as 'tainted' and can't // participate in video decoder suspending. bool mHasSuspendTaint = false; // True if media element has been forced into being considered 'hidden'. // For use by mochitests. Enabling pref "media.test.video-suspend" bool mForcedHidden = false; + // True if we attempted to play before the media element had loaded + // metadata, and we need to attempt the play once we reach loaded metadata. + // If autoplay is disabled, we can't decide whether to allow a play() + // until we've loaded metadata, as we need to know whether the resource + // has an audio track. + bool mAttemptPlayUponLoadedMetadata = false; + // True if audio tracks and video tracks are constructed and added into the // track list, false if all tracks are removed from the track list. bool mMediaTracksConstructed = false; Visibility mVisibilityState = Visibility::UNTRACKED; UniquePtr<ErrorSink> mErrorSink;
--- a/dom/interfaces/core/moz.build +++ b/dom/interfaces/core/moz.build @@ -9,13 +9,12 @@ with Files("**"): XPIDL_SOURCES += [ 'nsIDOMDocument.idl', 'nsIDOMDocumentFragment.idl', 'nsIDOMElement.idl', 'nsIDOMNode.idl', 'nsIDOMNodeList.idl', 'nsIDOMNSEditableElement.idl', - 'nsIDOMXMLDocument.idl', ] XPIDL_MODULE = 'dom_core'
deleted file mode 100644 --- a/dom/interfaces/core/nsIDOMXMLDocument.idl +++ /dev/null @@ -1,15 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -// The only reason this interface still exists is that we have addon and Firefox -// code QIing to it and using it for instanceof via Components.interfaces, and -// the interface needs to exist in order for the shim stuff in -// xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp to work. -[uuid(89ab39cb-c568-4d85-bd34-306d5cd5164d)] -interface nsIDOMXMLDocument : nsISupports -{ -};
--- a/dom/interfaces/xul/moz.build +++ b/dom/interfaces/xul/moz.build @@ -9,17 +9,16 @@ with Files("**"): XPIDL_SOURCES += [ 'nsIDOMXULButtonElement.idl', 'nsIDOMXULCheckboxElement.idl', 'nsIDOMXULCommandDispatcher.idl', 'nsIDOMXULContainerElement.idl', 'nsIDOMXULControlElement.idl', 'nsIDOMXULDescriptionElement.idl', - 'nsIDOMXULElement.idl', 'nsIDOMXULLabeledControlEl.idl', 'nsIDOMXULLabelElement.idl', 'nsIDOMXULMenuListElement.idl', 'nsIDOMXULMultSelectCntrlEl.idl', 'nsIDOMXULRelatedElement.idl', 'nsIDOMXULSelectCntrlEl.idl', 'nsIDOMXULSelectCntrlItemEl.idl', 'nsIDOMXULTextboxElement.idl',
--- a/dom/interfaces/xul/nsIDOMXULContainerElement.idl +++ b/dom/interfaces/xul/nsIDOMXULContainerElement.idl @@ -1,68 +1,22 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsIDOMXULElement.idl" +#include "nsISupports.idl" interface nsIDOMXULContainerElement; [scriptable, uuid(800a68c7-b854-4597-a436-3055ce5c5c96)] interface nsIDOMXULContainerItemElement : nsISupports { /** * Returns the parent container if any. */ readonly attribute nsIDOMXULContainerElement parentContainer; }; [scriptable, uuid(b2bc96b8-31fc-42f4-937a-bd27291af40b)] interface nsIDOMXULContainerElement : nsIDOMXULContainerItemElement { - /** - * Creates an item for the given label and value and appends it to the - * container. - * - * @param aLabel - the label for the new item - * @param aValue - the value of the new item - */ - nsIDOMXULElement appendItem(in DOMString aLabel, in DOMString aValue); - - /** - * Creates an item for the given label and value and inserts it into the - * container at the specified position. - * - * @param aIndex - the index where the new item will be inserted - * @param aLabel - the label for the new item - * @param aValue - the value of the new item - */ - nsIDOMXULElement insertItemAt(in long aIndex, in DOMString aLabel, - in DOMString aValue); - - /** - * Removes an item from the container. - * - * @param aIndex - index of the item to remove - */ - nsIDOMXULElement removeItemAt(in long aIndex); - - /** - * Returns a count of items in the container. - */ - readonly attribute unsigned long itemCount; - - /** - * Returns the index of an item or -1 if the item is not in the container. - * - * @param aItem - the item to determine the index of - */ - long getIndexOfItem(in nsIDOMXULElement aItem); - - /** - * Returns the item at a given index or null if the item is not is the - * container. - * - * @param aIndex - the index of the item to return - */ - nsIDOMXULElement getItemAtIndex(in long aIndex); };
--- a/dom/interfaces/xul/nsIDOMXULControlElement.idl +++ b/dom/interfaces/xul/nsIDOMXULControlElement.idl @@ -1,15 +1,14 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsIDOMElement.idl" -#include "nsIDOMXULElement.idl" +#include "nsISupports.idl" interface nsIControllers; [scriptable, uuid(ea7f92d0-b379-4107-91b4-1e69bdd771e3)] interface nsIDOMXULControlElement : nsISupports { attribute boolean disabled; attribute long tabIndex;
--- a/dom/interfaces/xul/nsIDOMXULDescriptionElement.idl +++ b/dom/interfaces/xul/nsIDOMXULDescriptionElement.idl @@ -1,15 +1,15 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsIDOMXULElement.idl" +#include "nsISupports.idl" [scriptable, uuid(64c3500e-e258-4d49-b7ca-c93ab0931ce4)] interface nsIDOMXULDescriptionElement : nsISupports { attribute boolean disabled; attribute boolean crop; attribute DOMString value; };
deleted file mode 100644 --- a/dom/interfaces/xul/nsIDOMXULElement.idl +++ /dev/null @@ -1,17 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIDOMElement.idl" - -interface nsIRDFCompositeDataSource; -interface nsIRDFResource; -interface nsIControllers; -interface nsIBoxObject; - - -[uuid(75435ab3-6863-42a1-ade3-025393d9e80e)] -interface nsIDOMXULElement : nsIDOMElement -{ -};
--- a/dom/interfaces/xul/nsIDOMXULMenuListElement.idl +++ b/dom/interfaces/xul/nsIDOMXULMenuListElement.idl @@ -1,15 +1,16 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIDOMXULSelectCntrlEl.idl" interface nsIDOMXULTextBoxElement; +interface nsIDOMNode; [scriptable, uuid(36c16a17-c0e9-4b35-951b-81a147314ef1)] interface nsIDOMXULMenuListElement : nsIDOMXULSelectControlElement { attribute boolean editable; attribute boolean open; // label of selected option or value of textfield for editable menu lists readonly attribute DOMString label;
--- a/dom/interfaces/xul/nsIDOMXULMultSelectCntrlEl.idl +++ b/dom/interfaces/xul/nsIDOMXULMultSelectCntrlEl.idl @@ -1,15 +1,17 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIDOMXULSelectCntrlEl.idl" +interface nsIDOMNodeList; + [scriptable, uuid(40654a10-8204-4f06-9f21-7baa31c7b1dd)] interface nsIDOMXULMultiSelectControlElement : nsIDOMXULSelectControlElement { attribute DOMString selType; attribute nsIDOMXULSelectControlItemElement currentItem; attribute long currentIndex;
--- a/dom/interfaces/xul/nsIDOMXULSelectCntrlItemEl.idl +++ b/dom/interfaces/xul/nsIDOMXULSelectCntrlItemEl.idl @@ -1,14 +1,14 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsIDOMXULElement.idl" +#include "nsISupports.idl" interface nsIDOMXULSelectControlElement; [scriptable, uuid(5c6be58f-17df-4750-88a5-4a59ac28adc9)] interface nsIDOMXULSelectControlItemElement : nsISupports { attribute boolean disabled; attribute DOMString crop; attribute DOMString image; attribute DOMString label;
--- a/dom/interfaces/xul/nsIDOMXULTreeElement.idl +++ b/dom/interfaces/xul/nsIDOMXULTreeElement.idl @@ -1,18 +1,18 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsIDOMXULElement.idl" -#include "nsIDOMElement.idl" +#include "nsISupports.idl" interface nsITreeColumns; interface nsITreeView; +interface nsIDOMElement; interface nsIDOMXULTextBoxElement; /** * @status UNDER_DEVELOPMENT */ [scriptable, uuid(013b62af-1e2f-4b07-9091-d7c0fc4687e2)] interface nsIDOMXULTreeElement : nsISupports
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -3185,27 +3185,36 @@ ContentParent::KillHard(const char* aRea NS_LITERAL_CSTRING("ipc_channel_error"), reason); Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1); RefPtr<ContentParent> self = this; std::function<void(bool)> callback = [self](bool aResult) { self->OnGenerateMinidumpComplete(aResult); + MessageChannel* channel = self->GetIPCChannel(); + if (channel) { + channel->Close(); + } }; // Generate the report and insert into the queue for submittal. mCrashReporter->GenerateMinidumpAndPair(Process(), nullptr, NS_LITERAL_CSTRING("browser"), Move(callback), true); return; } OnGenerateMinidumpComplete(false); + + MessageChannel* channel = GetIPCChannel(); + if (channel) { + channel->Close(); + } } void ContentParent::OnGenerateMinidumpComplete(bool aDumpResult) { if (mCrashReporter && aDumpResult) { // CrashReporterHost::GenerateMinidumpAndPair() is successful. mCreatedPairedMinidumps = mCrashReporter->FinalizeCrashReport();
--- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -64,16 +64,17 @@ using class mozilla::WidgetTouchEvent fr using class mozilla::WidgetPluginEvent from "ipc/nsGUIEventIPC.h"; using struct mozilla::dom::RemoteDOMEvent from "mozilla/dom/TabMessageUtils.h"; using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h"; using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h"; using mozilla::CSSToScreenScale from "Units.h"; using mozilla::CommandInt from "mozilla/EventForwards.h"; using mozilla::WritingMode from "mozilla/WritingModes.h"; using nsIWidget::TouchPointerState from "nsIWidget.h"; +using nsCursor from "nsIWidget.h"; using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h"; using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h"; using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h"; using mozilla::EventMessage from "mozilla/EventForwards.h"; using nsEventStatus from "mozilla/EventForwards.h"; using mozilla::Modifiers from "mozilla/EventForwards.h"; using nsSizeMode from "nsIWidgetListener.h"; using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h"; @@ -361,17 +362,17 @@ parent: /** * Set the native cursor. * @param value * The widget cursor to set. * @param force * Invalidate any locally cached cursor settings and force an * update. */ - async SetCursor(uint32_t value, bool force); + async SetCursor(nsCursor value, bool force); /** * Set the native cursor using a custom image. * @param cursorData * Serialized image data. * @param width * Width of the image. * @param height
--- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -131,18 +131,17 @@ namespace mozilla { namespace dom { TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr; NS_IMPL_ISUPPORTS(TabParent, nsITabParent, nsIAuthPromptProvider, nsISecureBrowserUI, - nsISupportsWeakReference, - nsIWebBrowserPersistable) + nsISupportsWeakReference) TabParent::TabParent(nsIContentParent* aManager, const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags) : TabContext(aContext) , mFrameElement(nullptr) , mContentCache(*this) @@ -1717,19 +1716,19 @@ TabParent::RecvAsyncMessage(const nsStri CrossProcessCpowHolder cpows(Manager(), aCpows); if (!ReceiveMessage(aMessage, false, &data, &cpows, aPrincipal, nullptr)) { return IPC_FAIL_NO_REASON(this); } return IPC_OK(); } mozilla::ipc::IPCResult -TabParent::RecvSetCursor(const uint32_t& aCursor, const bool& aForce) +TabParent::RecvSetCursor(const nsCursor& aCursor, const bool& aForce) { - mCursor = static_cast<nsCursor>(aCursor); + mCursor = aCursor; mCustomCursor = nullptr; nsCOMPtr<nsIWidget> widget = GetWidget(); if (widget) { if (aForce) { widget->ClearCachedCursor(); } if (mTabSetsCursor) { @@ -3432,29 +3431,33 @@ TabParent::TakeDragVisualization(RefPtr< bool TabParent::AsyncPanZoomEnabled() const { nsCOMPtr<nsIWidget> widget = GetWidget(); return widget && widget->AsyncPanZoomEnabled(); } -NS_IMETHODIMP +void TabParent::StartPersistence(uint64_t aOuterWindowID, - nsIWebBrowserPersistDocumentReceiver* aRecv) + nsIWebBrowserPersistDocumentReceiver* aRecv, + ErrorResult& aRv) { nsCOMPtr<nsIContentParent> manager = Manager(); if (!manager->IsContentParent()) { - return NS_ERROR_UNEXPECTED; + aRv.Throw(NS_ERROR_UNEXPECTED); + return; } auto* actor = new WebBrowserPersistDocumentParent(); actor->SetOnReady(aRecv); - return manager->AsContentParent() - ->SendPWebBrowserPersistDocumentConstructor(actor, this, aOuterWindowID) - ? NS_OK : NS_ERROR_FAILURE; + bool ok = manager->AsContentParent() + ->SendPWebBrowserPersistDocumentConstructor(actor, this, aOuterWindowID); + if (!ok) { + aRv.Throw(NS_ERROR_FAILURE); + } // (The actor will be destroyed on constructor failure.) } NS_IMETHODIMP TabParent::StartApzAutoscroll(float aAnchorX, float aAnchorY, nsViewID aScrollId, uint32_t aPresShellId, bool* aOutRetval) {
--- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -22,29 +22,29 @@ #include "mozilla/Move.h" #include "nsCOMPtr.h" #include "nsIAuthPromptProvider.h" #include "nsIBrowserDOMWindow.h" #include "nsIDOMEventListener.h" #include "nsIKeyEventInPluginCallback.h" #include "nsISecureBrowserUI.h" #include "nsITabParent.h" -#include "nsIWebBrowserPersistable.h" #include "nsIXULBrowserWindow.h" #include "nsRefreshDriver.h" #include "nsWeakReference.h" #include "Units.h" #include "nsIWidget.h" class nsFrameLoader; class nsIContent; class nsIPrincipal; class nsIURI; class nsILoadContext; class nsIDocShell; +class nsIWebBrowserPersistDocumentReceiver; namespace mozilla { namespace a11y { class DocAccessibleParent; } namespace jsipc { @@ -82,17 +82,16 @@ class StructuredCloneData; class TabParent final : public PBrowserParent , public nsIDOMEventListener , public nsITabParent , public nsIAuthPromptProvider , public nsISecureBrowserUI , public nsIKeyEventInPluginCallback , public nsSupportsWeakReference , public TabContext - , public nsIWebBrowserPersistable , public LiveResizeListener { typedef mozilla::dom::ClonedMessageData ClonedMessageData; virtual ~TabParent(); public: // Helper class for ContentParent::RecvCreateWindow. @@ -268,18 +267,18 @@ public: const bool& aIsVertical, const LayoutDeviceIntPoint& aPoint) override; virtual mozilla::ipc::IPCResult RecvEnableDisableCommands(const nsString& aAction, nsTArray<nsCString>&& aEnabledCommands, nsTArray<nsCString>&& aDisabledCommands) override; - virtual mozilla::ipc::IPCResult - RecvSetCursor(const uint32_t& aValue, const bool& aForce) override; + virtual mozilla::ipc::IPCResult RecvSetCursor(const nsCursor& aValue, + const bool& aForce) override; virtual mozilla::ipc::IPCResult RecvSetCustomCursor(const nsCString& aUri, const uint32_t& aWidth, const uint32_t& aHeight, const uint32_t& aStride, const uint8_t& aFormat, const uint32_t& aHotspotX, const uint32_t& aHotspotY, @@ -485,17 +484,20 @@ public: PIndexedDBPermissionRequestParent* aActor) override; bool GetGlobalJSObject(JSContext* cx, JSObject** globalp); NS_DECL_ISUPPORTS NS_DECL_NSIAUTHPROMPTPROVIDER NS_DECL_NSISECUREBROWSERUI - NS_DECL_NSIWEBBROWSERPERSISTABLE + + void StartPersistence(uint64_t aOuterWindowID, + nsIWebBrowserPersistDocumentReceiver* aRecv, + ErrorResult& aRv); bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent); bool SendPasteTransferable(const IPCDataTransfer& aDataTransfer, const bool& aIsPrivateData, const IPC::Principal& aRequestingPrincipal, const uint32_t& aContentPolicyType);
--- a/dom/media/ChannelMediaDecoder.cpp +++ b/dom/media/ChannelMediaDecoder.cpp @@ -162,19 +162,19 @@ ChannelMediaDecoder::NotifyPrincipalChan // We'll receive one notification when the channel's initial principal // is known, after all HTTP redirects have resolved. This isn't really a // principal change, so return here to avoid the mSameOriginMedia check // below. mInitialChannelPrincipalKnown = true; return; } if (!mSameOriginMedia && - DecoderTraits::CrossOriginRedirectsProhibited(ContainerType())) { - // For some content types we block mid-flight channel redirects to cross - // origin destinations due to security constraints. See bug 1441153. + Preferences::GetBool("media.block-midflight-redirects", true)) { + // Block mid-flight redirects to non CORS same origin destinations. + // See bugs 1441153, 1443942. LOG("ChannnelMediaDecoder prohibited cross origin redirect blocked."); NetworkError(MediaResult(NS_ERROR_DOM_BAD_URI, "Prohibited cross origin redirect blocked")); } } void ChannelMediaDecoder::ResourceCallback::NotifySuspendedStatusChanged(
--- a/dom/media/ChannelMediaResource.cpp +++ b/dom/media/ChannelMediaResource.cpp @@ -280,16 +280,21 @@ ChannelMediaResource::OnStartRequest(nsI // Not an HTTP channel. Assume data will be sent from position zero. startOffset = 0; } // Update principals before OnDataAvailable() putting the data in the cache. // This is important, we want to make sure all principals are updated before // any consumer can see the new data. UpdatePrincipal(); + if (owner->HasError()) { + // Updating the principal resulted in an error. Abort the load. + CloseChannel(); + return NS_OK; + } mCacheStream.NotifyDataStarted(mLoadID, startOffset, seekable, length); mIsTransportSeekable = seekable; mSuspendAgent.Delegate(mChannel); // Fires an initial progress event. owner->DownloadProgressed(); @@ -312,17 +317,17 @@ ChannelMediaResource::IsTransportSeekabl MOZ_ASSERT(NS_IsMainThread()); return mIsTransportSeekable; } nsresult ChannelMediaResource::ParseContentRangeHeader(nsIHttpChannel * aHttpChan, int64_t& aRangeStart, int64_t& aRangeEnd, - int64_t& aRangeTotal) + int64_t& aRangeTotal) const { NS_ENSURE_ARG(aHttpChan); nsAutoCString rangeStr; nsresult rv = aHttpChan->GetResponseHeader(NS_LITERAL_CSTRING("Content-Range"), rangeStr); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_FALSE(rangeStr.IsEmpty(), NS_ERROR_ILLEGAL_VALUE); @@ -441,40 +446,82 @@ ChannelMediaResource::OnDataAvailable(ui return rv; NS_ASSERTION(read > 0, "Read 0 bytes while data was available?"); count -= read; } return NS_OK; } +int64_t +ChannelMediaResource::CalculateStreamLength() const +{ + if (!mChannel) { + return -1; + } + + nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(mChannel); + if (!hc) { + return -1; + } + + bool succeeded = false; + Unused << hc->GetRequestSucceeded(&succeeded); + if (!succeeded) { + return -1; + } + + // We can't determine the length of uncompressed payload. + const bool isCompressed = IsPayloadCompressed(hc); + if (isCompressed) { + return -1; + } + + int64_t contentLength = -1; + if (NS_FAILED(hc->GetContentLength(&contentLength))) { + return -1; + } + + uint32_t responseStatus = 0; + Unused << hc->GetResponseStatus(&responseStatus); + if (responseStatus != HTTP_PARTIAL_RESPONSE_CODE) { + return contentLength; + } + + // We have an HTTP Byte Range response. The Content-Length is the length + // of the response, not the resource. We need to parse the Content-Range + // header and extract the range total in order to get the stream length. + int64_t rangeStart = 0; + int64_t rangeEnd = 0; + int64_t rangeTotal = 0; + bool gotRangeHeader = NS_SUCCEEDED( + ParseContentRangeHeader(hc, rangeStart, rangeEnd, rangeTotal)); + if (gotRangeHeader && rangeTotal != -1) { + contentLength = std::max(contentLength, rangeTotal); + } + return contentLength; +} + nsresult ChannelMediaResource::Open(nsIStreamListener** aStreamListener) { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); MOZ_ASSERT(aStreamListener); MOZ_ASSERT(mChannel); - int64_t cl = -1; - nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(mChannel); - if (hc && !IsPayloadCompressed(hc)) { - if (NS_FAILED(hc->GetContentLength(&cl))) { - cl = -1; - } - } - - nsresult rv = mCacheStream.Init(cl); + int64_t streamLength = CalculateStreamLength(); + nsresult rv = mCacheStream.Init(streamLength); if (NS_FAILED(rv)) { return rv; } mSharedInfo = new SharedInfo; mSharedInfo->mResources.AppendElement(this); - mIsLiveStream = cl < 0; + mIsLiveStream = streamLength < 0; mListener = new Listener(this, 0, ++mLoadID); *aStreamListener = mListener; NS_ADDREF(*aStreamListener); return NS_OK; } nsresult ChannelMediaResource::OpenChannel(int64_t aOffset)
--- a/dom/media/ChannelMediaResource.h +++ b/dom/media/ChannelMediaResource.h @@ -226,17 +226,21 @@ protected: void UpdatePrincipal(); // Parses 'Content-Range' header and returns results via parameters. // Returns error if header is not available, values are not parse-able or // values are out of range. nsresult ParseContentRangeHeader(nsIHttpChannel * aHttpChan, int64_t& aRangeStart, int64_t& aRangeEnd, - int64_t& aRangeTotal); + int64_t& aRangeTotal) const; + + // Calculates the length of the resource using HTTP headers, if this + // is an HTTP channel. Returns -1 on failure, or for non HTTP channels. + int64_t CalculateStreamLength() const; struct Closure { uint32_t mLoadID; ChannelMediaResource* mResource; }; static nsresult CopySegmentToCache(nsIInputStream* aInStream,
--- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -320,16 +320,9 @@ bool DecoderTraits::IsSupportedInVideoDo ADTSDecoder::IsSupportedType(*type) || FlacDecoder::IsSupportedType(*type) || #ifdef MOZ_ANDROID_HLS_SUPPORT HLSDecoder::IsSupportedType(*type) || #endif false; } -/* static */ -bool -DecoderTraits::CrossOriginRedirectsProhibited(const MediaContainerType& aType) -{ - return WaveDecoder::IsSupportedType(aType); -} - } // namespace mozilla
--- a/dom/media/DecoderTraits.h +++ b/dom/media/DecoderTraits.h @@ -52,18 +52,14 @@ public: // Returns true if aType is MIME type of hls. static bool IsHttpLiveStreamingType(const MediaContainerType& aType); // Returns true if aType is matroska type. static bool IsMatroskaType(const MediaContainerType& aType); static bool IsSupportedType(const MediaContainerType& aType); - - // For some content types we block channel redirects to cross origin - // destinations due to security constraints. See bug 1441153. - static bool CrossOriginRedirectsProhibited(const MediaContainerType& aType); }; } // namespace mozilla #endif
--- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -1,33 +1,26 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* 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/. */ -#ifdef XP_WIN -// Include Windows headers required for enabling high precision timers. -#include "windows.h" -#include "mmsystem.h" -#endif - #include <algorithm> #include <stdint.h> #include "mediasink/AudioSink.h" #include "mediasink/AudioSinkWrapper.h" #include "mediasink/DecodedStream.h" #include "mediasink/OutputStreamManager.h" #include "mediasink/VideoSink.h" #include "mozilla/IndexSequence.h" #include "mozilla/Logging.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/NotNull.h" -#include "mozilla/Preferences.h" #include "mozilla/SharedThreadPool.h" #include "mozilla/Sprintf.h" #include "mozilla/Telemetry.h" #include "mozilla/TaskQueue.h" #include "mozilla/Tuple.h" #include "nsIMemoryReporter.h" #include "nsPrintfCString.h" #include "nsTArray.h" @@ -2700,19 +2693,16 @@ MediaDecoderStateMachine::MediaDecoderSt INIT_MIRROR(mVolume, 1.0), INIT_MIRROR(mPreservesPitch, true), INIT_MIRROR(mLooping, false), INIT_MIRROR(mSameOriginMedia, false), INIT_MIRROR(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE), INIT_CANONICAL(mDuration, NullableTimeUnit()), INIT_CANONICAL(mCurrentPosition, TimeUnit::Zero()), INIT_CANONICAL(mIsAudioDataAudible, false) -#ifdef XP_WIN - , mShouldUseHiResTimers(Preferences::GetBool("media.hi-res-timers.enabled", true)) -#endif { MOZ_COUNT_CTOR(MediaDecoderStateMachine); NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); InitVideoQueuePrefs(); DDLINKCHILD("reader", aReader); } @@ -2720,20 +2710,16 @@ MediaDecoderStateMachine::MediaDecoderSt #undef INIT_WATCHABLE #undef INIT_MIRROR #undef INIT_CANONICAL MediaDecoderStateMachine::~MediaDecoderStateMachine() { MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread."); MOZ_COUNT_DTOR(MediaDecoderStateMachine); - -#ifdef XP_WIN - MOZ_ASSERT(!mHiResTimersRequested); -#endif } void MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder) { MOZ_ASSERT(OnTaskQueue()); // Connect mirrors. @@ -2924,22 +2910,16 @@ MediaDecoderStateMachine::StopPlayback() MOZ_ASSERT(OnTaskQueue()); LOG("StopPlayback()"); if (IsPlaying()) { mOnPlaybackEvent.Notify(MediaPlaybackEvent{ MediaPlaybackEvent::PlaybackStopped, mPlaybackOffset }); mMediaSink->SetPlaying(false); MOZ_ASSERT(!IsPlaying()); -#ifdef XP_WIN - if (mHiResTimersRequested) { - mHiResTimersRequested = false; - timeEndPeriod(1); - } -#endif } } void MediaDecoderStateMachine::MaybeStartPlayback() { MOZ_ASSERT(OnTaskQueue()); // Should try to start playback only after decoding first frames. MOZ_ASSERT(mSentFirstFrameLoadedEvent); @@ -2952,30 +2932,16 @@ void MediaDecoderStateMachine::MaybeStar if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) { LOG("Not starting playback [mPlayState=%d]", mPlayState.Ref()); return; } LOG("MaybeStartPlayback() starting playback"); StartMediaSink(); -#ifdef XP_WIN - if (!mHiResTimersRequested && mShouldUseHiResTimers) { - mHiResTimersRequested = true; - // Ensure high precision timers are enabled on Windows, otherwise the state - // machine isn't woken up at reliable intervals to set the next frame, and we - // drop frames while painting. Note that each call must be matched by a - // corresponding timeEndPeriod() call. Enabling high precision timers causes - // the CPU to wake up more frequently on Windows 7 and earlier, which causes - // more CPU load and battery use. So we only enable high precision timers - // when we're actually playing. - timeBeginPeriod(1); - } -#endif - if (!IsPlaying()) { mMediaSink->SetPlaying(true); MOZ_ASSERT(IsPlaying()); } mOnPlaybackEvent.Notify( MediaPlaybackEvent{ MediaPlaybackEvent::PlaybackStarted, mPlaybackOffset }); }
--- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -746,24 +746,13 @@ public: AbstractCanonical<media::TimeUnit>* CanonicalCurrentPosition() { return &mCurrentPosition; } AbstractCanonical<bool>* CanonicalIsAudioDataAudible() { return &mIsAudioDataAudible; } - -#ifdef XP_WIN - // Whether we've called timeBeginPeriod(1) to request high resolution - // timers. We request high resolution timers when playback starts, and - // turn them off when playback is paused. Enabling high resolution - // timers can cause higher CPU usage and battery drain on Windows 7. - bool mHiResTimersRequested = false; - // Whether we should enable high resolution timers. This is initialized at - // MDSM construction, and mirrors the value of media.hi-res-timers.enabled. - const bool mShouldUseHiResTimers; -#endif }; } // namespace mozilla #endif
--- a/dom/media/MediaPrefs.h +++ b/dom/media/MediaPrefs.h @@ -195,16 +195,17 @@ private: // resume background video decoding when the cursor is hovering over the tab. DECL_MEDIA_PREF("media.resume-bkgnd-video-on-tabhover", ResumeVideoDecodingOnTabHover, bool, false); DECL_MEDIA_PREF("media.videocontrols.lock-video-orientation", VideoOrientationLockEnabled, bool, false); // Media Seamless Looping DECL_MEDIA_PREF("media.seamless-looping", SeamlessLooping, bool, true); + public: // Manage the singleton: static MediaPrefs& GetSingleton(); static bool SingletonExists(); private: template<class T> friend class StaticAutoPtr; static StaticAutoPtr<MediaPrefs> sInstance;
--- a/dom/media/mediasink/VideoSink.cpp +++ b/dom/media/mediasink/VideoSink.cpp @@ -1,14 +1,20 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ +#ifdef XP_WIN +// Include Windows headers required for enabling high precision timers. +#include "windows.h" +#include "mmsystem.h" +#endif + #include "MediaQueue.h" #include "VideoSink.h" #include "MediaPrefs.h" #include "VideoUtils.h" #include "mozilla/IntegerPrintfMacros.h" namespace mozilla { @@ -40,22 +46,29 @@ VideoSink::VideoSink(AbstractThread* aTh , mVideoQueue(aVideoQueue) , mContainer(aContainer) , mProducerID(ImageContainer::AllocateProducerID()) , mFrameStats(aFrameStats) , mHasVideo(false) , mUpdateScheduler(aThread) , mVideoQueueSendToCompositorSize(aVQueueSentToCompositerSize) , mMinVideoQueueSize(MediaPrefs::RuinAvSync() ? 1 : 0) +#ifdef XP_WIN + , mHiResTimersRequested(false) +#endif + { MOZ_ASSERT(mAudioSink, "AudioSink should exist."); } VideoSink::~VideoSink() { +#ifdef XP_WIN + MOZ_ASSERT(!mHiResTimersRequested); +#endif } const MediaSink::PlaybackParams& VideoSink::GetPlaybackParams() const { AssertOwnerThread(); return mAudioSink->GetPlaybackParams(); @@ -133,16 +146,40 @@ void VideoSink::SetPreservesPitch(bool aPreservesPitch) { AssertOwnerThread(); mAudioSink->SetPreservesPitch(aPreservesPitch); } void +VideoSink::EnsureHighResTimersOnOnlyIfPlaying() +{ +#ifdef XP_WIN + const bool needed = IsPlaying(); + if (needed == mHiResTimersRequested) { + return; + } + if (needed) { + // Ensure high precision timers are enabled on Windows, otherwise the VideoSink + // isn't woken up at reliable intervals to set the next frame, and we + // drop frames while painting. Note that each call must be matched by a + // corresponding timeEndPeriod() call. Enabling high precision timers causes + // the CPU to wake up more frequently on Windows 7 and earlier, which causes + // more CPU load and battery use. So we only enable high precision timers + // when we're actually playing. + timeBeginPeriod(1); + } else { + timeEndPeriod(1); + } + mHiResTimersRequested = needed; +#endif +} + +void VideoSink::SetPlaying(bool aPlaying) { AssertOwnerThread(); VSINK_LOG_V(" playing (%d) -> (%d)", mAudioSink->IsPlaying(), aPlaying); if (!aPlaying) { // Reset any update timer if paused. mUpdateScheduler.Reset(); @@ -156,16 +193,18 @@ VideoSink::SetPlaying(bool aPlaying) mAudioSink->SetPlaying(aPlaying); if (mHasVideo && aPlaying) { // There's no thread in VideoSink for pulling video frames, need to trigger // rendering while becoming playing status. because the VideoQueue may be // full already. TryUpdateRenderedVideoFrames(); } + + EnsureHighResTimersOnOnlyIfPlaying(); } void VideoSink::Start(const TimeUnit& aStartTime, const MediaInfo& aInfo) { AssertOwnerThread(); VSINK_LOG("[%s]", __func__); @@ -219,16 +258,18 @@ VideoSink::Stop() mUpdateScheduler.Reset(); if (mHasVideo) { DisconnectListener(); mVideoSinkEndRequest.DisconnectIfExists(); mEndPromiseHolder.ResolveIfExists(true, __func__); mEndPromise = nullptr; } mVideoFrameEndTime = TimeUnit::Zero(); + + EnsureHighResTimersOnOnlyIfPlaying(); } bool VideoSink::IsStarted() const { AssertOwnerThread(); return mAudioSink->IsStarted();
--- a/dom/media/mediasink/VideoSink.h +++ b/dom/media/mediasink/VideoSink.h @@ -74,16 +74,18 @@ private: virtual ~VideoSink(); // VideoQueue listener related. void OnVideoQueuePushed(RefPtr<VideoData>&& aSample); void OnVideoQueueFinished(); void ConnectListener(); void DisconnectListener(); + void EnsureHighResTimersOnOnlyIfPlaying(); + // Sets VideoQueue images into the VideoFrameContainer. Called on the shared // state machine thread. The first aMaxFrames (at most) are set. // aClockTime and aClockTimeStamp are used as the baseline for deriving // timestamps for the frames; when omitted, aMaxFrames must be 1 and // a null timestamp is passed to the VideoFrameContainer. // If the VideoQueue is empty, this does nothing. void RenderVideoFrames(int32_t aMaxFrames, int64_t aClockTime = 0, const TimeStamp& aClickTimeStamp = TimeStamp()); @@ -146,14 +148,23 @@ private: // Talos tests for the compositor require at least one frame in the // video queue so that the compositor has something to composit during // the talos test when the decode is stressed. We have a minimum size // on the video queue in order to facilitate this talos test. // Note: Normal playback should not have a queue size of more than 0, // otherwise A/V sync will be ruined! *Only* make this non-zero for // testing purposes. const uint32_t mMinVideoQueueSize; + +#ifdef XP_WIN + // Whether we've called timeBeginPeriod(1) to request high resolution + // timers. We request high resolution timers when playback starts, and + // turn them off when playback is paused. Enabling high resolution + // timers can cause higher CPU usage and battery drain on Windows 7, + // but reduces our frame drop rate. + bool mHiResTimersRequested; +#endif }; } // namespace media } // namespace mozilla #endif
--- a/dom/media/test/AutoplayTestUtils.js +++ b/dom/media/test/AutoplayTestUtils.js @@ -11,26 +11,16 @@ function playAndPostResult(muted, parent parent_window.postMessage({played: true}, "*"); }, () => { parent_window.postMessage({played: false}, "*"); } ); } -function nextEvent(eventTarget, eventName) { - return new Promise(function(resolve, reject) { - let f = function(event) { - eventTarget.removeEventListener(eventName, f, false); - resolve(event); - }; - eventTarget.addEventListener(eventName, f, false); - }); -} - function nextWindowMessage() { return nextEvent(window, "message"); } function log(msg) { var log_pane = document.body; log_pane.appendChild(document.createTextNode(msg)); log_pane.appendChild(document.createElement("br"));
--- a/dom/media/test/background_video.js +++ b/dom/media/test/background_video.js @@ -9,32 +9,16 @@ function startTest(test) { info(test.desc); SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({ 'set': test.prefs }, () => { manager.runTests(test.tests, test.runTest); }); } -/** - * @param {HTMLMediaElement} video target of interest. - * @param {string} eventName the event to wait on. - * @returns {Promise} A promise that is resolved when event happens. - */ -function nextEvent(video, eventName) { - return new Promise(function (resolve, reject) { - let f = function (event) { - ok(true, `${video.token} ${eventName}.`); - video.removeEventListener(eventName, f, false); - resolve(event); - }; - video.addEventListener(eventName, f, false); - }); -} - function nextVideoEnded(video) { return nextEvent(video, 'ended'); } function nextVideoPlaying(video) { return nextEvent(video, 'playing'); }
deleted file mode 100644 --- a/dom/media/test/dynamic_redirect.sjs +++ /dev/null @@ -1,67 +0,0 @@ -function parseQuery(query, key) { - for (let p of query.split('&')) { - if (p == key) { - return true; - } - if (p.startsWith(key + "=")) { - return p.substring(key.length + 1); - } - } -} - -// Return seek.ogv file content for the first request with a given key. -// All subsequent requests return a redirect to a different-origin resource. -function handleRequest(request, response) -{ - var query = request.queryString; - var key = parseQuery(query, "key"); - var resource = parseQuery(query, "res"); - var nested = parseQuery(query, "nested") || false; - - dump("Received request for key = "+ key +"\n"); - if (!nested) { - if (getState(key) == "redirect") { - var origin = request.host == "mochi.test" ? "example.org" : "mochi.test:8888"; - response.setStatusLine(request.httpVersion, 303, "See Other"); - let url = "http://" + origin + - "/tests/dom/media/test/dynamic_redirect.sjs?nested&" + query; - dump("Redirecting to "+ url + "\n"); - response.setHeader("Location", url); - response.setHeader("Content-Type", "text/html"); - return; - } - setState(key, "redirect"); - } - var file = Components.classes["@mozilla.org/file/directory_service;1"]. - getService(Components.interfaces.nsIProperties). - get("CurWorkD", Components.interfaces.nsIFile); - var fis = Components.classes['@mozilla.org/network/file-input-stream;1']. - createInstance(Components.interfaces.nsIFileInputStream); - var bis = Components.classes["@mozilla.org/binaryinputstream;1"]. - createInstance(Components.interfaces.nsIBinaryInputStream); - var paths = "tests/dom/media/test/" + resource; - var split = paths.split("/"); - for (var i = 0; i < split.length; ++i) { - file.append(split[i]); - } - fis.init(file, -1, -1, false); - - bis.setInputStream(fis); - var bytes = bis.readBytes(bis.available()); - let [from, to] = request.getHeader("range").split("=")[1].split("-").map(s => parseInt(s)); - to = to || Math.max(from, bytes.length - 1); - byterange = bytes.substring(from, to + 1); - - let contentRange = "bytes "+ from +"-"+ to +"/"+ bytes.length; - let contentLength = (to - from + 1).toString(); - dump("Response Content-Range = "+ contentRange +"\n"); - dump("Response Content-Length = "+ contentLength +"\n"); - - response.setStatusLine(request.httpVersion, 206, "Partial Content"); - response.setHeader("Content-Range", contentRange); - response.setHeader("Content-Length", contentLength, false); - response.setHeader("Content-Type", "video/ogg", false); - response.setHeader("Accept-Ranges", "bytes", false); - response.write(byterange, byterange.length); - bis.close(); -}
--- a/dom/media/test/file_autoplay_policy_activation_frame.html +++ b/dom/media/test/file_autoplay_policy_activation_frame.html @@ -1,12 +1,13 @@ <!DOCTYPE HTML> <html> <head> <title>Autoplay policy frame</title> + <script type="text/javascript" src="manifest.js"></script> <script type="text/javascript" src="AutoplayTestUtils.js"></script> <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> <style> video { width: 50%; height: 50%; } </style>
new file mode 100644 --- /dev/null +++ b/dom/media/test/file_autoplay_policy_play_before_loadedmetadata.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<html> + +<head> + <title>Autoplay policy window</title> + <style> + video { + width: 50%; + height: 50%; + } + </style> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> + <script type="text/javascript" src="manifest.js"></script> + <script type="text/javascript" src="AutoplayTestUtils.js"></script> +</head> + +<body> + <pre id="test"> + <script> + + window.is = window.opener.is; + window.info = window.opener.info; + + async function testPlayBeforeLoadedMetata(testCase, parent_window) { + info("testPlayBeforeLoadedMetata: " + testCase.resource); + + let element = document.createElement("video"); + element.preload = "auto"; + element.src = testCase.resource; + document.body.appendChild(element); + + let played = await element.play().then(() => true, () => false); + let msg = testCase.resource + " should " + (!testCase.shouldPlay ? "not " : "") + "play"; + is(played, testCase.shouldPlay, msg); + + removeNodeAndSource(element); + } + + nextWindowMessage().then( + async (event) => { + await testPlayBeforeLoadedMetata(event.data, event.source); + event.source.postMessage("done", "*"); + }); + + </script> + </pre> +</body> + +</html> \ No newline at end of file
--- a/dom/media/test/manifest.js +++ b/dom/media/test/manifest.js @@ -1586,16 +1586,31 @@ function once(target, name, cb) { }, {once: true}); }); if (cb) { p.then(cb); } return p; } +/** + * @param {HTMLMediaElement} video target of interest. + * @param {string} eventName the event to wait on. + * @returns {Promise} A promise that is resolved when event happens. + */ +function nextEvent(video, eventName) { + return new Promise(function (resolve, reject) { + let f = function (event) { + video.removeEventListener(eventName, f, false); + resolve(event); + }; + video.addEventListener(eventName, f, false); + }); +} + function TimeStamp(token) { function pad(x) { return (x < 10) ? "0" + x : x; } var now = new Date(); var ms = now.getMilliseconds(); var time = "[" + pad(now.getHours()) + ":" +
new file mode 100644 --- /dev/null +++ b/dom/media/test/midflight-redirect.sjs @@ -0,0 +1,78 @@ +function parseQuery(query, key) { + for (let p of query.split('&')) { + if (p == key) { + return true; + } + if (p.startsWith(key + "=")) { + return p.substring(key.length + 1); + } + } +} + +// Return the first few bytes in a short byte range response. When Firefox +// requests subsequent bytes in a second range request, respond with a +// redirect. Requests after the first redirected are serviced as expected. +function handleRequest(request, response) +{ + var query = request.queryString; + var resource = parseQuery(query, "resource"); + var type = parseQuery(query, "type") || "application/octet-stream"; + var redirected = parseQuery(query, "redirected") || false; + var useCors = parseQuery(query, "cors") || false; + + var file = Components.classes["@mozilla.org/file/directory_service;1"]. + getService(Components.interfaces.nsIProperties). + get("CurWorkD", Components.interfaces.nsIFile); + var fis = Components.classes['@mozilla.org/network/file-input-stream;1']. + createInstance(Components.interfaces.nsIFileInputStream); + var bis = Components.classes["@mozilla.org/binaryinputstream;1"]. + createInstance(Components.interfaces.nsIBinaryInputStream); + var paths = "tests/dom/media/test/" + resource; + var split = paths.split("/"); + for (var i = 0; i < split.length; ++i) { + file.append(split[i]); + } + fis.init(file, -1, -1, false); + + bis.setInputStream(fis); + var bytes = bis.readBytes(bis.available()); + let [from, to] = request.getHeader("range").split("=")[1].split("-").map(s => parseInt(s)); + + if (!redirected && from > 0) { + var origin = request.host == "mochi.test" ? "example.org" : "mochi.test:8888"; + response.setStatusLine(request.httpVersion, 303, "See Other"); + let url = "http://" + origin + + "/tests/dom/media/test/midflight-redirect.sjs?redirected&" + query; + response.setHeader("Location", url); + response.setHeader("Content-Type", "text/html"); + return; + } + + if (isNaN(to)) { + to = bytes.length - 1; + } + + if (from == 0 && !redirected) { + to = parseInt(parseQuery(query, "redirectAt")) || Math.floor(bytes.length / 4); + } + to = Math.min(to, bytes.length - 1); + + // Note: 'to' is the first index *excluded*, so we need (to + 1) + // in the substring end here. + byterange = bytes.substring(from, to + 1); + + let contentRange = "bytes " + from + "-" + to + "/" + bytes.length; + let contentLength = byterange.length.toString(); + + response.setStatusLine(request.httpVersion, 206, "Partial Content"); + response.setHeader("Content-Range", contentRange); + response.setHeader("Content-Length", contentLength, false); + response.setHeader("Content-Type", type, false); + response.setHeader("Accept-Ranges", "bytes", false); + response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + if (redirected && useCors) { + response.setHeader("Access-Control-Allow-Origin", "*"); + } + response.write(byterange, byterange.length); + bis.close(); +}
--- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -429,23 +429,23 @@ support-files = detodos-short.webm detodos-short.webm^headers^ detodos-recorder-test.opus detodos-recorder-test.opus^headers^ detodos-short.opus detodos-short.opus^headers^ dirac.ogg dirac.ogg^headers^ - dynamic_redirect.sjs dynamic_resource.sjs eme.js file_access_controls.html file_autoplay_policy_unmute_pauses.html file_autoplay_policy_activation_window.html file_autoplay_policy_activation_frame.html + file_autoplay_policy_play_before_loadedmetadata.html flac-s24.flac flac-s24.flac^headers^ flac-noheader-s16.flac flac-noheader-s16.flac^headers^ fragment_noplay.js fragment_play.js gizmo.mp4 gizmo.mp4^headers^ @@ -490,16 +490,17 @@ support-files = invalid-m2c1.opus invalid-m2c1.opus^headers^ invalid-neg_discard.webm invalid-neg_discard.webm^headers^ invalid-preskip.webm invalid-preskip.webm^headers^ long.vtt manifest.js + midflight-redirect.sjs multiple-bos.ogg multiple-bos.ogg^headers^ multiple-bos-more-header-fileds.ogg multiple-bos-more-header-fileds.ogg^headers^ no-cues.webm no-cues.webm^headers^ notags.mp3 notags.mp3^headers^ @@ -690,16 +691,18 @@ skip-if = true # bug 475110 - disabled s [test_autoplay_contentEditable.html] skip-if = android_version == '15' || android_version == '17' || android_version == '22' # android(bug 1232305, bug 1232318, bug 1372457) [test_autoplay_policy.html] skip-if = android_version == '23' # bug 1424903 [test_autoplay_policy_activation.html] skip-if = android_version == '23' # bug 1424903 [test_autoplay_policy_unmute_pauses.html] skip-if = android_version == '23' # bug 1424903 +[test_autoplay_policy_play_before_loadedmetadata.html] +skip-if = android_version == '23' # bug 1424903 [test_buffered.html] skip-if = android_version == '15' || android_version == '22' # bug 1308388, android(bug 1232305) [test_bug448534.html] [test_bug463162.xhtml] [test_bug465498.html] skip-if = toolkit == 'android' # android(bug 1232305) [test_bug495145.html] skip-if = (os == 'mac' && os_version == '10.6') || (toolkit == 'android') # bug 1311229, android(bug 1232305) @@ -945,16 +948,17 @@ skip-if = android_version == '17' # andr tags=msg [test_mediatrack_events.html] skip-if = android_version == '17' # android(bug 1232305) [test_mediatrack_parsing_ogg.html] skip-if = android_version == '17' # android(bug 1232305) [test_mediatrack_replay_from_end.html] skip-if = toolkit == 'android' # android(bug 1232305) [test_metadata.html] +[test_midflight_redirect_blocked.html] [test_mixed_principals.html] skip-if = toolkit == 'android' # bug 1309814, android(bug 1232305) [test_mozHasAudio.html] skip-if = toolkit == 'android' # android(bug 1232305) [test_multiple_mediastreamtracks.html] skip-if = android_version == '17' # android(bug 1232305) [test_networkState.html] skip-if = android_version == '17' # android(bug 1232305)
new file mode 100644 --- /dev/null +++ b/dom/media/test/test_autoplay_policy_play_before_loadedmetadata.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML> +<html> + +<head> + <title>Autoplay policy test</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <script type="text/javascript" src="manifest.js"></script> + <script type="text/javascript" src="AutoplayTestUtils.js"></script> +</head> + +<body> + <pre id="test"> + <script> + + window.is = SimpleTest.is; + window.info = SimpleTest.info; + + // Tests that videos which have no audio track will play if play() + // is called before the video has reached readyState >= HAVE_METADATA. + + gTestPrefs.push(["media.autoplay.enabled", false], + ["media.autoplay.enabled.user-gestures-needed", true]); + + SpecialPowers.pushPrefEnv({ 'set': gTestPrefs }, () => { + runTest(); + }); + + let testCases = [ + { + resource: "320x240.ogv", // Only video track. + shouldPlay: true, + }, + { + resource: "short.mp4", // Audio and video track. + shouldPlay: false, + }, + ]; + + let child_url = "file_autoplay_policy_play_before_loadedmetadata.html"; + + async function runTest() { + for (testCase of testCases) { + // Run each test in a new window, to ensure its user gesture + // activation state isn't tainted by preceeding tests. + let child = window.open(child_url, "", "width=500,height=500"); + await once(child, "load"); + child.postMessage(testCase, window.origin); + let result = await nextWindowMessage(); + child.close(); + } + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + + </script> + </pre> +</body> + +</html> \ No newline at end of file
--- a/dom/media/test/test_mediarecorder_principals.html +++ b/dom/media/test/test_mediarecorder_principals.html @@ -10,109 +10,123 @@ https://bugzilla.mozilla.org/show_bug.cg <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <script type="text/javascript" src="manifest.js"></script> </head> <body> <div> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1018299">Test for MediaRecorder Principal Handling</a> </div> -<video id="v1" preload="metadata"></video> -<video id="v2" preload="metadata"></video> - <pre id="test"> <script type="text/javascript"> SimpleTest.waitForExplicitFinish(); let throwOutside = e => setTimeout(() => { throw e; }); -// Generate a random key. The first load with that key will return -// data, the second and subsequent loads with that key will return a redirect -// to a different origin ('localhost:8888' will be redirected to 'example.org', -// and 'example.org' will be redirected to 'localhost:8888'). -// Loading data from two different origins should be detected by the media -// cache and result in a null principal so that the MediaRecorder usages below -// fail. -// This test relies on that preloading the metadata then forcing another load -// via video.load() will result in two requests taking place to retreive the -// resource. -let key = Math.floor(Math.random()*100000000); -let interval; +// Loading data from a resource that changes origins while streaming should +// be detected by the media cache and result in a null principal so that the +// MediaRecorder usages below fail. -function testPrincipals(resource) { +// This test relies on midflight-redirect.sjs returning the the first quarter of +// the resource as a byte range response, and then hanging up, and when Firefox +// requests the remainder midflight-redirect.sjs serves a redirect to another origin. + +async function testPrincipals(resource) { if (!resource) { todo(false, "No types supported"); return; } - // First test: Load file from same-origin first, then get redirected to - // another origin before attempting to record stream. - let video = document.getElementById("v1"); + await testPrincipals1(resource); + await testPrincipals2(resource); +} + +function makeVideo() { + let video = document.createElement("video"); + video.preload = "metadata"; + video.controls = true; + document.body.appendChild(video); + return video; +} + +// First test: Load file from same-origin first, then get redirected to +// another origin before attempting to record stream. +async function testPrincipals1(resource) { + let video = makeVideo(); video.src = - "http://mochi.test:8888/tests/dom/media/test/dynamic_redirect.sjs?key=v1_" + - key + "&res=" + resource.name; - return new Promise(resolve => video.onloadedmetadata = resolve).then(() => { - video.load(); - video.play(); - interval = setInterval(() => info("video.currentTime = "+ video.currentTime), 1000); + "http://mochi.test:8888/tests/dom/media/test/midflight-redirect.sjs" + + "?resource=" + resource.name + "&type=" + resource.type; + + let errorBarrier = once(video, "error"); + // Wait for the video to load to metadata. We can then start capturing. + // Must also handle the download bursting and hitting the error before we + // reach loadedmetadata. Normally we reach loadedmetadata first, but + // rarely we hit the redirect first. + await Promise.race([once(video, "loadedmetadata"), errorBarrier]); + + let rec = new MediaRecorder(video.mozCaptureStreamUntilEnded()); + video.play(); + + // Wait until we hit a playback error. This means our download has hit the redirect. + await errorBarrier; + + // Try to record, it should be blocked with a security error. + try { + rec.start(); + ok(false, "mediaRecorder.start() must throw SecurityError, but didn't throw at all"); + } catch (ex) { + is(ex.name, "SecurityError", "mediaRecorder.start() must throw SecurityError"); + } + removeNodeAndSource(video); +} - let msg = "mediaRecorder.start() must throw SecurityError"; - return new Promise(resolve => video.onplaying = resolve) - .then(() => waitUntil(() => video.currentTime > resource.duration / 5)) - // Test failure of the next step only, so "catch-bypass" any errors above. - .then(() => Promise.resolve() - .then(() => new MediaRecorder(video.mozCaptureStreamUntilEnded()).start()) - .then(() => ok(false, msg), e => is(e.name, "SecurityError", msg)), 0) - .then(() => clearInterval(interval)); - }) - .then(() => { - // Second test: Load file from same-origin first, but record ASAP, before - // getting redirected to another origin. - let video = document.getElementById("v2"); - video.src = - "http://mochi.test:8888/tests/dom/media/test/dynamic_redirect.sjs?key=v2_" + - key + "&res=" + resource.name; - let rec, hasStopped, hasEnded = new Promise(r => video.onended = r); - let data = []; +// Second test: Load file from same-origin first, but record ASAP, before +// getting redirected to another origin. +async function testPrincipals2(resource) { + let video = makeVideo(); + video.src = + "http://mochi.test:8888/tests/dom/media/test/midflight-redirect.sjs" + + "?resource=" + resource.name + "&type=" + resource.type; + + // Wait for the video to load to metadata. We can then start capturing. + // Must also handle the download bursting and hitting the error before we + // reach loadedmetadata. Normally we reach loadedmetadata first, but + // rarely we hit the redirect first. + await Promise.race([once(video, "loadedmetadata"), once(video, "error")]); + + let ended = false; + once(video, "ended", () => ended = true); - let msgNoThrow = "mediaRecorder.start() should not throw here"; - let msgSecErr = "mediaRecorder.onerror must fire SecurityError"; - let msgOnStop = "mediaRecorder.onstop must also have fired"; - return new Promise(resolve => video.onloadedmetadata = resolve).then(() => { - rec = new MediaRecorder(video.mozCaptureStreamUntilEnded()); - rec.ondataavailable = e => data.push(e.data); - rec.start(); - video.load(); - hasStopped = new Promise(resolve => rec.onstop = resolve); - video.play(); - }) - .then(() => ok(true, msgNoThrow), e => is(e.error.name, null, msgNoThrow)) - .then(() => Promise.race([ - new Promise((_, reject) => rec.onerror = e => reject(e.error)), - hasEnded - ])) - .then(() => ok(false, msgSecErr), e => { - is(e.name, "SecurityError", msgSecErr); - ok(e.stack.includes('test_mediarecorder_principals.html'), - 'Events fired from onerror should include an error with a stack trace indicating ' + - 'an error in this test'); - }) - .then(() => Promise.race([hasStopped, hasEnded.then(() => Promise.reject())])) - .then(() => ok(true, msgOnStop), e => ok(false, msgOnStop)) - .then(() => clearInterval(interval)); - }); + // Start capturing. It should work. + let rec; + let errorBarrier; + try { + rec = new MediaRecorder(video.mozCaptureStreamUntilEnded()); + errorBarrier = nextEvent(rec, "error"); + rec.start(); + ok(true, "mediaRecorder.start() should not throw here, and didn't"); + } catch (ex) { + ok(false, "mediaRecorder.start() unexpectedly threw " + ex.name + " (" + ex.message + ")"); + } + + // Play the video, this should result in a SecurityError on the recorder. + let hasStopped = once(rec, "stop"); + video.play(); + let error = (await errorBarrier).error; + is(error.name, "SecurityError", "mediaRecorder.onerror must fire SecurityError"); + ok(error.stack.includes('test_mediarecorder_principals.html'), + 'Events fired from onerror should include an error with a stack trace indicating ' + + 'an error in this test'); + is(ended, false, "Playback should not have reached end"); + await hasStopped; + is(ended, false, "Playback should definitely not have reached end"); + + removeNodeAndSource(video); } testPrincipals({ name:"pixel_aspect_ratio.mp4", type:"video/mp4", duration:28 }) -.catch(e => throwOutside(e)) -.then(() => SimpleTest.finish()) -.catch(e => throwOutside(e)); - -let stop = stream => stream.getTracks().forEach(track => track.stop()); -let wait = ms => new Promise(resolve => setTimeout(resolve, ms)); -let waitUntil = f => new Promise(resolve => { - let ival = setInterval(() => f() && resolve(clearInterval(ival)), 100); -}); + .catch(e => throwOutside(e)) + .then(() => SimpleTest.finish()); </script> </pre> </body> </html>
new file mode 100644 --- /dev/null +++ b/dom/media/test/test_midflight_redirect_blocked.html @@ -0,0 +1,100 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>Test mid-flight cross site redirects are blocked</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <script type="text/javascript" src="manifest.js"></script> + </head> + <body> + <pre id='test'> + <script class="testbody" type='application/javascript'> + + function testIfLoadsToMetadata(test, useCors) { + return new Promise(function(resolve, reject) { + var elemType = getMajorMimeType(test.type); + var element = document.createElement(elemType); + + if (useCors) { + element.crossOrigin = "anonymous"; + } + + // Log events for debugging. + [ + "suspend", "play", "canplay", "canplaythrough", "loadstart", + "loadedmetadata", "loadeddata", "playing", "ended", "error", + "stalled", "emptied", "abort", "waiting", "pause" + ].forEach((eventName) => { + element.addEventListener(eventName, (event)=> { + info(test.name + " " + event.type); + }); + }); + + element.addEventListener("loadedmetadata", ()=>{ + resolve(true); + removeNodeAndSource(element); + }, false); + + element.addEventListener("error", ()=>{ + resolve(false); + removeNodeAndSource(element); + }, false); + + var noise = Math.floor(Math.random() * 100000000); + // Note: request redirect before the end of metadata, otherwise we won't + // error before metadata has loaded if mixed origins are allowed. + element.src = "midflight-redirect.sjs?resource=" + test.name + + (useCors ? "&cors" : "") + + "&type=" + test.type + + "&redirectAt=200"; + element.preload = "metadata"; + document.body.appendChild(element); + element.load() + }); + } + + let v = document.createElement("video"); + const testCases = gSmallTests.filter(t => v.canPlayType(t.type)); + + function testMediaLoad(expectedToLoad, message, useCors) { + return new Promise(async function(resolve, reject) { + for (let test of testCases) { + let loaded = await testIfLoadsToMetadata(test, useCors); + is(loaded, expectedToLoad, test.name + " " + message); + } + resolve(); + }); + } + + async function runTest() { + try { + SimpleTest.info("Allowing midflight redirects..."); + await SpecialPowers.pushPrefEnv({'set': [["media.block-midflight-redirects", false]]}); + + SimpleTest.info("Test that all media plays..."); + await testMediaLoad(true, "expected to load", false); + + SimpleTest.info("Blocking midflight redirects..."); + await SpecialPowers.pushPrefEnv({'set': [["media.block-midflight-redirects", true]]}); + + SimpleTest.info("Test that all media no longer play..."); + await testMediaLoad(false, "expected to be blocked", false); + + SimpleTest.info("Test that all media play if CORS used..."); + await testMediaLoad(true, "expected to play with CORS", true); + } catch (e) { + info("Exception " + e.message); + ok(false, "Threw exception " + e.message); + } + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + + addLoadEvent(runTest); + + </script> + </pre> + </body> +</html>
--- a/dom/media/test/test_mixed_principals.html +++ b/dom/media/test/test_mixed_principals.html @@ -2,93 +2,82 @@ <html> <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=489415 --> <head> <title>Test for Bug 489415</title> <script type="application/javascript" src="/MochiKit/MochiKit.js"></script> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> <script type="text/javascript" src="manifest.js"></script> + <style> + video { + width: 40%; + border: solid black 1px; + } + </style> </head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=489415">Mozilla Bug 489415</a> -<p id="display"></p> - -<video id="v1" preload="metadata" onended="onendedcb('v1')"></video> -<video id="v2" preload="metadata" onended="onendedcb('v2')"></video> - -<pre id="test"> -<script type="text/javascript"> -SimpleTest.waitForExplicitFinish(); - -var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p}); - -var v1 = document.getElementById("v1"); -var v2 = document.getElementById("v2"); -var count = 0; -function onendedcb(id) { - var c = document.createElement("canvas"); - var ctx = c.getContext("2d"); - var v = document.getElementById(id); - ctx.drawImage(v, 0, 0); - try { - c.toDataURL(); - ok(false, "Failed to throw exception in toDataURL for " + id); - } catch (ex) { - ok(true, "Threw exception in toDataURL for " + id); - } - if (++count == 2) { - SimpleTest.finish(); - } -} +<body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=489415">Mozilla Bug 489415</a> + <p id="display"></p> + <pre id="test"> + <script type="text/javascript"> + SimpleTest.waitForExplicitFinish(); + + var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({ set: p }); + var count = 0; -function testMixedPrincipals(resource) { - // In some OS(XP) can not play mp4. Add this checking for the test failure. - if (!resource || !v1.canPlayType(resource.type)) { - todo(false, "No types supported"); - SimpleTest.finish(); - return; - } - // Make sure the media cache size(50MB) is large enough that the data could - // be download in MediaCache completely. - return pushPrefs(['media.cache_size', 50*1024]) - .then(() => { - - // Generate a random key. The first load with that key will return - // data, the second and subsequent loads with that key will return a redirect - // to a different origin ('localhost:8888' will be redirected to 'example.org', - // and 'example.org' will be redirected to 'localhost:8888'). We rely on the - // fact that Ogg will do a seek to the end of the resource, triggering a new - // load with the same key which will return a same-origin resource. - // Loading data from two different origins should be detected by the media - // cache and result in a null principal so that the canvas usage above fails. - var key = Math.floor(Math.random()*100000000); - - // In v1, try loading from same-origin first and then getting redirected to - // another origin. - v1.src = - "http://mochi.test:8888/tests/dom/media/test/dynamic_redirect.sjs?key=v1_" + - key + "&res=" + resource.name; - v1.onloadeddata = function () { - // To limit readahead, avoid racing with playback and "catching up" mode. - v1.play(); + function canReadBack(video) { + var c = document.createElement("canvas"); + var ctx = c.getContext("2d"); + ctx.drawImage(video, 0, 0); + try { + c.toDataURL(); + return true; + } catch (ex) { + return false; + } } - // In v2, try loading cross-origin first and then getting redirected to - // our origin. - v2.src = "http://example.org/tests/dom/media/test/dynamic_redirect.sjs?key=v2_" + key + "&res=" + resource.name; - v2.onloadeddata = function () { - // To limit readahead, avoid racing with playback and "catching up" mode. - v2.play(); + function runTest(origin, shouldReadBackOnLoad) { + return new Promise(function (resolve, reject) { + // Load will redirect mid-flight, which will be detected and should error, + // and we should no longer be able to readback. + var video = document.createElement("video"); + video.preload = "metadata"; + video.controls = true; + var url = "http://" + origin + "/tests/dom/media/test/midflight-redirect.sjs" + + "?resource=pixel_aspect_ratio.mp4&type=video/mp4"; + SimpleTest.info("Loading from " + url); + video.src = url; + document.body.appendChild(video); + + once(video, "loadeddata", () => { + is(canReadBack(video), shouldReadBackOnLoad, "Should be able to readback"); + video.play(); + }); + + once(video, "error", () => { + is(canReadBack(video), false, "Should not be able to readback after error"); + removeNodeAndSource(video); + resolve(); + }); + + once(video, "ended", () => { + ok(false, "Should not be able to playback to end, we should have errored!"); + removeNodeAndSource(video); + resolve(); + }); + + }); } - }); -} -testMixedPrincipals({ name:"pixel_aspect_ratio.mp4", type:"video/mp4", duration:28}); + Promise.all([ + runTest("mochi.test:8888", true), + runTest("example.org", false), + ]).then(SimpleTest.finish); -</script> + </script> </pre> - </body> </html>
--- a/dom/tests/browser/browser_noopener.js +++ b/dom/tests/browser/browser_noopener.js @@ -39,17 +39,17 @@ async function doTests(private, containe for (let test of TESTS) { const testid = `${test.id} (private=${private}, container=${container}, alwaysNewWindow=${alwaysNewWindow})`; let originalTab = BrowserTestUtils.addTab(window.gBrowser, TEST_URL, tabOpenOptions); await BrowserTestUtils.browserLoaded(originalTab.linkedBrowser); await BrowserTestUtils.switchTab(window.gBrowser, originalTab); let waitFor; if (test.newWindow || alwaysNewWindow) { - waitFor = BrowserTestUtils.waitForNewWindow(TARGET_URL); + waitFor = BrowserTestUtils.waitForNewWindow({url: TARGET_URL}); // Confirm that this window has private browsing set if we're doing a private browsing test } else { waitFor = BrowserTestUtils.waitForNewTab(window.gBrowser, TARGET_URL, true); } BrowserTestUtils.synthesizeMouseAtCenter(test.id, {}, window.gBrowser.getBrowserForTab(originalTab)); let tab;
--- a/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp +++ b/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp @@ -324,17 +324,19 @@ ResourceReader::OnWalkSubframe(nsIDOMNod NS_ENSURE_STATE(loaderOwner); RefPtr<nsFrameLoader> loader = loaderOwner->GetFrameLoader(); NS_ENSURE_STATE(loader); ++mOutstandingDocuments; // Pass in 0 as the outer window ID so that we start // persisting the root of this subframe, and not some other // subframe child of this subframe. - nsresult rv = loader->StartPersistence(0, this); + ErrorResult err; + loader->StartPersistence(0, this, err); + nsresult rv = err.StealNSResult(); if (NS_FAILED(rv)) { if (rv == NS_ERROR_NO_CONTENT) { // Just ignore frames with no content document. rv = NS_OK; } // StartPersistence won't eventually call this if it failed, // so this does so (to keep mOutstandingDocuments correct). DocumentDone(rv);
--- a/dom/webbrowserpersist/moz.build +++ b/dom/webbrowserpersist/moz.build @@ -6,17 +6,16 @@ # moved from embedding/components/webbrowserpersist Jan 13, 2017 with Files("**"): BUG_COMPONENT = ("Core", "DOM") XPIDL_SOURCES += [ 'nsCWebBrowserPersist.idl', 'nsIWebBrowserPersist.idl', - 'nsIWebBrowserPersistable.idl', 'nsIWebBrowserPersistDocument.idl', ] XPIDL_MODULE = 'webbrowserpersist' IPDL_SOURCES += [ 'PWebBrowserPersistDocument.ipdl', 'PWebBrowserPersistResources.ipdl',
--- a/dom/webbrowserpersist/nsIWebBrowserPersist.idl +++ b/dom/webbrowserpersist/nsIWebBrowserPersist.idl @@ -243,17 +243,17 @@ interface nsIWebBrowserPersist : nsICanc * document and all subdocuments into or nullptr to use * the default behaviour. * @param aEncodingFlags Flags to pass to the encoder. * @param aWrapColumn For text documents, indicates the desired width to * wrap text at. Parameter is ignored if wrapping is not * specified by the encoding flags. * * @see nsIWebBrowserPersistDocument - * @see nsIWebBrowserPersistable + * @see WebBrowserPersistable * @see nsIFile * @see nsIURI * * @throws NS_ERROR_INVALID_ARG One or more arguments was invalid. */ void saveDocument(in nsISupports aDocument, in nsISupports aFile, in nsISupports aDataPath, in string aOutputContentType, in unsigned long aEncodingFlags,
--- a/dom/webbrowserpersist/nsIWebBrowserPersistDocument.idl +++ b/dom/webbrowserpersist/nsIWebBrowserPersistDocument.idl @@ -182,16 +182,19 @@ interface nsIWebBrowserPersistWriteCompl in ACString aContentType, in nsresult aStatus); }; /** * Asynchronous callback for creating a persistable document from some * other object. * - * @see nsIWebBrowserPersistable. + * XXXbz This should really be changed to just return a promise that + * then gets resolved or rejected... + * + * @see WebBrowserPersistable in FrameLoader.webidl. */ [scriptable, uuid(321e3174-594f-4036-b7be-791b821bd376)] interface nsIWebBrowserPersistDocumentReceiver : nsISupports { void onDocumentReady(in nsIWebBrowserPersistDocument aDocument); void onError(in nsresult aFailure); };
deleted file mode 100644 --- a/dom/webbrowserpersist/nsIWebBrowserPersistable.idl +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: IDL; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIWebBrowserPersistDocumentReceiver; - -/** - * Interface for objects which represent a document that can be - * serialized with nsIWebBrowserPersist. This interface is - * asynchronous because the actual document can be in another process - * (e.g., if this object is an nsFrameLoader for an out-of-process - * frame). - * - * Warning: this is currently implemented only by nsFrameLoader, and - * may change in the future to become more frame-loader-specific or be - * merged into nsFrameLoader. See bug 1101100 comment #34. - * - * @see nsIWebBrowserPersistDocumentReceiver - * @see nsIWebBrowserPersistDocument - * @see nsIWebBrowserPersist - * - * @param aOuterWindowID - * The outer window ID of the subframe we'd like to persist. - * If set at 0, nsIWebBrowserPersistable will attempt to persist - * the top-level document. If the outer window ID is for a subframe - * that does not exist, or is not held beneath the nsIWebBrowserPersistable, - * aRecv's onError method will be called with NS_ERROR_NO_CONTENT. - * @param aRecv - * The nsIWebBrowserPersistDocumentReceiver is a callback that - * will be fired once the document is ready for persisting. - */ -[uuid(f4c3fa8e-83e9-49f8-ac6f-951fc7541fe4)] -interface nsIWebBrowserPersistable : nsISupports -{ - void startPersistence(in unsigned long long aOuterWindowID, - in nsIWebBrowserPersistDocumentReceiver aRecv); -};
--- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp +++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp @@ -50,17 +50,16 @@ #include "nsIImageLoadingContent.h" #include "ftpCore.h" #include "nsITransport.h" #include "nsISocketTransport.h" #include "nsIStringBundle.h" #include "nsIProtocolHandler.h" -#include "nsIWebBrowserPersistable.h" #include "nsWebBrowserPersist.h" #include "WebBrowserPersistLocalDocument.h" #include "nsIContent.h" #include "nsIMIMEInfo.h" #include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/HTMLSharedElement.h" #include "mozilla/Printf.h"
--- a/dom/webidl/FrameLoader.webidl +++ b/dom/webidl/FrameLoader.webidl @@ -174,16 +174,39 @@ interface FrameLoader { /** * Is `true` if the frameloader is dead (destroy has been called on it) */ [Pure] readonly attribute boolean isDead; }; +/** + * Interface for objects which represent a document that can be + * serialized with nsIWebBrowserPersist. This interface is + * asynchronous because the actual document can be in another process + * (e.g., if this object is a FrameLoader for an out-of-process + * frame). + * + * XXXbz This method should really just return a Promise... + * + * @see nsIWebBrowserPersistDocumentReceiver + * @see nsIWebBrowserPersistDocument + * @see nsIWebBrowserPersist + * + * @param aOuterWindowID + * The outer window ID of the subframe we'd like to persist. + * If set at 0, WebBrowserPersistable will attempt to persist + * the top-level document. If the outer window ID is for a subframe + * that does not exist, or is not held beneath the WebBrowserPersistable, + * aRecv's onError method will be called with NS_ERROR_NO_CONTENT. + * @param aRecv + * The nsIWebBrowserPersistDocumentReceiver is a callback that + * will be fired once the document is ready for persisting. + */ [NoInterfaceObject] interface WebBrowserPersistable { [Throws] void startPersistence(unsigned long long aOuterWindowID, nsIWebBrowserPersistDocumentReceiver aRecv); };
--- a/dom/webidl/XMLSerializer.webidl +++ b/dom/webidl/XMLSerializer.webidl @@ -5,16 +5,34 @@ * The origin of this IDL file is * http://domparsing.spec.whatwg.org/#the-xmlserializer-interface */ interface OutputStream; [Constructor] interface XMLSerializer { + /** + * The subtree rooted by the specified element is serialized to + * a string. + * + * @param root The root of the subtree to be serialized. This could + * be any node, including a Document. + * @returns The serialized subtree in the form of a Unicode string + */ [Throws] DOMString serializeToString(Node root); // Mozilla-specific stuff + /** + * The subtree rooted by the specified element is serialized to + * a byte stream using the character set specified. + * @param root The root of the subtree to be serialized. This could + * be any node, including a Document. + * @param stream The byte stream to which the subtree is serialized. + * @param charset The name of the character set to use for the encoding + * to a byte stream. If this string is empty and root is + * a document, the document's character set will be used. + */ [Throws, ChromeOnly] void serializeToStream(Node root, OutputStream stream, DOMString? charset); };
--- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -50,17 +50,16 @@ #include "nsIOutputStream.h" #include "nsISupportsPrimitives.h" #include "nsISupportsPriority.h" #include "nsIInterfaceRequestorUtils.h" #include "nsStreamUtils.h" #include "nsThreadUtils.h" #include "nsIUploadChannel.h" #include "nsIUploadChannel2.h" -#include "nsIDOMSerializer.h" #include "nsXPCOM.h" #include "nsIDOMEventListener.h" #include "nsIScriptSecurityManager.h" #include "nsIVariant.h" #include "nsVariant.h" #include "nsIScriptError.h" #include "nsIStreamConverterService.h" #include "nsICachingChannel.h"
--- a/dom/xml/XMLDocument.cpp +++ b/dom/xml/XMLDocument.cpp @@ -254,19 +254,16 @@ XMLDocument::XMLDocument(const char* aCo } XMLDocument::~XMLDocument() { // XXX We rather crash than hang mLoopingForSyncLoad = false; } -// QueryInterface implementation for XMLDocument -NS_IMPL_ISUPPORTS_INHERITED(XMLDocument, nsDocument, nsIDOMXMLDocument) - nsresult XMLDocument::Init() { nsresult rv = nsDocument::Init(); NS_ENSURE_SUCCESS(rv, rv); return rv; }
--- a/dom/xml/XMLDocument.h +++ b/dom/xml/XMLDocument.h @@ -5,32 +5,30 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_XMLDocument_h #define mozilla_dom_XMLDocument_h #include "mozilla/Attributes.h" #include "mozilla/dom/BindingDeclarations.h" #include "nsDocument.h" -#include "nsIDOMXMLDocument.h" #include "nsIScriptContext.h" class nsIURI; class nsIChannel; namespace mozilla { namespace dom { -class XMLDocument : public nsDocument, - public nsIDOMXMLDocument +class XMLDocument : public nsDocument { public: explicit XMLDocument(const char* aContentType = "application/xml"); - NS_DECL_ISUPPORTS_INHERITED + NS_INLINE_DECL_REFCOUNTING_INHERITED(XMLDocument, nsDocument) virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) override; virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup, nsIPrincipal* aPrincipal) override; virtual void SetSuppressParserErrorElement(bool aSuppress) override; virtual bool SuppressParserErrorElement() override; @@ -41,19 +39,16 @@ public: nsILoadGroup* aLoadGroup, nsISupports* aContainer, nsIStreamListener **aDocListener, bool aReset = true, nsIContentSink* aSink = nullptr) override; virtual void EndLoad() override; - // nsIDOMXMLDocument - NS_DECL_NSIDOMXMLDOCUMENT - virtual nsresult Init() override; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult, bool aPreallocateChildren) const override; virtual void DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const override; // DocAddSizeOfIncludingThis is inherited from nsIDocument.
--- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -26,17 +26,16 @@ #include "XULDocument.h" #include "nsError.h" #include "nsIBoxObject.h" #include "nsIChromeRegistry.h" #include "nsView.h" #include "nsViewManager.h" #include "nsIContentViewer.h" -#include "nsIDOMXULElement.h" #include "nsIStreamListener.h" #include "nsITimer.h" #include "nsDocShell.h" #include "nsGkAtoms.h" #include "nsXMLContentSink.h" #include "nsXULContentSink.h" #include "nsXULContentUtils.h" #include "nsIXULOverlayProvider.h"
--- a/dom/xul/nsXULCommandDispatcher.cpp +++ b/dom/xul/nsXULCommandDispatcher.cpp @@ -11,17 +11,16 @@ */ #include "nsIContent.h" #include "nsFocusManager.h" #include "nsIControllers.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" #include "nsIDOMWindow.h" -#include "nsIDOMXULElement.h" #include "nsIDocument.h" #include "nsPresContext.h" #include "nsIPresShell.h" #include "nsIScriptGlobalObject.h" #include "nsPIDOMWindow.h" #include "nsPIWindowRoot.h" #include "nsRDFCID.h" #include "nsXULCommandDispatcher.h"
--- a/dom/xul/nsXULElement.cpp +++ b/dom/xul/nsXULElement.cpp @@ -10,17 +10,16 @@ #include "nsIDOMEvent.h" #include "nsAtom.h" #include "nsIBaseWindow.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" #include "nsIDOMEventListener.h" #include "nsIDOMNodeList.h" #include "nsIDOMXULCommandDispatcher.h" -#include "nsIDOMXULElement.h" #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsIDocument.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/EventListenerManager.h" #include "mozilla/EventStateManager.h" #include "mozilla/EventStates.h" #include "mozilla/DeclarationBlockInlines.h" @@ -112,17 +111,17 @@ public: explicit nsXULElementTearoff(nsXULElement* aElement) : mElement(aElement) { } NS_FORWARD_NSIFRAMELOADEROWNER(static_cast<nsXULElement*>(mElement.get())->) private: - nsCOMPtr<nsIDOMXULElement> mElement; + RefPtr<nsXULElement> mElement; }; NS_IMPL_CYCLE_COLLECTION(nsXULElementTearoff, mElement) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULElementTearoff) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULElementTearoff) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULElementTearoff) @@ -290,18 +289,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN // Why aren't we unlinking the prototype? tmp->ClearHasID(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_ADDREF_INHERITED(nsXULElement, nsStyledElement) NS_IMPL_RELEASE_INHERITED(nsXULElement, nsStyledElement) NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULElement) - NS_INTERFACE_TABLE_INHERITED(nsXULElement, nsIDOMNode, nsIDOMElement, - nsIDOMXULElement) + NS_INTERFACE_TABLE_INHERITED(nsXULElement, nsIDOMNode, nsIDOMElement) NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIFrameLoaderOwner, new nsXULElementTearoff(this)) NS_INTERFACE_MAP_END_INHERITING(nsStyledElement) //---------------------------------------------------------------------- // nsIDOMNode interface @@ -1526,17 +1524,17 @@ void nsXULElement::SwapFrameLoaders(HTMLIFrameElement& aOtherLoaderOwner, ErrorResult& rv) { if (!GetExistingDOMSlots()) { rv.Throw(NS_ERROR_NOT_IMPLEMENTED); return; } - nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(static_cast<nsIDOMXULElement*>(this)); + nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(ToSupports(this)); aOtherLoaderOwner.SwapFrameLoaders(flo, rv); } void nsXULElement::SwapFrameLoaders(nsXULElement& aOtherLoaderOwner, ErrorResult& rv) { if (&aOtherLoaderOwner == this) { @@ -1544,17 +1542,17 @@ nsXULElement::SwapFrameLoaders(nsXULElem return; } if (!GetExistingDOMSlots()) { rv.Throw(NS_ERROR_NOT_IMPLEMENTED); return; } - nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(static_cast<nsIDOMXULElement*>(this)); + nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(ToSupports(this)); aOtherLoaderOwner.SwapFrameLoaders(flo, rv); } void nsXULElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoaderOwner, mozilla::ErrorResult& rv) { if (!GetExistingDOMSlots()) { @@ -1564,17 +1562,17 @@ nsXULElement::SwapFrameLoaders(nsIFrameL RefPtr<nsFrameLoader> loader = GetFrameLoader(); RefPtr<nsFrameLoader> otherLoader = aOtherLoaderOwner->GetFrameLoader(); if (!loader || !otherLoader) { rv.Throw(NS_ERROR_NOT_IMPLEMENTED); return; } - nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(static_cast<nsIDOMXULElement*>(this)); + nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(ToSupports(this)); rv = loader->SwapWithOtherLoader(otherLoader, flo, aOtherLoaderOwner); } NS_IMETHODIMP nsXULElement::GetParentTree(nsIDOMXULMultiSelectControlElement** aTreeElement) { for (nsIContent* current = GetParent(); current; current = current->GetParent()) {
--- a/dom/xul/nsXULElement.h +++ b/dom/xul/nsXULElement.h @@ -15,17 +15,16 @@ #include "js/TracingAPI.h" #include "mozilla/Attributes.h" #include "nsIDOMEvent.h" #include "nsIServiceManager.h" #include "nsAtom.h" #include "mozilla/dom/NodeInfo.h" #include "nsIControllers.h" #include "nsIDOMElement.h" -#include "nsIDOMXULElement.h" #include "nsIDOMXULMultSelectCntrlEl.h" #include "nsIURI.h" #include "nsLayoutCID.h" #include "nsAttrAndChildArray.h" #include "nsGkAtoms.h" #include "nsStringFwd.h" #include "nsStyledElement.h" #include "nsIFrameLoaderOwner.h" @@ -330,17 +329,17 @@ enum { XUL_ELEMENT_HAS_POPUP_LISTENER = XUL_ELEMENT_FLAG_BIT(1) }; ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2); #undef XUL_ELEMENT_FLAG_BIT class nsXULElement final : public nsStyledElement, - public nsIDOMXULElement + public nsIDOMElement { public: using Element::Blur; using Element::Focus; explicit nsXULElement(already_AddRefed<mozilla::dom::NodeInfo> aNodeInfo); static nsresult Create(nsXULPrototypeElement* aPrototype, nsIDocument* aDocument, @@ -383,19 +382,16 @@ public: virtual bool IsNodeOfType(uint32_t aFlags) const override; virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) override; virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute, int32_t aModType) const override; NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override; - // nsIDOMXULElement - NS_DECL_NSIDOMXULELEMENT - virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult, bool aPreallocateChildren) const override; virtual mozilla::EventStates IntrinsicState() const override; void PresetOpenerWindow(mozIDOMWindowProxy* aWindow, ErrorResult& aRv); virtual void RecompileScriptEventListeners() override;
--- a/gfx/layers/LayerAttributes.h +++ b/gfx/layers/LayerAttributes.h @@ -1,202 +1,241 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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_gfx_layers_LayerAttributes_h #define mozilla_gfx_layers_LayerAttributes_h #include "mozilla/Maybe.h" #include "mozilla/gfx/Types.h" #include "mozilla/layers/LayersTypes.h" namespace IPC { template <typename T> struct ParamTraits; } // namespace IPC namespace mozilla { namespace layers { -// Data stored for scroll thumb container layers. -struct ScrollThumbData { - ScrollThumbData() - : mThumbRatio(0.0f) - , mIsAsyncDraggable(false) - {} - ScrollThumbData(ScrollDirection aDirection, - float aThumbRatio, - CSSCoord aThumbStart, - CSSCoord aThumbLength, - bool aIsAsyncDraggable, - CSSCoord aScrollTrackStart, - CSSCoord aScrollTrackLength) +enum class ScrollbarLayerType : uint8_t { None, Thumb, Container }; + +/** + * It stores data for scroll thumb layer or container layers. + */ +struct ScrollbarData { + ScrollbarData() = default; + + ScrollbarData(ScrollDirection aDirection, + ScrollbarLayerType aScrollbarLayerType, + float aThumbRatio, + CSSCoord aThumbStart, + CSSCoord aThumbLength, + bool aThumbIsAsyncDraggable, + CSSCoord aScrollTrackStart, + CSSCoord aScrollTrackLength) : mDirection(Some(aDirection)) + , mScrollbarLayerType(aScrollbarLayerType) , mThumbRatio(aThumbRatio) , mThumbStart(aThumbStart) , mThumbLength(aThumbLength) - , mIsAsyncDraggable(aIsAsyncDraggable) + , mThumbIsAsyncDraggable(aThumbIsAsyncDraggable) , mScrollTrackStart(aScrollTrackStart) , mScrollTrackLength(aScrollTrackLength) {} + /** + * The mDirection contains a direction if mScrollbarLayerType is Thumb + * or Container, otherwise it's empty. + */ Maybe<ScrollDirection> mDirection; - // The scrollbar thumb ratio is the ratio of the thumb position (in the CSS - // pixels of the scrollframe's parent's space) to the scroll position (in the - // CSS pixels of the scrollframe's space). - float mThumbRatio; + + /** + * Indicate what kind of layer this data is for. All possibilities are defined in + * enum ScrollbarLayerType + */ + ScrollbarLayerType mScrollbarLayerType = ScrollbarLayerType::None; + + /** + * The scrollbar thumb ratio is the ratio of the thumb position (in the CSS + * pixels of the scrollframe's parent's space) to the scroll position (in the + * CSS pixels of the scrollframe's space). + */ + float mThumbRatio = 0.0f; + CSSCoord mThumbStart; CSSCoord mThumbLength; - // Whether the scrollbar thumb can be dragged asynchronously. - bool mIsAsyncDraggable; + + /** + * Whether the scrollbar thumb can be dragged asynchronously. + */ + bool mThumbIsAsyncDraggable = false; + CSSCoord mScrollTrackStart; CSSCoord mScrollTrackLength; + uint64_t mTargetViewId = FrameMetrics::NULL_SCROLL_ID; - bool operator==(const ScrollThumbData& aOther) const { + bool operator==(const ScrollbarData& aOther) const { return mDirection == aOther.mDirection && + mScrollbarLayerType == aOther.mScrollbarLayerType && mThumbRatio == aOther.mThumbRatio && mThumbStart == aOther.mThumbStart && mThumbLength == aOther.mThumbLength && - mIsAsyncDraggable == aOther.mIsAsyncDraggable && + mThumbIsAsyncDraggable == aOther.mThumbIsAsyncDraggable && mScrollTrackStart == aOther.mScrollTrackStart && - mScrollTrackLength == aOther.mScrollTrackLength; + mScrollTrackLength == aOther.mScrollTrackLength && + mTargetViewId == aOther.mTargetViewId; } - bool operator!=(const ScrollThumbData& aOther) const { + bool operator!=(const ScrollbarData& aOther) const { return !(*this == aOther); } }; -// Infrequently changing layer attributes that require no special -// serialization work. +/** + * Infrequently changing layer attributes that require no special + * serialization work. + */ class SimpleLayerAttributes final { friend struct IPC::ParamTraits<mozilla::layers::SimpleLayerAttributes>; public: SimpleLayerAttributes() : mTransformIsPerspective(false), mPostXScale(1.0f), mPostYScale(1.0f), mContentFlags(0), mOpacity(1.0f), mIsFixedPosition(false), - mScrollbarTargetContainerId(FrameMetrics::NULL_SCROLL_ID), mMixBlendMode(gfx::CompositionOp::OP_OVER), mForceIsolatedGroup(false) { } - // - // Setters. - // All set methods return true if values changed, false otherwise. - // + /** + * Setters. + * All set methods return true if values changed, false otherwise. + */ bool SetPostScale(float aXScale, float aYScale) { if (mPostXScale == aXScale && mPostYScale == aYScale) { return false; } mPostXScale = aXScale; mPostYScale = aYScale; return true; } + bool SetContentFlags(uint32_t aFlags) { if (aFlags == mContentFlags) { return false; } mContentFlags = aFlags; return true; } + bool SetOpacity(float aOpacity) { if (aOpacity == mOpacity) { return false; } mOpacity = aOpacity; return true; } + bool SetIsFixedPosition(bool aFixedPosition) { if (mIsFixedPosition == aFixedPosition) { return false; } mIsFixedPosition = aFixedPosition; return true; } - bool SetScrollThumbData(FrameMetrics::ViewID aScrollId, const ScrollThumbData& aThumbData) { - if (mScrollbarTargetContainerId == aScrollId && - mThumbData == aThumbData) + + bool SetScrollbarData(const ScrollbarData& aScrollbarData) { + if (mScrollbarData == aScrollbarData) { return false; } - mScrollbarTargetContainerId = aScrollId; - mThumbData = aThumbData; + mScrollbarData = aScrollbarData; return true; } - bool SetScrollbarContainer(FrameMetrics::ViewID aScrollId, + + bool SetScrollbarContainer(FrameMetrics::ViewID aTargetViewId, ScrollDirection aDirection) { - if (mScrollbarContainerDirection && - *mScrollbarContainerDirection == aDirection && - mScrollbarTargetContainerId == aScrollId) { + if (mScrollbarData.mScrollbarLayerType == ScrollbarLayerType::Container && + mScrollbarData.mDirection && + *mScrollbarData.mDirection == aDirection && + mScrollbarData.mTargetViewId == aTargetViewId) { return false; } - mScrollbarContainerDirection = Some(aDirection); - mScrollbarTargetContainerId = aScrollId; + mScrollbarData.mDirection = Some(aDirection); + mScrollbarData.mTargetViewId = aTargetViewId; + mScrollbarData.mScrollbarLayerType = ScrollbarLayerType::Container; return true; } + bool SetMixBlendMode(gfx::CompositionOp aMixBlendMode) { if (mMixBlendMode == aMixBlendMode) { return false; } mMixBlendMode = aMixBlendMode; return true; } + bool SetForceIsolatedGroup(bool aForceIsolatedGroup) { if (mForceIsolatedGroup == aForceIsolatedGroup) { return false; } mForceIsolatedGroup = aForceIsolatedGroup; return true; } + bool SetTransform(const gfx::Matrix4x4& aMatrix) { if (mTransform == aMatrix) { return false; } mTransform = aMatrix; return true; } + bool SetTransformIsPerspective(bool aIsPerspective) { if (mTransformIsPerspective == aIsPerspective) { return false; } mTransformIsPerspective = aIsPerspective; return true; } + bool SetScrolledClip(const Maybe<LayerClip>& aScrolledClip) { if (mScrolledClip == aScrolledClip) { return false; } mScrolledClip = aScrolledClip; return true; } - bool SetFixedPositionData(FrameMetrics::ViewID aScrollId, + + bool SetFixedPositionData(FrameMetrics::ViewID aTargetViewId, const LayerPoint& aAnchor, int32_t aSides) { if (mFixedPositionData && - mFixedPositionData->mScrollId == aScrollId && + mFixedPositionData->mScrollId == aTargetViewId && mFixedPositionData->mAnchor == aAnchor && mFixedPositionData->mSides == aSides) { return false; } if (!mFixedPositionData) { mFixedPositionData.emplace(); } - mFixedPositionData->mScrollId = aScrollId; + mFixedPositionData->mScrollId = aTargetViewId; mFixedPositionData->mAnchor = aAnchor; mFixedPositionData->mSides = aSides; return true; } + bool SetStickyPositionData(FrameMetrics::ViewID aScrollId, LayerRectAbsolute aOuter, LayerRectAbsolute aInner) { if (mStickyPositionData && mStickyPositionData->mOuter.IsEqualEdges(aOuter) && mStickyPositionData->mInner.IsEqualEdges(aInner)) { return false; } @@ -204,132 +243,145 @@ public: mStickyPositionData.emplace(); } mStickyPositionData->mScrollId = aScrollId; mStickyPositionData->mOuter = aOuter; mStickyPositionData->mInner = aInner; return true; } - // This returns true if scrolling info is equivalent for the purposes of - // APZ hit testing. + /** + * This returns true if scrolling info is equivalent for the purposes of + * APZ hit testing. + */ bool HitTestingInfoIsEqual(const SimpleLayerAttributes& aOther) const { - if (mScrollbarContainerDirection != aOther.mScrollbarContainerDirection) { + if (mScrollbarData != aOther.mScrollbarData) { return false; } - if (mScrollbarTargetContainerId != aOther.mScrollbarTargetContainerId) { - return false; - } - if (mThumbData != aOther.mThumbData) { - return false; - } - if (FixedPositionScrollContainerId() != aOther.FixedPositionScrollContainerId()) { + if (GetFixedPositionScrollContainerId() != aOther.GetFixedPositionScrollContainerId()) { return false; } if (mTransform != aOther.mTransform) { return false; } return true; } - // - // Getters. - // + /** + * Getters. + */ - float PostXScale() const { + float GetPostXScale() const { return mPostXScale; } - float PostYScale() const { + + float GetPostYScale() const { return mPostYScale; } - uint32_t ContentFlags() const { + + uint32_t GetContentFlags() const { return mContentFlags; } - float Opacity() const { + + float GetOpacity() const { return mOpacity; } + bool IsFixedPosition() const { return mIsFixedPosition; } - FrameMetrics::ViewID ScrollbarTargetContainerId() const { - return mScrollbarTargetContainerId; + + FrameMetrics::ViewID GetScrollbarTargetViewId() const { + return mScrollbarData.mTargetViewId; + } + + const ScrollbarData& GetScrollbarData() const { + return mScrollbarData; } - const ScrollThumbData& ThumbData() const { - return mThumbData; - } + Maybe<ScrollDirection> GetScrollbarContainerDirection() const { - return mScrollbarContainerDirection; + return (mScrollbarData.mScrollbarLayerType == ScrollbarLayerType::Container) + ? mScrollbarData.mDirection + : Nothing(); } - gfx::CompositionOp MixBlendMode() const { + + gfx::CompositionOp GetMixBlendMode() const { return mMixBlendMode; } - bool ForceIsolatedGroup() const { + + bool GetForceIsolatedGroup() const { return mForceIsolatedGroup; } - const gfx::Matrix4x4& Transform() const { + + const gfx::Matrix4x4& GetTransform() const { return mTransform; } - bool TransformIsPerspective() const { + + bool GetTransformIsPerspective() const { return mTransformIsPerspective; } - const Maybe<LayerClip>& ScrolledClip() const { + + const Maybe<LayerClip>& GetScrolledClip() const { return mScrolledClip; } - FrameMetrics::ViewID FixedPositionScrollContainerId() const { + + FrameMetrics::ViewID GetFixedPositionScrollContainerId() const { return mFixedPositionData ? mFixedPositionData->mScrollId : FrameMetrics::NULL_SCROLL_ID; } - LayerPoint FixedPositionAnchor() const { + + LayerPoint GetFixedPositionAnchor() const { return mFixedPositionData ? mFixedPositionData->mAnchor : LayerPoint(); } - int32_t FixedPositionSides() const { + + int32_t GetFixedPositionSides() const { return mFixedPositionData ? mFixedPositionData->mSides : eSideBitsNone; } + bool IsStickyPosition() const { return !!mStickyPositionData; } - FrameMetrics::ViewID StickyScrollContainerId() const { + + FrameMetrics::ViewID GetStickyScrollContainerId() const { return mStickyPositionData->mScrollId; } - const LayerRectAbsolute& StickyScrollRangeOuter() const { + + const LayerRectAbsolute& GetStickyScrollRangeOuter() const { return mStickyPositionData->mOuter; } - const LayerRectAbsolute& StickyScrollRangeInner() const { + + const LayerRectAbsolute& GetStickyScrollRangeInner() const { return mStickyPositionData->mInner; } bool operator ==(const SimpleLayerAttributes& aOther) const { return mTransform == aOther.mTransform && mTransformIsPerspective == aOther.mTransformIsPerspective && mScrolledClip == aOther.mScrolledClip && mPostXScale == aOther.mPostXScale && mPostYScale == aOther.mPostYScale && mContentFlags == aOther.mContentFlags && mOpacity == aOther.mOpacity && mIsFixedPosition == aOther.mIsFixedPosition && - mScrollbarTargetContainerId == aOther.mScrollbarTargetContainerId && - mThumbData == aOther.mThumbData && - mScrollbarContainerDirection == aOther.mScrollbarContainerDirection && + mScrollbarData == aOther.mScrollbarData && mMixBlendMode == aOther.mMixBlendMode && mForceIsolatedGroup == aOther.mForceIsolatedGroup; } private: gfx::Matrix4x4 mTransform; bool mTransformIsPerspective; Maybe<LayerClip> mScrolledClip; float mPostXScale; float mPostYScale; uint32_t mContentFlags; float mOpacity; bool mIsFixedPosition; - uint64_t mScrollbarTargetContainerId; - ScrollThumbData mThumbData; - Maybe<ScrollDirection> mScrollbarContainerDirection; + ScrollbarData mScrollbarData; gfx::CompositionOp mMixBlendMode; bool mForceIsolatedGroup; struct FixedPositionData { FrameMetrics::ViewID mScrollId; LayerPoint mAnchor; int32_t mSides; }; @@ -337,16 +389,18 @@ private: struct StickyPositionData { FrameMetrics::ViewID mScrollId; LayerRectAbsolute mOuter; LayerRectAbsolute mInner; }; Maybe<StickyPositionData> mStickyPositionData; - // This class may only contain plain-old-data members that can be safely - // copied over IPC. Make sure to add new members to operator ==. + /** + * This class may only contain plain-old-data members that can be safely + * copied over IPC. Make sure to add new members to operator ==. + */ }; } // namespace layers } // namespace mozilla #endif // mozilla_gfx_layers_LayerAttributes_h
--- a/gfx/layers/LayerMetricsWrapper.h +++ b/gfx/layers/LayerMetricsWrapper.h @@ -405,37 +405,37 @@ public: MOZ_ASSERT(IsValid()); if (mLayer->AsRefLayer()) { return mLayer->AsRefLayer()->GetEventRegionsOverride(); } return EventRegionsOverride::NoOverride; } - const ScrollThumbData& GetScrollThumbData() const + const ScrollbarData& GetScrollbarData() const { MOZ_ASSERT(IsValid()); - return mLayer->GetScrollThumbData(); + return mLayer->GetScrollbarData(); } uint64_t GetScrollbarAnimationId() const { MOZ_ASSERT(IsValid()); // This function is only really needed for template-compatibility with // WebRenderScrollDataWrapper. Although it will be called, the return // value is not used. return 0; } FrameMetrics::ViewID GetScrollbarTargetContainerId() const { MOZ_ASSERT(IsValid()); - return mLayer->GetScrollbarTargetContainerId(); + return mLayer->GetScrollbarTargetViewId(); } Maybe<ScrollDirection> GetScrollbarContainerDirection() const { MOZ_ASSERT(IsValid()); return mLayer->GetScrollbarContainerDirection(); }
--- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -544,17 +544,17 @@ Layer::CalculateScissorRect(const Render scissor.MoveBy(-container->GetIntermediateSurfaceRect().TopLeft()); } return currentClip.Intersect(scissor); } Maybe<ParentLayerIntRect> Layer::GetScrolledClipRect() const { - const Maybe<LayerClip> clip = mSimpleAttrs.ScrolledClip(); + const Maybe<LayerClip> clip = mSimpleAttrs.GetScrolledClip(); return clip ? Some(clip->GetClipRect()) : Nothing(); } const ScrollMetadata& Layer::GetScrollMetadata(uint32_t aIndex) const { MOZ_ASSERT(aIndex < GetScrollMetadataCount()); return mScrollMetadata[aIndex]; @@ -584,17 +584,17 @@ Layer::IsScrollableWithoutContent() cons return AsContainerLayer() && HasScrollableFrameMetrics() && !GetFirstChild(); } Matrix4x4 Layer::GetTransform() const { - Matrix4x4 transform = mSimpleAttrs.Transform(); + Matrix4x4 transform = mSimpleAttrs.GetTransform(); transform.PostScale(GetPostXScale(), GetPostYScale(), 1.0f); if (const ContainerLayer* c = AsContainerLayer()) { transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f); } return transform; } const CSSTransformMatrix @@ -628,17 +628,17 @@ bool Layer::HasTransformAnimation() const { return mAnimationInfo.HasTransformAnimation(); } void Layer::ApplyPendingUpdatesForThisTransaction() { - if (mPendingTransform && *mPendingTransform != mSimpleAttrs.Transform()) { + if (mPendingTransform && *mPendingTransform != mSimpleAttrs.GetTransform()) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this)); mSimpleAttrs.SetTransform(*mPendingTransform); MutatedSimple(); } mPendingTransform = nullptr; if (mAnimationInfo.ApplyPendingUpdatesForThisTransaction()) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this)); @@ -653,17 +653,17 @@ Layer::ApplyPendingUpdatesForThisTransac Mutated(); } } } float Layer::GetLocalOpacity() { - float opacity = mSimpleAttrs.Opacity(); + float opacity = mSimpleAttrs.GetOpacity(); if (HostLayer* shadow = AsHostLayer()) opacity = shadow->GetShadowOpacity(); return std::min(std::max(opacity, 0.0f), 1.0f); } float Layer::GetEffectiveOpacity() { @@ -673,25 +673,25 @@ Layer::GetEffectiveOpacity() opacity *= c->GetLocalOpacity(); } return opacity; } CompositionOp Layer::GetEffectiveMixBlendMode() { - if (mSimpleAttrs.MixBlendMode() != CompositionOp::OP_OVER) - return mSimpleAttrs.MixBlendMode(); + if (mSimpleAttrs.GetMixBlendMode() != CompositionOp::OP_OVER) + return mSimpleAttrs.GetMixBlendMode(); for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface(); c = c->GetParent()) { - if(c->mSimpleAttrs.MixBlendMode() != CompositionOp::OP_OVER) - return c->mSimpleAttrs.MixBlendMode(); + if(c->mSimpleAttrs.GetMixBlendMode() != CompositionOp::OP_OVER) + return c->mSimpleAttrs.GetMixBlendMode(); } - return mSimpleAttrs.MixBlendMode(); + return mSimpleAttrs.GetMixBlendMode(); } Matrix4x4 Layer::ComputeTransformToPreserve3DRoot() { Matrix4x4 transform = GetLocalTransform(); for (Layer* layer = GetParent(); layer && layer->Extend3DContext(); @@ -1761,24 +1761,24 @@ Layer::PrintInfo(std::stringstream& aStr aStream << aPrefix; aStream << nsPrintfCString("%s%s (0x%p)", mManager->Name(), Name(), this).get(); layers::PrintInfo(aStream, AsHostLayer()); if (mClipRect) { AppendToString(aStream, *mClipRect, " [clip=", "]"); } - if (mSimpleAttrs.ScrolledClip()) { - AppendToString(aStream, mSimpleAttrs.ScrolledClip()->GetClipRect(), " [scrolled-clip=", "]"); - if (const Maybe<size_t>& ix = mSimpleAttrs.ScrolledClip()->GetMaskLayerIndex()) { + if (mSimpleAttrs.GetScrolledClip()) { + AppendToString(aStream, mSimpleAttrs.GetScrolledClip()->GetClipRect(), " [scrolled-clip=", "]"); + if (const Maybe<size_t>& ix = mSimpleAttrs.GetScrolledClip()->GetMaskLayerIndex()) { AppendToString(aStream, ix.value(), " [scrolled-mask=", "]"); } } - if (1.0 != mSimpleAttrs.PostXScale() || 1.0 != mSimpleAttrs.PostYScale()) { - aStream << nsPrintfCString(" [postScale=%g, %g]", mSimpleAttrs.PostXScale(), mSimpleAttrs.PostYScale()).get(); + if (1.0 != mSimpleAttrs.GetPostXScale() || 1.0 != mSimpleAttrs.GetPostYScale()) { + aStream << nsPrintfCString(" [postScale=%g, %g]", mSimpleAttrs.GetPostXScale(), mSimpleAttrs.GetPostYScale()).get(); } if (!GetBaseTransform().IsIdentity()) { AppendToString(aStream, GetBaseTransform(), " [transform=", "]"); } if (!GetEffectiveTransform().IsIdentity()) { AppendToString(aStream, GetEffectiveTransform(), " [effective-transform=", "]"); } if (GetTransformIsPerspective()) { @@ -1811,22 +1811,22 @@ Layer::PrintInfo(std::stringstream& aStr aStream << " [combines3DTransformWithAncestors]"; } if (Is3DContextLeaf()) { aStream << " [is3DContextLeaf]"; } if (GetScrollbarContainerDirection().isSome()) { aStream << " [scrollbar]"; } - if (Maybe<ScrollDirection> thumbDirection = GetScrollThumbData().mDirection) { + if (Maybe<ScrollDirection> thumbDirection = GetScrollbarData().mDirection) { if (*thumbDirection == ScrollDirection::eVertical) { - aStream << nsPrintfCString(" [vscrollbar=%" PRIu64 "]", GetScrollbarTargetContainerId()).get(); + aStream << nsPrintfCString(" [vscrollbar=%" PRIu64 "]", GetScrollbarTargetViewId()).get(); } if (*thumbDirection == ScrollDirection::eHorizontal) { - aStream << nsPrintfCString(" [hscrollbar=%" PRIu64 "]", GetScrollbarTargetContainerId()).get(); + aStream << nsPrintfCString(" [hscrollbar=%" PRIu64 "]", GetScrollbarTargetViewId()).get(); } } if (GetIsFixedPosition()) { LayerPoint anchor = GetFixedPositionAnchor(); aStream << nsPrintfCString(" [isFixedPosition scrollId=%" PRIu64 " sides=0x%x anchor=%s]", GetFixedPositionScrollContainerId(), GetFixedPositionSides(), ToString(anchor).c_str()).get(); @@ -1962,21 +1962,21 @@ Layer::DumpPacket(layerscope::LayersPack } // Opacity layer->set_opacity(GetOpacity()); // Content opaque layer->set_copaque(static_cast<bool>(GetContentFlags() & CONTENT_OPAQUE)); // Component alpha layer->set_calpha(static_cast<bool>(GetContentFlags() & CONTENT_COMPONENT_ALPHA)); // Vertical or horizontal bar - if (Maybe<ScrollDirection> thumbDirection = GetScrollThumbData().mDirection) { - layer->set_direct(*thumbDirection == ScrollDirection::eVertical ? + if (GetScrollbarData().mScrollbarLayerType == layers::ScrollbarLayerType::Thumb) { + layer->set_direct(*GetScrollbarData().mDirection == ScrollDirection::eVertical ? LayersPacket::Layer::VERTICAL : LayersPacket::Layer::HORIZONTAL); - layer->set_barid(GetScrollbarTargetContainerId()); + layer->set_barid(GetScrollbarTargetViewId()); } // Mask layer if (mMaskLayer) { layer->set_mask(reinterpret_cast<uint64_t>(mMaskLayer.get())); } // DisplayList log.
--- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -1020,17 +1020,17 @@ public: if (mSimpleAttrs.SetForceIsolatedGroup(aForceIsolatedGroup)) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ForceIsolatedGroup", this)); MutatedSimple(); } } bool GetForceIsolatedGroup() const { - return mSimpleAttrs.ForceIsolatedGroup(); + return mSimpleAttrs.GetForceIsolatedGroup(); } /** * CONSTRUCTION PHASE ONLY * Set a clip rect which will be applied to this layer as it is * composited to the destination. The coordinates are relative to * the parent layer (i.e. the contents of this layer * are transformed before this clip rect is applied). @@ -1258,19 +1258,19 @@ public: } /** * CONSTRUCTION PHASE ONLY * If a layer is a scroll thumb container layer, set the scroll identifier * of the scroll frame scrolled by the thumb, and other data related to the * thumb. */ - void SetScrollThumbData(FrameMetrics::ViewID aScrollId, const ScrollThumbData& aThumbData) + void SetScrollbarData(const ScrollbarData& aThumbData) { - if (mSimpleAttrs.SetScrollThumbData(aScrollId, aThumbData)) { + if (mSimpleAttrs.SetScrollbarData(aThumbData)) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrollbarData", this)); MutatedSimple(); } } // Set during construction for the container layer of scrollbar components. // |aScrollId| holds the scroll identifier of the scrollable content that // the scrollbar is for. @@ -1286,22 +1286,22 @@ public: void SetSimpleAttributes(const SimpleLayerAttributes& aAttrs) { mSimpleAttrs = aAttrs; } const SimpleLayerAttributes& GetSimpleAttributes() const { return mSimpleAttrs; } // These getters can be used anytime. - float GetOpacity() { return mSimpleAttrs.Opacity(); } - gfx::CompositionOp GetMixBlendMode() const { return mSimpleAttrs.MixBlendMode(); } + float GetOpacity() { return mSimpleAttrs.GetOpacity(); } + gfx::CompositionOp GetMixBlendMode() const { return mSimpleAttrs.GetMixBlendMode(); } const Maybe<ParentLayerIntRect>& GetClipRect() const { return mClipRect; } - const Maybe<LayerClip>& GetScrolledClip() const { return mSimpleAttrs.ScrolledClip(); } + const Maybe<LayerClip>& GetScrolledClip() const { return mSimpleAttrs.GetScrolledClip(); } Maybe<ParentLayerIntRect> GetScrolledClipRect() const; - uint32_t GetContentFlags() { return mSimpleAttrs.ContentFlags(); } + uint32_t GetContentFlags() { return mSimpleAttrs.GetContentFlags(); } const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; } const ScrollMetadata& GetScrollMetadata(uint32_t aIndex) const; const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const; uint32_t GetScrollMetadataCount() const { return mScrollMetadata.Length(); } const nsTArray<ScrollMetadata>& GetAllScrollMetadata() { return mScrollMetadata; } bool HasScrollableFrameMetrics() const; bool IsScrollableWithoutContent() const; const EventRegions& GetEventRegions() const { return mEventRegions; } @@ -1321,31 +1321,31 @@ public: Layer* GetPrevSibling() { return mPrevSibling; } const Layer* GetPrevSibling() const { return mPrevSibling; } virtual Layer* GetFirstChild() const { return nullptr; } virtual Layer* GetLastChild() const { return nullptr; } gfx::Matrix4x4 GetTransform() const; // Same as GetTransform(), but returns the transform as a strongly-typed // matrix. Eventually this will replace GetTransform(). const CSSTransformMatrix GetTransformTyped() const; - const gfx::Matrix4x4& GetBaseTransform() const { return mSimpleAttrs.Transform(); } + const gfx::Matrix4x4& GetBaseTransform() const { return mSimpleAttrs.GetTransform(); } // Note: these are virtual because ContainerLayerComposite overrides them. - virtual float GetPostXScale() const { return mSimpleAttrs.PostXScale(); } - virtual float GetPostYScale() const { return mSimpleAttrs.PostYScale(); } + virtual float GetPostXScale() const { return mSimpleAttrs.GetPostXScale(); } + virtual float GetPostYScale() const { return mSimpleAttrs.GetPostYScale(); } bool GetIsFixedPosition() { return mSimpleAttrs.IsFixedPosition(); } - bool GetTransformIsPerspective() const { return mSimpleAttrs.TransformIsPerspective(); } + bool GetTransformIsPerspective() const { return mSimpleAttrs.GetTransformIsPerspective(); } bool GetIsStickyPosition() { return mSimpleAttrs.IsStickyPosition(); } - FrameMetrics::ViewID GetFixedPositionScrollContainerId() { return mSimpleAttrs.FixedPositionScrollContainerId(); } - LayerPoint GetFixedPositionAnchor() { return mSimpleAttrs.FixedPositionAnchor(); } - int32_t GetFixedPositionSides() { return mSimpleAttrs.FixedPositionSides(); } - FrameMetrics::ViewID GetStickyScrollContainerId() { return mSimpleAttrs.StickyScrollContainerId(); } - const LayerRectAbsolute& GetStickyScrollRangeOuter() { return mSimpleAttrs.StickyScrollRangeOuter(); } - const LayerRectAbsolute& GetStickyScrollRangeInner() { return mSimpleAttrs.StickyScrollRangeInner(); } - FrameMetrics::ViewID GetScrollbarTargetContainerId() { return mSimpleAttrs.ScrollbarTargetContainerId(); } - const ScrollThumbData& GetScrollThumbData() const { return mSimpleAttrs.ThumbData(); } + FrameMetrics::ViewID GetFixedPositionScrollContainerId() { return mSimpleAttrs.GetFixedPositionScrollContainerId(); } + LayerPoint GetFixedPositionAnchor() { return mSimpleAttrs.GetFixedPositionAnchor(); } + int32_t GetFixedPositionSides() { return mSimpleAttrs.GetFixedPositionSides(); } + FrameMetrics::ViewID GetStickyScrollContainerId() { return mSimpleAttrs.GetStickyScrollContainerId(); } + const LayerRectAbsolute& GetStickyScrollRangeOuter() { return mSimpleAttrs.GetStickyScrollRangeOuter(); } + const LayerRectAbsolute& GetStickyScrollRangeInner() { return mSimpleAttrs.GetStickyScrollRangeInner(); } + FrameMetrics::ViewID GetScrollbarTargetViewId() { return mSimpleAttrs.GetScrollbarTargetViewId(); } + const ScrollbarData& GetScrollbarData() const { return mSimpleAttrs.GetScrollbarData(); } bool IsScrollbarContainer() { return mSimpleAttrs.GetScrollbarContainerDirection().isSome(); } Maybe<ScrollDirection> GetScrollbarContainerDirection() { return mSimpleAttrs.GetScrollbarContainerDirection(); } Layer* GetMaskLayer() const { return mMaskLayer; } bool HasPendingTransform() const { return mPendingTransform; } void CheckCanary() const { mCanary.Check(); } // Ancestor mask layers are associated with FrameMetrics, but for simplicity
--- a/gfx/layers/apz/public/APZSampler.h +++ b/gfx/layers/apz/public/APZSampler.h @@ -19,17 +19,17 @@ namespace wr { class TransactionBuilder; struct WrTransformProperty; } // namespace wr namespace layers { class APZCTreeManager; class LayerMetricsWrapper; -struct ScrollThumbData; +struct ScrollbarData; /** * This interface exposes APZ methods related to "sampling" (i.e. reading the * async transforms produced by APZ). These methods should all be called on * the sampler thread. */ class APZSampler { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZSampler) @@ -53,17 +53,17 @@ public: * |aContent| instead of |aApzc| and |aMetrics|; aContent is the * LayerMetricsWrapper corresponding to the scroll frame that is scrolled by * the scroll thumb, and so the APZC and metrics can be obtained from * |aContent|. */ LayerToParentLayerMatrix4x4 ComputeTransformForScrollThumb( const LayerToParentLayerMatrix4x4& aCurrentTransform, const LayerMetricsWrapper& aContent, - const ScrollThumbData& aThumbData, + const ScrollbarData& aThumbData, bool aScrollbarIsDescendant, AsyncTransformComponentMatrix* aOutClipTransform); ParentLayerPoint GetCurrentAsyncScrollOffset(const LayerMetricsWrapper& aLayer); AsyncTransform GetCurrentAsyncTransform(const LayerMetricsWrapper& aLayer); AsyncTransformComponentMatrix GetOverscrollTransform(const LayerMetricsWrapper& aLayer); AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll(const LayerMetricsWrapper& aLayer);
--- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -629,17 +629,17 @@ APZCTreeManager::PushStateToWR(wr::Trans MOZ_ASSERT(scrollTargetApzc); LayerToParentLayerMatrix4x4 transform = scrollTargetApzc->CallWithLastContentPaintMetrics( [&](const FrameMetrics& aMetrics) { return ComputeTransformForScrollThumb( aNode->GetTransform() * AsyncTransformMatrix(), scrollTargetNode->GetTransform().ToUnknownMatrix(), scrollTargetApzc, aMetrics, - aNode->GetScrollThumbData(), + aNode->GetScrollbarData(), scrollTargetNode->IsAncestorOf(aNode), nullptr); }); aTransformArray.AppendElement(wr::ToWrTransformProperty( aNode->GetScrollbarAnimationId(), transform)); }); @@ -860,18 +860,17 @@ APZCTreeManager::PrepareNodeForLayer(con aLayer.GetTransformTyped(), (!parentHasPerspective && aLayer.GetClipRect()) ? Some(ParentLayerIntRegion(*aLayer.GetClipRect())) : Nothing(), GetEventRegionsOverride(aParent, aLayer), aLayer.IsBackfaceHidden()); node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(), aLayer.GetScrollbarAnimationId(), - aLayer.GetScrollThumbData(), - aLayer.GetScrollbarContainerDirection()); + aLayer.GetScrollbarData()); node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId()); return node; } AsyncPanZoomController* apzc = nullptr; // If we get here, aLayer is a scrollable layer and somebody // has registered a GeckoContentController for it, so we need to ensure // it has an APZC instance to manage its scrolling. @@ -1081,18 +1080,17 @@ APZCTreeManager::PrepareNodeForLayer(con aLayer.IsBackfaceHidden()); } // Note: if layer properties must be propagated to nodes, RecvUpdate in // LayerTransactionParent.cpp must ensure that APZ will be notified // when those properties change. node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(), aLayer.GetScrollbarAnimationId(), - aLayer.GetScrollThumbData(), - aLayer.GetScrollbarContainerDirection()); + aLayer.GetScrollbarData()); node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId()); return node; } template<typename PanGestureOrScrollWheelInput> static bool WillHandleInput(const PanGestureOrScrollWheelInput& aPanInput) { @@ -1208,17 +1206,17 @@ APZCTreeManager::ReceiveInputEvent(Input confFlags.mTargetConfirmed = false; } result = mInputQueue->ReceiveInputEvent( apzc, confFlags, mouseInput, aOutInputBlockId); // If we're starting an async scrollbar drag if (apzDragEnabled && startsDrag && hitScrollbarNode && hitScrollbarNode->IsScrollThumbNode() && - hitScrollbarNode->GetScrollThumbData().mIsAsyncDraggable) { + hitScrollbarNode->GetScrollbarData().mThumbIsAsyncDraggable) { SetupScrollbarDrag(mouseInput, hitScrollbarNode.get(), apzc.get()); } if (result == nsEventStatus_eConsumeDoDefault) { // This input event is part of a drag block, so whether or not it is // directed at a scrollbar depends on whether the drag block started // on a scrollbar. hitScrollbar = mInputQueue->IsDragOnScrollbar(hitScrollbar); @@ -1588,17 +1586,17 @@ APZCTreeManager::ProcessTouchInput(Multi &mHitResultForInputBlock, &hitScrollbarNode); // Check if this event starts a scrollbar touch-drag. The conditions // checked are similar to the ones we check for MOUSE_INPUT starting // a scrollbar mouse-drag. mInScrollbarTouchDrag = gfxPrefs::APZDragEnabled() && gfxPrefs::APZTouchDragEnabled() && hitScrollbarNode && hitScrollbarNode->IsScrollThumbNode() && - hitScrollbarNode->GetScrollThumbData().mIsAsyncDraggable; + hitScrollbarNode->GetScrollbarData().mThumbIsAsyncDraggable; MOZ_ASSERT(touchBehaviors.Length() == aInput.mTouches.Length()); for (size_t i = 0; i < touchBehaviors.Length(); i++) { APZCTM_LOG("Touch point has allowed behaviours 0x%02x\n", touchBehaviors[i]); if (touchBehaviors[i] == AllowedTouchBehavior::UNKNOWN) { // If there's any unknown items in the list, throw it out and we'll // wait for the main thread to send us a notification. touchBehaviors.Clear(); @@ -1763,17 +1761,17 @@ APZCTreeManager::SetupScrollbarDrag(Mous const HitTestingTreeNode* aScrollThumbNode, AsyncPanZoomController* aApzc) { DragBlockState* dragBlock = mInputQueue->GetCurrentDragBlock(); if (!dragBlock) { return; } - const ScrollThumbData& thumbData = aScrollThumbNode->GetScrollThumbData(); + const ScrollbarData& thumbData = aScrollThumbNode->GetScrollbarData(); MOZ_ASSERT(thumbData.mDirection.isSome()); // Record the thumb's position at the start of the drag. // We snap back to this position if, during the drag, the mouse // gets sufficiently far away from the scrollbar. dragBlock->SetInitialThumbPos(thumbData.mThumbStart); // Under some conditions, we can confirm the drag block right away. @@ -3001,17 +2999,17 @@ APZCTreeManager::ComputeTransformForNode MOZ_ASSERT(scrollTargetApzc); return scrollTargetApzc->CallWithLastContentPaintMetrics( [&](const FrameMetrics& aMetrics) { return ComputeTransformForScrollThumb( aNode->GetTransform() * AsyncTransformMatrix(), scrollTargetNode->GetTransform().ToUnknownMatrix(), scrollTargetApzc, aMetrics, - aNode->GetScrollThumbData(), + aNode->GetScrollbarData(), scrollTargetNode->IsAncestorOf(aNode), nullptr); }); } } // Otherwise, the node does not have an async transform. return aNode->GetTransform() * AsyncTransformMatrix(); } @@ -3055,17 +3053,17 @@ APZCTreeManager::GetAPZTestData(LayersId } /*static*/ LayerToParentLayerMatrix4x4 APZCTreeManager::ComputeTransformForScrollThumb( const LayerToParentLayerMatrix4x4& aCurrentTransform, const Matrix4x4& aScrollableContentTransform, AsyncPanZoomController* aApzc, const FrameMetrics& aMetrics, - const ScrollThumbData& aThumbData, + const ScrollbarData& aScrollbarData, bool aScrollbarIsDescendant, AsyncTransformComponentMatrix* aOutClipTransform) { // We only apply the transform if the scroll-target layer has non-container // children (i.e. when it has some possibly-visible content). This is to // avoid moving scroll-bars in the situation that only a scroll information // layer has been built for a scroll frame, as this would result in a // disparity between scrollbars and visible content. @@ -3078,32 +3076,32 @@ APZCTreeManager::ComputeTransformForScro AsyncTransformComponentMatrix asyncTransform = aApzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing); // |asyncTransform| represents the amount by which we have scrolled and // zoomed since the last paint. Because the scrollbar was sized and positioned based // on the painted content, we need to adjust it based on asyncTransform so that // it reflects what the user is actually seeing now. AsyncTransformComponentMatrix scrollbarTransform; - if (*aThumbData.mDirection == ScrollDirection::eVertical) { + if (*aScrollbarData.mDirection == ScrollDirection::eVertical) { const ParentLayerCoord asyncScrollY = asyncTransform._42; const float asyncZoomY = asyncTransform._22; // The scroll thumb needs to be scaled in the direction of scrolling by the // inverse of the async zoom. This is because zooming in decreases the // fraction of the whole srollable rect that is in view. const float yScale = 1.f / asyncZoomY; // Note: |metrics.GetZoom()| doesn't yet include the async zoom. const CSSToParentLayerScale effectiveZoom(aMetrics.GetZoom().yScale * asyncZoomY); // Here we convert the scrollbar thumb ratio into a true unitless ratio by // dividing out the conversion factor from the scrollframe's parent's space // to the scrollframe's space. - const float ratio = aThumbData.mThumbRatio / + const float ratio = aScrollbarData.mThumbRatio / (aMetrics.GetPresShellResolution() * asyncZoomY); // The scroll thumb needs to be translated in opposite direction of the // async scroll. This is because scrolling down, which translates the layer // content up, should result in moving the scroll thumb down. ParentLayerCoord yTranslation = -asyncScrollY * ratio; // The scroll thumb additionally needs to be translated to compensate for // the scale applied above. The origin with respect to which the scale is @@ -3130,27 +3128,27 @@ APZCTreeManager::ComputeTransformForScro // resolution-cancelling transform which ensures the scroll thumb isn't // actually rendered at a larger scale. yTranslation *= aMetrics.GetPresShellResolution(); } scrollbarTransform.PostScale(1.f, yScale, 1.f); scrollbarTransform.PostTranslate(0, yTranslation, 0); } - if (*aThumbData.mDirection == ScrollDirection::eHorizontal) { + if (*aScrollbarData.mDirection == ScrollDirection::eHorizontal) { // See detailed comments under the VERTICAL case. const ParentLayerCoord asyncScrollX = asyncTransform._41; const float asyncZoomX = asyncTransform._11; const float xScale = 1.f / asyncZoomX; const CSSToParentLayerScale effectiveZoom(aMetrics.GetZoom().xScale * asyncZoomX); - const float ratio = aThumbData.mThumbRatio / + const float ratio = aScrollbarData.mThumbRatio / (aMetrics.GetPresShellResolution() * asyncZoomX); ParentLayerCoord xTranslation = -asyncScrollX * ratio; const CSSCoord thumbOrigin = (aMetrics.GetScrollOffset().x * ratio); const CSSCoord thumbOriginScaled = thumbOrigin * xScale; const CSSCoord thumbOriginDelta = thumbOriginScaled - thumbOrigin; const ParentLayerCoord thumbOriginDeltaPL = thumbOriginDelta * effectiveZoom; xTranslation -= thumbOriginDeltaPL;
--- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -519,17 +519,17 @@ public: * @return The new shadow transform for the scroll thumb layer, including * any pre- or post-scales. */ static LayerToParentLayerMatrix4x4 ComputeTransformForScrollThumb( const LayerToParentLayerMatrix4x4& aCurrentTransform, const gfx::Matrix4x4& aScrollableContentTransform, AsyncPanZoomController* aApzc, const FrameMetrics& aMetrics, - const ScrollThumbData& aThumbData, + const ScrollbarData& aScrollbarData, bool aScrollbarIsDescendant, AsyncTransformComponentMatrix* aOutClipTransform); // Assert that the current thread is the sampler thread for this APZCTM. void AssertOnSamplerThread(); // Assert that the current thread is the updater thread for this APZCTM. void AssertOnUpdaterThread();
--- a/gfx/layers/apz/src/APZSampler.cpp +++ b/gfx/layers/apz/src/APZSampler.cpp @@ -62,17 +62,17 @@ APZSampler::SampleAnimations(const Layer ); return activeAnimations; } LayerToParentLayerMatrix4x4 APZSampler::ComputeTransformForScrollThumb(const LayerToParentLayerMatrix4x4& aCurrentTransform, const LayerMetricsWrapper& aContent, - const ScrollThumbData& aThumbData, + const ScrollbarData& aThumbData, bool aScrollbarIsDescendant, AsyncTransformComponentMatrix* aOutClipTransform) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); AssertOnSamplerThread(); return mApz->ComputeTransformForScrollThumb(aCurrentTransform, aContent.GetTransform(),
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -976,19 +976,20 @@ nsEventStatus AsyncPanZoomController::Ha if (aEvent.mType == MouseInput::MouseType::MOUSE_DOWN) { SetState(SCROLLBAR_DRAG); } if (aEvent.mType != MouseInput::MouseType::MOUSE_MOVE) { return nsEventStatus_eConsumeNoDefault; } - const ScrollThumbData& thumbData = node->GetScrollThumbData(); - MOZ_ASSERT(thumbData.mDirection.isSome()); - ScrollDirection direction = *thumbData.mDirection; + const ScrollbarData& scrollbarData = node->GetScrollbarData(); + MOZ_ASSERT(scrollbarData.mScrollbarLayerType == layers::ScrollbarLayerType::Thumb); + MOZ_ASSERT(scrollbarData.mDirection.isSome()); + ScrollDirection direction = *scrollbarData.mDirection; bool isMouseAwayFromThumb = false; if (int snapMultiplier = gfxPrefs::SliderSnapMultiplier()) { // It's fine to ignore the async component of the thumb's transform, // because any async transform of the thumb will be in the direction of // scrolling, but here we're interested in the other direction. ParentLayerRect thumbRect = (node->GetTransform() * AsyncTransformMatrix()).TransformBounds( @@ -1004,22 +1005,22 @@ nsEventStatus AsyncPanZoomController::Ha } } RecursiveMutexAutoLock lock(mRecursiveMutex); CSSCoord thumbPosition; if (isMouseAwayFromThumb) { thumbPosition = aInitialThumbPos; } else { - thumbPosition = ConvertScrollbarPoint(aEvent.mLocalOrigin, thumbData) - + thumbPosition = ConvertScrollbarPoint(aEvent.mLocalOrigin, scrollbarData) - aDragMetrics.mScrollbarDragOffset; } - CSSCoord maxThumbPos = thumbData.mScrollTrackLength; - maxThumbPos -= thumbData.mThumbLength; + CSSCoord maxThumbPos = scrollbarData.mScrollTrackLength; + maxThumbPos -= scrollbarData.mThumbLength; float scrollPercent = thumbPosition / maxThumbPos; CSSCoord minScrollPosition = GetAxisStart(direction, mFrameMetrics.GetScrollableRect().TopLeft()); CSSCoord maxScrollPosition = GetAxisStart(direction, mFrameMetrics.GetScrollableRect().BottomRight()) - GetAxisLength(direction, mFrameMetrics.CalculateCompositedRectInCssPixels()); @@ -1699,17 +1700,17 @@ AsyncPanZoomController::ConvertToGecko(c PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent)); return true; } return false; } CSSCoord AsyncPanZoomController::ConvertScrollbarPoint(const ParentLayerPoint& aScrollbarPoint, - const ScrollThumbData& aThumbData) const + const ScrollbarData& aThumbData) const { RecursiveMutexAutoLock lock(mRecursiveMutex); // First, get it into the right coordinate space. CSSPoint scrollbarPoint = aScrollbarPoint / mFrameMetrics.GetZoom(); // The scrollbar can be transformed with the frame but the pres shell // resolution is only applied to the scroll frame. scrollbarPoint = scrollbarPoint * mFrameMetrics.GetPresShellResolution();
--- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -498,17 +498,17 @@ public: bool CanScroll(ScrollDirection aDirection) const; /** * Convert a point on the scrollbar from this APZC's ParentLayer coordinates * to CSS coordinates relative to the beginning of the scroll track. * Only the component in the direction of scrolling is returned. */ CSSCoord ConvertScrollbarPoint(const ParentLayerPoint& aScrollbarPoint, - const ScrollThumbData& aThumbData) const; + const ScrollbarData& aThumbData) const; void NotifyMozMouseScrollEvent(const nsString& aString) const; bool OverscrollBehaviorAllowsSwipe() const; protected: // Protected destructor, to discourage deletion outside of Release(): virtual ~AsyncPanZoomController();
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp +++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp @@ -91,71 +91,67 @@ HitTestingTreeNode::SetLastChild(HitTest aChild->SetApzcParent(parent); } } } void HitTestingTreeNode::SetScrollbarData(FrameMetrics::ViewID aScrollViewId, const uint64_t& aScrollbarAnimationId, - const ScrollThumbData& aThumbData, - const Maybe<ScrollDirection>& aScrollContainerDirection) + const ScrollbarData& aScrollbarData) { mScrollViewId = aScrollViewId; mScrollbarAnimationId = aScrollbarAnimationId; - mScrollThumbData = aThumbData; - mScrollbarContainerDirection = aScrollContainerDirection; + mScrollbarData = aScrollbarData; } bool HitTestingTreeNode::MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const { return IsScrollThumbNode() && - mScrollThumbData.mDirection == aDragMetrics.mDirection && + mScrollbarData.mDirection == aDragMetrics.mDirection && mScrollViewId == aDragMetrics.mViewId; } bool HitTestingTreeNode::IsScrollThumbNode() const { - return mScrollThumbData.mDirection.isSome(); + return mScrollbarData.mScrollbarLayerType == layers::ScrollbarLayerType::Thumb; } bool HitTestingTreeNode::IsScrollbarNode() const { - return mScrollbarContainerDirection.isSome() || IsScrollThumbNode(); + return mScrollbarData.mScrollbarLayerType != layers::ScrollbarLayerType::None; } ScrollDirection HitTestingTreeNode::GetScrollbarDirection() const { MOZ_ASSERT(IsScrollbarNode()); - if (mScrollThumbData.mDirection.isSome()) { - return *(mScrollThumbData.mDirection); - } - return *mScrollbarContainerDirection; + MOZ_ASSERT(mScrollbarData.mDirection.isSome()); + return *mScrollbarData.mDirection; } FrameMetrics::ViewID HitTestingTreeNode::GetScrollTargetId() const { return mScrollViewId; } const uint64_t& HitTestingTreeNode::GetScrollbarAnimationId() const { return mScrollbarAnimationId; } -const ScrollThumbData& -HitTestingTreeNode::GetScrollThumbData() const +const ScrollbarData& +HitTestingTreeNode::GetScrollbarData() const { - return mScrollThumbData; + return mScrollbarData; } void HitTestingTreeNode::SetFixedPosData(FrameMetrics::ViewID aFixedPosTarget) { mFixedPosTarget = aFixedPosTarget; } @@ -386,17 +382,17 @@ HitTestingTreeNode::Dump(const char* aPr printf_stderr("%sHitTestingTreeNode (%p) APZC (%p) g=(%s) %s%s%sr=(%s) t=(%s) c=(%s)%s%s\n", aPrefix, this, mApzc.get(), mApzc ? Stringify(mApzc->GetGuid()).c_str() : nsPrintfCString("l=0x%" PRIx64, uint64_t(mLayersId)).get(), (mOverride & EventRegionsOverride::ForceDispatchToContent) ? "fdtc " : "", (mOverride & EventRegionsOverride::ForceEmptyHitRegion) ? "fehr " : "", (mFixedPosTarget != FrameMetrics::NULL_SCROLL_ID) ? nsPrintfCString("fixed=%" PRIu64 " ", mFixedPosTarget).get() : "", Stringify(mEventRegions).c_str(), Stringify(mTransform).c_str(), mClipRegion ? Stringify(mClipRegion.ref()).c_str() : "none", - mScrollbarContainerDirection.isSome() ? " scrollbar" : "", + mScrollbarData.mDirection.isSome() ? " scrollbar" : "", IsScrollThumbNode() ? " scrollthumb" : ""); if (mLastChild) { mLastChild->Dump(nsPrintfCString("%s ", aPrefix).get()); } } void HitTestingTreeNode::SetApzcParent(AsyncPanZoomController* aParent)
--- a/gfx/layers/apz/src/HitTestingTreeNode.h +++ b/gfx/layers/apz/src/HitTestingTreeNode.h @@ -92,25 +92,24 @@ public: const EventRegionsOverride& aOverride, bool aIsBackfaceHidden); bool IsOutsideClip(const ParentLayerPoint& aPoint) const; /* Scrollbar info */ void SetScrollbarData(FrameMetrics::ViewID aScrollViewId, const uint64_t& aScrollbarAnimationId, - const ScrollThumbData& aThumbData, - const Maybe<ScrollDirection>& aScrollContainerDirection); + const ScrollbarData& aScrollbarData); bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const; bool IsScrollbarNode() const; // Scroll thumb or scrollbar container layer. // This can only be called if IsScrollbarNode() is true ScrollDirection GetScrollbarDirection() const; bool IsScrollThumbNode() const; // Scroll thumb container layer. FrameMetrics::ViewID GetScrollTargetId() const; - const ScrollThumbData& GetScrollThumbData() const; + const ScrollbarData& GetScrollbarData() const; const uint64_t& GetScrollbarAnimationId() const; /* Fixed pos info */ void SetFixedPosData(FrameMetrics::ViewID aFixedPosTarget); FrameMetrics::ViewID GetFixedPosTarget() const; /* Convert |aPoint| into the LayerPixel space for the layer corresponding to @@ -145,21 +144,18 @@ private: // represents the scroll id of the scroll frame scrolled by the scrollbar. FrameMetrics::ViewID mScrollViewId; // This is only set to non-zero if WebRender is enabled, and only for HTTNs // where IsScrollThumbNode() returns true. It holds the animation id that we // use to move the thumb node to reflect async scrolling. uint64_t mScrollbarAnimationId; - // This is set for scroll thumb Container layers only. - ScrollThumbData mScrollThumbData; - - // This is set for scroll track Container layers only. - Maybe<ScrollDirection> mScrollbarContainerDirection; + // This is set for scrollbar Container and Thumb layers. + ScrollbarData mScrollbarData; FrameMetrics::ViewID mFixedPosTarget; /* Let {L,M} be the {layer, scrollable metrics} pair that this node * corresponds to in the layer tree. mEventRegions contains the event regions * from L, in the case where event-regions are enabled. If event-regions are * disabled, it will contain the visible region of L, which we use as an * approximation to the hit region for the purposes of obscuring other layers.
--- a/gfx/layers/apz/test/mochitest/test_group_touchevents.html +++ b/gfx/layers/apz/test/mochitest/test_group_touchevents.html @@ -71,17 +71,18 @@ var subtests = [ // For the following tests, we want to make sure APZ doesn't wait for a content // response that is never going to arrive. To detect this we set the content response // timeout to a day, so that the entire test times out and fails if APZ does // end up waiting. {'file': 'helper_tap_passive.html', 'prefs': [["apz.content_response_timeout", 24 * 60 * 60 * 1000], ["apz.test.fails_with_native_injection", isWindows]]}, {'file': 'helper_tap_default_passive.html', 'prefs': [["apz.content_response_timeout", 24 * 60 * 60 * 1000], - ["apz.test.fails_with_native_injection", isWindows]]}, + ["apz.test.fails_with_native_injection", isWindows], + ["dom.event.default_to_passive_touch_listeners", true]]}, // Simple test to exercise touch-action CSS property {'file': 'helper_touch_action.html', 'prefs': touch_action_prefs}, // More complex touch-action tests, with overlapping regions and such {'file': 'helper_touch_action_complex.html', 'prefs': touch_action_prefs}, // Tests that touch-action CSS properties are handled in APZ without waiting // on the main-thread, when possible {'file': 'helper_touch_action_regions.html', 'prefs': touch_action_prefs},
--- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -748,19 +748,19 @@ MoveScrollbarForLayerMargin(Layer* aRoot const ScreenMargin& aFixedLayerMargins) { // See bug 1223928 comment 9 - once we can detect the RCD with just the // isRootContent flag on the metrics, we can probably move this code into // ApplyAsyncTransformToScrollbar rather than having it as a separate // adjustment on the layer tree. Layer* scrollbar = BreadthFirstSearch<ReverseIterator>(aRoot, [aRootScrollId](Layer* aNode) { - return (aNode->GetScrollThumbData().mDirection.isSome() && - *aNode->GetScrollThumbData().mDirection == ScrollDirection::eHorizontal && - aNode->GetScrollbarTargetContainerId() == aRootScrollId); + return (aNode->GetScrollbarData().mDirection.isSome() && + *aNode->GetScrollbarData().mDirection == ScrollDirection::eHorizontal && + aNode->GetScrollbarTargetViewId() == aRootScrollId); }); if (scrollbar) { // Shift the horizontal scrollbar down into the new space exposed by the // dynamic toolbar hiding. Technically we should also scale the vertical // scrollbar a bit to expand into the new space but it's not as noticeable // and it would add a lot more complexity, so we're going with the "it's not // worth it" justification. TranslateShadowLayer(scrollbar, ParentLayerPoint(0, -aFixedLayerMargins.bottom), true, nullptr); @@ -1029,33 +1029,33 @@ AsyncCompositionManager::ApplyAsyncConte maskLayer->GetLocalTransformTyped() * combinedAsyncTransform); } appliedTransform = true; } ExpandRootClipRect(layer, fixedLayerMargins); - if (layer->GetScrollThumbData().mDirection.isSome()) { + if (layer->GetScrollbarData().mScrollbarLayerType == layers::ScrollbarLayerType::Thumb) { ApplyAsyncTransformToScrollbar(layer); } }); return appliedTransform; } static bool LayerIsScrollbarTarget(const LayerMetricsWrapper& aTarget, Layer* aScrollbar) { if (!aTarget.GetApzc()) { return false; } const FrameMetrics& metrics = aTarget.Metrics(); MOZ_ASSERT(metrics.IsScrollable()); - if (metrics.GetScrollId() != aScrollbar->GetScrollbarTargetContainerId()) { + if (metrics.GetScrollId() != aScrollbar->GetScrollbarTargetViewId()) { return false; } return !metrics.IsScrollInfoLayer(); } static void ApplyAsyncTransformToScrollbarForContent(const RefPtr<APZSampler>& aSampler, Layer* aScrollbar, @@ -1064,17 +1064,17 @@ ApplyAsyncTransformToScrollbarForContent { AsyncTransformComponentMatrix clipTransform; MOZ_ASSERT(aSampler); LayerToParentLayerMatrix4x4 transform = aSampler->ComputeTransformForScrollThumb( aScrollbar->GetLocalTransformTyped(), aContent, - aScrollbar->GetScrollThumbData(), + aScrollbar->GetScrollbarData(), aScrollbarIsDescendant, &clipTransform); if (aScrollbarIsDescendant) { // We also need to make a corresponding change on the clip rect of all the // layers on the ancestor chain from the scrollbar layer up to but not // including the layer with the async transform. Otherwise the scrollbar // shifts but gets clipped and so appears to flicker.
--- a/gfx/layers/composite/ContainerLayerComposite.h +++ b/gfx/layers/composite/ContainerLayerComposite.h @@ -103,25 +103,25 @@ public: // If the layer is marked as scale-to-resolution, add a post-scale // to the layer's transform equal to the pres shell resolution we're // scaling to. This cancels out the post scale of '1 / resolution' // added by Layout. TODO: It would be nice to get rid of both of these // post-scales. virtual float GetPostXScale() const override { if (mScaleToResolution) { - return mSimpleAttrs.PostXScale() * mPresShellResolution; + return mSimpleAttrs.GetPostXScale() * mPresShellResolution; } - return mSimpleAttrs.PostXScale(); + return mSimpleAttrs.GetPostXScale(); } virtual float GetPostYScale() const override { if (mScaleToResolution) { - return mSimpleAttrs.PostYScale() * mPresShellResolution; + return mSimpleAttrs.GetPostYScale() * mPresShellResolution; } - return mSimpleAttrs.PostYScale(); + return mSimpleAttrs.GetPostYScale(); } virtual const char* Name() const override { return "ContainerLayerComposite"; } UniquePtr<PreparedData> mPrepared; RefPtr<CompositingRenderTarget> mLastIntermediateSurface; };
--- a/gfx/layers/wr/WebRenderScrollData.h +++ b/gfx/layers/wr/WebRenderScrollData.h @@ -72,18 +72,18 @@ public: EventRegions GetEventRegions() const { return mEventRegions; } void SetEventRegionsOverride(const EventRegionsOverride& aOverride) { mEventRegionsOverride = aOverride; } EventRegionsOverride GetEventRegionsOverride() const { return mEventRegionsOverride; } const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; } void SetReferentId(LayersId aReferentId) { mReferentId = Some(aReferentId); } Maybe<LayersId> GetReferentId() const { return mReferentId; } - void SetScrollThumbData(const ScrollThumbData& aData) { mScrollThumbData = aData; } - const ScrollThumbData& GetScrollThumbData() const { return mScrollThumbData; } + void SetScrollbarData(const ScrollbarData& aData) { mScrollbarData = aData; } + const ScrollbarData& GetScrollbarData() const { return mScrollbarData; } void SetScrollbarAnimationId(const uint64_t& aId) { mScrollbarAnimationId = aId; } const uint64_t& GetScrollbarAnimationId() const { return mScrollbarAnimationId; } void SetScrollbarTargetContainerId(FrameMetrics::ViewID aId) { mScrollbarTargetContainerId = aId; } FrameMetrics::ViewID GetScrollbarTargetContainerId() const { return mScrollbarTargetContainerId; } void SetScrollbarContainerDirection(ScrollDirection aDirection) { mScrollbarContainerDirection = Some(aDirection); } Maybe<ScrollDirection> GetScrollbarContainerDirection() const { return mScrollbarContainerDirection; } void SetFixedPositionScrollContainerId(FrameMetrics::ViewID aId) { mFixedPosScrollContainerId = aId; } @@ -110,17 +110,17 @@ private: // over IPC, and use on the parent side in APZ. gfx::Matrix4x4 mTransform; bool mTransformIsPerspective; EventRegions mEventRegions; LayerIntRegion mVisibleRegion; Maybe<LayersId> mReferentId; EventRegionsOverride mEventRegionsOverride; - ScrollThumbData mScrollThumbData; + ScrollbarData mScrollbarData; uint64_t mScrollbarAnimationId; FrameMetrics::ViewID mScrollbarTargetContainerId; Maybe<ScrollDirection> mScrollbarContainerDirection; FrameMetrics::ViewID mFixedPosScrollContainerId; }; // Data needed by APZ, for the whole layer tree. One instance of this class // is created for each transaction sent over PWebRenderBridge. It is populated @@ -196,25 +196,25 @@ private: uint32_t mPaintSequenceNumber; }; } // namespace layers } // namespace mozilla namespace IPC { -// When ScrollThumbData is stored on the layer tree, it's part of +// When ScrollbarData is stored on the layer tree, it's part of // SimpleAttributes which itself uses PlainOldDataSerializer, so -// we don't need a ParamTraits specialization for ScrollThumbData -// separately. Here, however, ScrollThumbData is stored as part +// we don't need a ParamTraits specialization for ScrollbarData +// separately. Here, however, ScrollbarData is stored as part // of WebRenderLayerScrollData whose fields are serialized // individually, so we do. template<> -struct ParamTraits<mozilla::layers::ScrollThumbData> - : public PlainOldDataSerializer<mozilla::layers::ScrollThumbData> +struct ParamTraits<mozilla::layers::ScrollbarData> + : public PlainOldDataSerializer<mozilla::layers::ScrollbarData> { }; template<> struct ParamTraits<mozilla::layers::WebRenderLayerScrollData> { typedef mozilla::layers::WebRenderLayerScrollData paramType; static void @@ -223,17 +223,17 @@ struct ParamTraits<mozilla::layers::WebR WriteParam(aMsg, aParam.mDescendantCount); WriteParam(aMsg, aParam.mScrollIds); WriteParam(aMsg, aParam.mTransform); WriteParam(aMsg, aParam.mTransformIsPerspective); WriteParam(aMsg, aParam.mEventRegions); WriteParam(aMsg, aParam.mVisibleRegion); WriteParam(aMsg, aParam.mReferentId); WriteParam(aMsg, aParam.mEventRegionsOverride); - WriteParam(aMsg, aParam.mScrollThumbData); + WriteParam(aMsg, aParam.mScrollbarData); WriteParam(aMsg, aParam.mScrollbarAnimationId); WriteParam(aMsg, aParam.mScrollbarTargetContainerId); WriteParam(aMsg, aParam.mScrollbarContainerDirection); WriteParam(aMsg, aParam.mFixedPosScrollContainerId); } static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) @@ -241,17 +241,17 @@ struct ParamTraits<mozilla::layers::WebR return ReadParam(aMsg, aIter, &aResult->mDescendantCount) && ReadParam(aMsg, aIter, &aResult->mScrollIds) && ReadParam(aMsg, aIter, &aResult->mTransform) && ReadParam(aMsg, aIter, &aResult->mTransformIsPerspective) && ReadParam(aMsg, aIter, &aResult->mEventRegions) && ReadParam(aMsg, aIter, &aResult->mVisibleRegion) && ReadParam(aMsg, aIter, &aResult->mReferentId) && ReadParam(aMsg, aIter, &aResult->mEventRegionsOverride) - && ReadParam(aMsg, aIter, &aResult->mScrollThumbData) + && ReadParam(aMsg, aIter, &aResult->mScrollbarData) && ReadParam(aMsg, aIter, &aResult->mScrollbarAnimationId) && ReadParam(aMsg, aIter, &aResult->mScrollbarTargetContainerId) && ReadParam(aMsg, aIter, &aResult->mScrollbarContainerDirection) && ReadParam(aMsg, aIter, &aResult->mFixedPosScrollContainerId); } }; template<>
--- a/gfx/layers/wr/WebRenderScrollDataWrapper.h +++ b/gfx/layers/wr/WebRenderScrollDataWrapper.h @@ -280,20 +280,20 @@ public: } EventRegionsOverride GetEventRegionsOverride() const { MOZ_ASSERT(IsValid()); return mLayer->GetEventRegionsOverride(); } - const ScrollThumbData& GetScrollThumbData() const + const ScrollbarData& GetScrollbarData() const { MOZ_ASSERT(IsValid()); - return mLayer->GetScrollThumbData(); + return mLayer->GetScrollbarData(); } uint64_t GetScrollbarAnimationId() const { MOZ_ASSERT(IsValid()); return mLayer->GetScrollbarAnimationId(); }
--- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -51,16 +51,17 @@ #include "mozilla/dom/FileReaderBinding.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/TextDecoderBinding.h" #include "mozilla/dom/TextEncoderBinding.h" #include "mozilla/dom/UnionConversions.h" #include "mozilla/dom/URLBinding.h" #include "mozilla/dom/URLSearchParamsBinding.h" #include "mozilla/dom/XMLHttpRequest.h" +#include "mozilla/dom/XMLSerializerBinding.h" #include "mozilla/dom/FormDataBinding.h" #include "mozilla/DeferredFinalize.h" using namespace mozilla; using namespace JS; using namespace xpc; using mozilla::dom::DestroyProtoAndIfaceCache; @@ -827,16 +828,18 @@ xpc::GlobalProperties::Parse(JSContext* } else if (!strcmp(name.ptr(), "TextEncoder")) { TextEncoder = true; } else if (!strcmp(name.ptr(), "URL")) { URL = true; } else if (!strcmp(name.ptr(), "URLSearchParams")) { URLSearchParams = true; } else if (!strcmp(name.ptr(), "XMLHttpRequest")) { XMLHttpRequest = true; + } else if (!strcmp(name.ptr(), "XMLSerializer")) { + XMLSerializer = true; } else if (!strcmp(name.ptr(), "atob")) { atob = true; } else if (!strcmp(name.ptr(), "btoa")) { btoa = true; } else if (!strcmp(name.ptr(), "caches")) { caches = true; } else if (!strcmp(name.ptr(), "crypto")) { crypto = true; @@ -920,16 +923,20 @@ xpc::GlobalProperties::Define(JSContext* if (URLSearchParams && !dom::URLSearchParamsBinding::GetConstructorObject(cx)) return false; if (XMLHttpRequest && !dom::XMLHttpRequestBinding::GetConstructorObject(cx)) return false; + if (XMLSerializer && + !dom::XMLSerializerBinding::GetConstructorObject(cx)) + return false; + if (atob && !JS_DefineFunction(cx, obj, "atob", Atob, 1, 0)) return false; if (btoa && !JS_DefineFunction(cx, obj, "btoa", Btoa, 1, 0)) return false;
--- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -2618,16 +2618,17 @@ struct GlobalProperties { bool InspectorUtils : 1; bool MessageChannel: 1; bool NodeFilter : 1; bool TextDecoder : 1; bool TextEncoder : 1; bool URL : 1; bool URLSearchParams : 1; bool XMLHttpRequest : 1; + bool XMLSerializer : 1; // Ad-hoc property names we implement. bool atob : 1; bool btoa : 1; bool caches : 1; bool crypto : 1; bool fetch : 1; bool indexedDB : 1;
new file mode 100644 --- /dev/null +++ b/layout/base/LayoutConstants.h @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +/* constants used throughout the Layout module */ + +#ifndef LayoutConstants_h___ +#define LayoutConstants_h___ + +#include "nsSize.h" // for NS_MAXSIZE + +/** + * Constant used to indicate an unconstrained size. + */ +#define NS_UNCONSTRAINEDSIZE NS_MAXSIZE + +// NOTE: There are assumptions all over that these have the same value, +// namely NS_UNCONSTRAINEDSIZE. +#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE +#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE +#define NS_AUTOOFFSET NS_UNCONSTRAINEDSIZE + +// +1 is to avoid clamped huge margin values being processed as auto margins +#define NS_AUTOMARGIN (NS_UNCONSTRAINEDSIZE + 1) + +#define NS_INTRINSIC_WIDTH_UNKNOWN nscoord_MIN + + +#endif // LayoutConstants_h___
--- a/layout/base/moz.build +++ b/layout/base/moz.build @@ -30,16 +30,17 @@ if CONFIG['MOZ_DEBUG']: 'nsAutoLayoutPhase.cpp', ] XPIDL_MODULE = 'layout_base' EXPORTS += [ 'CaretAssociationHint.h', 'FrameProperties.h', + 'LayoutConstants.h', 'LayoutLogging.h', 'MobileViewportManager.h', 'nsAutoLayoutPhase.h', 'nsBidi.h', 'nsBidiPresUtils.h', 'nsCaret.h', 'nsChangeHint.h', 'nsCompatibility.h',
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -5046,18 +5046,16 @@ GetDefiniteSize(const nsStyleCoord& if (calc->mPercent != 0.0f) { if (aPercentageBasis.isNothing()) { return false; } auto wm = aFrame->GetWritingMode(); nscoord pb = aIsInlineAxis ? aPercentageBasis.value().ISize(wm) : aPercentageBasis.value().BSize(wm); if (pb == NS_UNCONSTRAINEDSIZE) { - // XXXmats given that we're calculating an intrinsic size here, - // maybe we should back-compute the calc-size using AddPercents? return false; } *aResult = std::max(0, calc->mLength + NSToCoordFloorClamped(pb * calc->mPercent)); } else { *aResult = std::max(0, calc->mLength); } return true; @@ -5291,44 +5289,35 @@ AddIntrinsicSizeOffset(gfxContext* aRend const nscoord* aFixedMaxSize, const nsStyleCoord& aStyleMaxSize, uint32_t aFlags, PhysicalAxis aAxis) { nscoord result = aContentSize; nscoord min = aContentMinSize; nscoord coordOutsideSize = 0; - float pctOutsideSize = 0; - float pctTotal = 0.0f; if (!(aFlags & nsLayoutUtils::IGNORE_PADDING)) { coordOutsideSize += aOffsets.hPadding; - pctOutsideSize += aOffsets.hPctPadding; } coordOutsideSize += aOffsets.hBorder; if (aBoxSizing == StyleBoxSizing::Border) { min += coordOutsideSize; result = NSCoordSaturatingAdd(result, coordOutsideSize); - pctTotal += pctOutsideSize; coordOutsideSize = 0; - pctOutsideSize = 0.0f; } coordOutsideSize += aOffsets.hMargin; - pctOutsideSize += aOffsets.hPctMargin; min += coordOutsideSize; result = NSCoordSaturatingAdd(result, coordOutsideSize); - pctTotal += pctOutsideSize; - - const bool shouldAddPercent = aType == nsLayoutUtils::PREF_ISIZE || - (aFlags & nsLayoutUtils::ADD_PERCENTS); + nscoord size; if (aType == nsLayoutUtils::MIN_ISIZE && (((aStyleSize.HasPercent() || aStyleMaxSize.HasPercent()) && aFrame->IsFrameOfType(nsIFrame::eReplacedSizing)) || (aStyleSize.HasPercent() && FormControlShrinksForPercentISize(aFrame)))) { // A percentage width or max-width on replaced elements means they // can shrink to 0. @@ -5336,78 +5325,54 @@ AddIntrinsicSizeOffset(gfxContext* aRend // text inputs. // Note that if this is max-width, this overrides the fixed-width // rule in the next condition. result = 0; // let |min| handle padding/border/margin } else if (GetAbsoluteCoord(aStyleSize, size) || GetIntrinsicCoord(aStyleSize, aRenderingContext, aFrame, PROP_WIDTH, size)) { result = size + coordOutsideSize; - if (shouldAddPercent) { - result = nsLayoutUtils::AddPercents(result, pctOutsideSize); - } - } else { - // NOTE: We could really do a lot better for percents and for some - // cases of calc() containing percent (certainly including any where - // the coefficient on the percent is positive and there are no max() - // expressions). However, doing better for percents wouldn't be - // backwards compatible. - if (shouldAddPercent) { - result = nsLayoutUtils::AddPercents(result, pctTotal); - } } nscoord maxSize = aFixedMaxSize ? *aFixedMaxSize : 0; if (aFixedMaxSize || GetIntrinsicCoord(aStyleMaxSize, aRenderingContext, aFrame, PROP_MAX_WIDTH, maxSize)) { maxSize += coordOutsideSize; - if (shouldAddPercent) { - maxSize = nsLayoutUtils::AddPercents(maxSize, pctOutsideSize); - } if (result > maxSize) { result = maxSize; } } nscoord minSize = aFixedMinSize ? *aFixedMinSize : 0; if (aFixedMinSize || GetIntrinsicCoord(aStyleMinSize, aRenderingContext, aFrame, PROP_MIN_WIDTH, minSize)) { minSize += coordOutsideSize; - if (shouldAddPercent) { - minSize = nsLayoutUtils::AddPercents(minSize, pctOutsideSize); - } if (result < minSize) { result = minSize; } } - if (shouldAddPercent) { - min = nsLayoutUtils::AddPercents(min, pctTotal); - } if (result < min) { result = min; } const nsStyleDisplay* disp = aFrame->StyleDisplay(); if (aFrame->IsThemed(disp)) { LayoutDeviceIntSize devSize; bool canOverride = true; nsPresContext* pc = aFrame->PresContext(); pc->GetTheme()->GetMinimumWidgetSize(pc, aFrame, disp->mAppearance, &devSize, &canOverride); nscoord themeSize = pc->DevPixelsToAppUnits(aAxis == eAxisVertical ? devSize.height : devSize.width); // GetMinimumWidgetSize() returns a border-box width. themeSize += aOffsets.hMargin; - if (shouldAddPercent) { - themeSize = nsLayoutUtils::AddPercents(themeSize, aOffsets.hPctMargin); - } if (themeSize > result || !canOverride) { result = themeSize; } } return result; } static void @@ -5631,19 +5596,29 @@ nsLayoutUtils::IntrinsicForAxis(Physical } if (aFrame->IsTableFrame()) { // Tables can't shrink smaller than their intrinsic minimum width, // no matter what. min = aFrame->GetMinISize(aRenderingContext); } + nscoord pmPercentageBasis = NS_UNCONSTRAINEDSIZE; + if (aPercentageBasis.isSome()) { + // The padding/margin percentage basis is the inline-size in the parent's + // writing-mode. + auto childWM = aFrame->GetWritingMode(); + pmPercentageBasis = + aFrame->GetParent()->GetWritingMode().IsOrthogonalTo(childWM) ? + aPercentageBasis->BSize(childWM) : + aPercentageBasis->ISize(childWM); + } nsIFrame::IntrinsicISizeOffsetData offsets = - MOZ_LIKELY(isInlineAxis) ? aFrame->IntrinsicISizeOffsets() - : aFrame->IntrinsicBSizeOffsets(); + MOZ_LIKELY(isInlineAxis) ? aFrame->IntrinsicISizeOffsets(pmPercentageBasis) + : aFrame->IntrinsicBSizeOffsets(pmPercentageBasis); nscoord contentBoxSize = result; result = AddIntrinsicSizeOffset(aRenderingContext, aFrame, offsets, aType, boxSizing, result, min, styleISize, haveFixedMinISize ? &minISize : nullptr, styleMinISize, haveFixedMaxISize ? &maxISize : nullptr, styleMaxISize, aFlags, aAxis); @@ -5674,37 +5649,36 @@ nsLayoutUtils::IntrinsicForContainer(gfx MOZ_ASSERT(aFrame && aFrame->GetParent()); // We want the size aFrame will contribute to its parent's inline-size. PhysicalAxis axis = aFrame->GetParent()->GetWritingMode().PhysicalAxis(eLogicalAxisInline); return IntrinsicForAxis(axis, aRenderingContext, aFrame, aType, Nothing(), aFlags); } /* static */ nscoord -nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis, - gfxContext* aRC, - nsIFrame* aFrame, - IntrinsicISizeType aType, - uint32_t aFlags) +nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis, + gfxContext* aRC, + nsIFrame* aFrame, + IntrinsicISizeType aType, + const LogicalSize& aPercentageBasis, + uint32_t aFlags) { MOZ_ASSERT(aFrame); MOZ_ASSERT(aFrame->IsFlexOrGridItem(), "only grid/flex items have this behavior currently"); #ifdef DEBUG_INTRINSIC_WIDTH nsFrame::IndentBy(stderr, gNoiseIndent); static_cast<nsFrame*>(aFrame)->ListTag(stderr); printf_stderr(" %s min-isize for %s WM:\n", aType == MIN_ISIZE ? "min" : "pref", aWM.IsVertical() ? "vertical" : "horizontal"); #endif - // Note: this method is only meant for grid/flex items which always - // include percentages in their intrinsic size. - aFlags |= nsLayoutUtils::ADD_PERCENTS; + // Note: this method is only meant for grid/flex items. const nsStylePosition* const stylePos = aFrame->StylePosition(); const nsStyleCoord* style = aAxis == eAxisHorizontal ? &stylePos->mMinWidth : &stylePos->mMinHeight; nscoord minSize; nscoord* fixedMinSize = nullptr; auto minSizeUnit = style->GetUnit(); if (minSizeUnit == eStyleUnit_Auto) { if (aFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE) { @@ -5739,24 +5713,29 @@ nsLayoutUtils::MinSizeContributionForAxi #endif return NS_UNCONSTRAINEDSIZE; } // If aFrame is a container for font size inflation, then shrink // wrapping inside of it should not apply font size inflation. AutoMaybeDisableFontInflation an(aFrame); - PhysicalAxis ourInlineAxis = - aFrame->GetWritingMode().PhysicalAxis(eLogicalAxisInline); + // The padding/margin percentage basis is the inline-size in the parent's + // writing-mode. + auto childWM = aFrame->GetWritingMode(); + nscoord pmPercentageBasis = + aFrame->GetParent()->GetWritingMode().IsOrthogonalTo(childWM) ? + aPercentageBasis.BSize(childWM) : + aPercentageBasis.ISize(childWM); + PhysicalAxis ourInlineAxis = childWM.PhysicalAxis(eLogicalAxisInline); nsIFrame::IntrinsicISizeOffsetData offsets = - ourInlineAxis == aAxis ? aFrame->IntrinsicISizeOffsets() - : aFrame->IntrinsicBSizeOffsets(); + ourInlineAxis == aAxis ? aFrame->IntrinsicISizeOffsets(pmPercentageBasis) + : aFrame->IntrinsicBSizeOffsets(pmPercentageBasis); nscoord result = 0; nscoord min = 0; - const nsStyleCoord& maxISize = aAxis == eAxisHorizontal ? stylePos->mMaxWidth : stylePos->mMaxHeight; result = AddIntrinsicSizeOffset(aRC, aFrame, offsets, aType, stylePos->mBoxSizing, result, min, *style, fixedMinSize, *style, nullptr, maxISize, aFlags, aAxis); #ifdef DEBUG_INTRINSIC_WIDTH @@ -10355,37 +10334,8 @@ nsLayoutUtils::ParseFontLanguageOverride } result = (result << 8) + ch; } while (index++ < 4) { result = (result << 8) + 0x20; } return result; } - -/* static */ nscoord -nsLayoutUtils::ResolveGapToLength(const nsStyleCoord& aCoord, - nscoord aPercentageBasis) -{ - switch (aCoord.GetUnit()) { - case eStyleUnit_Normal: - return nscoord(0); - case eStyleUnit_Coord: - return aCoord.GetCoordValue(); - case eStyleUnit_Percent: - if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) { - return nscoord(0); - } - return NSToCoordFloorClamped(aPercentageBasis * - aCoord.GetPercentValue()); - case eStyleUnit_Calc: { - nsStyleCoord::Calc* calc = aCoord.GetCalcValue(); - if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) { - return std::max(nscoord(0), calc->mLength); - } - return std::max(nscoord(0), calc->mLength + - NSToCoordFloorClamped(aPercentageBasis * calc->mPercent)); - } - default: - MOZ_ASSERT_UNREACHABLE("Unexpected unit!"); - return nscoord(0); - } -}
--- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2,16 +2,17 @@ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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 nsLayoutUtils_h__ #define nsLayoutUtils_h__ +#include "LayoutConstants.h" #include "mozilla/MemoryReporting.h" #include "mozilla/ArrayUtils.h" #include "mozilla/LookAndFeel.h" #include "mozilla/Maybe.h" #include "mozilla/TypedEnumBits.h" #include "nsBoundingMetrics.h" #include "nsChangeHint.h" #include "nsFrameList.h" @@ -170,16 +171,17 @@ public: typedef mozilla::CSSSize CSSSize; typedef mozilla::CSSIntSize CSSIntSize; typedef mozilla::CSSRect CSSRect; typedef mozilla::ScreenMargin ScreenMargin; typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize; typedef mozilla::LayoutDeviceRect LayoutDeviceRect; typedef mozilla::StyleGeometryBox StyleGeometryBox; typedef mozilla::SVGImageContext SVGImageContext; + typedef mozilla::LogicalSize LogicalSize; /** * Finds previously assigned ViewID for the given content element, if any. * Returns whether a ViewID was previously assigned. */ static bool FindIDFor(const nsIContent* aContent, ViewID* aOutViewId); /** @@ -1404,38 +1406,38 @@ public: /** * Get the contribution of aFrame to its containing block's intrinsic * size for the given physical axis. This considers the child's intrinsic * width, its 'width', 'min-width', and 'max-width' properties (or 'height' * variations if that's what matches aAxis) and its padding, border and margin * in the corresponding dimension. * @param aPercentageBasis an optional percentage basis (in aFrame's WM). - * Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes. + * If the basis is indefinite in a given axis, pass a size with + * NS_UNCONSTRAINEDSIZE in that component. * If you pass Nothing() a percentage basis will be calculated from aFrame's * ancestors' computed size in the relevant axis, if needed. * @param aMarginBoxMinSizeClamp make the result fit within this margin-box * size by reducing the *content size* (flooring at zero). This is used for: * https://drafts.csswg.org/css-grid/#min-size-auto */ enum class IntrinsicISizeType { MIN_ISIZE, PREF_ISIZE }; static const auto MIN_ISIZE = IntrinsicISizeType::MIN_ISIZE; static const auto PREF_ISIZE = IntrinsicISizeType::PREF_ISIZE; enum { IGNORE_PADDING = 0x01, BAIL_IF_REFLOW_NEEDED = 0x02, // returns NS_INTRINSIC_WIDTH_UNKNOWN if so MIN_INTRINSIC_ISIZE = 0x04, // use min-width/height instead of width/height - ADD_PERCENTS = 0x08, // apply AddPercents also for MIN_ISIZE }; static nscoord IntrinsicForAxis(mozilla::PhysicalAxis aAxis, gfxContext* aRenderingContext, nsIFrame* aFrame, IntrinsicISizeType aType, - const mozilla::Maybe<mozilla::LogicalSize>& aPercentageBasis = mozilla::Nothing(), + const mozilla::Maybe<LogicalSize>& aPercentageBasis = mozilla::Nothing(), uint32_t aFlags = 0, nscoord aMarginBoxMinSizeClamp = NS_MAXSIZE); /** * Calls IntrinsicForAxis with aFrame's parent's inline physical axis. */ static nscoord IntrinsicForContainer(gfxContext* aRenderingContext, nsIFrame* aFrame, IntrinsicISizeType aType, @@ -1450,41 +1452,28 @@ public: * the "specified size" for: * https://drafts.csswg.org/css-grid/#min-size-auto * Note that the "transferred size" is not handled here; use IntrinsicForAxis. * Note that any percentage in 'width'/'height' makes it count as indefinite. * If the 'min-' property is 'auto' and 'overflow' is not 'visible', then it * calculates the result as if the 'min-' computed value is zero. * Otherwise, return NS_UNCONSTRAINEDSIZE. * + * @param aPercentageBasis the percentage basis (in aFrame's WM). + * Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes. * @note this behavior is specific to Grid/Flexbox (currently) so aFrame * should be a grid/flex item. */ - static nscoord MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis, - gfxContext* aRC, - nsIFrame* aFrame, - IntrinsicISizeType aType, - uint32_t aFlags = 0); - - /** - * This function increases an initial intrinsic size, 'aCurrent', according - * to the given 'aPercent', such that the size-increase makes up exactly - * 'aPercent' percent of the returned value. If 'aPercent' or 'aCurrent' are - * less than or equal to zero the original 'aCurrent' value is returned. - * If 'aPercent' is greater than or equal to 1.0 the value nscoord_MAX is - * returned. - */ - static nscoord AddPercents(nscoord aCurrent, float aPercent) - { - if (aPercent > 0.0f && aCurrent > 0) { - return MOZ_UNLIKELY(aPercent >= 1.0f) ? nscoord_MAX - : NSToCoordRound(float(aCurrent) / (1.0f - aPercent)); - } - return aCurrent; - } + static nscoord + MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis, + gfxContext* aRC, + nsIFrame* aFrame, + IntrinsicISizeType aType, + const LogicalSize& aPercentageBasis, + uint32_t aFlags = 0); /* * Convert nsStyleCoord to nscoord when percentages depend on the * containing block size. * @param aPercentBasis The width or height of the containing block * (whichever the client wants to use for resolving percentages). */ static nscoord ComputeCBDependentValue(nscoord aPercentBasis, @@ -3064,22 +3053,70 @@ public: nsTArray<gfxFontFeature>& aFeatureSettings); static void ComputeFontVariations(const nsCSSValuePairList* aVariationsList, nsTArray<gfxFontVariation>& aVariationSettings); static uint32_t ParseFontLanguageOverride(const nsAString& aLangTag); /** + * Resolve a CSS <length-percentage> value to a definite size. + */ + template<bool clampNegativeResultToZero> + static nscoord ResolveToLength(const nsStyleCoord& aCoord, + nscoord aPercentageBasis) + { + NS_WARNING_ASSERTION(aPercentageBasis >= nscoord(0), "nscoord overflow?"); + + switch (aCoord.GetUnit()) { + case eStyleUnit_Coord: + MOZ_ASSERT(!clampNegativeResultToZero || aCoord.GetCoordValue() >= 0, + "This value should have been rejected by the style system"); + return aCoord.GetCoordValue(); + case eStyleUnit_Percent: + if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) { + return nscoord(0); + } + MOZ_ASSERT(!clampNegativeResultToZero || aCoord.GetPercentValue() >= 0, + "This value should have been rejected by the style system"); + return NSToCoordFloorClamped(aPercentageBasis * + aCoord.GetPercentValue()); + case eStyleUnit_Calc: { + nsStyleCoord::Calc* calc = aCoord.GetCalcValue(); + nscoord result; + if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) { + result = calc->mLength; + } else { + result = calc->mLength + + NSToCoordFloorClamped(aPercentageBasis * calc->mPercent); + } + if (clampNegativeResultToZero && result < 0) { + return nscoord(0); + } + return result; + } + default: + MOZ_ASSERT_UNREACHABLE("Unexpected unit!"); + return nscoord(0); + } + } + + /** * Resolve a column-gap/row-gap to a definite size. * @note This method resolves 'normal' to zero. * Callers who want different behavior should handle 'normal' on their own. */ static nscoord ResolveGapToLength(const nsStyleCoord& aGap, - nscoord aPercentageBasis); + nscoord aPercentageBasis) + { + if (aGap.GetUnit() == eStyleUnit_Normal) { + return nscoord(0); + } + return ResolveToLength<true>(aGap, aPercentageBasis); + } private: static uint32_t sFontSizeInflationEmPerLine; static uint32_t sFontSizeInflationMinTwips; static uint32_t sFontSizeInflationLineThreshold; static int32_t sFontSizeInflationMappingIntercept; static uint32_t sFontSizeInflationMaxRatio; static bool sFontSizeInflationForceEnabled;
--- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -52,17 +52,16 @@ #include "nsIEventListenerService.h" #include "nsIMessageManager.h" // Transformiix stuff #include "mozilla/dom/XPathEvaluator.h" #include "mozilla/dom/DOMParser.h" -#include "nsDOMSerializer.h" // view stuff #include "nsContentCreatorFunctions.h" #include "nsHostObjectURI.h" #include "nsGlobalWindowCommands.h" #include "nsIControllerCommandTable.h" #include "nsJSProtocolHandler.h" @@ -194,17 +193,16 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(HTMLEdito { 0xe1e79dec, 0x4085, 0x4994, { 0xac, 0x5b, 0x74, 0x4b, 0x01, 0x66, 0x97, 0xe6 } } #define PRESENTATION_TCP_SESSION_TRANSPORT_CID \ { 0xc9d023f4, 0x6228, 0x4c07, { 0x8b, 0x1d, 0x9c, 0x19, 0x57, 0x3f, 0xaa, 0x27 } } already_AddRefed<nsIPresentationService> NS_CreatePresentationService(); // Factory Constructor -NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMSerializer) typedef nsHostObjectURI::Mutator nsHostObjectURIMutator; NS_GENERIC_FACTORY_CONSTRUCTOR(nsHostObjectURIMutator) NS_GENERIC_FACTORY_CONSTRUCTOR(DOMParser) NS_GENERIC_FACTORY_CONSTRUCTOR(LocalStorageManager) NS_GENERIC_FACTORY_CONSTRUCTOR(SessionStorageManager) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DOMRequestService, DOMRequestService::FactoryCreate) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(QuotaManagerService, @@ -545,17 +543,16 @@ NS_DEFINE_NAMED_CID(NS_JSPROTOCOLHANDLER NS_DEFINE_NAMED_CID(NS_JSURI_CID); NS_DEFINE_NAMED_CID(NS_JSURIMUTATOR_CID); NS_DEFINE_NAMED_CID(NS_WINDOWCOMMANDTABLE_CID); NS_DEFINE_NAMED_CID(NS_WINDOWCONTROLLER_CID); NS_DEFINE_NAMED_CID(NS_PLUGINDOCLOADERFACTORY_CID); NS_DEFINE_NAMED_CID(NS_PLUGINDOCUMENT_CID); NS_DEFINE_NAMED_CID(NS_VIDEODOCUMENT_CID); NS_DEFINE_NAMED_CID(NS_STYLESHEETSERVICE_CID); -NS_DEFINE_NAMED_CID(NS_XMLSERIALIZER_CID); NS_DEFINE_NAMED_CID(NS_HOSTOBJECTURI_CID); NS_DEFINE_NAMED_CID(NS_HOSTOBJECTURIMUTATOR_CID); NS_DEFINE_NAMED_CID(NS_DOMPARSER_CID); NS_DEFINE_NAMED_CID(NS_DOMSESSIONSTORAGEMANAGER_CID); NS_DEFINE_NAMED_CID(NS_DOMLOCALSTORAGEMANAGER_CID); NS_DEFINE_NAMED_CID(NS_TEXTEDITOR_CID); NS_DEFINE_NAMED_CID(DOMREQUEST_SERVICE_CID); NS_DEFINE_NAMED_CID(QUOTAMANAGER_SERVICE_CID); @@ -788,17 +785,16 @@ static const mozilla::Module::CIDEntry k { &kNS_JSURI_CID, false, nullptr, nsJSURIMutatorConstructor }, // do_CreateInstance returns mutator { &kNS_JSURIMUTATOR_CID, false, nullptr, nsJSURIMutatorConstructor }, { &kNS_WINDOWCOMMANDTABLE_CID, false, nullptr, CreateWindowCommandTableConstructor }, { &kNS_WINDOWCONTROLLER_CID, false, nullptr, CreateWindowControllerWithSingletonCommandTable }, { &kNS_PLUGINDOCLOADERFACTORY_CID, false, nullptr, CreateContentDLF }, { &kNS_PLUGINDOCUMENT_CID, false, nullptr, CreatePluginDocument }, { &kNS_VIDEODOCUMENT_CID, false, nullptr, CreateVideoDocument }, { &kNS_STYLESHEETSERVICE_CID, false, nullptr, nsStyleSheetServiceConstructor }, - { &kNS_XMLSERIALIZER_CID, false, nullptr, nsDOMSerializerConstructor }, { &kNS_HOSTOBJECTURI_CID, false, nullptr, nsHostObjectURIMutatorConstructor }, // do_CreateInstance returns mutator { &kNS_HOSTOBJECTURIMUTATOR_CID, false, nullptr, nsHostObjectURIMutatorConstructor }, { &kNS_DOMPARSER_CID, false, nullptr, DOMParserConstructor }, { &kNS_DOMSESSIONSTORAGEMANAGER_CID, false, nullptr, SessionStorageManagerConstructor }, { &kNS_DOMLOCALSTORAGEMANAGER_CID, false, nullptr, LocalStorageManagerConstructor }, { &kNS_TEXTEDITOR_CID, false, nullptr, TextEditorConstructor }, { &kDOMREQUEST_SERVICE_CID, false, nullptr, DOMRequestServiceConstructor }, { &kQUOTAMANAGER_SERVICE_CID, false, nullptr, QuotaManagerServiceConstructor }, @@ -896,17 +892,16 @@ static const mozilla::Module::ContractID #ifdef MOZ_XUL { "@mozilla.org/xul/xul-sort-service;1", &kNS_XULSORTSERVICE_CID }, #endif { CONTENT_DLF_CONTRACTID, &kNS_CONTENT_DOCUMENT_LOADER_FACTORY_CID }, { NS_JSPROTOCOLHANDLER_CONTRACTID, &kNS_JSPROTOCOLHANDLER_CID }, { NS_WINDOWCONTROLLER_CONTRACTID, &kNS_WINDOWCONTROLLER_CID }, { PLUGIN_DLF_CONTRACTID, &kNS_PLUGINDOCLOADERFACTORY_CID }, { NS_STYLESHEETSERVICE_CONTRACTID, &kNS_STYLESHEETSERVICE_CID }, - { NS_XMLSERIALIZER_CONTRACTID, &kNS_XMLSERIALIZER_CID }, { NS_DOMPARSER_CONTRACTID, &kNS_DOMPARSER_CID }, { "@mozilla.org/dom/localStorage-manager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID }, // Keeping the old ContractID for backward compatibility { "@mozilla.org/dom/storagemanager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID }, { "@mozilla.org/dom/sessionStorage-manager;1", &kNS_DOMSESSIONSTORAGEMANAGER_CID }, { "@mozilla.org/editor/texteditor;1", &kNS_TEXTEDITOR_CID }, { DOMREQUEST_SERVICE_CONTRACTID, &kDOMREQUEST_SERVICE_CID }, { QUOTAMANAGER_SERVICE_CONTRACTID, &kQUOTAMANAGER_SERVICE_CID },
--- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -3378,17 +3378,17 @@ nsIFrame::BuildDisplayListForStackingCon if (clipCapturedBy == ContainerItemType::eOwnLayerForTransformWithRoundedClip) { clipState.Restore(); resultList.AppendToTop( MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, this, &resultList, aBuilder->CurrentActiveScrolledRoot(), nsDisplayOwnLayerFlags::eNone, mozilla::layers::FrameMetrics::NULL_SCROLL_ID, - ScrollThumbData{}, /* aForceActive = */ false)); + ScrollbarData{}, /* aForceActive = */ false)); if (aCreatedContainerItem) { *aCreatedContainerItem = true; } } /* If we have sticky positioning, wrap it in a sticky position item. */ if (useFixedPosition) { @@ -5479,78 +5479,54 @@ nsIFrame::InlinePrefISizeData::ForceBrea mCurrentLine = NSCoordSaturatingSubtract(mCurrentLine, mTrailingWhitespace, nscoord_MAX); mPrevLines = std::max(mPrevLines, mCurrentLine); mCurrentLine = mTrailingWhitespace = 0; mSkipWhitespace = true; mLineIsEmpty = true; } -static void -AddCoord(const nsStyleCoord& aStyle, - nsIFrame* aFrame, - nscoord* aCoord, float* aPercent, - bool aClampNegativeToZero) -{ - switch (aStyle.GetUnit()) { - case eStyleUnit_Coord: { - NS_ASSERTION(!aClampNegativeToZero || aStyle.GetCoordValue() >= 0, - "unexpected negative value"); - *aCoord += aStyle.GetCoordValue(); - return; - } - case eStyleUnit_Percent: { - NS_ASSERTION(!aClampNegativeToZero || aStyle.GetPercentValue() >= 0.0f, - "unexpected negative value"); - *aPercent += aStyle.GetPercentValue(); - return; - } - case eStyleUnit_Calc: { - const nsStyleCoord::Calc *calc = aStyle.GetCalcValue(); - if (aClampNegativeToZero) { - // This is far from ideal when one is negative and one is positive. - *aCoord += std::max(calc->mLength, 0); - *aPercent += std::max(calc->mPercent, 0.0f); - } else { - *aCoord += calc->mLength; - *aPercent += calc->mPercent; - } - return; - } - default: { - return; - } - } +static nscoord +ResolveMargin(const nsStyleCoord& aStyle, nscoord aPercentageBasis) +{ + if (aStyle.GetUnit() == eStyleUnit_Auto) { + return nscoord(0); + } + return nsLayoutUtils::ResolveToLength<false>(aStyle, aPercentageBasis); +} + +static nscoord +ResolvePadding(const nsStyleCoord& aStyle, nscoord aPercentageBasis) +{ + return nsLayoutUtils::ResolveToLength<true>(aStyle, aPercentageBasis); } static nsIFrame::IntrinsicISizeOffsetData -IntrinsicSizeOffsets(nsIFrame* aFrame, bool aForISize) +IntrinsicSizeOffsets(nsIFrame* aFrame, nscoord aPercentageBasis, bool aForISize) { nsIFrame::IntrinsicISizeOffsetData result; WritingMode wm = aFrame->GetWritingMode(); - const nsStyleMargin* styleMargin = aFrame->StyleMargin(); + const auto& margin = aFrame->StyleMargin()->mMargin; bool verticalAxis = aForISize == wm.IsVertical(); - AddCoord(verticalAxis ? styleMargin->mMargin.GetTop() - : styleMargin->mMargin.GetLeft(), - aFrame, &result.hMargin, &result.hPctMargin, - false); - AddCoord(verticalAxis ? styleMargin->mMargin.GetBottom() - : styleMargin->mMargin.GetRight(), - aFrame, &result.hMargin, &result.hPctMargin, - false); - - const nsStylePadding* stylePadding = aFrame->StylePadding(); - AddCoord(verticalAxis ? stylePadding->mPadding.GetTop() - : stylePadding->mPadding.GetLeft(), - aFrame, &result.hPadding, &result.hPctPadding, - true); - AddCoord(verticalAxis ? stylePadding->mPadding.GetBottom() - : stylePadding->mPadding.GetRight(), - aFrame, &result.hPadding, &result.hPctPadding, - true); + if (verticalAxis) { + result.hMargin += ResolveMargin(margin.GetTop(), aPercentageBasis); + result.hMargin += ResolveMargin(margin.GetBottom(), aPercentageBasis); + } else { + result.hMargin += ResolveMargin(margin.GetLeft(), aPercentageBasis); + result.hMargin += ResolveMargin(margin.GetRight(), aPercentageBasis); + } + + const auto& padding = aFrame->StylePadding()->mPadding; + if (verticalAxis) { + result.hPadding += ResolvePadding(padding.GetTop(), aPercentageBasis); + result.hPadding += ResolvePadding(padding.GetBottom(), aPercentageBasis); + } else { + result.hPadding += ResolvePadding(padding.GetLeft(), aPercentageBasis); + result.hPadding += ResolvePadding(padding.GetRight(), aPercentageBasis); + } const nsStyleBorder* styleBorder = aFrame->StyleBorder(); if (verticalAxis) { result.hBorder += styleBorder->GetComputedBorderWidth(eSideTop); result.hBorder += styleBorder->GetComputedBorderWidth(eSideBottom); } else { result.hBorder += styleBorder->GetComputedBorderWidth(eSideLeft); result.hBorder += styleBorder->GetComputedBorderWidth(eSideRight); @@ -5570,32 +5546,31 @@ IntrinsicSizeOffsets(nsIFrame* aFrame, b nsIntMargin padding; if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(), aFrame, disp->mAppearance, &padding)) { result.hPadding = presContext->DevPixelsToAppUnits(verticalAxis ? padding.TopBottom() : padding.LeftRight()); - result.hPctPadding = 0; } } return result; } /* virtual */ nsIFrame::IntrinsicISizeOffsetData -nsFrame::IntrinsicISizeOffsets() -{ - return IntrinsicSizeOffsets(this, true); +nsFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis) +{ + return IntrinsicSizeOffsets(this, aPercentageBasis, true); } nsIFrame::IntrinsicISizeOffsetData -nsIFrame::IntrinsicBSizeOffsets() -{ - return IntrinsicSizeOffsets(this, false); +nsIFrame::IntrinsicBSizeOffsets(nscoord aPercentageBasis) +{ + return IntrinsicSizeOffsets(this, aPercentageBasis, false); } /* virtual */ IntrinsicSize nsFrame::GetIntrinsicSize() { return IntrinsicSize(); // default is width/height set to eStyleUnit_None }
--- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -269,17 +269,18 @@ public: void MarkIntrinsicISizesDirty() override; nscoord GetMinISize(gfxContext *aRenderingContext) override; nscoord GetPrefISize(gfxContext *aRenderingContext) override; void AddInlineMinISize(gfxContext *aRenderingContext, InlineMinISizeData *aData) override; void AddInlinePrefISize(gfxContext *aRenderingContext, InlinePrefISizeData *aData) override; - IntrinsicISizeOffsetData IntrinsicISizeOffsets() override; + IntrinsicISizeOffsetData + IntrinsicISizeOffsets(nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) override; mozilla::IntrinsicSize GetIntrinsicSize() override; nsSize GetIntrinsicRatio() override; mozilla::LogicalSize ComputeSize(gfxContext* aRenderingContext, mozilla::WritingMode aWM, const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
--- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -3,19 +3,19 @@ /* 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/. */ /* rendering object for CSS "display: grid | inline-grid" */ #include "nsGridContainerFrame.h" -#include <algorithm> // for std::stable_sort #include <functional> #include <limits> +#include <stdlib.h> // for div() #include "gfxContext.h" #include "mozilla/AutoRestore.h" #include "mozilla/ComputedStyle.h" #include "mozilla/CSSAlignUtils.h" #include "mozilla/CSSOrderAwareFrameIterator.h" #include "mozilla/dom/GridBinding.h" #include "mozilla/IntegerRange.h" #include "mozilla/Maybe.h" @@ -119,52 +119,16 @@ ResolveToDefiniteSize(const nsStyleCoord { MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit()); if (::IsPercentOfIndefiniteSize(aCoord, aPercentBasis)) { return nscoord(0); } return std::max(nscoord(0), aCoord.ComputeCoordPercentCalc(aPercentBasis)); } -static bool -GetPercentSizeParts(const nsStyleCoord& aCoord, nscoord* aLength, float* aPercent) -{ - switch (aCoord.GetUnit()) { - case eStyleUnit_Percent: - *aLength = 0; - *aPercent = aCoord.GetPercentValue(); - return true; - case eStyleUnit_Calc: { - nsStyleCoord::Calc* calc = aCoord.GetCalcValue(); - *aLength = calc->mLength; - *aPercent = calc->mPercent; - return true; - } - default: - return false; - } -} - -static void -ResolvePercentSizeParts(const nsStyleCoord& aCoord, nscoord aPercentBasis, - nscoord* aLength, float* aPercent) -{ - MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit()); - if (aPercentBasis != NS_UNCONSTRAINEDSIZE) { - *aLength = std::max(nscoord(0), - aCoord.ComputeCoordPercentCalc(aPercentBasis)); - *aPercent = 0.0f; - return; - } - if (!GetPercentSizeParts(aCoord, aLength, aPercent)) { - *aLength = aCoord.ToLength(); - *aPercent = 0.0f; - } -} - // Synthesize a baseline from a border box. For an alphabetical baseline // this is the end edge of the border box. For a central baseline it's // the center of the border box. // https://drafts.csswg.org/css-align-3/#synthesize-baselines // For a 'first baseline' the measure is from the border-box start edge and // for a 'last baseline' the measure is from the border-box end edge. static nscoord SynthesizeBaselineFromBorderBox(BaselineSharingGroup aGroup, @@ -925,81 +889,58 @@ struct nsGridContainerFrame::TrackSizing const uint32_t numTracks = mMinSizingFunctions.Length(); MOZ_ASSERT(numTracks >= 1, "expected at least the repeat() track"); nscoord maxFill = aSize != NS_UNCONSTRAINEDSIZE ? aSize : aMaxSize; if (maxFill == NS_UNCONSTRAINEDSIZE && aMinSize == 0) { // "Otherwise, the specified track list repeats only once." return 1; } nscoord repeatTrackSize = 0; - // Note that the repeat() track size is included in |sum| in this loop. + // Note that one repeat() track size is included in |sum| in this loop. nscoord sum = 0; const nscoord percentBasis = aSize; for (uint32_t i = 0; i < numTracks; ++i) { // "treating each track as its max track sizing function if that is // definite or as its minimum track sizing function otherwise" // https://drafts.csswg.org/css-grid/#valdef-repeat-auto-fill const auto& maxCoord = mMaxSizingFunctions[i]; const auto* coord = &maxCoord; if (!coord->IsCoordPercentCalcUnit()) { coord = &mMinSizingFunctions[i]; if (!coord->IsCoordPercentCalcUnit()) { return 1; } } nscoord trackSize = ::ResolveToDefiniteSize(*coord, percentBasis); if (i == mRepeatAutoStart) { - if (percentBasis != NS_UNCONSTRAINEDSIZE) { - // Use a minimum 1px for the repeat() track-size. - if (trackSize < AppUnitsPerCSSPixel()) { - trackSize = AppUnitsPerCSSPixel(); - } + // Use a minimum 1px for the repeat() track-size. + if (trackSize < AppUnitsPerCSSPixel()) { + trackSize = AppUnitsPerCSSPixel(); } repeatTrackSize = trackSize; } sum += trackSize; } - nscoord gridGap; - float percentSum = 0.0f; - float gridGapPercent; - ResolvePercentSizeParts(aGridGap, percentBasis, &gridGap, &gridGapPercent); + nscoord gridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aSize); if (numTracks > 1) { // Add grid-gaps for all the tracks including the repeat() track. sum += gridGap * (numTracks - 1); - percentSum = gridGapPercent * (numTracks - 1); } // Calculate the max number of tracks that fits without overflow. nscoord available = maxFill != NS_UNCONSTRAINEDSIZE ? maxFill : aMinSize; - nscoord size = nsLayoutUtils::AddPercents(sum, percentSum); - if (available - size < 0) { + nscoord spaceToFill = available - sum; + if (spaceToFill <= 0) { // "if any number of repetitions would overflow, then 1 repetition" return 1; } - uint32_t numRepeatTracks = 1; - bool exactFit = false; - while (true) { - sum += gridGap + repeatTrackSize; - percentSum += gridGapPercent; - nscoord newSize = nsLayoutUtils::AddPercents(sum, percentSum); - if (newSize <= size) { - // Adding more repeat-tracks won't make forward progress. - return numRepeatTracks; - } - size = newSize; - nscoord remaining = available - size; - exactFit = remaining == 0; - if (remaining >= 0) { - ++numRepeatTracks; - } - if (remaining <= 0) { - break; - } - } - - if (!exactFit && maxFill == NS_UNCONSTRAINEDSIZE) { + // Calculate the max number of tracks that fits without overflow. + div_t q = div(spaceToFill, repeatTrackSize + gridGap); + // The +1 here is for the one repeat track we already accounted for above. + uint32_t numRepeatTracks = q.quot + 1; + if (q.rem != 0 && maxFill == NS_UNCONSTRAINEDSIZE) { // "Otherwise, if the grid container has a definite min size in // the relevant axis, the number of repetitions is the largest possible // positive integer that fulfills that minimum requirement." ++numRepeatTracks; // one more to ensure the grid is at least min-size } // Clamp the number of repeat tracks so that the last line <= kMaxLine. // (note that |numTracks| already includes one repeat() track) const uint32_t maxRepeatTracks = nsStyleGridLine::kMaxLine - numTracks; @@ -1634,23 +1575,16 @@ struct nsGridContainerFrame::Tracks /** * Apply 'align/justify-content', whichever is relevant for this axis. * https://drafts.csswg.org/css-align-3/#propdef-align-content */ void AlignJustifyContent(const nsStylePosition* aStyle, WritingMode aWM, const LogicalSize& aContainerSize); - /** - * Return the intrinsic size by back-computing percentages as: - * IntrinsicSize = SumOfCoordSizes / (1 - SumOfPercentages). - */ - nscoord BackComputedIntrinsicSize(const TrackSizingFunctions& aFunctions, - const nsStyleCoord& aGridGap) const; - nscoord GridLineEdge(uint32_t aLine, GridLineSide aSide) const { if (MOZ_UNLIKELY(mSizes.IsEmpty())) { // https://drafts.csswg.org/css-grid/#grid-definition // "... the explicit grid still contains one grid line in each axis." MOZ_ASSERT(aLine == 0, "We should only resolve line 1 in an empty grid"); return nscoord(0); } @@ -1944,21 +1878,20 @@ struct MOZ_STACK_CLASS nsGridContainerFr // Copy in the computed grid info state bit if (mSharedGridData->mGenerateComputedGridInfo) { aGridContainerFrame->AddStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES); } } /** - * Calculate our track sizes. If the given aContentBox block-axis size is - * unconstrained, it is assigned to the resulting intrinsic block-axis size. + * Calculate our track sizes. */ void CalculateTrackSizes(const Grid& aGrid, - LogicalSize& aContentBox, + const LogicalSize& aContentBox, SizingConstraint aConstraint); /** * Return the percentage basis for a grid item in its writing-mode. * If aAxis is eLogicalAxisInline then we return NS_UNCONSTRAINEDSIZE in * both axes since we know all track sizes are indefinite at this point * (we calculate column sizes before row sizes). Otherwise, assert that * column sizes are known and calculate the size for aGridItem.mArea.mCols @@ -2434,17 +2367,17 @@ struct MOZ_STACK_CLASS nsGridContainerFr */ uint32_t mExplicitGridOffsetCol; uint32_t mExplicitGridOffsetRow; }; void nsGridContainerFrame::GridReflowInput::CalculateTrackSizes( const Grid& aGrid, - LogicalSize& aContentBox, + const LogicalSize& aContentBox, SizingConstraint aConstraint) { mCols.Initialize(mColFunctions, mGridStyle->mGridColumnGap, aGrid.mGridColEnd, aContentBox.ISize(mWM)); mRows.Initialize(mRowFunctions, mGridStyle->mGridRowGap, aGrid.mGridRowEnd, aContentBox.BSize(mWM)); mCols.CalculateSizes(*this, mGridItems, mColFunctions, @@ -2452,22 +2385,16 @@ nsGridContainerFrame::GridReflowInput::C aConstraint); mCols.AlignJustifyContent(mGridStyle, mWM, aContentBox); // Column positions and sizes are now final. mCols.mCanResolveLineRangeSize = true; mRows.CalculateSizes(*this, mGridItems, mRowFunctions, aContentBox.BSize(mWM), &GridArea::mRows, aConstraint); - if (aContentBox.BSize(mWM) == NS_AUTOHEIGHT) { - aContentBox.BSize(mWM) = - mRows.BackComputedIntrinsicSize(mRowFunctions, mGridStyle->mGridRowGap); - mRows.mGridGap = - ::ResolveToDefiniteSize(mGridStyle->mGridRowGap, aContentBox.BSize(mWM)); - } } /** * (XXX share this utility function with nsFlexContainerFrame at some point) * * Helper for BuildDisplayList, to implement this special-case for grid * items from the spec: * The painting order of grid items is exactly the same as inline blocks, @@ -3559,17 +3486,17 @@ nsGridContainerFrame::Tracks::Initialize aFunctions.NumExplicitTracks()); mSizes.SetLength(aNumTracks); PodZero(mSizes.Elements(), mSizes.Length()); for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) { mStateUnion |= mSizes[i].Initialize(aContentBoxSize, aFunctions.MinSizingFor(i), aFunctions.MaxSizingFor(i)); } - mGridGap = ::ResolveToDefiniteSize(aGridGap, aContentBoxSize); + mGridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aContentBoxSize); mContentBoxSize = aContentBoxSize; } /** * Reflow aChild in the given aAvailableSize. */ static nscoord MeasuringReflow(nsIFrame* aChild, @@ -3650,18 +3577,17 @@ ContentContribution(const GridItemInfo& IntrinsicISizeType aConstraint, nscoord aMinSizeClamp = NS_MAXSIZE, uint32_t aFlags = 0) { nsIFrame* child = aGridItem.mFrame; PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis)); nscoord size = nsLayoutUtils::IntrinsicForAxis(axis, aRC, child, aConstraint, aPercentageBasis, - aFlags | nsLayoutUtils::BAIL_IF_REFLOW_NEEDED | - nsLayoutUtils::ADD_PERCENTS, + aFlags | nsLayoutUtils::BAIL_IF_REFLOW_NEEDED, aMinSizeClamp); if (size == NS_INTRINSIC_WIDTH_UNKNOWN) { // We need to reflow the child to find its BSize contribution. // XXX this will give mostly correct results for now (until bug 1174569). nscoord availISize = INFINITE_ISIZE_COORD; nscoord availBSize = NS_UNCONSTRAINEDSIZE; auto childWM = child->GetWritingMode(); const bool isOrthogonal = childWM.IsOrthogonalTo(aCBWM); @@ -3688,25 +3614,17 @@ ContentContribution(const GridItemInfo& if (isOrthogonal == (aAxis == eLogicalAxisInline)) { bMinSizeClamp = aMinSizeClamp; } else { iMinSizeClamp = aMinSizeClamp; } LogicalSize availableSize(childWM, availISize, availBSize); size = ::MeasuringReflow(child, aState.mReflowInput, aRC, availableSize, cbSize, iMinSizeClamp, bMinSizeClamp); - nsIFrame::IntrinsicISizeOffsetData offsets = child->IntrinsicBSizeOffsets(); - size += offsets.hMargin; - auto percent = offsets.hPctMargin; - if (availBSize == NS_UNCONSTRAINEDSIZE) { - // We always want to add in percent padding too, unless we already did so - // using a resolved column size above. - percent += offsets.hPctPadding; - } - size = nsLayoutUtils::AddPercents(size, percent); + size += child->GetLogicalUsedMargin(childWM).BStartEnd(childWM); nscoord overflow = size - aMinSizeClamp; if (MOZ_UNLIKELY(overflow > 0)) { nscoord contentSize = child->ContentBSize(childWM); nscoord newContentSize = std::max(nscoord(0), contentSize - overflow); // XXXmats deal with percentages better, see bug 1300369 comment 27. size -= contentSize - newContentSize; } } @@ -3801,41 +3719,43 @@ MinSize(const GridItemInfo& aGridItem axis == eAxisHorizontal ? stylePos->mWidth : stylePos->mHeight; if (sizeStyle.GetUnit() != eStyleUnit_Auto) { nscoord s = MinContentContribution(aGridItem, aState, aRC, aCBWM, aAxis, aCache); aCache->mMinSize.emplace(s); return s; } + if (aCache->mPercentageBasis.isNothing()) { + aCache->mPercentageBasis.emplace(aState.PercentageBasisFor(aAxis, aGridItem)); + } + // https://drafts.csswg.org/css-grid/#min-size-auto // This calculates the min-content contribution from either a definite // min-width (or min-height depending on aAxis), or the "specified / // transferred size" for min-width:auto if overflow == visible (as min-width:0 // otherwise), or NS_UNCONSTRAINEDSIZE for other min-width intrinsic values // (which results in always taking the "content size" part below). MOZ_ASSERT(aGridItem.mBaselineOffset[aAxis] >= 0, "baseline offset should be non-negative at this point"); MOZ_ASSERT((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) || aGridItem.mBaselineOffset[aAxis] == nscoord(0), "baseline offset should be zero when not baseline-aligned"); nscoord sz = aGridItem.mBaselineOffset[aAxis] + nsLayoutUtils::MinSizeContributionForAxis(axis, aRC, child, - nsLayoutUtils::MIN_ISIZE); + nsLayoutUtils::MIN_ISIZE, + *aCache->mPercentageBasis); const nsStyleCoord& style = axis == eAxisHorizontal ? stylePos->mMinWidth : stylePos->mMinHeight; auto unit = style.GetUnit(); if (unit == eStyleUnit_Enumerated || (unit == eStyleUnit_Auto && child->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)) { // Now calculate the "content size" part and return whichever is smaller. MOZ_ASSERT(unit != eStyleUnit_Enumerated || sz == NS_UNCONSTRAINEDSIZE); - if (aCache->mPercentageBasis.isNothing()) { - aCache->mPercentageBasis.emplace(aState.PercentageBasisFor(aAxis, aGridItem)); - } sz = std::min(sz, ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis, aCache->mPercentageBasis, nsLayoutUtils::MIN_ISIZE, aCache->mMinSizeClamp, nsLayoutUtils::MIN_INTRINSIC_ISIZE)); } aCache->mMinSize.emplace(sz); return sz; @@ -4829,46 +4749,16 @@ nsGridContainerFrame::Tracks::AlignJusti roundingError -= 1; spacing += 1; } pos += sz.mBase + spacing; } MOZ_ASSERT(!roundingError, "we didn't distribute all rounding error?"); } -nscoord -nsGridContainerFrame::Tracks::BackComputedIntrinsicSize( - const TrackSizingFunctions& aFunctions, - const nsStyleCoord& aGridGap) const -{ - // Sum up the current sizes (where percentage tracks were treated as 'auto') - // in 'size'. - nscoord size = 0; - for (size_t i = 0, len = mSizes.Length(); i < len; ++i) { - size += mSizes[i].mBase; - } - - // Add grid-gap contributions to 'size' and calculate a 'percent' sum. - float percent = 0.0f; - size_t numTracks = mSizes.Length(); - if (numTracks > 1) { - const size_t gridGapCount = numTracks - 1; - nscoord gridGapLength; - float gridGapPercent; - if (::GetPercentSizeParts(aGridGap, &gridGapLength, &gridGapPercent)) { - percent = gridGapCount * gridGapPercent; - } else { - gridGapLength = aGridGap.ToLength(); - } - size += gridGapCount * gridGapLength; - } - - return std::max(0, nsLayoutUtils::AddPercents(size, percent)); -} - void nsGridContainerFrame::LineRange::ToPositionAndLength( const nsTArray<TrackSize>& aTrackSizes, nscoord* aPos, nscoord* aLength) const { MOZ_ASSERT(mStart != kAutoLine && mEnd != kAutoLine, "expected a definite LineRange"); MOZ_ASSERT(mStart < mEnd); nscoord startPos = aTrackSizes[mStart].mPosition; @@ -6046,25 +5936,30 @@ nsGridContainerFrame::Reflow(nsPresConte RemoveStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE); } const nscoord computedBSize = aReflowInput.ComputedBSize(); const nscoord computedISize = aReflowInput.ComputedISize(); const WritingMode& wm = gridReflowInput.mWM; LogicalSize computedSize(wm, computedISize, computedBSize); nscoord consumedBSize = 0; - nscoord bSize; + nscoord bSize = 0; if (!prevInFlow) { Grid grid; grid.PlaceGridItems(gridReflowInput, aReflowInput.ComputedMinSize(), computedSize, aReflowInput.ComputedMaxSize()); gridReflowInput.CalculateTrackSizes(grid, computedSize, SizingConstraint::eNoConstraint); - bSize = computedSize.BSize(wm); + // Note: we can't use GridLineEdge here since we haven't calculated + // the rows' mPosition yet (happens in AlignJustifyContent below). + for (const auto& sz : gridReflowInput.mRows.mSizes) { + bSize += sz.mBase; + } + bSize += gridReflowInput.mRows.SumOfGridGaps(); } else { consumedBSize = ConsumedBSize(wm); gridReflowInput.InitializeForContinuation(this, consumedBSize); const uint32_t numRows = gridReflowInput.mRows.mSizes.Length(); bSize = gridReflowInput.mRows.GridLineEdge(numRows, GridLineSide::eAfterGridGap); } if (computedBSize == NS_AUTOHEIGHT) { @@ -6477,18 +6372,24 @@ nsGridContainerFrame::IntrinsicISize(gfx } state.mCols.Initialize(state.mColFunctions, state.mGridStyle->mGridColumnGap, grid.mGridColEnd, NS_UNCONSTRAINEDSIZE); auto constraint = aType == nsLayoutUtils::MIN_ISIZE ? SizingConstraint::eMinContent : SizingConstraint::eMaxContent; state.mCols.CalculateSizes(state, state.mGridItems, state.mColFunctions, NS_UNCONSTRAINEDSIZE, &GridArea::mCols, constraint); - return state.mCols.BackComputedIntrinsicSize(state.mColFunctions, - state.mGridStyle->mGridColumnGap); + state.mCols.mGridGap = + nsLayoutUtils::ResolveGapToLength(state.mGridStyle->mGridColumnGap, + NS_UNCONSTRAINEDSIZE); + nscoord length = 0; + for (const TrackSize& sz : state.mCols.mSizes) { + length += sz.mBase; + } + return length + state.mCols.SumOfGridGaps(); } nscoord nsGridContainerFrame::GetMinISize(gfxContext* aRC) { DISPLAY_MIN_WIDTH(this, mCachedMinISize); if (mCachedMinISize == NS_INTRINSIC_WIDTH_UNKNOWN) { mCachedMinISize = IntrinsicISize(aRC, nsLayoutUtils::MIN_ISIZE);
--- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -20,16 +20,17 @@ we're midway through this process, so you will see inlined functions and member variables in this file. -dwh */ #include <algorithm> #include <stdio.h> #include "CaretAssociationHint.h" #include "FrameProperties.h" +#include "LayoutConstants.h" #include "mozilla/layout/FrameChildList.h" #include "mozilla/Maybe.h" #include "mozilla/SmallPointerArray.h" #include "mozilla/WritingModes.h" #include "nsDirection.h" #include "nsFrameList.h" #include "nsFrameState.h" #include "mozilla/ReflowOutput.h" @@ -135,40 +136,22 @@ typedef uint32_t nsSplittableType; #define NS_FRAME_SPLITTABLE_NON_RECTANGULAR 0x3 #define NS_FRAME_IS_SPLITTABLE(type)\ (0 != ((type) & NS_FRAME_SPLITTABLE)) #define NS_FRAME_IS_NOT_SPLITTABLE(type)\ (0 == ((type) & NS_FRAME_SPLITTABLE)) -#define NS_INTRINSIC_WIDTH_UNKNOWN nscoord_MIN - //---------------------------------------------------------------------- #define NS_SUBTREE_DIRTY(_frame) \ (((_frame)->GetStateBits() & \ (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0) -/** - * Constant used to indicate an unconstrained size. - * - * @see #Reflow() - */ -#define NS_UNCONSTRAINEDSIZE NS_MAXSIZE - -#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE -#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE -// +1 is to avoid clamped huge margin values being processed as auto margins -#define NS_AUTOMARGIN (NS_UNCONSTRAINEDSIZE + 1) -#define NS_AUTOOFFSET NS_UNCONSTRAINEDSIZE -// NOTE: there are assumptions all over that these have the same value, namely NS_UNCONSTRAINEDSIZE -// if any are changed to be a value other than NS_UNCONSTRAINEDSIZE -// at least update AdjustComputedHeight/Width and test ad nauseum - // 1 million CSS pixels less than our max app unit measure. // For reflowing with an "infinite" available inline space per [css-sizing]. // (reflowing with an NS_UNCONSTRAINEDSIZE available inline size isn't allowed // and leads to assertions) #define INFINITE_ISIZE_COORD nscoord(NS_MAXSIZE - (1000000*60)) //---------------------------------------------------------------------- @@ -2350,33 +2333,37 @@ public: */ virtual void AddInlinePrefISize(gfxContext *aRenderingContext, InlinePrefISizeData *aData) = 0; /** * Return the horizontal components of padding, border, and margin * that contribute to the intrinsic width that applies to the parent. + * @param aPercentageBasis the percentage basis to use for padding/margin - + * i.e. the Containing Block's inline-size */ struct IntrinsicISizeOffsetData { nscoord hPadding, hBorder, hMargin; - float hPctPadding, hPctMargin; IntrinsicISizeOffsetData() : hPadding(0), hBorder(0), hMargin(0) - , hPctPadding(0.0f), hPctMargin(0.0f) {} }; - virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() = 0; + virtual IntrinsicISizeOffsetData + IntrinsicISizeOffsets(nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) = 0; /** * Return the bsize components of padding, border, and margin * that contribute to the intrinsic width that applies to the parent. - */ - IntrinsicISizeOffsetData IntrinsicBSizeOffsets(); + * @param aPercentageBasis the percentage basis to use for padding/margin - + * i.e. the Containing Block's inline-size + */ + IntrinsicISizeOffsetData + IntrinsicBSizeOffsets(nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE); virtual mozilla::IntrinsicSize GetIntrinsicSize() = 0; /** * Get the intrinsic ratio of this element, or nsSize(0,0) if it has * no intrinsic ratio. The intrinsic ratio is the ratio of the * height/width of a box with an intrinsic size or the intrinsic * aspect ratio of a scalable vector image without an intrinsic size.
--- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -6890,17 +6890,17 @@ nsDisplayTableBlendContainer::CreateForB { return MakeDisplayItem<nsDisplayTableBlendContainer>(aBuilder, aFrame, aList, aActiveScrolledRoot, true, aAncestorFrame); } nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, const ActiveScrolledRoot* aActiveScrolledRoot, nsDisplayOwnLayerFlags aFlags, ViewID aScrollTarget, - const ScrollThumbData& aThumbData, + const ScrollbarData& aThumbData, bool aForceActive, bool aClearClipChain) : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, aClearClipChain) , mFlags(aFlags) , mScrollTarget(aScrollTarget) , mThumbData(aThumbData) , mForceActive(aForceActive) , mWrAnimationId(0) @@ -6932,17 +6932,17 @@ nsDisplayOwnLayer::GetLayerState(nsDispl } return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, mAnimatedGeometryRoot); } bool nsDisplayOwnLayer::IsScrollThumbLayer() const { - return mThumbData.mDirection.isSome(); + return mThumbData.mScrollbarLayerType == layers::ScrollbarLayerType::Thumb; } bool nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const { // Render scroll thumb layers even if they are invisible, because async // scrolling might bring them into view. return IsScrollThumbLayer(); @@ -6954,17 +6954,18 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayL LayerManager* aManager, const ContainerLayerParameters& aContainerParameters) { RefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()-> BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, aContainerParameters, nullptr, FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR); if (IsScrollThumbLayer()) { - layer->SetScrollThumbData(mScrollTarget, mThumbData); + mThumbData.mTargetViewId = mScrollTarget; + layer->SetScrollbarData(mThumbData); } if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) { ScrollDirection dir = (mFlags & nsDisplayOwnLayerFlags::eVerticalScrollbar) ? ScrollDirection::eVertical : ScrollDirection::eHorizontal; layer->SetScrollbarContainer(mScrollTarget, dir); } @@ -7010,17 +7011,17 @@ nsDisplayOwnLayer::CreateWebRenderComman bool nsDisplayOwnLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData, mozilla::layers::WebRenderLayerScrollData* aLayerData) { bool ret = false; if (IsScrollThumbLayer()) { ret = true; if (aLayerData) { - aLayerData->SetScrollThumbData(mThumbData); + aLayerData->SetScrollbarData(mThumbData); aLayerData->SetScrollbarAnimationId(mWrAnimationId); aLayerData->SetScrollbarTargetContainerId(mScrollTarget); } } if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) { ret = true; if (aLayerData) { ScrollDirection dir = (mFlags & nsDisplayOwnLayerFlags::eVerticalScrollbar)
--- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -5473,17 +5473,17 @@ enum class nsDisplayOwnLayerFlags { MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsDisplayOwnLayerFlags) /** * A display item that has no purpose but to ensure its contents get * their own layer. */ class nsDisplayOwnLayer : public nsDisplayWrapList { public: - typedef mozilla::layers::ScrollThumbData ScrollThumbData; + typedef mozilla::layers::ScrollbarData ScrollbarData; /** * @param aFlags eGenerateSubdocInvalidations : * Add UserData to the created ContainerLayer, so that invalidations * for this layer are send to our nsPresContext. * eGenerateScrollableLayer : only valid on nsDisplaySubDocument (and * subclasses), indicates this layer is to be a scrollable layer, so call * ComputeFrameMetrics, etc. @@ -5491,17 +5491,17 @@ public: * is set in the flags, this parameter should be the ViewID of the * scrollable content this scrollbar is for. */ nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, const ActiveScrolledRoot* aActiveScrolledRoot, nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::eNone, ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID, - const ScrollThumbData& aThumbData = ScrollThumbData{}, + const ScrollbarData& aThumbData = ScrollbarData{}, bool aForceActive = true, bool aClearClipChain = false); #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayOwnLayer(); #endif nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, const nsDisplayOwnLayer& aOther) : nsDisplayWrapList(aBuilder, aOther) , mFlags(aOther.mFlags) @@ -5546,17 +5546,17 @@ public: NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER) protected: nsDisplayOwnLayerFlags mFlags; ViewID mScrollTarget; // If this nsDisplayOwnLayer represents a scroll thumb layer, mThumbData // stores information about the scroll thumb. Otherwise, mThumbData will be // default-constructed (in particular with mDirection == Nothing()) // and can be ignored. - ScrollThumbData mThumbData; + ScrollbarData mThumbData; bool mForceActive; uint64_t mWrAnimationId; }; /** * A display item for subdocuments. This is more or less the same as nsDisplayOwnLayer, * except that it always populates the FrameMetrics instance on the ContainerLayer it * builds.
--- a/layout/reftests/bugs/403519-2-ref.html +++ b/layout/reftests/bugs/403519-2-ref.html @@ -12,17 +12,17 @@ table { width: 200px; border-spacing: 0; } </style> </head> <body> <table> <tbody><tr> - <td colspan="2" style="width: 100%;"><div> </div></td> + <td colspan="2"><div> </div></td> <td>b</td> </tr> <tr> <td> </td> <td> </td> <td> </td> </tr> </tbody></table>
--- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -551,19 +551,19 @@ fuzzy-if(skiaContent,2,4) == 362594-2c.h skip-if(Android) == 363706-1.html 363706-1-ref.html != 363706-1.html about:blank == 363728-1.html 363728-1-ref.html == 363728-2.html 363728-2-ref.html fuzzy-if(skiaContent||Android,4,11) == 363858-1.html 363858-1-ref.html == 363858-2.html 363858-2-ref.html == 363858-3.html 363858-3-ref.html == 363858-4.html 363858-4-ref.html -fuzzy-if(OSX,45,2) fuzzy-if(winWidget,114,1) fails-if(webrender&&winWidget) == 363858-5a.html 363858-5-ref.html +# fuzzy-if(OSX,45,2) fuzzy-if(winWidget,114,1) fails-if(webrender&&winWidget) == 363858-5a.html 363858-5-ref.html # bug 1452797 == 363858-5b.html 363858-5-ref.html -fuzzy-if(OSX,45,2) fuzzy-if(winWidget,114,1) fails-if(webrender&&winWidget) == 363858-6a.html 363858-6-ref.html +# fuzzy-if(OSX,45,2) fuzzy-if(winWidget,114,1) fails-if(webrender&&winWidget) == 363858-6a.html 363858-6-ref.html # bug 1452797 == 363858-6b.html 363858-6-ref.html == 363874.html 363874-ref.html == 363874-max-width.html 363874-max-width-ref.html == 364066-1.html 364066-1-ref.html == 364079-1.html 364079-1-ref.html == 364318-1.xhtml 364318-1-ref.xhtml == 364861-1.html 364861-1-ref.html == 364862-1.html 364862-1-ref.html
--- a/layout/reftests/css-grid/grid-auto-min-sizing-definite-001-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-definite-001-ref.html @@ -60,55 +60,73 @@ b40 { height: 40px; border: 1px solid pink; z-index: 1; position:relative; } .h.r { height: 42px; width: 42px; - /* This margin-left is 20% of 98px-wide grid area */ - margin-left: 19.6px; - /* This padding-bottom is 10% of 98px wide grid area */ - /* This padding-left is 30% of 98px wide grid area */ - padding: 1px 3px 9.8px 29.4px; + /* 49px is the percentage basis, i.e. the column size */ + margin-left: calc(0.2 * 49px); + padding: 1px 3px calc(0.1 * 49px) calc(0.3 * 49px); } .v.r { height: 42px; width: 42px; /* This margin-left is 20% of 54px-wide grid area */ - margin-left: 10.8px; - /* This padding-bottom is 10% of 54px wide grid area */ - /* This padding-left is 30% of 54px wide grid area */ - padding: 1px 3px 5.4px 16.2px; + /* 27px is the percentage basis, i.e. the column size */ + margin-left: calc(0.2 * 27px); + padding: 1px 3px calc(0.1 * 27px) calc(0.3 * 27px); } .r { position:relative; } +.t4 { width: 49px; + height: calc(10px /* item min-height */ + + 7px /* item margin-top */ + + 1px /* item padding-top */ + + 1px /* item border-top */ + + calc(0.5 * 49px) /* item margin-bottom */ + + calc(0.1 * 49px) /* item padding-bottom */); + } .t6 { width:46px; } -.t8 { width:118px; height: 102.5px; } +.t8 { width: 27px; + height: calc(30px /* item min-height */ + + 7px /* item margin-top */ + + 3px /* item padding-top */ + + 1px /* item border-top */ + + calc(0.5 * 27px) /* item margin-bottom */ + + calc(0.1 * 27px) /* item padding-bottom */); + } + xx { display: block; background: lime; - padding:32px 32px 16px 32px; - margin: 0 0 32px 16px; + padding: 32px 32px calc(0.2 * 32px) calc(0.4 * 32px); + margin: 0 0 calc(0.4 * 32px) calc(0.2 * 32px); +} +.t9, .t10 { + position: relative; + z-index: 1; + grid: calc(32px + calc(0.4 * 32px) + calc(0.2 * 32px)) 0 / 32px; } </style> </head> <body> <div class="grid"><span class="h"><x></x></span></div> <div class="grid"><span class="h bb"><x></x></span></div> <div class="grid"><span class="h"><x></x></span><span class="h"><x></x></span></div> -<div class="grid" style="grid:48px / 122px"><span class="h r"><b40></b40></span></div> +<div class="grid t4"><span class="h r"><b40></b40></span></div> <br> <div class="grid"><span class="v"><x></x></span></div> -<div class="grid t6"><span class="v bb"><x></x></span></div> +<div class="grid"><span class="v bb"><x></x></span></div> <div class="grid"><span class="v"><x></x></span><span class="v"><x></x></span></div> <div class="grid t8"><span class="v r"><b40></b40></span></div> -<div class="grid"><xx class="v"></xx></div> -<div class="grid v"><xx class="h"></xx></div> +<div class="grid t9"><xx class="v"></xx></div> +<div class="grid v t10"><xx class="h"></xx></div> </body> </html>
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html @@ -31,17 +31,17 @@ br { clear:both; } <script> var coltest = [ "height:30px; max-width:200%", "height:30px; width:200%", "height:30px; width:50%", "width:50%", "max-width:50%", "height:30px", "height:200%; width:80px", "height:50%", "height:50%; width:20px", "max-height:50%", "max-height:50%; max-width:6px", "min-height:40%", "min-height:40%; max-width:30px" ]; var results = [ -"360px", "360px", "360px", "24px", "24px", "360px", "80px", "24px", "24px", "24px", +"24px", "24px", "24px", "24px", "24px", "24px", "80px", "24px", "24px", "24px", "24px", "24px", "24px" ]; var item_width = [ "48px", "48px", "24px", "24px", "24px;max-width:none;", "360px", "80px", "60px", "24px", "24px", "24px;max-width:none;", "48px", "30px" ]; var h3 = document.createElement('h3');
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html @@ -31,17 +31,17 @@ br { clear:both; } <script> var rowtest = [ "width:50%; max-height:200%", "width:50%; height:200%", "width:4px; height:50%", "height:50%", "max-height:200%", "max-height:50%", "max-width:50%", "width:50%; height:20px", "min-width:80%; max-height:20px", "min-width:50%", "margin-left: 50px; width:50%" ]; var results = [ -"0/2px", "0/2px", "0/4px", "0/2px", "0/2px", "0/2px", "12px/2px", "20px/2px", "20px/2px", "24px/2px", "24px/52px" +"0/2px", "0/2px", "0/4px", "0/2px", "0/2px", "0/2px", "12px/2px", "20px/2px", "20px/2px", "24px/2px", "312px/52px" ]; var item_height = [ "0", "0", "0", "0", "0", "0", "12px", "20px", "20px", "24px", "312px" ]; var h3 = document.createElement('h3'); h3.appendChild(document.createTextNode("grid-template-rows:minmax(auto,0.0001fr)")); document.body.appendChild(h3);
--- a/layout/reftests/css-grid/grid-auto-min-sizing-percent-001-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-percent-001-ref.html @@ -49,19 +49,19 @@ br { clear:both; } .c200 { grid-template-columns: 200px; } #px-border .c100 { grid-template-columns: minmax(120px,0) 1fr; } #px-border .c100calc100 { grid-template-columns: minmax(120px,0) 1fr; } #px-border .c100100 { grid-template-columns: minmax(120px,0) 120px; } #px-border .c200 { grid-template-columns: 240px; } .c10 { grid-template-columns: minmax(10px,0) 1fr; } #px-border .c10 { grid-template-columns: minmax(30px,0) 1fr; } -#percent-border .c100 { grid-template-columns: 111px 0; } -#percent-border .c100calc100 { grid-template-columns: 100px 11px; } -#percent-border .c10 { grid-template-columns: minmax(11px,0) 0; } +#percent-border .c100 { grid-template-columns: 100px 0; } +#percent-border .c100calc100 { grid-template-columns: 100px 10px; } +#percent-border .c10 { grid-template-columns: minmax(10px,0) 0; } #percent-border .c100100 { grid-template-columns: minmax(100px,0) 150px; } #percent-border .c200 { grid-template-columns: 250px; } </style> </head> <body> <table border="1"> <tr><th>no border/padding/margin</th><th>'border-left:20px'</th><th>'padding-left:10%'</th> @@ -94,28 +94,28 @@ var styles = [ "min-width:calc(100px + 50%); max-width:150px", ]; var grids = [ "grid", "grid", "grid c100", "grid c100", "grid", -"grid c200", +"grid c100", "grid c10", "grid c100", "grid c100", "grid", "grid", "grid", "grid", "grid c100", "grid c100", "grid", -"grid c200", +"grid c100", "grid c10", "grid c100", "grid c100", "grid", "grid", ]; var containers = [ "no-border", "px-border", "percent-border" ]; for (var i = 0; i < containers.length; ++i) {
--- a/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-002-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-002-ref.html @@ -31,17 +31,17 @@ br { clear:both; } <script> var coltest = [ "height:30px; max-width:200%", "height:30px; width:200%", "height:30px; width:50%", "width:50%", "max-width:50%", "height:30px", "height:200%; width:80px", "height:50%", "height:50%; width:20px", "max-height:50%", "max-height:50%; max-width:6px", "min-height:40%", "min-height:40%; max-width:30px" ]; var results = [ -"360px", "360px", "360px", "24px", "24px", "360px", "80px", "24px", "20px", "24px", +"360px", "0px", "0px", "0px", "24px", "360px", "80px", "24px", "20px", "24px", "6px", "24px", "24px" ]; var item_width = [ "0px", "0px", "0px", "0px", "0px", "360px", "80px", "60px", "20px", "24px", "6px", "48px", "30px" ]; var h3 = document.createElement('h3');
--- a/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-004-ref.html +++ b/layout/reftests/css-grid/grid-auto-min-sizing-transferred-size-004-ref.html @@ -31,17 +31,17 @@ br { clear:both; } <script> var rowtest = [ "width:50%; max-height:200%", "width:50%; height:200%", "width:4px; height:50%", "height:50%", "max-height:200%", "max-height:50%", "max-width:50%", "width:50%; height:20px", "min-width:80%; max-height:20px", "min-width:50%", "margin-left: 50px; width:50%" ]; var results = [ -"0/2px", "0/2px", "0/4px", "0/2px", "0/2px", "0/2px", "12px/2px", "20px/2px", "20px/2px", "24px/2px", "24px/52px" +"0/2px", "0/2px", "0/4px", "0/2px", "0/2px", "0/2px", "12px/2px", "20px/2px", "20px/2px", "24px/2px", "312px/52px" ]; var item_height = [ "0", "0", "0", "0", "0", "0", "12px", "20px", "20px", "24px", "312px" ]; var h3 = document.createElement('h3'); h3.appendChild(document.createTextNode("grid-template-rows:minmax(auto,0.0001fr)")); document.body.appendChild(h3);
--- a/layout/reftests/css-grid/grid-item-sizing-percent-003-ref.html +++ b/layout/reftests/css-grid/grid-item-sizing-percent-003-ref.html @@ -64,74 +64,74 @@ a { background: blue; } </style> </head> <body> <div style="float:left"> <div class="grid" style="grid-template-rows:calc(12px)"><div class="item"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:20px"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> <div class="grid" style="grid-template-rows:calc(18px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(21px/0.9)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:26px"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 36px"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 36px"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> </div> <div style="float:left" class="maxw"> <div class="grid" style="grid-template-rows:calc(12px)"><div class="item"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:20px"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> <div class="grid" style="grid-template-rows:calc(18px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(21px/.9)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:26px"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 36px"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 36px"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> </div> <div style="float:left" class="minw"> <div class="grid" style="grid-template-rows:calc(12px)"><div class="item"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:20px"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> <div class="grid" style="grid-template-rows:calc(18px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(21px/.9)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:26px"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 36px"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 36px"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> </div> <div style="float:left"> -<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(22.5px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(30px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(30px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:20px"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:28px"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:34px"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 54px"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> </div> <br clear="all"> <div style="float:left" class="maxw"> -<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(22.5px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(30px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(30px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:20px"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:28px"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:34px"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 54px"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> </div> <div style="float:left" class="minw"> -<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(22.5px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:calc(30px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-rows:0 calc(30px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:20px"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 30px"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:28px"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:34px"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-rows:0 54px"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> </div> </body> </html>
--- a/layout/reftests/css-grid/grid-item-sizing-percent-004-ref.html +++ b/layout/reftests/css-grid/grid-item-sizing-percent-004-ref.html @@ -57,78 +57,78 @@ a { background: blue; } </style> </head> <body> <div style="float:left"> <div class="grid" style="grid-template-columns:calc(10px)"><div class="item"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(18.75px)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(18.75px)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:15px"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 15px"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> <div class="grid" style="grid-template-columns:calc(16px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(26.25px)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(51.25px)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(26.25px)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:21px"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 41px"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 21px"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> </div> <br clear="all"> <div style="float:left" class="maxw"> <div class="grid" style="grid-template-columns:calc(30px)"><div class="item"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(43.75px)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:35px"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> <div class="grid" style="grid-template-columns:calc(36px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(51.25px)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(51.25px)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(51.25px)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:41px"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 41px"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 41px"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> </div> <br clear="all"> <div style="float:left" class="minw"> <div class="grid" style="grid-template-columns:calc(10px)"><div class="item"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(18.75px)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(18.75px)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:15px"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 15px"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div> <div class="grid" style="grid-template-columns:calc(16px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(26.25px)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(51.25px)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(26.25px)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:21px"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 41px"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 21px"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div> </div> <div style="float:left"> -<div class="grid" style="grid-template-columns:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(35px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(20px/.7)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(37.15px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(37.15px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:15px"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 15px"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:20px"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:26px"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 26px"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> </div> <br clear="all"> <div style="float:left" class="maxw"> -<div class="grid" style="grid-template-columns:calc(35px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(35px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(35px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(57.15px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(46px/.7)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(46px/.7)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:35px"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:40px"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:46px"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 46px"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> </div> <div style="float:left" class="minw"> -<div class="grid" style="grid-template-columns:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(35px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(20px/.7)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:calc(37.15px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> -<div class="grid" style="grid-template-columns:0 calc(37.15px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:15px"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 35px"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 15px"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:20px"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:26px"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div> +<div class="grid" style="grid-template-columns:0 26px"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div> </div> </body> </html>
--- a/layout/reftests/css-grid/grid-percent-grid-gap-001-ref.html +++ b/layout/reftests/css-grid/grid-percent-grid-gap-001-ref.html @@ -60,26 +60,26 @@ br { clear: both; } <span><x></x></span> <span><x></x></span> <span><x></x></span> <span><x></x></span> </div> </div> <div class="float"> -<div class="grid" style="align-self:start; justify-self:start; grid-gap:15px"> +<div class="grid" style="width:60px; height:60px; grid-column-gap:12px"> <span><x></x></span> <span><x></x></span> <span><x></x></span> <span><x></x></span> </div> </div> <div class="inline-grid"> -<div class="grid" style="align-self:start; justify-self:start; grid-gap:15px"> +<div class="grid" style="width:60px; height:60px; grid-column-gap:12px; align-self:start; justify-self:start;"> <span><x></x></span> <span><x></x></span> <span><x></x></span> <span><x></x></span> </div> </div> <br> @@ -136,19 +136,19 @@ br { clear: both; } <div class="grid calcgap" style="height:120px; grid-gap:0"> <span><x></x></span> <span><x></x></span> <span><x></x></span> <span><x></x></span> </div> </div> -<div class="float" style="margin-top:-50px"> -<div class="grid" style="min-width:300%; grid-gap:15px 15px"> - <span><x></x></span> - <span style="margin-left:31px; width:30px"><x></x></span> - <span><x></x></span> - <span style="margin-left:31px; width:30px"><x></x></span> +<div class="float" style="margin-top:-50px; width:62px"> +<div class="grid" style="padding-left:186px; height:60px; grid-column-gap:calc(186px * 0.2);"> + <span style="margin-left:-186px; width:30px"><x></x></span> + <span style="margin-left:-186px; width:30px"><x></x></span> + <span style="margin-left:-186px; width:30px"><x></x></span> + <span style="margin-left:-186px; width:30px"><x></x></span> </div> </div> </body> </html>
--- a/layout/reftests/css-grid/grid-repeat-auto-fill-fit-002-ref.html +++ b/layout/reftests/css-grid/grid-repeat-auto-fill-fit-002-ref.html @@ -78,22 +78,26 @@ x:last-child { fill,fit { float: left; height: 400px; } .zero-progress { grid-row-gap: calc(10px - 1%); - grid-template-rows: [a] 10px repeat(4, [b] minmax(0,auto) [c]) [d]; + grid-template-rows: [a] 10px repeat(3, [b] 0 [c]) [d]; } .w50.zero-progress { grid-row-gap: calc(10px - 1%); grid-template-rows: [a] 10px repeat(3, [b] 0 [c]) [d]; } +.mw50.zero-progress { + grid-row-gap: calc(10px - 1%); + grid-template-rows: [a] 10px repeat(4, [b] 0 [c]) [d]; +} </style> </head> <body> <fill> <div class="grid r1"><x></x><x></x><a></a><b></b><x></x></div> <div class="grid r1 float"><x></x><x></x><a></a><b></b><x></x></div>
--- a/layout/reftests/css-grid/reftest.list +++ b/layout/reftests/css-grid/reftest.list @@ -47,29 +47,29 @@ fails == grid-item-sizing-percent-002.ht == grid-item-sizing-percent-003.html grid-item-sizing-percent-003-ref.html == grid-item-sizing-percent-004.html grid-item-sizing-percent-004-ref.html == grid-item-sizing-px-001.html grid-item-sizing-percent-001-ref.html == grid-item-dir-001.html grid-item-dir-001-ref.html fuzzy-if(winWidget,70,130) fuzzy-if(cocoaWidget,85,180) == grid-col-max-sizing-max-content-001.html grid-col-max-sizing-max-content-001-ref.html fuzzy-if(winWidget,70,130) fuzzy-if(cocoaWidget,85,180) == grid-col-max-sizing-max-content-002.html grid-col-max-sizing-max-content-002-ref.html == grid-min-max-content-sizing-001.html grid-min-max-content-sizing-001-ref.html == grid-min-max-content-sizing-002.html grid-min-max-content-sizing-002-ref.html -# fails fuzzy-if(winWidget,1,36) == grid-auto-min-sizing-definite-001.html grid-auto-min-sizing-definite-001-ref.html +fuzzy-if(winWidget,1,36) == grid-auto-min-sizing-definite-001.html grid-auto-min-sizing-definite-001-ref.html == grid-auto-min-sizing-intrinsic-001.html grid-auto-min-sizing-intrinsic-001-ref.html == grid-auto-min-sizing-intrinsic-002.html grid-auto-min-sizing-intrinsic-002-ref.html == grid-auto-min-sizing-intrinsic-003.html grid-auto-min-sizing-intrinsic-003-ref.html == grid-auto-min-sizing-intrinsic-004.html grid-auto-min-sizing-intrinsic-004-ref.html == grid-auto-min-sizing-transferred-size-001.html grid-auto-min-sizing-transferred-size-001-ref.html -fails == grid-auto-min-sizing-transferred-size-002.html grid-auto-min-sizing-transferred-size-002-ref.html +== grid-auto-min-sizing-transferred-size-002.html grid-auto-min-sizing-transferred-size-002-ref.html == grid-auto-min-sizing-transferred-size-003.html grid-auto-min-sizing-transferred-size-003-ref.html -fails == grid-auto-min-sizing-transferred-size-004.html grid-auto-min-sizing-transferred-size-004-ref.html +== grid-auto-min-sizing-transferred-size-004.html grid-auto-min-sizing-transferred-size-004-ref.html == grid-auto-min-sizing-min-content-min-size-001.html grid-auto-min-sizing-min-content-min-size-001-ref.html -fails == grid-auto-min-sizing-min-content-min-size-002.html grid-auto-min-sizing-min-content-min-size-002-ref.html +== grid-auto-min-sizing-min-content-min-size-002.html grid-auto-min-sizing-min-content-min-size-002-ref.html == grid-auto-min-sizing-min-content-min-size-003.html grid-auto-min-sizing-min-content-min-size-003-ref.html -fails == grid-auto-min-sizing-min-content-min-size-004.html grid-auto-min-sizing-min-content-min-size-004-ref.html +== grid-auto-min-sizing-min-content-min-size-004.html grid-auto-min-sizing-min-content-min-size-004-ref.html == grid-min-content-min-sizing-transferred-size-001.html grid-min-content-min-sizing-transferred-size-001-ref.html == grid-min-content-min-sizing-transferred-size-002.html grid-min-content-min-sizing-transferred-size-002-ref.html == grid-min-content-min-sizing-transferred-size-003.html grid-min-content-min-sizing-transferred-size-003-ref.html == grid-min-content-min-sizing-transferred-size-004.html grid-min-content-min-sizing-transferred-size-004-ref.html skip-if(Android) == grid-auto-min-sizing-percent-001.html grid-auto-min-sizing-percent-001-ref.html # bug 1305716 == grid-track-intrinsic-sizing-001.html grid-track-intrinsic-sizing-001-ref.html == grid-track-intrinsic-sizing-002.html grid-track-intrinsic-sizing-002-ref.html == grid-track-intrinsic-sizing-003.html grid-track-intrinsic-sizing-003-ref.html
--- a/layout/reftests/writing-mode/1174450-intrinsic-sizing-ref.html +++ b/layout/reftests/writing-mode/1174450-intrinsic-sizing-ref.html @@ -8,30 +8,30 @@ <title>Testcase for bug 1174450</title> <style type="text/css"> body,html { color:black; background:white; font-size:12px; line-height:16px; padding:0; margin:0; } div.v, div.h { display: block; position: relative; border: 1px dashed silver; - width:92px; - height:60px; + width:74px; + height:24px; } div.h { - width:124px; - height:98px; + width:62px; + height:61.2px; } .h span { - margin: 7px 13px 62px 25px; - padding: 1px 3px 12px 37px; + margin: 7px 13px 32px 12px; + padding: 1px 3px 6px 19px; } .v span { - margin: 7px 13px 30px 12px; - padding: 1px 3px 6px 18px; + margin: 7px 13px 30px 5px; + padding: 1px 3px 2px 7px; } span { display: block; position: absolute; width: 30px; height: 10px; background: lime;
--- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -772,22 +772,22 @@ nsTableCellFrame::GetPrefISize(gfxContex nsIFrame *inner = mFrames.FirstChild(); result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner, nsLayoutUtils::PREF_ISIZE); return result; } /* virtual */ nsIFrame::IntrinsicISizeOffsetData -nsTableCellFrame::IntrinsicISizeOffsets() +nsTableCellFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis) { - IntrinsicISizeOffsetData result = nsContainerFrame::IntrinsicISizeOffsets(); + IntrinsicISizeOffsetData result = + nsContainerFrame::IntrinsicISizeOffsets(aPercentageBasis); result.hMargin = 0; - result.hPctMargin = 0; WritingMode wm = GetWritingMode(); result.hBorder = GetBorderWidth(wm).IStartEnd(wm); return result; } #ifdef DEBUG
--- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -105,17 +105,18 @@ public: const nsDisplayListSet& aLists) override; virtual nsresult ProcessBorders(nsTableFrame* aFrame, nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists); virtual nscoord GetMinISize(gfxContext *aRenderingContext) override; virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override; - virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() override; + IntrinsicISizeOffsetData IntrinsicISizeOffsets(nscoord aPercentageBasis = + NS_UNCONSTRAINEDSIZE) override; virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) override; #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override;
--- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1766,26 +1766,25 @@ nsTableFrame::GetPrefISize(gfxContext *a CalcBCBorders(); ReflowColGroups(aRenderingContext); return LayoutStrategy()->GetPrefISize(aRenderingContext, false); } /* virtual */ nsIFrame::IntrinsicISizeOffsetData -nsTableFrame::IntrinsicISizeOffsets() -{ - IntrinsicISizeOffsetData result = nsContainerFrame::IntrinsicISizeOffsets(); +nsTableFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis) +{ + IntrinsicISizeOffsetData result = + nsContainerFrame::IntrinsicISizeOffsets(aPercentageBasis); result.hMargin = 0; - result.hPctMargin = 0; if (IsBorderCollapse()) { result.hPadding = 0; - result.hPctPadding = 0; WritingMode wm = GetWritingMode(); LogicalMargin outerBC = GetIncludedOuterBCBorder(wm); result.hBorder = outerBC.IStartEnd(wm); } return result; }
--- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -303,17 +303,18 @@ public: const mozilla::layers::StackingContextHelper& aSc, const nsPoint& aPt); virtual void MarkIntrinsicISizesDirty() override; // For border-collapse tables, the caller must not add padding and // border to the results of these functions. virtual nscoord GetMinISize(gfxContext *aRenderingContext) override; virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override; - virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() override; + IntrinsicISizeOffsetData IntrinsicISizeOffsets(nscoord aPercentageBasis = + NS_UNCONSTRAINEDSIZE) override; virtual mozilla::LogicalSize ComputeSize(gfxContext* aRenderingContext, mozilla::WritingMode aWM, const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize, const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder,
--- a/layout/xul/BoxObject.cpp +++ b/layout/xul/BoxObject.cpp @@ -9,21 +9,17 @@ #include "nsIDocument.h" #include "nsIPresShell.h" #include "nsPresContext.h" #include "nsIContent.h" #include "nsContainerFrame.h" #include "nsIDocShell.h" #include "nsReadableUtils.h" #include "nsView.h" -#ifdef MOZ_XUL -#include "nsIDOMXULElement.h" -#else #include "nsIDOMElement.h" -#endif #include "nsLayoutUtils.h" #include "nsISupportsPrimitives.h" #include "nsSupportsPrimitives.h" #include "mozilla/dom/Element.h" #include "nsComponentManagerUtils.h" #include "mozilla/dom/BoxObjectBinding.h" // Implementation /////////////////////////////////////////////////////////////////
--- a/layout/xul/nsBoxFrame.cpp +++ b/layout/xul/nsBoxFrame.cpp @@ -1386,17 +1386,17 @@ nsBoxFrame::BuildDisplayList(nsDisplayLi DisplayListClipState::AutoSaveRestore ownLayerClipState(aBuilder); // Wrap the list to make it its own layer aLists.Content()->AppendToTop( MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, this, &masterList, ownLayerASR, nsDisplayOwnLayerFlags::eNone, mozilla::layers::FrameMetrics::NULL_SCROLL_ID, - mozilla::layers::ScrollThumbData{}, true, true)); + mozilla::layers::ScrollbarData{}, true, true)); } } void nsBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { nsIFrame* kid = mFrames.FirstChild();
--- a/layout/xul/nsSliderFrame.cpp +++ b/layout/xul/nsSliderFrame.cpp @@ -49,17 +49,17 @@ #include "mozilla/layers/InputAPZContext.h" #include <algorithm> using namespace mozilla; using mozilla::layers::APZCCallbackHelper; using mozilla::layers::AsyncDragMetrics; using mozilla::layers::InputAPZContext; using mozilla::layers::ScrollDirection; -using mozilla::layers::ScrollThumbData; +using mozilla::layers::ScrollbarData; bool nsSliderFrame::gMiddlePref = false; int32_t nsSliderFrame::gSnapMultiplier; // Turn this on if you want to debug slider frames. #undef DEBUG_SLIDER static already_AddRefed<nsIContent> @@ -455,23 +455,24 @@ nsSliderFrame::BuildDisplayListForChildr // Restore the saved clip so it applies to the thumb container layer. thumbContentsClipState.Restore(); // Wrap the list to make it its own layer. const ActiveScrolledRoot* ownLayerASR = contASRTracker.GetContainerASR(); aLists.Content()->AppendToTop( MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, this, &masterList, ownLayerASR, flags, scrollTargetId, - ScrollThumbData{scrollDirection, - GetThumbRatio(), - thumbStart, - thumbLength, - isAsyncDraggable, - sliderTrackStart, - sliderTrackLength})); + ScrollbarData{scrollDirection, + layers::ScrollbarLayerType::Thumb, + GetThumbRatio(), + thumbStart, + thumbLength, + isAsyncDraggable, + sliderTrackStart, + sliderTrackLength})); return; } } nsBoxFrame::BuildDisplayListForChildren(aBuilder, aLists); }
--- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -31,17 +31,16 @@ #include "nsCSSAnonBoxes.h" #include "gfxContext.h" #include "nsIContent.h" #include "mozilla/ComputedStyle.h" #include "nsIBoxObject.h" #include "nsIDOMElement.h" #include "nsIDOMNodeList.h" -#include "nsIDOMXULElement.h" #include "nsIDocument.h" #include "nsCSSRendering.h" #include "nsString.h" #include "nsContainerFrame.h" #include "nsView.h" #include "nsViewManager.h" #include "nsVariant.h" #include "nsWidgetsCID.h"
--- a/mobile/android/components/extensions/ext-android.js +++ b/mobile/android/components/extensions/ext-android.js @@ -5,17 +5,17 @@ const getSender = (extension, target, sender) => { let tabId = -1; if ("tabId" in sender) { // The message came from a privileged extension page running in a tab. In // that case, it should include a tabId property (which is filled in by the // page-open listener below). tabId = sender.tabId; delete sender.tabId; - } else if (target instanceof Ci.nsIDOMXULElement) { + } else if (ChromeUtils.getClassName(target) == "XULElement") { tabId = tabTracker.getBrowserData(target).tabId; } if (tabId != null && tabId >= 0) { let tab = extension.tabManager.get(tabId, null); if (tab) { sender.tab = tab.convert(); }
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5838,8 +5838,12 @@ pref("layers.omtp.paint-workers", 1); #endif pref("layers.omtp.release-capture-on-main-thread", false); pref("layers.omtp.dump-capture", false); // Limits the depth of recursive conversion of data when opening // a content to view. This is mostly intended to prevent infinite // loops with faulty converters involved. pref("general.document_open_conversion_depth_limit", 20); + +// If true, touchstart and touchmove listeners on window, document, +// documentElement and document.body are passive by default. +pref("dom.event.default_to_passive_touch_listeners", false);
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm +++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm @@ -254,21 +254,26 @@ var BrowserTestUtils = { * @param {xul:browser} browser * A xul:browser. * @param {Boolean} includeSubFrames * A boolean indicating if loads from subframes should be included. * @param {optional string or function} wantLoad * If a function, takes a URL and returns true if that's the load we're * interested in. If a string, gives the URL of the load we're interested * in. If not present, the first load resolves the promise. + * @param {optional boolean} maybeErrorPage + * If true, this uses DOMContentLoaded event instead of load event. + * Also wantLoad will be called with visible URL, instead of + * 'about:neterror?...' for error page. * * @return {Promise} * @resolves When a load event is triggered for the browser. */ - browserLoaded(browser, includeSubFrames=false, wantLoad=null) { + browserLoaded(browser, includeSubFrames=false, wantLoad=null, + maybeErrorPage=false) { // Passing a url as second argument is a common mistake we should prevent. if (includeSubFrames && typeof includeSubFrames != "boolean") { throw("The second argument to browserLoaded should be a boolean."); } // If browser belongs to tabbrowser-tab, ensure it has been // inserted into the document. let tabbrowser = browser.ownerGlobal.gBrowser; @@ -284,21 +289,27 @@ var BrowserTestUtils = { } else { // It's a string. return wantLoad == url; } } return new Promise(resolve => { let mm = browser.ownerGlobal.messageManager; - mm.addMessageListener("browser-test-utils:loadEvent", function onLoad(msg) { + let eventName = maybeErrorPage + ? "browser-test-utils:DOMContentLoadedEvent" + : "browser-test-utils:loadEvent"; + mm.addMessageListener(eventName, function onLoad(msg) { + // See testing/mochitest/BrowserTestUtils/content/content-utils.js for + // the difference between visibleURL and internalURL. if (msg.target == browser && (!msg.data.subframe || includeSubFrames) && - isWanted(msg.data.url)) { - mm.removeMessageListener("browser-test-utils:loadEvent", onLoad); - resolve(msg.data.url); + isWanted(maybeErrorPage + ? msg.data.visibleURL : msg.data.internalURL)) { + mm.removeMessageListener(eventName, onLoad); + resolve(msg.data.internalURL); } }); }); }, /** * Waits for the selected browser to load in a new window. This * is most useful when you've got a window that might not have @@ -475,54 +486,89 @@ var BrowserTestUtils = { }; tabbrowser.addTabsProgressListener(progressListener); }); }, /** * Waits for the next browser window to open and be fully loaded. * - * @param {string} initialBrowserLoaded (optional) - * If set, we will wait until the initial browser in the new - * window has loaded a particular page. If unset, the initial - * browser may or may not have finished loading its first page - * when the resulting Promise resolves. + * @param aParams + * { + * url: A string (optional). If set, we will wait until the initial + * browser in the new window has loaded a particular page. + * If unset, the initial browser may or may not have finished + * loading its first page when the resulting Promise resolves. + * anyWindow: True to wait for the url to be loaded in any new + * window, not just the next one opened. + * maybeErrorPage: See browserLoaded function. + * } * @return {Promise} * A Promise which resolves the next time that a DOM window * opens and the delayed startup observer notification fires. */ - async waitForNewWindow(initialBrowserLoaded=null) { - let win = await this.domWindowOpened(); - - let promises = [ - TestUtils.topicObserved("browser-delayed-startup-finished", - subject => subject == win), - ]; - - if (initialBrowserLoaded) { - await this.waitForEvent(win, "DOMContentLoaded"); + waitForNewWindow(aParams = {}) { + let { + url = null, + anyWindow = false, + maybeErrorPage = false, + } = aParams; - let browser = win.gBrowser.selectedBrowser; - - // Retrieve the given browser's current process type. - let process = - browser.isRemoteBrowser ? Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT - : Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; - if (win.gMultiProcessBrowser && - !E10SUtils.canLoadURIInProcess(initialBrowserLoaded, process)) { - await this.waitForEvent(browser, "XULFrameLoaderCreated"); - } - - let loadPromise = this.browserLoaded(browser, false, initialBrowserLoaded); - promises.push(loadPromise); + if (anyWindow && !url) { + throw new Error("url should be specified if anyWindow is true"); } - await Promise.all(promises); + return new Promise(resolve => { + let observe = async (win, topic, data) => { + if (topic != "domwindowopened") { + return; + } + + if (!anyWindow) { + Services.ww.unregisterNotification(observe); + } + + if (url) { + await this.waitForEvent(win, "DOMContentLoaded"); + + if (win.document.documentURI != "chrome://browser/content/browser.xul") { + return; + } + } + + let promises = [ + TestUtils.topicObserved("browser-delayed-startup-finished", + subject => subject == win), + ]; - return win; + if (url) { + let browser = win.gBrowser.selectedBrowser; + + // Retrieve the given browser's current process type. + let process = + browser.isRemoteBrowser ? Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT + : Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; + if (win.gMultiProcessBrowser && + !E10SUtils.canLoadURIInProcess(url, process)) { + await this.waitForEvent(browser, "XULFrameLoaderCreated"); + } + + let loadPromise = this.browserLoaded(browser, false, url, maybeErrorPage); + promises.push(loadPromise); + } + + await Promise.all(promises); + + if (anyWindow) { + Services.ww.unregisterNotification(observe); + } + resolve(win); + }; + Services.ww.registerNotification(observe); + }); }, /** * Loads a new URI in the given browser and waits until we really started * loading. In e10s browser.loadURI() can be an asynchronous operation due * to having to switch the browser's remoteness and keep its shistory data. * * @param {xul:browser} browser
--- a/testing/mochitest/BrowserTestUtils/content/content-utils.js +++ b/testing/mochitest/BrowserTestUtils/content/content-utils.js @@ -1,14 +1,24 @@ /* 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/. */ "use strict"; ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); +addEventListener("DOMContentLoaded", function(event) { + let subframe = event.target != content.document; + // For error page, internalURL is 'about:neterror?...', and visibleURL + // is the original URL. + sendAsyncMessage("browser-test-utils:DOMContentLoadedEvent", + {subframe: subframe, internalURL: event.target.documentURI, + visibleURL: content.document.location.href}); +}, true); + addEventListener("load", function(event) { let subframe = event.target != content.document; sendAsyncMessage("browser-test-utils:loadEvent", - {subframe: subframe, url: event.target.documentURI}); + {subframe: subframe, internalURL: event.target.documentURI, + visibleURL: content.document.location.href}); }, true);
deleted file mode 100644 --- a/testing/web-platform/meta/css/css-grid/alignment/grid-gutters-010.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[grid-gutters-010.html] - expected: FAIL
--- a/toolkit/components/find/nsFind.cpp +++ b/toolkit/components/find/nsFind.cpp @@ -790,18 +790,18 @@ nsFind::PeekNextChar(nsRange* aSearchRan do { tc = nullptr; NextNode(aSearchRange, aStartPoint, aEndPoint, false); // Get the text content: tc = do_QueryInterface(mIterNode); // Get the block parent. - nsCOMPtr<nsIDOMNode> blockParent; - rv = GetBlockParent(mIterNode->AsDOMNode(), getter_AddRefs(blockParent)); + nsCOMPtr<nsINode> blockParent; + rv = GetBlockParent(mIterNode, getter_AddRefs(blockParent)); if (NS_FAILED(rv)) return L'\0'; // If out of nodes or in new parent. if (!mIterNode || !tc || (blockParent != mLastBlockParent)) return L'\0'; frag = tc->GetText(); @@ -890,27 +890,23 @@ nsFind::SkipNode(nsIContent* aContent) content = content->GetParent(); } return false; #endif /* HAVE_BIDI_ITERATOR */ } nsresult -nsFind::GetBlockParent(nsIDOMNode* aNode, nsIDOMNode** aParent) +nsFind::GetBlockParent(nsINode* aNode, nsINode** aParent) { - nsCOMPtr<nsINode> node = do_QueryInterface(aNode); - // non-nsCOMPtr temporary so we don't keep addrefing/releasing as we - // go up the tree. - nsINode* curNode = node; + nsINode* curNode = aNode; while (curNode) { nsIContent* parent = curNode->GetParent(); if (parent && IsBlockNode(parent)) { - *aParent = parent->AsDOMNode(); - NS_ADDREF(*aParent); + *aParent = do_AddRef(parent).take(); return NS_OK; } curNode = parent; } return NS_ERROR_FAILURE; } // Call ResetAll before returning, to remove all references to external objects. @@ -1025,18 +1021,18 @@ nsFind::Find(const char16_t* aPatText, n // to search again (from beginning/end). ResetAll(); return NS_OK; } // We have a new text content. If its block parent is different from the // block parent of the last text content, then we need to clear the match // since we don't want to find across block boundaries. - nsCOMPtr<nsIDOMNode> blockParent; - GetBlockParent(mIterNode->AsDOMNode(), getter_AddRefs(blockParent)); + nsCOMPtr<nsINode> blockParent; + GetBlockParent(mIterNode, getter_AddRefs(blockParent)); #ifdef DEBUG_FIND printf("New node: old blockparent = %p, new = %p\n", (void*)mLastBlockParent.get(), (void*)blockParent.get()); #endif if (blockParent != mLastBlockParent) { #ifdef DEBUG_FIND printf("Different block parent!\n"); #endif
--- a/toolkit/components/find/nsFind.h +++ b/toolkit/components/find/nsFind.h @@ -45,18 +45,18 @@ protected: // Use "find entire words" mode by setting to a word breaker or null, to // disable "entire words" mode. RefPtr<mozilla::intl::WordBreaker> mWordBreaker; int32_t mIterOffset; nsCOMPtr<nsINode> mIterNode; // Last block parent, so that we will notice crossing block boundaries: - nsCOMPtr<nsIDOMNode> mLastBlockParent; - nsresult GetBlockParent(nsIDOMNode* aNode, nsIDOMNode** aParent); + nsCOMPtr<nsINode> mLastBlockParent; + nsresult GetBlockParent(nsINode* aNode, nsINode** aParent); // Utility routines: bool IsBlockNode(nsIContent* aNode); bool SkipNode(nsIContent* aNode); bool IsVisibleNode(nsINode* aNode); // Move in the right direction for our search: nsresult NextNode(nsRange* aSearchRange,
--- a/toolkit/components/reader/ReaderMode.jsm +++ b/toolkit/components/reader/ReaderMode.jsm @@ -27,17 +27,17 @@ const CLASSES_TO_PRESERVE = [ "visuallyhidden", "wp-caption", "wp-caption-text", ]; ChromeUtils.import("resource://gre/modules/Services.jsm"); ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.importGlobalProperties(["XMLHttpRequest"]); +Cu.importGlobalProperties(["XMLHttpRequest", "XMLSerializer"]); ChromeUtils.defineModuleGetter(this, "CommonUtils", "resource://services-common/utils.js"); ChromeUtils.defineModuleGetter(this, "EventDispatcher", "resource://gre/modules/Messaging.jsm"); ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); ChromeUtils.defineModuleGetter(this, "ReaderWorker", "resource://gre/modules/reader/ReaderWorker.jsm"); ChromeUtils.defineModuleGetter(this, "TelemetryStopwatch", "resource://gre/modules/TelemetryStopwatch.jsm"); ChromeUtils.defineModuleGetter(this, "LanguageDetector", "resource:///modules/translation/LanguageDetector.jsm"); @@ -466,18 +466,17 @@ var ReaderMode = { let uriParam = { spec: doc.baseURIObject.spec, host: doc.baseURIObject.host, prePath: doc.baseURIObject.prePath, scheme: doc.baseURIObject.scheme, pathBase: Services.io.newURI(".", null, doc.baseURIObject).spec }; - let serializer = Cc["@mozilla.org/xmlextras/xmlserializer;1"]. - createInstance(Ci.nsIDOMSerializer); + let serializer = new XMLSerializer(); let serializedDoc = serializer.serializeToString(doc); let options = { classesToPreserve: CLASSES_TO_PRESERVE, }; let article = null; try {
--- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -288,17 +288,17 @@ "expires_in_version": "never", "description": "Time from vsync to finishing a composite in milliseconds.", "kind": "exponential", "high": 1000, "n_buckets": 50 }, "CONTENT_PROCESS_LAUNCH_TIME_MS" : { "record_in_processes": ["main", "content"], - "alert_emails": ["bsmedberg@mozilla.com", "mconley@mozilla.com"], + "alert_emails": ["fgomes@mozilla.com", "mconley@mozilla.com"], "expires_in_version": "57", "bug_numbers": [1304790], "kind": "exponential", "high": 64000, "n_buckets": 100, "releaseChannelCollection": "opt-out", "description": "Content process launch time until the GetXPCOMProcessAttributes message is received, in milliseconds" }, @@ -1922,64 +1922,64 @@ "bug_numbers": [1377340], "kind": "categorical", "labels": ["NetworkNoRace", "CacheNoRace", "NetworkRace", "CacheRace", "NetworkDelayedRace", "CacheDelayedRace"], "description": "Whether we raced network with the cache." }, "NETWORK_RACE_CACHE_WITH_NETWORK_SAVED_TIME": { "record_in_processes": ["main", "content"], "expires_in_version": "62", - "alert_emails": ["necko@mozilla.com", "bsmedberg@mozilla.com"], + "alert_emails": ["necko@mozilla.com"], "bug_numbers": [1354407], "kind": "exponential", "high": 60000, "n_buckets": 100, "description": "Time in milliseconds that we saved when we race cache with network." }, "NETWORK_RACE_CACHE_WITH_NETWORK_OCEC_ON_START_DIFF": { "record_in_processes": ["main", "content"], "expires_in_version": "62", - "alert_emails": ["necko@mozilla.com", "bsmedberg@mozilla.com"], + "alert_emails": ["necko@mozilla.com"], "bug_numbers": [1354407], "kind": "linear", "high": 1000, "n_buckets": 100, "description": "Time in milliseconds between onStartRequest from the cache and onCacheEntryCheck. Report only when net wins and OCEC is before onStartRequest from net." }, "NETWORK_RACE_CACHE_BANDWIDTH_RACE_NETWORK_WIN": { "record_in_processes": ["main", "content"], "expires_in_version": "62", "kind": "exponential", "low": 32, "high": 16777216, "n_buckets": 100, "description": "Amount of bytes received when we decide to race cache with network and network wins.", - "alert_emails": ["necko@mozilla.com", "bsmedberg@mozilla.com"], + "alert_emails": ["necko@mozilla.com"], "bug_numbers": [1354405] }, "NETWORK_RACE_CACHE_BANDWIDTH_RACE_CACHE_WIN": { "record_in_processes": ["main", "content"], "expires_in_version": "62", "kind": "exponential", "low": 32, "high": 16777216, "n_buckets": 100, "description": "Amount of bytes received when we decide to race cache with network and cache wins.", - "alert_emails": ["necko@mozilla.com", "bsmedberg@mozilla.com"], + "alert_emails": ["necko@mozilla.com"], "bug_numbers": [1354405] }, "NETWORK_RACE_CACHE_BANDWIDTH_NOT_RACE": { "record_in_processes": ["main", "content"], "expires_in_version": "62", "kind": "exponential", "low": 32, "high": 16777216, "n_buckets": 100, "description": "Amount of bytes received when we decide not to race cache with network.", - "alert_emails": ["necko@mozilla.com", "bsmedberg@mozilla.com"], + "alert_emails": ["necko@mozilla.com"], "bug_numbers": [1354405] }, "NETWORK_RACE_CACHE_VALIDATION": { "record_in_processes": ["main"], "expires_in_version": "62", "alert_emails": ["necko@mozilla.com"], "bug_numbers": [1377223], "kind": "categorical", @@ -7977,77 +7977,77 @@ "kind": "exponential", "high": 10000, "n_buckets": 50, "description": "Time spent to display first page in PDF Viewer (ms)" }, "PLUGINS_NOTIFICATION_SHOWN": { "record_in_processes": ["main", "content"], "releaseChannelCollection": "opt-out", - "expires_in_version": "60", + "expires_in_version": "never", "kind": "boolean", "description": "The number of times the click-to-activate notification was shown: false: shown by in-content activation true: shown by location bar activation", "bug_numbers": [902075, 1345894], - "alert_emails": ["bsmedberg@mozilla.com"] + "alert_emails": ["flashvideo-2015@mozilla.com"] }, "PLUGINS_NOTIFICATION_PLUGIN_COUNT": { "record_in_processes": ["main", "content"], "releaseChannelCollection": "opt-out", - "expires_in_version": "60", + "expires_in_version": "never", "kind": "enumerated", "n_values": 5, "description": "The number of plugins present in the click-to-activate notification, minus one (1, 2, 3, 4, more than 4)", "bug_numbers": [902075, 1345894], - "alert_emails": ["bsmedberg@mozilla.com"] + "alert_emails": ["flashvideo-2015@mozilla.com"] }, "PLUGINS_NOTIFICATION_USER_ACTION_2": { "record_in_processes": ["main", "content"], "releaseChannelCollection": "opt-out", - "expires_in_version": "60", + "expires_in_version": "never", "kind": "enumerated", "n_values": 8, "description": "User actions taken in the plugin notification: 0: allownow 1: allowalways 2: block 3: blockalways", "bug_numbers": [902075, 1345894, 1398972], - "alert_emails": ["bsmedberg@mozilla.com"] + "alert_emails": ["flashvideo-2015@mozilla.com"] }, "PLUGINS_INFOBAR_SHOWN": { "record_in_processes": ["main"], "releaseChannelCollection": "opt-out", - "expires_in_version": "60", + "expires_in_version": "never", "kind": "boolean", "description": "Count of when the hidden-plugin infobar was displayed.", "bug_numbers": [902075, 1345894], - "alert_emails": ["bsmedberg@mozilla.com"] + "alert_emails": ["flashvideo-2015@mozilla.com"] }, "PLUGINS_INFOBAR_BLOCK": { "record_in_processes": ["main"], "releaseChannelCollection": "opt-out", - "expires_in_version": "60", + "expires_in_version": "never", "kind": "boolean", "description": "Count the number of times the user clicked 'block' on the hidden-plugin infobar.", "bug_numbers": [902075, 1345894], - "alert_emails": ["bsmedberg@mozilla.com"] + "alert_emails": ["flashvideo-2015@mozilla.com"] }, "PLUGINS_INFOBAR_ALLOW": { "record_in_processes": ["main"], "releaseChannelCollection": "opt-out", - "expires_in_version": "60", + "expires_in_version": "never", "kind": "boolean", "description": "Count the number of times the user clicked 'allow' on the hidden-plugin infobar.", "bug_numbers": [902075, 1345894], - "alert_emails": ["bsmedberg@mozilla.com"] + "alert_emails": ["flashvideo-2015@mozilla.com"] }, "PLUGINS_INFOBAR_DISMISSED": { "record_in_processes": ["main"], "releaseChannelCollection": "opt-out", - "expires_in_version": "60", + "expires_in_version": "never", "kind": "boolean", "description": "Count the number of times the user explicitly dismisses the hidden-plugin infobar without choosing allow or continue-blocking.", "bug_numbers": [1368060], - "alert_emails": ["bsmedberg@mozilla.com"] + "alert_emails": ["flashvideo-2015@mozilla.com"] }, "POPUP_NOTIFICATION_STATS": { "record_in_processes": ["main", "content"], "releaseChannelCollection": "opt-out", "alert_emails": ["firefox-dev@mozilla.org"], "bug_numbers": [1207089], "expires_in_version": "55", "kind": "enumerated",
--- a/toolkit/components/thumbnails/PageThumbUtils.jsm +++ b/toolkit/components/thumbnails/PageThumbUtils.jsm @@ -295,17 +295,17 @@ var PageThumbUtils = { shouldStoreContentThumbnail(aDocument, aDocShell) { if (BrowserUtils.isToolbarVisible(aDocShell, "findbar")) { return false; } // FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as // that currently regresses Talos SVG tests. - if (aDocument instanceof Ci.nsIDOMXMLDocument) { + if (ChromeUtils.getClassName(aDocument) === "XMLDocument") { return false; } let webNav = aDocShell.QueryInterface(Ci.nsIWebNavigation); // Don't take screenshots of about: pages. if (webNav.currentURI.schemeIs("about")) { return false;
--- a/toolkit/components/windowcreator/test/browser_bug1204626.js +++ b/toolkit/components/windowcreator/test/browser_bug1204626.js @@ -6,18 +6,17 @@ const testPageURL = contentBase + "bug12 function one_test(delay, continuation) { let delayStr = delay === null ? "no delay" : "delay = " + delay + "ms"; let browser; BrowserTestUtils.openNewForegroundTab(gBrowser, testPageURL).then((tab) => { browser = tab.linkedBrowser; let persistable = browser.QueryInterface(Ci.nsIFrameLoaderOwner) - .frameLoader - .QueryInterface(Ci.nsIWebBrowserPersistable); + .frameLoader; persistable.startPersistence(/* outer window ID: */ 0, { onDocumentReady, onError(status) { ok(false, new Components.Exception("startPersistence failed", status)); continuation(); } }); });
--- a/toolkit/components/windowwatcher/test/browser_new_content_window_from_chrome_principal.js +++ b/toolkit/components/windowwatcher/test/browser_new_content_window_from_chrome_principal.js @@ -8,17 +8,17 @@ add_task(async function test_chrome_opens_window() { // This magic value of 2 means that by default, when content tries // to open a new window, it'll actually open in a new window instead // of a new tab. await SpecialPowers.pushPrefEnv({"set": [ ["browser.link.open_newwindow", 2], ]}); - let newWinPromise = BrowserTestUtils.waitForNewWindow("http://example.com/"); + let newWinPromise = BrowserTestUtils.waitForNewWindow({url: "http://example.com/"}); await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() { content.open("http://example.com/", "_blank"); }); let win = await newWinPromise; let browser = win.gBrowser.selectedBrowser;
--- a/toolkit/modules/PopupNotifications.jsm +++ b/toolkit/modules/PopupNotifications.jsm @@ -39,17 +39,17 @@ var gNotificationParents = new WeakMap; function getAnchorFromBrowser(aBrowser, aAnchorID) { let attrPrefix = aAnchorID ? aAnchorID.replace("notification-icon", "") : ""; let anchor = aBrowser.getAttribute(attrPrefix + ICON_ANCHOR_ATTRIBUTE) || aBrowser[attrPrefix + ICON_ANCHOR_ATTRIBUTE] || aBrowser.getAttribute(ICON_ANCHOR_ATTRIBUTE) || aBrowser[ICON_ANCHOR_ATTRIBUTE]; if (anchor) { - if (anchor instanceof Ci.nsIDOMXULElement) { + if (ChromeUtils.getClassName(anchor) == "XULElement") { return anchor; } return aBrowser.ownerDocument.getElementById(anchor); } return null; } function getNotificationFromElement(aElement) { @@ -208,19 +208,19 @@ Notification.prototype = { * suppressed for this window. This state is checked on construction * and when the "anchorVisibilityChange" method is called. * } */ function PopupNotifications(tabbrowser, panel, iconBox, options = {}) { if (!tabbrowser) throw "Invalid tabbrowser"; - if (iconBox && !(iconBox instanceof Ci.nsIDOMXULElement)) + if (iconBox && ChromeUtils.getClassName(iconBox) != "XULElement") throw "Invalid iconBox"; - if (!(panel instanceof Ci.nsIDOMXULElement)) + if (ChromeUtils.getClassName(panel) != "XULElement") throw "Invalid panel"; this._shouldSuppress = options.shouldSuppress || (() => false); this._suppress = this._shouldSuppress(); this.window = tabbrowser.ownerGlobal; this.panel = panel; this.tabbrowser = tabbrowser; @@ -1080,17 +1080,17 @@ PopupNotifications.prototype = { * browser tab * @param anchors is a XUL element or a Set of XUL elements that the * notifications panel(s) will be anchored to. * @param dismissShowing if true, dismiss any currently visible notifications * if there are no notifications to show. Otherwise, * currently displayed notifications will be left alone. */ _update: function PopupNotifications_update(notifications, anchors = new Set(), dismissShowing = false) { - if (anchors instanceof Ci.nsIDOMXULElement) + if (ChromeUtils.getClassName(anchors) == "XULElement") anchors = new Set([anchors]); if (!notifications) notifications = this._currentNotifications; let haveNotifications = notifications.length > 0; if (!anchors.size && haveNotifications) anchors = this._getAnchorsForNotifications(notifications);
--- a/toolkit/modules/WindowDraggingUtils.jsm +++ b/toolkit/modules/WindowDraggingUtils.jsm @@ -47,17 +47,17 @@ WindowDraggingElement.prototype = { while (target != this._elem) { if (!this.dragTags.includes(target.localName)) return false; target = target.parentNode; } return true; }, isPanel() { - return this._elem instanceof Ci.nsIDOMXULElement && + return ChromeUtils.getClassName(this._elem) == "XULElement" && this._elem.localName == "panel"; }, handleEvent(aEvent) { let isPanel = this.isPanel(); switch (aEvent.type) { case "mousedown": if (!this.shouldDrag(aEvent)) return;
--- a/toolkit/modules/addons/WebRequest.jsm +++ b/toolkit/modules/addons/WebRequest.jsm @@ -222,17 +222,17 @@ var ContentPolicyManager = { init() { Services.ppmm.initialProcessData.webRequestContentPolicies = this.policyData; Services.ppmm.addMessageListener("WebRequest:ShouldLoad", this); Services.mm.addMessageListener("WebRequest:ShouldLoad", this); }, receiveMessage(msg) { - let browser = msg.target instanceof Ci.nsIDOMXULElement ? msg.target : null; + let browser = ChromeUtils.getClassName(msg.target) == "XULElement" ? msg.target : null; let requestId = `fakeRequest-${++nextFakeRequestId}`; for (let id of msg.data.ids) { let callback = this.policies.get(id); if (!callback) { // It's possible that this listener has been removed and the // child hasn't learned yet. continue;
--- a/toolkit/modules/addons/WebRequestContent.js +++ b/toolkit/modules/addons/WebRequestContent.js @@ -122,17 +122,18 @@ var ContentPolicy = { function getWindowId(window) { return window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils) .outerWindowID; } if (policyType == Ci.nsIContentPolicy.TYPE_SUBDOCUMENT || - (node instanceof Ci.nsIDOMXULElement && node.localName == "browser")) { + (ChromeUtils.getClassName(node) == "XULElement" && + node.localName == "browser")) { // Chrome sets frameId to the ID of the sub-window. But when // Firefox loads an iframe, it sets |node| to the <iframe> // element, whose window is the parent window. We adopt the // Chrome behavior here. node = node.contentWindow; } if (node) {
--- a/uriloader/exthandler/tests/mochitest/browser_auto_close_window.js +++ b/uriloader/exthandler/tests/mochitest/browser_auto_close_window.js @@ -87,17 +87,17 @@ add_task(async function target_blank() { add_task(async function new_window() { // Tests that a link that forces us to open a new window (by specifying a // width and a height in window.open) opens a new window for the load, // realizes that we need to close that window and returns the *original* // window as the window context. await BrowserTestUtils.withNewTab({ gBrowser, url: URL }, async function(browser) { let dialogAppeared = promiseHelperAppDialog(); - let windowOpened = BrowserTestUtils.waitForNewWindow(false); + let windowOpened = BrowserTestUtils.waitForNewWindow(); await BrowserTestUtils.synthesizeMouseAtCenter("#new_window", {}, browser); let windowContext = await dialogAppeared; is(windowContext.gBrowser.selectedBrowser.currentURI.spec, URL, "got the right windowContext"); let win = await windowOpened;
--- a/widget/WidgetMessageUtils.h +++ b/widget/WidgetMessageUtils.h @@ -34,11 +34,17 @@ struct ParamTraits<LookAndFeelInt> return false; } }; template<> struct ParamTraits<nsTransparencyMode> : public ContiguousEnumSerializerInclusive<nsTransparencyMode, eTransparencyOpaque, eTransparencyBorderlessGlass> { }; +template<> +struct ParamTraits<nsCursor> + : public ContiguousEnumSerializer<nsCursor, eCursor_standard, eCursorCount> +{ +}; + } // namespace IPC #endif // WidgetMessageUtils_h
--- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -3637,18 +3637,21 @@ nsWindow::Create(nsIWidget* aParent, aInitData->mSupportTranslucency); // mozilla.widget.use-argb-visuals is a hidden pref defaulting to false // to allow experimentation if (Preferences::GetBool("mozilla.widget.use-argb-visuals", false)) useAlphaVisual = true; #ifdef GL_PROVIDER_GLX - bool useWebRender = gfxPlatform::Initialized() && - gfx::gfxVars::UseWebRender() && + // Ensure gfxPlatform is initialized, since that is what initializes + // gfxVars, used below. + Unused << gfxPlatform::GetPlatform(); + + bool useWebRender = gfx::gfxVars::UseWebRender() && AllowWebRenderForThisWindow(); // If using WebRender on X11, we need to select a visual with a depth buffer, // as well as an alpha channel if transparency is requested. This must be done // before the widget is realized. if (mIsX11Display && useWebRender) { auto display = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(mShell));
--- a/xpcom/ds/PLDHashTable.cpp +++ b/xpcom/ds/PLDHashTable.cpp @@ -471,27 +471,26 @@ PLDHashTable::ChangeTable(int32_t aDelta return false; } uint32_t nbytes; if (!SizeOfEntryStore(newCapacity, mEntrySize, &nbytes)) { return false; // overflowed } - char* newEntryStore = (char*)malloc(nbytes); + char* newEntryStore = (char*)calloc(1, nbytes); if (!newEntryStore) { return false; } // We can't fail from here on, so update table parameters. mHashShift = kHashBits - newLog2; mRemovedCount = 0; // Assign the new entry store to table. - memset(newEntryStore, 0, nbytes); char* oldEntryStore; char* oldEntryAddr; oldEntryAddr = oldEntryStore = mEntryStore.Get(); mEntryStore.Set(newEntryStore, &mGeneration); PLDHashMoveEntry moveEntry = mOps->moveEntry; // Copy only live entries, leaving removed ones behind. uint32_t oldCapacity = 1u << oldLog2; @@ -550,21 +549,20 @@ PLDHashTable::Add(const void* aKey, cons #endif // Allocate the entry storage if it hasn't already been allocated. if (!mEntryStore.Get()) { uint32_t nbytes; // We already checked this in the constructor, so it must still be true. MOZ_RELEASE_ASSERT(SizeOfEntryStore(CapacityFromHashShift(), mEntrySize, &nbytes)); - mEntryStore.Set((char*)malloc(nbytes), &mGeneration); + mEntryStore.Set((char*)calloc(1, nbytes), &mGeneration); if (!mEntryStore.Get()) { return nullptr; } - memset(mEntryStore.Get(), 0, nbytes); } // If alpha is >= .75, grow or compress the table. If aKey is already in the // table, we may grow once more than necessary, but only if we are on the // edge of being overloaded. uint32_t capacity = Capacity(); if (mEntryCount + mRemovedCount >= MaxLoad(capacity)) { // Compress if a quarter or more of all entries are removed.
--- a/xpcom/ds/nsCRT.cpp +++ b/xpcom/ds/nsCRT.cpp @@ -106,41 +106,16 @@ nsCRT::strcmp(const char16_t* aStr1, con } if (aStr2) { // aStr1 must have been null return 1; } } return 0; } -const char* -nsCRT::memmem(const char* aHaystack, uint32_t aHaystackLen, - const char* aNeedle, uint32_t aNeedleLen) -{ - // Sanity checking - if (!(aHaystack && aNeedle && aHaystackLen && aNeedleLen && - aNeedleLen <= aHaystackLen)) { - return nullptr; - } - -#ifdef HAVE_MEMMEM - return (const char*)::memmem(aHaystack, aHaystackLen, aNeedle, aNeedleLen); -#else - // No memmem means we need to roll our own. This isn't really optimized - // for performance ... if that becomes an issue we can take some inspiration - // from the js string compare code in jsstr.cpp - for (uint32_t i = 0; i < aHaystackLen - aNeedleLen; i++) { - if (!memcmp(aHaystack + i, aNeedle, aNeedleLen)) { - return aHaystack + i; - } - } -#endif - return nullptr; -} - // This should use NSPR but NSPR isn't exporting its PR_strtoll function // Until then... int64_t nsCRT::atoll(const char* aStr) { if (!aStr) { return 0; }
--- a/xpcom/ds/nsCRT.h +++ b/xpcom/ds/nsCRT.h @@ -80,22 +80,16 @@ public: * WARNING - STRTOK WHACKS str THE FIRST TIME IT IS CALLED * * MAKE A COPY OF str IF YOU NEED TO USE IT AFTER strtok() * */ static char* strtok(char* aStr, const char* aDelims, char** aNewStr); /// Like strcmp except for ucs2 strings static int32_t strcmp(const char16_t* aStr1, const char16_t* aStr2); - // The GNU libc has memmem, which is strstr except for binary data - // This is our own implementation that uses memmem on platforms - // where it's available. - static const char* memmem(const char* aHaystack, uint32_t aHaystackLen, - const char* aNeedle, uint32_t aNeedleLen); - // String to longlong static int64_t atoll(const char* aStr); static char ToUpper(char aChar) { return NS_ToUpper(aChar); } static char ToLower(char aChar) { return NS_ToLower(aChar); } static bool IsUpper(char aChar) { return NS_IsUpper(aChar); } static bool IsLower(char aChar) { return NS_IsLower(aChar); }
--- a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp +++ b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp @@ -15,38 +15,33 @@ #include "nsIDOMEventTarget.h" #include "nsIDOMGeoPositionError.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMNode.h" #include "nsIDOMNodeList.h" #include "nsIDOMOfflineResourceList.h" #include "nsIDOMParser.h" #include "nsIDOMRange.h" -#include "nsIDOMSerializer.h" -#include "nsIDOMXMLDocument.h" -#include "nsIDOMXULElement.h" #include "nsIListBoxObject.h" #include "nsIMessageManager.h" #include "nsISelection.h" #include "nsITreeBoxObject.h" -#include "nsIWebBrowserPersistable.h" #include "mozilla/dom/CSSPrimitiveValueBinding.h" #include "mozilla/dom/CSSStyleDeclarationBinding.h" #include "mozilla/dom/CSSStyleSheetBinding.h" #include "mozilla/dom/CSSValueBinding.h" #include "mozilla/dom/CSSValueListBinding.h" #include "mozilla/dom/DOMParserBinding.h" #include "mozilla/dom/DOMRequestBinding.h" #include "mozilla/dom/DocumentBinding.h" #include "mozilla/dom/DocumentFragmentBinding.h" #include "mozilla/dom/ElementBinding.h" #include "mozilla/dom/EventBinding.h" #include "mozilla/dom/EventTargetBinding.h" -#include "mozilla/dom/FrameLoaderBinding.h" #include "mozilla/dom/HTMLAnchorElementBinding.h" #include "mozilla/dom/HTMLAreaElementBinding.h" #include "mozilla/dom/HTMLButtonElementBinding.h" #include "mozilla/dom/HTMLFrameSetElementBinding.h" #include "mozilla/dom/HTMLHtmlElementBinding.h" #include "mozilla/dom/HTMLInputElementBinding.h" #include "mozilla/dom/ListBoxObjectBinding.h" #include "mozilla/dom/MediaListBinding.h" @@ -60,20 +55,17 @@ #include "mozilla/dom/RangeBinding.h" #include "mozilla/dom/SelectionBinding.h" #include "mozilla/dom/StorageEventBinding.h" #include "mozilla/dom/StyleSheetBinding.h" #include "mozilla/dom/StyleSheetListBinding.h" #include "mozilla/dom/SVGElementBinding.h" #include "mozilla/dom/TimeEventBinding.h" #include "mozilla/dom/TreeBoxObjectBinding.h" -#include "mozilla/dom/XMLDocumentBinding.h" -#include "mozilla/dom/XMLSerializerBinding.h" #include "mozilla/dom/XULDocumentBinding.h" -#include "mozilla/dom/XULElementBinding.h" using namespace mozilla; struct ComponentsInterfaceShimEntry { constexpr ComponentsInterfaceShimEntry(const char* aName, const nsIID& aIID, const dom::NativePropertyHooks* aNativePropHooks) : geckoName(aName), iid(aIID), nativePropHooks(aNativePropHooks) {} @@ -136,21 +128,17 @@ const ComponentsInterfaceShimEntry kComp DEFINE_SHIM(HTMLInputElement), DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIListBoxObject, ListBoxObject), DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIMessageSender, MessageSender), DEFINE_SHIM(NodeList), DEFINE_SHIM(Node), DEFINE_SHIM(OfflineResourceList), DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMParser, DOMParser), DEFINE_SHIM(Range), - DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMSerializer, XMLSerializer), DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsITreeBoxObject, TreeBoxObject), - DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIWebBrowserPersistable, FrameLoader), - DEFINE_SHIM(XMLDocument), - DEFINE_SHIM(XULElement), DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsISelection, Selection), }; #undef DEFINE_SHIM #undef DEFINE_SHIM_WITH_CUSTOM_INTERFACE NS_IMPL_ISUPPORTS(ShimInterfaceInfo, nsISupports, nsIInterfaceInfo)