diff -Nru firefox-47.0~b1+build1/browser/app/blocklist.xml firefox-47.0~b2+build1/browser/app/blocklist.xml --- firefox-47.0~b1+build1/browser/app/blocklist.xml 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/browser/app/blocklist.xml 2016-05-03 05:14:13.000000000 +0000 @@ -1,5 +1,5 @@ - + @@ -3594,6 +3594,7 @@ 0x0046 BLOCKED_DRIVER_VERSION 8.15.10.2086 EQUAL + All 0x8086 FEATURE_HARDWARE_VIDEO_DECODING BLOCKED_DRIVER_VERSION 10.18.10.3947 EQUAL @@ -3733,9 +3734,6 @@ O2S99lVUxErLSk56GvWRv+E= - F7PAjw2k0dTX5escPnyVOBo= - - Mq0P6o03FDk0B2bnJ+mYPGo= @@ -3771,6 +3769,174 @@ TA6EVg== + + CWhp + + + XhcFm2g619rt8Sro+a4rHA== + + + EDQMI0tR4kSntv1O37N10g== + + + P6G7IYSL2RZxtzTh8I6qPA== + + + HNo1DR4XCe4mS1iUMsY6Wg== + + + KjoVfZ3by6+pL8fssyfM6A== + + + UW3oKZKTDsrPy/rfwmGNaQ== + + + XLhHIg7vP+tWfRqvuKeAxw== + + + YNOos6YJoPC77qwSGCpb7w== + + + dItWlz2V62Philqj9m6Pbg== + + + ORFgmCj072NjcJnrxOMfQA== + + + L79XLVO2ZmtAu7FAG8Wmzw== + + + H08= + + + OE4/d+p3YRzzcSl+kmZ8Mw== + + + ZgwfEqZnBsUNvNuZ77FbQA== + + + OUvvVscW0/NltofkmV9qmg== + + + SdegFrLaFTCsoMAW5ED+zA== + + + VfTSum25nb65YPlpuhJAvg== + + + WX89jn8yGZVvoKTD9jDfRQ== + + + cpqpXVWPk5AXzGw+zNIcBw== + + + RUT1Gehd1KKYPfqOlgspoQ== + + + bx/XHJqcwxDOptxJ2lh5vw== + + + AuhvPsYZfVP6UDsuyjeZ4Q== + + + OhrtngFwotLcm4i+z00SjA== + + + U3SgRR3J+D6575WuCxuXeQ== + + + UVKsEezpGWOVQ4W9esstng== + + + acI1CFIgmwSFBoU5+ahDgg== + + + Sx51x7V8pYe8rp7PMP/3qg== + + + PAdKZPiaac2CvPxbOrsHOw== + + + E77H6yvyFQjO0PcN3x0H+Q== + + + d8AtKymQwkOPDBj+hjPzFg== + + + TurPPI6eivtNeGYdM0ZWXQ== + + + a9/VeyVWrzFD7rM2PEHwQA== + + + LnfcUaXG/pxV2CpXM5+YSg== + + + AygWP2Fgd2T+iLbmAlKT6g== + + + ezdAeCxKH7BFs7vn3byYaw== + + + 45KI4WIxyXfNrdtdj7C6 + + + UMUwXwT1Z4juyQ/CNTf4mw== + + + HZyLf+K70FKc+jomm8DiDw== + + + IIxFSyNM6mWtCgTG0IL3Og== + + + Rvm2CEw2IC2Mu/ax0A46QQ== + + + TqfXw+FkhxfVgE9GVMgjWQ== + + + E5I2y6sIonl4a+TmlXc7fw== + + + GdXz4L1b6FKNCMG9Jz2tjA== + + + BUrYjru5px1ym4QUN33TOQ== + + + CqZgEvHAsnzkT//QV9KjXw== + + + DYifRdP6aQQ8MLbXZY2f5g== + + + cDggUYfwJ3A1YcdoeT6s4A== + + + e0bEFhI16xx9U1yvlI56rA== + + + UKKK5ol/rKBZchAAOnZjaA== + + + FNISyWWTGi5Yco6fGh58/A== + + + JpUvYJyWjdGmeoH7YcYunw== + + + OnvXX72mvUI2Id/NMzegmg== + + + QZBvapTZFvmYktEPsBYLQQ== + + + OqQ2rV0ISTc308Z/oQgzFw== + + + NvEJoRYL2yvAZrAjbDIipQ== + diff -Nru firefox-47.0~b1+build1/browser/components/search/test/browser_bing_behavior.js firefox-47.0~b2+build1/browser/components/search/test/browser_bing_behavior.js --- firefox-47.0~b1+build1/browser/components/search/test/browser_bing_behavior.js 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/browser/components/search/test/browser_bing_behavior.js 2016-05-03 05:14:14.000000000 +0000 @@ -23,7 +23,7 @@ // Test search URLs (including purposes). url = engine.getSubmission("foo").uri.spec; - is(url, base, "Check search URL for 'foo'"); + is(url, base + "&form=MOZSBR", "Check search URL for 'foo'"); waitForExplicitFinish(); diff -Nru firefox-47.0~b1+build1/browser/components/search/test/browser_bing.js firefox-47.0~b2+build1/browser/components/search/test/browser_bing.js --- firefox-47.0~b1+build1/browser/components/search/test/browser_bing.js 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/browser/components/search/test/browser_bing.js 2016-05-03 05:14:14.000000000 +0000 @@ -18,7 +18,7 @@ // Test search URLs (including purposes). url = engine.getSubmission("foo").uri.spec; - is(url, base, "Check search URL for 'foo'"); + is(url, base + "&form=MOZSBR", "Check search URL for 'foo'"); url = engine.getSubmission("foo", null, "contextmenu").uri.spec; is(url, base + "&form=MOZCON", "Check context menu search URL for 'foo'"); url = engine.getSubmission("foo", null, "keyword").uri.spec; @@ -39,7 +39,7 @@ name: "Bing", alias: null, description: "Bing. Search by Microsoft.", - searchForm: "https://www.bing.com/search?q=&pc=MOZI", + searchForm: "https://www.bing.com/search?q=&pc=MOZI&form=MOZSBR", hidden: false, wrappedJSObject: { queryCharset: "UTF-8", diff -Nru firefox-47.0~b1+build1/browser/components/search/test/browser_google_codes.js firefox-47.0~b2+build1/browser/components/search/test/browser_google_codes.js --- firefox-47.0~b1+build1/browser/components/search/test/browser_google_codes.js 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/browser/components/search/test/browser_google_codes.js 2016-05-03 05:14:14.000000000 +0000 @@ -0,0 +1,161 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const kUrlPref = "geoSpecificDefaults.url"; +const BROWSER_SEARCH_PREF = "browser.search."; + +var originalGeoURL; + +/** + * Clean the profile of any cache file left from a previous run. + * Returns a boolean indicating if the cache file existed. + */ +function removeCacheFile() +{ + const CACHE_FILENAME = "search.json.mozlz4"; + + let file = Services.dirsvc.get("ProfD", Ci.nsIFile); + file.append(CACHE_FILENAME); + if (file.exists()) { + file.remove(false); + return true; + } + return false; +} + +/** + * Returns a promise that is resolved when an observer notification from the + * search service fires with the specified data. + * + * @param aExpectedData + * The value the observer notification sends that causes us to resolve + * the promise. + */ +function waitForSearchNotification(aExpectedData, aCallback) { + const SEARCH_SERVICE_TOPIC = "browser-search-service"; + Services.obs.addObserver(function observer(aSubject, aTopic, aData) { + if (aData != aExpectedData) + return; + + Services.obs.removeObserver(observer, SEARCH_SERVICE_TOPIC); + aCallback(); + }, SEARCH_SERVICE_TOPIC, false); +} + +function asyncInit() { + return new Promise(resolve => { + Services.search.init(function() { + ok(Services.search.isInitialized, "search service should be initialized"); + resolve(); + }); + }); +} + +function asyncReInit() { + const kLocalePref = "general.useragent.locale"; + + let promise = new Promise(resolve => { + waitForSearchNotification("reinit-complete", resolve); + }); + + Services.search.QueryInterface(Ci.nsIObserver) + .observe(null, "nsPref:changed", kLocalePref); + + return promise; +} + +let gEngineCount; + +add_task(function* preparation() { + // ContentSearch is interferring with our async re-initializations of the + // search service: once _initServicePromise has resolved, it will access + // the search service, thus causing unpredictable behavior due to + // synchronous initializations of the service. + let originalContentSearchPromise = ContentSearch._initServicePromise; + ContentSearch._initServicePromise = new Promise(resolve => { + registerCleanupFunction(() => { + ContentSearch._initServicePromise = originalContentSearchPromise; + resolve(); + }); + }); + + yield asyncInit(); + gEngineCount = Services.search.getVisibleEngines().length; + + waitForSearchNotification("uninit-complete", () => { + // Verify search service is not initialized + is(Services.search.isInitialized, false, "Search service should NOT be initialized"); + + removeCacheFile(); + + // Geo specific defaults won't be fetched if there's no country code. + Services.prefs.setCharPref("browser.search.geoip.url", + 'data:application/json,{"country_code": "US"}'); + + Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true); + + // Make the new Google the only engine + originalGeoURL = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + kUrlPref); + let geoUrl = 'data:application/json,{"interval": 31536000, "settings": {"searchDefault": "Google", "visibleDefaultEngines": ["google"]}}'; + Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF).setCharPref(kUrlPref, geoUrl); + }); + + yield asyncReInit(); + + yield new Promise(resolve => { + waitForSearchNotification("write-cache-to-disk-complete", resolve); + }); +}); + +add_task(function* tests() { + let engines = Services.search.getEngines(); + is(Services.search.currentEngine.name, "Google", "Search engine should be Google"); + is(engines.length, 1, "There should only be one engine"); + + let engine = Services.search.getEngineByName("Google"); + ok(engine, "Google"); + + let base = "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8&client=firefox-b"; + + // Keyword uses a slightly different code + let keywordBase = base + "-ab"; + + let url; + + // Test search URLs (including purposes). + url = engine.getSubmission("foo", null, "contextmenu").uri.spec; + is(url, base, "Check context menu search URL for 'foo'"); + url = engine.getSubmission("foo", null, "keyword").uri.spec; + is(url, keywordBase, "Check keyword search URL for 'foo'"); + url = engine.getSubmission("foo", null, "searchbar").uri.spec; + is(url, base, "Check search bar search URL for 'foo'"); + url = engine.getSubmission("foo", null, "homepage").uri.spec; + is(url, base, "Check homepage search URL for 'foo'"); + url = engine.getSubmission("foo", null, "newtab").uri.spec; + is(url, base, "Check newtab search URL for 'foo'"); + url = engine.getSubmission("foo", null, "system").uri.spec; + is(url, base, "Check system search URL for 'foo'"); +}); + + +add_task(function* cleanup() { + waitForSearchNotification("uninit-complete", () => { + // Verify search service is not initialized + is(Services.search.isInitialized, false, + "Search service should NOT be initialized"); + removeCacheFile(); + + Services.prefs.clearUserPref("browser.search.geoip.url"); + + // We can't clear the pref because it's set to false by testing/profiles/prefs_general.js + Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", false); + + Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF).setCharPref(kUrlPref, originalGeoURL); + }); + + yield asyncReInit(); + is(gEngineCount, Services.search.getVisibleEngines().length, + "correct engine count after cleanup"); +}); diff -Nru firefox-47.0~b1+build1/browser/components/search/test/browser.ini firefox-47.0~b2+build1/browser/components/search/test/browser.ini --- firefox-47.0~b1+build1/browser/components/search/test/browser.ini 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/browser/components/search/test/browser.ini 2016-05-03 05:14:14.000000000 +0000 @@ -26,6 +26,7 @@ [browser_eBay.js] [browser_eBay_behavior.js] [browser_google.js] +[browser_google_codes.js] [browser_google_behavior.js] [browser_healthreport.js] [browser_hiddenOneOffs_cleanup.js] diff -Nru firefox-47.0~b1+build1/browser/components/search/test/browser_yahoo_behavior.js firefox-47.0~b2+build1/browser/components/search/test/browser_yahoo_behavior.js --- firefox-47.0~b1+build1/browser/components/search/test/browser_yahoo_behavior.js 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/browser/components/search/test/browser_yahoo_behavior.js 2016-05-03 05:14:14.000000000 +0000 @@ -23,7 +23,7 @@ // Test search URLs (including purposes). url = engine.getSubmission("foo").uri.spec; - is(url, base, "Check search URL for 'foo'"); + is(url, base + "&hsimp=yhs-001", "Check search URL for 'foo'"); waitForExplicitFinish(); diff -Nru firefox-47.0~b1+build1/browser/components/search/test/browser_yahoo.js firefox-47.0~b2+build1/browser/components/search/test/browser_yahoo.js --- firefox-47.0~b1+build1/browser/components/search/test/browser_yahoo.js 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/browser/components/search/test/browser_yahoo.js 2016-05-03 05:14:14.000000000 +0000 @@ -18,7 +18,21 @@ // Test search URLs (including purposes). url = engine.getSubmission("foo").uri.spec; - is(url, base, "Check search URL for 'foo'"); + is(url, base + "&hsimp=yhs-001", "Check search URL for 'foo'"); + url = engine.getSubmission("foo", null, "searchbar").uri.spec; + is(url, base + "&hsimp=yhs-001", "Check search bar search URL for 'foo'"); + url = engine.getSubmission("foo", null, "keyword").uri.spec; + is(url, base + "&hsimp=yhs-002", "Check keyword search URL for 'foo'"); + url = engine.getSubmission("foo", null, "homepage").uri.spec; + is(url, base + "&hsimp=yhs-003", "Check homepage search URL for 'foo'"); + url = engine.getSubmission("foo", null, "newtab").uri.spec; + is(url, base + "&hsimp=yhs-004", "Check newtab search URL for 'foo'"); + url = engine.getSubmission("foo", null, "contextmenu").uri.spec; + is(url, base + "&hsimp=yhs-005", "Check context menu search URL for 'foo'"); + url = engine.getSubmission("foo", null, "system").uri.spec; + is(url, base + "&hsimp=yhs-007", "Check system search URL for 'foo'"); + url = engine.getSubmission("foo", null, "invalid").uri.spec; + is(url, base + "&hsimp=yhs-001", "Check invalid URL for 'foo'"); // Check search suggestion URL. url = engine.getSubmission("foo", "application/x-suggestions+json").uri.spec; @@ -29,7 +43,7 @@ name: "Yahoo", alias: null, description: "Yahoo Search", - searchForm: "https://search.yahoo.com/yhs/search?p=&ei=UTF-8&hspart=mozilla", + searchForm: "https://search.yahoo.com/yhs/search?p=&ei=UTF-8&hspart=mozilla&hsimp=yhs-001", hidden: false, wrappedJSObject: { queryCharset: "UTF-8", diff -Nru firefox-47.0~b1+build1/browser/config/version_display.txt firefox-47.0~b2+build1/browser/config/version_display.txt --- firefox-47.0~b1+build1/browser/config/version_display.txt 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/browser/config/version_display.txt 2016-05-03 05:14:14.000000000 +0000 @@ -1 +1 @@ -47.0b1 +47.0b2 diff -Nru firefox-47.0~b1+build1/browser/extensions/pocket/bootstrap.js firefox-47.0~b2+build1/browser/extensions/pocket/bootstrap.js --- firefox-47.0~b1+build1/browser/extensions/pocket/bootstrap.js 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/browser/extensions/pocket/bootstrap.js 2016-05-03 05:14:14.000000000 +0000 @@ -59,17 +59,6 @@ } } -function* allBrowserWindows() { - var winEnum = Services.wm.getEnumerator("navigator:browser"); - while (winEnum.hasMoreElements()) { - let win = winEnum.getNext(); - // skip closed windows - if (win.closed) - continue; - yield win; - } -} - function createElementWithAttrs(document, type, attrs) { let element = document.createElement(type); Object.keys(attrs).forEach(function (attr) { @@ -220,7 +209,7 @@ Services.obs.removeObserver(this, "on-build-contextmenu"); // loop through windows and remove context menus // iterate through all windows and add pocket to them - for (let win of allBrowserWindows()) { + for (let win of CustomizableUI.windows) { let document = win.document; for (let id of ["context-pocket", "context-savelinktopocket"]) { let element = document.getElementById(id); @@ -382,7 +371,7 @@ CreatePocketWidget(reason); PocketContextMenu.init(); - for (let win of allBrowserWindows()) { + for (let win of CustomizableUI.windows) { this.onWindowOpened(win); } }, @@ -390,7 +379,7 @@ AboutSaved.unregister(); AboutSignup.unregister(); CustomizableUI.removeListener(this); - for (let window of allBrowserWindows()) { + for (let window of CustomizableUI.windows) { for (let id of ["panelMenu_pocket", "menu_pocket", "BMB_pocket", "panelMenu_pocketSeparator", "menu_pocketSeparator", "BMB_pocketSeparator"]) { diff -Nru firefox-47.0~b1+build1/browser/locales/en-US/searchplugins/google.xml firefox-47.0~b2+build1/browser/locales/en-US/searchplugins/google.xml --- firefox-47.0~b1+build1/browser/locales/en-US/searchplugins/google.xml 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/browser/locales/en-US/searchplugins/google.xml 2016-05-03 05:14:14.000000000 +0000 @@ -12,7 +12,7 @@ - + diff -Nru firefox-47.0~b1+build1/browser/modules/Feeds.jsm firefox-47.0~b2+build1/browser/modules/Feeds.jsm --- firefox-47.0~b1+build1/browser/modules/Feeds.jsm 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/browser/modules/Feeds.jsm 2016-05-03 05:14:14.000000000 +0000 @@ -20,6 +20,7 @@ init() { let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); mm.addMessageListener("WCCR:registerProtocolHandler", this); + mm.addMessageListener("WCCR:registerContentHandler", this); Services.ppmm.addMessageListener("WCCR:setAutoHandler", this); Services.ppmm.addMessageListener("FeedConverter:addLiveBookmark", this); diff -Nru firefox-47.0~b1+build1/browser/themes/linux/linuxShared.inc firefox-47.0~b2+build1/browser/themes/linux/linuxShared.inc --- firefox-47.0~b1+build1/browser/themes/linux/linuxShared.inc 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/browser/themes/linux/linuxShared.inc 2016-05-03 05:14:14.000000000 +0000 @@ -4,7 +4,7 @@ %filter substitution -%define toolbarHighlight hsla(0,0%,100%,.05) +%define toolbarHighlight hsla(0,0%,100%,.15) %define toolbarHighlightLWT rgba(255,255,255,.4) /* navbarInsetHighlight is tightly coupled to the toolbarHighlight constant. */ %define navbarInsetHighlight hsla(0,0%,100%,.4) diff -Nru firefox-47.0~b1+build1/debian/changelog firefox-47.0~b2+build1/debian/changelog --- firefox-47.0~b1+build1/debian/changelog 2016-04-26 16:53:33.000000000 +0000 +++ firefox-47.0~b2+build1/debian/changelog 2016-05-03 05:41:29.000000000 +0000 @@ -1,4 +1,10 @@ -firefox (47.0~b1+build1-0ubuntu0.16.10.3) yakkety; urgency=medium +firefox (47.0~b2+build1-0ubuntu0.16.10.1) yakkety; urgency=medium + + * New upstream release from the beta channel (FIREFOX_47_0b2_BUILD1) + + -- Rico Tzschichholz Tue, 03 May 2016 07:35:36 +0200 + +firefox (47.0~b1+build1-0ubuntu0.16.04.3) xenial; urgency=medium [ Will Cooke ] * Remove U1 from Ubuntu bookmarks patch (LP: #1322724) @@ -8,9 +14,18 @@ --enable-official-branding * Update debian/build/create-tarball.py to create release tarballs correctly after changes to the upstream release automation + * Refresh patches: + - update debian/patches/unity-menubar.patch + - update debian/patches/support-coinstallable-trunk-build.patch + - update debian/patches/allow-lockPref-everywhere.patch [ Rico Tzschichholz ] * New upstream release from the beta channel (FIREFOX_47_0b1_BUILD1) + * Add Kaqchikel language pack + - update debian/config/locales.all + - update debian/config/locales.shipped + - update debian/control + - update debian/config/searchplugins.conf -- Rico Tzschichholz Tue, 26 Apr 2016 10:29:19 +0200 diff -Nru firefox-47.0~b1+build1/devtools/client/inspector/computed/computed.js firefox-47.0~b2+build1/devtools/client/inspector/computed/computed.js --- firefox-47.0~b1+build1/devtools/client/inspector/computed/computed.js 2016-04-26 07:45:03.000000000 +0000 +++ firefox-47.0~b2+build1/devtools/client/inspector/computed/computed.js 2016-05-03 05:14:16.000000000 +0000 @@ -502,11 +502,14 @@ * Handle the keypress event in the computed view. */ _onKeypress: function(event) { + if (!event.target.closest("#sidebar-panel-computedview")) { + return; + } let isOSX = Services.appinfo.OS === "Darwin"; if (((isOSX && event.metaKey && !event.ctrlKey && !event.altKey) || (!isOSX && event.ctrlKey && !event.metaKey && !event.altKey)) && - event.code === "KeyF") { + event.key === "f") { this.searchField.focus(); event.preventDefault(); } diff -Nru firefox-47.0~b1+build1/devtools/client/inspector/computed/test/browser_computed_search-filter.js firefox-47.0~b2+build1/devtools/client/inspector/computed/test/browser_computed_search-filter.js --- firefox-47.0~b1+build1/devtools/client/inspector/computed/test/browser_computed_search-filter.js 2016-04-26 07:45:03.000000000 +0000 +++ firefox-47.0~b2+build1/devtools/client/inspector/computed/test/browser_computed_search-filter.js 2016-05-03 05:14:16.000000000 +0000 @@ -35,9 +35,18 @@ info("setting filter text to \"color\""); let searchField = computedView.searchField; let onRefreshed = inspector.once("computed-view-refreshed"); - searchField.focus(); - let win = computedView.styleWindow; + + // First check to make sure that accel + F doesn't focus search if the container + // isn't focused + inspector.panelWin.focus(); + EventUtils.synthesizeKey("f", { accelKey: true }); + isnot(inspector.panelDoc.activeElement, searchField, "Search field isn't focused"); + + computedView.element.focus(); + EventUtils.synthesizeKey("f", { accelKey: true }); + is(inspector.panelDoc.activeElement, searchField, "Search field is focused"); + synthesizeKeys("color", win); yield onRefreshed; diff -Nru firefox-47.0~b1+build1/devtools/client/inspector/rules/rules.js firefox-47.0~b2+build1/devtools/client/inspector/rules/rules.js --- firefox-47.0~b1+build1/devtools/client/inspector/rules/rules.js 2016-04-26 07:45:03.000000000 +0000 +++ firefox-47.0~b2+build1/devtools/client/inspector/rules/rules.js 2016-05-03 05:14:16.000000000 +0000 @@ -1499,11 +1499,15 @@ * Handle the keypress event in the rule view. */ _onKeypress: function(event) { + if (!event.target.closest("#sidebar-panel-ruleview")) { + return; + } + let isOSX = Services.appinfo.OS === "Darwin"; if (((isOSX && event.metaKey && !event.ctrlKey && !event.altKey) || (!isOSX && event.ctrlKey && !event.metaKey && !event.altKey)) && - event.code === "KeyF") { + event.key === "f") { this.searchField.focus(); event.preventDefault(); } diff -Nru firefox-47.0~b1+build1/devtools/client/inspector/rules/test/browser.ini firefox-47.0~b2+build1/devtools/client/inspector/rules/test/browser.ini --- firefox-47.0~b1+build1/devtools/client/inspector/rules/test/browser.ini 2016-04-26 07:45:03.000000000 +0000 +++ firefox-47.0~b2+build1/devtools/client/inspector/rules/test/browser.ini 2016-05-03 05:14:16.000000000 +0000 @@ -3,6 +3,7 @@ subsuite = devtools support-files = doc_author-sheet.html + doc_blob_stylesheet.html doc_content_stylesheet.html doc_content_stylesheet_imported.css doc_content_stylesheet_imported2.css @@ -49,6 +50,7 @@ [browser_rules_authored.js] [browser_rules_authored_color.js] [browser_rules_authored_override.js] +[browser_rules_blob_stylesheet.js] [browser_rules_colorpicker-and-image-tooltip_01.js] [browser_rules_colorpicker-and-image-tooltip_02.js] [browser_rules_colorpicker-appears-on-swatch-click.js] diff -Nru firefox-47.0~b1+build1/devtools/client/inspector/rules/test/browser_rules_blob_stylesheet.js firefox-47.0~b2+build1/devtools/client/inspector/rules/test/browser_rules_blob_stylesheet.js --- firefox-47.0~b1+build1/devtools/client/inspector/rules/test/browser_rules_blob_stylesheet.js 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/devtools/client/inspector/rules/test/browser_rules_blob_stylesheet.js 2016-05-03 05:14:16.000000000 +0000 @@ -0,0 +1,20 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that the rule-view content is correct for stylesheet generated +// with createObjectURL(cssBlob) +const TEST_URL = URL_ROOT + "doc_blob_stylesheet.html"; + +add_task(function* () { + yield addTab(TEST_URL); + let {inspector, view} = yield openRuleView(); + + yield selectNode("h1", inspector); + is(view.element.querySelectorAll("#noResults").length, 0, + "The no-results element is not displayed"); + + is(view.element.querySelectorAll(".ruleview-rule").length, 2, + "There are 2 displayed rules"); +}); diff -Nru firefox-47.0~b1+build1/devtools/client/inspector/rules/test/doc_blob_stylesheet.html firefox-47.0~b2+build1/devtools/client/inspector/rules/test/doc_blob_stylesheet.html --- firefox-47.0~b1+build1/devtools/client/inspector/rules/test/doc_blob_stylesheet.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/devtools/client/inspector/rules/test/doc_blob_stylesheet.html 2016-05-03 05:14:16.000000000 +0000 @@ -0,0 +1,39 @@ + + + + + + + Blob stylesheet sourcemap + + +

Test

+ + + diff -Nru firefox-47.0~b1+build1/devtools/client/themes/commandline.inc.css firefox-47.0~b2+build1/devtools/client/themes/commandline.inc.css --- firefox-47.0~b1+build1/devtools/client/themes/commandline.inc.css 2016-04-26 07:45:04.000000000 +0000 +++ firefox-47.0~b2+build1/devtools/client/themes/commandline.inc.css 2016-05-03 05:14:16.000000000 +0000 @@ -40,7 +40,7 @@ #developer-toolbar > toolbarbutton { -moz-appearance: none; border: none; - background: transparent; + background-color: transparent; margin: 0; padding: 0 10px; width: 32px; diff -Nru firefox-47.0~b1+build1/devtools/server/actors/stylesheets.js firefox-47.0~b2+build1/devtools/server/actors/stylesheets.js --- firefox-47.0~b1+build1/devtools/server/actors/stylesheets.js 2016-04-26 07:45:04.000000000 +0000 +++ firefox-47.0~b2+build1/devtools/server/actors/stylesheets.js 2016-05-03 05:14:16.000000000 +0000 @@ -803,6 +803,9 @@ * Sets the source map's sourceRoot to be relative to the source map url. */ _setSourceMapRoot: function(aSourceMap, aAbsSourceMapURL, aScriptURL) { + if (aScriptURL.startsWith("blob:")) { + aScriptURL = aScriptURL.replace("blob:", ""); + } const base = dirname( aAbsSourceMapURL.startsWith("data:") ? aScriptURL diff -Nru firefox-47.0~b1+build1/dom/events/IMEContentObserver.cpp firefox-47.0~b2+build1/dom/events/IMEContentObserver.cpp --- firefox-47.0~b1+build1/dom/events/IMEContentObserver.cpp 2016-04-26 07:45:06.000000000 +0000 +++ firefox-47.0~b2+build1/dom/events/IMEContentObserver.cpp 2016-05-03 05:14:19.000000000 +0000 @@ -1548,12 +1548,18 @@ // If notifications caused some new change, we should notify them now. if (mIMEContentObserver->NeedsToNotifyIMEOfSomething()) { - MOZ_LOG(sIMECOLog, LogLevel::Debug, - ("IMECO: 0x%p IMEContentObserver::IMENotificationSender::Run(), " - "posting IMENotificationSender to current thread", this)); - mIMEContentObserver->mQueuedSender = - new IMENotificationSender(mIMEContentObserver); - NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender); + if (mIMEContentObserver->GetState() == eState_StoppedObserving) { + MOZ_LOG(sIMECOLog, LogLevel::Debug, + ("IMECO: 0x%p IMEContentObserver::IMENotificationSender::Run(), " + "waiting IMENotificationSender to be reinitialized", this)); + } else { + MOZ_LOG(sIMECOLog, LogLevel::Debug, + ("IMECO: 0x%p IMEContentObserver::IMENotificationSender::Run(), " + "posting IMENotificationSender to current thread", this)); + mIMEContentObserver->mQueuedSender = + new IMENotificationSender(mIMEContentObserver); + NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender); + } } return NS_OK; } diff -Nru firefox-47.0~b1+build1/dom/geolocation/nsGeolocation.cpp firefox-47.0~b2+build1/dom/geolocation/nsGeolocation.cpp --- firefox-47.0~b1+build1/dom/geolocation/nsGeolocation.cpp 2016-04-26 07:45:06.000000000 +0000 +++ firefox-47.0~b2+build1/dom/geolocation/nsGeolocation.cpp 2016-05-03 05:14:19.000000000 +0000 @@ -775,7 +775,7 @@ NS_IMETHODIMP nsGeolocationRequest::TimerCallbackHolder::Notify(nsITimer*) { - if (mRequest) { + if (mRequest && mRequest->mLocator) { RefPtr request(mRequest); request->Notify(); } diff -Nru firefox-47.0~b1+build1/dom/media/MediaDecoder.cpp firefox-47.0~b2+build1/dom/media/MediaDecoder.cpp --- firefox-47.0~b1+build1/dom/media/MediaDecoder.cpp 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/MediaDecoder.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -732,7 +732,7 @@ MOZ_ASSERT(NS_IsMainThread()); NS_ASSERTION(mDecoderStateMachine, "Cannot initialize null state machine!"); - nsresult rv = mDecoderStateMachine->Init(); + nsresult rv = mDecoderStateMachine->Init(this); NS_ENSURE_SUCCESS(rv, rv); // If some parameters got set before the state machine got created, diff -Nru firefox-47.0~b1+build1/dom/media/MediaDecoderStateMachine.cpp firefox-47.0~b2+build1/dom/media/MediaDecoderStateMachine.cpp --- firefox-47.0~b1+build1/dom/media/MediaDecoderStateMachine.cpp 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/MediaDecoderStateMachine.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -284,11 +284,6 @@ MOZ_COUNT_CTOR(MediaDecoderStateMachine); NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - // Dispatch initialization that needs to happen on that task queue. - nsCOMPtr r = NS_NewRunnableMethodWithArg>( - this, &MediaDecoderStateMachine::InitializationTask, aDecoder); - mTaskQueue->Dispatch(r.forget()); - InitVideoQueuePrefs(); mBufferingWait = IsRealTime() ? 0 : 15; @@ -302,22 +297,6 @@ // timeEndPeriod() call. timeBeginPeriod(1); #endif - - mAudioQueueListener = AudioQueue().PopEvent().Connect( - mTaskQueue, this, &MediaDecoderStateMachine::OnAudioPopped); - mVideoQueueListener = VideoQueue().PopEvent().Connect( - mTaskQueue, this, &MediaDecoderStateMachine::OnVideoPopped); - - mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread()); - - mMediaSink = CreateMediaSink(mAudioCaptured); - -#ifdef MOZ_EME - mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then( - OwnerThread(), __func__, this, - &MediaDecoderStateMachine::OnCDMProxyReady, - &MediaDecoderStateMachine::OnCDMProxyNotReady)); -#endif } MediaDecoderStateMachine::~MediaDecoderStateMachine() @@ -1071,9 +1050,31 @@ return mMediaSink->IsPlaying(); } -nsresult MediaDecoderStateMachine::Init() +nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder) { MOZ_ASSERT(NS_IsMainThread()); + + // Dispatch initialization that needs to happen on that task queue. + nsCOMPtr r = NS_NewRunnableMethodWithArg>( + this, &MediaDecoderStateMachine::InitializationTask, aDecoder); + mTaskQueue->Dispatch(r.forget()); + + mAudioQueueListener = AudioQueue().PopEvent().Connect( + mTaskQueue, this, &MediaDecoderStateMachine::OnAudioPopped); + mVideoQueueListener = VideoQueue().PopEvent().Connect( + mTaskQueue, this, &MediaDecoderStateMachine::OnVideoPopped); + + mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread()); + + mMediaSink = CreateMediaSink(mAudioCaptured); + +#ifdef MOZ_EME + mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then( + OwnerThread(), __func__, this, + &MediaDecoderStateMachine::OnCDMProxyReady, + &MediaDecoderStateMachine::OnCDMProxyNotReady)); +#endif + nsresult rv = mReader->Init(); NS_ENSURE_SUCCESS(rv, rv); ScheduleStateMachineCrossThread(); diff -Nru firefox-47.0~b1+build1/dom/media/MediaDecoderStateMachine.h firefox-47.0~b2+build1/dom/media/MediaDecoderStateMachine.h --- firefox-47.0~b1+build1/dom/media/MediaDecoderStateMachine.h 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/MediaDecoderStateMachine.h 2016-05-03 05:14:20.000000000 +0000 @@ -141,7 +141,7 @@ MediaDecoderReader* aReader, bool aRealTime = false); - nsresult Init(); + nsresult Init(MediaDecoder* aDecoder); // Enumeration for the valid decoding states enum State { diff -Nru firefox-47.0~b1+build1/dom/media/mediasource/MediaSourceDecoder.cpp firefox-47.0~b2+build1/dom/media/mediasource/MediaSourceDecoder.cpp --- firefox-47.0~b1+build1/dom/media/mediasource/MediaSourceDecoder.cpp 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/mediasource/MediaSourceDecoder.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -61,7 +61,7 @@ return NS_ERROR_FAILURE; } - nsresult rv = GetStateMachine()->Init(); + nsresult rv = GetStateMachine()->Init(this); NS_ENSURE_SUCCESS(rv, rv); SetStateMachineParameters(); diff -Nru firefox-47.0~b1+build1/dom/media/PeerConnection.js firefox-47.0~b2+build1/dom/media/PeerConnection.js --- firefox-47.0~b1+build1/dom/media/PeerConnection.js 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/PeerConnection.js 2016-05-03 05:14:20.000000000 +0000 @@ -1053,7 +1053,13 @@ "InvalidParameterError"); } }); - this._impl.addTrack(track, stream); + try { + this._impl.addTrack(track, stream); + } catch (e if (e.result == Cr.NS_ERROR_NOT_IMPLEMENTED)) { + throw new this._win.DOMException( + "track in constructed stream not yet supported (see Bug 1259236).", + "NotSupportedError"); + } let sender = this._win.RTCRtpSender._create(this._win, new RTCRtpSender(this, track, stream)); diff -Nru firefox-47.0~b1+build1/dom/media/tests/mochitest/head.js firefox-47.0~b2+build1/dom/media/tests/mochitest/head.js --- firefox-47.0~b1+build1/dom/media/tests/mochitest/head.js 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/tests/mochitest/head.js 2016-05-03 05:14:20.000000000 +0000 @@ -406,6 +406,17 @@ }, false)); }; +/* Test that a function throws the right error */ +function mustThrowWith(msg, reason, f) { + try { + f(); + ok(false, msg + " must throw"); + } catch (e) { + is(e.name, reason, msg + " must throw: " + e.message); + } +}; + + /*** Test control flow methods */ /** diff -Nru firefox-47.0~b1+build1/dom/media/tests/mochitest/mochitest.ini firefox-47.0~b2+build1/dom/media/tests/mochitest/mochitest.ini --- firefox-47.0~b1+build1/dom/media/tests/mochitest/mochitest.ini 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/tests/mochitest/mochitest.ini 2016-05-03 05:14:20.000000000 +0000 @@ -70,6 +70,7 @@ [test_getUserMedia_peerIdentity.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 1021776, too --ing slow on b2g) [test_peerConnection_addIceCandidate.html] +[test_peerConnection_addTrack.html] [test_peerConnection_basicAudio.html] skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably [test_peerConnection_basicAudioRequireEOC.html] diff -Nru firefox-47.0~b1+build1/dom/media/tests/mochitest/test_peerConnection_addTrack.html firefox-47.0~b2+build1/dom/media/tests/mochitest/test_peerConnection_addTrack.html --- firefox-47.0~b1+build1/dom/media/tests/mochitest/test_peerConnection_addTrack.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/tests/mochitest/test_peerConnection_addTrack.html 2016-05-03 05:14:20.000000000 +0000 @@ -0,0 +1,31 @@ + + + + + + +
+
+
+ + diff -Nru firefox-47.0~b1+build1/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html firefox-47.0~b2+build1/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html --- firefox-47.0~b1+build1/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html 2016-05-03 05:14:20.000000000 +0000 @@ -19,15 +19,6 @@ pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback()); pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback()); - function mustThrowWith(msg, reason, f) { - try { - f(); - ok(false, msg + " must throw"); - } catch (e) { - is(e.name, reason, msg + " must throw: " + e.message); - } - }; - var v1, v2; var delivered = new Promise(resolve => pc2.ontrack = e => { // Test RTCTrackEvent here. diff -Nru firefox-47.0~b1+build1/dom/media/webaudio/blink/PeriodicWave.cpp firefox-47.0~b2+build1/dom/media/webaudio/blink/PeriodicWave.cpp --- firefox-47.0~b1+build1/dom/media/webaudio/blink/PeriodicWave.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/webaudio/blink/PeriodicWave.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -153,7 +153,9 @@ // Nyquist frequency. unsigned numberOfPartials = numberOfPartialsForRange(0); float nyquist = 0.5 * m_sampleRate; - numberOfPartials = std::min(numberOfPartials, (unsigned)(nyquist / fundamentalFrequency)); + if (fundamentalFrequency != 0.0) { + numberOfPartials = std::min(numberOfPartials, (unsigned)(nyquist / fundamentalFrequency)); + } if (numberOfPartials > m_maxPartialsInBandLimitedTable) { for (unsigned rangeIndex = 0; rangeIndex < m_numberOfRanges; ++rangeIndex) { m_bandLimitedTables[rangeIndex] = 0; @@ -240,8 +242,10 @@ // Limit number of partials to those below Nyquist frequency float nyquist = 0.5 * m_sampleRate; - numberOfPartials = std::min(numberOfPartials, - (unsigned)(nyquist / fundamentalFrequency)); + if (fundamentalFrequency != 0.0) { + numberOfPartials = std::min(numberOfPartials, + (unsigned)(nyquist / fundamentalFrequency)); + } // Copy from loaded frequency data and generate complex conjugate // because of the way the inverse FFT is defined. diff -Nru firefox-47.0~b1+build1/dom/media/webaudio/test/mochitest.ini firefox-47.0~b2+build1/dom/media/webaudio/test/mochitest.ini --- firefox-47.0~b1+build1/dom/media/webaudio/test/mochitest.ini 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/webaudio/test/mochitest.ini 2016-05-03 05:14:21.000000000 +0000 @@ -89,6 +89,7 @@ [test_bug1118372.html] [test_bug1056032.html] skip-if = toolkit == 'android' # bug 1056706 +[test_bug1267579.html] [test_channelMergerNode.html] [test_channelMergerNodeWithVolume.html] [test_channelSplitterNode.html] diff -Nru firefox-47.0~b1+build1/dom/media/webaudio/test/test_bug1267579.html firefox-47.0~b2+build1/dom/media/webaudio/test/test_bug1267579.html --- firefox-47.0~b1+build1/dom/media/webaudio/test/test_bug1267579.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/dom/media/webaudio/test/test_bug1267579.html 2016-05-03 05:14:21.000000000 +0000 @@ -0,0 +1,46 @@ + + + + Test that PeriodicWave handles fundamental fequency of zero + + + + + +
+
+
+ + diff -Nru firefox-47.0~b1+build1/dom/plugins/ipc/PluginInstanceChild.cpp firefox-47.0~b2+build1/dom/plugins/ipc/PluginInstanceChild.cpp --- firefox-47.0~b1+build1/dom/plugins/ipc/PluginInstanceChild.cpp 2016-04-26 07:45:09.000000000 +0000 +++ firefox-47.0~b2+build1/dom/plugins/ipc/PluginInstanceChild.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -196,6 +196,7 @@ , mHasPainted(false) , mSurfaceDifferenceRect(0,0,0,0) , mDestroyed(false) + , mStackDepth(0) { memset(&mWindow, 0, sizeof(mWindow)); mWindow.type = NPWindowTypeWindow; @@ -383,6 +384,7 @@ { PLUGIN_LOG_DEBUG(("%s (aVar=%i)", FULLFUNCTION, (int) aVar)); AssertPluginThread(); + AutoStackHelper guard(this); switch(aVar) { @@ -587,6 +589,8 @@ AssertPluginThread(); + AutoStackHelper guard(this); + switch (aVar) { case NPPVpluginWindowBool: { NPError rv; @@ -691,6 +695,7 @@ bool* wantsAllStreams, NPError* rv) { AssertPluginThread(); + AutoStackHelper guard(this); uint32_t value = 0; if (!mPluginIface->getvalue) { @@ -709,6 +714,7 @@ bool* needs, NPError* rv) { AssertPluginThread(); + AutoStackHelper guard(this); #ifdef MOZ_X11 // The documentation on the types for many variables in NP(N|P)_GetValue @@ -743,6 +749,7 @@ NPError* aResult) { AssertPluginThread(); + AutoStackHelper guard(this); NPObject* object = nullptr; NPError result = NPERR_GENERIC_ERROR; @@ -780,6 +787,7 @@ NPError* aResult) { AssertPluginThread(); + AutoStackHelper guard(this); #if MOZ_ACCESSIBILITY_ATK @@ -837,6 +845,7 @@ { PLUGIN_LOG_DEBUG_FUNCTION; AssertPluginThread(); + AutoStackHelper guard(this); #if defined(MOZ_X11) && defined(DEBUG) if (GraphicsExpose == event.event.type) @@ -919,6 +928,7 @@ { PLUGIN_LOG_DEBUG_FUNCTION; AssertPluginThread(); + AutoStackHelper guard(this); PaintTracker pt; @@ -1023,6 +1033,7 @@ { PLUGIN_LOG_DEBUG_FUNCTION; AssertPluginThread(); + AutoStackHelper guard(this); PaintTracker pt; @@ -1218,6 +1229,7 @@ NS_ASSERTION(!mLayersRendering && !mPendingPluginCall, "Shouldn't be receiving NPP_SetWindow with layer rendering"); AssertPluginThread(); + AutoStackHelper guard(this); #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) NS_ASSERTION(mWsInfo.display, "We should have a valid display!"); @@ -2471,6 +2483,7 @@ uint16_t* stype) { AssertPluginThread(); + AutoStackHelper guard(this); NPError rv = actor->StreamConstructed(mimeType, seekable, stype); return rv; } @@ -2689,6 +2702,7 @@ NPStream** aStream) { AssertPluginThread(); + AutoStackHelper guard(this); PluginStreamChild* ps = new PluginStreamChild(); @@ -2771,6 +2785,7 @@ void *initData, NPAsyncSurface *surface) { AssertPluginThread(); + AutoStackHelper guard(this); if (!IsUsingDirectDrawing()) { return NPERR_INVALID_PARAM; @@ -2988,6 +3003,7 @@ { AssertPluginThread(); + AutoStackHelper guard(this); NS_ASSERTION(!aWindow.window, "Remote window should be null."); if (mCurrentAsyncSetWindowTask) { @@ -4242,6 +4258,9 @@ if (mDestroyed) { return; } + if (mStackDepth != 0) { + NS_RUNTIMEABORT("Destroying plugin instance on the stack."); + } mDestroyed = true; #if defined(OS_WIN) diff -Nru firefox-47.0~b1+build1/dom/plugins/ipc/PluginInstanceChild.h firefox-47.0~b2+build1/dom/plugins/ipc/PluginInstanceChild.h --- firefox-47.0~b1+build1/dom/plugins/ipc/PluginInstanceChild.h 2016-04-26 07:45:09.000000000 +0000 +++ firefox-47.0~b2+build1/dom/plugins/ipc/PluginInstanceChild.h 2016-05-03 05:14:21.000000000 +0000 @@ -657,6 +657,25 @@ // Has this instance been destroyed, either by ActorDestroy or NPP_Destroy? bool mDestroyed; + + // A counter is incremented by AutoStackHelper to indicate that there is an + // active plugin call which should be preventing shutdown. +public: + class AutoStackHelper { + public: + explicit AutoStackHelper(PluginInstanceChild* instance) + : mInstance(instance) + { + ++mInstance->mStackDepth; + } + ~AutoStackHelper() { + --mInstance->mStackDepth; + } + private: + PluginInstanceChild *const mInstance; + }; +private: + int32_t mStackDepth; }; } // namespace plugins diff -Nru firefox-47.0~b1+build1/dom/plugins/ipc/PluginScriptableObjectChild.cpp firefox-47.0~b2+build1/dom/plugins/ipc/PluginScriptableObjectChild.cpp --- firefox-47.0~b1+build1/dom/plugins/ipc/PluginScriptableObjectChild.cpp 2016-04-26 07:45:09.000000000 +0000 +++ firefox-47.0~b2+build1/dom/plugins/ipc/PluginScriptableObjectChild.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -338,6 +338,8 @@ NS_ASSERTION(actor, "This shouldn't ever be null!"); NS_ASSERTION(actor->Type() == Proxy, "Bad type!"); + PluginInstanceChild::AutoStackHelper guard(actor->mInstance); + Variant result; bool success; actor->CallGetParentProperty(FromNPIdentifier(aName), @@ -707,6 +709,7 @@ PluginScriptableObjectChild::AnswerInvalidate() { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); if (mInvalidated) { return true; @@ -731,6 +734,7 @@ bool* aHasMethod) { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); if (mInvalidated) { NS_WARNING("Calling AnswerHasMethod with an invalidated object!"); @@ -758,6 +762,7 @@ bool* aSuccess) { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); if (mInvalidated) { NS_WARNING("Calling AnswerInvoke with an invalidated object!"); @@ -828,6 +833,7 @@ bool* aSuccess) { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); if (mInvalidated) { NS_WARNING("Calling AnswerInvokeDefault with an invalidated object!"); @@ -896,6 +902,7 @@ bool* aHasProperty) { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); if (mInvalidated) { NS_WARNING("Calling AnswerHasProperty with an invalidated object!"); @@ -924,6 +931,7 @@ bool* aSuccess) { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); *aHasProperty = *aHasMethod = *aSuccess = false; *aResult = void_t(); @@ -972,6 +980,7 @@ bool* aSuccess) { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); if (mInvalidated) { NS_WARNING("Calling AnswerSetProperty with an invalidated object!"); @@ -1010,6 +1019,7 @@ bool* aSuccess) { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); if (mInvalidated) { NS_WARNING("Calling AnswerRemoveProperty with an invalidated object!"); @@ -1040,6 +1050,7 @@ bool* aSuccess) { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); if (mInvalidated) { NS_WARNING("Calling AnswerEnumerate with an invalidated object!"); @@ -1079,6 +1090,7 @@ bool* aSuccess) { AssertPluginThread(); + PluginInstanceChild::AutoStackHelper guard(mInstance); if (mInvalidated) { NS_WARNING("Calling AnswerConstruct with an invalidated object!"); @@ -1165,6 +1177,8 @@ PluginScriptableObjectChild::Evaluate(NPString* aScript, NPVariant* aResult) { + PluginInstanceChild::AutoStackHelper guard(mInstance); + nsDependentCString script(""); if (aScript->UTF8Characters && aScript->UTF8Length) { script.Rebind(aScript->UTF8Characters, aScript->UTF8Length); diff -Nru firefox-47.0~b1+build1/dom/workers/ServiceWorkerEvents.cpp firefox-47.0~b2+build1/dom/workers/ServiceWorkerEvents.cpp --- firefox-47.0~b1+build1/dom/workers/ServiceWorkerEvents.cpp 2016-04-26 07:45:10.000000000 +0000 +++ firefox-47.0~b2+build1/dom/workers/ServiceWorkerEvents.cpp 2016-05-03 05:14:23.000000000 +0000 @@ -52,8 +52,10 @@ BEGIN_WORKERS_NAMESPACE CancelChannelRunnable::CancelChannelRunnable(nsMainThreadPtrHandle& aChannel, + nsMainThreadPtrHandle& aRegistration, nsresult aStatus) : mChannel(aChannel) + , mRegistration(aRegistration) , mStatus(aStatus) { } @@ -62,8 +64,8 @@ CancelChannelRunnable::Run() { MOZ_ASSERT(NS_IsMainThread()); - nsresult rv = mChannel->Cancel(mStatus); - NS_ENSURE_SUCCESS(rv, rv); + mChannel->Cancel(mStatus); + mRegistration->MaybeScheduleUpdate(); return NS_OK; } @@ -82,9 +84,11 @@ void FetchEvent::PostInit(nsMainThreadPtrHandle& aChannel, + nsMainThreadPtrHandle& aRegistration, const nsACString& aScriptSpec) { mChannel = aChannel; + mRegistration = aRegistration; mScriptSpec.Assign(aScriptSpec); } @@ -255,6 +259,7 @@ class RespondWithHandler final : public PromiseNativeHandler { nsMainThreadPtrHandle mInterceptedChannel; + nsMainThreadPtrHandle mRegistration; const RequestMode mRequestMode; const DebugOnly mIsClientRequest; const bool mIsNavigationRequest; @@ -268,6 +273,7 @@ NS_DECL_ISUPPORTS RespondWithHandler(nsMainThreadPtrHandle& aChannel, + nsMainThreadPtrHandle& aRegistration, RequestMode aRequestMode, bool aIsClientRequest, bool aIsNavigationRequest, const nsACString& aScriptSpec, @@ -276,6 +282,7 @@ uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber) : mInterceptedChannel(aChannel) + , mRegistration(aRegistration) , mRequestMode(aRequestMode) , mIsClientRequest(aIsClientRequest) , mIsNavigationRequest(aIsNavigationRequest) @@ -322,6 +329,7 @@ struct RespondWithClosure { nsMainThreadPtrHandle mInterceptedChannel; + nsMainThreadPtrHandle mRegistration; RefPtr mInternalResponse; ChannelInfo mWorkerChannelInfo; const nsCString mScriptSpec; @@ -332,6 +340,7 @@ const uint32_t mRespondWithColumnNumber; RespondWithClosure(nsMainThreadPtrHandle& aChannel, + nsMainThreadPtrHandle& aRegistration, InternalResponse* aInternalResponse, const ChannelInfo& aWorkerChannelInfo, const nsCString& aScriptSpec, @@ -341,6 +350,7 @@ uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber) : mInterceptedChannel(aChannel) + , mRegistration(aRegistration) , mInternalResponse(aInternalResponse) , mWorkerChannelInfo(aWorkerChannelInfo) , mScriptSpec(aScriptSpec) @@ -363,6 +373,7 @@ NS_LITERAL_CSTRING("InterceptionFailedWithURL"), data->mRequestURL); event = new CancelChannelRunnable(data->mInterceptedChannel, + data->mRegistration, NS_ERROR_INTERCEPTION_FAILED); } else { event = new FinishResponse(data->mInterceptedChannel, @@ -609,7 +620,8 @@ } } - nsAutoPtr closure(new RespondWithClosure(mInterceptedChannel, ir, + nsAutoPtr closure(new RespondWithClosure(mInterceptedChannel, + mRegistration, ir, worker->GetChannelInfo(), mScriptSpec, responseURL, @@ -690,7 +702,7 @@ RespondWithHandler::CancelRequest(nsresult aStatus) { nsCOMPtr runnable = - new CancelChannelRunnable(mInterceptedChannel, aStatus); + new CancelChannelRunnable(mInterceptedChannel, mRegistration, aStatus); NS_DispatchToMainThread(runnable); mRequestWasHandled = true; } @@ -722,9 +734,9 @@ StopImmediatePropagation(); mWaitToRespond = true; RefPtr handler = - new RespondWithHandler(mChannel, mRequest->Mode(), ir->IsClientRequest(), - ir->IsNavigationRequest(), mScriptSpec, - NS_ConvertUTF8toUTF16(requestURL), + new RespondWithHandler(mChannel, mRegistration, mRequest->Mode(), + ir->IsClientRequest(), ir->IsNavigationRequest(), + mScriptSpec, NS_ConvertUTF8toUTF16(requestURL), spec, line, column); aArg.AppendNativeHandler(handler); diff -Nru firefox-47.0~b1+build1/dom/workers/ServiceWorkerEvents.h firefox-47.0~b2+build1/dom/workers/ServiceWorkerEvents.h --- firefox-47.0~b1+build1/dom/workers/ServiceWorkerEvents.h 2016-04-26 07:45:10.000000000 +0000 +++ firefox-47.0~b2+build1/dom/workers/ServiceWorkerEvents.h 2016-05-03 05:14:23.000000000 +0000 @@ -38,12 +38,16 @@ BEGIN_WORKERS_NAMESPACE +class ServiceWorkerRegistrationInfo; + class CancelChannelRunnable final : public nsRunnable { nsMainThreadPtrHandle mChannel; + nsMainThreadPtrHandle mRegistration; const nsresult mStatus; public: CancelChannelRunnable(nsMainThreadPtrHandle& aChannel, + nsMainThreadPtrHandle& aRegistration, nsresult aStatus); NS_IMETHOD Run() override; @@ -104,6 +108,7 @@ class FetchEvent final : public ExtendableEvent { nsMainThreadPtrHandle mChannel; + nsMainThreadPtrHandle mRegistration; RefPtr mRequest; nsCString mScriptSpec; nsCString mPreventDefaultScriptSpec; @@ -130,6 +135,7 @@ } void PostInit(nsMainThreadPtrHandle& aChannel, + nsMainThreadPtrHandle& aRegistration, const nsACString& aScriptSpec); static already_AddRefed diff -Nru firefox-47.0~b1+build1/dom/workers/ServiceWorkerManager.cpp firefox-47.0~b2+build1/dom/workers/ServiceWorkerManager.cpp --- firefox-47.0~b1+build1/dom/workers/ServiceWorkerManager.cpp 2016-04-26 07:45:10.000000000 +0000 +++ firefox-47.0~b2+build1/dom/workers/ServiceWorkerManager.cpp 2016-05-03 05:14:23.000000000 +0000 @@ -2903,8 +2903,7 @@ const uint64_t kSecondsPerDay = 86400; const uint64_t now = PR_IntervalNow() / PR_MSEC_PER_SEC; - if ((mLastUpdateCheckTime != 0) && - (now - mLastUpdateCheckTime > kSecondsPerDay)) { + if ((now - mLastUpdateCheckTime) > kSecondsPerDay) { return true; } return false; diff -Nru firefox-47.0~b1+build1/dom/workers/ServiceWorkerPrivate.cpp firefox-47.0~b2+build1/dom/workers/ServiceWorkerPrivate.cpp --- firefox-47.0~b1+build1/dom/workers/ServiceWorkerPrivate.cpp 2016-04-26 07:45:10.000000000 +0000 +++ firefox-47.0~b2+build1/dom/workers/ServiceWorkerPrivate.cpp 2016-05-03 05:14:23.000000000 +0000 @@ -988,6 +988,7 @@ , public nsIHttpHeaderVisitor { nsMainThreadPtrHandle mInterceptedChannel; const nsCString mScriptSpec; + nsMainThreadPtrHandle mRegistration; nsTArray mHeaderNames; nsTArray mHeaderValues; nsCString mSpec; @@ -1015,6 +1016,7 @@ aWorkerPrivate, aKeepAliveToken, aRegistration) , mInterceptedChannel(aChannel) , mScriptSpec(aScriptSpec) + , mRegistration(aRegistration) , mClientId(aDocumentId) , mIsReload(aIsReload) , mRequestMode(RequestMode::No_cors) @@ -1244,7 +1246,7 @@ return false; } - event->PostInit(mInterceptedChannel, mScriptSpec); + event->PostInit(mInterceptedChannel, mRegistration, mScriptSpec); event->SetTrusted(true); RefPtr target = do_QueryObject(aWorkerPrivate->GlobalScope()); @@ -1260,11 +1262,8 @@ } if (!runnable) { - nsCOMPtr updateRunnable = - new RegistrationUpdateRunnable(mRegistration, false /* time check */); - NS_DispatchToMainThread(runnable.forget()); - runnable = new CancelChannelRunnable(mInterceptedChannel, + mRegistration, NS_ERROR_INTERCEPTION_FAILED); } diff -Nru firefox-47.0~b1+build1/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp firefox-47.0~b2+build1/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp --- firefox-47.0~b1+build1/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp 2016-04-26 07:45:12.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp 2016-05-03 05:14:24.000000000 +0000 @@ -453,7 +453,9 @@ gl::Error StateManager11::setRasterizerState(const gl::RasterizerState &rasterState) { - if (!mRasterizerStateIsDirty) + // TODO: Remove pointDrawMode and multiSample from gl::RasterizerState. + if (!mRasterizerStateIsDirty && rasterState.pointDrawMode == mCurRasterState.pointDrawMode && + rasterState.multiSample == mCurRasterState.multiSample) { return gl::Error(GL_NO_ERROR); } diff -Nru firefox-47.0~b1+build1/gfx/angle/src/tests/gl_tests/PointSpritesTest.cpp firefox-47.0~b2+build1/gfx/angle/src/tests/gl_tests/PointSpritesTest.cpp --- firefox-47.0~b1+build1/gfx/angle/src/tests/gl_tests/PointSpritesTest.cpp 2016-04-26 07:45:12.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/angle/src/tests/gl_tests/PointSpritesTest.cpp 2016-05-03 05:14:24.000000000 +0000 @@ -432,6 +432,84 @@ glDeleteProgram(program); } +// Test to cover a bug where the D3D11 rasterizer state would not be update when switching between +// draw types. This causes the cull face to potentially be incorrect when drawing emulated point +// spites. +TEST_P(PointSpritesTest, PointSpriteAlternatingDrawTypes) +{ + // clang-format off + const std::string pointFS = SHADER_SOURCE + ( + precision mediump float; + void main() + { + gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); + } + ); + + const std::string pointVS = SHADER_SOURCE + ( + void main() + { + gl_PointSize = 16.0; + gl_Position = vec4(0.0, 0.0, 0.0, 1.0); + } + ); + + const std::string quadFS = SHADER_SOURCE + ( + precision mediump float; + void main() + { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + ); + + const std::string quadVS = SHADER_SOURCE + ( + precision mediump float; + attribute vec4 pos; + void main() + { + gl_Position = pos; + } + ); + // clang-format on + + GLuint pointProgram = CompileProgram(pointVS, pointFS); + ASSERT_NE(pointProgram, 0u); + ASSERT_GL_NO_ERROR(); + + GLuint quadProgram = CompileProgram(quadVS, quadFS); + ASSERT_NE(pointProgram, 0u); + ASSERT_GL_NO_ERROR(); + + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + + const GLfloat quadVertices[] = { + -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, -1.0f, -1.0f, 0.5f, + + -1.0f, 1.0f, 0.5f, 1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, + }; + + glUseProgram(quadProgram); + GLint positionLocation = glGetAttribLocation(quadProgram, "pos"); + glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices); + glEnableVertexAttribArray(positionLocation); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glUseProgram(pointProgram); + glDrawArrays(GL_POINTS, 0, 1); + ASSERT_GL_NO_ERROR(); + + // expect the center pixel to be green + EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 255, 0, 255); + + glDeleteProgram(pointProgram); + glDeleteProgram(quadProgram); +} + // Use this to select which configurations (e.g. which renderer, which GLES // major version) these tests should be run against. // diff -Nru firefox-47.0~b1+build1/gfx/ipc/GfxMessageUtils.h firefox-47.0~b2+build1/gfx/ipc/GfxMessageUtils.h --- firefox-47.0~b1+build1/gfx/ipc/GfxMessageUtils.h 2016-04-26 07:45:13.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/ipc/GfxMessageUtils.h 2016-05-03 05:14:25.000000000 +0000 @@ -698,8 +698,6 @@ WriteParam(aMsg, aParam.GetContentDescription()); WriteParam(aMsg, aParam.mLineScrollAmount); WriteParam(aMsg, aParam.mPageScrollAmount); - WriteParam(aMsg, aParam.mClipRect); - WriteParam(aMsg, aParam.mMaskLayerIndex); WriteParam(aMsg, aParam.mPaintRequestTime); WriteParam(aMsg, aParam.mIsRootContent); WriteParam(aMsg, aParam.mHasScrollgrab); @@ -760,8 +758,6 @@ ReadContentDescription(aMsg, aIter, aResult) && ReadParam(aMsg, aIter, &aResult->mLineScrollAmount) && ReadParam(aMsg, aIter, &aResult->mPageScrollAmount) && - ReadParam(aMsg, aIter, &aResult->mClipRect) && - ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex) && ReadParam(aMsg, aIter, &aResult->mPaintRequestTime) && ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetIsRootContent) && ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetHasScrollgrab) && @@ -775,6 +771,54 @@ } }; +template <> +struct ParamTraits +{ + typedef mozilla::layers::ScrollSnapInfo paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.mScrollSnapTypeX); + WriteParam(aMsg, aParam.mScrollSnapTypeY); + WriteParam(aMsg, aParam.mScrollSnapIntervalX); + WriteParam(aMsg, aParam.mScrollSnapIntervalY); + WriteParam(aMsg, aParam.mScrollSnapDestination); + WriteParam(aMsg, aParam.mScrollSnapCoordinates); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + return (ReadParam(aMsg, aIter, &aResult->mScrollSnapTypeX) && + ReadParam(aMsg, aIter, &aResult->mScrollSnapTypeY) && + ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalX) && + ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalY) && + ReadParam(aMsg, aIter, &aResult->mScrollSnapDestination) && + ReadParam(aMsg, aIter, &aResult->mScrollSnapCoordinates)); + } +}; + +template <> +struct ParamTraits +{ + typedef mozilla::layers::ScrollMetadata paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.mMetrics); + WriteParam(aMsg, aParam.mSnapInfo); + WriteParam(aMsg, aParam.mMaskLayerIndex); + WriteParam(aMsg, aParam.mClipRect); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + return (ReadParam(aMsg, aIter, &aResult->mMetrics) && + ReadParam(aMsg, aIter, &aResult->mSnapInfo) && + ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex) && + ReadParam(aMsg, aIter, &aResult->mClipRect)); + } +}; + template<> struct ParamTraits { diff -Nru firefox-47.0~b1+build1/gfx/layers/apz/src/APZCTreeManager.cpp firefox-47.0~b2+build1/gfx/layers/apz/src/APZCTreeManager.cpp --- firefox-47.0~b1+build1/gfx/layers/apz/src/APZCTreeManager.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/apz/src/APZCTreeManager.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -456,7 +456,7 @@ APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId()); - apzc->NotifyLayersUpdated(aMetrics, aState.mIsFirstPaint, + apzc->NotifyLayersUpdated(aLayer.Metadata(), aState.mIsFirstPaint, aLayersId == aState.mOriginatingLayersId); // Since this is the first time we are encountering an APZC with this guid, diff -Nru firefox-47.0~b1+build1/gfx/layers/apz/src/APZUtils.h firefox-47.0~b2+build1/gfx/layers/apz/src/APZUtils.h --- firefox-47.0~b1+build1/gfx/layers/apz/src/APZUtils.h 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/apz/src/APZUtils.h 2016-05-03 05:14:12.000000000 +0000 @@ -25,7 +25,7 @@ enum CancelAnimationFlags : uint32_t { Default = 0x0, /* Cancel all animations */ ExcludeOverscroll = 0x1, /* Don't clear overscroll */ - RequestSnap = 0x2 /* Request snapping to snap points */ + ScrollSnap = 0x2 /* Snap to snap points */ }; inline CancelAnimationFlags diff -Nru firefox-47.0~b1+build1/gfx/layers/apz/src/AsyncPanZoomController.cpp firefox-47.0~b2+build1/gfx/layers/apz/src/AsyncPanZoomController.cpp --- firefox-47.0~b1+build1/gfx/layers/apz/src/AsyncPanZoomController.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/apz/src/AsyncPanZoomController.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -71,6 +71,7 @@ #include "nsThreadUtils.h" // for NS_IsMainThread #include "prsystem.h" // for PR_GetPhysicalMemorySize #include "SharedMemoryBasic.h" // for SharedMemoryBasic +#include "ScrollSnap.h" // for ScrollSnapUtils #include "WheelScrollAnimation.h" #define ENABLE_APZC_LOGGING 0 @@ -690,7 +691,13 @@ // snap point, so we request one now. If there are no snap points, this will // do nothing. If there are snap points, we'll get a scrollTo that snaps us // back to the nearest valid snap point. - mApzc.RequestSnap(); + // The scroll snapping is done in a deferred task, otherwise the state + // change to NOTHING caused by the overscroll animation ending would + // clobber a possible state change to SMOOTH_SCROLL in ScrollSnap(). + if (!mDeferredTasks.append(NewRunnableMethod(&mApzc, + &AsyncPanZoomController::ScrollSnap))) { + MOZ_CRASH(); + } return false; } return true; @@ -708,7 +715,6 @@ class SmoothScrollAnimation : public AsyncPanZoomAnimation { public: SmoothScrollAnimation(AsyncPanZoomController& aApzc, - ScrollSource aSource, const nsPoint &aInitialPosition, const nsPoint &aInitialVelocity, const nsPoint& aDestination, double aSpringConstant, @@ -859,6 +865,7 @@ // mTreeManager must be initialized before GetFrameTime() is called mTreeManager(aTreeManager), mSharingFrameMetricsAcrossProcesses(false), + mFrameMetrics(mScrollMetadata.GetMetrics()), mMonitor("AsyncPanZoomController"), mX(this), mY(this), @@ -923,7 +930,7 @@ { APZThreadUtils::AssertOnCompositorThread(); - CancelAnimation(CancelAnimationFlags::RequestSnap); + CancelAnimation(CancelAnimationFlags::ScrollSnap); { // scope the lock MonitorAutoLock lock(mRefPtrMonitor); @@ -1540,6 +1547,20 @@ { ReentrantMonitorAutoEnter lock(mMonitor); + ScheduleComposite(); + RequestContentRepaint(); + UpdateSharedCompositorFrameMetrics(); + } + + // Non-negative focus point would indicate that one finger is still down + if (aEvent.mFocusPoint.x != -1 && aEvent.mFocusPoint.y != -1) { + mPanDirRestricted = false; + mX.StartTouch(aEvent.mFocusPoint.x, aEvent.mTime); + mY.StartTouch(aEvent.mFocusPoint.y, aEvent.mTime); + SetState(TOUCHING); + } else { + // Otherwise, handle the fingers being lifted. + ReentrantMonitorAutoEnter lock(mMonitor); // We can get into a situation where we are overscrolled at the end of a // pinch if we go into overscroll with a two-finger pan, and then turn @@ -1555,21 +1576,8 @@ ClearOverscroll(); } // Along with clearing the overscroll, we also want to snap to the nearest - // snap point as appropriate, so ask the main thread (which knows about such - // things) to handle it. - RequestSnap(); - - ScheduleComposite(); - RequestContentRepaint(); - UpdateSharedCompositorFrameMetrics(); - } - - // Non-negative focus point would indicate that one finger is still down - if (aEvent.mFocusPoint.x != -1 && aEvent.mFocusPoint.y != -1) { - mPanDirRestricted = false; - mX.StartTouch(aEvent.mFocusPoint.x, aEvent.mTime); - mY.StartTouch(aEvent.mFocusPoint.y, aEvent.mTime); - SetState(TOUCHING); + // snap point as appropriate. + ScrollSnap(); } return nsEventStatus_eConsumeNoDefault; @@ -1993,7 +2001,7 @@ RequestContentRepaint(); if (!aEvent.mFollowedByMomentum) { - RequestSnap(); + ScrollSnap(); } return nsEventStatus_eConsumeNoDefault; @@ -2008,7 +2016,7 @@ } SetState(PAN_MOMENTUM); - RequestSnapToDestination(); + ScrollSnapToDestination(); // Call into OnPan in order to process any delta included in this event. OnPan(aEvent, false); @@ -2473,51 +2481,18 @@ mY.SetVelocity(mY.GetVelocity() + aHandoffState.mVelocity.y); aHandoffState.mVelocity.y = 0; } - SetState(FLING); - FlingAnimation *fling = new FlingAnimation(*this, - aHandoffState.mChain, - !aHandoffState.mIsHandoff, // only apply acceleration if this is an initial fling - aHandoffState.mScrolledApzc); - RequestSnapToDestination(); - StartAnimation(fling); -} - -void -AsyncPanZoomController::RequestSnapToDestination() -{ - ReentrantMonitorAutoEnter lock(mMonitor); - - float friction = gfxPrefs::APZFlingFriction(); - ParentLayerPoint velocity(mX.GetVelocity(), mY.GetVelocity()); - ParentLayerPoint predictedDelta; - // "-velocity / log(1.0 - friction)" is the integral of the deceleration - // curve modeled for flings in the "Axis" class. - if (velocity.x != 0.0f) { - predictedDelta.x = -velocity.x / log(1.0 - friction); - } - if (velocity.y != 0.0f) { - predictedDelta.y = -velocity.y / log(1.0 - friction); - } - CSSPoint predictedDestination = mFrameMetrics.GetScrollOffset() + predictedDelta / mFrameMetrics.GetZoom(); - // If the fling will overscroll, don't request a fling snap, because the - // resulting content scrollTo() would unnecessarily cancel the overscroll - // animation. - bool flingWillOverscroll = IsOverscrolled() && ((velocity.x * mX.GetOverscroll() >= 0) || - (velocity.y * mY.GetOverscroll() >= 0)); - if (!flingWillOverscroll) { - RefPtr controller = GetGeckoContentController(); - if (controller) { - APZC_LOG("%p fling snapping. friction: %f velocity: %f, %f " - "predictedDelta: %f, %f position: %f, %f " - "predictedDestination: %f, %f\n", - this, friction, velocity.x, velocity.y, (float)predictedDelta.x, - (float)predictedDelta.y, (float)mFrameMetrics.GetScrollOffset().x, - (float)mFrameMetrics.GetScrollOffset().y, - (float)predictedDestination.x, (float)predictedDestination.y); - controller->RequestFlingSnap(mFrameMetrics.GetScrollId(), - predictedDestination); - } + // If there's a scroll snap point near the predicted fling destination, + // scroll there using a smooth scroll animation. Otherwise, start a + // fling animation. + ScrollSnapToDestination(); + if (mState != SMOOTH_SCROLL) { + SetState(FLING); + FlingAnimation *fling = new FlingAnimation(*this, + aHandoffState.mChain, + !aHandoffState.mIsHandoff, // only apply acceleration if this is an initial fling + aHandoffState.mScrolledApzc); + StartAnimation(fling); } } @@ -2560,21 +2535,28 @@ HandleFlingOverscroll(aVelocity, BuildOverscrollHandoffChain(), nullptr); } -void AsyncPanZoomController::StartSmoothScroll(ScrollSource aSource) { - SetState(SMOOTH_SCROLL); - nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset()); - // Cast velocity from ParentLayerPoints/ms to CSSPoints/ms then convert to - // appunits/second - nsPoint initialVelocity = CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(), - mY.GetVelocity())) * 1000.0f; - nsPoint destination = CSSPoint::ToAppUnits(mFrameMetrics.GetSmoothScrollOffset()); - - StartAnimation(new SmoothScrollAnimation(*this, - aSource, - initialPosition, initialVelocity, - destination, - gfxPrefs::ScrollBehaviorSpringConstant(), - gfxPrefs::ScrollBehaviorDampingRatio())); +void AsyncPanZoomController::SmoothScrollTo(const CSSPoint& aDestination) { + if (mState == SMOOTH_SCROLL && mAnimation) { + APZC_LOG("%p updating destination on existing animation\n", this); + RefPtr animation( + static_cast(mAnimation.get())); + animation->SetDestination(CSSPoint::ToAppUnits(aDestination)); + } else { + CancelAnimation(); + SetState(SMOOTH_SCROLL); + nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset()); + // Cast velocity from ParentLayerPoints/ms to CSSPoints/ms then convert to + // appunits/second + nsPoint initialVelocity = CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(), + mY.GetVelocity())) * 1000.0f; + nsPoint destination = CSSPoint::ToAppUnits(aDestination); + + StartAnimation(new SmoothScrollAnimation(*this, + initialPosition, initialVelocity, + destination, + gfxPrefs::ScrollBehaviorSpringConstant(), + gfxPrefs::ScrollBehaviorDampingRatio())); + } } void AsyncPanZoomController::StartOverscrollAnimation(const ParentLayerPoint& aVelocity) { @@ -2655,9 +2637,9 @@ repaint = true; } // Similar to relieving overscroll, we also need to snap to any snap points - // if appropriate, so ask the main thread to do that. - if (aFlags & CancelAnimationFlags::RequestSnap) { - RequestSnap(); + // if appropriate. + if (aFlags & CancelAnimationFlags::ScrollSnap) { + ScrollSnap(); } if (repaint) { RequestContentRepaint(); @@ -2854,7 +2836,7 @@ // main thread to snap to any nearby snap points, assuming we haven't already // done so when we started this fling if (mState != FLING) { - RequestSnap(); + ScrollSnap(); } return false; } @@ -3249,14 +3231,16 @@ return true; } -void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, +void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMetadata, bool aIsFirstPaint, bool aThisLayerTreeUpdated) { APZThreadUtils::AssertOnCompositorThread(); ReentrantMonitorAutoEnter lock(mMonitor); - bool isDefault = mFrameMetrics.IsDefault(); + bool isDefault = mScrollMetadata.IsDefault(); + + const FrameMetrics& aLayerMetrics = aScrollMetadata.GetMetrics(); mLastContentPaintMetrics = aLayerMetrics; @@ -3332,7 +3316,7 @@ // that was just painted is something we knew nothing about previously CancelAnimation(); - mFrameMetrics = aLayerMetrics; + mScrollMetadata = aScrollMetadata; if (scrollOffsetUpdated) { AcknowledgeScrollUpdate(); } @@ -3388,8 +3372,9 @@ mFrameMetrics.SetHasScrollgrab(aLayerMetrics.GetHasScrollgrab()); mFrameMetrics.SetLineScrollAmount(aLayerMetrics.GetLineScrollAmount()); mFrameMetrics.SetPageScrollAmount(aLayerMetrics.GetPageScrollAmount()); - mFrameMetrics.SetClipRect(aLayerMetrics.GetClipRect()); - mFrameMetrics.SetMaskLayerIndex(aLayerMetrics.GetMaskLayerIndex()); + mScrollMetadata.SetSnapInfo(ScrollSnapInfo(aScrollMetadata.GetSnapInfo())); + mScrollMetadata.SetClipRect(aScrollMetadata.GetClipRect()); + mScrollMetadata.SetMaskLayerIndex(aScrollMetadata.GetMaskLayerIndex()); mFrameMetrics.SetIsLayersIdRoot(aLayerMetrics.IsLayersIdRoot()); mFrameMetrics.SetUsesContainerScrolling(aLayerMetrics.UsesContainerScrolling()); mFrameMetrics.SetIsScrollInfoLayer(aLayerMetrics.IsScrollInfoLayer()); @@ -3442,16 +3427,7 @@ AcknowledgeScrollUpdate(); mExpectedGeckoMetrics = aLayerMetrics; - if (mState == SMOOTH_SCROLL && mAnimation) { - APZC_LOG("%p updating destination on existing animation\n", this); - RefPtr animation( - static_cast(mAnimation.get())); - animation->SetDestination( - CSSPoint::ToAppUnits(aLayerMetrics.GetSmoothScrollOffset())); - } else { - CancelAnimation(); - StartSmoothScroll(ScrollSource::DOM); - } + SmoothScrollTo(mFrameMetrics.GetSmoothScrollOffset()); } if (needContentRepaint) { @@ -3664,7 +3640,7 @@ { mX.CancelGesture(); mY.CancelGesture(); - CancelAnimation(CancelAnimationFlags::RequestSnap); + CancelAnimation(CancelAnimationFlags::ScrollSnap); } bool @@ -3841,12 +3817,62 @@ } } -void AsyncPanZoomController::RequestSnap() { - if (RefPtr controller = GetGeckoContentController()) { - APZC_LOG("%p requesting snap near %s\n", this, - Stringify(mFrameMetrics.GetScrollOffset()).c_str()); - controller->RequestFlingSnap(mFrameMetrics.GetScrollId(), - mFrameMetrics.GetScrollOffset()); +void AsyncPanZoomController::ScrollSnapNear(const CSSPoint& aDestination) { + mMonitor.AssertCurrentThreadIn(); + APZC_LOG("%p scroll snapping near %s\n", this, Stringify(aDestination).c_str()); + CSSRect scrollRange = mFrameMetrics.CalculateScrollRange(); + if (Maybe snapPoint = ScrollSnapUtils::GetSnapPointForDestination( + mScrollMetadata.GetSnapInfo(), + nsIScrollableFrame::DEVICE_PIXELS, + CSSSize::ToAppUnits(mFrameMetrics.CalculateCompositedSizeInCssPixels()), + CSSRect::ToAppUnits(scrollRange), + CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset()), + CSSPoint::ToAppUnits(aDestination))) { + CSSPoint cssSnapPoint = CSSPoint::FromAppUnits(snapPoint.ref()); + // GetSnapPointForDestination() can produce a destination that's outside + // of the scroll frame's scroll range. Clamp it here (this matches the + // behaviour of the main-thread code path, which clamps it in + // nsGfxScrollFrame::ScrollTo()). + cssSnapPoint = scrollRange.ClampPoint(cssSnapPoint); + SmoothScrollTo(cssSnapPoint); + } +} + +void AsyncPanZoomController::ScrollSnap() { + ReentrantMonitorAutoEnter lock(mMonitor); + ScrollSnapNear(mFrameMetrics.GetScrollOffset()); +} + +void AsyncPanZoomController::ScrollSnapToDestination() { + ReentrantMonitorAutoEnter lock(mMonitor); + + float friction = gfxPrefs::APZFlingFriction(); + ParentLayerPoint velocity(mX.GetVelocity(), mY.GetVelocity()); + ParentLayerPoint predictedDelta; + // "-velocity / log(1.0 - friction)" is the integral of the deceleration + // curve modeled for flings in the "Axis" class. + if (velocity.x != 0.0f) { + predictedDelta.x = -velocity.x / log(1.0 - friction); + } + if (velocity.y != 0.0f) { + predictedDelta.y = -velocity.y / log(1.0 - friction); + } + CSSPoint predictedDestination = mFrameMetrics.GetScrollOffset() + predictedDelta / mFrameMetrics.GetZoom(); + + // If the fling will overscroll, don't scroll snap, because then the user + // user would not see any overscroll animation. + bool flingWillOverscroll = IsOverscrolled() && ((velocity.x * mX.GetOverscroll() >= 0) || + (velocity.y * mY.GetOverscroll() >= 0)); + if (!flingWillOverscroll) { + APZC_LOG("%p fling snapping. friction: %f velocity: %f, %f " + "predictedDelta: %f, %f position: %f, %f " + "predictedDestination: %f, %f\n", + this, friction, velocity.x, velocity.y, (float)predictedDelta.x, + (float)predictedDelta.y, (float)mFrameMetrics.GetScrollOffset().x, + (float)mFrameMetrics.GetScrollOffset().y, + (float)predictedDestination.x, (float)predictedDestination.y); + + ScrollSnapNear(predictedDestination); } } diff -Nru firefox-47.0~b1+build1/gfx/layers/apz/src/AsyncPanZoomController.h firefox-47.0~b2+build1/gfx/layers/apz/src/AsyncPanZoomController.h --- firefox-47.0~b1+build1/gfx/layers/apz/src/AsyncPanZoomController.h 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/apz/src/AsyncPanZoomController.h 2016-05-03 05:14:12.000000000 +0000 @@ -178,13 +178,13 @@ AsyncTransformComponentMatrix GetOverscrollTransform() const; /** - * A shadow layer update has arrived. |aLayerMetrics| is the new FrameMetrics + * A shadow layer update has arrived. |aScrollMetdata| is the new ScrollMetadata * for the container layer corresponding to this APZC. * |aIsFirstPaint| is a flag passed from the shadow - * layers code indicating that the frame metrics being sent with this call are - * the initial metrics and the initial paint of the frame has just happened. + * layers code indicating that the scroll metadata being sent with this call are + * the initial metadata and the initial paint of the frame has just happened. */ - void NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint, + void NotifyLayersUpdated(const ScrollMetadata& aScrollMetadata, bool aIsFirstPaint, bool aThisLayerTreeUpdated); /** @@ -641,13 +641,14 @@ // Common processing at the end of a touch block. void OnTouchEndOrCancel(); - // This is called to request that the main thread snap the scroll position - // to a nearby snap position if appropriate. The current scroll position is - // used as the final destination. - void RequestSnap(); - // Same as above, but takes into account the current velocity to find a - // predicted destination. - void RequestSnapToDestination(); + // Snap to a snap position nearby the current scroll position, if appropriate. + void ScrollSnap(); + // Snap to a snap position nearby the destination predicted based on the + // current velocity, if appropriate. + void ScrollSnapToDestination(); + + // Helper function for ScrollSnap() and ScrollSnapToDestination(). + void ScrollSnapNear(const CSSPoint& aDestination); uint64_t mLayersId; RefPtr mCompositorParent; @@ -679,7 +680,8 @@ protected: // Both |mFrameMetrics| and |mLastContentPaintMetrics| are protected by the // monitor. Do not read from or modify either of them without locking. - FrameMetrics mFrameMetrics; + ScrollMetadata mScrollMetadata; + FrameMetrics& mFrameMetrics; // for convenience, refers to mScrollMetadata.mMetrics // Protects |mFrameMetrics|, |mLastContentPaintMetrics|, and |mState|. // Before manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the @@ -871,7 +873,7 @@ // Start an overscroll animation with the given initial velocity. void StartOverscrollAnimation(const ParentLayerPoint& aVelocity); - void StartSmoothScroll(ScrollSource aSource); + void SmoothScrollTo(const CSSPoint& aDestination); // Returns whether overscroll is allowed during an event. bool AllowScrollHandoffInCurrentBlock() const; diff -Nru firefox-47.0~b1+build1/gfx/layers/apz/test/gtest/APZCTreeManagerTester.h firefox-47.0~b2+build1/gfx/layers/apz/test/gtest/APZCTreeManagerTester.h --- firefox-47.0~b1+build1/gfx/layers/apz/test/gtest/APZCTreeManagerTester.h 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/apz/test/gtest/APZCTreeManagerTester.h 2016-05-03 05:14:12.000000000 +0000 @@ -13,11 +13,13 @@ */ #include "APZTestCommon.h" +#include "gfxPlatform.h" class APZCTreeManagerTester : public ::testing::Test { protected: virtual void SetUp() { gfxPrefs::GetSingleton(); + gfxPlatform::GetPlatform(); APZThreadUtils::SetThreadAssertionsEnabled(false); APZThreadUtils::SetControllerThread(MessageLoop::current()); @@ -57,7 +59,8 @@ protected: static void SetScrollableFrameMetrics(Layer* aLayer, FrameMetrics::ViewID aScrollId, CSSRect aScrollableRect = CSSRect(-1, -1, -1, -1)) { - FrameMetrics metrics; + ScrollMetadata metadata; + FrameMetrics& metrics = metadata.GetMetrics(); metrics.SetScrollId(aScrollId); // By convention in this test file, START_SCROLL_ID is the root, so mark it as such. if (aScrollId == FrameMetrics::START_SCROLL_ID) { @@ -70,7 +73,7 @@ metrics.SetScrollOffset(CSSPoint(0, 0)); metrics.SetPageScrollAmount(LayoutDeviceIntSize(50, 100)); metrics.SetAllowVerticalScrollWithWheel(true); - aLayer->SetFrameMetrics(metrics); + aLayer->SetScrollMetadata(metadata); aLayer->SetClipRect(Some(ViewAs(layerBound))); if (!aScrollableRect.IsEqualEdges(CSSRect(-1, -1, -1, -1))) { // The purpose of this is to roughly mimic what layout would do in the @@ -84,13 +87,13 @@ } void SetScrollHandoff(Layer* aChild, Layer* aParent) { - FrameMetrics metrics = aChild->GetFrameMetrics(0); - metrics.SetScrollParentId(aParent->GetFrameMetrics(0).GetScrollId()); - aChild->SetFrameMetrics(metrics); + ScrollMetadata metadata = aChild->GetScrollMetadata(0); + metadata.GetMetrics().SetScrollParentId(aParent->GetFrameMetrics(0).GetScrollId()); + aChild->SetScrollMetadata(metadata); } static TestAsyncPanZoomController* ApzcOf(Layer* aLayer) { - EXPECT_EQ(1u, aLayer->GetFrameMetricsCount()); + EXPECT_EQ(1u, aLayer->GetScrollMetadataCount()); return (TestAsyncPanZoomController*)aLayer->GetAsyncPanZoomController(0); } @@ -151,9 +154,9 @@ SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1); // Make layers[1] the root content - FrameMetrics childMetrics = layers[1]->GetFrameMetrics(0); - childMetrics.SetIsRootContent(true); - layers[1]->SetFrameMetrics(childMetrics); + ScrollMetadata childMetadata = layers[1]->GetScrollMetadata(0); + childMetadata.GetMetrics().SetIsRootContent(true); + layers[1]->SetScrollMetadata(childMetadata); // Both layers are fully dispatch-to-content EventRegions regions; diff -Nru firefox-47.0~b1+build1/gfx/layers/apz/test/gtest/TestBasic.cpp firefox-47.0~b2+build1/gfx/layers/apz/test/gtest/TestBasic.cpp --- firefox-47.0~b1+build1/gfx/layers/apz/test/gtest/TestBasic.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/apz/test/gtest/TestBasic.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -78,7 +78,8 @@ RefPtr lm; RefPtr root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers); - FrameMetrics metrics; + ScrollMetadata metadata; + FrameMetrics& metrics = metadata.GetMetrics(); metrics.SetCompositionBounds(ParentLayerRect(0, 0, 24, 24)); metrics.SetDisplayPort(CSSRect(-1, -1, 6, 6)); metrics.SetScrollOffset(CSSPoint(10, 10)); @@ -89,11 +90,12 @@ metrics.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale(3)); metrics.SetScrollId(FrameMetrics::START_SCROLL_ID); - FrameMetrics childMetrics = metrics; + ScrollMetadata childMetadata = metadata; + FrameMetrics& childMetrics = childMetadata.GetMetrics(); childMetrics.SetScrollId(FrameMetrics::START_SCROLL_ID + 1); - layers[0]->SetFrameMetrics(metrics); - layers[1]->SetFrameMetrics(childMetrics); + layers[0]->SetScrollMetadata(metadata); + layers[1]->SetScrollMetadata(childMetadata); ParentLayerPoint pointOut; AsyncTransform viewTransformOut; @@ -103,13 +105,13 @@ // initial transform apzc->SetFrameMetrics(metrics); - apzc->NotifyLayersUpdated(metrics, true, true); + apzc->NotifyLayersUpdated(metadata, true, true); apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut); EXPECT_EQ(ParentLayerPoint(60, 60), pointOut); childApzc->SetFrameMetrics(childMetrics); - childApzc->NotifyLayersUpdated(childMetrics, true, true); + childApzc->NotifyLayersUpdated(childMetadata, true, true); childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut); EXPECT_EQ(ParentLayerPoint(60, 60), pointOut); diff -Nru firefox-47.0~b1+build1/gfx/layers/apz/util/ChromeProcessController.cpp firefox-47.0~b2+build1/gfx/layers/apz/util/ChromeProcessController.cpp --- firefox-47.0~b1+build1/gfx/layers/apz/util/ChromeProcessController.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/apz/util/ChromeProcessController.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -99,6 +99,9 @@ nsIPresShell* ChromeProcessController::GetPresShell() const { + if (!mWidget) { + return nullptr; + } if (nsView* view = nsView::GetViewFor(mWidget)) { return view->GetPresShell(); } diff -Nru firefox-47.0~b1+build1/gfx/layers/composite/AsyncCompositionManager.cpp firefox-47.0~b2+build1/gfx/layers/composite/AsyncCompositionManager.cpp --- firefox-47.0~b1+build1/gfx/layers/composite/AsyncCompositionManager.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/composite/AsyncCompositionManager.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -330,7 +330,7 @@ static LayerMetricsWrapper FindMetricsWithScrollId(Layer* aLayer, FrameMetrics::ViewID aScrollId) { - for (uint64_t i = 0; i < aLayer->GetFrameMetricsCount(); ++i) { + for (uint64_t i = 0; i < aLayer->GetScrollMetadataCount(); ++i) { if (aLayer->GetFrameMetrics(i).GetScrollId() == aScrollId) { return LayerMetricsWrapper(aLayer, i); } @@ -687,7 +687,7 @@ RecordShadowTransforms(child); } - for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) { + for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) { AsyncPanZoomController* apzc = aLayer->GetAsyncPanZoomController(i); if (!apzc) { continue; @@ -842,7 +842,7 @@ // of all scroll frames inside the current one. nsTArray ancestorMaskLayers; - for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) { + for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) { AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(i); if (!controller) { continue; @@ -863,7 +863,8 @@ controller->MarkAsyncTransformAppliedToContent(); } - const FrameMetrics& metrics = aLayer->GetFrameMetrics(i); + const ScrollMetadata& scrollMetadata = aLayer->GetScrollMetadata(i); + const FrameMetrics& metrics = scrollMetadata.GetMetrics(); #if defined(MOZ_ANDROID_APZ) // If we find a metrics which is the root content doc, use that. If not, use @@ -875,7 +876,7 @@ if (!(*aOutFoundRoot)) { *aOutFoundRoot = metrics.IsRootContent() || /* RCD */ (aLayer->GetParent() == nullptr && /* rootmost metrics */ - i + 1 >= aLayer->GetFrameMetricsCount()); + i + 1 >= aLayer->GetScrollMetadataCount()); if (*aOutFoundRoot) { mRootScrollableId = metrics.GetScrollId(); CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor(); @@ -944,8 +945,8 @@ // Combine the local clip with the ancestor scrollframe clip. This is not // included in the async transform above, since the ancestor clip should not // move with this APZC. - if (metrics.HasClipRect()) { - ParentLayerIntRect clip = metrics.ClipRect(); + if (scrollMetadata.HasClipRect()) { + ParentLayerIntRect clip = scrollMetadata.ClipRect(); if (aLayer->GetParent() && aLayer->GetParent()->GetTransformIsPerspective()) { // If our parent layer has a perspective transform, we want to apply // our scroll clip to it instead of to this layer (see bug 1168263). @@ -973,8 +974,8 @@ } // Append the ancestor mask layer for this scroll frame to ancestorMaskLayers. - if (metrics.GetMaskLayerIndex()) { - size_t maskLayerIndex = metrics.GetMaskLayerIndex().value(); + if (scrollMetadata.GetMaskLayerIndex()) { + size_t maskLayerIndex = scrollMetadata.GetMaskLayerIndex().value(); Layer* ancestorMaskLayer = aLayer->GetAncestorMaskLayerAt(maskLayerIndex); ancestorMaskLayers.AppendElement(ancestorMaskLayer); } diff -Nru firefox-47.0~b1+build1/gfx/layers/composite/ContainerLayerComposite.cpp firefox-47.0~b2+build1/gfx/layers/composite/ContainerLayerComposite.cpp --- firefox-47.0~b1+build1/gfx/layers/composite/ContainerLayerComposite.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/composite/ContainerLayerComposite.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -358,7 +358,8 @@ static bool NeedToDrawCheckerboardingForLayer(Layer* aLayer, Color* aOutCheckerboardingColor) { - return (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) && + return (aLayer->Manager()->AsyncPanZoomEnabled() && + aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) && aLayer->IsOpaqueForVisibility() && LayerHasCheckerboardingAPZC(aLayer, aOutCheckerboardingColor); } @@ -476,7 +477,7 @@ { Compositor* compositor = aManager->GetCompositor(); - if (aLayer->GetFrameMetricsCount() < 1) { + if (aLayer->GetScrollMetadataCount() < 1) { return; } @@ -628,7 +629,7 @@ // frames higher up, so loop from the top down, and accumulate an async // transform as we go along. Matrix4x4 asyncTransform; - for (uint32_t i = layer->GetFrameMetricsCount(); i > 0; --i) { + for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; --i) { if (layer->GetFrameMetrics(i - 1).IsScrollable()) { // Since the composition bounds are in the parent layer's coordinates, // use the parent's effective transform rather than the layer's own. diff -Nru firefox-47.0~b1+build1/gfx/layers/d3d11/TextureD3D11.cpp firefox-47.0~b2+build1/gfx/layers/d3d11/TextureD3D11.cpp --- firefox-47.0~b1+build1/gfx/layers/d3d11/TextureD3D11.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/d3d11/TextureD3D11.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -763,7 +763,7 @@ DXGIYCbCrTextureHostD3D11::SetCompositor(Compositor* aCompositor) { mCompositor = AssertD3D11Compositor(aCompositor); - if (!mCompositor) { + if (mCompositor && mTextureSources[0]) { mTextureSources[0]->SetCompositor(aCompositor); } } diff -Nru firefox-47.0~b1+build1/gfx/layers/FrameMetrics.cpp firefox-47.0~b2+build1/gfx/layers/FrameMetrics.cpp --- firefox-47.0~b1+build1/gfx/layers/FrameMetrics.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/FrameMetrics.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -10,7 +10,6 @@ namespace layers { const FrameMetrics::ViewID FrameMetrics::NULL_SCROLL_ID = 0; -const FrameMetrics FrameMetrics::sNullMetrics; void FrameMetrics::SetUsesContainerScrolling(bool aValue) { @@ -18,5 +17,7 @@ mUsesContainerScrolling = aValue; } +StaticAutoPtr ScrollMetadata::sNullMetadata; + +} } -} \ No newline at end of file diff -Nru firefox-47.0~b1+build1/gfx/layers/FrameMetrics.h firefox-47.0~b2+build1/gfx/layers/FrameMetrics.h --- firefox-47.0~b1+build1/gfx/layers/FrameMetrics.h 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/FrameMetrics.h 2016-05-03 05:14:12.000000000 +0000 @@ -13,8 +13,10 @@ #include "mozilla/gfx/Rect.h" // for RoundedIn #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor #include "mozilla/gfx/Logging.h" // for Log +#include "mozilla/StaticPtr.h" // for StaticAutoPtr #include "mozilla/TimeStamp.h" // for TimeStamp #include "nsString.h" +#include "nsStyleCoord.h" // for nsStyleCoord namespace IPC { template struct ParamTraits; @@ -37,7 +39,6 @@ static const ViewID NULL_SCROLL_ID; // This container layer does not scroll. static const ViewID START_SCROLL_ID = 2; // This is the ID that scrolling subframes // will begin at. - static const FrameMetrics sNullMetrics; // We often need an empty metrics FrameMetrics() : mScrollId(NULL_SCROLL_ID) @@ -62,8 +63,6 @@ , mContentDescription() , mLineScrollAmount(0, 0) , mPageScrollAmount(0, 0) - , mClipRect() - , mMaskLayerIndex() , mPaintRequestTime() , mIsRootContent(false) , mHasScrollgrab(false) @@ -104,8 +103,6 @@ // don't compare mContentDescription mLineScrollAmount == aOther.mLineScrollAmount && mPageScrollAmount == aOther.mPageScrollAmount && - mClipRect == aOther.mClipRect && - mMaskLayerIndex == aOther.mMaskLayerIndex && mPaintRequestTime == aOther.mPaintRequestTime && mIsRootContent == aOther.mIsRootContent && mHasScrollgrab == aOther.mHasScrollgrab && @@ -123,14 +120,6 @@ return !operator==(aOther); } - bool IsDefault() const - { - FrameMetrics def; - - def.mPresShellId = mPresShellId; - return (def == *this); - } - bool IsScrollable() const { return mScrollId != NULL_SCROLL_ID; @@ -204,6 +193,15 @@ return size; } + CSSRect CalculateScrollRange() const + { + CSSSize scrollPortSize = CalculateCompositedSizeInCssPixels(); + CSSRect scrollRange = mScrollableRect; + scrollRange.width = std::max(scrollRange.width - scrollPortSize.width, 0.0f); + scrollRange.height = std::max(scrollRange.height - scrollPortSize.height, 0.0f); + return scrollRange; + } + void ScrollBy(const CSSPoint& aPoint) { mScrollOffset += aPoint; @@ -521,28 +519,6 @@ mAllowVerticalScrollWithWheel = aValue; } - void SetClipRect(const Maybe& aClipRect) - { - mClipRect = aClipRect; - } - const Maybe& GetClipRect() const - { - return mClipRect; - } - bool HasClipRect() const { - return mClipRect.isSome(); - } - const ParentLayerIntRect& ClipRect() const { - return mClipRect.ref(); - } - - void SetMaskLayerIndex(const Maybe& aIndex) { - mMaskLayerIndex = aIndex; - } - const Maybe& GetMaskLayerIndex() const { - return mMaskLayerIndex; - } - void SetPaintRequestTime(const TimeStamp& aTime) { mPaintRequestTime = aTime; } @@ -724,14 +700,6 @@ // The value of GetPageScrollAmount(), for scroll frames. LayoutDeviceIntSize mPageScrollAmount; - // The clip rect to use when compositing a layer with this FrameMetrics. - Maybe mClipRect; - - // An extra clip mask layer to use when compositing a layer with this - // FrameMetrics. This is an index into the MetricsMaskLayers array on - // the Layer. - Maybe mMaskLayerIndex; - // The time at which the APZC last requested a repaint for this scrollframe. TimeStamp mPaintRequestTime; @@ -787,6 +755,124 @@ } }; +struct ScrollSnapInfo { + ScrollSnapInfo() + : mScrollSnapTypeX(NS_STYLE_SCROLL_SNAP_TYPE_NONE) + , mScrollSnapTypeY(NS_STYLE_SCROLL_SNAP_TYPE_NONE) + {} + + bool operator==(const ScrollSnapInfo& aOther) const + { + return mScrollSnapTypeX == aOther.mScrollSnapTypeX && + mScrollSnapTypeY == aOther.mScrollSnapTypeY && + mScrollSnapIntervalX == aOther.mScrollSnapIntervalX && + mScrollSnapIntervalY == aOther.mScrollSnapIntervalY && + mScrollSnapDestination == aOther.mScrollSnapDestination && + mScrollSnapCoordinates == aOther.mScrollSnapCoordinates; + } + + // The scroll frame's scroll-snap-type. + // One of NS_STYLE_SCROLL_SNAP_{NONE, MANDATORY, PROXIMITY}. + uint8_t mScrollSnapTypeX; + uint8_t mScrollSnapTypeY; + + // The intervals derived from the scroll frame's scroll-snap-points. + Maybe mScrollSnapIntervalX; + Maybe mScrollSnapIntervalY; + + // The scroll frame's scroll-snap-destination, in cooked form (to avoid + // shipping the raw nsStyleCoord::CalcValue over IPC). + nsPoint mScrollSnapDestination; + + // The scroll-snap-coordinates of any descendant frames of the scroll frame, + // relative to the origin of the scrolled frame. + nsTArray mScrollSnapCoordinates; +}; + +/** + * Metadata about a scroll frame that's stored in the layer tree for use by + * the compositor (including APZ). This includes the scroll frame's FrameMetrics, + * as well as other metadata. We don't put the other metadata into FrameMetrics + * to avoid FrameMetrics becoming too bloated (as a FrameMetrics is e.g. sent + * over IPC for every repaint request for every active scroll frame). + */ +struct ScrollMetadata { + friend struct IPC::ParamTraits; +public: + static StaticAutoPtr sNullMetadata; // We sometimes need an empty metadata + + ScrollMetadata() + : mMetrics() + , mSnapInfo() + , mMaskLayerIndex() + , mClipRect() + {} + + bool operator==(const ScrollMetadata& aOther) const + { + return mMetrics == aOther.mMetrics && + mSnapInfo == aOther.mSnapInfo && + mMaskLayerIndex == aOther.mMaskLayerIndex && + mClipRect == aOther.mClipRect; + } + + bool operator!=(const ScrollMetadata& aOther) const + { + return !operator==(aOther); + } + + bool IsDefault() const + { + ScrollMetadata def; + + def.mMetrics.SetPresShellId(mMetrics.GetPresShellId()); + return (def == *this); + } + + FrameMetrics& GetMetrics() { return mMetrics; } + const FrameMetrics& GetMetrics() const { return mMetrics; } + + void SetSnapInfo(ScrollSnapInfo&& aSnapInfo) { + mSnapInfo = Move(aSnapInfo); + } + const ScrollSnapInfo& GetSnapInfo() const { return mSnapInfo; } + + void SetMaskLayerIndex(const Maybe& aIndex) { + mMaskLayerIndex = aIndex; + } + const Maybe& GetMaskLayerIndex() const { + return mMaskLayerIndex; + } + + void SetClipRect(const Maybe& aClipRect) + { + mClipRect = aClipRect; + } + const Maybe& GetClipRect() const + { + return mClipRect; + } + bool HasClipRect() const { + return mClipRect.isSome(); + } + const ParentLayerIntRect& ClipRect() const { + return mClipRect.ref(); + } +private: + FrameMetrics mMetrics; + + // Information used to determine where to snap to for a given scroll. + ScrollSnapInfo mSnapInfo; + + // An extra clip mask layer to use when compositing a layer with this + // FrameMetrics. This is an index into the MetricsMaskLayers array on + // the Layer. + Maybe mMaskLayerIndex; + + // The clip rect to use when compositing a layer with this FrameMetrics. + Maybe mClipRect; +}; + /** * This class allows us to uniquely identify a scrollable layer. The * mLayersId identifies the layer tree (corresponding to a child process diff -Nru firefox-47.0~b1+build1/gfx/layers/ipc/APZChild.cpp firefox-47.0~b2+build1/gfx/layers/ipc/APZChild.cpp --- firefox-47.0~b1+build1/gfx/layers/ipc/APZChild.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/ipc/APZChild.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -78,12 +78,17 @@ return apz.forget(); } +APZChild::APZChild() + : mDestroyed(false) +{ +} + APZChild::~APZChild() { if (mObserver) { nsCOMPtr os = services::GetObserverService(); os->RemoveObserver(mObserver, "tab-child-created"); - } else { + } else if (mBrowser) { mBrowser->SetAPZChild(nullptr); } } @@ -159,6 +164,18 @@ return true; } +bool +APZChild::RecvDestroy() +{ + mDestroyed = true; + if (mBrowser) { + mBrowser->SetAPZChild(nullptr); + mBrowser = nullptr; + } + PAPZChild::Send__delete__(this); + return true; +} + void APZChild::SetObserver(nsIObserver* aObserver) { @@ -175,8 +192,13 @@ os->RemoveObserver(mObserver, "tab-child-created"); mObserver = nullptr; } - mBrowser = aBrowser; - mBrowser->SetAPZChild(this); + // We might get the tab-child-created notification after we receive a + // Destroy message from the parent. In that case we don't want to install + // ourselves with the browser. + if (!mDestroyed) { + mBrowser = aBrowser; + mBrowser->SetAPZChild(this); + } } } // namespace layers diff -Nru firefox-47.0~b1+build1/gfx/layers/ipc/APZChild.h firefox-47.0~b2+build1/gfx/layers/ipc/APZChild.h --- firefox-47.0~b1+build1/gfx/layers/ipc/APZChild.h 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/ipc/APZChild.h 2016-05-03 05:14:12.000000000 +0000 @@ -54,15 +54,18 @@ virtual bool RecvNotifyFlushComplete() override; + virtual bool RecvDestroy() override; + void SetBrowser(dom::TabChild* aBrowser); private: - APZChild() {}; + APZChild(); void SetObserver(nsIObserver* aObserver); RefPtr mBrowser; RefPtr mObserver; + bool mDestroyed; }; } // namespace layers diff -Nru firefox-47.0~b1+build1/gfx/layers/ipc/CompositorParent.cpp firefox-47.0~b2+build1/gfx/layers/ipc/CompositorParent.cpp --- firefox-47.0~b1+build1/gfx/layers/ipc/CompositorParent.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/ipc/CompositorParent.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -952,13 +952,13 @@ if (mLayerManager) { mLayerManager->Destroy(); mLayerManager = nullptr; - { // scope lock - MonitorAutoLock lock(*sIndirectLayerTreesLock); - sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = nullptr; - } mCompositionManager = nullptr; mCompositor = nullptr; } + { // scope lock + MonitorAutoLock lock(*sIndirectLayerTreesLock); + sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = nullptr; + } } diff -Nru firefox-47.0~b1+build1/gfx/layers/ipc/LayersMessages.ipdlh firefox-47.0~b2+build1/gfx/layers/ipc/LayersMessages.ipdlh --- firefox-47.0~b1+build1/gfx/layers/ipc/LayersMessages.ipdlh 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/ipc/LayersMessages.ipdlh 2016-05-03 05:14:12.000000000 +0000 @@ -41,7 +41,7 @@ using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h"; using mozilla::layers::EventRegionsOverride from "mozilla/layers/LayersTypes.h"; using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h"; -using struct mozilla::layers::FrameMetrics from "FrameMetrics.h"; +using struct mozilla::layers::ScrollMetadata from "FrameMetrics.h"; using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h"; using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h"; using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h"; @@ -237,7 +237,7 @@ // Animated colors will only honored for ColorLayers. Animation[] animations; nsIntRegion invalidRegion; - FrameMetrics[] metrics; + ScrollMetadata[] scrollMetadata; nsCString displayListLog; }; diff -Nru firefox-47.0~b1+build1/gfx/layers/ipc/LayerTransactionParent.cpp firefox-47.0~b2+build1/gfx/layers/ipc/LayerTransactionParent.cpp --- firefox-47.0~b1+build1/gfx/layers/ipc/LayerTransactionParent.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/ipc/LayerTransactionParent.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -367,7 +367,7 @@ layer->SetMaskLayer(nullptr); } layer->SetAnimations(common.animations()); - layer->SetFrameMetrics(common.metrics()); + layer->SetScrollMetadata(common.scrollMetadata()); layer->SetDisplayListLog(common.displayListLog().get()); // The updated invalid region is added to the existing one, since we can @@ -792,7 +792,7 @@ static AsyncPanZoomController* GetAPZCForViewID(Layer* aLayer, FrameMetrics::ViewID aScrollID) { - for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) { + for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) { if (aLayer->GetFrameMetrics(i).GetScrollId() == aScrollID) { return aLayer->GetAsyncPanZoomController(i); } diff -Nru firefox-47.0~b1+build1/gfx/layers/ipc/PAPZ.ipdl firefox-47.0~b2+build1/gfx/layers/ipc/PAPZ.ipdl --- firefox-47.0~b1+build1/gfx/layers/ipc/PAPZ.ipdl 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/ipc/PAPZ.ipdl 2016-05-03 05:14:12.000000000 +0000 @@ -83,6 +83,8 @@ async UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId, MaybeZoomConstraints aConstraints); + async __delete__(); + child: async UpdateFrame(FrameMetrics frame); @@ -97,7 +99,7 @@ async NotifyAPZStateChange(ViewID aViewId, APZStateChange aChange, int aArg); async NotifyFlushComplete(); - async __delete__(); + async Destroy(); }; } // layers diff -Nru firefox-47.0~b1+build1/gfx/layers/ipc/RemoteContentController.cpp firefox-47.0~b2+build1/gfx/layers/ipc/RemoteContentController.cpp --- firefox-47.0~b1+build1/gfx/layers/ipc/RemoteContentController.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/ipc/RemoteContentController.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -25,6 +25,8 @@ namespace mozilla { namespace layers { +static std::map> sDestroyedControllers; + RemoteContentController::RemoteContentController(uint64_t aLayersId, dom::TabParent* aBrowserParent) : mUILoop(MessageLoop::current()) @@ -37,9 +39,6 @@ RemoteContentController::~RemoteContentController() { - if (mBrowserParent) { - Unused << PAPZParent::Send__delete__(this); - } } void @@ -335,17 +334,13 @@ mApzcTreeManager = nullptr; } mBrowserParent = nullptr; -} -// TODO: Remove once upgraded to GCC 4.8+ on linux. Calling a static member -// function (like PAPZParent::Send__delete__) in a lambda leads to a bogus -// error: "'this' was not captured for this lambda function". -// -// (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51494) -static void -DeletePAPZParent(PAPZParent* aPAPZ) -{ - Unused << PAPZParent::Send__delete__(aPAPZ); + uint64_t key = mLayersId; + NS_DispatchToMainThread(NS_NewRunnableFunction([key]() { + // sDestroyedControllers may or may not contain the key, depending on + // whether or not SendDestroy() was successfully sent out or not. + sDestroyedControllers.erase(key); + })); } void @@ -354,7 +349,15 @@ RefPtr controller = this; NS_DispatchToMainThread(NS_NewRunnableFunction([controller] { if (controller->CanSend()) { - DeletePAPZParent(controller); + // Gfx code is done with this object, and it will probably get destroyed + // soon. However, if CanSend() is true, ActorDestroy has not yet been + // called, which means IPC code still has a handle to this object. We need + // to keep it alive until we get the ActorDestroy call, either via the + // __delete__ message or via IPC shutdown on our end. + uint64_t key = controller->mLayersId; + MOZ_ASSERT(sDestroyedControllers.find(key) == sDestroyedControllers.end()); + sDestroyedControllers[key] = controller; + Unused << controller->SendDestroy(); } })); } diff -Nru firefox-47.0~b1+build1/gfx/layers/ipc/ShadowLayers.cpp firefox-47.0~b2+build1/gfx/layers/ipc/ShadowLayers.cpp --- firefox-47.0~b1+build1/gfx/layers/ipc/ShadowLayers.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/ipc/ShadowLayers.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -678,7 +678,7 @@ common.maskLayerParent() = nullptr; common.animations() = mutant->GetAnimations(); common.invalidRegion() = mutant->GetInvalidRegion(); - common.metrics() = mutant->GetAllFrameMetrics(); + common.scrollMetadata() = mutant->GetAllScrollMetadata(); for (size_t i = 0; i < mutant->GetAncestorMaskLayerCount(); i++) { auto layer = Shadow(mutant->GetAncestorMaskLayerAt(i)->AsShadowableLayer()); common.ancestorMaskLayersChild().AppendElement(layer); diff -Nru firefox-47.0~b1+build1/gfx/layers/LayerMetricsWrapper.h firefox-47.0~b2+build1/gfx/layers/LayerMetricsWrapper.h --- firefox-47.0~b1+build1/gfx/layers/LayerMetricsWrapper.h 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/LayerMetricsWrapper.h 2016-05-03 05:14:12.000000000 +0000 @@ -142,7 +142,7 @@ switch (aStart) { case StartAt::TOP: - mIndex = mLayer->GetFrameMetricsCount(); + mIndex = mLayer->GetScrollMetadataCount(); if (mIndex > 0) { mIndex--; } @@ -161,7 +161,7 @@ , mIndex(aMetricsIndex) { MOZ_ASSERT(mLayer); - MOZ_ASSERT(mIndex == 0 || mIndex < mLayer->GetFrameMetricsCount()); + MOZ_ASSERT(mIndex == 0 || mIndex < mLayer->GetScrollMetadataCount()); } bool IsValid() const @@ -240,21 +240,26 @@ return LayerMetricsWrapper(nullptr); } - const FrameMetrics& Metrics() const + const ScrollMetadata& Metadata() const { MOZ_ASSERT(IsValid()); - if (mIndex >= mLayer->GetFrameMetricsCount()) { - return FrameMetrics::sNullMetrics; + if (mIndex >= mLayer->GetScrollMetadataCount()) { + return *ScrollMetadata::sNullMetadata; } - return mLayer->GetFrameMetrics(mIndex); + return mLayer->GetScrollMetadata(mIndex); + } + + const FrameMetrics& Metrics() const + { + return Metadata().GetMetrics(); } AsyncPanZoomController* GetApzc() const { MOZ_ASSERT(IsValid()); - if (mIndex >= mLayer->GetFrameMetricsCount()) { + if (mIndex >= mLayer->GetScrollMetadataCount()) { return nullptr; } return mLayer->GetAsyncPanZoomController(mIndex); @@ -264,12 +269,12 @@ { MOZ_ASSERT(IsValid()); - if (mLayer->GetFrameMetricsCount() == 0) { + if (mLayer->GetScrollMetadataCount() == 0) { MOZ_ASSERT(mIndex == 0); MOZ_ASSERT(aApzc == nullptr); return; } - MOZ_ASSERT(mIndex < mLayer->GetFrameMetricsCount()); + MOZ_ASSERT(mIndex < mLayer->GetScrollMetadataCount()); mLayer->SetAsyncPanZoomController(mIndex, aApzc); } @@ -441,30 +446,30 @@ static const FrameMetrics& TopmostScrollableMetrics(Layer* aLayer) { - for (uint32_t i = aLayer->GetFrameMetricsCount(); i > 0; i--) { + for (uint32_t i = aLayer->GetScrollMetadataCount(); i > 0; i--) { if (aLayer->GetFrameMetrics(i - 1).IsScrollable()) { return aLayer->GetFrameMetrics(i - 1); } } - return FrameMetrics::sNullMetrics; + return ScrollMetadata::sNullMetadata->GetMetrics(); } static const FrameMetrics& BottommostScrollableMetrics(Layer* aLayer) { - for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) { + for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) { if (aLayer->GetFrameMetrics(i).IsScrollable()) { return aLayer->GetFrameMetrics(i); } } - return FrameMetrics::sNullMetrics; + return ScrollMetadata::sNullMetadata->GetMetrics(); } static const FrameMetrics& BottommostMetrics(Layer* aLayer) { - if (aLayer->GetFrameMetricsCount() > 0) { + if (aLayer->GetScrollMetadataCount() > 0) { return aLayer->GetFrameMetrics(0); } - return FrameMetrics::sNullMetrics; + return ScrollMetadata::sNullMetadata->GetMetrics(); } private: @@ -475,7 +480,7 @@ bool AtTopLayer() const { - return mLayer->GetFrameMetricsCount() == 0 || mIndex == mLayer->GetFrameMetricsCount() - 1; + return mLayer->GetScrollMetadataCount() == 0 || mIndex == mLayer->GetScrollMetadataCount() - 1; } private: diff -Nru firefox-47.0~b1+build1/gfx/layers/Layers.cpp firefox-47.0~b2+build1/gfx/layers/Layers.cpp --- firefox-47.0~b1+build1/gfx/layers/Layers.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/Layers.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -536,14 +536,14 @@ void Layer::SetAsyncPanZoomController(uint32_t aIndex, AsyncPanZoomController *controller) { - MOZ_ASSERT(aIndex < GetFrameMetricsCount()); + MOZ_ASSERT(aIndex < GetScrollMetadataCount()); mApzcs[aIndex] = controller; } AsyncPanZoomController* Layer::GetAsyncPanZoomController(uint32_t aIndex) const { - MOZ_ASSERT(aIndex < GetFrameMetricsCount()); + MOZ_ASSERT(aIndex < GetScrollMetadataCount()); #ifdef DEBUG if (mApzcs[aIndex]) { MOZ_ASSERT(GetFrameMetrics(aIndex).IsScrollable()); @@ -553,9 +553,9 @@ } void -Layer::FrameMetricsChanged() +Layer::ScrollMetadataChanged() { - mApzcs.SetLength(GetFrameMetricsCount()); + mApzcs.SetLength(GetScrollMetadataCount()); } void @@ -844,17 +844,23 @@ return currentClip.Intersect(scissor); } +const ScrollMetadata& +Layer::GetScrollMetadata(uint32_t aIndex) const +{ + MOZ_ASSERT(aIndex < GetScrollMetadataCount()); + return mScrollMetadata[aIndex]; +} + const FrameMetrics& Layer::GetFrameMetrics(uint32_t aIndex) const { - MOZ_ASSERT(aIndex < GetFrameMetricsCount()); - return mFrameMetrics[aIndex]; + return GetScrollMetadata(aIndex).GetMetrics(); } bool Layer::HasScrollableFrameMetrics() const { - for (uint32_t i = 0; i < GetFrameMetricsCount(); i++) { + for (uint32_t i = 0; i < GetScrollMetadataCount(); i++) { if (GetFrameMetrics(i).IsScrollable()) { return true; } @@ -1086,12 +1092,12 @@ { Maybe clip = GetClipRect(); - for (size_t i = 0; i < mFrameMetrics.Length(); i++) { - if (!mFrameMetrics[i].HasClipRect()) { + for (size_t i = 0; i < mScrollMetadata.Length(); i++) { + if (!mScrollMetadata[i].HasClipRect()) { continue; } - const ParentLayerIntRect& other = mFrameMetrics[i].ClipRect(); + const ParentLayerIntRect& other = mScrollMetadata[i].ClipRect(); if (clip) { clip = Some(clip.value().Intersect(other)); } else { @@ -1943,10 +1949,10 @@ if (mMaskLayer) { aStream << nsPrintfCString(" [mMaskLayer=%p]", mMaskLayer.get()).get(); } - for (uint32_t i = 0; i < mFrameMetrics.Length(); i++) { - if (!mFrameMetrics[i].IsDefault()) { + for (uint32_t i = 0; i < mScrollMetadata.Length(); i++) { + if (!mScrollMetadata[i].IsDefault()) { aStream << nsPrintfCString(" [metrics%d=", i).get(); - AppendToString(aStream, mFrameMetrics[i], "", "]"); + AppendToString(aStream, mScrollMetadata[i], "", "]"); } } } diff -Nru firefox-47.0~b1+build1/gfx/layers/Layers.h firefox-47.0~b2+build1/gfx/layers/Layers.h --- firefox-47.0~b1+build1/gfx/layers/Layers.h 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/Layers.h 2016-05-03 05:14:12.000000000 +0000 @@ -854,12 +854,12 @@ * them with the provided FrameMetrics. See the documentation for * SetFrameMetrics(const nsTArray&) for more details. */ - void SetFrameMetrics(const FrameMetrics& aFrameMetrics) + void SetScrollMetadata(const ScrollMetadata& aScrollMetadata) { - if (mFrameMetrics.Length() != 1 || mFrameMetrics[0] != aFrameMetrics) { + if (mScrollMetadata.Length() != 1 || mScrollMetadata[0] != aScrollMetadata) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) FrameMetrics", this)); - mFrameMetrics.ReplaceElementsAt(0, mFrameMetrics.Length(), aFrameMetrics); - FrameMetricsChanged(); + mScrollMetadata.ReplaceElementsAt(0, mScrollMetadata.Length(), aScrollMetadata); + ScrollMetadataChanged(); Mutated(); } } @@ -870,23 +870,23 @@ * rooted at this. There might be multiple metrics on this layer * because the layer may, for example, be contained inside multiple * nested scrolling subdocuments. In general a Layer having multiple - * FrameMetrics objects is conceptually equivalent to having a stack + * ScrollMetadata objects is conceptually equivalent to having a stack * of ContainerLayers that have been flattened into this Layer. * See the documentation in LayerMetricsWrapper.h for a more detailed * explanation of this conceptual equivalence. * * Note also that there is actually a many-to-many relationship between - * Layers and FrameMetrics, because multiple Layers may have identical - * FrameMetrics objects. This happens when those layers belong to the + * Layers and ScrollMetadata, because multiple Layers may have identical + * ScrollMetadata objects. This happens when those layers belong to the * same scrolling subdocument and therefore end up with the same async * transform when they are scrolled by the APZ code. */ - void SetFrameMetrics(const nsTArray& aMetricsArray) + void SetScrollMetadata(const nsTArray& aMetadataArray) { - if (mFrameMetrics != aMetricsArray) { + if (mScrollMetadata != aMetadataArray) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) FrameMetrics", this)); - mFrameMetrics = aMetricsArray; - FrameMetricsChanged(); + mScrollMetadata = aMetadataArray; + ScrollMetadataChanged(); Mutated(); } } @@ -1253,9 +1253,10 @@ uint32_t GetContentFlags() { return mContentFlags; } const gfx::IntRect& GetLayerBounds() const { return mLayerBounds; } const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; } + const ScrollMetadata& GetScrollMetadata(uint32_t aIndex) const; const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const; - uint32_t GetFrameMetricsCount() const { return mFrameMetrics.Length(); } - const nsTArray& GetAllFrameMetrics() { return mFrameMetrics; } + uint32_t GetScrollMetadataCount() const { return mScrollMetadata.Length(); } + const nsTArray& GetAllScrollMetadata() { return mScrollMetadata; } bool HasScrollableFrameMetrics() const; bool IsScrollInfoLayer() const; const EventRegions& GetEventRegions() const { return mEventRegions; } @@ -1665,10 +1666,10 @@ // The aIndex for these functions must be less than GetFrameMetricsCount(). void SetAsyncPanZoomController(uint32_t aIndex, AsyncPanZoomController *controller); AsyncPanZoomController* GetAsyncPanZoomController(uint32_t aIndex) const; - // The FrameMetricsChanged function is used internally to ensure the APZC array length + // The ScrollMetadataChanged function is used internally to ensure the APZC array length // matches the frame metrics array length. private: - void FrameMetricsChanged(); + void ScrollMetadataChanged(); public: void ApplyPendingUpdatesForThisTransaction(); @@ -1789,7 +1790,7 @@ gfx::UserData mUserData; gfx::IntRect mLayerBounds; LayerIntRegion mVisibleRegion; - nsTArray mFrameMetrics; + nsTArray mScrollMetadata; EventRegions mEventRegions; gfx::Matrix4x4 mTransform; // A mutation of |mTransform| that we've queued to be applied at the @@ -2494,8 +2495,6 @@ virtual bool RepositionChild(Layer* aChild, Layer* aAfter) override { MOZ_CRASH(); return false; } - using Layer::SetFrameMetrics; - public: /** * CONSTRUCTION PHASE ONLY diff -Nru firefox-47.0~b1+build1/gfx/layers/LayersLogging.cpp firefox-47.0~b2+build1/gfx/layers/LayersLogging.cpp --- firefox-47.0~b1+build1/gfx/layers/LayersLogging.cpp 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/LayersLogging.cpp 2016-05-03 05:14:12.000000000 +0000 @@ -145,6 +145,18 @@ } void +AppendToString(std::stringstream& aStream, const ScrollMetadata& m, + const char* pfx, const char* sfx) +{ + aStream << pfx; + AppendToString(aStream, m.GetMetrics(), "{ [metrics=", "]"); + if (m.HasClipRect()) { + AppendToString(aStream, m.ClipRect(), " [clip=", "]"); + } + aStream << "}" << sfx; +} + +void AppendToString(std::stringstream& aStream, const FrameMetrics& m, const char* pfx, const char* sfx, bool detailed) { @@ -166,9 +178,6 @@ if (m.IsRootContent()) { aStream << "] [rcd"; } - if (m.HasClipRect()) { - AppendToString(aStream, m.ClipRect(), "] [clip="); - } AppendToString(aStream, m.GetZoom(), "] [z=", "] }"); } else { AppendToString(aStream, m.GetDisplayPortMargins(), " [dpm="); diff -Nru firefox-47.0~b1+build1/gfx/layers/LayersLogging.h firefox-47.0~b2+build1/gfx/layers/LayersLogging.h --- firefox-47.0~b1+build1/gfx/layers/LayersLogging.h 2016-04-26 07:45:00.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/layers/LayersLogging.h 2016-05-03 05:14:12.000000000 +0000 @@ -115,6 +115,10 @@ const char* pfx="", const char* sfx=""); void +AppendToString(std::stringstream& aStream, const ScrollMetadata& m, + const char* pfx="", const char* sfx=""); + +void AppendToString(std::stringstream& aStream, const FrameMetrics& m, const char* pfx="", const char* sfx="", bool detailed = false); diff -Nru firefox-47.0~b1+build1/gfx/tests/gtest/TestLayers.cpp firefox-47.0~b2+build1/gfx/tests/gtest/TestLayers.cpp --- firefox-47.0~b1+build1/gfx/tests/gtest/TestLayers.cpp 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/tests/gtest/TestLayers.cpp 2016-05-03 05:14:13.000000000 +0000 @@ -352,7 +352,15 @@ ASSERT_EQ(nullptr, layers[1]->GetNextSibling()); } -TEST(LayerMetricsWrapper, SimpleTree) { +class LayerMetricsWrapperTester : public ::testing::Test { +protected: + virtual void SetUp() { + // This ensures ScrollMetadata::sNullMetadata is initialized. + gfxPlatform::GetPlatform(); + } +}; + +TEST_F(LayerMetricsWrapperTester, SimpleTree) { nsTArray > layers; RefPtr lm; RefPtr root = CreateLayerTree("c(c(c(tt)c(t)))", nullptr, nullptr, lm, layers); @@ -389,43 +397,43 @@ ASSERT_TRUE(rootWrapper == wrapper.GetParent()); } -static FrameMetrics -MakeMetrics(FrameMetrics::ViewID aId) { - FrameMetrics metrics; - metrics.SetScrollId(aId); - return metrics; +static ScrollMetadata +MakeMetadata(FrameMetrics::ViewID aId) { + ScrollMetadata metadata; + metadata.GetMetrics().SetScrollId(aId); + return metadata; } -TEST(LayerMetricsWrapper, MultiFramemetricsTree) { +TEST_F(LayerMetricsWrapperTester, MultiFramemetricsTree) { nsTArray > layers; RefPtr lm; RefPtr root = CreateLayerTree("c(c(c(tt)c(t)))", nullptr, nullptr, lm, layers); - nsTArray metrics; - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 0)); // topmost of root layer - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::NULL_SCROLL_ID)); - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 1)); - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 2)); - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::NULL_SCROLL_ID)); - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::NULL_SCROLL_ID)); // bottom of root layer - root->SetFrameMetrics(metrics); - - metrics.Clear(); - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 3)); - layers[1]->SetFrameMetrics(metrics); - - metrics.Clear(); - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::NULL_SCROLL_ID)); - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 4)); - layers[2]->SetFrameMetrics(metrics); - - metrics.Clear(); - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 5)); - layers[4]->SetFrameMetrics(metrics); - - metrics.Clear(); - metrics.InsertElementAt(0, MakeMetrics(FrameMetrics::START_SCROLL_ID + 6)); - layers[5]->SetFrameMetrics(metrics); + nsTArray metadata; + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 0)); // topmost of root layer + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID)); + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 1)); + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 2)); + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID)); + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID)); // bottom of root layer + root->SetScrollMetadata(metadata); + + metadata.Clear(); + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 3)); + layers[1]->SetScrollMetadata(metadata); + + metadata.Clear(); + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::NULL_SCROLL_ID)); + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 4)); + layers[2]->SetScrollMetadata(metadata); + + metadata.Clear(); + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 5)); + layers[4]->SetScrollMetadata(metadata); + + metadata.Clear(); + metadata.InsertElementAt(0, MakeMetadata(FrameMetrics::START_SCROLL_ID + 6)); + layers[5]->SetScrollMetadata(metadata); LayerMetricsWrapper wrapper(root, LayerMetricsWrapper::StartAt::TOP); nsTArray expectedLayers; diff -Nru firefox-47.0~b1+build1/gfx/thebes/gfxPlatform.cpp firefox-47.0~b2+build1/gfx/thebes/gfxPlatform.cpp --- firefox-47.0~b1+build1/gfx/thebes/gfxPlatform.cpp 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/thebes/gfxPlatform.cpp 2016-05-03 05:14:13.000000000 +0000 @@ -9,6 +9,7 @@ #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/SharedBufferManagerChild.h" #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter +#include "mozilla/ClearOnShutdown.h" #include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" @@ -67,6 +68,7 @@ #include "nsILocaleService.h" #include "nsIObserverService.h" #include "nsIScreenManager.h" +#include "FrameMetrics.h" #include "MainThreadUtils.h" #ifdef MOZ_CRASHREPORTER #include "nsExceptionHandler.h" @@ -725,6 +727,9 @@ gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource(); } } + + ScrollMetadata::sNullMetadata = new ScrollMetadata(); + ClearOnShutdown(&ScrollMetadata::sNullMetadata); } static bool sLayersIPCIsUp = false; diff -Nru firefox-47.0~b1+build1/gfx/thebes/gfxPrefs.h firefox-47.0~b2+build1/gfx/thebes/gfxPrefs.h --- firefox-47.0~b1+build1/gfx/thebes/gfxPrefs.h 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/gfx/thebes/gfxPrefs.h 2016-05-03 05:14:13.000000000 +0000 @@ -396,6 +396,7 @@ DECL_GFX_PREF(Live, "layout.css.scroll-behavior.spring-constant", ScrollBehaviorSpringConstant, float, 250.0f); DECL_GFX_PREF(Live, "layout.css.scroll-snap.prediction-max-velocity", ScrollSnapPredictionMaxVelocity, int32_t, 2000); DECL_GFX_PREF(Live, "layout.css.scroll-snap.prediction-sensitivity", ScrollSnapPredictionSensitivity, float, 0.750f); + DECL_GFX_PREF(Live, "layout.css.scroll-snap.proximity-threshold", ScrollSnapProximityThreshold, int32_t, 200); DECL_GFX_PREF(Once, "layout.css.touch_action.enabled", TouchActionEnabled, bool, false); DECL_GFX_PREF(Live, "layout.display-list.dump", LayoutDumpDisplayList, bool, false); DECL_GFX_PREF(Live, "layout.event-regions.enabled", LayoutEventRegionsEnabledDoNotUseDirectly, bool, false); diff -Nru firefox-47.0~b1+build1/ipc/chromium/src/base/pickle.cc firefox-47.0~b2+build1/ipc/chromium/src/base/pickle.cc --- firefox-47.0~b1+build1/ipc/chromium/src/base/pickle.cc 2016-04-26 07:45:03.000000000 +0000 +++ firefox-47.0~b2+build1/ipc/chromium/src/base/pickle.cc 2016-05-03 05:14:15.000000000 +0000 @@ -24,6 +24,8 @@ // static const int Pickle::kPayloadUnit = 64; +const uint32_t kFastGrowthCap = 128 * 1024; + // We mark a read only pickle with a special capacity_. static const uint32_t kCapacityReadOnly = (uint32_t) -1; @@ -515,7 +517,8 @@ uint32_t needed_size = header_size_ + new_size; if (needed_size > capacity_) { - Resize(std::max(capacity_ * 2, needed_size)); + double growth_rate = capacity_ < kFastGrowthCap ? 2.0 : 1.4; + Resize(std::max(static_cast(capacity_ * growth_rate), needed_size)); } DCHECK(intptr_t(header_) % alignment == 0); diff -Nru firefox-47.0~b1+build1/js/public/MemoryMetrics.h firefox-47.0~b2+build1/js/public/MemoryMetrics.h --- firefox-47.0~b1+build1/js/public/MemoryMetrics.h 2016-04-26 07:45:03.000000000 +0000 +++ firefox-47.0~b2+build1/js/public/MemoryMetrics.h 2016-05-03 05:14:15.000000000 +0000 @@ -737,6 +737,8 @@ MOZ_ASSERT(!other.isTotals); } + CompartmentStats(const CompartmentStats&) = delete; // disallow copying + ~CompartmentStats() { // |allClasses| is usually deleted and set to nullptr before this // destructor runs. But there are failure cases due to OOMs that may diff -Nru firefox-47.0~b1+build1/js/src/jit/BaselineIC.cpp firefox-47.0~b2+build1/js/src/jit/BaselineIC.cpp --- firefox-47.0~b1+build1/js/src/jit/BaselineIC.cpp 2016-04-26 07:45:05.000000000 +0000 +++ firefox-47.0~b2+build1/js/src/jit/BaselineIC.cpp 2016-05-03 05:14:18.000000000 +0000 @@ -5618,7 +5618,7 @@ // Check for natives to which template objects can be attached. This is // done to provide templates to Ion for inlining these natives later on. - if (native == ArrayConstructor) { + if (native == ArrayConstructor || native == array_construct) { // Note: the template array won't be used if its length is inaccurately // computed here. (We allocate here because compilation may occur on a // separate thread where allocation is impossible.) diff -Nru firefox-47.0~b1+build1/js/src/jit/MCallOptimize.cpp firefox-47.0~b2+build1/js/src/jit/MCallOptimize.cpp --- firefox-47.0~b1+build1/js/src/jit/MCallOptimize.cpp 2016-04-26 07:45:05.000000000 +0000 +++ firefox-47.0~b2+build1/js/src/jit/MCallOptimize.cpp 2016-05-03 05:14:18.000000000 +0000 @@ -411,6 +411,10 @@ uint32_t initLength = 0; JSObject* templateObject = inspector->getTemplateObjectForNative(pc, ArrayConstructor); + // This is shared by ArrayConstructor and array_construct (std_Array). + if (!templateObject) + templateObject = inspector->getTemplateObjectForNative(pc, array_construct); + if (!templateObject) { trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoTemplateObj); return InliningStatus_NotInlined; diff -Nru firefox-47.0~b1+build1/js/src/jit-test/tests/arrays/std_Array-prototype.js firefox-47.0~b2+build1/js/src/jit-test/tests/arrays/std_Array-prototype.js --- firefox-47.0~b1+build1/js/src/jit-test/tests/arrays/std_Array-prototype.js 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/js/src/jit-test/tests/arrays/std_Array-prototype.js 2016-05-03 05:14:16.000000000 +0000 @@ -0,0 +1,6 @@ +Object.prototype.prototype = {}; +assertEq(Object.getPrototypeOf([].concat()), Array.prototype); +assertEq(Object.getPrototypeOf([].map(x => x)), Array.prototype); +assertEq(Object.getPrototypeOf([].filter(x => x)), Array.prototype); +assertEq(Object.getPrototypeOf([].slice()), Array.prototype); +assertEq(Object.getPrototypeOf([].splice()), Array.prototype); diff -Nru firefox-47.0~b1+build1/js/src/jsarray.cpp firefox-47.0~b2+build1/js/src/jsarray.cpp --- firefox-47.0~b1+build1/js/src/jsarray.cpp 2016-04-26 07:45:05.000000000 +0000 +++ firefox-47.0~b2+build1/js/src/jsarray.cpp 2016-05-03 05:14:18.000000000 +0000 @@ -3194,15 +3194,20 @@ JS_FS_END }; -/* ES5 15.4.2 */ -bool -js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp) +static inline bool +ArrayConstructorImpl(JSContext* cx, CallArgs& args, bool isConstructor) { - CallArgs args = CallArgsFromVp(argc, vp); - RootedObject proto(cx); - if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) - return false; + if (isConstructor) { + if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) + return false; + } else { + // We're emulating |new Array(n)| with |std_Array(n)| in self-hosted JS, + // and the proto should be %ArrayPrototype% regardless of the callee. + proto = GlobalObject::getOrCreateArrayPrototype(cx, cx->global()); + if (!proto) + return false; + } if (args.length() != 1 || !args[0].isNumber()) return ArrayFromCallArgs(cx, args, proto); @@ -3232,6 +3237,24 @@ return true; } +/* ES5 15.4.2 */ +bool +js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + return ArrayConstructorImpl(cx, args, /* isConstructor = */ true); +} + +bool +js::array_construct(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(!args.isConstructing()); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isNumber()); + return ArrayConstructorImpl(cx, args, /* isConstructor = */ false); +} + JSObject* js::ArrayConstructorOneArg(JSContext* cx, HandleObjectGroup group, int32_t lengthInt) { diff -Nru firefox-47.0~b1+build1/js/src/jsarray.h firefox-47.0~b2+build1/js/src/jsarray.h --- firefox-47.0~b1+build1/js/src/jsarray.h 2016-04-26 07:45:05.000000000 +0000 +++ firefox-47.0~b2+build1/js/src/jsarray.h 2016-05-03 05:14:18.000000000 +0000 @@ -216,6 +216,10 @@ extern bool ArrayConstructor(JSContext* cx, unsigned argc, Value* vp); +// Like Array constructor, but doesn't perform GetPrototypeFromConstructor. +extern bool +array_construct(JSContext* cx, unsigned argc, Value* vp); + } /* namespace js */ #endif /* jsarray_h */ diff -Nru firefox-47.0~b1+build1/js/src/jscompartment.cpp firefox-47.0~b2+build1/js/src/jscompartment.cpp --- firefox-47.0~b1+build1/js/src/jscompartment.cpp 2016-04-26 07:45:05.000000000 +0000 +++ firefox-47.0~b2+build1/js/src/jscompartment.cpp 2016-05-03 05:14:18.000000000 +0000 @@ -78,7 +78,7 @@ debugScriptMap(nullptr), debugScopes(nullptr), enumerators(nullptr), - compartmentStats(nullptr), + compartmentStats_(nullptr), scheduledForDestruction(false), maybeAlive(true), jitCompartment_(nullptr), diff -Nru firefox-47.0~b1+build1/js/src/jscompartment.h firefox-47.0~b2+build1/js/src/jscompartment.h --- firefox-47.0~b1+build1/js/src/jscompartment.h 2016-04-26 07:45:05.000000000 +0000 +++ firefox-47.0~b2+build1/js/src/jscompartment.h 2016-05-03 05:14:18.000000000 +0000 @@ -735,8 +735,28 @@ */ js::NativeIterator* enumerators; + private: /* Used by memory reporters and invalid otherwise. */ - void* compartmentStats; + JS::CompartmentStats* compartmentStats_; + + public: + // This should only be called when it is non-null, i.e. during memory + // reporting. + JS::CompartmentStats& compartmentStats() { + // We use MOZ_RELEASE_ASSERT here because in bug 1132502 there was some + // (inconclusive) evidence that compartmentStats_ can be nullptr + // unexpectedly. + MOZ_RELEASE_ASSERT(compartmentStats_); + return *compartmentStats_; + } + void nullCompartmentStats() { + MOZ_ASSERT(compartmentStats_); + compartmentStats_ = nullptr; + } + void setCompartmentStats(JS::CompartmentStats* newStats) { + MOZ_ASSERT(!compartmentStats_ && newStats); + compartmentStats_ = newStats; + } // These flags help us to discover if a compartment that shouldn't be alive // manages to outlive a GC. diff -Nru firefox-47.0~b1+build1/js/src/vm/MemoryMetrics.cpp firefox-47.0~b2+build1/js/src/vm/MemoryMetrics.cpp --- firefox-47.0~b1+build1/js/src/vm/MemoryMetrics.cpp 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/js/src/vm/MemoryMetrics.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -329,7 +329,7 @@ MOZ_CRASH("oom"); rtStats->initExtraCompartmentStats(compartment, &cStats); - compartment->compartmentStats = &cStats; + compartment->setCompartmentStats(&cStats); // Measure the compartment object itself, and things hanging off it. compartment->addSizeOfIncludingThis(rtStats->mallocSizeOf_, @@ -367,12 +367,6 @@ rtStats->currZoneStats->unusedGCThings.addToKind(traceKind, allocationSpace); } -static CompartmentStats* -GetCompartmentStats(JSCompartment* comp) -{ - return static_cast(comp->compartmentStats); -} - // FineGrained is used for normal memory reporting. CoarseGrained is used by // AddSizeOfTab(), which aggregates all the measurements into a handful of // high-level numbers, which means that fine-grained reporting would be a waste @@ -383,16 +377,15 @@ }; static void -AddClassInfo(Granularity granularity, CompartmentStats* cStats, const char* className, +AddClassInfo(Granularity granularity, CompartmentStats& cStats, const char* className, JS::ClassInfo& info) { if (granularity == FineGrained) { if (!className) className = ""; - CompartmentStats::ClassesHashMap::AddPtr p = - cStats->allClasses->lookupForAdd(className); + CompartmentStats::ClassesHashMap::AddPtr p = cStats.allClasses->lookupForAdd(className); if (!p) { - bool ok = cStats->allClasses->add(p, className, info); + bool ok = cStats.allClasses->add(p, className, info); // Ignore failure -- we just won't record the // object/shape/base-shape as notable. (void)ok; @@ -416,12 +409,12 @@ switch (traceKind) { case JS::TraceKind::Object: { JSObject* obj = static_cast(thing); - CompartmentStats* cStats = GetCompartmentStats(obj->compartment()); + CompartmentStats& cStats = obj->compartment()->compartmentStats(); JS::ClassInfo info; // This zeroes all the sizes. info.objectsGCHeap += thingSize; obj->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &info); - cStats->classInfo.add(info); + cStats.classInfo.add(info); const Class* clasp = obj->getClass(); const char* className = clasp->name; @@ -430,20 +423,20 @@ if (ObjectPrivateVisitor* opv = closure->opv) { nsISupports* iface; if (opv->getISupports_(obj, &iface) && iface) - cStats->objectsPrivate += opv->sizeOfIncludingThis(iface); + cStats.objectsPrivate += opv->sizeOfIncludingThis(iface); } break; } case JS::TraceKind::Script: { JSScript* script = static_cast(thing); - CompartmentStats* cStats = GetCompartmentStats(script->compartment()); - cStats->scriptsGCHeap += thingSize; - cStats->scriptsMallocHeapData += script->sizeOfData(rtStats->mallocSizeOf_); - cStats->typeInferenceTypeScripts += script->sizeOfTypeScript(rtStats->mallocSizeOf_); - jit::AddSizeOfBaselineData(script, rtStats->mallocSizeOf_, &cStats->baselineData, - &cStats->baselineStubsFallback); - cStats->ionData += jit::SizeOfIonData(script, rtStats->mallocSizeOf_); + CompartmentStats& cStats = script->compartment()->compartmentStats(); + cStats.scriptsGCHeap += thingSize; + cStats.scriptsMallocHeapData += script->sizeOfData(rtStats->mallocSizeOf_); + cStats.typeInferenceTypeScripts += script->sizeOfTypeScript(rtStats->mallocSizeOf_); + jit::AddSizeOfBaselineData(script, rtStats->mallocSizeOf_, &cStats.baselineData, + &cStats.baselineStubsFallback); + cStats.ionData += jit::SizeOfIonData(script, rtStats->mallocSizeOf_); ScriptSource* ss = script->scriptSource(); SourceSet::AddPtr entry = closure->seenSources.lookupForAdd(ss); @@ -514,17 +507,48 @@ case JS::TraceKind::BaseShape: { BaseShape* base = static_cast(thing); - CompartmentStats* cStats = GetCompartmentStats(base->compartment()); + CompartmentStats& cStats = base->compartment()->compartmentStats(); JS::ClassInfo info; // This zeroes all the sizes. info.shapesGCHeapBase += thingSize; // No malloc-heap measurements. - cStats->classInfo.add(info); + cStats.classInfo.add(info); - const Class* clasp = base->clasp(); - const char* className = clasp->name; - AddClassInfo(granularity, cStats, className, info); + // XXX: This code is currently disabled because it occasionally causes + // crashes (bug 1132502 and bug 1243529). The best theory as to why is + // as follows. + // + // - XPCNativeScriptableShared have heap-allocated js::Class instances. + // + // - Once an XPCNativeScriptableShared is destroyed, its js::Class is + // freed, but we can still have a BaseShape with a clasp_ pointer + // that points to the freed js::Class. + // + // - This dangling pointer isn't used in normal execution, because the + // BaseShape is unreachable. + // + // - However, memory reporting inspects all GC cells, reachable or not, + // so we trace the dangling pointer and crash. + // + // One solution would be to mark BaseShapes whose js::Class is + // heap-allocated, and skip this code just for them. However, that's a + // non-trivial change, and heap-allocated js::Class instances are + // likely to go away soon. + // + // So for now we just skip this code for all BaseShapes. The + // consequence is that all BaseShapes will show up in about:memory + // under "class()" sub-trees, instead of the more + // appropriate, class-specific "class(Foo)" sub-tree. But BaseShapes + // typically don't take up that much memory so this isn't a big deal. + // + // XXX: once bug 1265271 is done this code should be re-enabled. + // + if (0) { + const Class* clasp = base->clasp(); + const char* className = clasp->name; + AddClassInfo(granularity, cStats, className, info); + } break; } @@ -543,19 +567,23 @@ case JS::TraceKind::Shape: { Shape* shape = static_cast(thing); - CompartmentStats* cStats = GetCompartmentStats(shape->compartment()); + CompartmentStats& cStats = shape->compartment()->compartmentStats(); JS::ClassInfo info; // This zeroes all the sizes. if (shape->inDictionary()) info.shapesGCHeapDict += thingSize; else info.shapesGCHeapTree += thingSize; shape->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &info); - cStats->classInfo.add(info); + cStats.classInfo.add(info); - const BaseShape* base = shape->base(); - const Class* clasp = base->clasp(); - const char* className = clasp->name; - AddClassInfo(granularity, cStats, className, info); + // XXX: once bug 1265271 is done, occur, this code should be + // re-enabled. (See the big comment on the BaseShape case above.) + if (0) { + const BaseShape* base = shape->base(); + const Class* clasp = base->clasp(); + const char* className = clasp->name; + AddClassInfo(granularity, cStats, className, info); + } break; } @@ -779,7 +807,7 @@ #endif for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next()) - comp->compartmentStats = nullptr; + comp->nullCompartmentStats(); size_t numDirtyChunks = (rtStats->gcHeapChunkTotal - rtStats->gcHeapUnusedChunks) / gc::ChunkSize; @@ -884,7 +912,7 @@ rtStats.cTotals.addSizes(rtStats.compartmentStatsVector[i]); for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) - comp->compartmentStats = nullptr; + comp->nullCompartmentStats(); rtStats.zTotals.addToTabSizes(sizes); rtStats.cTotals.addToTabSizes(sizes); diff -Nru firefox-47.0~b1+build1/js/src/vm/SelfHosting.cpp firefox-47.0~b2+build1/js/src/vm/SelfHosting.cpp --- firefox-47.0~b1+build1/js/src/vm/SelfHosting.cpp 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/js/src/vm/SelfHosting.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -1781,7 +1781,7 @@ // Additionally, a set of C++-implemented helper functions is defined on the // self-hosting global. static const JSFunctionSpec intrinsic_functions[] = { - JS_INLINABLE_FN("std_Array", ArrayConstructor, 1,0, Array), + JS_INLINABLE_FN("std_Array", array_construct, 1,0, Array), JS_FN("std_Array_join", array_join, 1,0), JS_INLINABLE_FN("std_Array_push", array_push, 1,0, ArrayPush), JS_INLINABLE_FN("std_Array_pop", array_pop, 0,0, ArrayPop), diff -Nru firefox-47.0~b1+build1/js/xpconnect/src/XPCJSRuntime.cpp firefox-47.0~b2+build1/js/xpconnect/src/XPCJSRuntime.cpp --- firefox-47.0~b1+build1/js/xpconnect/src/XPCJSRuntime.cpp 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/js/xpconnect/src/XPCJSRuntime.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -2126,8 +2126,8 @@ static nsresult ReportClassStats(const ClassInfo& classInfo, const nsACString& path, - nsIHandleReportCallback* cb, nsISupports* closure, - size_t& gcTotal) + const nsACString& shapesPath, nsIHandleReportCallback* cb, + nsISupports* closure, size_t& gcTotal) { // We deliberately don't use ZCREPORT_BYTES, so that these per-class values // don't go into sundries. @@ -2197,37 +2197,37 @@ } if (classInfo.shapesGCHeapTree > 0) { - REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("shapes/gc-heap/tree"), + REPORT_GC_BYTES(shapesPath + NS_LITERAL_CSTRING("shapes/gc-heap/tree"), classInfo.shapesGCHeapTree, "Shapes in a property tree."); } if (classInfo.shapesGCHeapDict > 0) { - REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("shapes/gc-heap/dict"), + REPORT_GC_BYTES(shapesPath + NS_LITERAL_CSTRING("shapes/gc-heap/dict"), classInfo.shapesGCHeapDict, "Shapes in dictionary mode."); } if (classInfo.shapesGCHeapBase > 0) { - REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("shapes/gc-heap/base"), + REPORT_GC_BYTES(shapesPath + NS_LITERAL_CSTRING("shapes/gc-heap/base"), classInfo.shapesGCHeapBase, "Base shapes, which collate data common to many shapes."); } if (classInfo.shapesMallocHeapTreeTables > 0) { - REPORT_BYTES(path + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-tables"), + REPORT_BYTES(shapesPath + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-tables"), KIND_HEAP, classInfo.shapesMallocHeapTreeTables, "Property tables of shapes in a property tree."); } if (classInfo.shapesMallocHeapDictTables > 0) { - REPORT_BYTES(path + NS_LITERAL_CSTRING("shapes/malloc-heap/dict-tables"), + REPORT_BYTES(shapesPath + NS_LITERAL_CSTRING("shapes/malloc-heap/dict-tables"), KIND_HEAP, classInfo.shapesMallocHeapDictTables, "Property tables of shapes in dictionary mode."); } if (classInfo.shapesMallocHeapTreeKids > 0) { - REPORT_BYTES(path + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-kids"), + REPORT_BYTES(shapesPath + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-kids"), KIND_HEAP, classInfo.shapesMallocHeapTreeKids, "Kid hashes of shapes in a property tree."); } @@ -2275,8 +2275,12 @@ ? NS_LITERAL_CSTRING("classes/") : NS_LITERAL_CSTRING("classes/class()/"); - rv = ReportClassStats(cStats.classInfo, nonNotablePath, cb, closure, - gcTotal); + // XXX: shapes need special treatment until bug 1265271 is fixed. + nsCString shapesPath = cJSPathPrefix; + shapesPath += NS_LITERAL_CSTRING("classes/"); + + rv = ReportClassStats(cStats.classInfo, nonNotablePath, shapesPath, cb, + closure, gcTotal); NS_ENSURE_SUCCESS(rv, rv); for (size_t i = 0; i < cStats.notableClasses.length(); i++) { @@ -2286,7 +2290,8 @@ nsCString classPath = cJSPathPrefix + nsPrintfCString("classes/class(%s)/", classInfo.className_); - rv = ReportClassStats(classInfo, classPath, cb, closure, gcTotal); + rv = ReportClassStats(classInfo, classPath, shapesPath, cb, closure, + gcTotal); NS_ENSURE_SUCCESS(rv, rv); } diff -Nru firefox-47.0~b1+build1/js/xpconnect/src/XPCMaps.cpp firefox-47.0~b2+build1/js/xpconnect/src/XPCMaps.cpp --- firefox-47.0~b1+build1/js/xpconnect/src/XPCMaps.cpp 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/js/xpconnect/src/XPCMaps.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -556,6 +556,15 @@ XPCNativeScriptableShared* shared = entry->key; + // XXX: this XPCNativeScriptableShared is heap-allocated, which means the + // js::Class it contains is also heap-allocated. This causes problems for + // memory reporting. See the comment above the BaseShape case in + // StatsCellCallback() in js/src/vm/MemoryMetrics.cpp. + // + // When the code below is removed (bug 1265271) and there are no longer any + // heap-allocated js::Class instances, the disabled code in + // StatsCellCallback() should be reinstated. + // if (!shared) { entry->key = shared = new XPCNativeScriptableShared(flags, key.TransferNameOwnership()); diff -Nru firefox-47.0~b1+build1/l10n/changesets firefox-47.0~b2+build1/l10n/changesets --- firefox-47.0~b1+build1/l10n/changesets 2016-04-26 08:05:46.000000000 +0000 +++ firefox-47.0~b2+build1/l10n/changesets 2016-05-03 05:28:47.000000000 +0000 @@ -1,91 +1,91 @@ ach 477:9a0c8e338b70 af 870:7916f4313058 -an 532:5290183126a0 -ar 1972:236266c550bf -as 690:c5b0acb66a53 -ast 1495:9c6df11d4f5f -az 567:e5a0c63e1020 -be 1940:67b6c2bf6ba7 -bg 1317:d3b685e8eed4 -bn-BD 1240:1dac94619464 -bn-IN 897:d19236696954 -br 1572:1288f2ff9f7f +an 533:fb1989f849d5 +ar 1974:2e4294b5db16 +as 691:3ba5737ca2f9 +ast 1496:a4dc899c6d18 +az 568:964cafc36636 +be 1942:411ef61e0495 +bg 1318:243a68c7eec0 +bn-BD 1241:d12ca6519bb5 +bn-IN 898:c4fbff1a32c1 +br 1574:6f11163d17ca bs 563:05922f414549 -ca 2695:6b62e6b5e9e0 -cak 347:622d2f7940b1 -cs 4429:eda884de181f -cy 1359:de6687916589 -da 2476:4b381f09624d -de 5165:a3d27a16dee2 -dsb 597:eaf2afddba03 -el 1471:5ad8a9ea7629 -en-GB 2184:863863e37df0 +ca 2697:eb051324d7e2 +cak 348:53de9ec649b9 +cs 4431:f066220564c9 +cy 1361:4f923bc8a3ba +da 2478:afd1f2293e42 +de 5183:f45ba2fb1764 +dsb 599:7cb2eeeb745a +el 1473:ec65d2bcf998 +en-GB 2186:bdfa9d63b1b0 en-ZA 529:52a936eeeea1 -eo 987:bddef720796c -es-AR 2804:edc2a7eb1051 +eo 988:9c7ba24ee939 +es-AR 2806:f97190977e7a es-CL 1064:247114b95260 -es-ES 4474:45f28d36aa15 -es-MX 1133:cc199f8e6b4d -et 2014:a204b5301e7c -eu 1856:15be6408275c -fa 1211:9ce600e358a6 -ff 561:ac13ff5377d1 -fi 2448:ff3af2ebd538 -fr 7450:152ea31fc4d4 -fy-NL 2853:28c71ae55a8a -ga-IE 2058:8e4730ebf819 -gd 1924:a3e05b9f817a -gl 3262:53b72bd8ec31 +es-ES 4476:3007fcdd3775 +es-MX 1134:337d83cf8e16 +et 2016:c448e9e99e2c +eu 1858:f97a2852ba49 +fa 1212:a8dd448cf61e +ff 562:85745a151639 +fi 2450:43aa317c99e3 +fr 7452:78459bff4714 +fy-NL 2855:35af4a592199 +ga-IE 2060:41d42f78dd15 +gd 1926:b1b3fa8d3873 +gl 3264:a931fcb8ebec gn 72:677f87f210fb -gu-IN 1151:110fd755dd3d -he 1635:c2d883840896 -hi-IN 1030:e70eb88eab01 -hr 1992:349aca814a07 -hsb 751:5d5d76bf375a -hu 2766:175b6ee038d0 -hy-AM 1500:5c8d1ef8acc7 -id 1918:b9910563d89f -is 1628:d58074da38d9 -it 6635:f4795184ef7b -ja 2645:b9eb952ec3ee -ja-JP-mac 2189:ee480d56992e -kk 1041:f5ca58ee3f8e +gu-IN 1152:dbacc7266df6 +he 1637:a45b2cc87bfa +hi-IN 1031:d2d3596ac9c3 +hr 1994:fa92064dbde0 +hsb 753:470e1af5f32b +hu 2768:5f79b6975e22 +hy-AM 1502:bca262b7c266 +id 1920:6dccc5ced018 +is 1630:ce816983a502 +it 6637:8050fd5e73b4 +ja 2649:f3cc1b0a7186 +ja-JP-mac 2192:438f72c47042 +kk 1042:0bbc40b3d537 km 672:7c2f4c770bfd -kn 977:8c86a4d507ff -ko 2223:b344cffbaa32 +kn 978:01f33e29073a +ko 2226:d6a6b4ab7893 lij 767:d46003cd897c -lt 3287:d4548b5bae90 -lv 1266:a4ed8b0666d4 -mai 764:8b4a9ae1ccac +lt 3289:e8974ad2d4c5 +lv 1267:8c557da43a22 +mai 765:a4febfffafcd mk 557:922b154511b5 -ml 913:8eefbc7296b8 -mr 1029:05a02deadc4d -ms 515:da2916b8e95c -nb-NO 2933:f4acff56dd5d -nl 5832:e3795208e40f -nn-NO 1678:1deb8231f357 -or 757:0b1733674cf1 -pa-IN 2040:27db4f6507bf -pl 8611:8b1eefee668b -pt-BR 2553:e32ec45da519 -pt-PT 5298:125dcfece7c1 -rm 1580:f21417c20181 -ro 2203:122bf7d400f4 -ru 4393:5481f2fa6b97 -si 1411:af540569d60d -sk 4162:83b87059e487 -sl 2672:9caea737d731 -son 794:a570895f11aa -sq 2181:36db326f736e -sr 1395:d81a5ddcb2a5 -sv-SE 4993:41dc1bf58cb6 -ta 795:434d7c35d466 -te 842:c149a2596362 -th 1203:26209963e036 -tr 2512:27b40dd467bf -uk 3341:719415e4ebd9 -uz 514:1e1398b33e2c -vi 1104:d79e36ec2a3e -xh 685:60cef4e50976 -zh-CN 2651:63b06c78d58f -zh-TW 2886:0394766c3755 +ml 914:714c4dc802c3 +mr 1030:9010382b9ab0 +ms 516:b0a07d4cfb7a +nb-NO 2935:07e4429ff63f +nl 5834:2d5473dc6fc4 +nn-NO 1679:dbd67913ee37 +or 758:428a7ebdd098 +pa-IN 2043:36b5104e9ad7 +pl 8613:e60a26401e8c +pt-BR 2556:84cdc11c7a13 +pt-PT 5300:4f6bb767e662 +rm 1583:76aeeee9a591 +ro 2205:a7fabadf8312 +ru 4395:8d905f75f835 +si 1414:3d5aecc6344a +sk 4168:df3bb5decd9b +sl 2675:4246ae9440c1 +son 795:7494d363f588 +sq 2183:0365769d34d3 +sr 1397:3054c3740041 +sv-SE 4995:8b8829b64cbe +ta 796:0b76962a903e +te 843:bcf65256002e +th 1204:85770d5551e0 +tr 2514:8eb66d5ce5bb +uk 3343:ee0b0fbaf8ec +uz 515:c990fb8c5bce +vi 1105:d63fbc4c0f45 +xh 686:cedd13fda535 +zh-CN 2654:3e16381b7857 +zh-TW 2890:616b4177ebec diff -Nru firefox-47.0~b1+build1/l10n/tr/dom/chrome/plugins.properties firefox-47.0~b2+build1/l10n/tr/dom/chrome/plugins.properties --- firefox-47.0~b1+build1/l10n/tr/dom/chrome/plugins.properties 2016-04-26 08:04:08.000000000 +0000 +++ firefox-47.0~b2+build1/l10n/tr/dom/chrome/plugins.properties 2016-05-03 05:27:24.000000000 +0000 @@ -23,9 +23,12 @@ # GMP Plugins gmp_license_info=Lisans bilgileri +gmp_privacy_info=Gizlilik bilgileri openH264_name=OpenH264 Video Çözücü (saÄŸlayan: Cisco Systems, Inc.) openH264_description2=Bu yan uygulama, WebRTC ÅŸartnamesine uyum saÄŸlamak ve H.264 video çözücüye ihtiyaç duyan cihazlarda WebRTC görüşmeleri yapabilmek amacıyla Mozilla tarafından otomatik yüklenir. Çözücünün kaynak kodlarını görmek ve daha bilgi almak için http://www.openh264.org/ adresini ziyaret edin. eme-adobe_name=Primetime İçerik Çözme Modülü (saÄŸlayan: Adobe Systems, Incorporated) eme-adobe_description=Korumalı web videolarını oynatır. + +widevine_description=Widevine İçerik Çözme Modülü (saÄŸlayan: Google Inc.) diff -Nru firefox-47.0~b1+build1/l10n/tr/security/manager/chrome/pipnss/nsserrors.properties firefox-47.0~b2+build1/l10n/tr/security/manager/chrome/pipnss/nsserrors.properties --- firefox-47.0~b1+build1/l10n/tr/security/manager/chrome/pipnss/nsserrors.properties 2016-04-26 08:04:08.000000000 +0000 +++ firefox-47.0~b2+build1/l10n/tr/security/manager/chrome/pipnss/nsserrors.properties 2016-05-03 05:27:24.000000000 +0000 @@ -89,7 +89,7 @@ SSL_ERROR_HANDSHAKE_NOT_COMPLETED=Hâlihazırdaki SSL karşılaması bitmeden baÅŸka bir karşılamaya giriÅŸilemez. SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE=EÅŸten yanlış karşılama özeti deÄŸerleri alındı. SSL_ERROR_CERT_KEA_MISMATCH=Sunulan sertifika seçilen anahtar deÄŸiÅŸtirme çözüm yoluyla kullanılamaz. -SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA=SSL istemci doÄŸrulaması konusunda hiçbir sertifika yetkilisine güvenilmiyor. +SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA=SSL istemci doÄŸrulaması için hiçbir sertifika yetkilisine güvenilmiyor. SSL_ERROR_SESSION_NOT_FOUND=Ä°stemcinin SSL oturum kimliÄŸi sunucunun oturum ön belleÄŸinde bulunamadı. SSL_ERROR_DECRYPTION_FAILED_ALERT=EÅŸ, aldığı bir SSL kaydının ÅŸifresini çözemedi. SSL_ERROR_RECORD_OVERFLOW_ALERT=EÅŸ izin verilenden daha uzun olan bir SSL kaydı aldı. diff -Nru firefox-47.0~b1+build1/l10n/tr/security/manager/chrome/pippki/pippki.dtd firefox-47.0~b2+build1/l10n/tr/security/manager/chrome/pippki/pippki.dtd --- firefox-47.0~b1+build1/l10n/tr/security/manager/chrome/pippki/pippki.dtd 2016-04-26 08:04:08.000000000 +0000 +++ firefox-47.0~b2+build1/l10n/tr/security/manager/chrome/pippki/pippki.dtd 2016-05-03 05:27:24.000000000 +0000 @@ -18,10 +18,10 @@ - + - + diff -Nru firefox-47.0~b1+build1/layout/base/FrameLayerBuilder.cpp firefox-47.0~b2+build1/layout/base/FrameLayerBuilder.cpp --- firefox-47.0~b1+build1/layout/base/FrameLayerBuilder.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/base/FrameLayerBuilder.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -686,9 +686,9 @@ RefPtr mLayer; AnimatedGeometryRoot* mAnimatedGeometryRoot; const DisplayItemScrollClip* mScrollClip; - // If non-null, this FrameMetrics is set to the be the first FrameMetrics + // If non-null, this ScrollMetadata is set to the be the first ScrollMetadata // on the layer. - UniquePtr mBaseFrameMetrics; + UniquePtr mBaseScrollMetadata; // The following are only used for retained layers (for occlusion // culling of those layers). These regions are all relative to the // container reference frame. @@ -4143,15 +4143,15 @@ if (itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) { nsDisplayScrollInfoLayer* scrollItem = static_cast(item); newLayerEntry->mOpaqueForAnimatedGeometryRootParent = false; - newLayerEntry->mBaseFrameMetrics = - scrollItem->ComputeFrameMetrics(ownLayer, mParameters); + newLayerEntry->mBaseScrollMetadata = + scrollItem->ComputeScrollMetadata(ownLayer, mParameters); } else if ((itemType == nsDisplayItem::TYPE_SUBDOCUMENT || itemType == nsDisplayItem::TYPE_ZOOM || itemType == nsDisplayItem::TYPE_RESOLUTION) && gfxPrefs::LayoutUseContainersForRootFrames()) { - newLayerEntry->mBaseFrameMetrics = - static_cast(item)->ComputeFrameMetrics(ownLayer, mParameters); + newLayerEntry->mBaseScrollMetadata = + static_cast(item)->ComputeScrollMetadata(ownLayer, mParameters); } /** @@ -4697,13 +4697,13 @@ return; } - AutoTArray metricsArray; - if (aEntry->mBaseFrameMetrics) { - metricsArray.AppendElement(*aEntry->mBaseFrameMetrics); + AutoTArray metricsArray; + if (aEntry->mBaseScrollMetadata) { + metricsArray.AppendElement(*aEntry->mBaseScrollMetadata); // The base FrameMetrics was not computed by the nsIScrollableframe, so it // should not have a mask layer. - MOZ_ASSERT(!aEntry->mBaseFrameMetrics->GetMaskLayerIndex()); + MOZ_ASSERT(!aEntry->mBaseScrollMetadata->GetMaskLayerIndex()); } // Any extra mask layers we need to attach to FrameMetrics. @@ -4722,9 +4722,9 @@ nsIScrollableFrame* scrollFrame = scrollClip->mScrollableFrame; const DisplayItemClip* clip = scrollClip->mClip; - Maybe metrics = - scrollFrame->ComputeFrameMetrics(aEntry->mLayer, mContainerReferenceFrame, mParameters, clip); - if (!metrics) { + Maybe metadata = + scrollFrame->ComputeScrollMetadata(aEntry->mLayer, mContainerReferenceFrame, mParameters, clip); + if (!metadata) { continue; } @@ -4740,16 +4740,16 @@ RefPtr maskLayer = CreateMaskLayer(aEntry->mLayer, *clip, nextIndex, clip->GetRoundedRectCount()); if (maskLayer) { - metrics->SetMaskLayerIndex(nextIndex); + metadata->SetMaskLayerIndex(nextIndex); maskLayers.AppendElement(maskLayer); } } - metricsArray.AppendElement(*metrics); + metricsArray.AppendElement(*metadata); } // Watch out for FrameMetrics copies in profiles - aEntry->mLayer->SetFrameMetrics(metricsArray); + aEntry->mLayer->SetScrollMetadata(metricsArray); aEntry->mLayer->SetAncestorMaskLayers(maskLayers); } @@ -4789,8 +4789,8 @@ static inline const Maybe& GetStationaryClipInContainer(Layer* aLayer) { - if (size_t metricsCount = aLayer->GetFrameMetricsCount()) { - return aLayer->GetFrameMetrics(metricsCount - 1).GetClipRect(); + if (size_t metricsCount = aLayer->GetScrollMetadataCount()) { + return aLayer->GetScrollMetadata(metricsCount - 1).GetClipRect(); } return aLayer->GetClipRect(); } diff -Nru firefox-47.0~b1+build1/layout/base/nsDisplayList.cpp firefox-47.0~b2+build1/layout/base/nsDisplayList.cpp --- firefox-47.0~b1+build1/layout/base/nsDisplayList.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/base/nsDisplayList.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -1691,11 +1691,11 @@ props = Move(LayerProperties::CloneFrom(layerManager->GetRoot())); } - // Clear any FrameMetrics that may have been set on the root layer on a + // Clear any ScrollMetadata that may have been set on the root layer on a // previous paint. This paint will set new metrics if necessary, and if we // don't clear the old one here, we may be left with extra metrics. if (Layer* root = layerManager->GetRoot()) { - root->SetFrameMetrics(nsTArray()); + root->SetScrollMetadata(nsTArray()); } ContainerLayerParameters containerParameters @@ -1767,8 +1767,8 @@ nsRect viewport(aBuilder->ToReferenceFrame(frame), frame->GetSize()); - root->SetFrameMetrics( - nsLayoutUtils::ComputeFrameMetrics(frame, + root->SetScrollMetadata( + nsLayoutUtils::ComputeScrollMetadata(frame, rootScrollFrame, content, aBuilder->FindReferenceFrameFor(frame), root, FrameMetrics::NULL_SCROLL_ID, viewport, Nothing(), @@ -4522,12 +4522,12 @@ return layer.forget(); } -UniquePtr -nsDisplaySubDocument::ComputeFrameMetrics(Layer* aLayer, - const ContainerLayerParameters& aContainerParameters) +UniquePtr +nsDisplaySubDocument::ComputeScrollMetadata(Layer* aLayer, + const ContainerLayerParameters& aContainerParameters) { if (!(mFlags & GENERATE_SCROLLABLE_LAYER)) { - return UniquePtr(nullptr); + return UniquePtr(nullptr); } nsPresContext* presContext = mFrame->PresContext(); @@ -4548,8 +4548,8 @@ mFrame->GetPosition() + mFrame->GetOffsetToCrossDoc(ReferenceFrame()); - return MakeUnique( - nsLayoutUtils::ComputeFrameMetrics( + return MakeUnique( + nsLayoutUtils::ComputeScrollMetadata( mFrame, rootScrollFrame, rootScrollFrame->GetContent(), ReferenceFrame(), aLayer, mScrollParentId, viewport, Nothing(), isRootContentDocument, params)); @@ -4931,9 +4931,9 @@ return LAYER_ACTIVE_EMPTY; } -UniquePtr -nsDisplayScrollInfoLayer::ComputeFrameMetrics(Layer* aLayer, - const ContainerLayerParameters& aContainerParameters) +UniquePtr +nsDisplayScrollInfoLayer::ComputeScrollMetadata(Layer* aLayer, + const ContainerLayerParameters& aContainerParameters) { ContainerLayerParameters params = aContainerParameters; if (mScrolledFrame->GetContent() && @@ -4945,13 +4945,13 @@ mScrollFrame->GetPosition() + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame()); - FrameMetrics metrics = nsLayoutUtils::ComputeFrameMetrics( + ScrollMetadata metadata = nsLayoutUtils::ComputeScrollMetadata( mScrolledFrame, mScrollFrame, mScrollFrame->GetContent(), ReferenceFrame(), aLayer, mScrollParentId, viewport, Nothing(), false, params); - metrics.SetIsScrollInfoLayer(true); + metadata.GetMetrics().SetIsScrollInfoLayer(true); - return UniquePtr(new FrameMetrics(metrics)); + return UniquePtr(new ScrollMetadata(metadata)); } diff -Nru firefox-47.0~b1+build1/layout/base/nsDisplayList.h firefox-47.0~b2+build1/layout/base/nsDisplayList.h --- firefox-47.0~b1+build1/layout/base/nsDisplayList.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/base/nsDisplayList.h 2016-05-03 05:14:21.000000000 +0000 @@ -1306,6 +1306,7 @@ typedef mozilla::DisplayItemClip DisplayItemClip; typedef mozilla::DisplayItemScrollClip DisplayItemScrollClip; typedef mozilla::layers::FrameMetrics FrameMetrics; + typedef mozilla::layers::ScrollMetadata ScrollMetadata; typedef mozilla::layers::FrameMetrics::ViewID ViewID; typedef mozilla::layers::Layer Layer; typedef mozilla::layers::LayerManager LayerManager; @@ -3536,8 +3537,8 @@ NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT) - mozilla::UniquePtr ComputeFrameMetrics(Layer* aLayer, - const ContainerLayerParameters& aContainerParameters); + mozilla::UniquePtr ComputeScrollMetadata(Layer* aLayer, + const ContainerLayerParameters& aContainerParameters); protected: ViewID mScrollParentId; @@ -3677,8 +3678,8 @@ virtual void WriteDebugInfo(std::stringstream& aStream) override; - mozilla::UniquePtr ComputeFrameMetrics(Layer* aLayer, - const ContainerLayerParameters& aContainerParameters); + mozilla::UniquePtr ComputeScrollMetadata(Layer* aLayer, + const ContainerLayerParameters& aContainerParameters); protected: nsIFrame* mScrollFrame; diff -Nru firefox-47.0~b1+build1/layout/base/nsFrameManager.cpp firefox-47.0~b2+build1/layout/base/nsFrameManager.cpp --- firefox-47.0~b1+build1/layout/base/nsFrameManager.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/base/nsFrameManager.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -553,7 +553,7 @@ nsAutoCString stateKey; nsIContent* content = aFrame->GetContent(); nsIDocument* doc = content ? content->GetCurrentDoc() : nullptr; - rv = nsContentUtils::GenerateStateKey(content, doc, stateKey); + rv = statefulFrame->GenerateStateKey(content, doc, stateKey); if(NS_FAILED(rv) || stateKey.IsEmpty()) { return; } @@ -616,7 +616,7 @@ nsAutoCString stateKey; nsIDocument* doc = content->GetCurrentDoc(); - nsresult rv = nsContentUtils::GenerateStateKey(content, doc, stateKey); + nsresult rv = statefulFrame->GenerateStateKey(content, doc, stateKey); if (NS_FAILED(rv) || stateKey.IsEmpty()) { return; } diff -Nru firefox-47.0~b1+build1/layout/base/nsLayoutUtils.cpp firefox-47.0~b2+build1/layout/base/nsLayoutUtils.cpp --- firefox-47.0~b1+build1/layout/base/nsLayoutUtils.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/base/nsLayoutUtils.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -8628,23 +8628,24 @@ && aScrollOrigin != nsGkAtoms::restore; } -/* static */ FrameMetrics -nsLayoutUtils::ComputeFrameMetrics(nsIFrame* aForFrame, - nsIFrame* aScrollFrame, - nsIContent* aContent, - const nsIFrame* aReferenceFrame, - Layer* aLayer, - ViewID aScrollParentId, - const nsRect& aViewport, - const Maybe& aClipRect, - bool aIsRootContent, - const ContainerLayerParameters& aContainerParameters) +/* static */ ScrollMetadata +nsLayoutUtils::ComputeScrollMetadata(nsIFrame* aForFrame, + nsIFrame* aScrollFrame, + nsIContent* aContent, + const nsIFrame* aReferenceFrame, + Layer* aLayer, + ViewID aScrollParentId, + const nsRect& aViewport, + const Maybe& aClipRect, + bool aIsRootContent, + const ContainerLayerParameters& aContainerParameters) { nsPresContext* presContext = aForFrame->PresContext(); int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel(); nsIPresShell* presShell = presContext->GetPresShell(); - FrameMetrics metrics; + ScrollMetadata metadata; + FrameMetrics& metrics = metadata.GetMetrics(); metrics.SetViewport(CSSRect::FromAppUnits(aViewport)); ViewID scrollId = FrameMetrics::NULL_SCROLL_ID; @@ -8712,6 +8713,8 @@ } metrics.SetUsesContainerScrolling(scrollableFrame->UsesContainerScrolling()); + + metadata.SetSnapInfo(scrollableFrame->GetScrollSnapInfo()); } // If we have the scrollparent being the same as the scroll id, the @@ -8779,7 +8782,7 @@ ParentLayerRect rect = LayoutDeviceRect::FromAppUnits(*aClipRect, auPerDevPixel) * metrics.GetCumulativeResolution() * layerToParentLayerScale; - metrics.SetClipRect(Some(RoundedToInt(rect))); + metadata.SetClipRect(Some(RoundedToInt(rect))); } // For the root scroll frame of the root content document (RCD-RSF), the above calculation @@ -8843,13 +8846,13 @@ } } - return metrics; + return metadata; } /* static */ bool nsLayoutUtils::ContainsMetricsWithId(const Layer* aLayer, const ViewID& aScrollId) { - for (uint32_t i = aLayer->GetFrameMetricsCount(); i > 0; i--) { + for (uint32_t i = aLayer->GetScrollMetadataCount(); i > 0; i--) { if (aLayer->GetFrameMetrics(i-1).GetScrollId() == aScrollId) { return true; } diff -Nru firefox-47.0~b1+build1/layout/base/nsLayoutUtils.h firefox-47.0~b2+build1/layout/base/nsLayoutUtils.h --- firefox-47.0~b1+build1/layout/base/nsLayoutUtils.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/base/nsLayoutUtils.h 2016-05-03 05:14:21.000000000 +0000 @@ -143,6 +143,7 @@ public: typedef mozilla::layers::FrameMetrics FrameMetrics; + typedef mozilla::layers::ScrollMetadata ScrollMetadata; typedef FrameMetrics::ViewID ViewID; typedef mozilla::CSSPoint CSSPoint; typedef mozilla::CSSSize CSSSize; @@ -2728,16 +2729,16 @@ */ static bool CanScrollOriginClobberApz(nsIAtom* aScrollOrigin); - static FrameMetrics ComputeFrameMetrics(nsIFrame* aForFrame, - nsIFrame* aScrollFrame, - nsIContent* aContent, - const nsIFrame* aReferenceFrame, - Layer* aLayer, - ViewID aScrollParentId, - const nsRect& aViewport, - const mozilla::Maybe& aClipRect, - bool aIsRoot, - const ContainerLayerParameters& aContainerParameters); + static ScrollMetadata ComputeScrollMetadata(nsIFrame* aForFrame, + nsIFrame* aScrollFrame, + nsIContent* aContent, + const nsIFrame* aReferenceFrame, + Layer* aLayer, + ViewID aScrollParentId, + const nsRect& aViewport, + const mozilla::Maybe& aClipRect, + bool aIsRoot, + const ContainerLayerParameters& aContainerParameters); /** * If the given scroll frame needs an area excluded from its composition diff -Nru firefox-47.0~b1+build1/layout/base/nsPresState.h firefox-47.0~b2+build1/layout/base/nsPresState.h --- firefox-47.0~b1+build1/layout/base/nsPresState.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/base/nsPresState.h 2016-05-03 05:14:21.000000000 +0000 @@ -25,6 +25,7 @@ , mScaleToResolution(false) , mDisabledSet(false) , mDisabled(false) + , mDroppedDown(false) {} void SetScrollState(const nsPoint& aState) @@ -89,6 +90,16 @@ mContentData = aProperty; } + void SetDroppedDown(bool aDroppedDown) + { + mDroppedDown = aDroppedDown; + } + + bool GetDroppedDown() const + { + return mDroppedDown; + } + // MEMBER VARIABLES protected: nsCOMPtr mContentData; @@ -97,6 +108,7 @@ bool mScaleToResolution; bool mDisabledSet; bool mDisabled; + bool mDroppedDown; }; #endif /* nsPresState_h_ */ diff -Nru firefox-47.0~b1+build1/layout/base/Units.h firefox-47.0~b2+build1/layout/base/Units.h --- firefox-47.0~b1+build1/layout/base/Units.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/base/Units.h 2016-05-03 05:14:21.000000000 +0000 @@ -248,6 +248,11 @@ NSToCoordRoundWithClamp(float(aPoint.y) * float(AppUnitsPerCSSPixel()))); } + static nsSize ToAppUnits(const CSSSize& aSize) { + return nsSize(NSToCoordRoundWithClamp(aSize.width * float(AppUnitsPerCSSPixel())), + NSToCoordRoundWithClamp(aSize.height * float(AppUnitsPerCSSPixel()))); + } + static nsSize ToAppUnits(const CSSIntSize& aSize) { return nsSize(NSToCoordRoundWithClamp(float(aSize.width) * float(AppUnitsPerCSSPixel())), NSToCoordRoundWithClamp(float(aSize.height) * float(AppUnitsPerCSSPixel()))); diff -Nru firefox-47.0~b1+build1/layout/forms/nsComboboxControlFrame.cpp firefox-47.0~b2+build1/layout/forms/nsComboboxControlFrame.cpp --- firefox-47.0~b1+build1/layout/forms/nsComboboxControlFrame.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/forms/nsComboboxControlFrame.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -19,6 +19,7 @@ #include "nsIListControlFrame.h" #include "nsPIDOMWindow.h" #include "nsIPresShell.h" +#include "nsPresState.h" #include "nsContentList.h" #include "nsView.h" #include "nsViewManager.h" @@ -316,14 +317,15 @@ viewManager->ResizeView(view, emptyRect); } - // fire a popup dom event - nsEventStatus status = nsEventStatus_eIgnore; - WidgetMouseEvent event(true, aShowPopup ? eXULPopupShowing : eXULPopupHiding, - nullptr, WidgetMouseEvent::eReal); - + // fire a popup dom event if it is safe to do so nsCOMPtr shell = PresContext()->GetPresShell(); - if (shell) + if (shell && nsContentUtils::IsSafeToRunScript()) { + nsEventStatus status = nsEventStatus_eIgnore; + WidgetMouseEvent event(true, aShowPopup ? eXULPopupShowing : eXULPopupHiding, + nullptr, WidgetMouseEvent::eReal); + shell->HandleDOMEventWithTarget(mContent, &event, &status); + } } bool @@ -447,7 +449,7 @@ forcedISize)); // ensure we start off hidden - if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { + if (!mDroppedDown && GetStateBits() & NS_FRAME_FIRST_REFLOW) { nsView* view = mDropdownFrame->GetView(); nsViewManager* viewManager = view->GetViewManager(); viewManager->SetViewVisibility(view, nsViewVisibility_kHide); @@ -1652,24 +1654,37 @@ NS_IMETHODIMP nsComboboxControlFrame::SaveState(nsPresState** aState) { - if (!mListControlFrame) - return NS_ERROR_FAILURE; - - nsIStatefulFrame* stateful = do_QueryFrame(mListControlFrame); - return stateful->SaveState(aState); + MOZ_ASSERT(!(*aState)); + (*aState) = new nsPresState(); + (*aState)->SetDroppedDown(mDroppedDown); + return NS_OK; } NS_IMETHODIMP nsComboboxControlFrame::RestoreState(nsPresState* aState) { - if (!mListControlFrame) + if (!aState) { return NS_ERROR_FAILURE; - - nsIStatefulFrame* stateful = do_QueryFrame(mListControlFrame); - NS_ASSERTION(stateful, "Must implement nsIStatefulFrame"); - return stateful->RestoreState(aState); + } + ShowList(aState->GetDroppedDown()); // might destroy us + return NS_OK; } +// Append a suffix so that the state key for the combobox is different +// from the state key the list control uses to sometimes save the scroll +// position for the same Element +NS_IMETHODIMP +nsComboboxControlFrame::GenerateStateKey(nsIContent* aContent, + nsIDocument* aDocument, + nsACString& aKey) +{ + nsresult rv = nsContentUtils::GenerateStateKey(aContent, aDocument, aKey); + if (NS_FAILED(rv) || aKey.IsEmpty()) { + return rv; + } + aKey.Append("CCF"); + return NS_OK; +} // Fennec uses a custom combobox built-in widget. // diff -Nru firefox-47.0~b1+build1/layout/forms/nsComboboxControlFrame.h firefox-47.0~b2+build1/layout/forms/nsComboboxControlFrame.h --- firefox-47.0~b1+build1/layout/forms/nsComboboxControlFrame.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/forms/nsComboboxControlFrame.h 2016-05-03 05:14:21.000000000 +0000 @@ -204,6 +204,9 @@ //nsIStatefulFrame NS_IMETHOD SaveState(nsPresState** aState) override; NS_IMETHOD RestoreState(nsPresState* aState) override; + NS_IMETHOD GenerateStateKey(nsIContent* aContent, + nsIDocument* aDocument, + nsACString& aKey) override; static bool ToolkitHasNativePopup(); diff -Nru firefox-47.0~b1+build1/layout/generic/moz.build firefox-47.0~b2+build1/layout/generic/moz.build --- firefox-47.0~b1+build1/layout/generic/moz.build 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/moz.build 2016-05-03 05:14:21.000000000 +0000 @@ -96,6 +96,7 @@ 'nsTextRunTransformations.h', 'RubyUtils.h', 'ScrollbarActivity.h', + 'ScrollSnap.h', ] EXPORTS.mozilla += [ @@ -165,6 +166,7 @@ 'nsViewportFrame.cpp', 'RubyUtils.cpp', 'ScrollbarActivity.cpp', + 'ScrollSnap.cpp', 'ScrollVelocityQueue.cpp', 'StickyScrollContainer.cpp', 'SummaryFrame.cpp', diff -Nru firefox-47.0~b1+build1/layout/generic/nsFrame.cpp firefox-47.0~b2+build1/layout/generic/nsFrame.cpp --- firefox-47.0~b1+build1/layout/generic/nsFrame.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/nsFrame.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -5273,7 +5273,7 @@ static bool DoesLayerHaveOutOfDateFrameMetrics(Layer* aLayer) { - for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) { + for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) { const FrameMetrics& metrics = aLayer->GetFrameMetrics(i); if (!metrics.IsScrollable()) { continue; diff -Nru firefox-47.0~b1+build1/layout/generic/nsGfxScrollFrame.cpp firefox-47.0~b2+build1/layout/generic/nsGfxScrollFrame.cpp --- firefox-47.0~b1+build1/layout/generic/nsGfxScrollFrame.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/nsGfxScrollFrame.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -59,6 +59,7 @@ #include "gfxPlatform.h" #include "gfxPrefs.h" #include "AsyncScrollBase.h" +#include "ScrollSnap.h" #include "UnitTransforms.h" #include "nsPluginFrame.h" #include @@ -3455,11 +3456,11 @@ } -Maybe -ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer, - nsIFrame* aContainerReferenceFrame, - const ContainerLayerParameters& aParameters, - const DisplayItemClip* aClip) const +Maybe +ScrollFrameHelper::ComputeScrollMetadata(Layer* aLayer, + nsIFrame* aContainerReferenceFrame, + const ContainerLayerParameters& aParameters, + const DisplayItemClip* aClip) const { if (!mWillBuildScrollableLayer || mIsScrollableLayerInRootContainer) { return Nothing(); @@ -3511,7 +3512,7 @@ nsRect scrollport = mScrollPort + toReferenceFrame; - return Some(nsLayoutUtils::ComputeFrameMetrics( + return Some(nsLayoutUtils::ComputeScrollMetadata( mScrolledFrame, mOuter, mOuter->GetContent(), aContainerReferenceFrame, aLayer, mScrollParentID, scrollport, parentLayerClip, isRootContent, aParameters)); @@ -5658,244 +5659,13 @@ } /** - * Stores candidate snapping edges. + * Collect the scroll-snap-coordinates of frames in the subtree rooted at + * |aFrame|, relative to |aScrolledFrame|, into |aOutCoords|. */ -class SnappingEdgeCallback { -public: - virtual void AddHorizontalEdge(nscoord aEdge) = 0; - virtual void AddVerticalEdge(nscoord aEdge) = 0; - virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange, - nscoord aInterval, - nscoord aOffset) = 0; - virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange, - nscoord aInterval, - nscoord aOffset) = 0; -}; - -/** - * Keeps track of the current best edge to snap to. The criteria for - * adding an edge depends on the scrolling unit. - */ -class CalcSnapPoints : public SnappingEdgeCallback { -public: - CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit, - const nsPoint& aDestination, - const nsPoint& aStartPos); - virtual void AddHorizontalEdge(nscoord aEdge) override; - virtual void AddVerticalEdge(nscoord aEdge) override; - virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange, - nscoord aInterval, nscoord aOffset) - override; - virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange, - nscoord aInterval, nscoord aOffset) - override; - void AddEdge(nscoord aEdge, - nscoord aDestination, - nscoord aStartPos, - nscoord aScrollingDirection, - nscoord* aBestEdge, - bool* aEdgeFound); - void AddEdgeInterval(nscoord aInterval, - nscoord aMinPos, - nscoord aMaxPos, - nscoord aOffset, - nscoord aDestination, - nscoord aStartPos, - nscoord aScrollingDirection, - nscoord* aBestEdge, - bool* aEdgeFound); - nsPoint GetBestEdge() const; -protected: - nsIScrollableFrame::ScrollUnit mUnit; - nsPoint mDestination; // gives the position after scrolling but before snapping - nsPoint mStartPos; // gives the position before scrolling - nsIntPoint mScrollingDirection; // always -1, 0, or 1 - nsPoint mBestEdge; // keeps track of the position of the current best edge - bool mHorizontalEdgeFound; // true if mBestEdge.x is storing a valid horizontal edge - bool mVerticalEdgeFound; // true if mBestEdge.y is storing a valid vertical edge -}; - -CalcSnapPoints::CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit, - const nsPoint& aDestination, - const nsPoint& aStartPos) -{ - mUnit = aUnit; - mDestination = aDestination; - mStartPos = aStartPos; - - nsPoint direction = aDestination - aStartPos; - mScrollingDirection = nsIntPoint(0,0); - if (direction.x < 0) { - mScrollingDirection.x = -1; - } - if (direction.x > 0) { - mScrollingDirection.x = 1; - } - if (direction.y < 0) { - mScrollingDirection.y = -1; - } - if (direction.y > 0) { - mScrollingDirection.y = 1; - } - mBestEdge = aDestination; - mHorizontalEdgeFound = false; - mVerticalEdgeFound = false; -} - -nsPoint -CalcSnapPoints::GetBestEdge() const -{ - return nsPoint(mVerticalEdgeFound ? mBestEdge.x : mStartPos.x, - mHorizontalEdgeFound ? mBestEdge.y : mStartPos.y); -} - -void -CalcSnapPoints::AddHorizontalEdge(nscoord aEdge) -{ - AddEdge(aEdge, mDestination.y, mStartPos.y, mScrollingDirection.y, &mBestEdge.y, - &mHorizontalEdgeFound); -} - void -CalcSnapPoints::AddVerticalEdge(nscoord aEdge) +CollectScrollSnapCoordinates(nsIFrame* aFrame, nsIFrame* aScrolledFrame, + nsTArray& aOutCoords) { - AddEdge(aEdge, mDestination.x, mStartPos.x, mScrollingDirection.x, &mBestEdge.x, - &mVerticalEdgeFound); -} - -void -CalcSnapPoints::AddHorizontalEdgeInterval(const nsRect &aScrollRange, - nscoord aInterval, nscoord aOffset) -{ - AddEdgeInterval(aInterval, aScrollRange.y, aScrollRange.YMost(), aOffset, - mDestination.y, mStartPos.y, mScrollingDirection.y, - &mBestEdge.y, &mHorizontalEdgeFound); -} - -void -CalcSnapPoints::AddVerticalEdgeInterval(const nsRect &aScrollRange, - nscoord aInterval, nscoord aOffset) -{ - AddEdgeInterval(aInterval, aScrollRange.x, aScrollRange.XMost(), aOffset, - mDestination.x, mStartPos.x, mScrollingDirection.x, - &mBestEdge.x, &mVerticalEdgeFound); -} - -void -CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination, nscoord aStartPos, - nscoord aScrollingDirection, nscoord* aBestEdge, - bool *aEdgeFound) -{ - // nsIScrollableFrame::DEVICE_PIXELS indicates that we are releasing a drag - // gesture or any other user input event that sets an absolute scroll - // position. In this case, scroll snapping is expected to travel in any - // direction. Otherwise, we will restrict the direction of the scroll - // snapping movement based on aScrollingDirection. - if (mUnit != nsIScrollableFrame::DEVICE_PIXELS) { - // Unless DEVICE_PIXELS, we only want to snap to points ahead of the - // direction we are scrolling - if (aScrollingDirection == 0) { - // The scroll direction is neutral - will not hit a snap point. - return; - } - // nsIScrollableFrame::WHOLE indicates that we are navigating to "home" or - // "end". In this case, we will always select the first or last snap point - // regardless of the direction of the scroll. Otherwise, we will select - // scroll snapping points only in the direction specified by - // aScrollingDirection. - if (mUnit != nsIScrollableFrame::WHOLE) { - // Direction of the edge from the current position (before scrolling) in - // the direction of scrolling - nscoord direction = (aEdge - aStartPos) * aScrollingDirection; - if (direction <= 0) { - // The edge is not in the direction we are scrolling, skip it. - return; - } - } - } - if (!*aEdgeFound) { - *aBestEdge = aEdge; - *aEdgeFound = true; - return; - } - if (mUnit == nsIScrollableFrame::DEVICE_PIXELS || - mUnit == nsIScrollableFrame::LINES) { - if (std::abs(aEdge - aDestination) < std::abs(*aBestEdge - aDestination)) { - *aBestEdge = aEdge; - } - } else if (mUnit == nsIScrollableFrame::PAGES) { - // distance to the edge from the scrolling destination in the direction of scrolling - nscoord overshoot = (aEdge - aDestination) * aScrollingDirection; - // distance to the current best edge from the scrolling destination in the direction of scrolling - nscoord curOvershoot = (*aBestEdge - aDestination) * aScrollingDirection; - - // edges between the current position and the scrolling destination are favoured - // to preserve context - if (overshoot < 0 && (overshoot > curOvershoot || curOvershoot >= 0)) { - *aBestEdge = aEdge; - } - // if there are no edges between the current position and the scrolling destination - // the closest edge beyond the destination is used - if (overshoot > 0 && overshoot < curOvershoot) { - *aBestEdge = aEdge; - } - } else if (mUnit == nsIScrollableFrame::WHOLE) { - // the edge closest to the top/bottom/left/right is used, depending on scrolling direction - if (aScrollingDirection > 0 && aEdge > *aBestEdge) { - *aBestEdge = aEdge; - } else if (aScrollingDirection < 0 && aEdge < *aBestEdge) { - *aBestEdge = aEdge; - } - } else { - NS_ERROR("Invalid scroll mode"); - return; - } -} - -void -CalcSnapPoints::AddEdgeInterval(nscoord aInterval, nscoord aMinPos, - nscoord aMaxPos, nscoord aOffset, - nscoord aDestination, nscoord aStartPos, - nscoord aScrollingDirection, - nscoord* aBestEdge, bool *aEdgeFound) -{ - if (aInterval == 0) { - // When interval is 0, there are no scroll snap points. - // Avoid division by zero and bail. - return; - } - - // The only possible candidate interval snap points are the edges immediately - // surrounding aDestination. - - // aDestination must be clamped to the scroll - // range in order to handle cases where the best matching snap point would - // result in scrolling out of bounds. This clamping must be prior to - // selecting the two interval edges. - nscoord clamped = std::max(std::min(aDestination, aMaxPos), aMinPos); - - // Add each edge in the interval immediately before aTarget and after aTarget - // Do not add edges that are out of range. - nscoord r = (clamped + aOffset) % aInterval; - if (r < aMinPos) { - r += aInterval; - } - nscoord edge = clamped - r; - if (edge >= aMinPos && edge <= aMaxPos) { - AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge, - aEdgeFound); - } - edge += aInterval; - if (edge >= aMinPos && edge <= aMaxPos) { - AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge, - aEdgeFound); - } -} - -static void -ScrollSnapHelper(SnappingEdgeCallback& aCallback, nsIFrame* aFrame, - nsIFrame* aScrolledFrame, - const nsPoint &aScrollSnapDestination) { nsIFrame::ChildListIterator childLists(aFrame); for (; !childLists.IsDone(); childLists.Next()) { nsFrameList::Enumerator childFrames(childLists.CurrentList()); @@ -5912,7 +5682,7 @@ for (size_t coordNum = 0; coordNum < coordCount; coordNum++) { const nsStyleImageLayers::Position &coordPosition = f->StyleDisplay()->mScrollSnapCoordinate[coordNum]; - nsPoint coordPoint = edgesRect.TopLeft() - aScrollSnapDestination; + nsPoint coordPoint = edgesRect.TopLeft(); coordPoint += nsPoint(coordPosition.mXPosition.mLength, coordPosition.mYPosition.mLength); if (coordPosition.mXPosition.mHasPercent) { @@ -5924,77 +5694,82 @@ frameRect.height); } - aCallback.AddVerticalEdge(coordPoint.x); - aCallback.AddHorizontalEdge(coordPoint.y); + aOutCoords.AppendElement(coordPoint); } } - ScrollSnapHelper(aCallback, f, aScrolledFrame, aScrollSnapDestination); + CollectScrollSnapCoordinates(f, aScrolledFrame, aOutCoords); } } } -bool -ScrollFrameHelper::GetSnapPointForDestination(nsIScrollableFrame::ScrollUnit aUnit, - nsPoint aStartPos, - nsPoint &aDestination) +layers::ScrollSnapInfo +ComputeScrollSnapInfo(const ScrollFrameHelper& aScrollFrame) { - ScrollbarStyles styles = GetScrollbarStylesFromFrame(); + ScrollSnapInfo result; + + ScrollbarStyles styles = aScrollFrame.GetScrollbarStylesFromFrame(); + if (styles.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_NONE && styles.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_NONE) { - return false; + // We won't be snapping, short-circuit the computation. + return result; } - nsSize scrollPortSize = mScrollPort.Size(); - nsRect scrollRange = GetScrollRangeForClamping(); + result.mScrollSnapTypeX = styles.mScrollSnapTypeX; + result.mScrollSnapTypeY = styles.mScrollSnapTypeY; + + nsSize scrollPortSize = aScrollFrame.GetScrollPortRect().Size(); - nsPoint destPos = nsPoint(styles.mScrollSnapDestinationX.mLength, - styles.mScrollSnapDestinationY.mLength); + result.mScrollSnapDestination = nsPoint(styles.mScrollSnapDestinationX.mLength, + styles.mScrollSnapDestinationY.mLength); if (styles.mScrollSnapDestinationX.mHasPercent) { - destPos.x += NSToCoordFloorClamped(styles.mScrollSnapDestinationX.mPercent - * scrollPortSize.width); + result.mScrollSnapDestination.x += + NSToCoordFloorClamped(styles.mScrollSnapDestinationX.mPercent * + scrollPortSize.width); } - if (styles.mScrollSnapDestinationY.mHasPercent) { - destPos.y += NSToCoordFloorClamped(styles.mScrollSnapDestinationY.mPercent - * scrollPortSize.height); + result.mScrollSnapDestination.y += + NSToCoordFloorClamped(styles.mScrollSnapDestinationY.mPercent * + scrollPortSize.height); } - CalcSnapPoints calcSnapPoints(aUnit, aDestination, aStartPos); - if (styles.mScrollSnapPointsX.GetUnit() != eStyleUnit_None) { - nscoord interval = nsRuleNode::ComputeCoordPercentCalc(styles.mScrollSnapPointsX, - scrollPortSize.width); - calcSnapPoints.AddVerticalEdgeInterval(scrollRange, interval, destPos.x); + result.mScrollSnapIntervalX = Some(nsRuleNode::ComputeCoordPercentCalc( + styles.mScrollSnapPointsX, scrollPortSize.width)); } if (styles.mScrollSnapPointsY.GetUnit() != eStyleUnit_None) { - nscoord interval = nsRuleNode::ComputeCoordPercentCalc(styles.mScrollSnapPointsY, - scrollPortSize.height); - calcSnapPoints.AddHorizontalEdgeInterval(scrollRange, interval, destPos.y); + result.mScrollSnapIntervalY = Some(nsRuleNode::ComputeCoordPercentCalc( + styles.mScrollSnapPointsY, scrollPortSize.height)); } - ScrollSnapHelper(calcSnapPoints, mScrolledFrame, mScrolledFrame, destPos); - bool snapped = false; - nsPoint finalPos = calcSnapPoints.GetBestEdge(); - nscoord proximityThreshold = - Preferences::GetInt("layout.css.scroll-snap.proximity-threshold", 0); - proximityThreshold = nsPresContext::CSSPixelsToAppUnits(proximityThreshold); - if (styles.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY && - std::abs(aDestination.y - finalPos.y) > proximityThreshold) { - finalPos.y = aDestination.y; - } else { - snapped = true; - } - if (styles.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY && - std::abs(aDestination.x - finalPos.x) > proximityThreshold) { - finalPos.x = aDestination.x; - } else { - snapped = true; - } - if (snapped) { - aDestination = finalPos; + CollectScrollSnapCoordinates(aScrollFrame.GetScrolledFrame(), + aScrollFrame.GetScrolledFrame(), + result.mScrollSnapCoordinates); + + return result; +} + +layers::ScrollSnapInfo +ScrollFrameHelper::GetScrollSnapInfo() const +{ + // TODO(botond): Should we cache it? + return ComputeScrollSnapInfo(*this); +} + +bool +ScrollFrameHelper::GetSnapPointForDestination(nsIScrollableFrame::ScrollUnit aUnit, + nsPoint aStartPos, + nsPoint &aDestination) +{ + Maybe snapPoint = ScrollSnapUtils::GetSnapPointForDestination( + GetScrollSnapInfo(), aUnit, mScrollPort.Size(), + GetScrollRangeForClamping(), aStartPos, aDestination); + if (snapPoint) { + aDestination = snapPoint.ref(); + return true; } - return snapped; + return false; } bool diff -Nru firefox-47.0~b1+build1/layout/generic/nsGfxScrollFrame.h firefox-47.0~b2+build1/layout/generic/nsGfxScrollFrame.h --- firefox-47.0~b1+build1/layout/generic/nsGfxScrollFrame.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/nsGfxScrollFrame.h 2016-05-03 05:14:21.000000000 +0000 @@ -49,6 +49,7 @@ typedef mozilla::CSSIntPoint CSSIntPoint; typedef mozilla::layout::ScrollbarActivity ScrollbarActivity; typedef mozilla::layers::FrameMetrics FrameMetrics; + typedef mozilla::layers::ScrollSnapInfo ScrollSnapInfo; typedef mozilla::layers::Layer Layer; class AsyncScroll; @@ -388,6 +389,8 @@ bool UsesContainerScrolling() const; + ScrollSnapInfo GetScrollSnapInfo() const; + bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder, nsRect* aDirtyRect, bool aAllowCreateDisplayPort); @@ -414,7 +417,7 @@ } } bool WantAsyncScroll() const; - Maybe ComputeFrameMetrics( + Maybe ComputeScrollMetadata( Layer* aLayer, nsIFrame* aContainerReferenceFrame, const ContainerLayerParameters& aParameters, const mozilla::DisplayItemClip* aClip) const; @@ -868,12 +871,12 @@ virtual bool WantAsyncScroll() const override { return mHelper.WantAsyncScroll(); } - virtual mozilla::Maybe ComputeFrameMetrics( + virtual mozilla::Maybe ComputeScrollMetadata( Layer* aLayer, nsIFrame* aContainerReferenceFrame, const ContainerLayerParameters& aParameters, const mozilla::DisplayItemClip* aClip) const override { - return mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame, aParameters, aClip); + return mHelper.ComputeScrollMetadata(aLayer, aContainerReferenceFrame, aParameters, aClip); } virtual bool IsIgnoringViewportClipping() const override { return mHelper.IsIgnoringViewportClipping(); @@ -966,6 +969,10 @@ mHelper.SetZoomableByAPZ(aZoomable); } + ScrollSnapInfo GetScrollSnapInfo() const override { + return mHelper.GetScrollSnapInfo(); + } + #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; #endif @@ -1269,12 +1276,12 @@ virtual bool WantAsyncScroll() const override { return mHelper.WantAsyncScroll(); } - virtual mozilla::Maybe ComputeFrameMetrics( + virtual mozilla::Maybe ComputeScrollMetadata( Layer* aLayer, nsIFrame* aContainerReferenceFrame, const ContainerLayerParameters& aParameters, const mozilla::DisplayItemClip* aClip) const override { - return mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame, aParameters, aClip); + return mHelper.ComputeScrollMetadata(aLayer, aContainerReferenceFrame, aParameters, aClip); } virtual bool IsIgnoringViewportClipping() const override { return mHelper.IsIgnoringViewportClipping(); @@ -1375,6 +1382,10 @@ mHelper.TriggerDisplayPortExpiration(); } + ScrollSnapInfo GetScrollSnapInfo() const override { + return mHelper.GetScrollSnapInfo(); + } + #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; #endif diff -Nru firefox-47.0~b1+build1/layout/generic/nsHTMLReflowState.cpp firefox-47.0~b2+build1/layout/generic/nsHTMLReflowState.cpp --- firefox-47.0~b1+build1/layout/generic/nsHTMLReflowState.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/nsHTMLReflowState.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -638,6 +638,29 @@ // Possibly; in that case we should at least be checking // NS_SUBTREE_DIRTY, I'd think. SetBResize(mCBReflowState->IsBResize()); + } else if (mCBReflowState && !nsLayoutUtils::GetAsBlock(frame)) { + // Some non-block frames (e.g. table frames) aggressively optimize out their + // BSize recomputation when they don't have the BResize flag set. This + // means that if they go from having a computed non-auto height to having an + // auto height and don't have that flag set, they will not actually compute + // their auto height and will just remain at whatever size they already + // were. We can end up in that situation if the child has a percentage + // specified height and the parent changes from non-auto height to auto + // height. When that happens, the parent will typically have the BResize + // flag set, and we want to propagate that flag to the kid. + // + // Ideally it seems like we'd do this for blocks too, of course... but we'd + // really want to restrict it to the percentage height case or something, to + // avoid extra reflows in common cases. Maybe we should be examining + // mStylePosition->BSize(wm).GetUnit() for that purpose? + // + // Note that we _also_ need to set the BResize flag if we have auto + // ComputedBSize() and a dirty subtree, since that might require us to + // change BSize due to kids having been added or removed. + SetBResize(mCBReflowState->IsBResize()); + if (ComputedBSize() == NS_AUTOHEIGHT) { + SetBResize(IsBResize() || NS_SUBTREE_DIRTY(frame)); + } } else if (ComputedBSize() == NS_AUTOHEIGHT) { if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() && mCBReflowState) { diff -Nru firefox-47.0~b1+build1/layout/generic/nsIScrollableFrame.h firefox-47.0~b2+build1/layout/generic/nsIScrollableFrame.h --- firefox-47.0~b1+build1/layout/generic/nsIScrollableFrame.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/nsIScrollableFrame.h 2016-05-03 05:14:21.000000000 +0000 @@ -48,6 +48,7 @@ typedef mozilla::CSSIntPoint CSSIntPoint; typedef mozilla::ContainerLayerParameters ContainerLayerParameters; typedef mozilla::layers::FrameMetrics FrameMetrics; + typedef mozilla::layers::ScrollSnapInfo ScrollSnapInfo; NS_DECL_QUERYFRAME_TARGET(nsIScrollableFrame) @@ -398,9 +399,9 @@ virtual bool WantAsyncScroll() const = 0; /** * aLayer's animated geometry root is this frame. If there needs to be a - * FrameMetrics contributed by this frame, append it to aOutput. + * ScrollMetadata contributed by this frame, append it to aOutput. */ - virtual mozilla::Maybe ComputeFrameMetrics( + virtual mozilla::Maybe ComputeScrollMetadata( mozilla::layers::Layer* aLayer, nsIFrame* aContainerReferenceFrame, const ContainerLayerParameters& aParameters, @@ -460,6 +461,11 @@ * own displayport and schedule a timer to do that if it is safe. */ virtual void TriggerDisplayPortExpiration() = 0; + + /** + * Returns information required to determine where to snap to after a scroll. + */ + virtual ScrollSnapInfo GetScrollSnapInfo() const = 0; }; #endif diff -Nru firefox-47.0~b1+build1/layout/generic/nsIStatefulFrame.h firefox-47.0~b2+build1/layout/generic/nsIStatefulFrame.h --- firefox-47.0~b1+build1/layout/generic/nsIStatefulFrame.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/nsIStatefulFrame.h 2016-05-03 05:14:21.000000000 +0000 @@ -25,6 +25,14 @@ // Restore the state for this frame from aState NS_IMETHOD RestoreState(nsPresState* aState) = 0; + + // Generate a key for this stateful frame + NS_IMETHOD GenerateStateKey(nsIContent* aContent, + nsIDocument* aDocument, + nsACString& aKey) + { + return nsContentUtils::GenerateStateKey(aContent, aDocument, aKey); + }; }; #endif /* _nsIStatefulFrame_h */ diff -Nru firefox-47.0~b1+build1/layout/generic/nsRubyTextContainerFrame.cpp firefox-47.0~b2+build1/layout/generic/nsRubyTextContainerFrame.cpp --- firefox-47.0~b1+build1/layout/generic/nsRubyTextContainerFrame.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/nsRubyTextContainerFrame.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -10,6 +10,7 @@ #include "mozilla/UniquePtr.h" #include "mozilla/WritingModes.h" +#include "nsLineLayout.h" #include "nsPresContext.h" #include "nsStyleContext.h" diff -Nru firefox-47.0~b1+build1/layout/generic/ScrollSnap.cpp firefox-47.0~b2+build1/layout/generic/ScrollSnap.cpp --- firefox-47.0~b1+build1/layout/generic/ScrollSnap.cpp 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/ScrollSnap.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -0,0 +1,311 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FrameMetrics.h" +#include "ScrollSnap.h" +#include "gfxPrefs.h" +#include "mozilla/Maybe.h" +#include "mozilla/Preferences.h" +#include "nsLineLayout.h" + +namespace mozilla { + +using layers::ScrollSnapInfo; + +/** + * Stores candidate snapping edges. + */ +class SnappingEdgeCallback { +public: + virtual void AddHorizontalEdge(nscoord aEdge) = 0; + virtual void AddVerticalEdge(nscoord aEdge) = 0; + virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange, + nscoord aInterval, + nscoord aOffset) = 0; + virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange, + nscoord aInterval, + nscoord aOffset) = 0; +}; + +/** + * Keeps track of the current best edge to snap to. The criteria for + * adding an edge depends on the scrolling unit. + */ +class CalcSnapPoints : public SnappingEdgeCallback { +public: + CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit, + const nsPoint& aDestination, + const nsPoint& aStartPos); + virtual void AddHorizontalEdge(nscoord aEdge) override; + virtual void AddVerticalEdge(nscoord aEdge) override; + virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange, + nscoord aInterval, nscoord aOffset) + override; + virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange, + nscoord aInterval, nscoord aOffset) + override; + void AddEdge(nscoord aEdge, + nscoord aDestination, + nscoord aStartPos, + nscoord aScrollingDirection, + nscoord* aBestEdge, + bool* aEdgeFound); + void AddEdgeInterval(nscoord aInterval, + nscoord aMinPos, + nscoord aMaxPos, + nscoord aOffset, + nscoord aDestination, + nscoord aStartPos, + nscoord aScrollingDirection, + nscoord* aBestEdge, + bool* aEdgeFound); + nsPoint GetBestEdge() const; +protected: + nsIScrollableFrame::ScrollUnit mUnit; + nsPoint mDestination; // gives the position after scrolling but before snapping + nsPoint mStartPos; // gives the position before scrolling + nsIntPoint mScrollingDirection; // always -1, 0, or 1 + nsPoint mBestEdge; // keeps track of the position of the current best edge + bool mHorizontalEdgeFound; // true if mBestEdge.x is storing a valid horizontal edge + bool mVerticalEdgeFound; // true if mBestEdge.y is storing a valid vertical edge +}; + +CalcSnapPoints::CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit, + const nsPoint& aDestination, + const nsPoint& aStartPos) +{ + mUnit = aUnit; + mDestination = aDestination; + mStartPos = aStartPos; + + nsPoint direction = aDestination - aStartPos; + mScrollingDirection = nsIntPoint(0,0); + if (direction.x < 0) { + mScrollingDirection.x = -1; + } + if (direction.x > 0) { + mScrollingDirection.x = 1; + } + if (direction.y < 0) { + mScrollingDirection.y = -1; + } + if (direction.y > 0) { + mScrollingDirection.y = 1; + } + mBestEdge = aDestination; + mHorizontalEdgeFound = false; + mVerticalEdgeFound = false; +} + +nsPoint +CalcSnapPoints::GetBestEdge() const +{ + return nsPoint(mVerticalEdgeFound ? mBestEdge.x : mStartPos.x, + mHorizontalEdgeFound ? mBestEdge.y : mStartPos.y); +} + +void +CalcSnapPoints::AddHorizontalEdge(nscoord aEdge) +{ + AddEdge(aEdge, mDestination.y, mStartPos.y, mScrollingDirection.y, &mBestEdge.y, + &mHorizontalEdgeFound); +} + +void +CalcSnapPoints::AddVerticalEdge(nscoord aEdge) +{ + AddEdge(aEdge, mDestination.x, mStartPos.x, mScrollingDirection.x, &mBestEdge.x, + &mVerticalEdgeFound); +} + +void +CalcSnapPoints::AddHorizontalEdgeInterval(const nsRect &aScrollRange, + nscoord aInterval, nscoord aOffset) +{ + AddEdgeInterval(aInterval, aScrollRange.y, aScrollRange.YMost(), aOffset, + mDestination.y, mStartPos.y, mScrollingDirection.y, + &mBestEdge.y, &mHorizontalEdgeFound); +} + +void +CalcSnapPoints::AddVerticalEdgeInterval(const nsRect &aScrollRange, + nscoord aInterval, nscoord aOffset) +{ + AddEdgeInterval(aInterval, aScrollRange.x, aScrollRange.XMost(), aOffset, + mDestination.x, mStartPos.x, mScrollingDirection.x, + &mBestEdge.x, &mVerticalEdgeFound); +} + +void +CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination, nscoord aStartPos, + nscoord aScrollingDirection, nscoord* aBestEdge, + bool *aEdgeFound) +{ + // nsIScrollableFrame::DEVICE_PIXELS indicates that we are releasing a drag + // gesture or any other user input event that sets an absolute scroll + // position. In this case, scroll snapping is expected to travel in any + // direction. Otherwise, we will restrict the direction of the scroll + // snapping movement based on aScrollingDirection. + if (mUnit != nsIScrollableFrame::DEVICE_PIXELS) { + // Unless DEVICE_PIXELS, we only want to snap to points ahead of the + // direction we are scrolling + if (aScrollingDirection == 0) { + // The scroll direction is neutral - will not hit a snap point. + return; + } + // nsIScrollableFrame::WHOLE indicates that we are navigating to "home" or + // "end". In this case, we will always select the first or last snap point + // regardless of the direction of the scroll. Otherwise, we will select + // scroll snapping points only in the direction specified by + // aScrollingDirection. + if (mUnit != nsIScrollableFrame::WHOLE) { + // Direction of the edge from the current position (before scrolling) in + // the direction of scrolling + nscoord direction = (aEdge - aStartPos) * aScrollingDirection; + if (direction <= 0) { + // The edge is not in the direction we are scrolling, skip it. + return; + } + } + } + if (!*aEdgeFound) { + *aBestEdge = aEdge; + *aEdgeFound = true; + return; + } + if (mUnit == nsIScrollableFrame::DEVICE_PIXELS || + mUnit == nsIScrollableFrame::LINES) { + if (std::abs(aEdge - aDestination) < std::abs(*aBestEdge - aDestination)) { + *aBestEdge = aEdge; + } + } else if (mUnit == nsIScrollableFrame::PAGES) { + // distance to the edge from the scrolling destination in the direction of scrolling + nscoord overshoot = (aEdge - aDestination) * aScrollingDirection; + // distance to the current best edge from the scrolling destination in the direction of scrolling + nscoord curOvershoot = (*aBestEdge - aDestination) * aScrollingDirection; + + // edges between the current position and the scrolling destination are favoured + // to preserve context + if (overshoot < 0 && (overshoot > curOvershoot || curOvershoot >= 0)) { + *aBestEdge = aEdge; + } + // if there are no edges between the current position and the scrolling destination + // the closest edge beyond the destination is used + if (overshoot > 0 && overshoot < curOvershoot) { + *aBestEdge = aEdge; + } + } else if (mUnit == nsIScrollableFrame::WHOLE) { + // the edge closest to the top/bottom/left/right is used, depending on scrolling direction + if (aScrollingDirection > 0 && aEdge > *aBestEdge) { + *aBestEdge = aEdge; + } else if (aScrollingDirection < 0 && aEdge < *aBestEdge) { + *aBestEdge = aEdge; + } + } else { + NS_ERROR("Invalid scroll mode"); + return; + } +} + +void +CalcSnapPoints::AddEdgeInterval(nscoord aInterval, nscoord aMinPos, + nscoord aMaxPos, nscoord aOffset, + nscoord aDestination, nscoord aStartPos, + nscoord aScrollingDirection, + nscoord* aBestEdge, bool *aEdgeFound) +{ + if (aInterval == 0) { + // When interval is 0, there are no scroll snap points. + // Avoid division by zero and bail. + return; + } + + // The only possible candidate interval snap points are the edges immediately + // surrounding aDestination. + + // aDestination must be clamped to the scroll + // range in order to handle cases where the best matching snap point would + // result in scrolling out of bounds. This clamping must be prior to + // selecting the two interval edges. + nscoord clamped = std::max(std::min(aDestination, aMaxPos), aMinPos); + + // Add each edge in the interval immediately before aTarget and after aTarget + // Do not add edges that are out of range. + nscoord r = (clamped + aOffset) % aInterval; + if (r < aMinPos) { + r += aInterval; + } + nscoord edge = clamped - r; + if (edge >= aMinPos && edge <= aMaxPos) { + AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge, + aEdgeFound); + } + edge += aInterval; + if (edge >= aMinPos && edge <= aMaxPos) { + AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge, + aEdgeFound); + } +} + +static void +ProcessScrollSnapCoordinates(SnappingEdgeCallback& aCallback, + const nsTArray& aScrollSnapCoordinates, + const nsPoint& aScrollSnapDestination) { + for (nsPoint snapCoords : aScrollSnapCoordinates) { + // Make them relative to the scroll snap destination. + snapCoords -= aScrollSnapDestination; + + aCallback.AddVerticalEdge(snapCoords.x); + aCallback.AddHorizontalEdge(snapCoords.y); + } +} + +Maybe ScrollSnapUtils::GetSnapPointForDestination( + const ScrollSnapInfo& aSnapInfo, + nsIScrollableFrame::ScrollUnit aUnit, + const nsSize& aScrollPortSize, + const nsRect& aScrollRange, + const nsPoint& aStartPos, + const nsPoint& aDestination) +{ + if (aSnapInfo.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_NONE && + aSnapInfo.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_NONE) { + return Nothing(); + } + + nsPoint destPos = aSnapInfo.mScrollSnapDestination; + + CalcSnapPoints calcSnapPoints(aUnit, aDestination, aStartPos); + + if (aSnapInfo.mScrollSnapIntervalX.isSome()) { + nscoord interval = aSnapInfo.mScrollSnapIntervalX.value(); + calcSnapPoints.AddVerticalEdgeInterval(aScrollRange, interval, destPos.x); + } + if (aSnapInfo.mScrollSnapIntervalY.isSome()) { + nscoord interval = aSnapInfo.mScrollSnapIntervalY.value(); + calcSnapPoints.AddHorizontalEdgeInterval(aScrollRange, interval, destPos.y); + } + + ProcessScrollSnapCoordinates(calcSnapPoints, aSnapInfo.mScrollSnapCoordinates, destPos); + bool snapped = false; + nsPoint finalPos = calcSnapPoints.GetBestEdge(); + nscoord proximityThreshold = gfxPrefs::ScrollSnapProximityThreshold(); + proximityThreshold = nsPresContext::CSSPixelsToAppUnits(proximityThreshold); + if (aSnapInfo.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY && + std::abs(aDestination.y - finalPos.y) > proximityThreshold) { + finalPos.y = aDestination.y; + } else { + snapped = true; + } + if (aSnapInfo.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY && + std::abs(aDestination.x - finalPos.x) > proximityThreshold) { + finalPos.x = aDestination.x; + } else { + snapped = true; + } + return snapped ? Some(finalPos) : Nothing(); +} + +} // namespace mozilla diff -Nru firefox-47.0~b1+build1/layout/generic/ScrollSnap.h firefox-47.0~b2+build1/layout/generic/ScrollSnap.h --- firefox-47.0~b1+build1/layout/generic/ScrollSnap.h 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/layout/generic/ScrollSnap.h 2016-05-03 05:14:21.000000000 +0000 @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layout_ScrollSnap_h_ +#define mozilla_layout_ScrollSnap_h_ + +namespace mozilla { + +namespace layers { +struct ScrollSnapInfo; +} + +struct ScrollSnapUtils { + /** + * GetSnapPointForDestination determines which point to snap to after + * scrolling. |aStartPos| gives the position before scrolling and + * |aDestination| gives the position after scrolling, with no snapping. + * Behaviour is dependent on the value of |aUnit|. + * |aSnapInfo|, |aScrollPortSize|, and |aScrollRange| are characteristics + * of the scroll frame for which snapping is being performed. + * If a suitable snap point could be found, it is returned. Otherwise, an + * empty Maybe is returned. + * IMPORTANT NOTE: This function is designed to be called both on and off + * the main thread. If modifying its implementation, be sure + * not to touch main-thread-only data structures without + * appropriate locking. + */ + static Maybe GetSnapPointForDestination( + const layers::ScrollSnapInfo& aSnapInfo, + nsIScrollableFrame::ScrollUnit aUnit, + const nsSize& aScrollPortSize, + const nsRect& aScrollRange, + const nsPoint& aStartPos, + const nsPoint& aDestination); +}; + +} // namespace mozilla + +#endif // mozilla_layout_ScrollSnap_h_ diff -Nru firefox-47.0~b1+build1/layout/reftests/bugs/1263845.html firefox-47.0~b2+build1/layout/reftests/bugs/1263845.html --- firefox-47.0~b1+build1/layout/reftests/bugs/1263845.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/layout/reftests/bugs/1263845.html 2016-05-03 05:14:22.000000000 +0000 @@ -0,0 +1,15 @@ + +
+ + + + +
+ This is some text +
+
+ diff -Nru firefox-47.0~b1+build1/layout/reftests/bugs/1263845-ref.html firefox-47.0~b2+build1/layout/reftests/bugs/1263845-ref.html --- firefox-47.0~b1+build1/layout/reftests/bugs/1263845-ref.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/layout/reftests/bugs/1263845-ref.html 2016-05-03 05:14:22.000000000 +0000 @@ -0,0 +1,10 @@ + +
+ + + + +
+ This is some text +
+
diff -Nru firefox-47.0~b1+build1/layout/reftests/bugs/reftest.list firefox-47.0~b2+build1/layout/reftests/bugs/reftest.list --- firefox-47.0~b1+build1/layout/reftests/bugs/reftest.list 2016-04-26 07:45:10.000000000 +0000 +++ firefox-47.0~b2+build1/layout/reftests/bugs/reftest.list 2016-05-03 05:14:23.000000000 +0000 @@ -1945,3 +1945,4 @@ pref(layout.css.overflow-clip-box.enabled,true) == 1226278.html 1226278-ref.html == 1230466.html about:blank fuzzy(100,2000) == 1239564.html 1239564-ref.html +== 1263845.html 1263845-ref.html diff -Nru firefox-47.0~b1+build1/layout/xul/nsSliderFrame.cpp firefox-47.0~b2+build1/layout/xul/nsSliderFrame.cpp --- firefox-47.0~b1+build1/layout/xul/nsSliderFrame.cpp 2016-04-26 07:45:03.000000000 +0000 +++ firefox-47.0~b2+build1/layout/xul/nsSliderFrame.cpp 2016-05-03 05:14:15.000000000 +0000 @@ -93,7 +93,6 @@ // stop timer nsSliderFrame::~nsSliderFrame() { - MOZ_ASSERT(!mSuppressionActive, "Should have un-suppress via StopDrag() first."); if (mSuppressionActive) { APZCCallbackHelper::SuppressDisplayport(false, PresContext() ? PresContext()->PresShell() : diff -Nru firefox-47.0~b1+build1/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp firefox-47.0~b2+build1/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp --- firefox-47.0~b1+build1/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp 2016-04-26 07:45:04.000000000 +0000 +++ firefox-47.0~b2+build1/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp 2016-05-03 05:14:16.000000000 +0000 @@ -2208,6 +2208,10 @@ CSFLogError(logTag, "%s: Track is not in stream", __FUNCTION__); return NS_ERROR_FAILURE; } + if (!aMediaStream.OwnsTrack(aTrack)) { + CSFLogError(logTag, "%s: Track is not in owned stream (Bug 1259236)", __FUNCTION__); + return NS_ERROR_NOT_IMPLEMENTED; + } uint32_t num = mMedia->LocalStreamsLength(); std::string streamId = PeerConnectionImpl::GetStreamId(aMediaStream); diff -Nru firefox-47.0~b1+build1/media/webrtc/signaling/test/FakeMediaStreams.h firefox-47.0~b2+build1/media/webrtc/signaling/test/FakeMediaStreams.h --- firefox-47.0~b1+build1/media/webrtc/signaling/test/FakeMediaStreams.h 2016-04-26 07:45:04.000000000 +0000 +++ firefox-47.0~b2+build1/media/webrtc/signaling/test/FakeMediaStreams.h 2016-05-03 05:14:16.000000000 +0000 @@ -414,6 +414,12 @@ ((mHintContents & HINT_CONTENTS_VIDEO) && aTrack.AsVideoStreamTrack()); } + bool + OwnsTrack(const Fake_MediaStreamTrack& aTrack) const + { + return HasTrack(aTrack); + } + void SetTrackEnabled(mozilla::TrackID aTrackID, bool aEnabled) {} Fake_MediaStreamTrack* diff -Nru firefox-47.0~b1+build1/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java firefox-47.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java --- firefox-47.0~b1+build1/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java 2016-04-26 07:45:06.000000000 +0000 +++ firefox-47.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java 2016-05-03 05:14:18.000000000 +0000 @@ -477,14 +477,15 @@ @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - if (mIMEState == IME_STATE_DISABLED) { - return null; - } - + // Some keyboards require us to fill out outAttrs even if we return null. outAttrs.inputType = InputType.TYPE_CLASS_TEXT; outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE; outAttrs.actionLabel = null; + if (mIMEState == IME_STATE_DISABLED) { + return null; + } + if (mIMEState == IME_STATE_PASSWORD || "password".equalsIgnoreCase(mIMETypeHint)) outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD; diff -Nru firefox-47.0~b1+build1/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java firefox-47.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java --- firefox-47.0~b1+build1/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java 2016-04-26 07:45:06.000000000 +0000 +++ firefox-47.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java 2016-05-03 05:14:18.000000000 +0000 @@ -142,6 +142,10 @@ void updateCompositor() { ThreadUtils.assertOnUiThread(); + if (mView == null) { + return; + } + if (mCompositorCreated) { // If the compositor has already been created, just resume it instead. We don't need // to block here because if the surface is destroyed before the compositor grabs it, diff -Nru firefox-47.0~b1+build1/mobile/android/base/java/org/mozilla/gecko/home/RemoteTabsStaticFragment.java firefox-47.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/home/RemoteTabsStaticFragment.java --- firefox-47.0~b1+build1/mobile/android/base/java/org/mozilla/gecko/home/RemoteTabsStaticFragment.java 2016-04-26 07:45:06.000000000 +0000 +++ firefox-47.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/home/RemoteTabsStaticFragment.java 2016-05-03 05:14:18.000000000 +0000 @@ -11,6 +11,8 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import org.mozilla.gecko.R; +import org.mozilla.gecko.Telemetry; +import org.mozilla.gecko.TelemetryContract; import org.mozilla.gecko.fxa.FirefoxAccounts; import org.mozilla.gecko.fxa.FxAccountConstants; import org.mozilla.gecko.home.HomePager.OnUrlOpenListener; @@ -123,6 +125,9 @@ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } + + final String extras = getResources().getResourceEntryName(id); + Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.BUTTON, extras); } @Override diff -Nru firefox-47.0~b1+build1/mobile/android/base/java/org/mozilla/gecko/TextSelection.java firefox-47.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/TextSelection.java --- firefox-47.0~b1+build1/mobile/android/base/java/org/mozilla/gecko/TextSelection.java 2016-04-26 07:45:06.000000000 +0000 +++ firefox-47.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/TextSelection.java 2016-05-03 05:14:18.000000000 +0000 @@ -14,6 +14,8 @@ import org.mozilla.gecko.menu.GeckoMenu; import org.mozilla.gecko.menu.GeckoMenuItem; import org.mozilla.gecko.EventDispatcher; +import org.mozilla.gecko.Telemetry; +import org.mozilla.gecko.TelemetryContract; import org.mozilla.gecko.util.FloatUtils; import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.ThreadUtils; @@ -144,6 +146,9 @@ public void run() { try { if (event.equals("TextSelection:ShowHandles")) { + Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, + TelemetryContract.Method.CONTENT, "text_selection"); + selectionID = message.getString("selectionID"); final JSONArray handles = message.getJSONArray("handles"); for (int i=0; i < handles.length(); i++) { diff -Nru firefox-47.0~b1+build1/netwerk/base/moz.build firefox-47.0~b2+build1/netwerk/base/moz.build --- firefox-47.0~b1+build1/netwerk/base/moz.build 2016-04-26 07:45:07.000000000 +0000 +++ firefox-47.0~b2+build1/netwerk/base/moz.build 2016-05-03 05:14:20.000000000 +0000 @@ -249,6 +249,7 @@ 'nsURLHelper.cpp', 'nsURLParsers.cpp', 'OfflineObserver.cpp', + 'PollableEvent.cpp', 'Predictor.cpp', 'ProxyAutoConfig.cpp', 'RedirectChannelRegistrar.cpp', diff -Nru firefox-47.0~b1+build1/netwerk/base/nsSocketTransportService2.cpp firefox-47.0~b2+build1/netwerk/base/nsSocketTransportService2.cpp --- firefox-47.0~b1+build1/netwerk/base/nsSocketTransportService2.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/netwerk/base/nsSocketTransportService2.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -87,13 +87,13 @@ nsSocketTransportService::nsSocketTransportService() : mThread(nullptr) - , mThreadEvent(nullptr) , mAutodialEnabled(false) , mLock("nsSocketTransportService::mLock") , mInitialized(false) , mShuttingDown(false) , mOffline(false) , mGoingOffline(false) + , mRawThread(nullptr) , mActiveListSize(SOCKET_LIMIT_MIN) , mIdleListSize(SOCKET_LIMIT_MIN) , mActiveCount(0) @@ -131,9 +131,6 @@ { NS_ASSERTION(NS_IsMainThread(), "wrong thread"); NS_ASSERTION(!mInitialized, "not shutdown properly"); - - if (mThreadEvent) - PR_DestroyPollableEvent(mThreadEvent); free(mActiveList); free(mIdleList); @@ -435,7 +432,7 @@ } int32_t -nsSocketTransportService::Poll(bool wait, uint32_t *interval, +nsSocketTransportService::Poll(uint32_t *interval, TimeDuration *pollDuration) { PRPollDesc *pollList; @@ -443,11 +440,16 @@ PRIntervalTime pollTimeout; *pollDuration = 0; + // If there are pending events for this thread then + // DoPollIteration() should service the network without blocking. + bool pendingEvents = false; + mRawThread->HasPendingEvents(&pendingEvents); + if (mPollList[0].fd) { mPollList[0].out_flags = 0; pollList = mPollList; pollCount = mActiveCount + 1; - pollTimeout = PollTimeout(); + pollTimeout = pendingEvents ? PR_INTERVAL_NO_WAIT : PollTimeout(); } else { // no pollable event, so busy wait... @@ -456,12 +458,10 @@ pollList = &mPollList[1]; else pollList = nullptr; - pollTimeout = PR_MillisecondsToInterval(25); + pollTimeout = + pendingEvents ? PR_INTERVAL_NO_WAIT : PR_MillisecondsToInterval(25); } - if (!wait) - pollTimeout = PR_INTERVAL_NO_WAIT; - PRIntervalTime ts = PR_IntervalNow(); TimeStamp pollStart; @@ -513,24 +513,6 @@ if (mShuttingDown) return NS_ERROR_UNEXPECTED; - if (!mThreadEvent) { - mThreadEvent = PR_NewPollableEvent(); - // - // NOTE: per bug 190000, this failure could be caused by Zone-Alarm - // or similar software. - // - // NOTE: per bug 191739, this failure could also be caused by lack - // of a loopback device on Windows and OS/2 platforms (NSPR creates - // a loopback socket pair on these platforms to implement a pollable - // event object). if we can't create a pollable event, then we'll - // have to "busy wait" to implement the socket event queue :-( - // - if (!mThreadEvent) { - NS_WARNING("running socket transport thread without a pollable event"); - SOCKET_LOG(("running socket transport thread without a pollable event")); - } - } - nsCOMPtr thread; nsresult rv = NS_NewThread(getter_AddRefs(thread), this); if (NS_FAILED(rv)) return rv; @@ -584,9 +566,9 @@ // signal the socket thread to shutdown mShuttingDown = true; - if (mThreadEvent) - PR_SetPollableEvent(mThreadEvent); - // else wait for Poll timeout + if (mPollableEvent) { + mPollableEvent->Signal(); + } } // join with thread @@ -635,8 +617,9 @@ else if (mOffline && !offline) { mOffline = false; } - if (mThreadEvent) - PR_SetPollableEvent(mThreadEvent); + if (mPollableEvent) { + mPollableEvent->Signal(); + } return NS_OK; } @@ -749,9 +732,19 @@ NS_IMETHODIMP nsSocketTransportService::OnDispatchedEvent(nsIThreadInternal *thread) { + if (PR_GetCurrentThread() == gSocketThread) { + // this check is redundant to one done inside ::Signal(), but + // we can do it here and skip obtaining the lock - given that + // this is a relatively common occurance its worth the + // redundant code + SOCKET_LOG(("OnDispatchedEvent Same Thread Skip Signal\n")); + return NS_OK; + } + DebugMutexAutoLock lock(mLock); - if (mThreadEvent) - PR_SetPollableEvent(mThreadEvent); + if (mPollableEvent) { + mPollableEvent->Signal(); + } return NS_OK; } @@ -796,15 +789,34 @@ gSocketThread = PR_GetCurrentThread(); - // add thread event to poll list (mThreadEvent may be nullptr) - mPollList[0].fd = mThreadEvent; - mPollList[0].in_flags = PR_POLL_READ; - mPollList[0].out_flags = 0; + { + DebugMutexAutoLock lock(mLock); + mPollableEvent.reset(new PollableEvent()); + // + // NOTE: per bug 190000, this failure could be caused by Zone-Alarm + // or similar software. + // + // NOTE: per bug 191739, this failure could also be caused by lack + // of a loopback device on Windows and OS/2 platforms (it creates + // a loopback socket pair on these platforms to implement a pollable + // event object). if we can't create a pollable event, then we'll + // have to "busy wait" to implement the socket event queue :-( + // + if (!mPollableEvent->Valid()) { + mPollableEvent = nullptr; + NS_WARNING("running socket transport thread without a pollable event"); + SOCKET_LOG(("running socket transport thread without a pollable event")); + } + + mPollList[0].fd = mPollableEvent ? mPollableEvent->PollableFD() : nullptr; + mPollList[0].in_flags = PR_POLL_READ | PR_POLL_EXCEPT; + mPollList[0].out_flags = 0; + } - nsIThread *thread = NS_GetCurrentThread(); + mRawThread = NS_GetCurrentThread(); // hook ourselves up to observe event processing for this thread - nsCOMPtr threadInt = do_QueryInterface(thread); + nsCOMPtr threadInt = do_QueryInterface(mRawThread); threadInt->SetObserver(this); // make sure the pseudo random number generator is seeded on this thread @@ -833,7 +845,6 @@ for (;;) { bool pendingEvents = false; - thread->HasPendingEvents(&pendingEvents); numberOfPendingEvents = 0; numberOfPendingEventsLastCycle = 0; @@ -848,9 +859,7 @@ pollCycleStart = TimeStamp::NowLoRes(); } - // If there are pending events for this thread then - // DoPollIteration() should service the network without blocking. - DoPollIteration(!pendingEvents, &singlePollDuration); + DoPollIteration(&singlePollDuration); if (mTelemetryEnabledPref && !pollCycleStart.IsNull()) { Telemetry::Accumulate(Telemetry::STS_POLL_BLOCK_TIME, @@ -862,11 +871,7 @@ pollDuration += singlePollDuration; } - // If nothing was pending before the poll, it might be now - if (!pendingEvents) { - thread->HasPendingEvents(&pendingEvents); - } - + mRawThread->HasPendingEvents(&pendingEvents); if (pendingEvents) { if (!mServingPendingQueue) { nsresult rv = Dispatch(NS_NewRunnableMethod(this, @@ -890,10 +895,10 @@ } TimeStamp eventQueueStart = TimeStamp::NowLoRes(); do { - NS_ProcessNextEvent(thread); + NS_ProcessNextEvent(mRawThread); numberOfPendingEvents++; pendingEvents = false; - thread->HasPendingEvents(&pendingEvents); + mRawThread->HasPendingEvents(&pendingEvents); } while (pendingEvents && mServingPendingQueue && ((TimeStamp::NowLoRes() - eventQueueStart).ToMilliseconds() < @@ -951,7 +956,7 @@ // Final pass over the event queue. This makes sure that events posted by // socket detach handlers get processed. - NS_ProcessPendingEvents(thread); + NS_ProcessPendingEvents(mRawThread); gSocketThread = nullptr; @@ -990,12 +995,11 @@ } nsresult -nsSocketTransportService::DoPollIteration(bool wait, TimeDuration *pollDuration) +nsSocketTransportService::DoPollIteration(TimeDuration *pollDuration) { - SOCKET_LOG(("STS poll iter [%d]\n", wait)); + SOCKET_LOG(("STS poll iter\n")); int32_t i, count; - // // poll loop // @@ -1054,7 +1058,7 @@ *pollDuration = 0; if (!gIOService->IsNetTearingDown()) { // Let's not do polling during shutdown. - n = Poll(wait, &pollInterval, pollDuration); + n = Poll(&pollInterval, pollDuration); } if (n < 0) { @@ -1110,29 +1114,28 @@ DetachSocket(mActiveList, &mActiveList[i]); } - if (n != 0 && mPollList[0].out_flags == PR_POLL_READ) { - // acknowledge pollable event (wait should not block) - if (PR_WaitForPollableEvent(mThreadEvent) != PR_SUCCESS) { + if (n != 0 && (mPollList[0].out_flags & (PR_POLL_READ | PR_POLL_EXCEPT))) { + DebugMutexAutoLock lock(mLock); + + // acknowledge pollable event (should not block) + if (mPollableEvent && + ((mPollList[0].out_flags & PR_POLL_EXCEPT) || + !mPollableEvent->Clear())) { // On Windows, the TCP loopback connection in the // pollable event may become broken when a laptop // switches between wired and wireless networks or // wakes up from hibernation. We try to create a // new pollable event. If that fails, we fall back // on "busy wait". - { - DebugMutexAutoLock lock(mLock); - PR_DestroyPollableEvent(mThreadEvent); - mThreadEvent = PR_NewPollableEvent(); - } - if (!mThreadEvent) { - NS_WARNING("running socket transport thread without " - "a pollable event"); - SOCKET_LOG(("running socket transport thread without " - "a pollable event")); + NS_WARNING("Trying to repair mPollableEvent"); + mPollableEvent.reset(new PollableEvent()); + if (!mPollableEvent->Valid()) { + mPollableEvent = nullptr; } - mPollList[0].fd = mThreadEvent; - // mPollList[0].in_flags was already set to PR_POLL_READ - // in Run(). + SOCKET_LOG(("running socket transport thread without " + "a pollable event now valid=%d", mPollableEvent->Valid())); + mPollList[0].fd = mPollableEvent ? mPollableEvent->PollableFD() : nullptr; + mPollList[0].in_flags = PR_POLL_READ | PR_POLL_EXCEPT; mPollList[0].out_flags = 0; } } diff -Nru firefox-47.0~b1+build1/netwerk/base/nsSocketTransportService2.h firefox-47.0~b2+build1/netwerk/base/nsSocketTransportService2.h --- firefox-47.0~b1+build1/netwerk/base/nsSocketTransportService2.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/netwerk/base/nsSocketTransportService2.h 2016-05-03 05:14:20.000000000 +0000 @@ -19,6 +19,8 @@ #include "mozilla/net/DashboardTypes.h" #include "mozilla/Atomics.h" #include "mozilla/TimeStamp.h" +#include "mozilla/UniquePtr.h" +#include "PollableEvent.h" class nsASocketHandler; struct PRPollDesc; @@ -124,14 +126,7 @@ //------------------------------------------------------------------------- nsCOMPtr mThread; // protected by mLock - PRFileDesc *mThreadEvent; - // protected by mLock. mThreadEvent may change - // if the old pollable event is broken. only - // the socket thread may change mThreadEvent; - // it needs to lock mLock only when it changes - // mThreadEvent. other threads don't change - // mThreadEvent; they need to lock mLock - // whenever they access mThreadEvent. + mozilla::UniquePtr mPollableEvent; bool mAutodialEnabled; // pref to control autodial code @@ -173,6 +168,7 @@ SocketContext *mActiveList; /* mListSize entries */ SocketContext *mIdleList; /* mListSize entries */ + nsIThread *mRawThread; uint32_t mActiveListSize; uint32_t mIdleListSize; @@ -197,18 +193,16 @@ //------------------------------------------------------------------------- // poll list (socket thread only) // - // first element of the poll list is mThreadEvent (or null if the pollable + // first element of the poll list is mPollableEvent (or null if the pollable // event cannot be created). //------------------------------------------------------------------------- PRPollDesc *mPollList; /* mListSize + 1 entries */ PRIntervalTime PollTimeout(); // computes ideal poll timeout - nsresult DoPollIteration(bool wait, - mozilla::TimeDuration *pollDuration); + nsresult DoPollIteration(mozilla::TimeDuration *pollDuration); // perfoms a single poll iteration - int32_t Poll(bool wait, - uint32_t *interval, + int32_t Poll(uint32_t *interval, mozilla::TimeDuration *pollDuration); // calls PR_Poll. the out param // interval indicates the poll diff -Nru firefox-47.0~b1+build1/netwerk/base/nsURIHashKey.h firefox-47.0~b2+build1/netwerk/base/nsURIHashKey.h --- firefox-47.0~b1+build1/netwerk/base/nsURIHashKey.h 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/netwerk/base/nsURIHashKey.h 2016-05-03 05:14:20.000000000 +0000 @@ -29,6 +29,9 @@ bool KeyEquals(const nsIURI* aKey) const { bool eq; + if (!mKey) { + return !aKey; + } if (NS_SUCCEEDED(mKey->Equals(const_cast(aKey), &eq))) { return eq; } @@ -37,11 +40,15 @@ static const nsIURI* KeyToPointer(nsIURI* aKey) { return aKey; } static PLDHashNumber HashKey(const nsIURI* aKey) { + if (!aKey) { + // If the key is null, return hash for empty string. + return mozilla::HashString(EmptyCString()); + } nsAutoCString spec; const_cast(aKey)->GetSpec(spec); return mozilla::HashString(spec); } - + enum { ALLOW_MEMMOVE = true }; protected: diff -Nru firefox-47.0~b1+build1/netwerk/base/PollableEvent.cpp firefox-47.0~b2+build1/netwerk/base/PollableEvent.cpp --- firefox-47.0~b1+build1/netwerk/base/PollableEvent.cpp 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/netwerk/base/PollableEvent.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -0,0 +1,275 @@ +/* -*- 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/. */ + +#include "nsSocketTransportService2.h" +#include "PollableEvent.h" +#include "mozilla/Assertions.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/Logging.h" +#include "prerror.h" +#include "prio.h" +#include "private/pprio.h" +#include "prnetdb.h" + +#ifdef XP_WIN +#include "ShutdownLayer.h" +#else +#include +#define USEPIPE 1 +#endif + +namespace mozilla { +namespace net { + +#ifndef USEPIPE +static PRDescIdentity sPollableEventLayerIdentity; +static PRIOMethods sPollableEventLayerMethods; +static PRIOMethods *sPollableEventLayerMethodsPtr = nullptr; + +static void LazyInitSocket() +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + if (sPollableEventLayerMethodsPtr) { + return; + } + sPollableEventLayerIdentity = PR_GetUniqueIdentity("PollableEvent Layer"); + sPollableEventLayerMethods = *PR_GetDefaultIOMethods(); + sPollableEventLayerMethodsPtr = &sPollableEventLayerMethods; +} + +static bool NewTCPSocketPair(PRFileDesc *fd[]) +{ + // this is a replacement for PR_NewTCPSocketPair that manually + // sets the recv buffer to 64K. A windows bug (1248358) + // can result in using an incompatible rwin and window + // scale option on localhost pipes if not set before connect. + + PRFileDesc *listener = nullptr; + PRFileDesc *writer = nullptr; + PRFileDesc *reader = nullptr; + PRSocketOptionData recvBufferOpt; + recvBufferOpt.option = PR_SockOpt_RecvBufferSize; + recvBufferOpt.value.recv_buffer_size = 65535; + + PRSocketOptionData nodelayOpt; + nodelayOpt.option = PR_SockOpt_NoDelay; + nodelayOpt.value.no_delay = true; + + PRSocketOptionData noblockOpt; + noblockOpt.option = PR_SockOpt_Nonblocking; + noblockOpt.value.non_blocking = true; + + listener = PR_OpenTCPSocket(PR_AF_INET); + if (!listener) { + goto failed; + } + PR_SetSocketOption(listener, &recvBufferOpt); + PR_SetSocketOption(listener, &nodelayOpt); + + PRNetAddr listenAddr; + memset(&listenAddr, 0, sizeof(listenAddr)); + if ((PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &listenAddr) == PR_FAILURE) || + (PR_Bind(listener, &listenAddr) == PR_FAILURE) || + (PR_GetSockName(listener, &listenAddr) == PR_FAILURE) || // learn the dynamic port + (PR_Listen(listener, 5) == PR_FAILURE)) { + goto failed; + } + + writer = PR_OpenTCPSocket(PR_AF_INET); + if (!writer) { + goto failed; + } + PR_SetSocketOption(writer, &recvBufferOpt); + PR_SetSocketOption(writer, &nodelayOpt); + PR_SetSocketOption(writer, &noblockOpt); + PRNetAddr writerAddr; + if (PR_InitializeNetAddr(PR_IpAddrLoopback, ntohs(listenAddr.inet.port), &writerAddr) == PR_FAILURE) { + goto failed; + } + + if (PR_Connect(writer, &writerAddr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + if ((PR_GetError() != PR_IN_PROGRESS_ERROR) || + (PR_ConnectContinue(writer, PR_POLL_WRITE) == PR_FAILURE)) { + goto failed; + } + } + + reader = PR_Accept(listener, &listenAddr, PR_INTERVAL_NO_TIMEOUT); + if (!reader) { + goto failed; + } + PR_SetSocketOption(reader, &recvBufferOpt); + PR_SetSocketOption(reader, &nodelayOpt); + PR_SetSocketOption(reader, &noblockOpt); + PR_Close(listener); + + fd[0] = reader; + fd[1] = writer; + return true; + +failed: + if (listener) { + PR_Close(listener); + } + if (reader) { + PR_Close(reader); + } + if (writer) { + PR_Close(writer); + } + return false; +} + +#endif + +PollableEvent::PollableEvent() + : mWriteFD(nullptr) + , mReadFD(nullptr) + , mSignaled(false) +{ + MOZ_COUNT_CTOR(PollableEvent); + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + // create pair of prfiledesc that can be used as a poll()ble + // signal. on windows use a localhost socket pair, and on + // unix use a pipe. +#ifdef USEPIPE + SOCKET_LOG(("PollableEvent() using pipe\n")); + if (PR_CreatePipe(&mReadFD, &mWriteFD) == PR_SUCCESS) { + // make the pipe non blocking. NSPR asserts at + // trying to use SockOpt here + PROsfd fd = PR_FileDesc2NativeHandle(mReadFD); + int flags = fcntl(fd, F_GETFL, 0); + (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK); + fd = PR_FileDesc2NativeHandle(mWriteFD); + flags = fcntl(fd, F_GETFL, 0); + (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } else { + mReadFD = nullptr; + mWriteFD = nullptr; + SOCKET_LOG(("PollableEvent() pipe failed\n")); + } +#else + SOCKET_LOG(("PollableEvent() using socket pair\n")); + PRFileDesc *fd[2]; + LazyInitSocket(); + if (NewTCPSocketPair(fd)) { + mReadFD = fd[0]; + mWriteFD = fd[1]; + + // compatibility with LSPs such as McAfee that assume a NSPR + // layer for read ala the nspr Pollable Event - Bug 698882. This layer is a nop. + PRFileDesc *topLayer = + PR_CreateIOLayerStub(sPollableEventLayerIdentity, + sPollableEventLayerMethodsPtr); + if (topLayer) { + if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, topLayer) == PR_FAILURE) { + topLayer->dtor(topLayer); + } else { + SOCKET_LOG(("PollableEvent() nspr layer ok\n")); + mReadFD = topLayer; + } + } + + } else { + SOCKET_LOG(("PollableEvent() socketpair failed\n")); + } +#endif + + if (mReadFD && mWriteFD) { + // prime the system to deal with races invovled in [dc]tor cycle + SOCKET_LOG(("PollableEvent() ctor ok\n")); + mSignaled = true; + PR_Write(mWriteFD, "I", 1); + } +} + +PollableEvent::~PollableEvent() +{ + MOZ_COUNT_DTOR(PollableEvent); + if (mWriteFD) { +#if defined(XP_WIN) + AttachShutdownLayer(mWriteFD); +#endif + PR_Close(mWriteFD); + } + if (mReadFD) { +#if defined(XP_WIN) + AttachShutdownLayer(mReadFD); +#endif + PR_Close(mReadFD); + } +} + +// we do not record signals on the socket thread +// because the socket thread can reliably look at its +// own runnable queue before selecting a poll time +// this is the "service the network without blocking" comment in +// nsSocketTransportService2.cpp +bool +PollableEvent::Signal() +{ + SOCKET_LOG(("PollableEvent::Signal\n")); + + if (!mWriteFD) { + SOCKET_LOG(("PollableEvent::Signal Failed on no FD\n")); + return false; + } + if (PR_GetCurrentThread() == gSocketThread) { + SOCKET_LOG(("PollableEvent::Signal OnSocketThread nop\n")); + return true; + } + if (mSignaled) { + return true; + } + mSignaled = true; + int32_t status = PR_Write(mWriteFD, "M", 1); + SOCKET_LOG(("PollableEvent::Signal PR_Write %d\n", status)); + if (status != 1) { + NS_WARNING("PollableEvent::Signal Failed\n"); + SOCKET_LOG(("PollableEvent::Signal Failed\n")); + } + return (status == 1); +} + +bool +PollableEvent::Clear() +{ + // necessary because of the "dont signal on socket thread" optimization + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + SOCKET_LOG(("PollableEvent::Clear\n")); + mSignaled = false; + if (!mReadFD) { + SOCKET_LOG(("PollableEvent::Clear mReadFD is null\n")); + return false; + } + char buf[2048]; + int32_t status = PR_Read(mReadFD, buf, 2048); + SOCKET_LOG(("PollableEvent::Signal PR_Read %d\n", status)); + + if (status == 1) { + return true; + } + if (status == 0) { + SOCKET_LOG(("PollableEvent::Clear EOF!\n")); + return false; + } + if (status > 1) { + MOZ_ASSERT(false); + SOCKET_LOG(("PollableEvent::Clear Unexpected events\n")); + Clear(); + return true; + } + PRErrorCode code = PR_GetError(); + if (code == PR_WOULD_BLOCK_ERROR) { + return true; + } + SOCKET_LOG(("PollableEvent::Clear unexpected error %d\n", code)); + return false; +} + +} // namespace net +} // namespace mozilla diff -Nru firefox-47.0~b1+build1/netwerk/base/PollableEvent.h firefox-47.0~b2+build1/netwerk/base/PollableEvent.h --- firefox-47.0~b1+build1/netwerk/base/PollableEvent.h 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/netwerk/base/PollableEvent.h 2016-05-03 05:14:20.000000000 +0000 @@ -0,0 +1,38 @@ +/* -*- 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/. */ + +#ifndef PollableEvent_h__ +#define PollableEvent_h__ + +#include "mozilla/Mutex.h" + +namespace mozilla { +namespace net { + +// class must be called locked +class PollableEvent +{ +public: + PollableEvent(); + ~PollableEvent(); + + // Signal/Clear return false only if they fail + bool Signal(); + bool Clear(); + bool Valid() { return mWriteFD && mReadFD; } + + PRFileDesc *PollableFD() { return mReadFD; } + +private: + PRFileDesc *mWriteFD; + PRFileDesc *mReadFD; + bool mSignaled; +}; + +} // namespace net +} // namespace mozilla + +#endif diff -Nru firefox-47.0~b1+build1/netwerk/protocol/http/HttpChannelChild.cpp firefox-47.0~b2+build1/netwerk/protocol/http/HttpChannelChild.cpp --- firefox-47.0~b1+build1/netwerk/protocol/http/HttpChannelChild.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/netwerk/protocol/http/HttpChannelChild.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -1271,14 +1271,8 @@ if (NS_SUCCEEDED(rv)) { if (mRedirectChannelChild) { mRedirectChannelChild->ConnectParent(newChannelId); - rv = gHttpHandler->AsyncOnChannelRedirect(this, - newChannel, - redirectFlags); - } else { - LOG((" redirecting to a protocol that doesn't implement" - " nsIChildChannel")); - rv = NS_ERROR_FAILURE; } + rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, redirectFlags); } if (NS_FAILED(rv)) @@ -1539,6 +1533,17 @@ nsCOMPtr newHttpChannel = do_QueryInterface(mRedirectChannelChild); + if (NS_SUCCEEDED(result) && !mRedirectChannelChild) { + // mRedirectChannelChild doesn't exist means we're redirecting to a protocol + // that doesn't implement nsIChildChannel. The redirect result should be set + // as failed by veto listeners and shouldn't enter this condition. As the + // last resort, we synthesize the error result as NS_ERROR_DOM_BAD_URI here + // to let nsHttpChannel::ContinueProcessResponse2 know it's redirecting to + // another protocol and throw an error. + LOG((" redirecting to a protocol that doesn't implement nsIChildChannel")); + result = NS_ERROR_DOM_BAD_URI; + } + if (newHttpChannel) { // Must not be called until after redirect observers called. newHttpChannel->SetOriginalURI(mOriginalURI); diff -Nru firefox-47.0~b1+build1/netwerk/protocol/http/SpdySession31.cpp firefox-47.0~b2+build1/netwerk/protocol/http/SpdySession31.cpp --- firefox-47.0~b1+build1/netwerk/protocol/http/SpdySession31.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/netwerk/protocol/http/SpdySession31.cpp 2016-05-03 05:14:21.000000000 +0000 @@ -2111,6 +2111,8 @@ MOZ_ASSERT(!mNeedsCleanup, "cleanup stream set unexpectedly"); mNeedsCleanup = nullptr; /* just in case */ + // The writesegments() stack can clear mInputFrameDataStream so + // only reference this local copy of it afterwards SpdyStream31 *stream = mInputFrameDataStream; mSegmentWriter = writer; rv = mInputFrameDataStream->WriteSegments(this, count, countWritten); @@ -2119,7 +2121,7 @@ LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X " "stream channel pipe full\n", this, stream, stream ? stream->StreamID() : 0)); - channelPipeFull = mInputFrameDataStream->ChannelPipeFull(); + channelPipeFull = stream->ChannelPipeFull(); } mSegmentWriter = nullptr; diff -Nru firefox-47.0~b1+build1/netwerk/standalone/moz.build firefox-47.0~b2+build1/netwerk/standalone/moz.build --- firefox-47.0~b1+build1/netwerk/standalone/moz.build 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/netwerk/standalone/moz.build 2016-05-03 05:14:21.000000000 +0000 @@ -12,6 +12,7 @@ ] netwerk_base_src = [ + 'PollableEvent.cpp', 'nsDNSPrefetch.cpp', 'nsNetAddr.cpp', 'nsSocketTransportService2.cpp', diff -Nru firefox-47.0~b1+build1/release/docker/funsize-update-generator/scripts/funsize.py firefox-47.0~b2+build1/release/docker/funsize-update-generator/scripts/funsize.py --- firefox-47.0~b1+build1/release/docker/funsize-update-generator/scripts/funsize.py 2016-04-26 07:45:17.000000000 +0000 +++ firefox-47.0~b2+build1/release/docker/funsize-update-generator/scripts/funsize.py 2016-05-03 05:14:22.000000000 +0000 @@ -238,6 +238,9 @@ "platform": e["platform"], "locale": e["locale"], } + # Override ACCEPTED_MAR_CHANNEL_IDS if needed + if "ACCEPTED_MAR_CHANNEL_IDS" in os.environ: + mar_data["ACCEPTED_MAR_CHANNEL_IDS"] = os.environ["ACCEPTED_MAR_CHANNEL_IDS"] for field in ("update_number", "previousVersion", "previousBuildNumber", "toVersion", "toBuildNumber"): diff -Nru firefox-47.0~b1+build1/security/apps/AppSignatureVerification.cpp firefox-47.0~b2+build1/security/apps/AppSignatureVerification.cpp --- firefox-47.0~b1+build1/security/apps/AppSignatureVerification.cpp 2016-04-26 07:45:09.000000000 +0000 +++ firefox-47.0~b2+build1/security/apps/AppSignatureVerification.cpp 2016-05-03 05:14:22.000000000 +0000 @@ -650,6 +650,27 @@ KeyPurposeId::id_kp_codeSigning, CertPolicyId::anyPolicy, nullptr/*stapledOCSPResponse*/); + if (rv == Result::ERROR_EXPIRED_CERTIFICATE) { + // For code-signing you normally need trusted 3rd-party timestamps to + // handle expiration properly. The signer could always mess with their + // system clock so you can't trust the certificate was un-expired when + // the signing took place. The choice is either to ignore expiration + // or to enforce expiration at time of use. The latter leads to the + // user-hostile result that perfectly good code stops working. + // + // Our package format doesn't support timestamps (nor do we have a + // trusted 3rd party timestamper), but since we sign all of our apps and + // add-ons ourselves we can trust ourselves not to mess with the clock + // on the signing systems. We also have a revocation mechanism if we + // need it. It's OK to ignore cert expiration under these conditions. + // + // This is an invalid approach if + // * we issue certs to let others sign their own packages + // * mozilla::pkix returns "expired" when there are "worse" problems + // with the certificate or chain. + // (see bug 1267318) + rv = Success; + } if (rv != Success) { return mozilla::psm::GetXPCOMFromNSSError(MapResultToPRErrorCode(rv)); } diff -Nru firefox-47.0~b1+build1/services/sync/modules/engines/clients.js firefox-47.0~b2+build1/services/sync/modules/engines/clients.js --- firefox-47.0~b1+build1/services/sync/modules/engines/clients.js 2016-04-26 07:45:01.000000000 +0000 +++ firefox-47.0~b2+build1/services/sync/modules/engines/clients.js 2016-05-03 05:14:12.000000000 +0000 @@ -121,11 +121,19 @@ }, get localName() { - return this.localName = Utils.getDeviceName(); + let name = Utils.getDeviceName(); + // If `getDeviceName` returns the default name, set the pref. FxA registers + // the device before syncing, so we don't need to update the registration + // in this case. + Svc.Prefs.set("client.name", name); + return name; }, set localName(value) { Svc.Prefs.set("client.name", value); - fxAccounts.updateDeviceRegistration(); + // Update the registration in the background. + fxAccounts.updateDeviceRegistration().catch(error => { + this._log.warn("failed to update fxa device registration", error); + }); }, get localType() { diff -Nru firefox-47.0~b1+build1/SOURCE_CHANGESET firefox-47.0~b2+build1/SOURCE_CHANGESET --- firefox-47.0~b1+build1/SOURCE_CHANGESET 2016-04-26 07:45:17.000000000 +0000 +++ firefox-47.0~b2+build1/SOURCE_CHANGESET 2016-05-03 05:14:28.000000000 +0000 @@ -1 +1 @@ -dcaf0a6fa115ad73bf7505a8e76464250b971a04 \ No newline at end of file +6f82d30fe05e1412e744cb76af86f0c9ffe509d4 \ No newline at end of file diff -Nru firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/en_us.yml.tmpl firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/en_us.yml.tmpl --- firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/en_us.yml.tmpl 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/en_us.yml.tmpl 2016-05-03 05:14:13.000000000 +0000 @@ -10,141 +10,144 @@ {{ locale }}: complete_mar: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar checksum: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums checksum_sig: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums.asc - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums.asc + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums.asc buildinfo: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.json - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.json mozinfo: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.mozinfo.json - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.mozinfo.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.mozinfo.json socorroinfo: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.txt - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.txt + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.txt jsshell: artifact: {{ artifact_base_url }}/jsshell-{{ platform }}.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/jsshell-{{ platform }}.zip + s3_key: {{ s3_prefix }}jsshell-{{ platform }}.zip mozharness_package: artifact: {{ artifact_base_url }}/mozharness.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/mozharness.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/mozharness.zip + xpi: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi + s3_key: {{ s3_prefix }}{{ platform }}/xpi/{{ locale }}.xpi {% if platform == "win32" %} full_installer: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe stub_installer: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer-stub.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup Stub {{ version }}.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup Stub {{ version }}.exe package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip buildid_info: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}_info.txt - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/win32_info.txt + s3_key: {{ s3_prefix }}win32_info.txt sdk: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.sdk.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/firefox-{{ version }}.{{ platform }}.sdk.zip + s3_key: {{ s3_prefix }}firefox-{{ version }}.{{ platform }}.sdk.zip mar_tools_mar: artifact: {{ artifact_base_url }}/mar.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/win32/mar.exe + s3_key: {{ s3_prefix }}mar-tools/win32/mar.exe mar_tools_mbdiff: artifact: {{ artifact_base_url }}/mbsdiff.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/win32/mbsdiff.exe + s3_key: {{ s3_prefix }}mar-tools/win32/mbsdiff.exe {% endif %} {% if platform == "win64" %} full_installer: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip buildid_info: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}_info.txt - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/win64_info.txt + s3_key: {{ s3_prefix }}win64_info.txt sdk: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.sdk.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/firefox-{{ version }}.{{ platform }}.sdk.zip + s3_key: {{ s3_prefix }}firefox-{{ version }}.{{ platform }}.sdk.zip mar_tools_mar: artifact: {{ artifact_base_url }}/mar.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/win64/mar.exe + s3_key: {{ s3_prefix }}mar-tools/win64/mar.exe mar_tools_mbdiff: artifact: {{ artifact_base_url }}/mbsdiff.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/win64/mbsdiff.exe + s3_key: {{ s3_prefix }}mar-tools/win64/mbsdiff.exe {% endif %} {% if platform == "linux-i686" %} package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip buildid_info: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}_info.txt - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/linux_info.txt + s3_key: {{ s3_prefix }}linux_info.txt sdk: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.sdk.tar.bz2 - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/firefox-{{ version }}.{{ platform }}.sdk.tar.bz2 + s3_key: {{ s3_prefix }}firefox-{{ version }}.{{ platform }}.sdk.tar.bz2 mar_tools_mar: artifact: {{ artifact_base_url }}/mar - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/linux/mar + s3_key: {{ s3_prefix }}mar-tools/linux/mar mar_tools_mbdiff: artifact: {{ artifact_base_url }}/mbsdiff - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/linux/mbsdiff + s3_key: {{ s3_prefix }}mar-tools/linux/mbsdiff {% endif %} {% if platform == "linux-x86_64" %} package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip buildid_info: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}_info.txt - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/linux64_info.txt + s3_key: {{ s3_prefix }}linux64_info.txt sdk: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.sdk.tar.bz2 - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/firefox-{{ version }}.{{ platform }}.sdk.tar.bz2 + s3_key: {{ s3_prefix }}firefox-{{ version }}.{{ platform }}.sdk.tar.bz2 mar_tools_mar: artifact: {{ artifact_base_url }}/mar - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/linux64/mar + s3_key: {{ s3_prefix }}mar-tools/linux64/mar mar_tools_mbdiff: artifact: {{ artifact_base_url }}/mbsdiff - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/linux64/mbsdiff + s3_key: {{ s3_prefix }}mar-tools/linux64/mbsdiff {% endif %} {% if platform == "mac" %} package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.dmg - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox {{ version }}.dmg + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox {{ version }}.dmg symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox {{ version }}.crashreporter-symbols.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox {{ version }}.crashreporter-symbols.zip buildid_info: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}_info.txt - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/macosx64_info.txt + s3_key: {{ s3_prefix }}macosx64_info.txt sdk: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}-x86_64.sdk.tar.bz2 - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/firefox-{{ version }}.{{ platform }}-x86_64.sdk.tar.bz2 + s3_key: {{ s3_prefix }}firefox-{{ version }}.{{ platform }}-x86_64.sdk.tar.bz2 mar_tools_mar: artifact: {{ artifact_base_url }}/mar - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/macosx64/mar + s3_key: {{ s3_prefix }}mar-tools/macosx64/mar mar_tools_mbdiff: artifact: {{ artifact_base_url }}/mbsdiff - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/mar-tools/macosx64/mbsdiff + s3_key: {{ s3_prefix }}mar-tools/macosx64/mbsdiff {% endif %} {% endfor %} diff -Nru firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/l10n_changesets.tmpl firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/l10n_changesets.tmpl --- firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/l10n_changesets.tmpl 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/l10n_changesets.tmpl 2016-05-03 05:14:13.000000000 +0000 @@ -8,4 +8,4 @@ all: l10n_changesets: artifact: {{ artifact_base_url }}/l10n_changesets.txt - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/l10n_changesets.txt + s3_key: {{ s3_prefix }}l10n_changesets.txt diff -Nru firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/partials.yml.tmpl firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/partials.yml.tmpl --- firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/partials.yml.tmpl 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/partials.yml.tmpl 2016-05-03 05:14:13.000000000 +0000 @@ -9,8 +9,8 @@ {{ locale }}: partial_mar: artifact: {{ artifact_base_url }}/firefox-{{ partial_version }}-{{ version }}.{{ locale }}.{{ platform }}.partial.mar - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/update/{{ platform }}/{{ locale }}/firefox-{{ partial_version }}-{{ version }}.partial.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ partial_version }}-{{ version }}.partial.mar partial_mar_sig: artifact: {{ artifact_base_url }}/firefox-{{ partial_version }}-{{ version }}.{{ locale }}.{{ platform }}.partial.mar.asc - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/update/{{ platform }}/{{ locale }}/firefox-{{ partial_version }}-{{ version }}.partial.mar.asc + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ partial_version }}-{{ version }}.partial.mar.asc {% endfor %} diff -Nru firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/repacks.yml.tmpl firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/repacks.yml.tmpl --- firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/repacks.yml.tmpl 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/repacks.yml.tmpl 2016-05-03 05:14:13.000000000 +0000 @@ -10,54 +10,54 @@ {{ locale }}: complete_mar: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar checksum: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums checksum_sig: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums.asc - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums.asc + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums.asc xpi: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/xpi/{{ locale }}.xpi + s3_key: {{ s3_prefix }}{{ platform }}/xpi/{{ locale }}.xpi {% if platform == "win32" %} full_installer: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe stub_installer: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer-stub.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup Stub {{ version }}.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup Stub {{ version }}.exe package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip {% endif %} {% if platform == "win64" %} full_installer: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip {% endif %} {% if platform == "linux-i686" %} package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 {% endif %} {% if platform == "linux-x86_64" %} package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 {% endif %} {% if platform == "mac" %} package: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.dmg - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox {{ version }}.dmg + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox {{ version }}.dmg {% endif %} {% endfor %} diff -Nru firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/source_checksums.yml.tmpl firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/source_checksums.yml.tmpl --- firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/source_checksums.yml.tmpl 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/source_checksums.yml.tmpl 2016-05-03 05:14:13.000000000 +0000 @@ -8,7 +8,7 @@ all: source_checksum: artifact: {{ artifact_base_url }}/firefox-{{ version }}.source.checksums - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/source/firefox-{{ version }}.source.checksums + s3_key: {{ s3_prefix }}source/firefox-{{ version }}.source.checksums source_checksum_asc: artifact: {{ artifact_base_url }}/firefox-{{ version }}.source.checksums.asc - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/source/firefox-{{ version }}.source.checksums.asc + s3_key: {{ s3_prefix }}source/firefox-{{ version }}.source.checksums.asc diff -Nru firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/source.yml.tmpl firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/source.yml.tmpl --- firefox-47.0~b1+build1/testing/mozharness/configs/beetmover/source.yml.tmpl 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/configs/beetmover/source.yml.tmpl 2016-05-03 05:14:13.000000000 +0000 @@ -8,7 +8,7 @@ all: source_bundle: artifact: {{ artifact_base_url }}/firefox-{{ version }}.bundle - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/source/firefox-{{ version }}.bundle + s3_key: {{ s3_prefix }}source/firefox-{{ version }}.bundle source_tar: artifact: {{ artifact_base_url }}/firefox-{{ version }}.source.tar.xz - s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/source/firefox-{{ version }}.source.tar.xz + s3_key: {{ s3_prefix }}source/firefox-{{ version }}.source.tar.xz diff -Nru firefox-47.0~b1+build1/testing/mozharness/configs/releases/bouncer_firefox_beta.py firefox-47.0~b2+build1/testing/mozharness/configs/releases/bouncer_firefox_beta.py --- firefox-47.0~b1+build1/testing/mozharness/configs/releases/bouncer_firefox_beta.py 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/configs/releases/bouncer_firefox_beta.py 2016-05-03 05:14:13.000000000 +0000 @@ -67,10 +67,6 @@ "path": "/firefox/releases/%(version)s/win32/:lang/Firefox%%20Setup%%20Stub%%20%(version)s.exe", "bouncer-platform": "win", }, - "win64": { - "path": "/firefox/releases/%(version)s/win64/:lang/Firefox%%20Setup%%20Stub%%20%(version)s.exe", - "bouncer-platform": "win64", - }, }, }, "complete-mar": { diff -Nru firefox-47.0~b1+build1/testing/mozharness/configs/releases/bouncer_firefox_release.py firefox-47.0~b2+build1/testing/mozharness/configs/releases/bouncer_firefox_release.py --- firefox-47.0~b1+build1/testing/mozharness/configs/releases/bouncer_firefox_release.py 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/configs/releases/bouncer_firefox_release.py 2016-05-03 05:14:13.000000000 +0000 @@ -99,10 +99,6 @@ "path": "/firefox/releases/%(version)s/win32/:lang/Firefox%%20Setup%%20Stub%%20%(version)s.exe", "bouncer-platform": "win", }, - "win64": { - "path": "/firefox/releases/%(version)s/win64/:lang/Firefox%%20Setup%%20Stub%%20%(version)s.exe", - "bouncer-platform": "win64", - }, }, }, "complete-mar": { diff -Nru firefox-47.0~b1+build1/testing/mozharness/configs/releases/dev_bouncer_firefox_beta.py firefox-47.0~b2+build1/testing/mozharness/configs/releases/dev_bouncer_firefox_beta.py --- firefox-47.0~b1+build1/testing/mozharness/configs/releases/dev_bouncer_firefox_beta.py 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/configs/releases/dev_bouncer_firefox_beta.py 2016-05-03 05:14:13.000000000 +0000 @@ -66,10 +66,6 @@ "path": "/firefox/releases/%(version)s/win32/:lang/Firefox%%20Setup%%20Stub%%20%(version)s.exe", "bouncer-platform": "win", }, - "win64": { - "path": "/firefox/releases/%(version)s/win64/:lang/Firefox%%20Setup%%20Stub%%20%(version)s.exe", - "bouncer-platform": "win64", - }, }, }, "complete-mar": { diff -Nru firefox-47.0~b1+build1/testing/mozharness/scripts/release/beet_mover.py firefox-47.0~b2+build1/testing/mozharness/scripts/release/beet_mover.py --- firefox-47.0~b1+build1/testing/mozharness/scripts/release/beet_mover.py 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/scripts/release/beet_mover.py 2016-05-03 05:14:13.000000000 +0000 @@ -176,6 +176,24 @@ } self.log("activated virtualenv with the modules: {}".format(str(self.virtualenv_imports))) + def _get_template_vars(self): + return { + "platform": self.config['platform'], + "locales": self.config.get('locales'), + "version": self.config['version'], + "app_version": self.config.get('app_version', ''), + "partial_version": self.config.get('partial_version', ''), + "build_num": self.config['build_num'], + # keep the trailing slash + "s3_prefix": 'pub/{prod}/candidates/{ver}-candidates/{n}/'.format( + prod=self.config['product'], ver=self.config['version'], + n=self.config['build_num'] + ), + "artifact_base_url": self.config['artifact_base_url'].format( + taskid=self.config['taskid'], subdir=self.config['artifact_subdir'] + ) + } + def generate_candidates_manifest(self): """ generates and outputs a manifest that maps expected Taskcluster artifact names @@ -189,20 +207,7 @@ jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir), undefined=jinja2.StrictUndefined) template = jinja_env.get_template(template_file) - template_vars = { - "platform": self.config['platform'], - "locales": self.config.get('locales'), - "version": self.config['version'], - "app_version": self.config.get('app_version', ''), - "partial_version": self.config.get('partial_version', ''), - "build_num": self.config['build_num'], - # mirror current release folder structure - "s3_prefix": 'pub/{}/candidates'.format(self.config['product']), - "artifact_base_url": self.config['artifact_base_url'].format( - taskid=self.config['taskid'], subdir=self.config['artifact_subdir'] - ) - } - self.manifest = yaml.safe_load(template.render(**template_vars)) + self.manifest = yaml.safe_load(template.render(**self._get_template_vars())) self.log("manifest generated:") self.log(pprint.pformat(self.manifest['mapping'])) @@ -215,34 +220,38 @@ self.log('skipping verification. unimplemented...') def refresh_antivirus(self): - self.info("Refreshing clamav db...") - try: - redo.retry(lambda: - sh.freshclam("--stdout", "--verbose", _timeout=300, _err_to_out=True)) - self.info("Done.") - except sh.ErrorReturnCode: - self.warning("Freshclam failed, skipping DB update") + self.info("Refreshing clamav db...") + try: + redo.retry(lambda: + sh.freshclam("--stdout", "--verbose", _timeout=300, + _err_to_out=True)) + self.info("Done.") + except sh.ErrorReturnCode: + self.warning("Freshclam failed, skipping DB update") def download_bits(self): """ downloads list of artifacts to self.dest_dir dir based on a given manifest """ self.log('downloading and uploading artifacts to self_dest_dir...') - - # TODO - do we want to mirror/upload to more than one region? dirs = self.query_abs_dirs() for locale in self.manifest['mapping']: for deliverable in self.manifest['mapping'][locale]: self.log("downloading '{}' deliverable for '{}' locale".format(deliverable, locale)) - # download locally to working dir - source=self.manifest['mapping'][locale][deliverable]['artifact'] - file_name = self.retry(self.download_file, + source = self.manifest['mapping'][locale][deliverable]['artifact'] + self.retry( + self.download_file, args=[source], kwargs={'parent_dir': dirs['abs_work_dir']}, error_level=FATAL) self.log('Success!') + def _strip_prefix(self, s3_key): + """Return file name relative to prefix""" + # "abc/def/hfg".split("abc/de")[-1] == "f/hfg" + return s3_key.split(self._get_template_vars()["s3_prefix"])[-1] + def upload_bits(self): """ uploads list of artifacts to s3 candidates dir based on a given manifest @@ -255,29 +264,34 @@ conn = boto.connect_s3(self.aws_key_id, self.aws_secret_key) bucket = conn.get_bucket(self.bucket) - #todo change so this is not every entry in manifest - should exclude those that don't pass virus sign - #not sure how to determine this for locale in self.manifest['mapping']: for deliverable in self.manifest['mapping'][locale]: self.log("uploading '{}' deliverable for '{}' locale".format(deliverable, locale)) - #we have already downloaded the files locally so we can use that version + # we have already downloaded the files locally so we can use that version source = self.manifest['mapping'][locale][deliverable]['artifact'] + s3_key = self.manifest['mapping'][locale][deliverable]['s3_key'] downloaded_file = os.path.join(dirs['abs_work_dir'], self.get_filename_from_url(source)) - self.upload_bit( - source=downloaded_file, - s3_key=self.manifest['mapping'][locale][deliverable]['s3_key'], - bucket=bucket, + # generate checksums for every uploaded file + beet_file_name = '{}.beet'.format(downloaded_file) + # upload checksums to a separate subdirectory + beet_dest = '{prefix}beetmover-checksums/{f}.beet'.format( + prefix=self._get_template_vars()["s3_prefix"], + f=self._strip_prefix(s3_key) ) + beet_contents = '{hash} sha512 {size} {name}\n'.format( + hash=self.file_sha512sum(downloaded_file), + size=os.path.getsize(downloaded_file), + name=self._strip_prefix(s3_key)) + self.write_to_file(beet_file_name, beet_contents) + self.upload_bit(source=downloaded_file, s3_key=s3_key, + bucket=bucket) + self.upload_bit(source=beet_file_name, s3_key=beet_dest, + bucket=bucket) self.log('Success!') def upload_bit(self, source, s3_key, bucket): - # TODO - do we want to mirror/upload to more than one region? - dirs = self.query_abs_dirs() boto = self.virtualenv_imports['boto'] - - #todo need to copy from dir to s3 - self.info('uploading to s3 with key: {}'.format(s3_key)) key = boto.s3.key.Key(bucket) # create new key key.key = s3_key # set key name diff -Nru firefox-47.0~b1+build1/testing/mozharness/scripts/release/generate-checksums.py firefox-47.0~b2+build1/testing/mozharness/scripts/release/generate-checksums.py --- firefox-47.0~b1+build1/testing/mozharness/scripts/release/generate-checksums.py 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/scripts/release/generate-checksums.py 2016-05-03 05:14:13.000000000 +0000 @@ -123,13 +123,13 @@ if not self.config.get("includes"): self.config["includes"] = [ - "^.*\.tar\.bz2$", - "^.*\.tar\.xz$", - "^.*\.dmg$", - "^.*\.bundle$", - "^.*\.mar$", - "^.*Setup.*\.exe$", - "^.*\.xpi$", + r"^.*\.tar\.bz2$", + r"^.*\.tar\.xz$", + r"^.*\.dmg$", + r"^.*\.bundle$", + r"^.*\.mar$", + r"^.*Setup.*\.exe$", + r"^.*\.xpi$", ] def _get_bucket_name(self): @@ -144,7 +144,7 @@ return "{}-{}".format(self.config["bucket_name_prefix"], suffix) def _get_file_prefix(self): - return "pub/{}/candidates/{}-candidates/build{}".format( + return "pub/{}/candidates/{}-candidates/build{}/".format( self.config["stage_product"], self.config["version"], self.config["build_number"] ) @@ -181,12 +181,22 @@ def find_checksums_files(): self.info("Getting key names from bucket") + checksum_files = {"beets": [], "checksums": []} for key in bucket.list(prefix=self.file_prefix): if key.key.endswith(".checksums"): self.debug("Found checksums file: {}".format(key.key)) - yield key.key + checksum_files["checksums"].append(key.key) + elif key.key.endswith(".beet"): + self.debug("Found beet file: {}".format(key.key)) + checksum_files["beets"].append(key.key) else: self.debug("Ignoring non-checksums file: {}".format(key.key)) + if checksum_files["beets"]: + self.log("Using beet format") + return checksum_files["beets"] + else: + self.log("Using checksums format") + return checksum_files["checksums"] pool = ThreadPool(self.config["parallelization"]) pool.map(worker, find_checksums_files()) diff -Nru firefox-47.0~b1+build1/testing/mozharness/scripts/release/push-candidate-to-releases.py firefox-47.0~b2+build1/testing/mozharness/scripts/release/push-candidate-to-releases.py --- firefox-47.0~b1+build1/testing/mozharness/scripts/release/push-candidate-to-releases.py 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/mozharness/scripts/release/push-candidate-to-releases.py 2016-05-03 05:14:13.000000000 +0000 @@ -106,7 +106,8 @@ r"^.*/mar-tools/.*$", r"^.*gecko-unsigned-unaligned.apk$", r"^.*robocop.apk$", - r"^.*contrib.*" + r"^.*contrib.*", + r"^.*/beetmover-checksums/.*$", ] def _get_candidates_prefix(self): diff -Nru firefox-47.0~b1+build1/testing/web-platform/meta/XMLHttpRequest/send-redirect-bogus.htm.ini firefox-47.0~b2+build1/testing/web-platform/meta/XMLHttpRequest/send-redirect-bogus.htm.ini --- firefox-47.0~b1+build1/testing/web-platform/meta/XMLHttpRequest/send-redirect-bogus.htm.ini 2016-04-26 07:45:02.000000000 +0000 +++ firefox-47.0~b2+build1/testing/web-platform/meta/XMLHttpRequest/send-redirect-bogus.htm.ini 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -[send-redirect-bogus.htm] - type: testharness - [XMLHttpRequest: send() - Redirects (bogus Location header) (302: mailto:someone@example.org)] - expected: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.2") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "linux") and (version == "Ubuntu 12.04") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.2") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL - if debug and e10s and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - - \ No newline at end of file diff -Nru firefox-47.0~b1+build1/testing/web-platform/mozilla/meta/MANIFEST.json firefox-47.0~b2+build1/testing/web-platform/mozilla/meta/MANIFEST.json --- firefox-47.0~b1+build1/testing/web-platform/mozilla/meta/MANIFEST.json 2016-04-26 07:45:03.000000000 +0000 +++ firefox-47.0~b2+build1/testing/web-platform/mozilla/meta/MANIFEST.json 2016-05-03 05:14:14.000000000 +0000 @@ -569,6 +569,12 @@ "url": "/_mozilla/service-workers/service-worker/update-after-oneday.https.html" } ], + "service-workers/service-worker/update-recovery.https.html": [ + { + "path": "service-workers/service-worker/update-recovery.https.html", + "url": "/_mozilla/service-workers/service-worker/update-recovery.https.html" + } + ], "service-workers/service-worker/update.https.html": [ { "path": "service-workers/service-worker/update.https.html", diff -Nru firefox-47.0~b1+build1/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/update-recovery-worker.py firefox-47.0~b2+build1/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/update-recovery-worker.py --- firefox-47.0~b1+build1/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/update-recovery-worker.py 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/update-recovery-worker.py 2016-05-03 05:14:14.000000000 +0000 @@ -0,0 +1,25 @@ +def main(request, response): + # Set mode to 'init' for initial fetch. + mode = 'init' + if 'update-recovery-mode' in request.cookies: + mode = request.cookies['update-recovery-mode'].value + + # no-cache itself to ensure the user agent finds a new version for each update. + headers = [('Cache-Control', 'no-cache, must-revalidate'), + ('Pragma', 'no-cache')] + + extra_body = '' + + if mode == 'init': + # Install a bad service worker that will break the controlled + # document navigation. + response.set_cookie('update-recovery-mode', 'bad') + extra_body = "addEventListener('fetch', function(e) { e.respondWith(Promise.reject()); });" + elif mode == 'bad': + # When the update tries to pull the script again, update to + # a worker service worker that does not break document + # navigation. Serve the same script from then on. + response.delete_cookie('update-recovery-mode') + + headers.append(('Content-Type', 'application/javascript')) + return headers, '%s' % (extra_body) diff -Nru firefox-47.0~b1+build1/testing/web-platform/mozilla/tests/service-workers/service-worker/update-recovery.https.html firefox-47.0~b2+build1/testing/web-platform/mozilla/tests/service-workers/service-worker/update-recovery.https.html --- firefox-47.0~b1+build1/testing/web-platform/mozilla/tests/service-workers/service-worker/update-recovery.https.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-47.0~b2+build1/testing/web-platform/mozilla/tests/service-workers/service-worker/update-recovery.https.html 2016-05-03 05:14:14.000000000 +0000 @@ -0,0 +1,71 @@ + +Service Worker: recovery by navigation update + + + + + diff -Nru firefox-47.0~b1+build1/toolkit/components/places/History.cpp firefox-47.0~b2+build1/toolkit/components/places/History.cpp --- firefox-47.0~b1+build1/toolkit/components/places/History.cpp 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/toolkit/components/places/History.cpp 2016-05-03 05:14:20.000000000 +0000 @@ -2619,6 +2619,7 @@ History::UnregisterVisitedCallback(nsIURI* aURI, Link* aLink) { + // TODO: aURI is sometimes null - see bug 548685 NS_ASSERTION(aURI, "Must pass a non-null URI!"); NS_ASSERTION(aLink, "Must pass a non-null Link object!"); diff -Nru firefox-47.0~b1+build1/toolkit/components/search/nsSearchService.js firefox-47.0~b2+build1/toolkit/components/search/nsSearchService.js --- firefox-47.0~b1+build1/toolkit/components/search/nsSearchService.js 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/toolkit/components/search/nsSearchService.js 2016-05-03 05:14:21.000000000 +0000 @@ -1140,12 +1140,11 @@ getSubmission: function SRCH_EURL_getSubmission(aSearchTerms, aEngine, aPurpose) { var url = ParamSubstitution(this.template, aSearchTerms, aEngine); - // Default to an empty string if the purpose is not provided so that default purpose params - // (purpose="") work consistently rather than having to define "null" and "" purposes. - var purpose = aPurpose || ""; + // Default to searchbar if the purpose is not provided + var purpose = aPurpose || "searchbar"; - // If the 'system' purpose isn't defined in the plugin, fallback to 'searchbar'. - if (purpose == "system" && !this.params.some(p => p.purpose == "system")) + // If a particular purpose isn't defined in the plugin, fallback to 'searchbar'. + if (!this.params.some(p => p.purpose !== undefined && p.purpose == purpose)) purpose = "searchbar"; // Create an application/x-www-form-urlencoded representation of our params @@ -2832,6 +2831,9 @@ }, _buildCache: function SRCH_SVC__buildCache() { + if (this._batchTask) + this._batchTask.disarm(); + TelemetryStopwatch.start("SEARCH_SERVICE_BUILD_CACHE_MS"); let cache = {}; let locale = getLocale(); diff -Nru firefox-47.0~b1+build1/toolkit/components/search/tests/xpcshell/data/engine.xml firefox-47.0~b2+build1/toolkit/components/search/tests/xpcshell/data/engine.xml --- firefox-47.0~b1+build1/toolkit/components/search/tests/xpcshell/data/engine.xml 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/toolkit/components/search/tests/xpcshell/data/engine.xml 2016-05-03 05:14:21.000000000 +0000 @@ -16,8 +16,8 @@ - - + + diff -Nru firefox-47.0~b1+build1/toolkit/components/search/tests/xpcshell/test_purpose.js firefox-47.0~b2+build1/toolkit/components/search/tests/xpcshell/test_purpose.js --- firefox-47.0~b1+build1/toolkit/components/search/tests/xpcshell/test_purpose.js 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/toolkit/components/search/tests/xpcshell/test_purpose.js 2016-05-03 05:14:21.000000000 +0000 @@ -43,12 +43,13 @@ // Tests for a param that varies with a purpose but has a default value. base = "http://www.google.com/search?q=foo"; - check_submission("&channel=none", "foo", "application/x-moz-default-purpose"); - check_submission("&channel=none", "foo", "application/x-moz-default-purpose", null); - check_submission("&channel=none", "foo", "application/x-moz-default-purpose", ""); + check_submission("&channel=ffsb", "foo", "application/x-moz-default-purpose"); + check_submission("&channel=ffsb", "foo", "application/x-moz-default-purpose", null); + check_submission("&channel=ffsb", "foo", "application/x-moz-default-purpose", ""); check_submission("&channel=rcs", "foo", "application/x-moz-default-purpose", "contextmenu"); check_submission("&channel=fflb", "foo", "application/x-moz-default-purpose", "keyword"); - check_submission("", "foo", "application/x-moz-default-purpose", "invalid"); + check_submission("&channel=ffsb", "foo", "application/x-moz-default-purpose", "searchbar"); + check_submission("&channel=ffsb", "foo", "application/x-moz-default-purpose", "invalid"); // Tests for a purpose on the search form (ie. empty query). engine = Services.search.getEngineByName("engine-rel-searchform-purpose"); diff -Nru firefox-47.0~b1+build1/toolkit/components/telemetry/Histograms.json firefox-47.0~b2+build1/toolkit/components/telemetry/Histograms.json --- firefox-47.0~b1+build1/toolkit/components/telemetry/Histograms.json 2016-04-26 07:45:08.000000000 +0000 +++ firefox-47.0~b2+build1/toolkit/components/telemetry/Histograms.json 2016-05-03 05:14:21.000000000 +0000 @@ -8616,12 +8616,14 @@ "expires_in_version": "never", "kind": "count", "keyed": true, + "releaseChannelCollection": "opt-out", "description": "Counts of plugin/content process abnormal shutdown, whether or not a crash report was available." }, "SUBPROCESS_CRASHES_WITH_DUMP": { "expires_in_version": "never", "kind": "count", "keyed": true, + "releaseChannelCollection": "opt-out", "description": "Counts of plugin and content process crashes which are reported with a crash dump." }, "PROCESS_CRASH_SUBMIT_ATTEMPT": { diff -Nru firefox-47.0~b1+build1/toolkit/modules/AppConstants.jsm firefox-47.0~b2+build1/toolkit/modules/AppConstants.jsm --- firefox-47.0~b1+build1/toolkit/modules/AppConstants.jsm 2016-04-26 07:45:09.000000000 +0000 +++ firefox-47.0~b2+build1/toolkit/modules/AppConstants.jsm 2016-05-03 05:14:22.000000000 +0000 @@ -283,6 +283,20 @@ false, #endif + MOZ_TOOLKIT_SEARCH: +#ifdef MOZ_TOOLKIT_SEARCH + true, +#else + false, +#endif + + MOZ_ENABLE_PROFILER_SPS: +#ifdef MOZ_ENABLE_PROFILER_SPS + true, +#else + false, +#endif + DLL_PREFIX: "@DLL_PREFIX@", DLL_SUFFIX: "@DLL_SUFFIX@", diff -Nru firefox-47.0~b1+build1/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul firefox-47.0~b2+build1/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul --- firefox-47.0~b1+build1/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul 2016-04-26 07:45:09.000000000 +0000 +++ firefox-47.0~b2+build1/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul 2016-05-03 05:14:22.000000000 +0000 @@ -67,21 +67,22 @@ file.append(FILE_UPDATE_ARCHIVE); ok(!file.exists(), file.path + " should not exist"); - let addonPrepDir = Services.dirsvc.get(NS_APP_USER_PROFILE_50_DIR, - Ci.nsILocalFile); - addonPrepDir.append(ADDON_PREP_DIR); - // Not being able to remove the directory used to create the test add-ons - // will not adversely affect subsequent tests so wrap it in a try block and - // don't test whether its removal was successful. - try { - removeDirRecursive(addonPrepDir); - } - catch (e) { - logTestInfo("Unable to remove directory. Path: " + addonPrepDir.path + - ", Exception: " + e); - } - - resetAddons(cleanupRestoreUpdaterBackup); + resetAddons(() => { + let addonPrepDir = Services.dirsvc.get(NS_APP_USER_PROFILE_50_DIR, + Ci.nsILocalFile); + addonPrepDir.append(ADDON_PREP_DIR); + // Not being able to remove the directory used to create the test add-ons + // will not adversely affect subsequent tests so wrap it in a try block and + // don't test whether its removal was successful. + try { + removeDirRecursive(addonPrepDir); + } + catch (e) { + logTestInfo("Unable to remove directory. Path: " + addonPrepDir.path + + ", Exception: " + e); + } + cleanupRestoreUpdaterBackup(); + }); } /** diff -Nru firefox-47.0~b1+build1/toolkit/mozapps/update/tests/chrome/utils.js firefox-47.0~b2+build1/toolkit/mozapps/update/tests/chrome/utils.js --- firefox-47.0~b1+build1/toolkit/mozapps/update/tests/chrome/utils.js 2016-04-26 07:45:09.000000000 +0000 +++ firefox-47.0~b2+build1/toolkit/mozapps/update/tests/chrome/utils.js 2016-05-03 05:14:22.000000000 +0000 @@ -1316,45 +1316,14 @@ Services.prefs.setCharPref(PREF_DISABLEDADDONS, disabledAddons.join(" ")); // Install the test add-ons. - let xpiFiles = getTestAddonXPIFiles(); - let xpiCount = xpiFiles.length; - let installs = []; - xpiFiles.forEach(function(aFile) { - AddonManager.getInstallForFile(aFile, function(aInstall) { - if (!aInstall) { - throw "No AddonInstall created for " + aFile.path; - } - - installs.push(aInstall); - - if (--xpiCount == 0) { - let installCount = installs.length; - let installCompleted = function(aInstall) { - aInstall.removeListener(listener); - - if (getAddonTestType(aInstall.addon.name) == "userdisabled") { - aInstall.addon.userDisabled = true; - } - if (--installCount == 0) { - setNoUpdateAddonsDisabledState(); - } - }; - - let listener = { - onDownloadFailed: installCompleted, - onDownloadCancelled: installCompleted, - onInstallFailed: installCompleted, - onInstallCancelled: installCompleted, - onInstallEnded: installCompleted - }; - - installs.forEach(function(aInstall) { - aInstall.addListener(listener); - aInstall.install(); - }); + let promises = getTestAddonXPIFiles().map(function(aFile) { + return AddonManager.installTemporaryAddon(aFile).then(addon => { + if (getAddonTestType(addon.name) == "userdisabled") { + addon.userDisabled = true; } }); }); + return Promise.all(promises).then(setNoUpdateAddonsDisabledState); }); } diff -Nru firefox-47.0~b1+build1/widget/cocoa/nsChildView.mm firefox-47.0~b2+build1/widget/cocoa/nsChildView.mm --- firefox-47.0~b1+build1/widget/cocoa/nsChildView.mm 2016-04-26 07:45:10.000000000 +0000 +++ firefox-47.0~b2+build1/widget/cocoa/nsChildView.mm 2016-05-03 05:14:23.000000000 +0000 @@ -629,6 +629,9 @@ return NS_OK; mOnDestroyCalled = true; + // Stuff below may delete the last ref to this + nsCOMPtr kungFuDeathGrip(this); + [mView widgetDestroyed]; nsBaseWidget::Destroy(); diff -Nru firefox-47.0~b1+build1/widget/gtk/nsDragService.cpp firefox-47.0~b2+build1/widget/gtk/nsDragService.cpp --- firefox-47.0~b1+build1/widget/gtk/nsDragService.cpp 2016-04-26 07:45:10.000000000 +0000 +++ firefox-47.0~b2+build1/widget/gtk/nsDragService.cpp 2016-05-03 05:14:23.000000000 +0000 @@ -1666,7 +1666,11 @@ // If a popup is set as the drag image, use its widget. Otherwise, use // the surface that DrawDrag created. - if (mDragPopup) { + // + // XXX: Disable drag popups on GTK 3.19.4 and above: see bug 1264454. + // Fix this once a new GTK version ships that does not destroy our + // widget in gtk_drag_set_icon_widget. + if (mDragPopup && gtk_check_version(3, 19, 4)) { GtkWidget* gtkWidget = nullptr; nsIFrame* frame = mDragPopup->GetPrimaryFrame(); if (frame) { diff -Nru firefox-47.0~b1+build1/widget/nsBaseWidget.cpp firefox-47.0~b2+build1/widget/nsBaseWidget.cpp --- firefox-47.0~b1+build1/widget/nsBaseWidget.cpp 2016-04-26 07:45:10.000000000 +0000 +++ firefox-47.0~b2+build1/widget/nsBaseWidget.cpp 2016-05-03 05:14:23.000000000 +0000 @@ -975,10 +975,10 @@ aInputBlockId, aFlags)); }; - RefPtr controller = CreateRootContentController(); - if (controller) { + mRootContentController = CreateRootContentController(); + if (mRootContentController) { uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId(); - CompositorParent::SetControllerForLayerTree(rootLayerTreeId, controller); + CompositorParent::SetControllerForLayerTree(rootLayerTreeId, mRootContentController); } // When APZ is enabled, we can actually enable raw touch events because we @@ -1299,6 +1299,11 @@ if (!success || !lf) { NS_WARNING("Failed to create an OMT compositor."); + mAPZC = nullptr; + if (mRootContentController) { + mRootContentController->Destroy(); + mRootContentController = nullptr; + } DestroyCompositor(); mLayerManager = nullptr; mCompositorChild = nullptr; @@ -1381,6 +1386,14 @@ // Don't release it until this widget actually released because after this // is called, TextEventDispatcher() may create it again. } + + // If this widget is being destroyed, let the APZ code know to drop references + // to this widget. Callers of this function all should be holding a deathgrip + // on this widget already. + if (mRootContentController) { + mRootContentController->Destroy(); + mRootContentController = nullptr; + } } NS_METHOD nsBaseWidget::SetWindowClass(const nsAString& xulWinType) diff -Nru firefox-47.0~b1+build1/widget/nsBaseWidget.h firefox-47.0~b2+build1/widget/nsBaseWidget.h --- firefox-47.0~b1+build1/widget/nsBaseWidget.h 2016-04-26 07:45:10.000000000 +0000 +++ firefox-47.0~b2+build1/widget/nsBaseWidget.h 2016-05-03 05:14:23.000000000 +0000 @@ -513,6 +513,7 @@ RefPtr mCompositorParent; RefPtr mCompositorVsyncDispatcher; RefPtr mAPZC; + RefPtr mRootContentController; RefPtr mAPZEventState; SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback; RefPtr mShutdownObserver;