diff --git a/browser/base/content/aboutNetError.xhtml b/browser/base/content/aboutNetError.xhtml new file mode 100644 index 0000000000..e07e031d79 --- /dev/null +++ b/browser/base/content/aboutNetError.xhtml @@ -0,0 +1,381 @@ + + + + %htmlDTD; + + %netErrorDTD; + + %globalDTD; +]> + + + + + + &loadError.label; + + + + + + + + + + +
+
+

&generic.title;

+

&dnsNotFound.title;

+

&fileNotFound.title;

+

&malformedURI.title;

+

&unknownProtocolFound.title;

+

&connectionFailure.title;

+

&netTimeout.title;

+

&redirectLoop.title;

+

&unknownSocketType.title;

+

&netReset.title;

+

¬Cached.title;

+

&netOffline.title;

+

&netInterrupt.title;

+

&deniedPortAccess.title;

+

&proxyResolveFailure.title;

+

&proxyConnectFailure.title;

+

&contentEncodingError.title;

+

&unsafeContentType.title;

+

&nssFailure2.title;

+

&nssBadCert.title;

+

&malwareBlocked.title;

+

&cspBlocked.title;

+

&remoteXUL.title;

+

&corruptedContentError.title;

+
+
+
&generic.longDesc;
+
&dnsNotFound.longDesc;
+
&fileNotFound.longDesc;
+
&malformedURI.longDesc;
+
&unknownProtocolFound.longDesc;
+
&connectionFailure.longDesc;
+
&netTimeout.longDesc;
+
&redirectLoop.longDesc;
+
&unknownSocketType.longDesc;
+
&netReset.longDesc;
+
¬Cached.longDesc;
+
&netOffline.longDesc2;
+
&netInterrupt.longDesc;
+
&deniedPortAccess.longDesc;
+
&proxyResolveFailure.longDesc;
+
&proxyConnectFailure.longDesc;
+
&contentEncodingError.longDesc;
+
&unsafeContentType.longDesc;
+
&nssFailure2.longDesc2;
+
&nssBadCert.longDesc2;
+
&malwareBlocked.longDesc;
+
&cspBlocked.longDesc;
+
&remoteXUL.longDesc;
+
&corruptedContentError.longDesc;
+
+
+ + +
+ + +
+

+

+ + +
+ + +
+

+

+ + +
+ + +
+ &securityOverride.linkText; + +
+
+ + + + + +
+ + + + + + diff --git a/browser/base/content/aboutneterror/netError.css b/browser/base/content/aboutneterror/netError.css new file mode 100644 index 0000000000..f875d09ae6 --- /dev/null +++ b/browser/base/content/aboutneterror/netError.css @@ -0,0 +1,76 @@ +/* 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/. */ + +@import url("chrome://browser/skin/in-content/common.css"); + +body { + display: flex; + box-sizing: padding-box; + min-height: 100vh; + padding: 0 48px; + align-items: center; + justify-content: center; +} + +ul, ol { + margin: 0; + padding: 0; + -moz-margin-start: 1em; +} + +ul > li, ol > li { + margin-bottom: .5em; +} + +ul { + list-style: disc; +} + +#errorPageContainer { + min-width: 320px; + max-width: 512px; +} + +#errorTitle { + background: url("info.svg") left 0 no-repeat; + background-size: 3em 3em; + -moz-margin-start: -5em; + -moz-padding-start: 5em; +} + +#errorTitle:-moz-locale-dir(rtl) { + background-position: right 0; +} + +#errorTryAgain { + margin-top: 1.2em; +} + +#errorContainer { + display: none; +} + +@media (max-width: 675px) { + #errorTitle { + padding-top: 0; + background-image: none; + -moz-padding-start: 0; + -moz-margin-start: 0; + } +} + + +/* common.css overrides */ + +button { + font-size: 1em; + min-width: 150px; +} + +/* Pressing the retry button will cause the cursor to flicker from a pointer to + * not-allowed. Override the disabled cursor behaviour since we will never show + * the button disabled as the initial state. */ +button:disabled { + cursor: pointer; +} diff --git a/browser/base/jar.mn b/browser/base/jar.mn index b9fc3b4063..fb2207ac08 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -43,6 +43,7 @@ browser.jar: content/browser/abouthome/settings@2x.png (content/abouthome/settings@2x.png) content/browser/abouthome/restore@2x.png (content/abouthome/restore@2x.png) content/browser/abouthome/restore-large@2x.png (content/abouthome/restore-large@2x.png) + content/browser/aboutNetError.xhtml (content/aboutNetError.xhtml) content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png) content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png) content/browser/autorecovery.js (content/autorecovery.js) @@ -129,3 +130,5 @@ browser.jar: # the following files are browser-specific overrides * content/browser/license.html (/toolkit/content/license.html) % override chrome://global/content/license.html chrome://browser/content/license.html + +% override chrome://global/content/netError.xhtml chrome://browser/content/aboutNetError.xhtml diff --git a/browser/branding/shared/pref/uaoverrides.inc b/browser/branding/shared/pref/uaoverrides.inc index f8ac4e5852..85f51aab7a 100644 --- a/browser/branding/shared/pref/uaoverrides.inc +++ b/browser/branding/shared/pref/uaoverrides.inc @@ -29,12 +29,11 @@ pref("@GUAO_PREF@.outlook.com","Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION@) @GK_SLI pref("@GUAO_PREF@.web.de","Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@ (Pale Moon)"); pref("@GUAO_PREF@.aol.com","Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@ (Pale Moon)"); pref("@GUAO_PREF@.calendar.yahoo.com","Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@ (Pale Moon)"); -pref("@GUAO_PREF@.google.com","Mozilla/5.0 (@OS_SLICE@ rv:52.9) @GK_SLICE@ @GRE_VERSION_SLICE@ Firefox/52.9 @PM_SLICE@"); -pref("@GUAO_PREF@.googlevideos.com","Mozilla/5.0 (@OS_SLICE@ rv:38.9) @GK_SLICE@ @GRE_VERSION_SLICE@ Firefox/38.9 @PM_SLICE@"); -pref("@GUAO_PREF@.gstatic.com","Mozilla/5.0 (@OS_SLICE@ rv:31.9) @GK_SLICE@ @GRE_VERSION_SLICE@ Firefox/31.9 @PM_SLICE@"); -pref("@GUAO_PREF@.yahoo.com","Mozilla/5.0 (@OS_SLICE@ rv:99.9) @GK_SLICE@ Firefox/99.9 (Pale Moon)"); -pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (@OS_SLICE@ rv:42.0) @GK_SLICE@ Firefox/42.0 @PM_SLICE@"); -pref("@GUAO_PREF@.gaming.youtube.com","Mozilla/5.0 (@OS_SLICE@ rv:42.0) @GK_SLICE@ Firefox/42.0"); +pref("@GUAO_PREF@.google.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) Gecko/20010101 @GRE_VERSION_SLICE@ Firefox/52.0 @PM_SLICE@"); +pref("@GUAO_PREF@.googlevideos.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) Gecko/20010101 @GRE_VERSION_SLICE@ Firefox/52.0 @PM_SLICE@"); +pref("@GUAO_PREF@.gstatic.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) Gecko/20010101 @GRE_VERSION_SLICE@ Firefox/52.0 @PM_SLICE@"); +// now YouTube needs to be fooled too +pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) Gecko/20010101 Firefox/52.0 @PM_SLICE@"); pref("@GUAO_PREF@.dropbox.com","Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko"); pref("@GUAO_PREF@.players.brightcove.net","Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko"); @@ -71,6 +70,9 @@ pref("@GUAO_PREF@.citi.com","Mozilla/5.0 (@OS_SLICE@ rv:57.0) @GK_SLICE@ Firefox pref("@GUAO_PREF@.netflix.com","Mozilla/5.0 (@OS_SLICE@ rv:45.9) @GK_SLICE@ Firefox/45.9"); pref("@GUAO_PREF@.netflximg.net","Mozilla/5.0 (@OS_SLICE@ rv:45.9) @GK_SLICE@ Firefox/45.9"); +// yahoo is nasty too +pref("@GUAO_PREF@.yahoo.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) @GK_SLICE@ @GRE_VERSION_SLICE@ Firefox/52.0"); + // get good old twitter interface back pref("@GUAO_PREF@.twitter.com","Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.18"); diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index 982e3a3506..28dd85fef4 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -80,8 +80,8 @@ const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; // We try to backup bookmarks at idle times, to avoid doing that at shutdown. -// Number of idle seconds before trying to backup bookmarks. 15 minutes. -const BOOKMARKS_BACKUP_IDLE_TIME = 15 * 60; +// Number of idle seconds before trying to backup bookmarks. 10 minutes. +const BOOKMARKS_BACKUP_IDLE_TIME = 10 * 60; // Minimum interval in milliseconds between backups. const BOOKMARKS_BACKUP_INTERVAL = 86400 * 1000; // Maximum number of backups to create. Old ones will be purged. @@ -256,8 +256,7 @@ BrowserGlue.prototype = { this._onPlacesShutdown(); break; case "idle": - if ((this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000) && - this._shouldBackupBookmarks()) + if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000) this._backupBookmarks(); break; case "distribution-customization-complete": @@ -1035,19 +1034,18 @@ BrowserGlue.prototype = { Services.prefs.getBoolPref("browser.bookmarks.restore_default_bookmarks"); if (restoreDefaultBookmarks) { // Ensure that we already have a bookmarks backup for today. - if (this._shouldBackupBookmarks()) - yield this._backupBookmarks(); + yield this._backupBookmarks(); importBookmarks = true; } } catch(ex) {} // If the user did not require to restore default bookmarks, or import - // from bookmarks.html, we will try to restore from JSON/JSONLZ4 + // from bookmarks.html, we will try to restore from JSON if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) { - // get latest JSON/JSONLZ4 backup + // get latest JSON backup var bookmarksBackupFile = yield PlacesBackups.getMostRecentBackup(); if (bookmarksBackupFile) { - // restore from JSON/JSONLZ4 backup + // restore from JSON backup yield BookmarkJSONUtils.importFromFile(bookmarksBackupFile, true); importBookmarks = false; } @@ -1188,22 +1186,19 @@ BrowserGlue.prototype = { } let waitingForBackupToComplete = true; - if (this._shouldBackupBookmarks()) { - waitingForBackupToComplete = false; - this._backupBookmarks().then( - function onSuccess() { - waitingForBackupToComplete = true; - }, - function onFailure() { - Cu.reportError("Unable to backup bookmarks."); - waitingForBackupToComplete = true; - } - ); - } + this._backupBookmarks().then( + function onSuccess() { + waitingForBackupToComplete = false; + }, + function onFailure() { + Cu.reportError("Unable to backup bookmarks."); + waitingForBackupToComplete = false; + } + ); // Backup bookmarks to bookmarks.html to support apps that depend // on the legacy format. - let waitingForHTMLExportToComplete = true; + let waitingForHTMLExportToComplete = false; // If this fails to get the preference value, we don't export. if (Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML")) { // Exceptionally, since this is a non-default setting and HTML format is @@ -1215,48 +1210,41 @@ BrowserGlue.prototype = { waitingForHTMLExportToComplete = false; BookmarkHTMLUtils.exportToFile(BookmarkHTMLUtils.defaultPath).then( function onSuccess() { - waitingForHTMLExportToComplete = true; + waitingForHTMLExportToComplete = false; }, function onFailure() { Cu.reportError("Unable to auto export html."); - waitingForHTMLExportToComplete = true; + waitingForHTMLExportToComplete = false; } ); } + // The events loop should spin at least once because waitingForBackupToComplete + // is true before checking whether backup should be made. let thread = Services.tm.currentThread; - while (!waitingForBackupToComplete || !waitingForHTMLExportToComplete) { + while (waitingForBackupToComplete || waitingForHTMLExportToComplete) { thread.processNextEvent(true); } }, - /** - * Determine whether to backup bookmarks or not. - * @return true if bookmarks should be backed up, false if not. - */ - _shouldBackupBookmarks: function BG__shouldBackupBookmarks() { - let lastBackupFile = PlacesBackups.getMostRecent(); - - // Should backup bookmarks if there are no backups or the maximum interval between - // backups elapsed. - return (!lastBackupFile || - new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL); - }, - /** * Backup bookmarks. */ _backupBookmarks: function BG__backupBookmarks() { return Task.spawn(function() { - // Backup bookmarks if there are no backups or the maximum interval between - // backups elapsed. - let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS; - try { - maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups"); - } - catch(ex) { /* Use default. */ } + let lastBackupFile = yield PlacesBackups.getMostRecentBackup(); + // Should backup bookmarks if there are no backups or the maximum + // interval between backups elapsed. + if (!lastBackupFile || + new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL) { + let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS; + try { + maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups"); + } + catch(ex) { /* Use default. */ } - yield PlacesBackups.create(maxBackups); // Don't force creation. + yield PlacesBackups.create(maxBackups); // Don't force creation. + } }); }, diff --git a/browser/themes/linux/jar.mn b/browser/themes/linux/jar.mn index e97c1f866b..a8dceb668c 100644 --- a/browser/themes/linux/jar.mn +++ b/browser/themes/linux/jar.mn @@ -13,6 +13,8 @@ browser.jar: skin/classic/browser/aboutCertError_sectionCollapsed.png skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png skin/classic/browser/aboutCertError_sectionExpanded.png + skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css) + skin/classic/browser/aboutNetError_info.svg (../shared/aboutNetError_info.svg) #ifdef MOZ_SERVICES_SYNC skin/classic/browser/aboutSyncTabs.css #endif @@ -33,6 +35,7 @@ browser.jar: skin/classic/browser/identity-icons-https-ev.png skin/classic/browser/identity-icons-https-mixed-active.png skin/classic/browser/Info.png + skin/classic/browser/in-content/common.css (../shared/in-content/common.css) skin/classic/browser/KUI-close.png skin/classic/browser/mixed-content-blocked-16.png skin/classic/browser/mixed-content-blocked-64.png diff --git a/browser/themes/moz.build b/browser/themes/moz.build index d82bda3efb..5040c10c15 100644 --- a/browser/themes/moz.build +++ b/browser/themes/moz.build @@ -12,4 +12,3 @@ elif toolkit in ('gtk2', 'gtk3', 'qt'): DIRS += ['linux'] else: DIRS += ['windows'] - diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn index b8e866db4e..b0ed2444bb 100644 --- a/browser/themes/osx/jar.mn +++ b/browser/themes/osx/jar.mn @@ -5,6 +5,7 @@ browser.jar: % skin browser classic/1.0 %skin/classic/browser/ skin/classic/browser/sanitizeDialog.css + skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css) * skin/classic/browser/aboutPrivateBrowsing.css * skin/classic/browser/aboutSessionRestore.css skin/classic/browser/aboutSessionRestore-window-icon.png (preferences/application.png) @@ -29,6 +30,7 @@ browser.jar: skin/classic/browser/Push-64.png skin/classic/browser/Push-64@2x.png skin/classic/browser/Info.png + skin/classic/browser/in-content/common.css (../shared/in-content/common.css) skin/classic/browser/identity.png skin/classic/browser/imagedocument.png skin/classic/browser/identity-icons-generic.png diff --git a/browser/themes/shared/aboutNetError.css b/browser/themes/shared/aboutNetError.css new file mode 100644 index 0000000000..71da6fbf79 --- /dev/null +++ b/browser/themes/shared/aboutNetError.css @@ -0,0 +1,69 @@ +/* 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/. */ + +@import url("chrome://global/skin/in-content/common.css"); + +body { + display: flex; + box-sizing: padding-box; + min-height: 100vh; + padding: 0 48px; + align-items: center; + justify-content: center; +} + +ul, ol { + margin: 0; + padding: 0; + -moz-margin-start: 1em; +} + +ul > li, ol > li { + margin-bottom: .5em; +} + +ul { + list-style: disc; +} + +#errorPageContainer { + min-width: 320px; + max-width: 512px; +} + +#errorTitleText { + background: url("aboutNetError_info.svg") left 0 no-repeat; + background-size: 1.2em; + -moz-margin-start: -2em; + -moz-padding-start: 2em; +} + +#errorTitleText:-moz-dir(rtl) { + background-position: right 0; +} + +#errorTryAgain { + margin-top: 1.2em; + min-width: 150px +} + +#errorContainer { + display: none; +} + +@media (max-width: 675px) { + #errorTitleText { + padding-top: 0; + background-image: none; + -moz-padding-start: 0; + -moz-margin-start: 0; + } +} + +/* Pressing the retry button will cause the cursor to flicker from a pointer to + * not-allowed. Override the disabled cursor behaviour since we will never show + * the button disabled as the initial state. */ +button:disabled { + cursor: pointer; +} diff --git a/browser/themes/shared/aboutNetError_info.svg b/browser/themes/shared/aboutNetError_info.svg new file mode 100644 index 0000000000..2d3e564b8e --- /dev/null +++ b/browser/themes/shared/aboutNetError_info.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/browser/themes/shared/in-content/common.css b/browser/themes/shared/in-content/common.css new file mode 100644 index 0000000000..d6b6e85c9f --- /dev/null +++ b/browser/themes/shared/in-content/common.css @@ -0,0 +1,56 @@ +/* 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/. */ + +body { + font: message-box; + font-size: 15px; + font-weight: normal; + margin: 0; + color: #737980; + background-image: linear-gradient(#fff, #ededed 100px); +} + +h1 { + font-size: 2.5em; + font-weight: lighter; + line-height: 1.2; + margin: 0; + margin-bottom: .5em; +} + +button { + line-height: 20px; + height: 30px; + max-height: 30px; + padding: 3px; + color: #737980; + border: 1px solid rgba(23,50,77,.4); + border-radius: 5px; + background-color: #f1f1f1; + background-image: linear-gradient(#fff, rgba(255,255,255,.1)); + box-shadow: 0 1px 1px 0 #fff, inset 0 2px 2px 0 #fff; + text-shadow: 0 1px 1px #fefffe; + -moz-appearance: none; + -moz-border-top-colors: none !important; + -moz-border-right-colors: none !important; + -moz-border-bottom-colors: none !important; + -moz-border-left-colors: none !important; +} + +button:enabled:hover { + background-image: linear-gradient(#fff, rgba(255,255,255,.6)); + cursor: pointer; +} + +button:enabled:hover:active { + background-image: linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.6)); +} + +button:disabled { + cursor: not-allowed; + color: rgba(115,121,128,.5); + border-color: rgba(23,50,77,.25); + background-image: linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.1)); + text-shadow: 0 1px 1px #fff; +} diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn index e1097fe1d3..136fd6a5c8 100644 --- a/browser/themes/windows/jar.mn +++ b/browser/themes/windows/jar.mn @@ -12,6 +12,8 @@ browser.jar: skin/classic/browser/aboutCertError_sectionCollapsed.png skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png skin/classic/browser/aboutCertError_sectionExpanded.png + skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css) + skin/classic/browser/aboutNetError_info.svg (../shared/aboutNetError_info.svg) #ifdef MOZ_SERVICES_SYNC skin/classic/browser/aboutSyncTabs.css #endif @@ -29,6 +31,7 @@ browser.jar: skin/classic/browser/Push-16.png skin/classic/browser/Push-64.png skin/classic/browser/Info.png + skin/classic/browser/in-content/common.css (../shared/in-content/common.css) skin/classic/browser/identity.png skin/classic/browser/imagedocument.png skin/classic/browser/identity-icons-generic.png diff --git a/dom/base/SameProcessMessageQueue.cpp b/dom/base/SameProcessMessageQueue.cpp new file mode 100644 index 0000000000..cc5097190e --- /dev/null +++ b/dom/base/SameProcessMessageQueue.cpp @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SameProcessMessageQueue.h" + +using namespace mozilla; +using namespace mozilla::dom; + +SameProcessMessageQueue* SameProcessMessageQueue::sSingleton; + +SameProcessMessageQueue::SameProcessMessageQueue() +{ +} + +SameProcessMessageQueue::~SameProcessMessageQueue() +{ + // This code should run during shutdown, and we should already have pumped the + // event loop. So we should only see messages here if someone is sending + // messages pretty late in shutdown. + NS_WARN_IF_FALSE(mQueue.IsEmpty(), "Shouldn't send messages during shutdown"); + sSingleton = nullptr; +} + +void +SameProcessMessageQueue::Push(Runnable* aRunnable) +{ + mQueue.AppendElement(aRunnable); + NS_DispatchToCurrentThread(aRunnable); +} + +void +SameProcessMessageQueue::Flush() +{ + nsTArray> queue; + mQueue.SwapElements(queue); + for (size_t i = 0; i < queue.Length(); i++) { + queue[i]->Run(); + } +} + +/* static */ SameProcessMessageQueue* +SameProcessMessageQueue::Get() +{ + if (!sSingleton) { + sSingleton = new SameProcessMessageQueue(); + } + return sSingleton; +} + +SameProcessMessageQueue::Runnable::Runnable() + : mDispatched(false) +{ +} + +NS_IMPL_ISUPPORTS(SameProcessMessageQueue::Runnable, nsIRunnable) + +nsresult +SameProcessMessageQueue::Runnable::Run() +{ + if (mDispatched) { + return NS_OK; + } + + SameProcessMessageQueue* queue = SameProcessMessageQueue::Get(); + queue->mQueue.RemoveElement(this); + + mDispatched = true; + return HandleMessage(); +} diff --git a/dom/base/SameProcessMessageQueue.h b/dom/base/SameProcessMessageQueue.h new file mode 100644 index 0000000000..565ec54a48 --- /dev/null +++ b/dom/base/SameProcessMessageQueue.h @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_SameProcessMessageQueue_h +#define mozilla_dom_SameProcessMessageQueue_h + +#include "nsIRunnable.h" +#include "mozilla/RefPtr.h" +#include "nsTArray.h" + +namespace mozilla { +namespace dom { + +class CancelableRunnable; + +class SameProcessMessageQueue +{ +public: + SameProcessMessageQueue(); + virtual ~SameProcessMessageQueue(); + + class Runnable : public nsIRunnable + { + public: + explicit Runnable(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + + virtual nsresult HandleMessage() = 0; + + protected: + virtual ~Runnable() {} + + private: + bool mDispatched; + }; + + void Push(Runnable* aRunnable); + void Flush(); + + static SameProcessMessageQueue* Get(); + +private: + friend class CancelableRunnable; + + nsTArray> mQueue; + static SameProcessMessageQueue* sSingleton; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_SameProcessMessageQueue_h diff --git a/dom/base/ThirdPartyUtil.cpp b/dom/base/ThirdPartyUtil.cpp index 4a8014f7bd..f52834f005 100644 --- a/dom/base/ThirdPartyUtil.cpp +++ b/dom/base/ThirdPartyUtil.cpp @@ -9,6 +9,7 @@ #include "nsIServiceManager.h" #include "nsIHttpChannelInternal.h" #include "nsIDOMWindow.h" +#include "nsPIDOMWindow.h" // rmottola - HACK - get build again, not needed in FF tree #include "nsILoadContext.h" #include "nsIPrincipal.h" #include "nsIScriptObjectPrincipal.h" diff --git a/dom/base/moz.build b/dom/base/moz.build index 3f240a7775..8992f6279a 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -192,6 +192,7 @@ EXPORTS.mozilla.dom += [ 'PerformanceResourceTiming.h', 'ProcessGlobal.h', 'ResponsiveImageSelector.h', + 'SameProcessMessageQueue.h', 'ScreenOrientation.h', 'ScriptSettings.h', 'ShadowRoot.h', @@ -329,6 +330,7 @@ UNIFIED_SOURCES += [ 'PerformanceResourceTiming.cpp', 'ProcessGlobal.cpp', 'ResponsiveImageSelector.cpp', + 'SameProcessMessageQueue.cpp', 'ScriptSettings.cpp', 'ShadowRoot.cpp', 'StyleSheetList.cpp', diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index a71f002721..7313c5e468 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -1381,6 +1381,9 @@ nsFrameLoader::StartDestroy() if (mRemoteBrowser) { mRemoteBrowser->CacheFrameLoader(this); } + if (mChildMessageManager) { + mChildMessageManager->CacheFrameLoader(this); + } } nsCOMPtr doc; @@ -1518,6 +1521,9 @@ nsFrameLoader::DestroyComplete() if (mRemoteBrowser) { mRemoteBrowser->CacheFrameLoader(nullptr); } + if (mChildMessageManager) { + mChildMessageManager->CacheFrameLoader(nullptr); + } } // Call TabParent::Destroy if we haven't already (in case of a crash). @@ -2427,7 +2433,7 @@ public: static_cast(mFrameLoader->mChildMessageManager.get()); if (tabChild && tabChild->GetInnerManager()) { nsCOMPtr kungFuDeathGrip(tabChild->GetGlobal()); - ReceiveMessage(static_cast(tabChild), + ReceiveMessage(static_cast(tabChild), mFrameLoader, tabChild->GetInnerManager()); } return NS_OK; diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index bd9e9cd888..2fef95bf36 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -35,6 +35,7 @@ #include "mozilla/dom/nsIContentParent.h" #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/dom/ProcessGlobal.h" +#include "mozilla/dom/SameProcessMessageQueue.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/StructuredCloneUtils.h" #include "mozilla/dom/ipc/BlobChild.h" @@ -980,6 +981,7 @@ public: nsresult nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, + nsIFrameLoader* aTargetFrameLoader, const nsAString& aMessage, bool aIsSync, const StructuredCloneData* aCloneData, @@ -987,12 +989,13 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal) { - return ReceiveMessage(aTarget, mClosed, aMessage, aIsSync, + return ReceiveMessage(aTarget, aTargetFrameLoader, mClosed, aMessage, aIsSync, aCloneData, aCpows, aPrincipal, aJSONRetVal); } nsresult nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, + nsIFrameLoader* aTargetFrameLoader, bool aTargetClosed, const nsAString& aMessage, bool aIsSync, @@ -1099,6 +1102,16 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, JS_DefineProperty(cx, param, "objects", cpowsv, JSPROP_ENUMERATE); NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED); + if (aTargetFrameLoader) { + JS::Rooted targetFrameLoaderv(cx); + nsresult rv = nsContentUtils::WrapNative(cx, aTargetFrameLoader, &targetFrameLoaderv); + NS_ENSURE_SUCCESS(rv, rv); + + ok = JS_DefineProperty(cx, param, "targetFrameLoader", targetFrameLoaderv, + JSPROP_ENUMERATE); + NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED); + } + // message.principal == null if (!aPrincipal) { bool ok = JS_DefineProperty(cx, param, "principal", @@ -1175,7 +1188,8 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, } } nsRefPtr kungfuDeathGrip = mParentManager; - return mParentManager ? mParentManager->ReceiveMessage(aTarget, aTargetClosed, aMessage, + return mParentManager ? mParentManager->ReceiveMessage(aTarget, aTargetFrameLoader, + aTargetClosed, aMessage, aIsSync, aCloneData, aCpows, aPrincipal, aJSONRetVal) : NS_OK; @@ -1736,7 +1750,6 @@ NS_IMPL_ISUPPORTS(nsScriptCacheCleaner, nsIObserver) nsFrameMessageManager* nsFrameMessageManager::sChildProcessManager = nullptr; nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr; nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr; -nsTArray >* nsFrameMessageManager::sPendingSameProcessAsyncMessages = nullptr; class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase, public nsRunnable @@ -1754,7 +1767,7 @@ public: NS_IMETHOD Run() { nsFrameMessageManager* ppm = nsFrameMessageManager::GetChildProcessManager(); - ReceiveMessage(static_cast(ppm), ppm); + ReceiveMessage(static_cast(ppm), nullptr, ppm); return NS_OK; } }; @@ -1894,7 +1907,7 @@ public: class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase, - public nsRunnable + public SameProcessMessageQueue::Runnable { public: nsAsyncMessageToSameProcessParent(JSContext* aCx, @@ -1903,25 +1916,15 @@ public: JS::Handle aCpows, nsIPrincipal* aPrincipal) : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal) - , mDelivered(false) { } - NS_IMETHOD Run() + virtual nsresult HandleMessage() override { - if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) { - nsFrameMessageManager::sPendingSameProcessAsyncMessages->RemoveElement(this); - } - if (!mDelivered) { - mDelivered = true; - nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager; - ReceiveMessage(static_cast(ppm), ppm); - } + nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager; + ReceiveMessage(static_cast(ppm), nullptr, ppm); return NS_OK; } - -private: - bool mDelivered; }; /** @@ -1947,19 +1950,13 @@ public: InfallibleTArray* aJSONRetVal, bool aIsSync) override { - nsTArray > asyncMessages; - if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) { - asyncMessages.SwapElements(*nsFrameMessageManager::sPendingSameProcessAsyncMessages); - uint32_t len = asyncMessages.Length(); - for (uint32_t i = 0; i < len; ++i) { - nsCOMPtr async = asyncMessages[i]; - async->Run(); - } - } + SameProcessMessageQueue* queue = SameProcessMessageQueue::Get(); + queue->Flush(); + if (nsFrameMessageManager::sSameProcessParentManager) { SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows); nsRefPtr ppm = nsFrameMessageManager::sSameProcessParentManager; - ppm->ReceiveMessage(static_cast(ppm.get()), aMessage, + ppm->ReceiveMessage(static_cast(ppm.get()), nullptr, aMessage, true, &aData, &cpows, aPrincipal, aJSONRetVal); } return true; @@ -1971,13 +1968,10 @@ public: JS::Handle aCpows, nsIPrincipal* aPrincipal) override { - if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) { - nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray >; - } - nsCOMPtr ev = + SameProcessMessageQueue* queue = SameProcessMessageQueue::Get(); + nsRefPtr ev = new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows, aPrincipal); - nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev); - NS_DispatchToCurrentThread(ev); + queue->Push(ev); return true; } @@ -2091,6 +2085,7 @@ nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx, void nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget, + nsIFrameLoader* aTargetFrameLoader, nsFrameMessageManager* aManager) { if (aManager) { @@ -2102,7 +2097,7 @@ nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget, SameProcessCpowHolder cpows(mRuntime, mCpows); nsRefPtr mm = aManager; - mm->ReceiveMessage(aTarget, mMessage, false, &data, &cpows, + mm->ReceiveMessage(aTarget, aTargetFrameLoader, mMessage, false, &data, &cpows, mPrincipal, nullptr); } } diff --git a/dom/base/nsFrameMessageManager.h b/dom/base/nsFrameMessageManager.h index bdd1fa8e15..d25a8eddbf 100644 --- a/dom/base/nsFrameMessageManager.h +++ b/dom/base/nsFrameMessageManager.h @@ -27,9 +27,12 @@ #include "mozilla/Attributes.h" #include "js/RootingAPI.h" #include "nsTObserverArray.h" +#include "mozilla/dom/SameProcessMessageQueue.h" #include "mozilla/dom/StructuredCloneUtils.h" #include "mozilla/jsipc/CpowHolder.h" +class nsIFrameLoader; + namespace mozilla { namespace dom { @@ -203,8 +206,7 @@ private: } if (this == sChildProcessManager) { sChildProcessManager = nullptr; - delete sPendingSameProcessAsyncMessages; - sPendingSameProcessAsyncMessages = nullptr; + delete mozilla::dom::SameProcessMessageQueue::Get(); } if (this == sSameProcessParentManager) { sSameProcessParentManager = nullptr; @@ -229,7 +231,8 @@ public: static nsFrameMessageManager* NewProcessMessageManager(bool aIsRemote); - nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage, + nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader, + const nsAString& aMessage, bool aIsSync, const StructuredCloneData* aCloneData, mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal); @@ -293,7 +296,8 @@ private: JS::MutableHandle aRetval, bool aIsSync); - nsresult ReceiveMessage(nsISupports* aTarget, bool aTargetClosed, const nsAString& aMessage, + nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader, + bool aTargetClosed, const nsAString& aMessage, bool aIsSync, const StructuredCloneData* aCloneData, mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal); @@ -369,7 +373,8 @@ public: JS::Handle aCpows, nsIPrincipal* aPrincipal); - void ReceiveMessage(nsISupports* aTarget, nsFrameMessageManager* aManager); + void ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader, + nsFrameMessageManager* aManager); private: nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&); diff --git a/dom/base/nsIMessageManager.idl b/dom/base/nsIMessageManager.idl index fdb926485e..012a3cb33e 100644 --- a/dom/base/nsIMessageManager.idl +++ b/dom/base/nsIMessageManager.idl @@ -8,6 +8,7 @@ interface nsIDOMWindow; interface nsIDocShell; interface nsIContent; +interface nsIFrameLoader; interface nsIPrincipal; /** @@ -383,10 +384,11 @@ interface nsIContentFrameMessageManager : nsIMessageManagerGlobal readonly attribute nsIDocShell docShell; }; -[uuid(a9e07e89-7125-48e3-bf73-2cbae7fc5b1c)] +[uuid(9c6bd4d7-88d2-46d6-8606-f2d57d46f051)] interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager { [notxpcom] nsIContent getOwnerContent(); + [notxpcom] void cacheFrameLoader(in nsIFrameLoader aFrameLoader); }; [scriptable, builtinclass, uuid(d0c799a2-d5ff-4a75-acbb-b8c8347944a6)] diff --git a/dom/base/nsInProcessTabChildGlobal.cpp b/dom/base/nsInProcessTabChildGlobal.cpp index 06e7b9468e..087df5e289 100644 --- a/dom/base/nsInProcessTabChildGlobal.cpp +++ b/dom/base/nsInProcessTabChildGlobal.cpp @@ -19,6 +19,7 @@ #include "nsIMozBrowserFrame.h" #include "nsDOMClassInfoID.h" #include "mozilla/EventDispatcher.h" +#include "mozilla/dom/SameProcessMessageQueue.h" #include "mozilla/dom/StructuredCloneUtils.h" #include "js/StructuredClone.h" @@ -35,24 +36,21 @@ nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx, InfallibleTArray* aJSONRetVal, bool aIsSync) { - nsTArray > asyncMessages; - asyncMessages.SwapElements(mASyncMessages); - uint32_t len = asyncMessages.Length(); - for (uint32_t i = 0; i < len; ++i) { - nsCOMPtr async = asyncMessages[i]; - async->Run(); - } + SameProcessMessageQueue* queue = SameProcessMessageQueue::Get(); + queue->Flush(); + if (mChromeMessageManager) { SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows); nsRefPtr mm = mChromeMessageManager; - mm->ReceiveMessage(mOwner, aMessage, true, &aData, &cpows, aPrincipal, + nsCOMPtr fl = GetFrameLoader(); + mm->ReceiveMessage(mOwner, fl, aMessage, true, &aData, &cpows, aPrincipal, aJSONRetVal); } return true; } class nsAsyncMessageToParent : public nsSameProcessAsyncMessageBase, - public nsRunnable + public SameProcessMessageQueue::Runnable { public: nsAsyncMessageToParent(JSContext* aCx, @@ -62,25 +60,17 @@ public: JS::Handle aCpows, nsIPrincipal* aPrincipal) : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal), - mTabChild(aTabChild), mRun(false) + mTabChild(aTabChild) { } - NS_IMETHOD Run() + virtual nsresult HandleMessage() override { - if (mRun) { - return NS_OK; - } - - mRun = true; - mTabChild->mASyncMessages.RemoveElement(this); - ReceiveMessage(mTabChild->mOwner, mTabChild->mChromeMessageManager); + nsCOMPtr fl = mTabChild->GetFrameLoader(); + ReceiveMessage(mTabChild->mOwner, fl, mTabChild->mChromeMessageManager); return NS_OK; } nsRefPtr mTabChild; - // True if this runnable has already been called. This can happen if DoSendSyncMessage - // is called while waiting for an asynchronous message send. - bool mRun; }; bool @@ -90,10 +80,10 @@ nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx, JS::Handle aCpows, nsIPrincipal* aPrincipal) { - nsCOMPtr ev = + SameProcessMessageQueue* queue = SameProcessMessageQueue::Get(); + nsRefPtr ev = new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows, aPrincipal); - mASyncMessages.AppendElement(ev); - NS_DispatchToCurrentThread(ev); + queue->Push(ev); return true; } @@ -187,6 +177,12 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(nsInProcessTabChildGlobal, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(nsInProcessTabChildGlobal, DOMEventTargetHelper) +void +nsInProcessTabChildGlobal::CacheFrameLoader(nsIFrameLoader* aFrameLoader) +{ + mFrameLoader = aFrameLoader; +} + NS_IMETHODIMP nsInProcessTabChildGlobal::GetContent(nsIDOMWindow** aContent) { @@ -347,3 +343,14 @@ nsInProcessTabChildGlobal::LoadFrameScript(const nsAString& aURL, bool aRunInGlo LoadScriptInternal(aURL, aRunInGlobalScope); mLoadingScript = tmp; } + +already_AddRefed +nsInProcessTabChildGlobal::GetFrameLoader() +{ + nsCOMPtr owner = do_QueryInterface(mOwner); + nsCOMPtr fl = owner ? owner->GetFrameLoader() : nullptr; + if (!fl) { + fl = mFrameLoader; + } + return fl.forget(); +} diff --git a/dom/base/nsInProcessTabChildGlobal.h b/dom/base/nsInProcessTabChildGlobal.h index 650e84dca4..20c05f9637 100644 --- a/dom/base/nsInProcessTabChildGlobal.h +++ b/dom/base/nsInProcessTabChildGlobal.h @@ -150,6 +150,9 @@ public: { MOZ_CRASH("nsInProcessTabChildGlobal doesn't use DOM bindings!"); } + + already_AddRefed GetFrameLoader(); + protected: virtual ~nsInProcessTabChildGlobal(); @@ -165,10 +168,14 @@ protected: // PreHandleEvent. bool mIsBrowserOrAppFrame; bool mPreventEventsEscaping; + + // We keep a strong reference to the frameloader after we've started + // teardown. This allows us to dispatch message manager messages during this + // time. + nsCOMPtr mFrameLoader; public: nsIContent* mOwner; nsFrameMessageManager* mChromeMessageManager; - nsTArray > mASyncMessages; }; #endif diff --git a/dom/base/test/browser.ini b/dom/base/test/browser.ini index bb1c9c70b5..a64380ef27 100644 --- a/dom/base/test/browser.ini +++ b/dom/base/test/browser.ini @@ -7,6 +7,7 @@ skip-if = e10s # Bug ?????? - test directly touches content (contentWindow.ifram [browser_bug902350.js] skip-if = e10s # Bug ?????? - test e10s utils don't support load events from iframe etc, which this test relies on. [browser_messagemanager_loadprocessscript.js] +[browser_messagemanager_targetframeloader.js] [browser_pagehide_on_tab_close.js] skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s. [browser_messagemanager_unload.js] diff --git a/dom/base/test/browser_messagemanager_targetframeloader.js b/dom/base/test/browser_messagemanager_targetframeloader.js new file mode 100644 index 0000000000..32575d0738 --- /dev/null +++ b/dom/base/test/browser_messagemanager_targetframeloader.js @@ -0,0 +1,31 @@ +function frameScript() +{ + sendSyncMessage("Test:Message"); + sendAsyncMessage("Test:Message"); + sendAsyncMessage("Test:Done"); +} + +function test() { + waitForExplicitFinish(); + + var newTab = gBrowser.addTab("about:blank"); + gBrowser.selectedTab = newTab; + + let browser = newTab.linkedBrowser; + let frameLoader = browser.frameLoader; + ok(frameLoader !== null, "frameLoader looks okay"); + + browser.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")()", false); + + browser.messageManager.addMessageListener("Test:Message", (msg) => { + ok(msg.target === browser, " is correct"); + ok(msg.targetFrameLoader === frameLoader, "frameLoader is correct"); + ok(browser.frameLoader === msg.targetFrameLoader, "browser frameloader is correct"); + }); + + browser.messageManager.addMessageListener("Test:Done", () => { + info("Finished"); + gBrowser.removeCurrentTab(); + finish(); + }); +} diff --git a/dom/base/test/browser_messagemanager_unload.js b/dom/base/test/browser_messagemanager_unload.js index f952bd67d1..b4a14e92d0 100644 --- a/dom/base/test/browser_messagemanager_unload.js +++ b/dom/base/test/browser_messagemanager_unload.js @@ -70,6 +70,8 @@ function test() { gBrowser.selectedTab = newTab; let browser = newTab.linkedBrowser; + let frameLoader = browser.frameLoader; + ok(frameLoader !== null, "frameLoader looks okay"); browser.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")()", false); @@ -80,6 +82,8 @@ function test() { let index = 0; browser.messageManager.addMessageListener("Test:Event", (msg) => { ok(msg.target === browser, " is correct"); + ok(msg.targetFrameLoader === frameLoader, "frameLoader is correct"); + ok(browser.frameLoader === null, "browser frameloader null during teardown"); info(JSON.stringify(msg.data)); diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 4f761b6625..9a080336ad 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1947,7 +1947,7 @@ ContentChild::RecvAsyncMessage(const nsString& aMsg, if (cpm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData); CrossProcessCpowHolder cpows(this, aCpows); - cpm->ReceiveMessage(static_cast(cpm.get()), + cpm->ReceiveMessage(static_cast(cpm.get()), nullptr, aMsg, false, &cloneData, &cpows, aPrincipal, nullptr); } return true; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 8183d2ed4d..b52da42687 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -119,6 +119,7 @@ #include "nsIStyleSheet.h" #include "nsISupportsPrimitives.h" #include "nsISystemMessagesInternal.h" +#include "nsITimer.h" #include "nsIURIFixup.h" #include "nsIWindowWatcher.h" #include "nsIXULRuntime.h" @@ -581,6 +582,7 @@ static uint64_t gContentChildID = 1; static const char* sObserverTopics[] = { "xpcom-shutdown", + "profile-before-change", NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, "child-memory-reporter-request", "memory-pressure", @@ -1555,12 +1557,22 @@ ContentParent::TransformPreallocatedIntoBrowser(ContentParent* aOpener) void ContentParent::ShutDownProcess(ShutDownMethod aMethod) { +#ifdef MOZ_NUWA_PROCESS + if (aMethod == SEND_SHUTDOWN_MESSAGE && IsNuwaProcess()) { + // We shouldn't send shutdown messages to frozen Nuwa processes, + // so just close the channel. + aMethod = CLOSE_CHANNEL; + } +#endif + // Shutting down by sending a shutdown message works differently than the // other methods. We first call Shutdown() in the child. After the child is // ready, it calls FinishShutdown() on us. Then we close the channel. if (aMethod == SEND_SHUTDOWN_MESSAGE) { - if (mIPCOpen && SendShutdown()) { + if (mIPCOpen && !mShutdownPending && SendShutdown()) { mShutdownPending = true; + // Start the force-kill timer if we haven't already. + StartForceKillTimer(); } // If call was not successful, the channel must have been broken @@ -1638,7 +1650,7 @@ ContentParent::ShutDownMessageManager() } mMessageManager->ReceiveMessage( - static_cast(mMessageManager.get()), + static_cast(mMessageManager.get()), nullptr, CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr, nullptr, nullptr); @@ -1816,13 +1828,13 @@ struct DelayedDeleteContentParentTask : public nsRunnable void ContentParent::ActorDestroy(ActorDestroyReason why) { - if (mForceKillTask) { - mForceKillTask->Cancel(); - mForceKillTask = nullptr; + if (mForceKillTimer) { + mForceKillTimer->Cancel(); + mForceKillTimer = nullptr; } - // Signal shutdown completion regardless of error state, - // so we can finish waiting in the xpcom-shutdown observer. + // Signal shutdown completion regardless of error state, so we can + // finish waiting in the xpcom-shutdown/profile-before-change observer. mIPCOpen = false; if (why == NormalShutdown && !mCalledClose) { @@ -1940,15 +1952,25 @@ ContentParent::NotifyTabDestroying(PBrowserParent* aTab) // We're dying now, so prevent this content process from being // recycled during its shutdown procedure. MarkAsDead(); + StartForceKillTimer(); +} + +void +ContentParent::StartForceKillTimer() +{ + if (mForceKillTimer || !mIPCOpen) { + return; + } - MOZ_ASSERT(!mForceKillTask); int32_t timeoutSecs = Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5); if (timeoutSecs > 0) { - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - mForceKillTask = NewRunnableMethod(this, &ContentParent::KillHard, nullptr), - timeoutSecs * 1000); + mForceKillTimer = do_CreateInstance("@mozilla.org/timer;1"); + MOZ_ASSERT(mForceKillTimer); + mForceKillTimer->InitWithFuncCallback(ContentParent::ForceKillTimerCallback, + this, + timeoutSecs * 1000, + nsITimer::TYPE_ONE_SHOT); } } @@ -2008,7 +2030,6 @@ ContentParent::InitializeMembers() mSubprocess = nullptr; mChildID = gContentChildID++; mGeolocationWatchID = -1; - mForceKillTask = nullptr; mNumDestroyingTabs = 0; mIsAlive = true; mMetamorphosed = false; @@ -2195,8 +2216,8 @@ ContentParent::ContentParent(ContentParent* aTemplate, ContentParent::~ContentParent() { - if (mForceKillTask) { - mForceKillTask->Cancel(); + if (mForceKillTimer) { + mForceKillTimer->Cancel(); } NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -2760,10 +2781,10 @@ ContentParent::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { - if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) { - if (!mShutdownPending && mIPCOpen) { - ShutDownProcess(SEND_SHUTDOWN_MESSAGE); - } + if (mSubprocess && (!strcmp(aTopic, "profile-before-change") || + !strcmp(aTopic, "xpcom-shutdown"))) { + // Okay to call ShutDownProcess multiple times. + ShutDownProcess(SEND_SHUTDOWN_MESSAGE); // Wait for shutdown to complete, so that we receive any shutdown // data (e.g. telemetry) from the child before we quit. @@ -3165,6 +3186,13 @@ ContentParent::DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParen return true; } +/* static */ void +ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) +{ + auto self = static_cast(aClosure); + self->KillHard("ShutDownKill"); +} + void ContentParent::KillHard(const char* aReason) { @@ -3175,7 +3203,7 @@ ContentParent::KillHard(const char* aReason) return; } mCalledKillHard = true; - mForceKillTask = nullptr; + mForceKillTimer = nullptr; ProcessHandle otherProcessHandle; if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 766771bdc2..d12359fc88 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -33,6 +33,7 @@ class nsICycleCollectorLogSink; class nsIDOMBlob; class nsIDumpGCAndCCLogsCallback; class nsIMemoryReporter; +class nsITimer; class ParentIdleListener; class nsIWidget; @@ -489,6 +490,11 @@ private: // manager and null out mMessageManager. void ShutDownMessageManager(); + // Start the force-kill timer on shutdown. + void StartForceKillTimer(); + + static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure); + PCompositorParent* AllocPCompositorParent(mozilla::ipc::Transport* aTransport, base::ProcessId aOtherProcess) override; @@ -819,7 +825,7 @@ private: // that even content processes that are 100% blocked (say from // SIGSTOP), are still killed eventually. This task enforces that // timer. - CancelableTask* mForceKillTask; + nsCOMPtr mForceKillTimer; // How many tabs we're waiting to finish their destruction // sequence. Precisely, how many TabParents have called // NotifyTabDestroying() but not called NotifyTabDestroyed(). diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 6bcfe948de..895dbf3113 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -477,7 +477,7 @@ TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName, // content manipulate the frame state. nsRefPtr mm = static_cast(mTabChildGlobal->mMessageManager.get()); - mm->ReceiveMessage(static_cast(mTabChildGlobal), + mm->ReceiveMessage(static_cast(mTabChildGlobal), nullptr, aMessageName, false, &cloneData, nullptr, nullptr, nullptr); } @@ -681,7 +681,10 @@ private: MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mTabChild); - unused << PBrowserChild::Send__delete__(mTabChild); + // Check in case ActorDestroy was called after RecvDestroy message. + if (mTabChild->IPCOpen()) { + unused << PBrowserChild::Send__delete__(mTabChild); + } mTabChild = nullptr; return NS_OK; @@ -847,6 +850,7 @@ TabChild::TabChild(nsIContentChild* aManager, , mUniqueId(aTabId) , mDPI(0) , mDefaultScale(0) + , mIPCOpen(true) , mParentIsActive(false) { // preloaded TabChild should not be added to child map @@ -1593,6 +1597,8 @@ TabChild::DestroyWindow() void TabChild::ActorDestroy(ActorDestroyReason why) { + mIPCOpen = false; + DestroyWindow(); if (mTabChildGlobal) { @@ -2618,7 +2624,7 @@ TabChild::RecvAsyncMessage(const nsString& aMessage, nsRefPtr mm = static_cast(mTabChildGlobal->mMessageManager.get()); CrossProcessCpowHolder cpows(Manager(), aCpows); - mm->ReceiveMessage(static_cast(mTabChildGlobal), + mm->ReceiveMessage(static_cast(mTabChildGlobal), nullptr, aMessage, false, &cloneData, &cpows, aPrincipal, nullptr); } return true; diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index fcc17cf864..fdde3d19cf 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -492,6 +492,8 @@ public: return mParentIsActive; } + bool IPCOpen() { return mIPCOpen; } + protected: virtual ~TabChild(); @@ -625,6 +627,7 @@ private: TabId mUniqueId; float mDPI; double mDefaultScale; + bool mIPCOpen; bool mParentIsActive; DISALLOW_EVIL_CONSTRUCTORS(TabChild); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index edb4595bcc..099ca9258c 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2239,6 +2239,7 @@ TabParent::ReceiveMessage(const nsString& aMessage, frameLoader->GetFrameMessageManager(); manager->ReceiveMessage(mFrameElement, + frameLoader, aMessage, aSync, aCloneData, diff --git a/dom/ipc/nsIContentChild.cpp b/dom/ipc/nsIContentChild.cpp index 9de7466e47..a49f68344d 100644 --- a/dom/ipc/nsIContentChild.cpp +++ b/dom/ipc/nsIContentChild.cpp @@ -117,7 +117,7 @@ nsIContentChild::RecvAsyncMessage(const nsString& aMsg, if (cpm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData); CrossProcessCpowHolder cpows(this, aCpows); - cpm->ReceiveMessage(static_cast(cpm.get()), + cpm->ReceiveMessage(static_cast(cpm.get()), nullptr, aMsg, false, &cloneData, &cpows, aPrincipal, nullptr); } return true; diff --git a/dom/ipc/nsIContentParent.cpp b/dom/ipc/nsIContentParent.cpp index 01a5685150..565fa8d86c 100644 --- a/dom/ipc/nsIContentParent.cpp +++ b/dom/ipc/nsIContentParent.cpp @@ -194,7 +194,7 @@ nsIContentParent::RecvSyncMessage(const nsString& aMsg, if (ppm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); CrossProcessCpowHolder cpows(this, aCpows); - ppm->ReceiveMessage(static_cast(ppm.get()), + ppm->ReceiveMessage(static_cast(ppm.get()), nullptr, aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals); } return true; @@ -221,7 +221,7 @@ nsIContentParent::RecvRpcMessage(const nsString& aMsg, if (ppm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); CrossProcessCpowHolder cpows(this, aCpows); - ppm->ReceiveMessage(static_cast(ppm.get()), + ppm->ReceiveMessage(static_cast(ppm.get()), nullptr, aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals); } return true; @@ -247,7 +247,7 @@ nsIContentParent::RecvAsyncMessage(const nsString& aMsg, if (ppm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); CrossProcessCpowHolder cpows(this, aCpows); - ppm->ReceiveMessage(static_cast(ppm.get()), + ppm->ReceiveMessage(static_cast(ppm.get()), nullptr, aMsg, false, &cloneData, &cpows, aPrincipal, nullptr); } return true; diff --git a/gfx/layers/client/ClientTiledPaintedLayer.cpp b/gfx/layers/client/ClientTiledPaintedLayer.cpp index c55c1deaea..81f8eb887f 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.cpp +++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp @@ -219,6 +219,12 @@ ClientTiledPaintedLayer::IsScrollingOnCompositor(const FrameMetrics& aParentMetr bool ClientTiledPaintedLayer::UseFastPath() { + // The fast path doesn't allow rendering at low resolution. It will draw the low-res + // area at full resolution and cause OOM. + if (gfxPrefs::UseLowPrecisionBuffer()) { + return false; + } + LayerMetricsWrapper scrollAncestor; GetAncestorLayers(&scrollAncestor, nullptr); if (!scrollAncestor) { @@ -227,16 +233,35 @@ ClientTiledPaintedLayer::UseFastPath() const FrameMetrics& parentMetrics = scrollAncestor.Metrics(); bool multipleTransactionsNeeded = gfxPlatform::GetPlatform()->UseProgressivePaint() - || gfxPrefs::UseLowPrecisionBuffer() || !parentMetrics.GetCriticalDisplayPort().IsEmpty(); bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition(); bool isScrollable = parentMetrics.IsScrollable(); - return !multipleTransactionsNeeded || isFixed || !isScrollable -#if !defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ) - || !IsScrollingOnCompositor(parentMetrics) + return !multipleTransactionsNeeded || isFixed || !isScrollable; +} + +bool +ClientTiledPaintedLayer::UseProgressiveDraw() { + // Don't draw progressively in a reftest scenario (that's what the HasShadowTarget() check is for). + if (!gfxPlatform::GetPlatform()->UseProgressivePaint() || ClientManager()->HasShadowTarget()) { + return false; + } + + // XXX We probably want to disable progressive drawing for non active APZ layers in the future + // but we should wait for a proper test case before making this change. + +#if 0 //!defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ) + LayerMetricsWrapper scrollAncestor; + GetAncestorLayers(&scrollAncestor, nullptr); + if (!scrollAncestor) { + return true; + } + const FrameMetrics& parentMetrics = scrollAncestor.Metrics(); + + return !IsScrollingOnCompositor(parentMetrics); +#else + return true; #endif - ; } bool @@ -251,10 +276,8 @@ ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion, return false; } - // Only draw progressively when the resolution is unchanged, and we're not - // in a reftest scenario (that's what the HasShadowManager() check is for). - if (gfxPlatform::GetPlatform()->UseProgressivePaint() && - !ClientManager()->HasShadowTarget() && + // Only draw progressively when the resolution is unchanged + if (UseProgressiveDraw() && mContentClient->mTiledBuffer.GetFrameResolution() == mPaintData.mResolution) { // Store the old valid region, then clear it before painting. // We clip the old valid region to the visible region, as it only gets @@ -418,36 +441,20 @@ ClientTiledPaintedLayer::RenderLayer() ToClientLayer(GetMaskLayer())->RenderLayer(); } - // For more complex cases we need to calculate a bunch of metrics before we - // can do the paint. - BeginPaint(); - if (mPaintData.mPaintFinished) { - return; - } - // In some cases we can take a fast path and just be done with it. if (UseFastPath()) { TILING_LOG("TILING %p: Taking fast-path\n", this); mValidRegion = neededRegion; - - // Make sure that tiles that fall outside of the visible region or outside of the - // critical displayport are discarded on the first update. Also make sure that we - // only draw stuff inside the critical displayport on the first update. - if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { - mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); - invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); - } - - if (invalidRegion.IsEmpty()) { - EndPaint(); - return; - } - - mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution); mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, callback, data); ClientManager()->Hold(this); mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER); - EndPaint(); + return; + } + + // For more complex cases we need to calculate a bunch of metrics before we + // can do the paint. + BeginPaint(); + if (mPaintData.mPaintFinished) { return; } diff --git a/gfx/layers/client/ClientTiledPaintedLayer.h b/gfx/layers/client/ClientTiledPaintedLayer.h index fa3a49f7c3..9920f121b4 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.h +++ b/gfx/layers/client/ClientTiledPaintedLayer.h @@ -106,6 +106,13 @@ private: */ bool IsScrollingOnCompositor(const FrameMetrics& aParentMetrics); + /** + * Check if we should use progressive draw on this layer. We will + * disable progressive draw based on a preference or if the layer + * is not being scrolled. + */ + bool UseProgressiveDraw(); + /** * Helper function to do the high-precision paint. * This function returns true if it updated the paint buffer. diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 20ea55a292..4ef956acce 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -316,7 +316,7 @@ private: DECL_GFX_PREF(Once, "layers.d3d11.force-warp", LayersD3D11ForceWARP, bool, false); DECL_GFX_PREF(Once, "layers.prefer-d3d9", LayersPreferD3D9, bool, false); DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false); - DECL_GFX_PREF(Once, "layers.progressive-paint", ProgressivePaintDoNotUseDirectly, bool, false); + DECL_GFX_PREF(Live, "layers.progressive-paint", ProgressivePaintDoNotUseDirectly, bool, false); DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false); DECL_GFX_PREF(Once, "layers.gralloc.disable", DisableGralloc, bool, false); diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list index 73d880baad..4b30b581ee 100644 --- a/layout/base/crashtests/crashtests.list +++ b/layout/base/crashtests/crashtests.list @@ -433,7 +433,7 @@ load 835056.html load 836990-1.html load 840480.html load 847242.html -load 852293.html +pref(layers.progressive-paint,false) pref(layers.low-precision-buffer,false) load 852293.html load 860579-1.html pref(layers.force-active,true) load 859526-1.html pref(layers.force-active,true) load 859630-1.html