diff --git a/addon-sdk/source/lib/sdk/ui/button/view.js b/addon-sdk/source/lib/sdk/ui/button/view.js index 02731a15d86..63b7aea31b8 100644 --- a/addon-sdk/source/lib/sdk/ui/button/view.js +++ b/addon-sdk/source/lib/sdk/ui/button/view.js @@ -142,7 +142,7 @@ function create(options) { node.setAttribute('label', label); node.setAttribute('tooltiptext', label); node.setAttribute('image', image); - node.setAttribute('sdk-button', 'true'); + node.setAttribute('constrain-size', 'true'); views.set(id, { area: this.currentArea, diff --git a/addon-sdk/source/test/test-sandbox.js b/addon-sdk/source/test/test-sandbox.js index ad342b8c5ca..ed4bb328fc6 100644 --- a/addon-sdk/source/test/test-sandbox.js +++ b/addon-sdk/source/test/test-sandbox.js @@ -57,7 +57,7 @@ exports['test exceptions'] = function(assert) { } + '();'); } catch (error) { - assert.equal(error.fileName, '', 'no fileName reported'); + assert.equal(error.fileName, '[System Principal]', 'No specific fileName reported'); assert.equal(error.lineNumber, 3, 'reports correct line number'); } diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 5d82f965685..1e50839ce81 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,9 +15,9 @@ - + - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index e3de5923517..da57a75cf09 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,8 +19,8 @@ - - + + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 4b0d8a2b195..581bcce6808 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,8 +17,8 @@ - - + + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 8da20ba9b18..8e75a513b1e 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,9 +15,9 @@ - + - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index d876e8bb85e..7214d561a38 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,9 +15,9 @@ - + - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index e3de5923517..da57a75cf09 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,8 +19,8 @@ - - + + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index c9e2f85dbfe..8e74f1047f7 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,9 +15,9 @@ - + - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 5eef347c9af..0d9e03a0a23 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,8 +17,8 @@ - - + + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index e4b9054bb29..7da0c765356 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "8e28588496f82f8f069c171c65842d622b9d8d7d", + "git_revision": "2dd89fef4fae4d86fd313037ef384086c2e0e8a5", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "ff36a42838b338d750be214ac110c5cc4369b180", + "revision": "9b4f4ec031e567ece9b707841fa50d27d346cd83", "repo_path": "integration/gaia-central" } diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 73fe6461967..3c18efe2317 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,8 +17,8 @@ - - + + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 9b4a2d89047..378d922daf7 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,9 +15,9 @@ - + - + diff --git a/browser/base/content/browser-readinglist.js b/browser/base/content/browser-readinglist.js index e41be1f6e90..7b846bf9142 100644 --- a/browser/base/content/browser-readinglist.js +++ b/browser/base/content/browser-readinglist.js @@ -252,7 +252,7 @@ let ReadingListUI = { if (this.enabled && state == "valid") { uri = gBrowser.currentURI; if (uri.schemeIs("about")) - uri = ReaderParent.parseReaderUrl(uri.spec); + uri = ReaderMode.getOriginalUrl(uri.spec); else if (!uri.schemeIs("http") && !uri.schemeIs("https")) uri = null; } @@ -309,7 +309,7 @@ let ReadingListUI = { togglePageByBrowser: Task.async(function* (browser) { let uri = browser.currentURI; if (uri.spec.startsWith("about:reader?")) - uri = ReaderParent.parseReaderUrl(uri.spec); + uri = ReaderMode.getOriginalUrl(uri.spec); if (!uri) return; @@ -330,7 +330,7 @@ let ReadingListUI = { isItemForCurrentBrowser(item) { let currentURL = gBrowser.currentURI.spec; if (currentURL.startsWith("about:reader?")) - currentURL = ReaderParent.parseReaderUrl(currentURL); + currentURL = ReaderMode.getOriginalUrl(currentURL); if (item.url == currentURL || item.resolvedURL == currentURL) { return true; diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index f5ccc901379..b1689f76446 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -213,6 +213,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "CastingApps", XPCOMUtils.defineLazyModuleGetter(this, "SimpleServiceDiscovery", "resource://gre/modules/SimpleServiceDiscovery.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", + "resource://gre/modules/ReaderMode.jsm"); + XPCOMUtils.defineLazyModuleGetter(this, "ReaderParent", "resource:///modules/ReaderParent.jsm"); diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 04d385099cb..6f69ada6859 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -578,6 +578,7 @@ nsContextMenu.prototype = { this.linkURI = null; this.linkText = ""; this.linkProtocol = ""; + this.linkDownload = ""; this.linkHasNoReferrer = false; this.onMathML = false; this.inFrame = false; @@ -751,6 +752,14 @@ nsContextMenu.prototype = { this.onMailtoLink = (this.linkProtocol == "mailto"); this.onSaveableLink = this.isLinkSaveable( this.link ); this.linkHasNoReferrer = BrowserUtils.linkHasNoReferrer(elem); + try { + if (elem.download) { + // Ignore download attribute on cross-origin links + this.principal.checkMayLoad(this.linkURI, false, true); + this.linkDownload = elem.download; + } + } + catch (ex) {} } // Background image? Don't bother if we've already found a @@ -1171,7 +1180,8 @@ nsContextMenu.prototype = { // Helper function to wait for appropriate MIME-type headers and // then prompt the user with a file picker - saveHelper: function(linkURL, linkText, dialogTitle, bypassCache, doc) { + saveHelper: function(linkURL, linkText, dialogTitle, bypassCache, doc, + linkDownload) { // canonical def in nsURILoader.h const NS_ERROR_SAVE_LINK_AS_TIMEOUT = 0x805d0020; @@ -1277,6 +1287,8 @@ nsContextMenu.prototype = { null, // aTriggeringPrincipal Ci.nsILoadInfo.SEC_NORMAL, Ci.nsIContentPolicy.TYPE_OTHER); + if (linkDownload) + channel.contentDispositionFilename = linkDownload; if (channel instanceof Ci.nsIPrivateBrowsingChannel) { let docIsPrivate = PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser); channel.setPrivate(docIsPrivate); @@ -1313,7 +1325,8 @@ nsContextMenu.prototype = { // Save URL of clicked-on link. saveLink: function() { urlSecurityCheck(this.linkURL, this.principal); - this.saveHelper(this.linkURL, this.linkText, null, true, this.ownerDoc); + this.saveHelper(this.linkURL, this.linkText, null, true, this.ownerDoc, + this.linkDownload); }, // Backwards-compatibility wrapper @@ -1341,7 +1354,7 @@ nsContextMenu.prototype = { else if (this.onVideo || this.onAudio) { urlSecurityCheck(this.mediaURL, this.principal); var dialogTitle = this.onVideo ? "SaveVideoTitle" : "SaveAudioTitle"; - this.saveHelper(this.mediaURL, null, dialogTitle, false, doc); + this.saveHelper(this.mediaURL, null, dialogTitle, false, doc, ""); } }, diff --git a/browser/base/content/test/general/browser_readerMode.js b/browser/base/content/test/general/browser_readerMode.js index 464fb7ec61e..c8d1cc4b4ef 100644 --- a/browser/base/content/test/general/browser_readerMode.js +++ b/browser/base/content/test/general/browser_readerMode.js @@ -17,7 +17,7 @@ const TEST_PATH = "http://example.com/browser/browser/base/content/test/general/ let readerButton = document.getElementById("reader-mode-button"); -add_task(function* () { +add_task(function* test_reader_button() { registerCleanupFunction(function() { // Reset test prefs. TEST_PREFS.forEach(([name, value]) => { @@ -90,3 +90,16 @@ add_task(function* () { yield promiseWaitForCondition(() => !readerButton.hidden); is_element_visible(readerButton, "Reader mode button is present on a reader-able page"); }); + +add_task(function* test_getOriginalUrl() { + let { ReaderMode } = Cu.import("resource://gre/modules/ReaderMode.jsm", {}); + let url = "http://foo.com/article.html"; + + is(ReaderMode.getOriginalUrl("about:reader?url=" + encodeURIComponent(url)), url, "Found original URL from encoded URL"); + is(ReaderMode.getOriginalUrl("about:reader?foobar"), null, "Did not find original URL from malformed reader URL"); + is(ReaderMode.getOriginalUrl(url), null, "Did not find original URL from non-reader URL"); + + let badUrl = "http://foo.com/?;$%^^"; + is(ReaderMode.getOriginalUrl("about:reader?url=" + encodeURIComponent(badUrl)), badUrl, "Found original URL from encoded malformed URL"); + is(ReaderMode.getOriginalUrl("about:reader?url=" + badUrl), badUrl, "Found original URL from non-encoded malformed URL"); +}); diff --git a/browser/base/content/test/newtab/browser_newtab_block.js b/browser/base/content/test/newtab/browser_newtab_block.js index bcb3d7baf57..9509786feec 100644 --- a/browser/base/content/test/newtab/browser_newtab_block.js +++ b/browser/base/content/test/newtab/browser_newtab_block.js @@ -6,7 +6,21 @@ * as expected. Pinned tabs should not be moved. Gaps will be re-filled * if more sites are available. */ + +gDirectorySource = "data:application/json," + JSON.stringify({ + "suggested": [{ + url: "http://suggested.com/", + imageURI: "data:image/png;base64,helloWORLD3", + title: "title", + type: "affiliate", + frecent_sites: ["example0.com"] + }] +}); + function runTests() { + let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; + NewTabUtils.isTopPlacesSite = (site) => false; + // we remove sites and expect the gaps to be filled as long as there still // are some sites available yield setLinks("0,1,2,3,4,5,6,7,8,9"); @@ -58,4 +72,16 @@ function runTests() { yield blockCell(0); checkGrid("1,2,3,4,5,6,7,9,8p"); + + // Test that blocking the targeted site also removes its associated suggested tile + NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; + yield restore(); + yield setLinks("0,1,2,3,4,5,6,7,8,9"); + yield addNewTabPageTab(); + yield customizeNewTabPage("enhanced"); + checkGrid("http://suggested.com/,0,1,2,3,4,5,6,7,8,9"); + + yield blockCell(1); + yield addNewTabPageTab(); + checkGrid("1,2,3,4,5,6,7,8,9"); } diff --git a/browser/base/content/test/newtab/browser_newtab_enhanced.js b/browser/base/content/test/newtab/browser_newtab_enhanced.js index 619ad8bf21b..a2ff6cd551d 100644 --- a/browser/base/content/test/newtab/browser_newtab_enhanced.js +++ b/browser/base/content/test/newtab/browser_newtab_enhanced.js @@ -109,7 +109,7 @@ function runTests() { // Test that a suggested tile is not enhanced by a directory tile let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; NewTabUtils.isTopPlacesSite = () => true; - yield setLinks("-1"); + yield setLinks("-1,2,3,4,5,6,7,8"); // Test with enhanced = false yield addNewTabPageTab(); @@ -119,7 +119,8 @@ function runTests() { is(enhanced, "", "history link has no enhanced image"); is(title, "site#-1"); - is(getData(1), null, "there is only one link and it's a history link"); + isnot(getData(7), null, "there are 8 history links"); + is(getData(8), null, "there are 8 history links"); // Test with enhanced = true @@ -138,5 +139,5 @@ function runTests() { isnot(enhanced, "", "pinned history link has enhanced image"); is(title, "title"); - is(getData(2), null, "there is only a suggested link followed by an enhanced history link"); + is(getData(9), null, "there is a suggested link followed by an enhanced history link and the remaining history links"); } diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml index 3443ccdcf2c..0a43bab66c9 100644 --- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -168,7 +168,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. } } } else { - let originalUrl = ReaderParent.parseReaderUrl(aValue); + let originalUrl = ReaderMode.getOriginalUrl(aValue); if (originalUrl) { returnValue = originalUrl; } diff --git a/browser/components/preferences/in-content/content.js b/browser/components/preferences/in-content/content.js index f5c9ed80cb7..9845638a708 100644 --- a/browser/components/preferences/in-content/content.js +++ b/browser/components/preferences/in-content/content.js @@ -185,7 +185,7 @@ var gContentPane = { */ configureFonts: function () { - gSubDialog.open("chrome://browser/content/preferences/fonts.xul"); + gSubDialog.open("chrome://browser/content/preferences/fonts.xul", "resizable=no"); }, /** @@ -194,7 +194,7 @@ var gContentPane = { */ configureColors: function () { - gSubDialog.open("chrome://browser/content/preferences/colors.xul"); + gSubDialog.open("chrome://browser/content/preferences/colors.xul", "resizable=no"); }, // LANGUAGES diff --git a/browser/components/preferences/in-content/privacy.js b/browser/components/preferences/in-content/privacy.js index 41e430c960d..97fa72316b4 100644 --- a/browser/components/preferences/in-content/privacy.js +++ b/browser/components/preferences/in-content/privacy.js @@ -511,7 +511,7 @@ var gPrivacyPane = { */ showClearPrivateDataSettings: function () { - gSubDialog.open("chrome://browser/content/preferences/sanitize.xul"); + gSubDialog.open("chrome://browser/content/preferences/sanitize.xul", "resizable=no"); }, diff --git a/browser/components/preferences/in-content/security.js b/browser/components/preferences/in-content/security.js index 2385462710c..fea9f52922a 100644 --- a/browser/components/preferences/in-content/security.js +++ b/browser/components/preferences/in-content/security.js @@ -217,7 +217,7 @@ var gSecurityPane = { changeMasterPassword: function () { gSubDialog.open("chrome://mozapps/content/preferences/changemp.xul", - null, null, this._initMasterPasswordUI.bind(this)); + "resizable=no", null, this._initMasterPasswordUI.bind(this)); }, /** diff --git a/browser/modules/DirectoryLinksProvider.jsm b/browser/modules/DirectoryLinksProvider.jsm index bf483c542e2..ff4c491c95f 100644 --- a/browser/modules/DirectoryLinksProvider.jsm +++ b/browser/modules/DirectoryLinksProvider.jsm @@ -65,6 +65,9 @@ const SUGGESTED_FRECENCY = Infinity; // Default number of times to show a link const DEFAULT_FREQUENCY_CAP = 5; +// The min number of visible (not blocked) history tiles to have before showing suggested tiles +const MIN_VISIBLE_HISTORY_TILES = 8; + // Divide frecency by this amount for pings const PING_SCORE_DIVISOR = 10000; @@ -509,6 +512,7 @@ let DirectoryLinksProvider = { this._lastDownloadMS = 0; NewTabUtils.placesProvider.addObserver(this); + NewTabUtils.links.addObserver(this); return Task.spawn(function() { // get the last modified time of the links file if it exists @@ -563,7 +567,7 @@ let DirectoryLinksProvider = { onLinkChanged: function (aProvider, aLink) { // Make sure NewTabUtils.links handles the notification first. setTimeout(() => { - if (this._handleLinkChanged(aLink)) { + if (this._handleLinkChanged(aLink) || this._shouldUpdateSuggestedTile()) { this._updateSuggestedTile(); } }, 0); @@ -591,6 +595,38 @@ let DirectoryLinksProvider = { } }, + _getCurrentTopSiteCount: function() { + let visibleTopSiteCount = 0; + for (let link of NewTabUtils.links.getLinks().slice(0, MIN_VISIBLE_HISTORY_TILES)) { + if (link && (link.type == "history" || link.type == "enhanced")) { + visibleTopSiteCount++; + } + } + return visibleTopSiteCount; + }, + + _shouldUpdateSuggestedTile: function() { + let sortedLinks = NewTabUtils.getProviderLinks(this); + + let mostFrecentLink = {}; + if (sortedLinks && sortedLinks.length) { + mostFrecentLink = sortedLinks[0] + } + + let currTopSiteCount = this._getCurrentTopSiteCount(); + if ((!mostFrecentLink.targetedSite && currTopSiteCount >= MIN_VISIBLE_HISTORY_TILES) || + (mostFrecentLink.targetedSite && currTopSiteCount < MIN_VISIBLE_HISTORY_TILES)) { + // If mostFrecentLink has a targetedSite then mostFrecentLink is a suggested link. + // If we have enough history links (8+) to show a suggested tile and we are not + // already showing one, then we should update (to *attempt* to add a suggested tile). + // OR if we don't have enough history to show a suggested tile (<8) and we are + // currently showing one, we should update (to remove it). + return true; + } + + return false; + }, + /** * Chooses and returns a suggested tile based on a user's top sites * that we have an available suggested tile for. @@ -620,8 +656,9 @@ let DirectoryLinksProvider = { } } - if (this._topSitesWithSuggestedLinks.size == 0) { - // There are no potential suggested links we can show. + if (this._topSitesWithSuggestedLinks.size == 0 || !this._shouldUpdateSuggestedTile()) { + // There are no potential suggested links we can show or not + // enough history for a suggested tile. return; } diff --git a/browser/modules/ReaderParent.jsm b/browser/modules/ReaderParent.jsm index dd18eb1a904..2068a4ae815 100644 --- a/browser/modules/ReaderParent.jsm +++ b/browser/modules/ReaderParent.jsm @@ -172,7 +172,7 @@ let ReaderParent = { let url = browser.currentURI.spec; if (url.startsWith("about:reader")) { - let originalURL = this._getOriginalUrl(url); + let originalURL = ReaderMode.getOriginalUrl(url); if (!originalURL) { Cu.reportError("Error finding original URL for about:reader URL: " + url); } else { @@ -183,28 +183,6 @@ let ReaderParent = { } }, - parseReaderUrl: function(url) { - if (!url.startsWith("about:reader?")) { - return null; - } - return this._getOriginalUrl(url); - }, - - /** - * Returns original URL from an about:reader URL. - * - * @param url An about:reader URL. - * @return The original URL for the article, or null if we did not find - * a properly formatted about:reader URL. - */ - _getOriginalUrl: function(url) { - let searchParams = new URLSearchParams(url.substring("about:reader?".length)); - if (!searchParams.has("url")) { - return null; - } - return decodeURIComponent(searchParams.get("url")); - }, - /** * Gets an article for a given URL. This method will download and parse a document. * diff --git a/browser/modules/Social.jsm b/browser/modules/Social.jsm index 877db42f5a6..5f807a82a21 100644 --- a/browser/modules/Social.jsm +++ b/browser/modules/Social.jsm @@ -265,18 +265,19 @@ function CreateSocialStatusWidget(aId, aProvider) { CustomizableUI.createWidget({ id: aId, - type: 'custom', + type: "custom", removable: true, defaultArea: CustomizableUI.AREA_NAVBAR, onBuild: function(aDocument) { - let node = aDocument.createElement('toolbarbutton'); + let node = aDocument.createElement("toolbarbutton"); node.id = this.id; - node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional social-status-button badged-button'); + node.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional social-status-button badged-button"); node.style.listStyleImage = "url(" + (aProvider.icon32URL || aProvider.iconURL) + ")"; node.setAttribute("origin", aProvider.origin); node.setAttribute("label", aProvider.name); node.setAttribute("tooltiptext", aProvider.name); node.setAttribute("oncommand", "SocialStatus.showPopup(this);"); + node.setAttribute("constrain-size", "true"); if (PrivateBrowsingUtils.isWindowPrivate(aDocument.defaultView)) node.setAttribute("disabled", "true"); @@ -298,14 +299,15 @@ function CreateSocialMarkWidget(aId, aProvider) { CustomizableUI.createWidget({ id: aId, - type: 'custom', + type: "custom", removable: true, defaultArea: CustomizableUI.AREA_NAVBAR, onBuild: function(aDocument) { - let node = aDocument.createElement('toolbarbutton'); + let node = aDocument.createElement("toolbarbutton"); node.id = this.id; - node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional social-mark-button'); - node.setAttribute('type', "socialmark"); + node.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional social-mark-button"); + node.setAttribute("type", "socialmark"); + node.setAttribute("constrain-size", "true"); node.style.listStyleImage = "url(" + (aProvider.unmarkedIcon || aProvider.icon32URL || aProvider.iconURL) + ")"; node.setAttribute("origin", aProvider.origin); diff --git a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js index 79c7e2b7c31..7faa9d97ac4 100644 --- a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js +++ b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js @@ -223,6 +223,42 @@ function run_test() { }); } +add_task(function test_shouldUpdateSuggestedTile() { + let suggestedLink = { + targetedSite: "somesite.com" + }; + + // DirectoryLinksProvider has no suggested tile and no top sites => no need to update + do_check_eq(DirectoryLinksProvider._getCurrentTopSiteCount(), 0); + isIdentical(NewTabUtils.getProviderLinks(), []); + do_check_eq(DirectoryLinksProvider._shouldUpdateSuggestedTile(), false); + + // DirectoryLinksProvider has a suggested tile and no top sites => need to update + let origGetProviderLinks = NewTabUtils.getProviderLinks; + NewTabUtils.getProviderLinks = (provider) => [suggestedLink]; + + do_check_eq(DirectoryLinksProvider._getCurrentTopSiteCount(), 0); + isIdentical(NewTabUtils.getProviderLinks(), [suggestedLink]); + do_check_eq(DirectoryLinksProvider._shouldUpdateSuggestedTile(), true); + + // DirectoryLinksProvider has a suggested tile and 8 top sites => no need to update + let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; + DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; + + do_check_eq(DirectoryLinksProvider._getCurrentTopSiteCount(), 8); + isIdentical(NewTabUtils.getProviderLinks(), [suggestedLink]); + do_check_eq(DirectoryLinksProvider._shouldUpdateSuggestedTile(), false); + + // DirectoryLinksProvider has no suggested tile and 8 top sites => need to update + NewTabUtils.getProviderLinks = origGetProviderLinks; + do_check_eq(DirectoryLinksProvider._getCurrentTopSiteCount(), 8); + isIdentical(NewTabUtils.getProviderLinks(), []); + do_check_eq(DirectoryLinksProvider._shouldUpdateSuggestedTile(), true); + + // Cleanup + DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; +}); + add_task(function test_updateSuggestedTile() { let topSites = ["site0.com", "1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"]; @@ -246,6 +282,9 @@ add_task(function test_updateSuggestedTile() { return links; } + let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; + DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; + do_check_eq(DirectoryLinksProvider._updateSuggestedTile(), undefined); function TestFirstRun() { @@ -346,6 +385,7 @@ add_task(function test_updateSuggestedTile() { yield promiseCleanDirectoryLinksProvider(); NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; NewTabUtils.getProviderLinks = origGetProviderLinks; + DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; }); add_task(function test_suggestedLinksMap() { @@ -436,6 +476,9 @@ add_task(function test_suggestedAttributes() { let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; NewTabUtils.isTopPlacesSite = () => true; + let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; + DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; + let frecent_sites = ["top.site.com"]; let imageURI = "https://image/"; let title = "the title"; @@ -478,6 +521,7 @@ add_task(function test_suggestedAttributes() { // Cleanup. NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; + DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; gLinks.removeProvider(DirectoryLinksProvider); DirectoryLinksProvider.removeObserver(gLinks); }); @@ -487,6 +531,9 @@ add_task(function test_frequencyCappedSites_views() { let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; NewTabUtils.isTopPlacesSite = () => true; + let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; + DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; + let testUrl = "http://frequency.capped/link"; let targets = ["top.site.com"]; let data = { @@ -548,6 +595,7 @@ add_task(function test_frequencyCappedSites_views() { // Cleanup. NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; + DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; gLinks.removeProvider(DirectoryLinksProvider); DirectoryLinksProvider.removeObserver(gLinks); Services.prefs.setCharPref(kPingUrlPref, kPingUrl); @@ -558,6 +606,9 @@ add_task(function test_frequencyCappedSites_click() { let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; NewTabUtils.isTopPlacesSite = () => true; + let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; + DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; + let testUrl = "http://frequency.capped/link"; let targets = ["top.site.com"]; let data = { @@ -613,6 +664,7 @@ add_task(function test_frequencyCappedSites_click() { // Cleanup. NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; + DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; gLinks.removeProvider(DirectoryLinksProvider); DirectoryLinksProvider.removeObserver(gLinks); Services.prefs.setCharPref(kPingUrlPref, kPingUrl); @@ -1089,6 +1141,8 @@ add_task(function test_DirectoryLinksProvider_getEnhancedLink() { add_task(function test_DirectoryLinksProvider_enhancedURIs() { let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; NewTabUtils.isTopPlacesSite = () => true; + let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; + DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; let data = { "suggested": [ @@ -1129,6 +1183,7 @@ add_task(function test_DirectoryLinksProvider_enhancedURIs() { // Cleanup. NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; + DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; gLinks.removeProvider(DirectoryLinksProvider); }); diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css index c7054267188..f01efae4c38 100644 --- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -595,12 +595,12 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { } /* Help SDK icons fit: */ -toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon, -toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon { +toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon, +toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon { width: 16px; } -:-moz-any(#TabsToolbar, #nav-bar) toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon { +:-moz-any(#TabsToolbar, #nav-bar) toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon { /* XXXgijs box models strike again: this is 16px + 2 * 7px padding + 2 * 1px border (from the rules above) */ width: 32px; } diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css index 1d352b7d69a..5358ce66bcf 100644 --- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -1353,8 +1353,8 @@ toolbar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutto } /* Help SDK icons fit: */ -toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon, -toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon { +toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon, +toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon { width: 16px; } diff --git a/browser/themes/shared/customizableui/panelUIOverlay.inc.css b/browser/themes/shared/customizableui/panelUIOverlay.inc.css index a6612ac3f4e..8148dbb7a4e 100644 --- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css +++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css @@ -300,10 +300,10 @@ toolbarpaletteitem[place="panel"]:not([haswideitem=true]) > .toolbarbutton-1 { } /* Help SDK buttons fit in. */ -toolbarpaletteitem[place="palette"] > toolbarbutton[sdk-button="true"] > .toolbarbutton-icon, -toolbarpaletteitem[place="palette"] > toolbarbutton[sdk-button="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon, -toolbarbutton[sdk-button="true"][cui-areatype="menu-panel"] > .toolbarbutton-icon, -toolbarbutton[sdk-button="true"][cui-areatype="menu-panel"] > .toolbarbutton-badge-container > .toolbarbutton-icon { +toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-icon, +toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon, +toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-icon, +toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-badge-container > .toolbarbutton-icon { height: 32px; width: 32px; } diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index dbe27936365..0263086ad1a 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -733,12 +733,12 @@ toolbarbutton[cui-areatype="toolbar"] > :-moz-any(@nestedButtons@) > .toolbarbut } /* Help SDK icons fit: */ -toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon, -toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon { +toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon, +toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon { width: 16px; } -#nav-bar toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon { +#nav-bar toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon { /* XXXgijs box models strike again: this is 16px + 2 * 7px padding + 2 * 1px border (from the rules above) */ width: 32px; } @@ -1630,13 +1630,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- } -toolbarbutton[type="socialmark"] > .toolbarbutton-icon { - width: auto; - height: auto; - max-width: 32px; - max-height: 24px; -} - /* fixup corners for share panel */ .social-panel > .social-panel-frame { border-radius: inherit; diff --git a/caps/nsPrincipal.cpp b/caps/nsPrincipal.cpp index 4d57071f26a..8c39a0dc578 100644 --- a/caps/nsPrincipal.cpp +++ b/caps/nsPrincipal.cpp @@ -980,8 +980,21 @@ nsExpandedPrincipal::IsOnCSSUnprefixingWhitelist() void nsExpandedPrincipal::GetScriptLocation(nsACString& aStr) { - // Is that a good idea to list it's principals? aStr.Assign(EXPANDED_PRINCIPAL_SPEC); + aStr.AppendLiteral(" ("); + + for (size_t i = 0; i < mPrincipals.Length(); ++i) { + if (i != 0) { + aStr.AppendLiteral(", "); + } + + nsAutoCString spec; + nsJSPrincipals::get(mPrincipals.ElementAt(i))->GetScriptLocation(spec); + + aStr.Append(spec); + + } + aStr.Append(")"); } #ifdef DEBUG diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index 11c1329e6f7..91a31e723db 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -446,6 +446,9 @@ GLContextEGL::ReleaseSurface() { if (mOwnsContext) { mozilla::gl::DestroySurface(mSurface); } + if (mSurface == mSurfaceOverride) { + mSurfaceOverride = EGL_NO_SURFACE; + } mSurface = EGL_NO_SURFACE; } @@ -813,6 +816,41 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget) return glContext.forget(); } +#if defined(ANDROID) +EGLSurface +GLContextProviderEGL::CreateEGLSurface(void* aWindow) +{ + if (!sEGLLibrary.EnsureInitialized()) { + MOZ_CRASH("Failed to load EGL library!\n"); + } + + EGLConfig config; + if (!CreateConfig(&config)) { + MOZ_CRASH("Failed to create EGLConfig!\n"); + } + + MOZ_ASSERT(aWindow); + + EGLSurface surface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, aWindow, 0); + + if (surface == EGL_NO_SURFACE) { + MOZ_CRASH("Failed to create EGLSurface!\n"); + } + + return surface; +} + +void +GLContextProviderEGL::DestroyEGLSurface(EGLSurface surface) +{ + if (!sEGLLibrary.EnsureInitialized()) { + MOZ_CRASH("Failed to load EGL library!\n"); + } + + sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); +} +#endif // defined(ANDROID) + already_AddRefed GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size) { diff --git a/gfx/gl/GLContextProviderImpl.h b/gfx/gl/GLContextProviderImpl.h index 9e87170c823..fa4d253fe22 100644 --- a/gfx/gl/GLContextProviderImpl.h +++ b/gfx/gl/GLContextProviderImpl.h @@ -10,6 +10,9 @@ #ifndef GL_CONTEXT_PROVIDER_NAME #error GL_CONTEXT_PROVIDER_NAME not defined #endif +#if defined(ANDROID) +typedef void* EGLSurface; +#endif // defined(ANDROID) class GL_CONTEXT_PROVIDER_NAME { @@ -76,6 +79,11 @@ public: static already_AddRefed CreateWrappingExisting(void* aContext, void* aSurface); +#if defined(ANDROID) + static EGLSurface CreateEGLSurface(void* aWindow); + static void DestroyEGLSurface(EGLSurface surface); +#endif // defined(ANDROID) + /** * Get a pointer to the global context, creating it if it doesn't exist. */ diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index d634a97834f..7d6a73cffcc 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -55,6 +55,11 @@ #include "nsRegion.h" // for nsIntRegion, etc #ifdef MOZ_WIDGET_ANDROID #include +#include "AndroidBridge.h" +#include "opengl/CompositorOGL.h" +#include "GLContextEGL.h" +#include "GLContextProvider.h" +#include "ScopedGLHelpers.h" #endif #include "GeckoProfiler.h" #include "TextRenderer.h" // for TextRenderer @@ -307,6 +312,9 @@ LayerManagerComposite::EndTransaction(DrawPaintedLayerCallback aCallback, ApplyOcclusionCulling(mRoot, opaque); Render(); +#ifdef MOZ_WIDGET_ANDROID + RenderToPresentationSurface(); +#endif mGeometryChanged = false; } else { // Modified layer tree @@ -769,6 +777,175 @@ LayerManagerComposite::Render() RecordFrame(); } +#ifdef MOZ_WIDGET_ANDROID +class ScopedCompositorProjMatrix { +public: + ScopedCompositorProjMatrix(CompositorOGL* aCompositor, const Matrix4x4& aProjMatrix): + mCompositor(aCompositor), + mOriginalProjMatrix(mCompositor->GetProjMatrix()) + { + mCompositor->SetProjMatrix(aProjMatrix); + } + + ~ScopedCompositorProjMatrix() + { + mCompositor->SetProjMatrix(mOriginalProjMatrix); + } +private: + CompositorOGL* const mCompositor; + const Matrix4x4 mOriginalProjMatrix; +}; + +class ScopedCompostitorSurfaceSize { +public: + ScopedCompostitorSurfaceSize(CompositorOGL* aCompositor, const gfx::IntSize& aSize) : + mCompositor(aCompositor), + mOriginalSize(mCompositor->GetDestinationSurfaceSize()) + { + mCompositor->SetDestinationSurfaceSize(aSize); + } + ~ScopedCompostitorSurfaceSize() + { + mCompositor->SetDestinationSurfaceSize(mOriginalSize); + } +private: + CompositorOGL* const mCompositor; + const gfx::IntSize mOriginalSize; +}; + +class ScopedCompositorRenderOffset { +public: + ScopedCompositorRenderOffset(CompositorOGL* aCompositor, const ScreenPoint& aOffset) : + mCompositor(aCompositor), + mOriginalOffset(mCompositor->GetScreenRenderOffset()) + { + mCompositor->SetScreenRenderOffset(aOffset); + } + ~ScopedCompositorRenderOffset() + { + mCompositor->SetScreenRenderOffset(mOriginalOffset); + } +private: + CompositorOGL* const mCompositor; + const ScreenPoint mOriginalOffset; +}; + +class ScopedContextSurfaceOverride { +public: + ScopedContextSurfaceOverride(GLContextEGL* aContext, void* aSurface) : + mContext(aContext) + { + MOZ_ASSERT(aSurface); + mContext->SetEGLSurfaceOverride(aSurface); + mContext->MakeCurrent(true); + } + ~ScopedContextSurfaceOverride() + { + mContext->SetEGLSurfaceOverride(EGL_NO_SURFACE); + mContext->MakeCurrent(true); + } +private: + GLContextEGL* const mContext; +}; + +void +LayerManagerComposite::RenderToPresentationSurface() +{ + if (!AndroidBridge::Bridge()) { + return; + } + + void* window = AndroidBridge::Bridge()->GetPresentationWindow(); + + if (!window) { + return; + } + + EGLSurface surface = AndroidBridge::Bridge()->GetPresentationSurface(); + + if (!surface) { + //create surface; + surface = GLContextProviderEGL::CreateEGLSurface(window); + if (!surface) { + return; + } + + AndroidBridge::Bridge()->SetPresentationSurface(surface); + } + + CompositorOGL* compositor = static_cast(mCompositor.get()); + GLContext* gl = compositor->gl(); + GLContextEGL* egl = GLContextEGL::Cast(gl); + + if (!egl) { + return; + } + + const IntSize windowSize = AndroidBridge::Bridge()->GetNativeWindowSize(window); + + if ((windowSize.width <= 0) || (windowSize.height <= 0)) { + return; + } + + const int actualWidth = windowSize.width; + const int actualHeight = windowSize.height; + + const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize(); + + const int pageWidth = originalSize.width; + const int pageHeight = originalSize.height; + + float scale = 1.0; + + if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) { + const float scaleWidth = (float)actualWidth / (float)pageWidth; + const float scaleHeight = (float)actualHeight / (float)pageHeight; + scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight; + } + + const gfx::IntSize actualSize(actualWidth, actualHeight); + ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize); + + const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0); + ScopedCompositorRenderOffset overrideRenderOffset(compositor, offset); + ScopedContextSurfaceOverride overrideSurface(egl, surface); + + nsIntRegion invalid; + Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight); + Rect rect, actualBounds; + + mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds); + + // Override the projection matrix since the presentation frame buffer + // is probably not the same size as the device frame buffer. The override + // projection matrix also scales the content to fit into the presentation + // frame buffer. + Matrix viewMatrix; + viewMatrix.PreTranslate(-1.0, 1.0); + viewMatrix.PreScale((2.0f * scale) / (float)actualWidth, (2.0f * scale) / (float)actualHeight); + viewMatrix.PreScale(1.0f, -1.0f); + viewMatrix.PreTranslate((int)((float)offset.x / scale), offset.y); + + Matrix4x4 projMatrix = Matrix4x4::From2D(viewMatrix); + + ScopedCompositorProjMatrix overrideProjMatrix(compositor, projMatrix); + + // The Java side of Fennec sets a scissor rect that accounts for + // chrome such as the URL bar. Override that so that the entire frame buffer + // is cleared. + ScopedScissorRect screen(egl, 0, 0, actualWidth, actualHeight); + egl->fClearColor(0.0, 0.0, 0.0, 0.0); + egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT); + + const nsIntRect clipRect = nsIntRect(0, 0, (int)(scale * pageWidth), actualHeight); + RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect)); + RootLayer()->RenderLayer(clipRect); + + mCompositor->EndFrame(); + mCompositor->SetFBAcquireFence(mRoot); +} +#endif + static void SubtractTransformedRegion(nsIntRegion& aRegion, const nsIntRegion& aRegionToSubtract, diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h index ca5f0712926..34b851079af 100644 --- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -278,6 +278,9 @@ private: * Render the current layer tree to the active target. */ void Render(); +#ifdef MOZ_WIDGET_ANDROID + void RenderToPresentationSurface(); +#endif /** * Render debug overlays such as the FPS/FrameCounter above the frame. diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 4d7647d02f4..db4dfba1044 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -800,6 +800,22 @@ CompositorParent::SchedulePauseOnCompositorThread() lock.Wait(); } +bool +CompositorParent::ScheduleResumeOnCompositorThread() +{ + MonitorAutoLock lock(mResumeCompositionMonitor); + + CancelableTask *resumeTask = + NewRunnableMethod(this, &CompositorParent::ResumeComposition); + MOZ_ASSERT(CompositorLoop()); + CompositorLoop()->PostTask(FROM_HERE, resumeTask); + + // Wait until the resume has actually been processed by the compositor thread + lock.Wait(); + + return !mPaused; +} + bool CompositorParent::ScheduleResumeOnCompositorThread(int width, int height) { diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 66e5d5a60ab..e066ec29e7b 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -226,6 +226,7 @@ public: * Returns true if a surface was obtained and the resume succeeded; false * otherwise. */ + bool ScheduleResumeOnCompositorThread(); bool ScheduleResumeOnCompositorThread(int width, int height); virtual void ScheduleComposition(); diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h index ff82fa5956c..94f7205ded7 100644 --- a/gfx/layers/opengl/CompositorOGL.h +++ b/gfx/layers/opengl/CompositorOGL.h @@ -304,6 +304,19 @@ public: const gfx::Matrix4x4& GetProjMatrix() const { return mProjMatrix; } + + void SetProjMatrix(const gfx::Matrix4x4& aProjMatrix) { + mProjMatrix = aProjMatrix; + } + + const gfx::IntSize GetDestinationSurfaceSize() const { + return gfx::IntSize (mSurfaceSize.width, mSurfaceSize.height); + } + + const ScreenPoint& GetScreenRenderOffset() const { + return mRenderOffset; + } + private: virtual gfx::IntSize GetWidgetSize() const override { diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 8ee810ed841..229e5742e92 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -1507,7 +1507,7 @@ xpc::EvalInSandbox(JSContext* cx, HandleObject sandboxArg, const nsAString& sour NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE); nsAutoCString filenameBuf; - if (!filename.IsVoid()) { + if (!filename.IsVoid() && filename.Length() != 0) { filenameBuf.Assign(filename); } else { // Default to the spec of the principal. diff --git a/js/xpconnect/tests/unit/test_sandbox_name.js b/js/xpconnect/tests/unit/test_sandbox_name.js new file mode 100644 index 00000000000..44e6bbcd40d --- /dev/null +++ b/js/xpconnect/tests/unit/test_sandbox_name.js @@ -0,0 +1,28 @@ +"use strict"; + +const { utils: Cu, interfaces: Ci, classes: Cc } = Components; + +/** + * Test that the name of a sandbox contains the name of all principals. + */ +function test_sandbox_name() { + let names = [ + "http://example.com/?" + Math.random(), + "http://example.org/?" + Math.random() + ]; + let sandbox = Cu.Sandbox(names); + let fileName = Cu.evalInSandbox( + "(new Error()).fileName", + sandbox, + "latest" /*js version*/, + ""/*file name*/ + ); + + for (let name of names) { + Assert.ok(fileName.indexOf(name) != -1, `Name ${name} appears in ${fileName}`); + } +}; + +function run_test() { + test_sandbox_name(); +} diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini index b3a4a78ee3e..5c446da9f8d 100644 --- a/js/xpconnect/tests/unit/xpcshell.ini +++ b/js/xpconnect/tests/unit/xpcshell.ini @@ -99,6 +99,7 @@ skip-if = os == "android" # native test components aren't available on Android [test_sandbox_atob.js] [test_isProxy.js] [test_getObjectPrincipal.js] +[test_sandbox_name.js] [test_watchdog_enable.js] head = head_watchdog.js [test_watchdog_disable.js] diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java index 7ade38f9f9c..cd524706543 100644 --- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -779,6 +779,7 @@ public class BrowserApp extends GeckoApp "Menu:Add", "Menu:Remove", "Reader:Share", + "Sanitize:ClearHistory", "Settings:Show", "Telemetry:Gather", "Updater:Launch"); @@ -1324,6 +1325,7 @@ public class BrowserApp extends GeckoApp "Menu:Add", "Menu:Remove", "Reader:Share", + "Sanitize:ClearHistory", "Settings:Show", "Telemetry:Gather", "Updater:Launch"); @@ -1360,6 +1362,16 @@ public class BrowserApp extends GeckoApp } } + private void handleClearHistory(final boolean clearSearchHistory) { + final BrowserDB db = getProfile().getDB(); + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + db.clearHistory(getContentResolver(), clearSearchHistory); + } + }); + } + private void shareCurrentUrl() { Tab tab = Tabs.getInstance().getSelectedTab(); if (tab == null) { @@ -1636,7 +1648,9 @@ public class BrowserApp extends GeckoApp final String title = message.getString("title"); final String url = message.getString("url"); GeckoAppShell.openUriExternal(url, "text/plain", "", "", Intent.ACTION_SEND, title); - + } else if ("Sanitize:ClearHistory".equals(event)) { + handleClearHistory(message.optBoolean("clearSearchHistory", false)); + callback.sendSuccess(true); } else if ("Settings:Show".equals(event)) { final String resource = message.optString(GeckoPreferences.INTENT_EXTRA_RESOURCES, null); diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index d756576d5b0..82157868b95 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -523,16 +523,6 @@ public abstract class GeckoApp outState.putString(SAVED_STATE_PRIVATE_SESSION, mPrivateBrowsingSession); } - void handleClearHistory(final boolean clearSearchHistory) { - final BrowserDB db = getProfile().getDB(); - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - db.clearHistory(getContentResolver(), clearSearchHistory); - } - }); - } - public void addTab() { } public void addPrivateTab() { } @@ -625,10 +615,6 @@ public abstract class GeckoApp } else if ("PrivateBrowsing:Data".equals(event)) { mPrivateBrowsingSession = message.optString("session", null); - } else if ("Sanitize:ClearHistory".equals(event)) { - handleClearHistory(message.optBoolean("clearSearchHistory", false)); - callback.sendSuccess(true); - } else if ("Session:StatePurged".equals(event)) { onStatePurged(); @@ -1547,7 +1533,6 @@ public abstract class GeckoApp "Locale:Set", "Permissions:Data", "PrivateBrowsing:Data", - "Sanitize:ClearHistory", "Session:StatePurged", "Share:Text", "SystemUI:Visibility", @@ -2039,7 +2024,6 @@ public abstract class GeckoApp "Locale:Set", "Permissions:Data", "PrivateBrowsing:Data", - "Sanitize:ClearHistory", "Session:StatePurged", "Share:Text", "SystemUI:Visibility", diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 5a9916bddf4..4b5c675ae97 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -294,6 +294,9 @@ public class GeckoAppShell public static native SurfaceBits getSurfaceBits(Surface surface); + public static native void addPresentationSurface(Surface surface); + public static native void removePresentationSurface(Surface surface); + public static native void onFullScreenPluginHidden(View view); public static class CreateShortcutFaviconLoadedListener implements OnFaviconLoadedListener { diff --git a/mobile/android/base/MediaPlayerManager.java b/mobile/android/base/MediaPlayerManager.java index 68f943b7aab..91ba5fc6147 100644 --- a/mobile/android/base/MediaPlayerManager.java +++ b/mobile/android/base/MediaPlayerManager.java @@ -5,6 +5,9 @@ package org.mozilla.gecko; +import android.app.Presentation; +import android.content.Context; +import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.media.MediaControlIntent; @@ -12,6 +15,13 @@ import android.support.v7.media.MediaRouteSelector; import android.support.v7.media.MediaRouter; import android.support.v7.media.MediaRouter.RouteInfo; import android.util.Log; +import android.view.Display; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.view.WindowManager; import com.google.android.gms.cast.CastMediaControlIntent; @@ -61,6 +71,7 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener private MediaRouter mediaRouter = null; private final Map displays = new HashMap(); + private GeckoPresentation presentation = null; @Override public void onCreate(Bundle savedInstanceState) { @@ -135,19 +146,23 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener displays.remove(route.getId()); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent( "MediaPlayer:Removed", route.getId())); + updatePresentation(); } @SuppressWarnings("unused") public void onRouteSelected(MediaRouter router, int type, MediaRouter.RouteInfo route) { + updatePresentation(); } // These methods aren't used by the support version Media Router @SuppressWarnings("unused") public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) { + updatePresentation(); } @Override public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) { + updatePresentation(); } @Override @@ -159,6 +174,7 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener debug("onRouteAdded: route=" + route); final GeckoMediaPlayer display = getMediaPlayerForRoute(route); saveAndNotifyOfDisplay("MediaPlayer:Added", route, display); + updatePresentation(); } @Override @@ -166,6 +182,7 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener debug("onRouteChanged: route=" + route); final GeckoMediaPlayer display = displays.get(route.getId()); saveAndNotifyOfDisplay("MediaPlayer:Changed", route, display); + updatePresentation(); } private void saveAndNotifyOfDisplay(final String eventName, @@ -221,4 +238,86 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener .build(); mediaRouter.addCallback(selectorBuilder, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } + + @Override + public void onStop() { + super.onStop(); + if (presentation != null) { + presentation.dismiss(); + presentation = null; + } + } + + private void updatePresentation() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + return; + } + + if (mediaRouter == null) { + return; + } + + MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(); + Display display = route != null ? route.getPresentationDisplay() : null; + + if (display != null) { + if ((presentation != null) && (presentation.getDisplay() != display)) { + presentation.dismiss(); + presentation = null; + } + + if (presentation == null) { + presentation = new GeckoPresentation(getActivity(), display); + + try { + presentation.show(); + } catch (WindowManager.InvalidDisplayException ex) { + Log.w(LOGTAG, "Couldn't show presentation! Display was removed in " + + "the meantime.", ex); + presentation = null; + } + } + } else if (presentation != null) { + presentation.dismiss(); + presentation = null; + } + } + + private static class SurfaceListener implements SurfaceHolder.Callback { + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, + int height) { + // Surface changed so force a composite + GeckoAppShell.scheduleComposite(); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + GeckoAppShell.addPresentationSurface(holder.getSurface()); + GeckoAppShell.scheduleComposite(); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + GeckoAppShell.removePresentationSurface(holder.getSurface()); + } + } + + private final static class GeckoPresentation extends Presentation { + private SurfaceView mView; + public GeckoPresentation(Context context, Display display) { + super(context, display); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mView = new SurfaceView(getContext()); + setContentView(mView, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + mView.getHolder().addCallback(new SurfaceListener()); + } + } } diff --git a/mobile/android/base/TextSelection.java b/mobile/android/base/TextSelection.java index 46fe172415e..d7dcfb2f53c 100644 --- a/mobile/android/base/TextSelection.java +++ b/mobile/android/base/TextSelection.java @@ -4,6 +4,7 @@ package org.mozilla.gecko; +import android.content.res.Resources; import org.mozilla.gecko.gfx.BitmapUtils; import org.mozilla.gecko.gfx.BitmapUtils.BitmapLoader; import org.mozilla.gecko.gfx.Layer; @@ -16,6 +17,7 @@ import org.mozilla.gecko.util.FloatUtils; import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.ActionModeCompat.Callback; +import org.mozilla.gecko.AppConstants.Versions; import android.content.Context; import android.app.Activity; @@ -279,11 +281,23 @@ class TextSelection extends Layer implements GeckoEventListener { final int actionEnum = obj.optBoolean("showAsAction") ? GeckoMenuItem.SHOW_AS_ACTION_ALWAYS : GeckoMenuItem.SHOW_AS_ACTION_NEVER; menuitem.setShowAsAction(actionEnum, R.attr.menuItemActionModeStyle); - BitmapUtils.getDrawable(anchorHandle.getContext(), obj.optString("icon"), new BitmapLoader() { + final String iconString = obj.optString("icon"); + BitmapUtils.getDrawable(anchorHandle.getContext(), iconString, new BitmapLoader() { @Override public void onBitmapFound(Drawable d) { if (d != null) { menuitem.setIcon(d); + + // Dynamically add padding to align the share icon on GB devices. + // To be removed in bug 1122752. + if (Versions.preHC && "drawable://ic_menu_share".equals(iconString)) { + final View view = menuitem.getActionView(); + + final Resources res = view.getContext().getResources(); + final int padding = res.getDimensionPixelSize(R.dimen.ab_share_padding); + + view.setPadding(padding, padding, padding, padding); + } } } }); diff --git a/mobile/android/base/resources/values/dimens.xml b/mobile/android/base/resources/values/dimens.xml index fcacc0ccc1e..62690a2002e 100644 --- a/mobile/android/base/resources/values/dimens.xml +++ b/mobile/android/base/resources/values/dimens.xml @@ -213,6 +213,10 @@ 10dip 2dip + + 12dp + 0.571 diff --git a/mobile/android/chrome/content/Reader.js b/mobile/android/chrome/content/Reader.js index afc96e5893d..9792386a136 100644 --- a/mobile/android/chrome/content/Reader.js +++ b/mobile/android/chrome/content/Reader.js @@ -5,8 +5,6 @@ "use strict"; -XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm"); - let Reader = { // These values should match those defined in BrowserContract.java. STATUS_UNFETCHED: 0, diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 5c69e8ea9ee..ff0a2f98e44 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -113,6 +113,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Notifications", XPCOMUtils.defineLazyModuleGetter(this, "GMPInstallManager", "resource://gre/modules/GMPInstallManager.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm"); + let lazilyLoadedBrowserScripts = [ ["SelectHelper", "chrome://browser/content/SelectHelper.js"], ["InputWidgetHelper", "chrome://browser/content/InputWidgetHelper.js"], @@ -4562,16 +4564,7 @@ Tab.prototype = { }, _stripAboutReaderURL: function (url) { - if (!url.startsWith("about:reader")) { - return url; - } - - // From ReaderParent._getOriginalUrl (browser/modules/ReaderParent.jsm). - let searchParams = new URLSearchParams(url.substring("about:reader?".length)); - if (!searchParams.has("url")) { - return url; - } - return decodeURIComponent(searchParams.get("url")); + return ReaderMode.getOriginalUrl(url) || url; }, // Properties used to cache security state used to update the UI diff --git a/mozglue/android/jni-stubs.inc b/mozglue/android/jni-stubs.inc index 92fb10fa904..6d2726366b6 100644 --- a/mozglue/android/jni-stubs.inc +++ b/mozglue/android/jni-stubs.inc @@ -305,6 +305,44 @@ Java_org_mozilla_gecko_GeckoAppShell_getSurfaceBits(JNIEnv * arg0, jclass arg1, #ifdef JNI_STUBS +typedef void (*Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface_t)(JNIEnv *, jclass, jobject); +static Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface_t f_Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface; +extern "C" NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface(JNIEnv * arg0, jclass arg1, jobject arg2) { + if (!f_Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface) { + arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), + "JNI Function called before it was loaded"); + return ; + } + f_Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface(arg0, arg1, arg2); +} +#endif + +#ifdef JNI_BINDINGS + xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface", &f_Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface); +#endif + +#ifdef JNI_STUBS + +typedef void (*Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface_t)(JNIEnv *, jclass, jobject); +static Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface_t f_Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface; +extern "C" NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface(JNIEnv * arg0, jclass arg1, jobject arg2) { + if (!f_Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface) { + arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), + "JNI Function called before it was loaded"); + return ; + } + f_Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface(arg0, arg1, arg2); +} +#endif + +#ifdef JNI_BINDINGS + xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface", &f_Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface); +#endif + +#ifdef JNI_STUBS + typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden_t)(JNIEnv *, jclass, jobject); static Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden_t f_Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden; extern "C" NS_EXPORT void JNICALL diff --git a/testing/docker/builder/Dockerfile b/testing/docker/builder/Dockerfile index 77c9ce6f9b2..56bd625e91c 100644 --- a/testing/docker/builder/Dockerfile +++ b/testing/docker/builder/Dockerfile @@ -21,7 +21,7 @@ RUN git config --global user.email "mozilla@example.com" && \ git config --global user.name "mozilla" # VCS Tools -RUN npm install -g taskcluster-vcs@2.3.4 +RUN npm install -g taskcluster-vcs@2.3.5 # TODO enable worker # TODO volume mount permissions will be an issue diff --git a/testing/docker/phone-builder/Dockerfile b/testing/docker/phone-builder/Dockerfile index bff90e9ec1e..e82cbbea9c6 100644 --- a/testing/docker/phone-builder/Dockerfile +++ b/testing/docker/phone-builder/Dockerfile @@ -4,9 +4,10 @@ MAINTAINER Wander Lairson Costa # Add utilities and configuration ADD bin /home/worker/bin ADD config /home/worker/.aws/config -ADD system-setup.sh /tmp/system-setup.sh -RUN /tmp/system-setup.sh +RUN yum install -y bc lzop +RUN pip install awscli +RUN npm install -g bower gulp apm grunt-cli # Set a default command useful for debugging ENTRYPOINT ["validate_task.py"] diff --git a/testing/docker/phone-builder/VERSION b/testing/docker/phone-builder/VERSION index 8cbf02c396d..43b29618309 100644 --- a/testing/docker/phone-builder/VERSION +++ b/testing/docker/phone-builder/VERSION @@ -1 +1 @@ -0.0.12 +0.0.13 diff --git a/testing/docker/phone-builder/system-setup.sh b/testing/docker/phone-builder/system-setup.sh deleted file mode 100755 index e21f16d1627..00000000000 --- a/testing/docker/phone-builder/system-setup.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -pip install awscli - -# Necessary for dolhin kernel building -yum install -y bc - -# Remove ourselves -rm -f $0 diff --git a/testing/taskcluster/scripts/phone-builder/build-lightsaber-nightly.sh b/testing/taskcluster/scripts/phone-builder/build-lightsaber-nightly.sh new file mode 100755 index 00000000000..57e25a99b9d --- /dev/null +++ b/testing/taskcluster/scripts/phone-builder/build-lightsaber-nightly.sh @@ -0,0 +1,49 @@ +#! /bin/bash -vex + +. pre-build.sh + +if [ 0$B2G_DEBUG -ne 0 ]; then + DEBUG_SUFFIX=-debug +fi + +if [ $TARGET == "aries" -o $TARGET == "shinano" ]; then + # caching objects might be dangerous for some devices (aka aries) + rm -rf $WORKSPACE/B2G/objdir* + rm -rf $WORKSPACE/B2G/out +fi + +aws s3 cp s3://b2g-nightly-credentials/balrog_credentials . +mar_file=b2g-${TARGET%%-*}-gecko-update.mar + +./mozharness/scripts/b2g_lightsaber.py \ + --config b2g/taskcluster-lightsaber-nightly.py \ + --config balrog/staging.py \ + "$debug_flag" \ + --disable-mock \ + --variant=$VARIANT \ + --work-dir=$WORKSPACE/B2G \ + --gaia-languages-file locales/languages_all.json \ + --log-level=debug \ + --target=$TARGET \ + --b2g-config-dir=$TARGET \ + --checkout-revision=$GECKO_HEAD_REV \ + --base-repo=$GECKO_BASE_REPOSITORY \ + --repo=$GECKO_HEAD_REPOSITORY \ + --platform $TARGET \ + --complete-mar-url https://queue.taskcluster.net/v1/task/$TASK_ID/runs/$RUN_ID/artifacts/public/build/$mar_file \ + +# Don't cache backups +rm -rf $WORKSPACE/B2G/backup-* +rm -f balrog_credentials + +mkdir -p $HOME/artifacts +mkdir -p $HOME/artifacts-public + +mv $WORKSPACE/B2G/upload-public/$mar_file $HOME/artifacts-public/ +mv $WORKSPACE/B2G/upload/sources.xml $HOME/artifacts/sources.xml +#mv $WORKSPACE/B2G/upload/b2g-*.crashreporter-symbols.zip $HOME/artifacts/b2g-crashreporter-symbols.zip +mv $WORKSPACE/B2G/upload/b2g-*.android-arm.tar.gz $HOME/artifacts/b2g-android-arm.tar.gz +mv $WORKSPACE/B2G/upload/${TARGET}.zip $HOME/artifacts/${TARGET}.zip +mv $WORKSPACE/B2G/upload/gaia.zip $HOME/artifacts/gaia.zip +ccache -s + diff --git a/testing/taskcluster/scripts/phone-builder/build-phone-nightly.sh b/testing/taskcluster/scripts/phone-builder/build-phone-nightly.sh index 8a3af888465..b9ececab7dd 100755 --- a/testing/taskcluster/scripts/phone-builder/build-phone-nightly.sh +++ b/testing/taskcluster/scripts/phone-builder/build-phone-nightly.sh @@ -11,7 +11,6 @@ if [ ! -d $HOME/.ssh ]; then fi aws s3 cp s3://b2g-nightly-credentials/balrog_credentials . -aws s3 cp s3://b2g-nightly-credentials/b2g-rsa $HOME/.ssh/ ./mozharness/scripts/b2g_build.py \ --config b2g/taskcluster-phone-nightly.py \ @@ -28,12 +27,11 @@ aws s3 cp s3://b2g-nightly-credentials/b2g-rsa $HOME/.ssh/ --base-repo=$GECKO_BASE_REPOSITORY \ --repo=$GECKO_HEAD_REPOSITORY \ --platform $TARGET \ - --complete-mar-url https://queue.taskcluster.net/v1/task/$TASK_ID/runs/0/artifacts/public/build/b2g-${TARGET%%-*}-gecko-update.mar \ + --complete-mar-url https://queue.taskcluster.net/v1/task/$TASK_ID/runs/$RUN_ID/artifacts/public/build/b2g-${TARGET%%-*}-gecko-update.mar \ # Don't cache backups rm -rf $WORKSPACE/B2G/backup-* rm -f balrog_credentials -rm -f $HOME/.ssh/b2g-rsa mkdir -p $HOME/artifacts mkdir -p $HOME/artifacts-public diff --git a/testing/taskcluster/scripts/phone-builder/pre-build.sh b/testing/taskcluster/scripts/phone-builder/pre-build.sh index cce46cd77d4..8699953a649 100755 --- a/testing/taskcluster/scripts/phone-builder/pre-build.sh +++ b/testing/taskcluster/scripts/phone-builder/pre-build.sh @@ -19,14 +19,7 @@ test $VARIANT . ../builder/setup-ccache.sh -# First check if the mozharness directory is available. This is intended to be -# used locally in development to test mozharness changes: -# -# $ docker -v your_mozharness:/home/worker/mozharness ... -# -if [ ! -d mozharness ]; then - tc-vcs checkout mozharness $MOZHARNESS_REPOSITORY $MOZHARNESS_REPOSITORY $MOZHARNESS_REV $MOZHARNESS_REF -fi +tc-vcs checkout mozharness $MOZHARNESS_REPOSITORY $MOZHARNESS_REPOSITORY $MOZHARNESS_REV $MOZHARNESS_REF # Figure out where the remote manifest is so we can use caches for it. MANIFEST=$(repository-url.py $GECKO_HEAD_REPOSITORY $GECKO_HEAD_REV b2g/config/$TARGET/sources.xml) diff --git a/testing/taskcluster/tasks/branches/base_job_flags.yml b/testing/taskcluster/tasks/branches/base_job_flags.yml index adc5506de85..91b11673b85 100644 --- a/testing/taskcluster/tasks/branches/base_job_flags.yml +++ b/testing/taskcluster/tasks/branches/base_job_flags.yml @@ -22,6 +22,7 @@ flags: - dolphin-eng - dolphin-512 - dolphin-512-eng + - aries-nightly tests: - cppunit diff --git a/testing/taskcluster/tasks/branches/cypress/job_flags.yml b/testing/taskcluster/tasks/branches/cypress/job_flags.yml index 30d08855f2a..1820ee53386 100644 --- a/testing/taskcluster/tasks/branches/cypress/job_flags.yml +++ b/testing/taskcluster/tasks/branches/cypress/job_flags.yml @@ -18,6 +18,12 @@ builds: types: opt: task: tasks/builds/b2g_flame_kk_eng.yml + aries-nightly: + platforms: + - b2g + types: + opt: + task: tasks/builds/b2g_aries_lightsaber_nightly.yml tests: gaia-build: diff --git a/testing/taskcluster/tasks/builds/b2g_aries_lightsaber_nightly.yml b/testing/taskcluster/tasks/builds/b2g_aries_lightsaber_nightly.yml new file mode 100644 index 00000000000..345b9a097cb --- /dev/null +++ b/testing/taskcluster/tasks/builds/b2g_aries_lightsaber_nightly.yml @@ -0,0 +1,35 @@ +$inherits: + from: 'tasks/builds/b2g_phone_base.yml' + variables: + build_name: 'aries' + build_type: 'nightly' +task: + workerType: flame-kk + scopes: + - 'docker-worker:cache:build-aries-lightsaber-nightly' + metadata: + name: '[TC] B2G Aries Nightly' + + payload: + cache: + build-aries-lightsaber-nightly: /home/worker/workspace + env: + TARGET: 'aries' + DEBUG: 0 + command: + - > + checkout-gecko workspace && + cd ./workspace/gecko/testing/taskcluster/scripts/phone-builder && + buildbot_step 'Build' ./build-lightsaber-nightly.sh $HOME/workspace + + extra: + treeherder: + symbol: B + groupSymbol: Aries + groupName: Aries Device Image + machine: + platform: b2g-device-image + locations: + img: 'private/build/aries.zip' + mar: 'public/build/b2g-aries-gecko-update.mar' + diff --git a/toolkit/components/build/nsToolkitCompsCID.h b/toolkit/components/build/nsToolkitCompsCID.h index b911c08b9c1..34742c79165 100644 --- a/toolkit/components/build/nsToolkitCompsCID.h +++ b/toolkit/components/build/nsToolkitCompsCID.h @@ -2,12 +2,6 @@ * 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/. */ -#if defined(MOZ_UPDATER) -# if !defined(MOZ_WIDGET_ANDROID) -# define USE_MOZ_UPDATER -# endif -#endif - #define NS_ALERTSERVICE_CONTRACTID \ "@mozilla.org/alerts-service;1" @@ -90,7 +84,7 @@ #define NS_APPSTARTUP_CONTRACTID \ "@mozilla.org/toolkit/app-startup;1" -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) #define NS_UPDATEPROCESSOR_CONTRACTID \ "@mozilla.org/updates/update-processor;1" #endif @@ -173,7 +167,7 @@ #define NS_FAVICONSERVICE_CID \ { 0x984e3259, 0x9266, 0x49cf, { 0xb6, 0x05, 0x60, 0xb0, 0x22, 0xa0, 0x07, 0x56 } } -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) #define NS_UPDATEPROCESSOR_CID \ { 0xf3dcf644, 0x79e8, 0x4f59, { 0xa1, 0xbb, 0x87, 0x84, 0x54, 0x48, 0x8e, 0xf9 } } #endif diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index c6ecbb81619..2b27a11c92a 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -7,7 +7,7 @@ #include "nsUserInfo.h" #include "nsToolkitCompsCID.h" #include "nsFindService.h" -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) #include "nsUpdateDriver.h" #endif @@ -109,7 +109,7 @@ nsUrlClassifierDBServiceConstructor(nsISupports *aOuter, REFNSIID aIID, #endif NS_GENERIC_FACTORY_CONSTRUCTOR(nsBrowserStatusFilter) -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) NS_GENERIC_FACTORY_CONSTRUCTOR(nsUpdateProcessor) #endif NS_GENERIC_FACTORY_CONSTRUCTOR(FinalizationWitnessService) @@ -141,7 +141,7 @@ NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERSTREAMUPDATER_CID); NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERUTILS_CID); #endif NS_DEFINE_NAMED_CID(NS_BROWSERSTATUSFILTER_CID); -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_CID); #endif NS_DEFINE_NAMED_CID(FINALIZATIONWITNESSSERVICE_CID); @@ -173,7 +173,7 @@ static const Module::CIDEntry kToolkitCIDs[] = { { &kNS_URLCLASSIFIERUTILS_CID, false, nullptr, nsUrlClassifierUtilsConstructor }, #endif { &kNS_BROWSERSTATUSFILTER_CID, false, nullptr, nsBrowserStatusFilterConstructor }, -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) { &kNS_UPDATEPROCESSOR_CID, false, nullptr, nsUpdateProcessorConstructor }, #endif { &kFINALIZATIONWITNESSSERVICE_CID, false, nullptr, FinalizationWitnessServiceConstructor }, @@ -207,7 +207,7 @@ static const Module::ContractIDEntry kToolkitContracts[] = { { NS_URLCLASSIFIERUTILS_CONTRACTID, &kNS_URLCLASSIFIERUTILS_CID }, #endif { NS_BROWSERSTATUSFILTER_CONTRACTID, &kNS_BROWSERSTATUSFILTER_CID }, -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) { NS_UPDATEPROCESSOR_CONTRACTID, &kNS_UPDATEPROCESSOR_CID }, #endif { FINALIZATIONWITNESSSERVICE_CONTRACTID, &kFINALIZATIONWITNESSSERVICE_CID }, diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index 41694c5a006..9daf31898cc 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -48,6 +48,7 @@ DIRS += [ 'statusfilter', 'telemetry', 'thumbnails', + 'timermanager', 'typeaheadfind', 'urlformatter', 'viewconfig', diff --git a/toolkit/components/reader/AboutReader.jsm b/toolkit/components/reader/AboutReader.jsm index 1c24db776b8..64fa223660b 100644 --- a/toolkit/components/reader/AboutReader.jsm +++ b/toolkit/components/reader/AboutReader.jsm @@ -8,6 +8,7 @@ let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils; this.EXPORTED_SYMBOLS = [ "AboutReader" ]; +Cu.import("resource://gre/modules/ReaderMode.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); @@ -734,9 +735,8 @@ AboutReader.prototype = { this._domainElement.href = article.url; let articleUri = Services.io.newURI(article.url, null, null); - this._domainElement.innerHTML = this._stripHost(articleUri.host); - - this._creditsElement.innerHTML = article.byline; + this._domainElement.textContent = this._stripHost(articleUri.host); + this._creditsElement.textContent = article.byline; this._titleElement.textContent = article.title; this._doc.title = article.title; @@ -787,12 +787,7 @@ AboutReader.prototype = { */ _getOriginalUrl: function(win) { let url = win ? win.location.href : this._win.location.href; - let searchParams = new URLSearchParams(url.split("?")[1]); - if (!searchParams.has("url")) { - Cu.reportError("Error finding original URL for about:reader URL: " + url); - return url; - } - return decodeURIComponent(searchParams.get("url")); + return ReaderMode.getOriginalUrl(url) || url; }, _setupSegmentedButton: function Reader_setupSegmentedButton(id, options, initialValue, callback) { diff --git a/toolkit/components/reader/ReaderMode.jsm b/toolkit/components/reader/ReaderMode.jsm index b4cab82eea0..20e107670d8 100644 --- a/toolkit/components/reader/ReaderMode.jsm +++ b/toolkit/components/reader/ReaderMode.jsm @@ -67,6 +67,31 @@ this.ReaderMode = { } }, + /** + * Returns original URL from an about:reader URL. + * + * @param url An about:reader URL. + * @return The original URL for the article, or null if we did not find + * a properly formatted about:reader URL. + */ + getOriginalUrl: function(url) { + if (!url.startsWith("about:reader?")) { + return null; + } + + let searchParams = new URLSearchParams(url.substring("about:reader?".length)); + if (!searchParams.has("url")) { + return null; + } + let encodedURL = searchParams.get("url"); + try { + return decodeURIComponent(encodedURL); + } catch (e) { + Cu.reportError("Error decoding original URL: " + e); + return encodedURL; + } + }, + /** * Decides whether or not a document is reader-able without parsing the whole thing. * diff --git a/toolkit/components/satchel/AutoCompleteE10S.jsm b/toolkit/components/satchel/AutoCompleteE10S.jsm index 87bc198de3a..77d0a0a6e6a 100644 --- a/toolkit/components/satchel/AutoCompleteE10S.jsm +++ b/toolkit/components/satchel/AutoCompleteE10S.jsm @@ -84,11 +84,12 @@ this.AutoCompleteE10S = { messageManager.addMessageListener("FormAutoComplete:ClosePopup", this); }, - _initPopup: function(browserWindow, rect) { + _initPopup: function(browserWindow, rect, direction) { this.browser = browserWindow.gBrowser.selectedBrowser; this.popup = this.browser.autoCompletePopup; this.popup.hidden = false; this.popup.setAttribute("width", rect.width); + this.popup.style.direction = direction; this.x = rect.left; this.y = rect.top + rect.height; @@ -137,8 +138,9 @@ this.AutoCompleteE10S = { search: function(message) { let browserWindow = message.target.ownerDocument.defaultView; let rect = message.data; + let direction = message.data.direction; - this._initPopup(browserWindow, rect); + this._initPopup(browserWindow, rect, direction); let formAutoComplete = Cc["@mozilla.org/satchel/form-autocomplete;1"] .getService(Ci.nsIFormAutoComplete); diff --git a/toolkit/components/satchel/nsFormAutoComplete.js b/toolkit/components/satchel/nsFormAutoComplete.js index 150965a63f2..4544c8e6419 100644 --- a/toolkit/components/satchel/nsFormAutoComplete.js +++ b/toolkit/components/satchel/nsFormAutoComplete.js @@ -372,9 +372,10 @@ FormAutoCompleteChild.prototype = { this.stopAutoCompleteSearch(); } - let rect = BrowserUtils.getElementBoundingScreenRect(aField); - let window = aField.ownerDocument.defaultView; + + let rect = BrowserUtils.getElementBoundingScreenRect(aField); + let direction = window.getComputedStyle(aField).direction; let topLevelDocshell = window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDocShell) .sameTypeRootTreeItem @@ -389,7 +390,8 @@ FormAutoCompleteChild.prototype = { left: rect.left, top: rect.top, width: rect.width, - height: rect.height + height: rect.height, + direction: direction, }); let search = this._pendingSearch = {}; diff --git a/toolkit/components/timermanager/moz.build b/toolkit/components/timermanager/moz.build new file mode 100644 index 00000000000..d9dfac4d29c --- /dev/null +++ b/toolkit/components/timermanager/moz.build @@ -0,0 +1,21 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +XPIDL_MODULE = 'update' + +XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] + +XPIDL_SOURCES += [ + 'nsIUpdateTimerManager.idl', +] + +EXTRA_COMPONENTS += [ + 'nsUpdateTimerManager.js', + 'nsUpdateTimerManager.manifest', +] + +with Files('**'): + BUG_COMPONENT = ('Toolkit', 'Application Update') diff --git a/toolkit/mozapps/update/nsIUpdateTimerManager.idl b/toolkit/components/timermanager/nsIUpdateTimerManager.idl similarity index 100% rename from toolkit/mozapps/update/nsIUpdateTimerManager.idl rename to toolkit/components/timermanager/nsIUpdateTimerManager.idl diff --git a/toolkit/mozapps/update/nsUpdateTimerManager.js b/toolkit/components/timermanager/nsUpdateTimerManager.js similarity index 100% rename from toolkit/mozapps/update/nsUpdateTimerManager.js rename to toolkit/components/timermanager/nsUpdateTimerManager.js diff --git a/toolkit/mozapps/update/nsUpdateTimerManager.manifest b/toolkit/components/timermanager/nsUpdateTimerManager.manifest similarity index 100% rename from toolkit/mozapps/update/nsUpdateTimerManager.manifest rename to toolkit/components/timermanager/nsUpdateTimerManager.manifest diff --git a/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js b/toolkit/components/timermanager/tests/unit/consumerNotifications.js similarity index 100% rename from toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js rename to toolkit/components/timermanager/tests/unit/consumerNotifications.js diff --git a/toolkit/mozapps/update/tests/unit_timermanager/xpcshell.ini b/toolkit/components/timermanager/tests/unit/xpcshell.ini similarity index 100% rename from toolkit/mozapps/update/tests/unit_timermanager/xpcshell.ini rename to toolkit/components/timermanager/tests/unit/xpcshell.ini diff --git a/toolkit/modules/NewTabUtils.jsm b/toolkit/modules/NewTabUtils.jsm index 9776fb31884..1ccba141eb9 100644 --- a/toolkit/modules/NewTabUtils.jsm +++ b/toolkit/modules/NewTabUtils.jsm @@ -471,11 +471,23 @@ let PinnedLinks = { * Singleton that keeps track of all blocked links in the grid. */ let BlockedLinks = { + /** + * A list of objects that are observing blocked link changes. + */ + _observers: [], + /** * The cached list of blocked links. */ _links: null, + /** + * Registers an object that will be notified when the blocked links change. + */ + addObserver: function (aObserver) { + this._observers.push(aObserver); + }, + /** * The list of blocked links. */ @@ -487,10 +499,11 @@ let BlockedLinks = { }, /** - * Blocks a given link. + * Blocks a given link. Adjusts siteMap accordingly, and notifies listeners. * @param aLink The link to block. */ block: function BlockedLinks_block(aLink) { + this._callObservers("onLinkBlocked", aLink); this.links[toHash(aLink.url)] = 1; this.save(); @@ -499,13 +512,14 @@ let BlockedLinks = { }, /** - * Unblocks a given link. + * Unblocks a given link. Adjusts siteMap accordingly, and notifies listeners. * @param aLink The link to unblock. */ unblock: function BlockedLinks_unblock(aLink) { if (this.isBlocked(aLink)) { delete this.links[toHash(aLink.url)]; this.save(); + this._callObservers("onLinkUnblocked", aLink); } }, @@ -537,6 +551,18 @@ let BlockedLinks = { */ resetCache: function BlockedLinks_resetCache() { this._links = null; + }, + + _callObservers(methodName, ...args) { + for (let obs of this._observers) { + if (typeof(obs[methodName]) == "function") { + try { + obs[methodName](...args); + } catch (err) { + Cu.reportError(err); + } + } + } } }; @@ -719,6 +745,8 @@ let Links = { * A mapping from each provider to an object { sortedLinks, siteMap, linkMap }. * sortedLinks is the cached, sorted array of links for the provider. * siteMap is a mapping from base domains to URL count associated with the domain. + * The count does not include blocked URLs. siteMap is used to look up a + * user's top sites that can be targeted with a suggested tile. * linkMap is a Map from link URLs to link objects. */ _providers: new Map(), @@ -737,6 +765,18 @@ let Links = { */ _populateCallbacks: [], + /** + * A list of objects that are observing links updates. + */ + _observers: [], + + /** + * Registers an object that will be notified when links updates. + */ + addObserver: function (aObserver) { + this._observers.push(aObserver); + }, + /** * Adds a link provider. * @param aProvider The link provider. @@ -861,11 +901,19 @@ let Links = { }, _incrementSiteMap: function(map, link) { + if (NewTabUtils.blockedLinks.isBlocked(link)) { + // Don't count blocked URLs. + return; + } let site = NewTabUtils.extractSite(link.url); map.set(site, (map.get(site) || 0) + 1); }, _decrementSiteMap: function(map, link) { + if (NewTabUtils.blockedLinks.isBlocked(link)) { + // Blocked URLs are not included in map. + return; + } let site = NewTabUtils.extractSite(link.url); let previousURLCount = map.get(site); if (previousURLCount === 1) { @@ -875,6 +923,37 @@ let Links = { } }, + /** + * Update the siteMap cache based on the link given and whether we need + * to increment or decrement it. We do this by iterating over all stored providers + * to find which provider this link already exists in. For providers that + * have this link, we will adjust siteMap for them accordingly. + * + * @param aLink The link that will affect siteMap + * @param increment A boolean for whether to increment or decrement siteMap + */ + _adjustSiteMapAndNotify: function(aLink, increment=true) { + for (let [provider, cache] of this._providers) { + // We only update siteMap if aLink is already stored in linkMap. + if (cache.linkMap.get(aLink.url)) { + if (increment) { + this._incrementSiteMap(cache.siteMap, aLink); + continue; + } + this._decrementSiteMap(cache.siteMap, aLink); + } + } + this._callObservers("onLinkChanged", aLink); + }, + + onLinkBlocked: function(aLink) { + this._adjustSiteMapAndNotify(aLink, false); + }, + + onLinkUnblocked: function(aLink) { + this._adjustSiteMapAndNotify(aLink); + }, + populateProviderCache: function(provider, callback) { if (!this._providers.has(provider)) { throw new Error("Can only populate provider cache for existing provider."); @@ -1095,6 +1174,18 @@ let Links = { this.resetCache(); }, + _callObservers(methodName, ...args) { + for (let obs of this._observers) { + if (typeof(obs[methodName]) == "function") { + try { + obs[methodName](this, ...args); + } catch (err) { + Cu.reportError(err); + } + } + } + }, + /** * Adds a sanitization observer and turns itself into a no-op after the first * invokation. @@ -1235,6 +1326,7 @@ this.NewTabUtils = { if (this.initWithoutProviders()) { PlacesProvider.init(); Links.addProvider(PlacesProvider); + BlockedLinks.addObserver(Links); } }, diff --git a/toolkit/moz.build b/toolkit/moz.build index b0c87ae0d64..e7e4a3faebe 100644 --- a/toolkit/moz.build +++ b/toolkit/moz.build @@ -23,10 +23,17 @@ DIRS += [ 'webapps', ] -DIRS += ['mozapps/update'] +if CONFIG['MOZ_UPDATER'] and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android': + DIRS += ['mozapps/update'] if CONFIG['MOZ_MAINTENANCE_SERVICE']: - DIRS += ['components/maintenanceservice'] +# Including mozapps/update/common-standalone allows the maintenance service +# to be built so the maintenance service can be used for things other than +# updating applications. + DIRS += [ + 'mozapps/update/common-standalone', + 'components/maintenanceservice' + ] DIRS += ['xre'] @@ -61,6 +68,3 @@ with Files('mozapps/plugins/*'): with Files('mozapps/preferences/*'): BUG_COMPONENT = ('Toolkit', 'Preferences') - -with Files('mozapps/update/*'): - BUG_COMPONENT = ('Toolkit', 'Application Update') diff --git a/toolkit/mozapps/update/common-standalone/moz.build b/toolkit/mozapps/update/common-standalone/moz.build index dbc787b437b..5e66f579180 100644 --- a/toolkit/mozapps/update/common-standalone/moz.build +++ b/toolkit/mozapps/update/common-standalone/moz.build @@ -10,3 +10,5 @@ include('../common/sources.mozbuild') if CONFIG['OS_ARCH'] == 'WINNT': USE_STATIC_LIBS = True + +FAIL_ON_WARNINGS = True diff --git a/toolkit/mozapps/update/common/moz.build b/toolkit/mozapps/update/common/moz.build index 2e9b89d747b..044433696ef 100644 --- a/toolkit/mozapps/update/common/moz.build +++ b/toolkit/mozapps/update/common/moz.build @@ -25,3 +25,5 @@ srcdir = '.' include('sources.mozbuild') FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True diff --git a/toolkit/mozapps/update/moz.build b/toolkit/mozapps/update/moz.build index 0d2d9dadc2f..334547d75e9 100644 --- a/toolkit/mozapps/update/moz.build +++ b/toolkit/mozapps/update/moz.build @@ -4,47 +4,32 @@ # 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/. -if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android': - if CONFIG['MOZ_UPDATER'] or CONFIG['MOZ_MAINTENANCE_SERVICE']: - # If only the maintenance service is installed and not - # the updater, then the maintenance service may still be - # used for other things. We need to build update/common - # which the maintenance service uses. - DIRS += ['common'] - if CONFIG['OS_ARCH'] == 'WINNT': - DIRS += ['common-standalone'] - - if CONFIG['MOZ_UPDATER']: - DIRS += ['updater'] - XPIDL_MODULE = 'update' -XPCSHELL_TESTS_MANIFESTS += ['tests/unit_timermanager/xpcshell.ini'] +DIRS += [ + 'common', + 'updater', +] XPIDL_SOURCES += [ - 'nsIUpdateTimerManager.idl', + 'nsIUpdateService.idl', ] +TEST_DIRS += ['tests'] + EXTRA_COMPONENTS += [ - 'nsUpdateTimerManager.js', - 'nsUpdateTimerManager.manifest', + 'nsUpdateService.js', + 'nsUpdateService.manifest', + 'nsUpdateServiceStub.js', ] -if CONFIG['MOZ_UPDATER']: - TEST_DIRS += ['tests'] - - XPIDL_SOURCES += [ - 'nsIUpdateService.idl', - ] - - EXTRA_COMPONENTS += [ - 'nsUpdateService.js', - 'nsUpdateService.manifest', - 'nsUpdateServiceStub.js', - ] - - EXTRA_JS_MODULES += [ - 'UpdateTelemetry.jsm', - ] +EXTRA_JS_MODULES += [ + 'UpdateTelemetry.jsm', +] JAR_MANIFESTS += ['jar.mn'] + +FAIL_ON_WARNINGS = True + +with Files('**'): + BUG_COMPONENT = ('Toolkit', 'Application Update') diff --git a/toolkit/mozapps/update/tests/Makefile.in b/toolkit/mozapps/update/tests/Makefile.in index bba7be0c67c..1a8baec0838 100644 --- a/toolkit/mozapps/update/tests/Makefile.in +++ b/toolkit/mozapps/update/tests/Makefile.in @@ -18,8 +18,6 @@ xpcshell-data_FILES := $(filter-out $(pp_const_file),$(wildcard $(srcdir)/data/ xpcshell-data_DEST := $(XPCSHELLTESTROOT)/data xpcshell-data_TARGET := misc -# Android doesn't use the Mozilla updater or the toolkit update UI -ifneq (android,$(MOZ_WIDGET_TOOLKIT)) ifndef MOZ_PROFILE_GENERATE ifdef COMPILE_ENVIRONMENT INSTALL_TARGETS += xpcshell-helper @@ -47,11 +45,8 @@ INI_TEST_FILES = \ MOZ_WINCONSOLE = 1 -endif # Not Android - include $(topsrcdir)/config/rules.mk -ifneq (android,$(MOZ_WIDGET_TOOLKIT)) # TestAUSReadStrings runs during check in the following directory with a Unicode # char in order to test bug 473417 on Windows. ifeq ($(OS_ARCH),WINNT) @@ -67,4 +62,3 @@ check:: done $(INSTALL) $(FINAL_TARGET)/TestAUSReadStrings$(BIN_SUFFIX) $(DEPTH)/_tests/updater/$(bug473417dir)/ @$(RUN_TEST_PROGRAM) $(DEPTH)/_tests/updater/$(bug473417dir)/TestAUSReadStrings$(BIN_SUFFIX) -endif # Not Android diff --git a/toolkit/mozapps/update/tests/moz.build b/toolkit/mozapps/update/tests/moz.build index 9081e5be43f..4642f47c135 100644 --- a/toolkit/mozapps/update/tests/moz.build +++ b/toolkit/mozapps/update/tests/moz.build @@ -8,37 +8,35 @@ HAS_MISC_RULE = True XPCSHELL_TESTS_MANIFESTS += ['unit_aus_update/xpcshell.ini'] -if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android': - MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini'] - XPCSHELL_TESTS_MANIFESTS += ['unit_base_updater/xpcshell.ini'] +MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini'] +XPCSHELL_TESTS_MANIFESTS += ['unit_base_updater/xpcshell.ini'] - if CONFIG['MOZ_MAINTENANCE_SERVICE']: - XPCSHELL_TESTS_MANIFESTS += ['unit_service_updater/xpcshell.ini'] +if CONFIG['MOZ_MAINTENANCE_SERVICE']: + XPCSHELL_TESTS_MANIFESTS += ['unit_service_updater/xpcshell.ini'] - SimplePrograms([ - 'TestAUSHelper', - 'TestAUSReadStrings', - ]) +SimplePrograms([ + 'TestAUSHelper', + 'TestAUSReadStrings', +]) - LOCAL_INCLUDES += [ - '/toolkit/mozapps/update', - '/toolkit/mozapps/update/common', +LOCAL_INCLUDES += [ + '/toolkit/mozapps/update', + '/toolkit/mozapps/update/common', +] + +if CONFIG['OS_ARCH'] == 'WINNT': + USE_LIBS += [ + 'updatecommon-standalone', ] - if CONFIG['OS_ARCH'] == 'WINNT': - USE_LIBS += [ - 'updatecommon-standalone', - ] - else: - USE_LIBS += [ - 'updatecommon', - ] - - if CONFIG['OS_ARCH'] == 'WINNT': - OS_LIBS += [ - 'wintrust', - 'shlwapi', - ] + OS_LIBS += [ + 'wintrust', + 'shlwapi', + ] +else: + USE_LIBS += [ + 'updatecommon', + ] for var in ('MOZ_APP_NAME', 'MOZ_APP_BASENAME', 'MOZ_APP_DISPLAYNAME', 'MOZ_APP_VENDOR', 'BIN_SUFFIX', 'MOZ_DEBUG'): diff --git a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini index 871c633552e..4ff7e3ac4ed 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini +++ b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini @@ -5,7 +5,6 @@ [DEFAULT] head = head_update.js tail = -skip-if = toolkit == 'android' [canCheckForAndCanApplyUpdates.js] [urlConstruction.js] diff --git a/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini index 8b853da784e..491a9d1d815 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini +++ b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini @@ -9,7 +9,6 @@ [DEFAULT] head = head_update.js tail = -skip-if = toolkit == 'android' [marSuccessComplete.js] [marSuccessPartial.js] diff --git a/toolkit/mozapps/update/updater/updater-xpcshell/moz.build b/toolkit/mozapps/update/updater/updater-xpcshell/moz.build index 7f16ee89e2c..81eef713d19 100644 --- a/toolkit/mozapps/update/updater/updater-xpcshell/moz.build +++ b/toolkit/mozapps/update/updater/updater-xpcshell/moz.build @@ -10,3 +10,4 @@ updater_rel_path = '../' NO_DIST_INSTALL = True DEFINES['UPDATER_XPCSHELL_CERT'] = True include('../updater-common.build') +FAIL_ON_WARNINGS = True diff --git a/toolkit/themes/osx/global/jar.mn b/toolkit/themes/osx/global/jar.mn index 251ef392f84..f465be9f0f3 100644 --- a/toolkit/themes/osx/global/jar.mn +++ b/toolkit/themes/osx/global/jar.mn @@ -6,13 +6,13 @@ toolkit.jar: % skin global classic/1.0 %skin/classic/global/ skin/classic/global/10pct_transparent_grey.png skin/classic/global/50pct_transparent_grey.png - skin/classic/global/about.css (../../windows/global/about.css) - skin/classic/global/aboutCache.css (../../windows/global/aboutCache.css) - skin/classic/global/aboutCacheEntry.css (../../windows/global/aboutCacheEntry.css) - skin/classic/global/aboutMemory.css (../../windows/global/aboutMemory.css) - skin/classic/global/aboutReader.css (../../windows/global/aboutReader.css) - skin/classic/global/aboutSupport.css (../../windows/global/aboutSupport.css) - skin/classic/global/appPicker.css (../../windows/global/appPicker.css) + skin/classic/global/about.css (../../shared/about.css) + skin/classic/global/aboutCache.css (../../shared/aboutCache.css) + skin/classic/global/aboutCacheEntry.css (../../shared/aboutCacheEntry.css) + skin/classic/global/aboutMemory.css (../../shared/aboutMemory.css) + skin/classic/global/aboutReader.css (../../shared/aboutReader.css) + skin/classic/global/aboutSupport.css (../../shared/aboutSupport.css) + skin/classic/global/appPicker.css (../../shared/appPicker.css) skin/classic/global/arrow.css skin/classic/global/autocomplete.css skin/classic/global/button.css diff --git a/toolkit/themes/windows/global/about.css b/toolkit/themes/shared/about.css similarity index 100% rename from toolkit/themes/windows/global/about.css rename to toolkit/themes/shared/about.css diff --git a/toolkit/themes/windows/global/aboutCache.css b/toolkit/themes/shared/aboutCache.css similarity index 100% rename from toolkit/themes/windows/global/aboutCache.css rename to toolkit/themes/shared/aboutCache.css diff --git a/toolkit/themes/windows/global/aboutCacheEntry.css b/toolkit/themes/shared/aboutCacheEntry.css similarity index 100% rename from toolkit/themes/windows/global/aboutCacheEntry.css rename to toolkit/themes/shared/aboutCacheEntry.css diff --git a/toolkit/themes/windows/global/aboutMemory.css b/toolkit/themes/shared/aboutMemory.css similarity index 100% rename from toolkit/themes/windows/global/aboutMemory.css rename to toolkit/themes/shared/aboutMemory.css diff --git a/toolkit/themes/windows/global/aboutReader.css b/toolkit/themes/shared/aboutReader.css similarity index 100% rename from toolkit/themes/windows/global/aboutReader.css rename to toolkit/themes/shared/aboutReader.css diff --git a/toolkit/themes/windows/global/aboutSupport.css b/toolkit/themes/shared/aboutSupport.css similarity index 100% rename from toolkit/themes/windows/global/aboutSupport.css rename to toolkit/themes/shared/aboutSupport.css diff --git a/toolkit/themes/windows/global/appPicker.css b/toolkit/themes/shared/appPicker.css similarity index 100% rename from toolkit/themes/windows/global/appPicker.css rename to toolkit/themes/shared/appPicker.css diff --git a/toolkit/themes/windows/global/jar.mn b/toolkit/themes/windows/global/jar.mn index 100357a1717..024f3ca0acf 100644 --- a/toolkit/themes/windows/global/jar.mn +++ b/toolkit/themes/windows/global/jar.mn @@ -4,13 +4,13 @@ toolkit.jar: % skin global classic/1.0 %skin/classic/global/ - skin/classic/global/about.css - skin/classic/global/aboutCache.css - skin/classic/global/aboutCacheEntry.css - skin/classic/global/aboutMemory.css - skin/classic/global/aboutReader.css - skin/classic/global/aboutSupport.css - skin/classic/global/appPicker.css + skin/classic/global/about.css (../../shared/about.css) + skin/classic/global/aboutCache.css (../../shared/aboutCache.css) + skin/classic/global/aboutCacheEntry.css (../../shared/aboutCacheEntry.css) + skin/classic/global/aboutMemory.css (../../shared/aboutMemory.css) + skin/classic/global/aboutReader.css (../../shared/aboutReader.css) + skin/classic/global/aboutSupport.css (../../shared/aboutSupport.css) + skin/classic/global/appPicker.css (../../shared/appPicker.css) skin/classic/global/arrow.css * skin/classic/global/autocomplete.css skin/classic/global/button.css diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 614831fdf9b..827806b2bce 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -23,7 +23,9 @@ #include "nsAppRunner.h" #include "mozilla/AppData.h" +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) #include "nsUpdateDriver.h" +#endif #include "ProfileReset.h" #ifdef MOZ_INSTRUMENT_EVENT_LOOP @@ -3718,7 +3720,7 @@ XREMain::XRE_mainStartup(bool* aExitFlag) } #endif -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) // Check for and process any available updates nsCOMPtr updRoot; bool persistent; diff --git a/toolkit/xre/nsUpdateDriver.h b/toolkit/xre/nsUpdateDriver.h index 6c6c0a520de..104b0520d24 100644 --- a/toolkit/xre/nsUpdateDriver.h +++ b/toolkit/xre/nsUpdateDriver.h @@ -8,13 +8,11 @@ #define nsUpdateDriver_h__ #include "nscore.h" -#ifdef MOZ_UPDATER #include "nsIUpdateService.h" #include "nsIThread.h" #include "nsCOMPtr.h" #include "nsString.h" #include "mozilla/Attributes.h" -#endif class nsIFile; @@ -57,7 +55,6 @@ nsresult ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *osApplyToDir = nullptr, ProcessType *pid = nullptr); -#ifdef MOZ_UPDATER // The implementation of the update processor handles the task of loading the // updater application for staging an update. // XXX ehsan this is living in this file in order to make use of the existing @@ -107,6 +104,4 @@ private: nsCOMPtr mProcessWatcher; StagedUpdateInfo mInfo; }; -#endif - #endif // nsUpdateDriver_h__ diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index f68f469224b..c2d1b522393 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -44,6 +44,7 @@ #include "MediaCodec.h" #include "SurfaceTexture.h" +#include "GLContextProvider.h" using namespace mozilla; using namespace mozilla::gfx; @@ -821,6 +822,8 @@ AndroidBridge::OpenGraphicsLibraries() ANativeWindow_setBuffersGeometry = (int (*)(void*, int, int, int)) dlsym(handle, "ANativeWindow_setBuffersGeometry"); ANativeWindow_lock = (int (*)(void*, void*, void*)) dlsym(handle, "ANativeWindow_lock"); ANativeWindow_unlockAndPost = (int (*)(void*))dlsym(handle, "ANativeWindow_unlockAndPost"); + ANativeWindow_getWidth = (int (*)(void*))dlsym(handle, "ANativeWindow_getWidth"); + ANativeWindow_getHeight = (int (*)(void*))dlsym(handle, "ANativeWindow_getHeight"); // This is only available in Honeycomb and ICS. It was removed in Jelly Bean ANativeWindow_fromSurfaceTexture = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurfaceTexture"); @@ -1275,6 +1278,16 @@ AndroidBridge::ReleaseNativeWindow(void *window) // have nothing to do here. We should probably ref it. } +IntSize +AndroidBridge::GetNativeWindowSize(void* window) +{ + if (!window || !ANativeWindow_getWidth || !ANativeWindow_getHeight) { + return IntSize(0, 0); + } + + return IntSize(ANativeWindow_getWidth(window), ANativeWindow_getHeight(window)); +} + void* AndroidBridge::AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurfaceTexture) { @@ -1508,7 +1521,9 @@ void AndroidBridge::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, floa } AndroidBridge::AndroidBridge() - : mLayerClient(nullptr) + : mLayerClient(nullptr), + mPresentationWindow(nullptr), + mPresentationSurface(nullptr) { } @@ -2036,6 +2051,51 @@ AndroidBridge::RunDelayedUiThreadTasks() return -1; } +void* +AndroidBridge::GetPresentationWindow() +{ + return mPresentationWindow; +} + +void +AndroidBridge::SetPresentationWindow(void* aPresentationWindow) +{ + if (mPresentationWindow) { + const bool wasAlreadyPaused = nsWindow::IsCompositionPaused(); + if (!wasAlreadyPaused) { + nsWindow::SchedulePauseComposition(); + } + + mPresentationWindow = aPresentationWindow; + if (mPresentationSurface) { + // destroy the egl surface! + // The compositor is paused so it should be okay to destroy + // the surface here. + mozilla::gl::GLContextProvider::DestroyEGLSurface(mPresentationSurface); + mPresentationSurface = nullptr; + } + + if (!wasAlreadyPaused) { + nsWindow::ScheduleResumeComposition(); + } + } + else { + mPresentationWindow = aPresentationWindow; + } +} + +EGLSurface +AndroidBridge::GetPresentationSurface() +{ + return mPresentationSurface; +} + +void +AndroidBridge::SetPresentationSurface(EGLSurface aPresentationSurface) +{ + mPresentationSurface = aPresentationSurface; +} + Object::LocalRef AndroidBridge::ChannelCreate(Object::Param stream) { JNIEnv* const env = GetJNIForThread(); auto rv = Object::LocalRef::Adopt(env, env->CallStaticObjectMethod( diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index c792d21731d..8e1aaf625d4 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -21,6 +21,7 @@ #include "nsIMIMEInfo.h" #include "nsColor.h" #include "gfxRect.h" +#include "mozilla/gfx/Point.h" #include "nsIAndroidBridge.h" #include "nsIMobileMessageCallback.h" @@ -264,6 +265,7 @@ public: void *AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface); void ReleaseNativeWindow(void *window); + mozilla::gfx::IntSize GetNativeWindowSize(void* window); void *AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurface); void ReleaseNativeWindowForSurfaceTexture(void *window); @@ -426,6 +428,8 @@ protected: int (* ANativeWindow_lock)(void *window, void *outBuffer, void *inOutDirtyBounds); int (* ANativeWindow_unlockAndPost)(void *window); + int (* ANativeWindow_getWidth)(void * window); + int (* ANativeWindow_getHeight)(void * window); int (* Surface_lock)(void* surface, void* surfaceInfo, void* region, bool block); int (* Surface_unlockAndPost)(void* surface); @@ -439,6 +443,15 @@ private: public: void PostTaskToUiThread(Task* aTask, int aDelayMs); int64_t RunDelayedUiThreadTasks(); + + void* GetPresentationWindow(); + void SetPresentationWindow(void* aPresentationWindow); + + EGLSurface GetPresentationSurface(); + void SetPresentationSurface(EGLSurface aPresentationSurface); +private: + void* mPresentationWindow; + EGLSurface mPresentationSurface; }; class AutoJNIClass { diff --git a/widget/android/AndroidJNI.cpp b/widget/android/AndroidJNI.cpp index dbd177df453..3200c8c7942 100644 --- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -811,6 +811,27 @@ cleanup: return surfaceBits; } +NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface(JNIEnv* jenv, jclass, jobject surface) +{ + if (surface != NULL) { + void* window = AndroidBridge::Bridge()->AcquireNativeWindow(jenv, surface); + if (window) { + AndroidBridge::Bridge()->SetPresentationWindow(window); + } + } +} + +NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface(JNIEnv* jenv, jclass, jobject surface) +{ + void* window = AndroidBridge::Bridge()->GetPresentationWindow(); + if (window) { + AndroidBridge::Bridge()->SetPresentationWindow(nullptr); + AndroidBridge::Bridge()->ReleaseNativeWindow(window); + } +} + NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden(JNIEnv* jenv, jclass, jobject view) { diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 028b7e55f40..1a432c8c150 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2454,6 +2454,29 @@ nsWindow::ScheduleComposite() } } +bool +nsWindow::IsCompositionPaused() +{ + return sCompositorPaused; +} + +void +nsWindow::SchedulePauseComposition() +{ + if (sCompositorParent) { + sCompositorParent->SchedulePauseOnCompositorThread(); + sCompositorPaused = true; + } +} + +void +nsWindow::ScheduleResumeComposition() +{ + if (sCompositorParent && sCompositorParent->ScheduleResumeOnCompositorThread()) { + sCompositorPaused = false; + } +} + void nsWindow::ScheduleResumeComposition(int width, int height) { diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index d3915089f93..648abca0dc9 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -156,7 +156,10 @@ public: static void SetCompositor(mozilla::layers::LayerManager* aLayerManager, mozilla::layers::CompositorParent* aCompositorParent, mozilla::layers::CompositorChild* aCompositorChild); + static bool IsCompositionPaused(); static void ScheduleComposite(); + static void SchedulePauseComposition(); + static void ScheduleResumeComposition(); static void ScheduleResumeComposition(int width, int height); static void ForceIsFirstPaint(); static float ComputeRenderIntegrity();