diff -Nru firefox-45.0~b2+build1/browser/app/profile/firefox.js firefox-45.0~b3+build1/browser/app/profile/firefox.js --- firefox-45.0~b2+build1/browser/app/profile/firefox.js 2016-02-02 06:57:31.000000000 +0000 +++ firefox-45.0~b3+build1/browser/app/profile/firefox.js 2016-02-05 06:54:46.000000000 +0000 @@ -1309,6 +1309,12 @@ pref("services.sync.prefs.sync.spellchecker.dictionary", true); pref("services.sync.prefs.sync.xpinstall.whitelist.required", true); +#ifdef NIGHTLY_BUILD +pref("services.sync.syncedTabsUIRefresh", true); +#else +pref("services.sync.syncedTabsUIRefresh", false); +#endif + // Developer edition preferences #ifdef MOZ_DEV_EDITION sticky_pref("lightweightThemes.selectedThemeID", "firefox-devedition@mozilla.org"); diff -Nru firefox-45.0~b2+build1/browser/base/content/browser-eme.js firefox-45.0~b3+build1/browser/base/content/browser-eme.js --- firefox-45.0~b2+build1/browser/base/content/browser-eme.js 2016-02-02 06:57:31.000000000 +0000 +++ firefox-45.0~b3+build1/browser/base/content/browser-eme.js 2016-02-05 06:54:46.000000000 +0000 @@ -33,16 +33,6 @@ return ""; }, - onDontAskAgain: function(menuPopupItem) { - let button = menuPopupItem.parentNode.anchorNode; - let bar = button.parentNode; - Services.prefs.setBoolPref("browser.eme.ui." + bar.value + ".disabled", true); - bar.close(); - }, - onNotNow: function(menuPopupItem) { - let button = menuPopupItem.parentNode.anchorNode; - button.parentNode.close(); - }, receiveMessage: function({target: browser, data: data}) { let parsedData; try { @@ -105,13 +95,6 @@ return; } - // If the user turned these off, bail out: - try { - if (Services.prefs.getBoolPref("browser.eme.ui." + notificationId + ".disabled")) { - return; - } - } catch (ex) { /* Don't care if the pref doesn't exist */ } - let msgPrefix = "emeNotifications." + notificationId + "."; let msgId = msgPrefix + "message"; @@ -140,13 +123,6 @@ accessKey: gNavigatorBundle.getString(btnAccessKeyId), callback: callback }); - - let optionsId = "emeNotifications.optionsButton"; - buttons.push({ - label: gNavigatorBundle.getString(optionsId + ".label"), - accessKey: gNavigatorBundle.getString(optionsId + ".accesskey"), - popup: "emeNotificationsPopup" - }); } let iconURL = "chrome://browser/skin/drm-icon.svg#chains-black"; diff -Nru firefox-45.0~b2+build1/browser/base/content/browser.js firefox-45.0~b3+build1/browser/base/content/browser.js --- firefox-45.0~b2+build1/browser/base/content/browser.js 2016-02-02 06:57:31.000000000 +0000 +++ firefox-45.0~b3+build1/browser/base/content/browser.js 2016-02-05 06:54:46.000000000 +0000 @@ -6567,7 +6567,11 @@ } function BrowserOpenSyncTabs() { - gSyncUI.openSyncedTabsPanel(); + if (Services.prefs.getBoolPref("services.sync.syncedTabsUIRefresh")) { + gSyncUI.openSyncedTabsPanel(); + } else { + switchToTabHavingURI("about:sync-tabs", true); + } } /** diff -Nru firefox-45.0~b2+build1/browser/base/content/browser.xul firefox-45.0~b3+build1/browser/base/content/browser.xul --- firefox-45.0~b2+build1/browser/base/content/browser.xul 2016-02-02 06:57:31.000000000 +0000 +++ firefox-45.0~b3+build1/browser/base/content/browser.xul 2016-02-05 06:54:46.000000000 +0000 @@ -463,17 +463,6 @@ - - - - - #ifdef CAN_DRAW_IN_TITLEBAR diff -Nru firefox-45.0~b2+build1/browser/base/content/tabbrowser.xml firefox-45.0~b3+build1/browser/base/content/tabbrowser.xml --- firefox-45.0~b2+build1/browser/base/content/tabbrowser.xml 2016-02-02 06:57:31.000000000 +0000 +++ firefox-45.0~b3+build1/browser/base/content/tabbrowser.xml 2016-02-05 06:54:46.000000000 +0000 @@ -761,7 +761,9 @@ } // If the browser was playing audio, we should remove the playing state. - if (this.mTab.hasAttribute("soundplaying") && this.mBrowser.lastURI != aLocation) { + if (this.mTab.hasAttribute("soundplaying") && + (!this.mBrowser.lastURI || + this.mBrowser.lastURI.spec != aLocation.spec)) { this.mTab.removeAttribute("soundplaying"); this.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]); } diff -Nru firefox-45.0~b2+build1/browser/components/customizableui/CustomizableWidgets.jsm firefox-45.0~b3+build1/browser/components/customizableui/CustomizableWidgets.jsm --- firefox-45.0~b2+build1/browser/components/customizableui/CustomizableWidgets.jsm 2016-02-02 06:57:32.000000000 +0000 +++ firefox-45.0~b3+build1/browser/components/customizableui/CustomizableWidgets.jsm 2016-02-05 06:54:47.000000000 +0000 @@ -330,13 +330,12 @@ this._tabsList = doc.getElementById("PanelUI-remotetabs-tabslist"); Services.obs.addObserver(this, SyncedTabs.TOPIC_TABS_CHANGED, false); - let deck = doc.getElementById("PanelUI-remotetabs-deck"); if (SyncedTabs.isConfiguredToSyncTabs) { if (SyncedTabs.hasSyncedThisSession) { - deck.selectedIndex = this.deckIndices.DECKINDEX_TABS; + this.setDeckIndex(this.deckIndices.DECKINDEX_TABS); } else { // Sync hasn't synced tabs yet, so show the "fetching" panel. - deck.selectedIndex = this.deckIndices.DECKINDEX_FETCHING; + this.setDeckIndex(this.deckIndices.DECKINDEX_FETCHING); } // force a background sync. SyncedTabs.syncTabs().catch(ex => { @@ -346,7 +345,7 @@ this._showTabs(); } else { // not configured to sync tabs, so no point updating the list. - deck.selectedIndex = this.deckIndices.DECKINDEX_TABSDISABLED; + this.setDeckIndex(this.deckIndices.DECKINDEX_TABSDISABLED); } }, onViewHiding() { @@ -363,6 +362,14 @@ break; } }, + setDeckIndex(index) { + let deck = this._tabsList.ownerDocument.getElementById("PanelUI-remotetabs-deck"); + // We call setAttribute instead of relying on the XBL property setter due + // to things going wrong when we try and set the index before the XBL + // binding has been created - see bug 1241851 for the gory details. + deck.setAttribute("selectedIndex", index); + }, + _showTabsPromise: Promise.resolve(), // Update the tab list after any existing in-flight updates are complete. _showTabs() { @@ -373,7 +380,6 @@ // Return a new promise to update the tab list. __showTabs() { let doc = this._tabsList.ownerDocument; - let deck = doc.getElementById("PanelUI-remotetabs-deck"); return SyncedTabs.getTabClients().then(clients => { // The view may have been hidden while the promise was resolving. if (!this._tabsList) { @@ -386,11 +392,11 @@ } if (clients.length === 0) { - deck.selectedIndex = this.deckIndices.DECKINDEX_NOCLIENTS; + this.setDeckIndex(this.deckIndices.DECKINDEX_NOCLIENTS); return; } - deck.selectedIndex = this.deckIndices.DECKINDEX_TABS; + this.setDeckIndex(this.deckIndices.DECKINDEX_TABS); this._clearTabList(); this._sortFilterClientsAndTabs(clients); let fragment = doc.createDocumentFragment(); diff -Nru firefox-45.0~b2+build1/browser/components/shell/nsWindowsShellService.cpp firefox-45.0~b3+build1/browser/components/shell/nsWindowsShellService.cpp --- firefox-45.0~b2+build1/browser/components/shell/nsWindowsShellService.cpp 2016-02-02 06:57:32.000000000 +0000 +++ firefox-45.0~b3+build1/browser/components/shell/nsWindowsShellService.cpp 2016-02-05 06:54:47.000000000 +0000 @@ -86,38 +86,6 @@ return NS_OK; } -static bool -GetPrefString(const nsCString& aPrefName, nsAString& aValue) -{ - nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); - if (!prefs) { - return false; - } - - nsAutoCString prefCStr; - nsresult rv = prefs->GetCharPref(aPrefName.get(), - getter_Copies(prefCStr)); - if (NS_FAILED(rv)) { - return false; - } - CopyUTF8toUTF16(prefCStr, aValue); - - return true; -} - -static bool -SetPrefString(const nsCString& aPrefName, const nsString& aValue) -{ - nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); - if (!prefs) { - return false; - } - - nsresult rv = prefs->SetCharPref(aPrefName.get(), - NS_ConvertUTF16toUTF8(aValue).get()); - return NS_SUCCEEDED(rv); -} - /////////////////////////////////////////////////////////////////////////////// // Default Browser Registry Settings // @@ -376,145 +344,7 @@ } static void -GetUserChoiceKeyName(LPCWSTR aClassName, bool aIsProtocol, - nsAString& aKeyName) -{ - aKeyName.AssignLiteral(aIsProtocol - ? "Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\" - : "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"); - aKeyName.Append(aClassName); - aKeyName.AppendLiteral("\\UserChoice"); -} - -static void -GetHashPrefName(LPCWSTR aClassName, nsACString& aPrefName) -{ - aPrefName.AssignLiteral("browser.shell.associationHash."); - aPrefName.Append(NS_ConvertUTF16toUTF8(*aClassName == L'.' ? aClassName + 1 - : aClassName)); -} - -static bool -SaveWin8RegistryHash(const RefPtr& pAAR, - LPCWSTR aClassName) -{ - bool isProtocol = *aClassName != L'.'; - bool isDefault = IsAARDefault(pAAR, aClassName); - // We can save the value only if Firefox is the default. - if (!isDefault) { - return isDefault; - } - - nsAutoString keyName; - GetUserChoiceKeyName(aClassName, isProtocol, keyName); - - nsCOMPtr regKey = - do_CreateInstance("@mozilla.org/windows-registry-key;1"); - if (!regKey) { - return isDefault; - } - - nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, - keyName, nsIWindowsRegKey::ACCESS_READ); - if (NS_FAILED(rv)) { - return isDefault; - } - - nsAutoString hash; - rv = regKey->ReadStringValue(NS_LITERAL_STRING("Hash"), hash); - if (NS_FAILED(rv)) { - return isDefault; - } - - nsAutoCString prefName; - GetHashPrefName(aClassName, prefName); - SetPrefString(prefName, hash); - - return isDefault; -} - -static bool -RestoreWin8RegistryHash(const RefPtr& pAAR, - LPCWSTR aClassName) -{ - nsAutoCString prefName; - GetHashPrefName(aClassName, prefName); - nsAutoString hash; - if (!GetPrefString(prefName, hash)) { - return false; - } - - bool isProtocol = *aClassName != L'.'; - nsString progId = isProtocol ? NS_LITERAL_STRING("FirefoxURL") - : NS_LITERAL_STRING("FirefoxHTML"); - - nsAutoString keyName; - GetUserChoiceKeyName(aClassName, isProtocol, keyName); - - nsCOMPtr regKey = - do_CreateInstance("@mozilla.org/windows-registry-key;1"); - if (!regKey) { - return false; - } - - nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, - keyName, nsIWindowsRegKey::ACCESS_READ); - if (NS_SUCCEEDED(rv)) { - nsAutoString currValue; - if (NS_SUCCEEDED(regKey->ReadStringValue(NS_LITERAL_STRING("Hash"), - currValue)) && - currValue.Equals(hash) && - NS_SUCCEEDED(regKey->ReadStringValue(NS_LITERAL_STRING("ProgId"), - currValue)) && - currValue.Equals(progId)) { - // The value is already set. - return true; - } - // We need to close this explicitly because nsIWindowsRegKey::SetKey - // does not close the old key. - regKey->Close(); - } - - // We have to use the registry function directly because - // nsIWindowsRegKey::Create will only return NS_ERROR_FAILURE - // on failure. - HKEY theKey; - DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName.get(), 0, - KEY_READ | KEY_SET_VALUE, &theKey); - if (REG_FAILED(res)) { - if (res != ERROR_ACCESS_DENIED && res != ERROR_FILE_NOT_FOUND) { - return false; - } - if (res == ERROR_ACCESS_DENIED) { - res = ::RegDeleteKeyW(HKEY_CURRENT_USER, keyName.get()); - if (REG_FAILED(res)) { - return false; - } - } - res = ::RegCreateKeyExW(HKEY_CURRENT_USER, keyName.get(), 0, - nullptr, 0, KEY_READ | KEY_SET_VALUE, - nullptr, &theKey, nullptr); - if (REG_FAILED(res)) { - return false; - } - } - regKey->SetKey(theKey); - - rv = regKey->WriteStringValue(NS_LITERAL_STRING("Hash"), hash); - if (NS_FAILED(rv)) { - return false; - } - - rv = regKey->WriteStringValue(NS_LITERAL_STRING("ProgId"), progId); - if (NS_FAILED(rv)) { - return false; - } - - return IsAARDefault(pAAR, aClassName); -} - -static void -SaveWin8RegistryHashes(bool aCheckAllTypes, bool* aIsDefaultBrowser) +IsDefaultBrowserWin8(bool aCheckAllTypes, bool* aIsDefaultBrowser) { RefPtr pAAR; HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration, @@ -526,48 +356,14 @@ return; } - bool res = SaveWin8RegistryHash(pAAR, L"http"); + bool res = IsAARDefault(pAAR, L"http"); if (*aIsDefaultBrowser) { *aIsDefaultBrowser = res; } - SaveWin8RegistryHash(pAAR, L"https"); - SaveWin8RegistryHash(pAAR, L"ftp"); - res = SaveWin8RegistryHash(pAAR, L".html"); + res = IsAARDefault(pAAR, L".html"); if (*aIsDefaultBrowser && aCheckAllTypes) { *aIsDefaultBrowser = res; } - SaveWin8RegistryHash(pAAR, L".htm"); - SaveWin8RegistryHash(pAAR, L".shtml"); - SaveWin8RegistryHash(pAAR, L".xhtml"); - SaveWin8RegistryHash(pAAR, L".xht"); -} - -static bool -RestoreWin8RegistryHashes(bool aClaimAllTypes) -{ - RefPtr pAAR; - HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration, - nullptr, - CLSCTX_INPROC, - IID_IApplicationAssociationRegistration, - getter_AddRefs(pAAR)); - if (FAILED(hr)) { - return false; - } - - bool res = RestoreWin8RegistryHash(pAAR, L"http"); - res = RestoreWin8RegistryHash(pAAR, L"https") && res; - RestoreWin8RegistryHash(pAAR, L"ftp"); - bool res2 = RestoreWin8RegistryHash(pAAR, L".html"); - res2 = RestoreWin8RegistryHash(pAAR, L".htm") && res2; - if (aClaimAllTypes) { - res = res && res2; - } - RestoreWin8RegistryHash(pAAR, L".shtml"); - RestoreWin8RegistryHash(pAAR, L".xhtml"); - RestoreWin8RegistryHash(pAAR, L".xht"); - - return res; } /* @@ -701,7 +497,7 @@ if (*aIsDefaultBrowser) { IsDefaultBrowserVista(aForAllTypes, aIsDefaultBrowser); if (IsWin8OrLater()) { - SaveWin8RegistryHashes(aForAllTypes, aIsDefaultBrowser); + IsDefaultBrowserWin8(aForAllTypes, aIsDefaultBrowser); } } @@ -937,8 +733,7 @@ } nsresult rv = LaunchHelper(appHelperPath); - if (NS_SUCCEEDED(rv) && IsWin8OrLater() && - !RestoreWin8RegistryHashes(aClaimAllTypes)) { + if (NS_SUCCEEDED(rv) && IsWin8OrLater()) { if (aClaimAllTypes) { if (IsWin10OrLater()) { rv = LaunchModernSettingsDialogDefaultApps(); @@ -968,8 +763,6 @@ if (NS_FAILED(rv)) { rv = LaunchControlPanelDefaultsSelectionUI(); } - bool isDefault; - SaveWin8RegistryHashes(aClaimAllTypes, &isDefault); } } diff -Nru firefox-45.0~b2+build1/browser/components/uitour/test/browser_UITour_defaultBrowser.js firefox-45.0~b3+build1/browser/components/uitour/test/browser_UITour_defaultBrowser.js --- firefox-45.0~b2+build1/browser/components/uitour/test/browser_UITour_defaultBrowser.js 2016-02-02 06:57:32.000000000 +0000 +++ firefox-45.0~b3+build1/browser/components/uitour/test/browser_UITour_defaultBrowser.js 2016-02-05 06:54:47.000000000 +0000 @@ -65,31 +65,4 @@ done(); }); }), - - taskify(function* test_setInBackgroundWhenPrefExists(done) { - Services.prefs.setCharPref("browser.shell.associationHash.http", "ABCDEFG"); - gContentAPI.getConfiguration("appinfo", (data) => { - let canSetInBackground = true; - is(canSetInBackground, data.canSetDefaultBrowserInBackground, - "canSetDefaultBrowserInBackground should be true when a hash is present"); - Services.prefs.clearUserPref("browser.shell.associationHash.http"); - done(); - }); - }), - - taskify(function* test_setInBackgroundWhenPrefDoesntExist(done) { - /* The association hashes are only supported on Windows. */ - Cu.import("resource://gre/modules/AppConstants.jsm"); - if (AppConstants.platform != "win") { - info("Skipping test_setInBackgroundWhenPrefDoesntExist on non-Windows platform"); - return; - } - - gContentAPI.getConfiguration("appinfo", (data) => { - let canSetInBackground = false; - is(canSetInBackground, data.canSetDefaultBrowserInBackground, - "canSetDefaultBrowserInBackground should be false when no hashes are present"); - done(); - }); - }) ]; diff -Nru firefox-45.0~b2+build1/browser/components/uitour/UITour.jsm firefox-45.0~b3+build1/browser/components/uitour/UITour.jsm --- firefox-45.0~b2+build1/browser/components/uitour/UITour.jsm 2016-02-02 06:57:32.000000000 +0000 +++ firefox-45.0~b3+build1/browser/components/uitour/UITour.jsm 2016-02-05 06:54:47.000000000 +0000 @@ -1793,12 +1793,8 @@ appinfo["defaultBrowser"] = isDefaultBrowser; let canSetDefaultBrowserInBackground = true; - if (AppConstants.isPlatformAndVersionAtLeast("win", "6.2")) { - let prefBranch = - Services.prefs.getBranch("browser.shell.associationHash"); - let prefChildren = prefBranch.getChildList(""); - canSetDefaultBrowserInBackground = prefChildren.length > 0; - } else if (AppConstants.isPlatformAndVersionAtLeast("macosx", "10.10")) { + if (AppConstants.isPlatformAndVersionAtLeast("win", "6.2") || + AppConstants.isPlatformAndVersionAtLeast("macosx", "10.10")) { canSetDefaultBrowserInBackground = false; } else if (AppConstants.platform == "linux") { // The ShellService may not exist on some versions of Linux. diff -Nru firefox-45.0~b2+build1/browser/config/version_display.txt firefox-45.0~b3+build1/browser/config/version_display.txt --- firefox-45.0~b2+build1/browser/config/version_display.txt 2016-02-02 06:57:32.000000000 +0000 +++ firefox-45.0~b3+build1/browser/config/version_display.txt 2016-02-05 06:54:47.000000000 +0000 @@ -1 +1 @@ -45.0b2 +45.0b3 diff -Nru firefox-45.0~b2+build1/configure.in firefox-45.0~b3+build1/configure.in --- firefox-45.0~b2+build1/configure.in 2016-02-02 06:57:34.000000000 +0000 +++ firefox-45.0~b3+build1/configure.in 2016-02-05 06:54:48.000000000 +0000 @@ -3451,7 +3451,7 @@ _USE_SYSTEM_NSS=1 ) if test -n "$_USE_SYSTEM_NSS"; then - AM_PATH_NSS(3.20.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])]) + AM_PATH_NSS(3.21, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])]) fi if test -n "$MOZ_NATIVE_NSS"; then @@ -8772,15 +8772,14 @@ MOZ_INCLUDE_SOURCE_INFO=1 fi -# On official builds, we need to know in Telemetry what revision this is built from. -# This is e.g. needed to match incoming data to a specific revision of the Histograms.json -# file. -if test "$MOZILLA_OFFICIAL" && test -d ${_topsrcdir}/.hg; then - SOURCE_REV=`cd $_topsrcdir && hg parent --template='{node|short}'` - SOURCE_REPO=`cd $_topsrcdir && hg showconfig paths.default | sed -e 's|^ssh://|http://|' -e 's|/$||'` - SOURCE_REV_URL=$SOURCE_REPO/rev/$SOURCE_REV -else - SOURCE_REV_URL= +# External builds (specifically Ubuntu) may drop the hg repo information, so we allow to +# explicitly set the repository and changeset information in. +if test "$MOZILLA_OFFICIAL"; then + if test -z "$MOZ_SOURCE_REPO" && test -z "$MOZ_SOURCE_CHANGESET" && test -d ${_topsrcdir}/.hg; then + MOZ_SOURCE_CHANGESET=`cd $_topsrcdir && hg parent --template='{node}'` + MOZ_SOURCE_REPO=`cd $_topsrcdir && hg showconfig paths.default | sed -e 's|^ssh://|http://|' -e 's|/$||'` + fi + SOURCE_REV_URL=$MOZ_SOURCE_REPO/rev/$MOZ_SOURCE_CHANGESET fi AC_SUBST(SOURCE_REV_URL) diff -Nru firefox-45.0~b2+build1/debian/changelog firefox-45.0~b3+build1/debian/changelog --- firefox-45.0~b2+build1/debian/changelog 2016-02-02 11:33:17.000000000 +0000 +++ firefox-45.0~b3+build1/debian/changelog 2016-02-05 07:29:06.000000000 +0000 @@ -1,3 +1,9 @@ +firefox (45.0~b3+build1-0ubuntu0.16.04.1) xenial; urgency=medium + + * New upstream release from the beta channel (FIREFOX_45_0b3_BUILD1) + + -- Rico Tzschichholz Fri, 05 Feb 2016 08:17:33 +0100 + firefox (45.0~b2+build1-0ubuntu0.16.04.2) xenial; urgency=medium [ Rico Tzschichholz ] diff -Nru firefox-45.0~b2+build1/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js firefox-45.0~b3+build1/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js --- firefox-45.0~b2+build1/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js 1970-01-01 00:00:00.000000000 +0000 +++ firefox-45.0~b3+build1/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js 2016-02-05 06:54:49.000000000 +0000 @@ -0,0 +1,190 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Check that user agent styles are inspectable via rule view if +// it is preffed on. + +var PREF_UA_STYLES = "devtools.inspector.showUserAgentStyles"; +const { PrefObserver } = require("devtools/client/styleeditor/utils"); + +const TEST_URI = ` + + + + + + +
+
+      inspect user agent styles
+    
+
+`; + +const TEST_DATA = [ + { + selector: "blockquote", + numUserRules: 1, + numUARules: 0 + }, + { + selector: "pre", + numUserRules: 1, + numUARules: 0 + }, + { + selector: "input[type=range]", + numUserRules: 1, + numUARules: 0 + }, + { + selector: "input[type=number]", + numUserRules: 1, + numUARules: 0 + }, + { + selector: "input[type=color]", + numUserRules: 1, + numUARules: 0 + }, + { + selector: "input[type=text]", + numUserRules: 1, + numUARules: 0 + }, + { + selector: "progress", + numUserRules: 1, + numUARules: 0 + }, + { + selector: "a", + numUserRules: 2, + numUARules: 0 + } +]; + +add_task(function*() { + requestLongerTimeout(2); + + info("Starting the test with the pref set to true before toolbox is opened"); + yield setUserAgentStylesPref(true); + + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + let {inspector, view} = yield openRuleView(); + + info("Making sure that UA styles are visible on initial load"); + yield userAgentStylesVisible(inspector, view); + + info("Making sure that setting the pref to false hides UA styles"); + yield setUserAgentStylesPref(false); + yield userAgentStylesNotVisible(inspector, view); + + info("Making sure that resetting the pref to true shows UA styles again"); + yield setUserAgentStylesPref(true); + yield userAgentStylesVisible(inspector, view); + + info("Resetting " + PREF_UA_STYLES); + Services.prefs.clearUserPref(PREF_UA_STYLES); +}); + +function* setUserAgentStylesPref(val) { + info("Setting the pref " + PREF_UA_STYLES + " to: " + val); + + // Reset the pref and wait for PrefObserver to callback so UI + // has a chance to get updated. + let oncePrefChanged = promise.defer(); + let prefObserver = new PrefObserver("devtools."); + prefObserver.on(PREF_UA_STYLES, oncePrefChanged.resolve); + Services.prefs.setBoolPref(PREF_UA_STYLES, val); + yield oncePrefChanged.promise; + prefObserver.off(PREF_UA_STYLES, oncePrefChanged.resolve); +} + +function* userAgentStylesVisible(inspector, view) { + info("Making sure that user agent styles are currently visible"); + + let userRules; + let uaRules; + + for (let data of TEST_DATA) { + yield selectNode(data.selector, inspector); + yield compareAppliedStylesWithUI(inspector, view, "ua"); + + userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); + uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); + is(userRules.length, data.numUserRules, "Correct number of user rules"); + ok(uaRules.length > data.numUARules, "Has UA rules"); + } + + ok(userRules.some(rule=> rule.matchedSelectors.length === 1), + "There is an inline style for element in user styles"); + + ok(uaRules.some(rule=> rule.matchedSelectors.indexOf(":-moz-any-link")), + "There is a rule for :-moz-any-link"); + ok(uaRules.some(rule=> rule.matchedSelectors.indexOf("*|*:link")), + "There is a rule for *|*:link"); + ok(uaRules.some(rule=> rule.matchedSelectors.length === 1), + "Inline styles for ua styles"); +} + +function* userAgentStylesNotVisible(inspector, view) { + info("Making sure that user agent styles are not currently visible"); + + let userRules; + let uaRules; + + for (let data of TEST_DATA) { + yield selectNode(data.selector, inspector); + yield compareAppliedStylesWithUI(inspector, view); + + userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); + uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); + is(userRules.length, data.numUserRules, "Correct number of user rules"); + is(uaRules.length, data.numUARules, "No UA rules"); + } +} + +function* compareAppliedStylesWithUI(inspector, view, filter) { + info("Making sure that UI is consistent with pageStyle.getApplied"); + + let entries = yield inspector.pageStyle.getApplied( + inspector.selection.nodeFront, { + inherited: true, + matchedSelectors: true, + filter: filter + }); + + // We may see multiple entries that map to a given rule; filter the + // duplicates here to match what the UI does. + let entryMap = new Map(); + for (let entry of entries) { + entryMap.set(entry.rule, entry); + } + entries = [...entryMap.values()]; + + let elementStyle = view._elementStyle; + is(elementStyle.rules.length, entries.length, + "Should have correct number of rules (" + entries.length + ")"); + + entries = entries.sort((a, b) => { + return (a.pseudoElement || "z") > (b.pseudoElement || "z"); + }); + + entries.forEach((entry, i) => { + let elementStyleRule = elementStyle.rules[i]; + is(elementStyleRule.inherited, entry.inherited, + "Same inherited (" + entry.inherited + ")"); + is(elementStyleRule.isSystem, entry.isSystem, + "Same isSystem (" + entry.isSystem + ")"); + is(elementStyleRule.editor.isEditable, !entry.isSystem, + "Editor isEditable opposite of UA (" + entry.isSystem + ")"); + }); +} diff -Nru firefox-45.0~b2+build1/devtools/client/performance/test/browser_perf-overview-render-02.js firefox-45.0~b3+build1/devtools/client/performance/test/browser_perf-overview-render-02.js --- firefox-45.0~b2+build1/devtools/client/performance/test/browser_perf-overview-render-02.js 2016-02-02 06:57:34.000000000 +0000 +++ firefox-45.0~b3+build1/devtools/client/performance/test/browser_perf-overview-render-02.js 2016-02-05 06:54:49.000000000 +0000 @@ -5,6 +5,7 @@ * Tests that the overview graphs cannot be selected during recording * and that they're cleared upon rerecording. */ +const TIMES_TO_UPDATE = 2; function* spawnTest() { // This test seems to take a long time to cleanup on Ubuntu VMs. requestLongerTimeout(2); @@ -51,7 +52,7 @@ let updated = 0; OverviewView.on(EVENTS.OVERVIEW_RENDERED, () => updated++); - ok((yield waitUntil(() => updated > 10)), + ok((yield waitUntil(() => updated > TIMES_TO_UPDATE)), "The overviews were updated several times."); ok("selectionEnabled" in framerate, diff -Nru firefox-45.0~b2+build1/devtools/client/performance/test/browser_perf-overview-render-03.js firefox-45.0~b3+build1/devtools/client/performance/test/browser_perf-overview-render-03.js --- firefox-45.0~b2+build1/devtools/client/performance/test/browser_perf-overview-render-03.js 2016-02-02 06:57:34.000000000 +0000 +++ firefox-45.0~b3+build1/devtools/client/performance/test/browser_perf-overview-render-03.js 2016-02-05 06:54:49.000000000 +0000 @@ -4,6 +4,7 @@ /** * Tests that the overview graphs share the exact same width and scaling. */ +const TIMES_TO_UPDATE = 2; function* spawnTest() { // This test seems to take a long time to cleanup on Ubuntu VMs. requestLongerTimeout(2); @@ -23,7 +24,7 @@ yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length); yield waitUntil(() => PerformanceController.getCurrentRecording().getMemory().length); yield waitUntil(() => PerformanceController.getCurrentRecording().getTicks().length); - yield waitUntil(() => updated > 10); + yield waitUntil(() => updated > TIMES_TO_UPDATE); yield stopRecording(panel); diff -Nru firefox-45.0~b2+build1/devtools/client/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js firefox-45.0~b3+build1/devtools/client/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js --- firefox-45.0~b2+build1/devtools/client/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js 2016-02-02 06:57:35.000000000 +0000 +++ firefox-45.0~b3+build1/devtools/client/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js 2016-02-05 06:54:49.000000000 +0000 @@ -38,7 +38,7 @@ let minTimestamp = Math.min.apply(null, aTimestampMilliseconds); let maxTimestamp = Math.max.apply(null, aTimestampMilliseconds); - ok(Math.abs(maxTimestamp - minTimestamp) < 1000, - "console.log message timestamp spread < 1000ms confirmed"); + ok(Math.abs(maxTimestamp - minTimestamp) < 2000, + "console.log message timestamp spread < 2000ms confirmed"); } } diff -Nru firefox-45.0~b2+build1/docshell/base/nsDocShell.cpp firefox-45.0~b3+build1/docshell/base/nsDocShell.cpp --- firefox-45.0~b2+build1/docshell/base/nsDocShell.cpp 2016-02-02 06:57:35.000000000 +0000 +++ firefox-45.0~b3+build1/docshell/base/nsDocShell.cpp 2016-02-05 06:54:50.000000000 +0000 @@ -14243,9 +14243,11 @@ NS_IMETHODIMP nsDocShell::IssueWarning(uint32_t aWarning, bool aAsError) { - nsCOMPtr doc = mContentViewer->GetDocument(); - if (doc) { - doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError); + if (mContentViewer) { + nsCOMPtr doc = mContentViewer->GetDocument(); + if (doc) { + doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError); + } } return NS_OK; } diff -Nru firefox-45.0~b2+build1/dom/base/nsPerformance.cpp firefox-45.0~b3+build1/dom/base/nsPerformance.cpp --- firefox-45.0~b2+build1/dom/base/nsPerformance.cpp 2016-02-02 06:57:36.000000000 +0000 +++ firefox-45.0~b3+build1/dom/base/nsPerformance.cpp 2016-02-05 06:54:50.000000000 +0000 @@ -11,7 +11,6 @@ #include "nsDOMNavigationTiming.h" #include "nsContentUtils.h" #include "nsIScriptSecurityManager.h" -#include "nsGlobalWindow.h" #include "nsIDOMWindow.h" #include "nsILoadInfo.h" #include "nsIURI.h" @@ -30,8 +29,6 @@ #include "mozilla/Preferences.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/TimeStamp.h" -#include "SharedWorker.h" -#include "ServiceWorker.h" #include "js/HeapAPI.h" #include "GeckoProfiler.h" #include "WorkerPrivate.h" @@ -919,37 +916,6 @@ } DOMHighResTimeStamp -PerformanceBase::TranslateTime(DOMHighResTimeStamp aTime, - const WindowOrWorkerOrSharedWorkerOrServiceWorker& aTimeSource, - ErrorResult& aRv) -{ - TimeStamp otherCreationTimeStamp; - - if (aTimeSource.IsWindow()) { - RefPtr performance = aTimeSource.GetAsWindow().GetPerformance(); - if (NS_WARN_IF(!performance)) { - aRv.Throw(NS_ERROR_FAILURE); - } - otherCreationTimeStamp = performance->CreationTimeStamp(); - } else if (aTimeSource.IsWorker()) { - otherCreationTimeStamp = aTimeSource.GetAsWorker().CreationTimeStamp(); - } else if (aTimeSource.IsSharedWorker()) { - SharedWorker& sharedWorker = aTimeSource.GetAsSharedWorker(); - WorkerPrivate* workerPrivate = sharedWorker.GetWorkerPrivate(); - otherCreationTimeStamp = workerPrivate->CreationTimeStamp(); - } else if (aTimeSource.IsServiceWorker()) { - ServiceWorker& serviceWorker = aTimeSource.GetAsServiceWorker(); - WorkerPrivate* workerPrivate = serviceWorker.GetWorkerPrivate(); - otherCreationTimeStamp = workerPrivate->CreationTimeStamp(); - } else { - MOZ_CRASH("This should not be possible."); - } - - return RoundTime( - aTime + (otherCreationTimeStamp - CreationTimeStamp()).ToMilliseconds()); -} - -DOMHighResTimeStamp PerformanceBase::RoundTime(double aTime) const { // Round down to the nearest 5us, because if the timer is too accurate people diff -Nru firefox-45.0~b2+build1/dom/base/nsPerformance.h firefox-45.0~b3+build1/dom/base/nsPerformance.h --- firefox-45.0~b2+build1/dom/base/nsPerformance.h 2016-02-02 06:57:36.000000000 +0000 +++ firefox-45.0~b3+build1/dom/base/nsPerformance.h 2016-02-05 06:54:50.000000000 +0000 @@ -30,7 +30,6 @@ class PerformanceEntry; class PerformanceObserver; -class WindowOrWorkerOrSharedWorkerOrServiceWorker; } // namespace dom } // namespace mozilla @@ -318,11 +317,6 @@ virtual DOMHighResTimeStamp Now() const = 0; - DOMHighResTimeStamp - TranslateTime(DOMHighResTimeStamp aTime, - const mozilla::dom::WindowOrWorkerOrSharedWorkerOrServiceWorker& aTimeSource, - mozilla::ErrorResult& aRv); - void Mark(const nsAString& aName, mozilla::ErrorResult& aRv); void ClearMarks(const mozilla::dom::Optional& aName); void Measure(const nsAString& aName, diff -Nru firefox-45.0~b2+build1/dom/base/test/empty_worker.js firefox-45.0~b3+build1/dom/base/test/empty_worker.js --- firefox-45.0~b2+build1/dom/base/test/empty_worker.js 2016-02-02 06:57:36.000000000 +0000 +++ firefox-45.0~b3+build1/dom/base/test/empty_worker.js 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -/* nothing here */ diff -Nru firefox-45.0~b2+build1/dom/base/test/mochitest.ini firefox-45.0~b3+build1/dom/base/test/mochitest.ini --- firefox-45.0~b2+build1/dom/base/test/mochitest.ini 2016-02-02 06:57:36.000000000 +0000 +++ firefox-45.0~b3+build1/dom/base/test/mochitest.ini 2016-02-05 06:54:50.000000000 +0000 @@ -256,7 +256,6 @@ file_explicit_user_agent.sjs referrer_change_server.sjs file_change_policy_redirect.html - empty_worker.js file_bug1198095.js [test_anonymousContent_api.html] @@ -860,6 +859,5 @@ [test_change_policy.html] skip-if = buildapp == 'b2g' #no ssl support [test_document.all_iteration.html] -[test_performance_translate.html] [test_bug1198095.html] [test_bug1187157.html] diff -Nru firefox-45.0~b2+build1/dom/base/test/test_performance_translate.html firefox-45.0~b3+build1/dom/base/test/test_performance_translate.html --- firefox-45.0~b2+build1/dom/base/test/test_performance_translate.html 2016-02-02 06:57:36.000000000 +0000 +++ firefox-45.0~b3+build1/dom/base/test/test_performance_translate.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ - - - - Test for performance.translate() - - - - - -
-      
-    
- - diff -Nru firefox-45.0~b2+build1/dom/events/Event.cpp firefox-45.0~b3+build1/dom/events/Event.cpp --- firefox-45.0~b2+build1/dom/events/Event.cpp 2016-02-02 06:57:37.000000000 +0000 +++ firefox-45.0~b3+build1/dom/events/Event.cpp 2016-02-05 06:54:51.000000000 +0000 @@ -1119,7 +1119,7 @@ MOZ_ASSERT(workerPrivate); TimeDuration duration = - mEvent->timeStamp - workerPrivate->CreationTimeStamp(); + mEvent->timeStamp - workerPrivate->NowBaseTimeStamp(); return duration.ToMilliseconds(); } diff -Nru firefox-45.0~b2+build1/dom/events/test/test_eventTimeStamp.html firefox-45.0~b3+build1/dom/events/test/test_eventTimeStamp.html --- firefox-45.0~b2+build1/dom/events/test/test_eventTimeStamp.html 2016-02-02 06:57:37.000000000 +0000 +++ firefox-45.0~b3+build1/dom/events/test/test_eventTimeStamp.html 2016-02-05 06:54:51.000000000 +0000 @@ -74,9 +74,8 @@ var worker = new Worker(window.URL.createObjectURL(blob)); worker.onmessage = function(evt) { var timeAfterEvent = window.performance.now(); - var time = window.performance.translateTime(evt.data, worker); - ok(time >= timeBeforeEvent && - time <= timeAfterEvent, + ok(evt.data > timeBeforeEvent && + evt.data < timeAfterEvent, "Event timestamp in dedicated worker (" + evt.data + ") is in expected range: (" + timeBeforeEvent + ", " + timeAfterEvent + ")"); diff -Nru firefox-45.0~b2+build1/dom/media/fmp4/MP4Decoder.cpp firefox-45.0~b3+build1/dom/media/fmp4/MP4Decoder.cpp --- firefox-45.0~b2+build1/dom/media/fmp4/MP4Decoder.cpp 2016-02-02 06:57:39.000000000 +0000 +++ firefox-45.0~b3+build1/dom/media/fmp4/MP4Decoder.cpp 2016-02-05 06:54:52.000000000 +0000 @@ -108,6 +108,7 @@ aMIMETypeExcludingCodecs.EqualsASCII(VIDEO_3GPP) || #endif aMIMETypeExcludingCodecs.EqualsASCII("video/mp4") || + aMIMETypeExcludingCodecs.EqualsASCII("video/quicktime") || aMIMETypeExcludingCodecs.EqualsASCII("video/x-m4v"); if (!isMP4Audio && !isMP4Video) { return false; diff -Nru firefox-45.0~b2+build1/dom/media/gtest/moz.build firefox-45.0~b3+build1/dom/media/gtest/moz.build --- firefox-45.0~b2+build1/dom/media/gtest/moz.build 2016-02-02 06:57:39.000000000 +0000 +++ firefox-45.0~b3+build1/dom/media/gtest/moz.build 2016-02-05 06:54:52.000000000 +0000 @@ -49,6 +49,7 @@ 'noise.mp3', 'noise_vbr.mp3', 'short-zero-in-moov.mp4', + 'short-zero-inband.mov', 'small-shot.mp3', 'test.webm', 'test_case_1224361.vp8.ivf', Binary files /tmp/tmpfEfzKX/msNJl3w7Fg/firefox-45.0~b2+build1/dom/media/gtest/short-zero-inband.mov and /tmp/tmpfEfzKX/RK7_IWUsIG/firefox-45.0~b3+build1/dom/media/gtest/short-zero-inband.mov differ diff -Nru firefox-45.0~b2+build1/dom/media/gtest/TestMP4Demuxer.cpp firefox-45.0~b3+build1/dom/media/gtest/TestMP4Demuxer.cpp --- firefox-45.0~b2+build1/dom/media/gtest/TestMP4Demuxer.cpp 2016-02-02 06:57:39.000000000 +0000 +++ firefox-45.0~b3+build1/dom/media/gtest/TestMP4Demuxer.cpp 2016-02-05 06:54:52.000000000 +0000 @@ -427,7 +427,7 @@ }); } -TEST(MP4Demuxer, ZeroInMoov) +TEST(MP4Demuxer, ZeroInLastMoov) { RefPtr binding = new MP4DemuxerBinding("short-zero-in-moov.mp4"); binding->RunTestAndWait([binding] () { @@ -436,3 +436,12 @@ }); } + +TEST(MP4Demuxer, ZeroInMoovQuickTime) +{ + RefPtr binding = new MP4DemuxerBinding("short-zero-inband.mov"); + binding->RunTestAndWait([binding] () { + // It demuxes without error. That is sufficient. + binding->mTaskQueue->BeginShutdown(); + }); +} diff -Nru firefox-45.0~b2+build1/dom/webidl/Performance.webidl firefox-45.0~b3+build1/dom/webidl/Performance.webidl --- firefox-45.0~b2+build1/dom/webidl/Performance.webidl 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/dom/webidl/Performance.webidl 2016-02-05 06:54:55.000000000 +0000 @@ -17,9 +17,6 @@ interface Performance { [DependsOn=DeviceState, Affects=Nothing] DOMHighResTimeStamp now(); - - [Throws] - DOMHighResTimeStamp translateTime(DOMHighResTimeStamp time, (Window or Worker or SharedWorker or ServiceWorker) timeSource); }; [Exposed=Window] diff -Nru firefox-45.0~b2+build1/dom/workers/Performance.cpp firefox-45.0~b3+build1/dom/workers/Performance.cpp --- firefox-45.0~b2+build1/dom/workers/Performance.cpp 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/dom/workers/Performance.cpp 2016-02-05 06:54:55.000000000 +0000 @@ -32,7 +32,7 @@ Performance::Now() const { TimeDuration duration = - TimeStamp::Now() - mWorkerPrivate->CreationTimeStamp(); + TimeStamp::Now() - mWorkerPrivate->NowBaseTimeStamp(); return RoundTime(duration.ToMilliseconds()); } @@ -52,7 +52,7 @@ } if (aProperty.EqualsLiteral("navigationStart")) { - return mWorkerPrivate->CreationTime(); + return mWorkerPrivate->NowBaseTime(); } MOZ_CRASH("IsPerformanceTimingAttribute and GetPerformanceTimingFromString are out of sync"); @@ -77,13 +77,13 @@ TimeStamp Performance::CreationTimeStamp() const { - return mWorkerPrivate->CreationTimeStamp(); + return mWorkerPrivate->NowBaseTimeStamp(); } DOMHighResTimeStamp Performance::CreationTime() const { - return mWorkerPrivate->CreationTime(); + return mWorkerPrivate->NowBaseTime(); } void diff -Nru firefox-45.0~b2+build1/dom/workers/ServiceWorker.cpp firefox-45.0~b3+build1/dom/workers/ServiceWorker.cpp --- firefox-45.0~b2+build1/dom/workers/ServiceWorker.cpp 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/dom/workers/ServiceWorker.cpp 2016-02-05 06:54:55.000000000 +0000 @@ -101,13 +101,6 @@ aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo)); } -WorkerPrivate* -ServiceWorker::GetWorkerPrivate() const -{ - ServiceWorkerPrivate* workerPrivate = mInfo->WorkerPrivate(); - return workerPrivate->GetWorkerPrivate(); -} - } // namespace workers } // namespace dom } // namespace mozilla diff -Nru firefox-45.0~b2+build1/dom/workers/ServiceWorker.h firefox-45.0~b3+build1/dom/workers/ServiceWorker.h --- firefox-45.0~b2+build1/dom/workers/ServiceWorker.h 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/dom/workers/ServiceWorker.h 2016-02-05 06:54:55.000000000 +0000 @@ -67,9 +67,6 @@ const Optional>& aTransferable, ErrorResult& aRv); - WorkerPrivate* - GetWorkerPrivate() const; - private: // This class can only be created from the ServiceWorkerManager. ServiceWorker(nsPIDOMWindow* aWindow, ServiceWorkerInfo* aInfo); diff -Nru firefox-45.0~b2+build1/dom/workers/ServiceWorkerPrivate.h firefox-45.0~b3+build1/dom/workers/ServiceWorkerPrivate.h --- firefox-45.0~b2+build1/dom/workers/ServiceWorkerPrivate.h 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/dom/workers/ServiceWorkerPrivate.h 2016-02-05 06:54:55.000000000 +0000 @@ -126,12 +126,6 @@ void NoteStoppedControllingDocuments(); - WorkerPrivate* - GetWorkerPrivate() const - { - return mWorkerPrivate; - } - void Activated(); diff -Nru firefox-45.0~b2+build1/dom/workers/WorkerPrivate.cpp firefox-45.0~b3+build1/dom/workers/WorkerPrivate.cpp --- firefox-45.0~b2+build1/dom/workers/WorkerPrivate.cpp 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/dom/workers/WorkerPrivate.cpp 2016-02-05 06:54:55.000000000 +0000 @@ -116,11 +116,22 @@ #define PREF_WORKERS_ENABLED "dom.workers.enabled" -#ifdef WORKER_LOGGING -#define LOG(_args) do { printf _args ; fflush(stdout); } while (0) -#else -#define LOG(_args) do { } while (0) -#endif +static mozilla::LazyLogModule sWorkerPrivateLog("WorkerPrivate"); +static mozilla::LazyLogModule sWorkerTimeoutsLog("WorkerTimeouts"); + +mozilla::LogModule* +WorkerLog() +{ + return sWorkerPrivateLog; +} + +mozilla::LogModule* +TimeoutsLog() +{ + return sWorkerTimeoutsLog; +} + +#define LOG(log, _args) MOZ_LOG(log, LogLevel::Debug, _args); using namespace mozilla; using namespace mozilla::dom; @@ -1119,14 +1130,19 @@ } }; -class TimerRunnable final : public WorkerRunnable +class TimerRunnable final : public WorkerRunnable, + public nsITimerCallback { public: + NS_DECL_ISUPPORTS_INHERITED + explicit TimerRunnable(WorkerPrivate* aWorkerPrivate) : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) { } private: + ~TimerRunnable() {} + virtual bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { @@ -1146,8 +1162,16 @@ { return aWorkerPrivate->RunExpiredTimeouts(aCx); } + + NS_IMETHOD + Notify(nsITimer* aTimer) override + { + return Run(); + } }; +NS_IMPL_ISUPPORTS_INHERITED(TimerRunnable, WorkerRunnable, nsITimerCallback) + class DebuggerImmediateRunnable : public WorkerRunnable { RefPtr mHandler; @@ -2198,11 +2222,25 @@ aParent->CopyJSSettings(mJSSettings); MOZ_ASSERT(IsDedicatedWorker()); + mNowBaseTimeStamp = aParent->NowBaseTimeStamp(); + mNowBaseTimeHighRes = aParent->NowBaseTime(); } else { AssertIsOnMainThread(); RuntimeService::GetDefaultJSSettings(mJSSettings); + + if (IsDedicatedWorker() && mLoadInfo.mWindow && + mLoadInfo.mWindow->GetPerformance()) { + mNowBaseTimeStamp = mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()-> + GetNavigationStartTimeStamp(); + mNowBaseTimeHighRes = + mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()-> + GetNavigationStartHighRes(); + } else { + mNowBaseTimeStamp = CreationTimeStamp(); + mNowBaseTimeHighRes = CreationTime(); + } } } @@ -4607,8 +4645,8 @@ mPeriodicGCTimerRunning = false; mIdleGCTimerRunning = false; - - LOG(("Worker %p canceled GC timer because %s\n", this, + LOG(WorkerLog(), + ("Worker %p canceled GC timer because %s\n", this, aMode == PeriodicTimer ? "periodic" : aMode == IdleTimer ? "idle" : "none")); @@ -4640,11 +4678,11 @@ "dom::workers::DummyCallback(2)"))); if (aMode == PeriodicTimer) { - LOG(("Worker %p scheduled periodic GC timer\n", this)); + LOG(WorkerLog(), ("Worker %p scheduled periodic GC timer\n", this)); mPeriodicGCTimerRunning = true; } else { - LOG(("Worker %p scheduled idle GC timer\n", this)); + LOG(WorkerLog(), ("Worker %p scheduled idle GC timer\n", this)); mIdleGCTimerRunning = true; } } @@ -4659,7 +4697,7 @@ // Always make sure the timer is canceled. MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mGCTimer->Cancel())); - LOG(("Worker %p killed the GC timer\n", this)); + LOG(WorkerLog(), ("Worker %p killed the GC timer\n", this)); mGCTimer = nullptr; mPeriodicGCTimerTarget = nullptr; @@ -5174,8 +5212,10 @@ { AssertIsOnWorkerThread(); + LOG(TimeoutsLog(), ("Worker %p CancelAllTimeouts.\n", this)); + if (mTimerRunning) { - NS_ASSERTION(mTimer, "Huh?!"); + NS_ASSERTION(mTimer && mTimerRunnable, "Huh?!"); NS_ASSERTION(!mTimeouts.IsEmpty(), "Huh?!"); if (NS_FAILED(mTimer->Cancel())) { @@ -5199,6 +5239,7 @@ #endif mTimer = nullptr; + mTimerRunnable = nullptr; } already_AddRefed @@ -5870,30 +5911,22 @@ nsAutoPtr* insertedInfo = mTimeouts.InsertElementSorted(newInfo.forget(), GetAutoPtrComparator(mTimeouts)); + LOG(TimeoutsLog(), ("Worker %p has new timeout: delay=%d interval=%s\n", + this, aTimeout, aIsInterval ? "yes" : "no")); + // If the timeout we just made is set to fire next then we need to update the - // timer. - if (insertedInfo == mTimeouts.Elements()) { + // timer, unless we're currently running timeouts. + if (insertedInfo == mTimeouts.Elements() && !mRunningExpiredTimeouts) { nsresult rv; if (!mTimer) { - nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); + mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); if (NS_FAILED(rv)) { aRv.Throw(rv); return 0; } - RefPtr runnable = new TimerRunnable(this); - - RefPtr target = - new TimerThreadEventTarget(this, runnable); - - rv = timer->SetTarget(target); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - return 0; - } - - timer.swap(mTimer); + mTimerRunnable = new TimerRunnable(this); } if (!mTimerRunning) { @@ -5943,7 +5976,7 @@ return true; } - NS_ASSERTION(mTimer, "Must have a timer!"); + NS_ASSERTION(mTimer && mTimerRunnable, "Must have a timer!"); NS_ASSERTION(!mTimeouts.IsEmpty(), "Should have some work to do!"); bool retval = true; @@ -5953,7 +5986,13 @@ // We want to make sure to run *something*, even if the timer fired a little // early. Fudge the value of now to at least include the first timeout. - const TimeStamp now = std::max(TimeStamp::Now(), mTimeouts[0]->mTargetTime); + const TimeStamp actual_now = TimeStamp::Now(); + const TimeStamp now = std::max(actual_now, mTimeouts[0]->mTargetTime); + + if (now != actual_now) { + LOG(TimeoutsLog(), ("Worker %p fudged timeout by %f ms.\n", this, + (now - actual_now).ToMilliseconds())); + } nsAutoTArray expiredTimeouts; for (uint32_t index = 0; index < mTimeouts.Length(); index++) { @@ -5975,6 +6014,9 @@ continue; } + LOG(TimeoutsLog(), ("Worker %p executing timeout with original delay %f ms.\n", + this, info->mInterval.ToMilliseconds())); + // Always call JS_ReportPendingException if something fails, and if // JS_ReportPendingException returns false (i.e. uncatchable exception) then // break out of the loop. @@ -6072,16 +6114,26 @@ WorkerPrivate::RescheduleTimeoutTimer(JSContext* aCx) { AssertIsOnWorkerThread(); + MOZ_ASSERT(!mRunningExpiredTimeouts); NS_ASSERTION(!mTimeouts.IsEmpty(), "Should have some timeouts!"); - NS_ASSERTION(mTimer, "Should have a timer!"); + NS_ASSERTION(mTimer && mTimerRunnable, "Should have a timer!"); + + // NB: This is important! The timer may have already fired, e.g. if a timeout + // callback itself calls setTimeout for a short duration and then takes longer + // than that to finish executing. If that has happened, it's very important + // that we don't execute the event that is now pending in our event queue, or + // our code in RunExpiredTimeouts to "fudge" the timeout value will unleash an + // early timeout when we execute the event we're about to queue. + mTimer->Cancel(); double delta = (mTimeouts[0]->mTargetTime - TimeStamp::Now()).ToMilliseconds(); uint32_t delay = delta > 0 ? std::min(delta, double(UINT32_MAX)) : 0; - nsresult rv = mTimer->InitWithNamedFuncCallback( - DummyCallback, nullptr, delay, nsITimer::TYPE_ONE_SHOT, - "dom::workers::DummyCallback(3)"); + LOG(TimeoutsLog(), ("Worker %p scheduled timer for %d ms, %d pending timeouts\n", + this, delay, mTimeouts.Length())); + + nsresult rv = mTimer->InitWithCallback(mTimerRunnable, delay, nsITimer::TYPE_ONE_SHOT); if (NS_FAILED(rv)) { JS_ReportError(aCx, "Failed to start timer!"); return false; @@ -6188,17 +6240,17 @@ JS::GCForReason(rt, GC_SHRINK, JS::gcreason::DOM_WORKER); if (!aCollectChildren) { - LOG(("Worker %p collected idle garbage\n", this)); + LOG(WorkerLog(), ("Worker %p collected idle garbage\n", this)); } } else { JS::GCForReason(rt, GC_NORMAL, JS::gcreason::DOM_WORKER); - LOG(("Worker %p collected garbage\n", this)); + LOG(WorkerLog(), ("Worker %p collected garbage\n", this)); } } else { JS_MaybeGC(aCx); - LOG(("Worker %p collected periodic garbage\n", this)); + LOG(WorkerLog(), ("Worker %p collected periodic garbage\n", this)); } if (aCollectChildren) { diff -Nru firefox-45.0~b2+build1/dom/workers/WorkerPrivate.h firefox-45.0~b3+build1/dom/workers/WorkerPrivate.h --- firefox-45.0~b2+build1/dom/workers/WorkerPrivate.h 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/dom/workers/WorkerPrivate.h 2016-02-05 06:54:55.000000000 +0000 @@ -191,6 +191,8 @@ WorkerType mWorkerType; TimeStamp mCreationTimeStamp; DOMHighResTimeStamp mCreationTimeHighRes; + TimeStamp mNowBaseTimeStamp; + DOMHighResTimeStamp mNowBaseTimeHighRes; protected: // The worker is owned by its thread, which is represented here. This is set @@ -552,6 +554,16 @@ return mCreationTimeHighRes; } + TimeStamp NowBaseTimeStamp() const + { + return mNowBaseTimeStamp; + } + + DOMHighResTimeStamp NowBaseTime() const + { + return mNowBaseTimeHighRes; + } + nsIPrincipal* GetPrincipal() const { @@ -914,6 +926,7 @@ nsTArray> mSyncLoopStack; nsCOMPtr mTimer; + nsCOMPtr mTimerRunnable; nsCOMPtr mGCTimer; nsCOMPtr mPeriodicGCTimerTarget; diff -Nru firefox-45.0~b2+build1/gfx/gl/GLScreenBuffer.cpp firefox-45.0~b3+build1/gfx/gl/GLScreenBuffer.cpp --- firefox-45.0~b2+build1/gfx/gl/GLScreenBuffer.cpp 2016-02-02 06:57:30.000000000 +0000 +++ firefox-45.0~b3+build1/gfx/gl/GLScreenBuffer.cpp 2016-02-05 06:54:46.000000000 +0000 @@ -840,7 +840,8 @@ DrawBuffer::~DrawBuffer() { - mGL->MakeCurrent(); + if (!mGL->MakeCurrent()) + return; GLuint fb = mFB; GLuint rbs[] = { @@ -917,7 +918,8 @@ ReadBuffer::~ReadBuffer() { - mGL->MakeCurrent(); + if (!mGL->MakeCurrent()) + return; GLuint fb = mFB; GLuint rbs[] = { diff -Nru firefox-45.0~b2+build1/gfx/thebes/gfxUserFontSet.cpp firefox-45.0~b3+build1/gfx/thebes/gfxUserFontSet.cpp --- firefox-45.0~b2+build1/gfx/thebes/gfxUserFontSet.cpp 2016-02-02 06:57:32.000000000 +0000 +++ firefox-45.0~b3+build1/gfx/thebes/gfxUserFontSet.cpp 2016-02-05 06:54:47.000000000 +0000 @@ -174,8 +174,15 @@ : mUserFontEntry(aUserFontEntry) {} virtual ots::TableAction GetTableAction(uint32_t aTag) override { - // preserve Graphite, color glyph and SVG tables - if (aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') || + // Preserve Graphite, color glyph and SVG tables + if ( +#ifdef RELEASE_BUILD // For Beta/Release, also allow OT Layout tables through + // unchecked, and rely on harfbuzz to handle them safely. + aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') || + aTag == TRUETYPE_TAG('G', 'P', 'O', 'S') || + aTag == TRUETYPE_TAG('G', 'S', 'U', 'B') || +#endif + aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') || aTag == TRUETYPE_TAG('S', 'i', 'l', 'l') || aTag == TRUETYPE_TAG('G', 'l', 'o', 'c') || aTag == TRUETYPE_TAG('G', 'l', 'a', 't') || diff -Nru firefox-45.0~b2+build1/image/Downscaler.cpp firefox-45.0~b3+build1/image/Downscaler.cpp --- firefox-45.0~b2+build1/image/Downscaler.cpp 2016-02-02 06:57:32.000000000 +0000 +++ firefox-45.0~b3+build1/image/Downscaler.cpp 2016-02-05 06:54:47.000000000 +0000 @@ -99,11 +99,21 @@ 0, mTargetSize.width, mXFilter.get()); + if (mXFilter->max_filter() <= 0 || mXFilter->num_values() != mTargetSize.width) { + NS_WARNING("Failed to compute filters for image downscaling"); + return NS_ERROR_OUT_OF_MEMORY; + } + skia::resize::ComputeFilters(resizeMethod, mOriginalSize.height, mTargetSize.height, 0, mTargetSize.height, mYFilter.get()); + if (mYFilter->max_filter() <= 0 || mYFilter->num_values() != mTargetSize.height) { + NS_WARNING("Failed to compute filters for image downscaling"); + return NS_ERROR_OUT_OF_MEMORY; + } + // Allocate the buffer, which contains scanlines of the original image. // pad by 15 to handle overreads by the simd code size_t bufferLen = mOriginalSize.width * sizeof(uint32_t) + 15; diff -Nru firefox-45.0~b2+build1/ipc/glue/MessageChannel.cpp firefox-45.0~b3+build1/ipc/glue/MessageChannel.cpp --- firefox-45.0~b2+build1/ipc/glue/MessageChannel.cpp 2016-02-02 06:58:42.000000000 +0000 +++ firefox-45.0~b3+build1/ipc/glue/MessageChannel.cpp 2016-02-05 06:54:49.000000000 +0000 @@ -319,6 +319,7 @@ mTimeoutMs(kNoTimeout), mInTimeoutSecondHalf(false), mNextSeqno(0), + mLastSendError(SyncSendError::SendSuccess), mAwaitingSyncReply(false), mAwaitingSyncReplyPriority(0), mDispatchingSyncMessage(false), @@ -326,6 +327,7 @@ mDispatchingAsyncMessage(false), mDispatchingAsyncMessagePriority(0), mCurrentTransaction(0), + mPendingSendPriorities(0), mTimedOutMessageSeqno(0), mTimedOutMessagePriority(0), mRecvdErrors(0), @@ -573,9 +575,10 @@ class CancelMessage : public IPC::Message { public: - CancelMessage() : + explicit CancelMessage(int transaction) : IPC::Message(MSG_ROUTING_NONE, CANCEL_MESSAGE_TYPE, PRIORITY_NORMAL) { + set_transaction_id(transaction); } static bool Read(const Message* msg) { return true; @@ -603,20 +606,9 @@ return true; } else if (CANCEL_MESSAGE_TYPE == aMsg.type()) { IPC_LOG("Cancel from message"); - - if (aMsg.transaction_id() == mTimedOutMessageSeqno) { - // An unusual case: We timed out a transaction which the other - // side then cancelled. In this case we just leave the timedout - // state and try to forget this ever happened. - mTimedOutMessageSeqno = 0; - return true; - } else { - MOZ_RELEASE_ASSERT(mCurrentTransaction == aMsg.transaction_id()); - CancelCurrentTransactionInternal(); - NotifyWorkerThread(); - IPC_LOG("Notified"); - return true; - } + CancelTransaction(aMsg.transaction_id()); + NotifyWorkerThread(); + return true; } } return false; @@ -691,7 +683,7 @@ if (aMsg.seqno() == mTimedOutMessageSeqno) { // Drop the message, but allow future sync messages to be sent. IPC_LOG("Received reply to timedout message; igoring; xid=%d", mTimedOutMessageSeqno); - mTimedOutMessageSeqno = 0; + EndTimeout(); return; } @@ -751,10 +743,18 @@ } } + bool wakeUpSyncSend = AwaitingSyncReply() && !ShouldDeferMessage(aMsg); + bool shouldWakeUp = AwaitingInterruptReply() || - (AwaitingSyncReply() && !ShouldDeferMessage(aMsg)) || + wakeUpSyncSend || AwaitingIncomingMessage(); + // Although we usually don't need to post an OnMaybeDequeueOne task if + // shouldWakeUp is true, it's easier to post anyway than to have to + // guarantee that every Send call processes everything it's supposed to + // before returning. + bool shouldPostTask = !shouldWakeUp || wakeUpSyncSend; + IPC_LOG("Receive on link thread; seqno=%d, xid=%d, shouldWakeUp=%d", aMsg.seqno(), aMsg.transaction_id(), shouldWakeUp); @@ -784,10 +784,9 @@ if (shouldWakeUp) { NotifyWorkerThread(); - } else { - // Worker thread is either not blocked on a reply, or this is an - // incoming Interrupt that raced with outgoing sync, and needs to be - // deferred to a later event-loop iteration. + } + + if (shouldPostTask) { if (!compress) { // If we compressed away the previous message, we'll re-use // its pending task. @@ -797,17 +796,28 @@ } void -MessageChannel::ProcessPendingRequests(int transaction, int prio) +MessageChannel::ProcessPendingRequests(int seqno, int transaction) { - IPC_LOG("ProcessPendingRequests"); + IPC_LOG("ProcessPendingRequests for seqno=%d, xid=%d", seqno, transaction); // Loop until there aren't any more priority messages to process. for (;;) { + // If we canceled during ProcessPendingRequest, then we need to leave + // immediately because the results of ShouldDeferMessage will be + // operating with weird state (as if no Send is in progress). That could + // cause even normal priority sync messages to be processed (but not + // normal priority async messages), which would break message ordering. + if (WasTransactionCanceled(transaction)) { + return; + } + mozilla::Vector toProcess; for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) { Message &msg = *it; + MOZ_ASSERT(mCurrentTransaction == transaction, + "Calling ShouldDeferMessage when cancelled"); bool defer = ShouldDeferMessage(msg); // Only log the interesting messages. @@ -831,56 +841,28 @@ for (auto it = toProcess.begin(); it != toProcess.end(); it++) ProcessPendingRequest(*it); - - // If we canceled during ProcessPendingRequest, then we need to leave - // immediately because the results of ShouldDeferMessage will be - // operating with weird state (as if no Send is in progress). That could - // cause even normal priority sync messages to be processed (but not - // normal priority async messages), which would break message ordering. - if (WasTransactionCanceled(transaction, prio)) { - return; - } } } bool -MessageChannel::WasTransactionCanceled(int transaction, int prio) +MessageChannel::WasTransactionCanceled(int transaction) { - if (transaction == mCurrentTransaction) { - return false; + if (transaction != mCurrentTransaction) { + // Imagine this scenario: + // 1. Child sends high prio sync message H1. + // 2. Parent sends reply to H1. + // 3. Parent sends high prio sync message H2. + // 4. Child's link thread receives H1 reply and H2 before worker wakes up. + // 5. Child dispatches H2 while still waiting for H1 reply. + // 6. Child cancels H2. + // + // In this case H1 will also be considered cancelled. However, its + // reply is still sitting in mRecvd, which can trip up later Sends. So + // we null it out here. + mRecvd = nullptr; + return true; } - - // This isn't an assert so much as an intentional crash because we're in a - // situation that we don't know how to recover from: The child is awaiting - // a reply to a normal-priority sync message. The transaction that this - // message initiated has now been canceled. That could only happen if a CPOW - // raced with the sync message and was dispatched by the child while the - // child was awaiting the sync reply; at some point while dispatching the - // CPOW, the transaction was canceled. - // - // Notes: - // - // 1. We don't want to cancel the normal-priority sync message along with - // the CPOWs because the browser relies on these messages working - // reliably. - // - // 2. Ideally we would like to avoid dispatching CPOWs while awaiting a sync - // response. This isn't possible though. To avoid deadlock, the parent would - // have to dispatch the sync message while waiting for the CPOW - // response. However, it wouldn't have dispatched async messages at that - // time, so we would have a message ordering bug. Dispatching the async - // messages first causes other hard-to-handle situations (what if they send - // CPOWs?). - // - // 3. We would like to be able to cancel the CPOWs but not the sync - // message. However, that would leave both the parent and the child running - // code at the same time, all while the sync message is still - // outstanding. That can cause a problem where message replies are received - // out of order. - IPC_ASSERT(prio != IPC::Message::PRIORITY_NORMAL, - "Intentional crash: We canceled a CPOW that was racing with a sync message."); - - return true; + return false; } bool @@ -910,6 +892,7 @@ // message receives a reply, we'll be able to send more sync messages // again. IPC_LOG("Send() failed due to previous timeout"); + mLastSendError = SyncSendError::PreviousTimeout; return false; } @@ -920,6 +903,7 @@ // Don't allow sending CPOWs while we're dispatching a sync message. // If you want to do that, use sendRpcMessage instead. IPC_LOG("Prio forbids send"); + mLastSendError = SyncSendError::SendingCPOWWhileDispatchingSync; return false; } @@ -931,6 +915,8 @@ // sync messages it can send are high-priority. Mainly we want to ensure // here that we don't return false for non-CPOW messages. MOZ_ASSERT(msg->priority() == IPC::Message::PRIORITY_HIGH); + IPC_LOG("Sending while dispatching urgent message"); + mLastSendError = SyncSendError::SendingCPOWWhileDispatchingUrgent; return false; } @@ -940,10 +926,9 @@ { MOZ_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage()); IPC_LOG("Cancel from Send"); - CancelMessage *cancel = new CancelMessage(); - cancel->set_transaction_id(mCurrentTransaction); + CancelMessage *cancel = new CancelMessage(mCurrentTransaction); + CancelTransaction(mCurrentTransaction); mLink->SendMessage(cancel); - CancelCurrentTransactionInternal(); } IPC_ASSERT(msg->is_sync(), "can only Send() sync messages here"); @@ -962,6 +947,7 @@ if (!Connected()) { ReportConnectionError("MessageChannel::SendAndWait", msg); + mLastSendError = SyncSendError::NotConnectedBeforeSend; return false; } @@ -975,24 +961,27 @@ AutoSetValue prioSet(mAwaitingSyncReplyPriority, prio); AutoEnterTransaction transact(this, seqno); + int prios = mPendingSendPriorities | (1 << prio); + AutoSetValue priosSet(mPendingSendPriorities, prios); + int32_t transaction = mCurrentTransaction; msg->set_transaction_id(transaction); - IPC_LOG("Send seqno=%d, xid=%d", seqno, transaction); - - ProcessPendingRequests(transaction, prio); - if (WasTransactionCanceled(transaction, prio)) { - IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction); - return false; - } + IPC_LOG("Send seqno=%d, xid=%d, pending=%d", seqno, transaction, prios); bool handleWindowsMessages = mListener->HandleWindowsMessages(*aMsg); mLink->SendMessage(msg.forget()); while (true) { - ProcessPendingRequests(transaction, prio); - if (WasTransactionCanceled(transaction, prio)) { + ProcessPendingRequests(seqno, transaction); + if (WasTransactionCanceled(transaction)) { IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction); + mLastSendError = SyncSendError::CancelledAfterSend; + return false; + } + if (!Connected()) { + ReportConnectionError("MessageChannel::Send"); + mLastSendError = SyncSendError::DisconnectedDuringSend; return false; } @@ -1000,6 +989,7 @@ if (mRecvdErrors) { IPC_LOG("Error: seqno=%d, xid=%d", seqno, transaction); mRecvdErrors--; + mLastSendError = SyncSendError::ReplyError; return false; } @@ -1015,11 +1005,13 @@ if (!Connected()) { ReportConnectionError("MessageChannel::SendAndWait"); + mLastSendError = SyncSendError::DisconnectedDuringSend; return false; } - if (WasTransactionCanceled(transaction, prio)) { + if (WasTransactionCanceled(transaction)) { IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction); + mLastSendError = SyncSendError::CancelledAfterSend; return false; } @@ -1027,22 +1019,29 @@ // if neither side has any other message Sends on the stack). bool canTimeOut = transaction == seqno; if (maybeTimedOut && canTimeOut && !ShouldContinueFromTimeout()) { - IPC_LOG("Timing out Send: xid=%d", transaction); - - // We might have received a reply during WaitForSyncNotify or inside - // ShouldContinueFromTimeout (which drops the lock). We need to make - // sure not to set mTimedOutMessageSeqno if that happens, since then - // there would be no way to unset it. + // Since ShouldContinueFromTimeout drops the lock, we need to + // re-check all our conditions here. We shouldn't time out if any of + // these things happen because there won't be a reply to the timed + // out message in these cases. + if (WasTransactionCanceled(transaction)) { + IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction); + mLastSendError = SyncSendError::CancelledAfterSend; + return false; + } if (mRecvdErrors) { mRecvdErrors--; + mLastSendError = SyncSendError::ReplyError; return false; } if (mRecvd) { break; } + IPC_LOG("Timing out Send: xid=%d", transaction); + mTimedOutMessageSeqno = seqno; mTimedOutMessagePriority = prio; + mLastSendError = SyncSendError::TimedOut; return false; } } @@ -1056,6 +1055,7 @@ *aReply = Move(*mRecvd); mRecvd = nullptr; + mLastSendError = SyncSendError::SendSuccess; return true; } @@ -1320,6 +1320,37 @@ if (!mDeferred.empty()) MaybeUndeferIncall(); + // If we've timed out a message and we're awaiting the reply to the timed + // out message, we have to be careful what messages we process. Here's what + // can go wrong: + // 1. child sends a normal priority sync message S + // 2. parent sends a high priority sync message H at the same time + // 3. parent times out H + // 4. child starts processing H and sends a high priority message H' nested + // within the same transaction + // 5. parent dispatches S and sends reply + // 6. child asserts because it instead expected a reply to H'. + // + // To solve this, we refuse to process S in the parent until we get a reply + // to H. More generally, let the timed out message be M. We don't process a + // message unless the child would need the response to that message in order + // to process M. Those messages are the ones that have a higher priority + // than M or that are part of the same transaction as M. + if (mTimedOutMessageSeqno) { + for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); it++) { + Message &msg = *it; + if (msg.priority() > mTimedOutMessagePriority || + (msg.priority() == mTimedOutMessagePriority + && msg.transaction_id() == mTimedOutMessageSeqno)) + { + *recvd = Move(msg); + mPending.erase(it); + return true; + } + } + return false; + } + if (mPending.empty()) return false; @@ -1412,22 +1443,7 @@ MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy; Result rv; - if (mTimedOutMessageSeqno && mTimedOutMessagePriority >= prio) { - // If the other side sends a message in response to one of our messages - // that we've timed out, then we reply with an error. - // - // We do this because want to avoid a situation where we process an - // incoming message from the child here while it simultaneously starts - // processing our timed-out CPOW. It's very bad for both sides to - // be processing sync messages concurrently. - // - // The only exception is if the incoming message has urgent priority and - // our timed-out message had only high priority. In that case it's safe - // to process the incoming message because we know that the child won't - // process anything (the child will defer incoming messages when waiting - // for a response to its urgent message). - rv = MsgNotAllowed; - } else { + { AutoSetValue blocked(blockingVar, this); AutoSetValue sync(mDispatchingSyncMessage, true); AutoSetValue prioSet(mDispatchingSyncMessagePriority, prio); @@ -1832,6 +1848,8 @@ AssertLinkThread(); mMonitor->AssertCurrentThreadOwns(); + IPC_LOG("OnChannelErrorFromLink"); + if (InterruptStackDepth() > 0) NotifyWorkerThread(); @@ -2097,7 +2115,25 @@ } void -MessageChannel::CancelCurrentTransactionInternal() +MessageChannel::EndTimeout() +{ + mMonitor->AssertCurrentThreadOwns(); + + IPC_LOG("Ending timeout of seqno=%d", mTimedOutMessageSeqno); + mTimedOutMessageSeqno = 0; + mTimedOutMessagePriority = 0; + + for (size_t i = 0; i < mPending.size(); i++) { + // There may be messages in the queue that we expected to process from + // OnMaybeDequeueOne. But during the timeout, that function will skip + // some messages. Now they're ready to be processed, so we enqueue more + // tasks. + mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); + } +} + +void +MessageChannel::CancelTransaction(int transaction) { mMonitor->AssertCurrentThreadOwns(); @@ -2111,20 +2147,91 @@ // tampered with (by us). If so, they don't reset the variable to the old // value. - IPC_LOG("CancelInternal: current xid=%d", mCurrentTransaction); + IPC_LOG("CancelTransaction: xid=%d prios=%d", transaction, mPendingSendPriorities); - MOZ_ASSERT(mCurrentTransaction); - mCurrentTransaction = 0; + if (mPendingSendPriorities & (1 << IPC::Message::PRIORITY_NORMAL)) { + // This isn't an assert so much as an intentional crash because we're in + // a situation that we don't know how to recover from: The child is + // awaiting a reply to a normal-priority sync message. The transaction + // that this message initiated has now been canceled. That could only + // happen if a CPOW raced with the sync message and was dispatched by + // the child while the child was awaiting the sync reply; at some point + // while dispatching the CPOW, the transaction was canceled. + // + // Notes: + // + // 1. We don't want to cancel the normal-priority sync message along + // with the CPOWs because the browser relies on these messages working + // reliably. + // + // 2. Ideally we would like to avoid dispatching CPOWs while awaiting a + // sync response. This isn't possible though. To avoid deadlock, the + // parent would have to dispatch the sync message while waiting for the + // CPOW response. However, it wouldn't have dispatched async messages at + // that time, so we would have a message ordering bug. Dispatching the + // async messages first causes other hard-to-handle situations (what if + // they send CPOWs?). + // + // 3. We would like to be able to cancel the CPOWs but not the sync + // message. However, that would leave both the parent and the child + // running code at the same time, all while the sync message is still + // outstanding. That can cause a problem where message replies are + // received out of order. + mListener->IntentionalCrash(); + } + + // An unusual case: We timed out a transaction which the other side then + // cancelled. In this case we just leave the timedout state and try to + // forget this ever happened. + if (transaction == mTimedOutMessageSeqno) { + IPC_LOG("Cancelled timed out message %d", mTimedOutMessageSeqno); + EndTimeout(); + + // Normally mCurrentTransaction == 0 here. But it can be non-zero if: + // 1. Parent sends hi prio message H. + // 2. Parent times out H. + // 3. Child dispatches H and sends nested message H' (same transaction). + // 4. Parent dispatches H' and cancels. + MOZ_ASSERT_IF(mCurrentTransaction, mCurrentTransaction == transaction); + mCurrentTransaction = 0; - mAwaitingSyncReply = false; - mAwaitingSyncReplyPriority = 0; + // During a timeout Send should always fail. + MOZ_ASSERT(!mAwaitingSyncReply); + } else { + MOZ_ASSERT(mCurrentTransaction == transaction); + mCurrentTransaction = 0; + + mAwaitingSyncReply = false; + mAwaitingSyncReplyPriority = 0; + } + + DebugOnly foundSync = false; + for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) { + Message &msg = *it; + + // If there was a race between the parent and the child, then we may + // have a queued sync message. We want to drop this message from the + // queue since it will get cancelled along with the transaction being + // cancelled. We don't bother doing this for normal priority messages + // because the child is just going to crash in that case, and we want to + // avoid processing messages out of order in the short time before it + // crashes. + if (msg.is_sync() && msg.priority() != IPC::Message::PRIORITY_NORMAL) { + MOZ_ASSERT(!foundSync); + MOZ_ASSERT(msg.transaction_id() != transaction); + IPC_LOG("Removing msg from queue seqno=%d xid=%d", msg.seqno(), msg.transaction_id()); + foundSync = true; + it = mPending.erase(it); + continue; + } - for (size_t i = 0; i < mPending.size(); i++) { // There may be messages in the queue that we expected to process from // ProcessPendingRequests. However, Send will no longer call that // function once it's been canceled. So we may need to process these // messages in the normal event loop instead. mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); + + it++; } // We could also zero out mDispatchingSyncMessage here. However, that would @@ -2138,10 +2245,17 @@ { MonitorAutoLock lock(*mMonitor); if (mCurrentTransaction) { - CancelMessage *cancel = new CancelMessage(); - cancel->set_transaction_id(mCurrentTransaction); + if (DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_URGENT || + DispatchingAsyncMessagePriority() == IPC::Message::PRIORITY_URGENT) + { + mListener->IntentionalCrash(); + } + + IPC_LOG("Cancel requested: current xid=%d", mCurrentTransaction); + MOZ_ASSERT(DispatchingSyncMessage()); + CancelMessage *cancel = new CancelMessage(mCurrentTransaction); + CancelTransaction(mCurrentTransaction); mLink->SendMessage(cancel); - CancelCurrentTransactionInternal(); } } diff -Nru firefox-45.0~b2+build1/ipc/glue/MessageChannel.h firefox-45.0~b3+build1/ipc/glue/MessageChannel.h --- firefox-45.0~b2+build1/ipc/glue/MessageChannel.h 2016-02-02 06:58:42.000000000 +0000 +++ firefox-45.0~b3+build1/ipc/glue/MessageChannel.h 2016-02-05 06:54:49.000000000 +0000 @@ -44,6 +44,19 @@ ~RefCountedMonitor() {} }; +enum class SyncSendError { + SendSuccess, + PreviousTimeout, + SendingCPOWWhileDispatchingSync, + SendingCPOWWhileDispatchingUrgent, + NotConnectedBeforeSend, + DisconnectedDuringSend, + CancelledBeforeSend, + CancelledAfterSend, + TimedOut, + ReplyError, +}; + class MessageChannel : HasResultCodes { friend class ProcessLink; @@ -132,6 +145,13 @@ bool CanSend() const; + // If sending a sync message returns an error, this function gives a more + // descriptive error message. + SyncSendError LastSendError() const { + AssertWorkerThread(); + return mLastSendError; + } + // Currently only for debugging purposes, doesn't aquire mMonitor. ChannelState GetChannelState__TotallyRacy() const { return mChannelState; @@ -250,7 +270,7 @@ bool InterruptEventOccurred(); bool HasPendingEvents(); - void ProcessPendingRequests(int transaction, int prio); + void ProcessPendingRequests(int seqno, int transaction); bool ProcessPendingRequest(const Message &aUrgent); void MaybeUndeferIncall(); @@ -288,7 +308,8 @@ bool ShouldContinueFromTimeout(); - void CancelCurrentTransactionInternal(); + void EndTimeout(); + void CancelTransaction(int transaction); // The "remote view of stack depth" can be different than the // actual stack depth when there are out-of-turn replies. When we @@ -426,7 +447,7 @@ // Tell the IO thread to close the channel and wait for it to ACK. void SynchronouslyClose(); - bool WasTransactionCanceled(int transaction, int prio); + bool WasTransactionCanceled(int transaction); bool ShouldDeferMessage(const Message& aMsg); void OnMessageReceivedFromLink(const Message& aMsg); void OnChannelErrorFromLink(); @@ -521,6 +542,9 @@ static bool sIsPumpingMessages; + // If ::Send returns false, this gives a more descriptive error. + SyncSendError mLastSendError; + template class AutoSetValue { public: @@ -576,6 +600,13 @@ // The current transaction ID. int32_t mCurrentTransaction; + // This field describes the priorities of the sync Send calls that are + // currently on stack. If a Send call for a message with priority P is on + // the C stack, then mPendingSendPriorities & (1 << P) will be + // non-zero. Note that cancelled Send calls are not removed from this + // bitfield (until they return). + int mPendingSendPriorities; + class AutoEnterTransaction { public: diff -Nru firefox-45.0~b2+build1/ipc/glue/MessageLink.h firefox-45.0~b3+build1/ipc/glue/MessageLink.h --- firefox-45.0~b2+build1/ipc/glue/MessageLink.h 2016-02-02 06:58:42.000000000 +0000 +++ firefox-45.0~b3+build1/ipc/glue/MessageLink.h 2016-02-05 06:54:49.000000000 +0000 @@ -76,6 +76,11 @@ return false; } + // WARNING: This function is called with the MessageChannel monitor held. + virtual void IntentionalCrash() { + MOZ_CRASH("Intentional IPDL crash"); + } + virtual void OnEnteredCxxStack() { NS_RUNTIMEABORT("default impl shouldn't be invoked"); } diff -Nru firefox-45.0~b2+build1/js/src/jit/Lowering.cpp firefox-45.0~b3+build1/js/src/jit/Lowering.cpp --- firefox-45.0~b2+build1/js/src/jit/Lowering.cpp 2016-02-02 06:57:36.000000000 +0000 +++ firefox-45.0~b3+build1/js/src/jit/Lowering.cpp 2016-02-05 06:54:51.000000000 +0000 @@ -539,15 +539,15 @@ MOZ_ASSERT(CallTempReg2 != JSReturnReg_Data); LApplyArrayGeneric* lir = new(alloc()) LApplyArrayGeneric( - useFixed(apply->getFunction(), CallTempReg3), - useFixed(apply->getElements(), CallTempReg0), + useFixedAtStart(apply->getFunction(), CallTempReg3), + useFixedAtStart(apply->getElements(), CallTempReg0), tempFixed(CallTempReg1), // object register tempFixed(CallTempReg2)); // stack counter register MDefinition* self = apply->getThis(); useBoxFixed(lir, LApplyArrayGeneric::ThisIndex, self, CallTempReg4, CallTempReg5); - // Bailout is needed in the case of possible non-JSFunction callee + // Bailout is needed in the case of possible non-JSFunction callee, // too many values in the array, or empty space at the end of the // array. I'm going to use NonJSFunctionCallee for the code even // if that is not an adequate description. diff -Nru firefox-45.0~b2+build1/l10n/changesets firefox-45.0~b3+build1/l10n/changesets --- firefox-45.0~b2+build1/l10n/changesets 2016-02-02 07:15:18.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/changesets 2016-02-05 07:10:09.000000000 +0000 @@ -1,90 +1,90 @@ -ach 455:bf64fd2a90b4 -af 841:4f0f35f2e6b3 -an 485:75ad76744057 -ar 1897:478f332808dd -as 650:fb87edc74a69 -ast 1464:1fdcc661816e -az 499:f978f17530df -be 1900:215f952c19a4 -bg 1242:200388693fc2 -bn-BD 1178:de5fe653f8c3 -bn-IN 851:31191b417050 -br 1485:85cbc5332eef -bs 542:95f10fd58ca5 -ca 2621:47b366353ba2 -cs 4327:972b595f9f95 -cy 1293:6a2ac290bbac -da 2368:11e7e890f48d -de 5080:a39a38b9963c -dsb 525:ae139f9a6540 -el 1442:c24c3877d8ad -en-GB 2099:98a1abba25cf -en-ZA 486:e1e2aab1c9f6 -eo 949:f3792a387e5b -es-AR 2748:2e57ea3b0d88 -es-CL 1027:aa9f0128c27d -es-ES 4374:91178cd0e7e3 -es-MX 1068:27a2477cea84 -et 1965:c7a8f8953e7a -eu 1784:26fde0781ed0 -fa 1132:d93f875ae471 -ff 522:da0875f41e99 -fi 2366:33c8c1a4970c -fr 7331:c657b5104cc6 -fy-NL 2761:bdc226d5b93c -ga-IE 1972:0f419cf6ee03 -gd 1841:a59a48a9ef9b -gl 3226:14ec8c7fb3e4 -gn 19:09465402d7e0 -gu-IN 1112:3e026d3c6cb4 -he 1612:b1dac6497220 -hi-IN 948:d6fc14e38963 -hr 1920:22dff8cf67b6 -hsb 669:0a8d4249234d -hu 2652:ab5bb8c41d86 -hy-AM 1410:31633bfd357f -id 1846:543e22f3622a -is 1553:0b5b967b4598 -it 6374:e7ae1caf58d3 -ja 2559:5d91e63fbeac -ja-JP-mac 2120:409ce8f45b6d -kk 980:02a176230bb9 -km 642:373ec5be44f5 -kn 911:b2c3515898a0 -ko 2150:165799e37cbc -lij 753:c928575aa749 -lt 3167:396298982de0 -lv 1198:e6b2ee2b1033 -mai 725:c8d641ac78bc -mk 547:6a82e2e0d09d -ml 875:45be44a9b890 -mr 938:11ea92cf705a -ms 477:2fc7b925ac62 -nb-NO 2884:b530f7c508e0 -nl 5735:520e14cbcac0 -nn-NO 1652:164bd7f4849f -or 718:101fea1cc4e9 -pa-IN 2001:d1324afa64ff -pl 8262:33e9e649c62f -pt-BR 2414:f11927017135 -pt-PT 5111:ff8140f3b97f -rm 1527:181b5cc90142 -ro 2129:90a34780ee77 -ru 4311:6ebcd9f256d6 -si 1393:945b91b0b287 -sk 2241:fc6bafd33448 -sl 2597:e3e7c9582002 -son 718:32a9918bc835 -sq 2119:b4f66148a6f8 -sr 1330:397c3f95399b -sv-SE 4919:d94e76f5af27 -ta 754:ea6a327ff680 -te 802:334b7e5e2469 -th 1074:d3d9ac6bf7d3 -tr 2401:f8c88c92c7cc -uk 3255:4460e096f052 -uz 402:bf71f05cc0b9 -vi 1077:234015516a45 -xh 575:1d53d5a1b917 -zh-CN 2548:b1bf71ff9d14 -zh-TW 2842:089fbd001215 +ach 456:9d7ff4d5ed4f +af 842:5e1164f62f06 +an 487:4c75558f9f90 +ar 1900:b200fe918283 +as 652:a7e7e1797971 +ast 1466:a5e218de88db +az 501:a97bd35bc356 +be 1903:a340049940d9 +bg 1244:944c6311f08a +bn-BD 1180:c7082204c2cf +bn-IN 853:d8604594dbff +br 1488:af8c1d9e392c +bs 543:1520a63017d3 +ca 2624:07251b89dd5c +cs 4330:3d5fcc8ea080 +cy 1296:249bd5b63e07 +da 2371:a85f25832e10 +de 5084:e6fb5ead64b1 +dsb 528:bd508a2ee378 +el 1444:a655ec09af4c +en-GB 2102:5fa08168b1dd +en-ZA 487:91aefc3b031a +eo 951:e3125fb2e6e9 +es-AR 2751:6a0088a4a0be +es-CL 1028:84ed948e5828 +es-ES 4377:a2a466ec28a6 +es-MX 1070:80380ae99332 +et 1968:b868e8b464ba +eu 1787:8f98463c0d7c +fa 1134:abee9cad0860 +ff 524:c1d1fa5ebbe4 +fi 2369:9b3d1da14490 +fr 7334:c7a8c6208be1 +fy-NL 2764:bcb8db357c73 +ga-IE 1975:4cc15853e7e6 +gd 1844:28f4de6ab7d5 +gl 3229:df427f679da4 +gn 20:496c6b8c4b96 +gu-IN 1114:00655f128398 +he 1614:c79aa65efce0 +hi-IN 950:c61ae7430937 +hr 1923:a498f38a2ea2 +hsb 672:2bc667bf334c +hu 2655:ac72ed0305c6 +hy-AM 1413:42c64c37804c +id 1849:09fd8bff9dd0 +is 1556:b9f2574a1c26 +it 6377:6c2e2354ca19 +ja 2562:c3a7ce9130fb +ja-JP-mac 2122:073258110dda +kk 982:ee21c49caf5c +km 643:af5cdaaf66e8 +kn 913:6c0f72096636 +ko 2153:2575fb0759a8 +lij 754:9254b3a72ddd +lt 3170:9245d26196f8 +lv 1200:c515b6439d79 +mai 727:821e4033b867 +mk 548:188e862b64bf +ml 877:9d2983f57d9a +mr 940:41987001f39b +ms 479:66b7be57904b +nb-NO 2887:1bc214de668a +nl 5740:2d10a9d28c59 +nn-NO 1654:732e6d6e6fc1 +or 720:0bf332804e32 +pa-IN 2004:f7d7a6d63c57 +pl 8265:1ea653dc28a3 +pt-BR 2417:266c0c9d51a6 +pt-PT 5114:64079e3f4027 +rm 1529:f2db3792f8f0 +ro 2132:d74d6fd4029e +ru 4314:ae4fd1490b69 +si 1395:77b22714850b +sk 2244:9233ca97ab8e +sl 2600:97acc44db94a +son 720:8950aca50834 +sq 2122:35089bf655c0 +sr 1332:dbeba371ad36 +sv-SE 4922:bc96e9fed4bc +ta 756:943b7a1f9f19 +te 804:8c64e7bb12b2 +th 1076:cc78c5cc3f9d +tr 2404:4c4f1c4a6a22 +uk 3258:6cba06b3cf80 +uz 404:4f4250e8a322 +vi 1079:87406fc85294 +xh 577:ed61a074bbdc +zh-CN 2551:8e86f19c1690 +zh-TW 2845:d7943b392fba diff -Nru firefox-45.0~b2+build1/l10n/de/browser/chrome/browser/preferences/main.dtd firefox-45.0~b3+build1/l10n/de/browser/chrome/browser/preferences/main.dtd --- firefox-45.0~b2+build1/l10n/de/browser/chrome/browser/preferences/main.dtd 2016-02-02 07:01:56.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/de/browser/chrome/browser/preferences/main.dtd 2016-02-05 06:58:42.000000000 +0000 @@ -42,4 +42,4 @@ - + diff -Nru firefox-45.0~b2+build1/l10n/fr/browser/searchplugins/wikipedia-fr.xml firefox-45.0~b3+build1/l10n/fr/browser/searchplugins/wikipedia-fr.xml --- firefox-45.0~b2+build1/l10n/fr/browser/searchplugins/wikipedia-fr.xml 2016-02-02 07:04:34.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/fr/browser/searchplugins/wikipedia-fr.xml 2016-02-05 07:00:51.000000000 +0000 @@ -7,8 +7,6 @@ Wikipédia, l'encyclopédie libre UTF-8 data:image/x-icon;base64,AAABAAIAEBAAAAAAAAA4AQAAJgAAACAgAAAAAAAAJAMAAGQBAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAEFSURBVDjLxZPRDYJAEESJoQjpgBoM/9IBtoAl4KcUQQlSAjYgJWAH0gPmyNtkzEEuxkQTPzawc3Ozc3MQTc/JfVPR/wW6a+eKQ+Hyfe54B2wvrfXVqXLDfTCMd3j0VHksrTcH9bl2aZq+BCgEwCCPj9E4TdPYGj0C9CYAKdkmBrIIxiIYbvpbb2sSl8AiA+ywAbJE5YLpCImLU/WRDyIAWRgu4k1s4v50ODru4haYSCk4ntkuM0wcMAINXiPKTJQ9CfgB40phBr8DyFjGKkKEhYhCY4iCDgpAYAM2EZBlhJnsZxQUYBNkSkfBvjDd0ttPeR0mxREQ+OhfYOJ6EmL+l/qzn2kGli9cAF3BOfkAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAIKSURBVFjD7ZdBSgNRDIYLguAB7FLwAkXwBl0JgiDYjQcY8ARduBJKu3I5C0EoWDxAT9AL9AK9QBeCIHQlCM/3DZOSmeZNZ2r1bQyEGV7yXv7kJZlJq6XIOXfs+crzwPPTnvnR863n05ZFufDD/T595Q4eauM37u/pWYwfeX53cegcABcuHg0AkEQE8AKAu4gAXv8BrAEMh0PXbrddt9t1vV4v406nk62laeqm02n2LjKYIuK5WCyyfeiLDF32yLn6TJ5mBFarlev3+9nBMMqsabkYhmezWcEd2ctTE/tYBwhgt14BhtmAV2VaLpdrAHioCW+VdwWy9IMAUBQjJcQFTwGqvcTD+Xy+oc8askZJyAYrnKEokCeWLpQkSSZvBIANYgSDVVEQQJaeyHQu1QIgiQNb6AmrTtaQ9+RFSLa1D4iXgfsrVITloeSFFZlaAEjAUMaXo2DJWQtVRe1OKF5aJUkf0NdglXO5VzQGoI2USwwD3LEl590CtdO3QBoT5WSFV+Q63Oha17ITgMlkslGSGBWPdeNiDR2SL1B6zQFINmOAkFOW5eTSURCdvX6OdUlapaWjsKX0dgOg26/VWHSUKhrPz35ISKwq76R9Wx+kKgC1f0o5mISsypUG3kPj2L/lDzKYvEUwzoh2JtPRdQQAo1jD6afne88H1oTMeH6ZK+x7PB/lQ/CJtvkNEgDh1dr/bVYAAAAASUVORK5CYII= -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAYAAADovjFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjA3MkMyRDY5QjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjA3MkMyRDZBQjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDcyQzJENjdCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDcyQzJENjhCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7lkNGzAAAELklEQVR42uyYa4hUZRjHn3Nm13X2Mu6urtqutrTeVjRUQikoKUoQLIy8hybiBcVMRdFASPwgQTczsCiMvFYGffBDeANFUDEydc31viheat2dyVndmdmdy57+7/I/+HCcKaX1Q3Re+LHnOe9z3sv/PM/znlnLcRz5vzdb/OaL4Ivgi3C/WV01UCAQkNraWqmpGSCVVVWSl5cnZaXl4jgZaWpugp0viURcwpGIJJMpSba1SY+yUlmy5B3ZuGGDXGlokJKSYkmn0pJOp6UDBbsl2iJFRYVi25bEYjFpwzOtra3S3t4umUxGuqqo53WVCGZR9fX1nZgWDAaxgWIJhUpASGyIFLBtSWKDhcFCScTjuE5JXV2dhMNhSaVS2Kwt0WgUYiU6hTCiRSLNGM2BnYF4yccWCWPB6yAC9oGzYC2Iga/pNx/kg/fBs2AcSICvQOMjT2pZD7xFE0kFBd0lHo89zsiv5d8L3o4nwW+dcotUMDo+p11Jn3YKY/qeY9900P0/lv5hUJ+rswc3Nlnd6wDvgmHgR3V/GfgyS0RZf1NrrEeoR/ZD1rDAPzzrHX8wuEYhcr68E6BV2W9RGJMiI9T9wxzwFfAd+AyUgeFgK/iG9ovgAMcpAIvB92AVNzCJ9hoKu4LjjwabmYrGdwtYyb45nPM98DbYyHW4bSr7Pwb9PPszqTwGnGdUZ22DuekX1L074JSy3wC7eV1C/53clFHXVLEz7Hc3UsG38gz9x7O/F+25oC+vPzI1FVwGN0FP8Dz4gmO4fvPYN5X2LI5ZSvsTT9F/iveEgkZyhc8lTrxd3TPhM1LZ08C3vL7HxRplM6AN/AqOgVGgjhts5sKugyi4qvKzhaKZ4voHGMKCe5oF2qHfIj7TyDGucSM/sH5tY7/p+x1cBGm17vmMgikUsxw8kSv/ZoBqqjiCm7zLsBQ+vMuTl/nKbuTJcdIjpmnduIBuKmfNmfcy570BlrMvzpSap+Z2GG2WZ869nr3Ynn7TngZ7wACKbIRdl+s74QgddlPphVzgh6A/c1g8xbND2b24qD/BLVDk8XWUv8MIKuTCTNinVFjfBh+oY82mv+OZs1SNJ1n6ZzLi1nvWsgksyFUbXuVAO5RQjppENxNynyq7AfzE6xsMyyDtfhxDF1mHkZCtSJ9T9mLWIPeZibzuyejb5hlztVr7ZaaBtzlu5GU7Zi7xW8BU0CaqZt7wfnBI+b0GhvIb4iBD7SWOuYfKr+Px+zN4k3loJj/KojYIFINfmALu6TCW0dGbp0gNj+nZLHI203YCOA6WqtNhEF/OWc45ki/kHOuWzW+cgYyyK//mw8MtLEU8AkMqbIMeP5OjfWj3oU9flUL63C5XZ7zZaJXq66+eGajmdJvrG2LkuHNUco1uLapWdarC8v+z5P+U9kXwRfBF8EXwRfBFyNH+EmAA/FQ613UCCjYAAAAASUVORK5CYII= -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAYAAABGkOCVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjg5QzlEREIwQjUyNjExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjg5QzlEREIxQjUyNjExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6ODlDOUREQUVCNTI2MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6ODlDOUREQUZCNTI2MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz41D9uwAAAJWElEQVR42uxcCWxURRj+t3t029IiVCyXLSpo0ERFLVAvNJ4oBRUVL7Se4IUXeOIVjaKmgkHxthweiKJGY/HAKxqwaiwYBBESwQtpgdCWtns//6nfi7/je7v72kI0mS/5s7vvn5n3Zuab/3pNfZZlkYFBjlkCA0MEA0MEA0MEA0MEA0MEA0MEA0MEA0MEA0MEA0MEg87B919+OL/fT4FAgELBIF0zZQqVl5dTSZ8SWr1mHY2oqKBYtIWSiSSlLB81bN5EkUiU4ok4BYMBSqZ8FItEqCmVoBhf6xvOJx+PY6VSRHi/krJS5PP5OiTB4+SFcymVTFI797N4TFJ6foatjVsoNxyi3sW7U3t7hOKxCB+hHGppbqFgfh7ts+cgamlvofy8fIrHk+Tj4ROxKK1Y+S21trbRgvnz+NkilOSxU+r+hghdw+DBg6msbBDV1X1FY8ZUUmtbS8fG+nw5VFVVRUWFPamppYlCoSAlkooI7dTMmxlnMvTzSAS1oe1trdSjqIiJsJWJEKRevYs7iBCLMhH8OfwZo2Zus7R2CcWYHIq0hw4fQX5+nveX1FJ9/bfGIuxqDBgwgPLy8ngD4x0bq7baSllUstcgGj9hAoWjfJ03yrIkESwQgU9wIkXh3FAHESLRKBUV7UZlpaW0dt2PFGlro8WLX6eGhoaOE93xxpb7qL7qpDfydRuKDIlkgsi81P0PBkI53kOhIUOG0LRptzAhijrV//8YIwxluZMlxtJCf3HZz1LM8hbLQpYDWe5gaWJhu0ghliBLNctqlqksB7NsYwmz9GCZw/IFy0Uso9E3ylLIkg/dbEPTnY5TWTawfJ+p4R4sN7GsAgmUtLHczXKYaDNb6JVMB1kUjmd5R+hU2z2hG8HyIMa09U+hj8HOhdo3FZ2+7qVTL5bN2KiVLm1mQd/OMlDTjYPuXpe+86EfZvZnl+EWcbD7e+l4jzi1Zzjo+7I0Ql+j6epYfoFbcSKZcjsLzN7sMoQ0Kz/FS+dSllZ0/MSlzf3Qq3b74dpxuHaOS5/roD/Q7M8uwyU4nPZ+feN1gGfRMc5S4WIVtqPNQ7imXMkacq9UbmJZJgLUXBcGO323ERTfA3rtSViioIM+IPr7tbFshNOsScDlmdImK2nmEfRwqp36+7PoW4cAvzcCfLVfI9NNUMfTLBfiIa5kWa7p/0AwOB2s246TPgaBiY7TQZ7r8VtZkWcwmQQ+fSDTVWgzE1lICqI2aS0yELUQL7H0YymCy1Exy40s37FczTIeYybFfdS8XmE5gOVhlgKM7cMixbR4Rrox5SavweYmsW5JCIHYPVmWIINSGAT3aY+fg+dox3xS+P0uywuwsDqRVFZ2CO5jZ3Mq87qV5es0JBjOUs5yLjK5z1hOhMX+0gub38ON1U33colGG4X/eSPNWJ/hYWzkY5NrRP8rVOou03g8tK1fxLK/sCiVQnctAtACu7bEMoplI/Q/sBzK0gd61e4gkMkeYxzIfBRMqLr2srBcfbCwddD9zjKR5TSWsSw3i+vSwgwDqe37TMJ91PzPxLqp6+vgXvXUfjDLWaL/QvQtzLB/i7DuNiah/88gbNY4Udx8hkub6aLNyS5t9oX+dgfdKOh+cnEVhBOu2hytXVfj/cpSlmYOj2vuS8dY6Fdo13uKOOlUlyj8SZf5qHx9d+36kejzmyCrbjHtTKw8wzqcksXe9YO1kfGaSvObMcZYNz/mhA+ECbkUfkbHAuEK3HzPZfic46ArEM9Q5KCXfl+eAHUSb8MmbczCv7qRLE/cR6JJFF+GuMQRuS6Wb6bDXDLN8024gDDis5DLWtjWNBOuByFfFde2ilrC+V6IQKLqpxhe5aAfIPpPhrvQF2AyxtnexQg4IU7X04gDVu7k1IsQf6R7HsIhuRzfH4OF84q5+FQu69guPHcAcdRH9O+3HfPxWYm9y5oIb7OsFz5GN2vVqBsov1iCTZc4Dye5O8rIO2B1aumvcvj8btx0PcBVzzwU35elKb6Voah2l2aGO/O66Xe4OoVjujCX0dgLZS3fRwngUwSxDwhLeK4XIuxAdG/7+tOErhIbczFMG+GUFos2KnVZikCoq3gB2UthmvpGZ1GAoEwFhHsjiAyhuLbGpc8RMOM1qJH80cVniCCGIK8VQA1Xw/o+D/em4p96ZFy1SALIiQiZoMz9ZoeCRD0iUBkMKZmGa8dmEdycgjYbRUSv+8Xv0eZhTE59X410NBOeQftZLvoJ0Dchyp6LhVqG9NkJd4vovT9M7HQtQtdxEvpsQiDnBBVzfI52zzvo7XU4M819hqLNJWnaVIhUtMIrGarFRg9DXqs/1MdiU1Xa8yICFuomItjvJz7E7+UZCkBeiLAClmyYS6rsRIRntYh8YheJ0EPM9Z5OEuEJkLogQ5HLTo8fzdY1yKDRLrY8CllF/3yjNVOUqFWGcAJOcXfBfsE1Hq5mJAKz7oAfUXW9h0DPr0XkC8R6FnbiGQpFhrK0k+7tKtQ+WjPEQ2+LtezphQgb4DftQGYU/L/EhyKKn4xCVE2WmUBKVOgkZOUuis9mpD9tKEJNTTN+Uvt003sJ7uLap44bHNxKMsM8CUWjIAI7pwDVcshW9JRR4bks5rAQNYtSFNA8YTgmYptlp9L0JOFCbs5izLPRdrtD6mlHt5vQZoKmu0Dc64I01TULgaYTqqBf72Ed5qBPrYPucJYGnDSJcaJKW+pQPZwI/VqntA6HdQPaOKXx+4EgjR7mUY/xvszgShzxCTpXuujzUUqO07//VkGiP8z6L2Izl+OE24tzKU6GJchyB/3zZc0XQl8rgh/lkxcLnYrI54miVxnihs2izTLc3+1vOEeCWAm0Vyf7LQSYNUjPLByWElF/mYENlvO8DylwNSzpr3AtJQ4EqBLxl4XsZBbWdyCqp1uEfgkOYaGL+1AW6zURMFqoWt4X8EAE9VJH1ezfcdG3IS3JFTmxW8CyDRNqwuIP1MxtApOai8XtiwmHRLtb8TxRBJs+4b9XIZJvBUF3E1YsgFStGic4DIsUyfDM67GQTfjdQyxmLsj0IwhmP4edgm/D8/Whv1+0qXavYKM3uNzT/nOARZh3Ma4HMZ6axyNYmyDIF3ex2DlYq3qszQ6sZzE5vyw0MDAwMDAwMDAwQKpm/uGmgZ1SGBgYIhgYIhgYIhgYIhgYIhgYIhgYIhgYIhgYIhh4w58CDAAL8AVXFSeKUgAAAABJRU5ErkJggg== diff -Nru firefox-45.0~b2+build1/l10n/it/browser/searchplugins/wikipedia-it.xml firefox-45.0~b3+build1/l10n/it/browser/searchplugins/wikipedia-it.xml --- firefox-45.0~b2+build1/l10n/it/browser/searchplugins/wikipedia-it.xml 2016-02-02 07:07:12.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/it/browser/searchplugins/wikipedia-it.xml 2016-02-05 07:03:05.000000000 +0000 @@ -7,8 +7,6 @@ Wikipedia, l'enciclopedia libera UTF-8 data:image/x-icon;base64,AAABAAIAEBAAAAAAAAA4AQAAJgAAACAgAAAAAAAAJAMAAGQBAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAEFSURBVDjLxZPRDYJAEESJoQjpgBoM/9IBtoAl4KcUQQlSAjYgJWAH0gPmyNtkzEEuxkQTPzawc3Ozc3MQTc/JfVPR/wW6a+eKQ+Hyfe54B2wvrfXVqXLDfTCMd3j0VHksrTcH9bl2aZq+BCgEwCCPj9E4TdPYGj0C9CYAKdkmBrIIxiIYbvpbb2sSl8AiA+ywAbJE5YLpCImLU/WRDyIAWRgu4k1s4v50ODru4haYSCk4ntkuM0wcMAINXiPKTJQ9CfgB40phBr8DyFjGKkKEhYhCY4iCDgpAYAM2EZBlhJnsZxQUYBNkSkfBvjDd0ttPeR0mxREQ+OhfYOJ6EmL+l/qzn2kGli9cAF3BOfkAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAIKSURBVFjD7ZdBSgNRDIYLguAB7FLwAkXwBl0JgiDYjQcY8ARduBJKu3I5C0EoWDxAT9AL9AK9QBeCIHQlCM/3DZOSmeZNZ2r1bQyEGV7yXv7kJZlJq6XIOXfs+crzwPPTnvnR863n05ZFufDD/T595Q4eauM37u/pWYwfeX53cegcABcuHg0AkEQE8AKAu4gAXv8BrAEMh0PXbrddt9t1vV4v406nk62laeqm02n2LjKYIuK5WCyyfeiLDF32yLn6TJ5mBFarlev3+9nBMMqsabkYhmezWcEd2ctTE/tYBwhgt14BhtmAV2VaLpdrAHioCW+VdwWy9IMAUBQjJcQFTwGqvcTD+Xy+oc8askZJyAYrnKEokCeWLpQkSSZvBIANYgSDVVEQQJaeyHQu1QIgiQNb6AmrTtaQ9+RFSLa1D4iXgfsrVITloeSFFZlaAEjAUMaXo2DJWQtVRe1OKF5aJUkf0NdglXO5VzQGoI2USwwD3LEl590CtdO3QBoT5WSFV+Q63Oha17ITgMlkslGSGBWPdeNiDR2SL1B6zQFINmOAkFOW5eTSURCdvX6OdUlapaWjsKX0dgOg26/VWHSUKhrPz35ISKwq76R9Wx+kKgC1f0o5mISsypUG3kPj2L/lDzKYvEUwzoh2JtPRdQQAo1jD6afne88H1oTMeH6ZK+x7PB/lQ/CJtvkNEgDh1dr/bVYAAAAASUVORK5CYII= -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAYAAADovjFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjA3MkMyRDY5QjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjA3MkMyRDZBQjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDcyQzJENjdCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDcyQzJENjhCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7lkNGzAAAELklEQVR42uyYa4hUZRjHn3Nm13X2Mu6urtqutrTeVjRUQikoKUoQLIy8hybiBcVMRdFASPwgQTczsCiMvFYGffBDeANFUDEydc31viheat2dyVndmdmdy57+7/I/+HCcKaX1Q3Re+LHnOe9z3sv/PM/znlnLcRz5vzdb/OaL4Ivgi3C/WV01UCAQkNraWqmpGSCVVVWSl5cnZaXl4jgZaWpugp0viURcwpGIJJMpSba1SY+yUlmy5B3ZuGGDXGlokJKSYkmn0pJOp6UDBbsl2iJFRYVi25bEYjFpwzOtra3S3t4umUxGuqqo53WVCGZR9fX1nZgWDAaxgWIJhUpASGyIFLBtSWKDhcFCScTjuE5JXV2dhMNhSaVS2Kwt0WgUYiU6hTCiRSLNGM2BnYF4yccWCWPB6yAC9oGzYC2Iga/pNx/kg/fBs2AcSICvQOMjT2pZD7xFE0kFBd0lHo89zsiv5d8L3o4nwW+dcotUMDo+p11Jn3YKY/qeY9900P0/lv5hUJ+rswc3Nlnd6wDvgmHgR3V/GfgyS0RZf1NrrEeoR/ZD1rDAPzzrHX8wuEYhcr68E6BV2W9RGJMiI9T9wxzwFfAd+AyUgeFgK/iG9ovgAMcpAIvB92AVNzCJ9hoKu4LjjwabmYrGdwtYyb45nPM98DbYyHW4bSr7Pwb9PPszqTwGnGdUZ22DuekX1L074JSy3wC7eV1C/53clFHXVLEz7Hc3UsG38gz9x7O/F+25oC+vPzI1FVwGN0FP8Dz4gmO4fvPYN5X2LI5ZSvsTT9F/iveEgkZyhc8lTrxd3TPhM1LZ08C3vL7HxRplM6AN/AqOgVGgjhts5sKugyi4qvKzhaKZ4voHGMKCe5oF2qHfIj7TyDGucSM/sH5tY7/p+x1cBGm17vmMgikUsxw8kSv/ZoBqqjiCm7zLsBQ+vMuTl/nKbuTJcdIjpmnduIBuKmfNmfcy570BlrMvzpSap+Z2GG2WZ869nr3Ynn7TngZ7wACKbIRdl+s74QgddlPphVzgh6A/c1g8xbND2b24qD/BLVDk8XWUv8MIKuTCTNinVFjfBh+oY82mv+OZs1SNJ1n6ZzLi1nvWsgksyFUbXuVAO5RQjppENxNynyq7AfzE6xsMyyDtfhxDF1mHkZCtSJ9T9mLWIPeZibzuyejb5hlztVr7ZaaBtzlu5GU7Zi7xW8BU0CaqZt7wfnBI+b0GhvIb4iBD7SWOuYfKr+Px+zN4k3loJj/KojYIFINfmALu6TCW0dGbp0gNj+nZLHI203YCOA6WqtNhEF/OWc45ki/kHOuWzW+cgYyyK//mw8MtLEU8AkMqbIMeP5OjfWj3oU9flUL63C5XZ7zZaJXq66+eGajmdJvrG2LkuHNUco1uLapWdarC8v+z5P+U9kXwRfBF8EXwRfBFyNH+EmAA/FQ613UCCjYAAAAASUVORK5CYII= -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAYAAABGkOCVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjg5QzlEREIwQjUyNjExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjg5QzlEREIxQjUyNjExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6ODlDOUREQUVCNTI2MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6ODlDOUREQUZCNTI2MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz41D9uwAAAJWElEQVR42uxcCWxU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 diff -Nru firefox-45.0~b2+build1/l10n/sq/chat/conversations.properties firefox-45.0~b3+build1/l10n/sq/chat/conversations.properties --- firefox-45.0~b2+build1/l10n/sq/chat/conversations.properties 2016-02-02 07:12:43.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/sq/chat/conversations.properties 2016-02-05 07:07:48.000000000 +0000 @@ -57,6 +57,17 @@ # %1$S is the user who cleared the topic. topicCleared=%1$S e hoqi temën. +# LOCALIZATION NOTE (nickSet): +# This is displayed as a system message when a participant changes his/her +# nickname in a conversation. +# %1$S is the old nick. +# %2$S is the new nick. +nickSet=%1$S tani njihet si %2$S. +# LOCALIZATION NOTE (nickSet.you): +# This is displayed as a system message when your nickname is changed. +# %S is your new nick. +nickSet.you=Tani njiheni si %S. + # LOCALIZATION NOTE (messenger.conversations.selections.ellipsis): # ellipsis is used when copying a part of a message to show that the message was cut messenger.conversations.selections.ellipsis=[…] diff -Nru firefox-45.0~b2+build1/l10n/sq/chat/irc.properties firefox-45.0~b3+build1/l10n/sq/chat/irc.properties --- firefox-45.0~b2+build1/l10n/sq/chat/irc.properties 2016-02-02 07:12:43.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/sq/chat/irc.properties 2016-02-05 07:07:48.000000000 +0000 @@ -96,10 +96,6 @@ message.channelmode=Mënyrë kanali %1$S vënë nga %2$S. # %1$S is the old nick and %2$S is the new nick. message.yourmode=Gjendeni nën mënyrën %S. -# %1$S is the old nick and %2$S is the new nick. -message.nick=%1$S tani njihet si %2$S. -# %S is your new nick. -message.nick.you=Tani njiheni si %S. # Could not change the nickname. %S is the user's nick. message.nick.fail=Nuk përdori dot nofkën e treguar. Nofka juaj mbetet ende %S. # The parameter is the message.parted.reason, if a part message is given. diff -Nru firefox-45.0~b2+build1/l10n/sq/chat/skype.properties firefox-45.0~b3+build1/l10n/sq/chat/skype.properties --- firefox-45.0~b2+build1/l10n/sq/chat/skype.properties 1970-01-01 00:00:00.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/sq/chat/skype.properties 2016-02-05 07:07:48.000000000 +0000 @@ -0,0 +1,14 @@ +# 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/. + +# LOCALIZATION NOTE (connection.*): +# These will show in the account manager to show progress during a connection. +connecting.authenticating=Po mirëfilltësohet +connecting.registrationToken=Po merret token regjistrimi + +# LOCALIZATION NOTE (error.*): +# These will show in the account manager if the account is disconnected +# because of an error. +error.auth=Dështoi mirëfilltësimi te shërbyesi +error.registrationToken=Dështoi marrja e tokenit të regjistrimit diff -Nru firefox-45.0~b2+build1/l10n/sq/chat/xmpp.properties firefox-45.0~b3+build1/l10n/sq/chat/xmpp.properties --- firefox-45.0~b2+build1/l10n/sq/chat/xmpp.properties 2016-02-02 07:12:43.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/sq/chat/xmpp.properties 2016-02-05 07:07:48.000000000 +0000 @@ -38,13 +38,47 @@ # This is displayed in a conversation as an error message when a message # the user has sent wasn't delivered. # %S is replaced by the text of the message that wasn't delivered. -conversation.error.notDelivered=Ky mesazh nuk u dërgua dot: %S +conversation.error.notDelivered=Ky mesazh s’u dërgua dot: %S # This is displayed in a conversation as an error message when joining a MUC # fails. # %S is the name of the MUC. -conversation.error.joinFailed=Nuk hyhet dot te: %S +conversation.error.joinFailed=S’hyhet dot te: %S +# This is displayed in a conversation as an error message when the user is +# banned from a room. +# %S is the name of the MUC room. +conversation.error.joinForbidden=S’u hy dot te %S, ngaqë jeni përzënë prej kësaj dhome. +conversation.error.joinFailedNotAuthorized=Lypset regjistrim: S’jeni i autorizuar të hyni në këtë dhomë. +conversation.error.creationFailedNotAllowed=Hyrje e kufizuar: S’ju lejohet të krijoni dhoma. +# This is displayed in a conversation as an error message when remote server +# is not found. +# %S is the name of MUC room. +conversation.error.joinFailedRemoteServerNotFound=S’u hy dot te dhoma %S, ngaqë s’kapet dot shërbyesi ku strehohet dhoma. +conversation.error.changeTopicFailedNotAuthorized=S’jeni i autorizuar të caktoni temën e kësaj dhome. +# This is displayed in a conversation as an error message when the user sends +# a message to a room that he is not in. +# %1$S is the name of MUC room. +# %2$S is the text of the message that wasn't delivered. +conversation.error.sendFailedAsNotInRoom=Mesazhi s’u dërgua dot te %1$S, ngaqë s’gjendeni më në dhomë: %2$S +# This is displayed in a conversation as an error message when the user sends +# a message to a room that the recipient is not in. +# %1$S is the jid of the recipient. +# %2$S is the text of the message that wasn't delivered. +conversation.error.sendFailedAsRecipientNotInRoom=Mesazhi s’u dërgua dot te %1$S, ngaqë marrësi s’gjendet më në dhomë: %2$S # These are displayed in a conversation as a system error message. -conversation.error.remoteServerNotFound=Nuk kapi dot shërbyesin e marrësit +conversation.error.remoteServerNotFound=S’kapi dot shërbyesin e marrësit +# %S is the nick of participant that is not in room. +conversation.error.nickNotInRoom=%S s’gjendet në dhomë. +conversation.error.banCommandAnonymousRoom=S"mund të përzini pjesëmarrës në dhoma anonime. Në vend të kësaj, provoni /kick. +conversation.error.banKickCommandNotAllowed=S’keni privilegjet e domosdoshme të hiqni këtë pjesëmarrës nga dhoma. +conversation.error.banKickCommandConflict=Na ndjeni, s’mund të hiqni veten nga dhoma. +conversation.error.changeNickFailedConflict=S’u ndryshua dot nofka juaj në %S, ngaqë kjo nofkë është tashmë në përdorim. +conversation.error.changeNickFailedNotAcceptable=S’u ndryshua dot nofka juaj në %S, ngaqë nofkat në këtë dhomë janë të kyçura. +conversation.error.inviteFailedForbidden=S’keni privilegjet e domosdoshme të ftoni përdorues në këtë dhomë. +# %S is the jid of user that is invited. +conversation.error.failedJIDNotFound=S’u kap dot %S. +# %S is the jid that is invalid. +conversation.error.invalidJID=%S është jid i pavlefshëm (Identifikuesit Jabber duhet të jenë të formës përdorues@përkatësi). +conversation.error.commandFailedNotInRoom=Duhet të rihyni në dhomë që të jeni në gjendje të përdorni këtë urdhër. conversation.error.unknownError=Gabim i panjohur # LOCALIZATION NOTE (tooltip.*): @@ -55,6 +89,15 @@ tooltip.status=Gjendje (%S) tooltip.statusNoResource=Gjendje tooltip.subscription=Pajtim +tooltip.fullName=Emër i Plotë +tooltip.nickname=Nofkë +tooltip.email=Email +tooltip.birthday=Ditëlindje +tooltip.userName=Emër përdoruesi +tooltip.title=Titull +tooltip.organization=Organizëm +tooltip.locality=Lokalitet +tooltip.country=Vend # LOCALIZATION NOTE (chatRoomField.*): # These are the name of fields displayed in the 'Join Chat' dialog @@ -67,6 +110,89 @@ chatRoomField.nick=_Nofkë chatRoomField.password=_Fjalëkalim +# LOCALIZATION NOTE (conversation.muc.join): +# This is displayed as a system message when a participant joins room. +# %S is the nick of the participant. +conversation.message.join=%S hyri në dhomë. + +# LOCALIZATION NOTE (conversation.muc.rejoined): +# This is displayed as a system message when a participant rejoins room after +# parting it. +conversation.message.rejoined=Rihytë në dhomë. + +# LOCALIZATION NOTE (conversation.message.parted.*): +# These are displayed as a system message when a participant parts a room. +# %S is the part message supplied by the user. +conversation.message.parted.you=Dolët nga dhoma. +conversation.message.parted.you.reason=Dolët nga dhoma: %S +# %1$S is the participant that is leaving. +# %2$S is the part message supplied by the participant. +conversation.message.parted=%1$S doli nga dhoma. +conversation.message.parted.reason=%1$S doli nga dhoma: %2$S + +# LOCALIZATION NOTE (conversation.message.invitationDeclined*): +# %1$S is the invitee that declined the invitation. +# %2$S is the decline message supplied by the invitee. +conversation.message.invitationDeclined=%1$S e hodhi tej ftesën tuaj. +conversation.message.invitationDeclined.reason=%1$S e hodhi tej ftesën tuaj: %2$S + +# LOCALIZATION NOTE (conversation.message.banned.*): +# These are displayed as a system message when a participant is banned from +# a room. +# %1$S is the participant that is banned. +# %2$S is the reason. +# %3$S is the person who is banning. +conversation.message.banned=%1$S është dëbuar prej dhome. +conversation.message.banned.reason=%1$S është dëbuar prej dhome: %2$S +# %1$S is the person who is banning. +# %2$S is the participant that is banned. +# %3$S is the reason. +conversation.message.banned.actor=%1$S ka dëbuar %2$S prej dhome. +conversation.message.banned.actor.reason=%1$S ka dëbuar %2$S prej dhome: %3$S +conversation.message.banned.you=Jeni dëbuar prej dhome. +# %1$S is the reason. +conversation.message.banned.you.reason=Jeni dëbuar prej dhome: %1$S +# %1$S is the person who is banning. +# %2$S is the reason. +conversation.message.banned.you.actor=%1$S ju ka dëbuar prej dhome. +conversation.message.banned.you.actor.reason=%1$S ju ka dëbuar prej dhome: %2$S + +# LOCALIZATION NOTE (conversation.message.kicked.*): +# These are displayed as a system message when a participant is kicked from +# a room. +# %1$S is the participant that is kicked. +# %2$S is the reason. +conversation.message.kicked=%1$S është përzënë prej dhome. +conversation.message.kicked.reason=%1$S është përzënë prej dhome: %2$S +# %1$S is the person who is kicking. +# %2$S is the participant that is kicked. +# %3$S is the reason. +conversation.message.kicked.actor=%1$S ka përzënë %2$S prej dhome. +conversation.message.kicked.actor.reason=%1$S ka përzënë %2$S prej dhome: %3$S +conversation.message.kicked.you=Jeni përzënë prej dhome. +# %1$S is the reason. +conversation.message.kicked.you.reason=Jeni përzënë prej dhome: %1$S +# %1$S is the person who is kicking. +# %2$S is the reason. +conversation.message.kicked.you.actor=%1$S ju ka përzënë nga dhoma. +conversation.message.kicked.you.actor.reason=%1$S ju ka përzënë nga dhoma: %2$S + +# LOCALIZATION NOTE (conversation.message.removedNonMember.*): +# These are displayed as a system message when a participant is removed from +# a room because the room has been changed to members-only. +# %1$S is the participant that is removed. +# %2$S is the person who changed the room configuration. +conversation.message.removedNonMember=%1$S është hequr nga dhoma, ngaqë formësimi i saj është ndryshuar në vetëm për anëtarë. +conversation.message.removedNonMember.actor=%1$S është hequr nga dhoma, ngaqë %2$S është ndryshuar në vetëm për anëtarë. +conversation.message.removedNonMember.you=Jeni hequr nga dhoma, ngaqë formësimi i saj është ndryshuar në vetëm për anëtarë. +# %1$S is the person who changed the room configuration. +conversation.message.removedNonMember.you.actor=Jeni hequr nga dhoma, ngaqë %1$S është ndryshuar në vetëm për anëtarë. + +# LOCALIZATION NOTE (conversation.message.MUCShutdown): +# These are displayed as a system message when a participant is removed from +# a room because of a system shutdown. +conversation.message.mucShutdown=Jeni hequr nga dhoma për shkak të një fikjeje të sistemit. + # LOCALIZATION NOTE (options.*): # These are the protocol specific options shown in the account manager and # account wizard windows. @@ -78,6 +204,7 @@ options.connectionSecurity.allowUnencryptedAuth=Lejo dërgim fjalëkalimesh pa fshehtëzim options.connectServer=Shërbyes options.connectPort=Portë +options.domain=Përkatësi # LOCALIZATION NOTE (*.protocolName) # This name is used whenever the name of the protocol is shown. @@ -101,3 +228,25 @@ # string defined in imAccounts.properties when the user is # configuring a Odnoklassniki account. odnoklassniki.usernameHint=ID Profili + +# LOCALZIATION NOTE (command.*): +# These are the help messages for each command. +command.join3=%S [<room>[@<server>][/<nick>]] [<password>]: Hyni në një dhomë, edhe duke dhënë një tjetër shërbyes, ose nofkë, ose fjalëkalim dhome. +command.part2=%S [<message>]: Dilni nga dhoma e tanishme, me një mesazh po deshët. +command.topic=%S [<new topic>]: Caktoni temën e kësaj dhome. +command.ban=%S <nick>[<message>]: Përzini dikë nga dhoma. Duhet të jeni përgjegjës dhome që të bëni këtë. +command.kick=%S <nick>[<message>]: Hiqni dikë nga dhoma. Duhet të jeni moderator dhome që të bëni këtë. +command.invite=%S <jid>[<message>]: Ftoni një përdorues të vijë te dhoma e tanishme, me një mesazh po deshët. +command.me=%S <action to perform>: Kryeni një veprim. +command.nick=%S <new nickname>: Ndryshoni nofkën tuaj. +command.msg=%S <nick> <message>: Dërgojini një pjesëmarrësi në dhomë një mesazh privat. + +# LOCALIZATION NOTE (conversation.muc.*): +# These are displayed as a system message when a chatroom invitation is +# received. +# %1$S is the inviter. +# %2$S is the room. +# %3$S is the reason which is a message provided by the person sending the +# invitation. +conversation.muc.invitationWithReason=%1$S ju ka ftuar të hyni te %2$S: %3$S +conversation.muc.invitationWithoutReason=%1$S ju ka ftuar të hyni te %2$S diff -Nru firefox-45.0~b2+build1/l10n/sq/dom/chrome/dom/dom.properties firefox-45.0~b3+build1/l10n/sq/dom/chrome/dom/dom.properties --- firefox-45.0~b2+build1/l10n/sq/dom/chrome/dom/dom.properties 2016-02-02 07:12:43.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/sq/dom/chrome/dom/dom.properties 2016-02-05 07:07:48.000000000 +0000 @@ -168,7 +168,7 @@ # LOCALIZATION NOTE: Do not translate "window.controllers" Window_ControllersWarning=window.controllers është vjetruar. Mos e përdorni për zbulim UA-sh. -ImportXULIntoContentWarning=Importimi i nyjeve XUL në një dokument lëndor është vjetruar. Së shpejti ky funksion mund të hiqet. +ImportXULIntoContentWarning=Importimi i nyjave XUL në një dokument lëndor është vjetruar. Së shpejti ky funksion mund të hiqet. XMLDocumentLoadPrincipalMismatch=Përdorimi i document.load është i ndaluar për Dokumente që vijnë nga të tjera Dritare. Vetëm Dritares në të cilën qe krijuar Dokumenti i lejohet të thërrasë .load në atë Dokument. Parapëlqehet përdorimi i XMLHttpRequest më mirë. # LOCALIZATION NOTE: Do not translate "IndexedDB". IndexedDBTransactionAbortNavigation=Një transaksion IndexedDB që nuk qe plotësuar ende, u ndërpre për shkak të lëvizjes në faqe. @@ -187,7 +187,7 @@ ExecCommandCutCopyDeniedNotInputDriven=document.execCommand('prije'/'kopjoje') s’u lejua, ngaqë s’qe thirrur nga brenda një trajtuesi akti me xhirim të shkurtër të prodhuar nga përdoruesi. # LOCALIZATION NOTE: Do not translate "ServiceWorker", "Error", "Response", "FetchEvent.respondWith()", or "fetch()". %S is a URL. InterceptedErrorResponseWithURL=Dështoi në ngarkimin e '%S'. Një ServiceWorker dha për FetchEvent.respondWith() Përgjigje Gabim. Zakonisht kjo do të thotë që ServiceWorker kreu një thirrje fetch() të pavlefshme. -# InterceptedNonResponseWithURL=Dështoi në ngarkimin e '%1$S'. Një ServiceWorker premtoi FetchEvent.respondWith() që resolved with non-Response value '%2$S'. +InterceptedNonResponseWithURL=Dështoi në ngarkimin e '%1$S'. Një ServiceWorker premtoi FetchEvent.respondWith() që u përgjigj me një vlerë non-Response '%2$S'. # LOCALIZATION NOTE: Do not translate "ServiceWorker", "Response", "FetchEvent.respondWith()", or "Response.clone()". %S is a URL. InterceptedUsedResponseWithURL=Dështoi ngarkimi i '%S'. Një ServiceWorker dha për FetchEvent.respondWith() një Përgjigje të përdorur. Lënda e një Përgjigjeje mund të lexohet vetëm një herë. Për shfrytëzim të lëndës shumë herë përdorni Response.clone(). # LOCALIZATION NOTE: Do not translate "ServiceWorker" or "FetchEvent.preventDefault()". %S is a URL. diff -Nru firefox-45.0~b2+build1/l10n/uk/browser/chrome/browser/browser.dtd firefox-45.0~b3+build1/l10n/uk/browser/chrome/browser/browser.dtd --- firefox-45.0~b2+build1/l10n/uk/browser/chrome/browser/browser.dtd 2016-02-02 07:13:54.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/uk/browser/chrome/browser/browser.dtd 2016-02-05 07:08:56.000000000 +0000 @@ -167,7 +167,7 @@ - + diff -Nru firefox-45.0~b2+build1/l10n/zh-TW/browser/searchplugins/wikipedia-zh-TW.xml firefox-45.0~b3+build1/l10n/zh-TW/browser/searchplugins/wikipedia-zh-TW.xml --- firefox-45.0~b2+build1/l10n/zh-TW/browser/searchplugins/wikipedia-zh-TW.xml 2016-02-02 07:14:45.000000000 +0000 +++ firefox-45.0~b3+build1/l10n/zh-TW/browser/searchplugins/wikipedia-zh-TW.xml 2016-02-05 07:09:43.000000000 +0000 @@ -7,8 +7,6 @@ 維基百科,自由的百科全書 UTF-8 data:image/x-icon;base64,AAABAAIAEBAAAAAAAAA4AQAAJgAAACAgAAAAAAAAJAMAAGQBAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAEFSURBVDjLxZPRDYJAEESJoQjpgBoM/9IBtoAl4KcUQQlSAjYgJWAH0gPmyNtkzEEuxkQTPzawc3Ozc3MQTc/JfVPR/wW6a+eKQ+Hyfe54B2wvrfXVqXLDfTCMd3j0VHksrTcH9bl2aZq+BCgEwCCPj9E4TdPYGj0C9CYAKdkmBrIIxiIYbvpbb2sSl8AiA+ywAbJE5YLpCImLU/WRDyIAWRgu4k1s4v50ODru4haYSCk4ntkuM0wcMAINXiPKTJQ9CfgB40phBr8DyFjGKkKEhYhCY4iCDgpAYAM2EZBlhJnsZxQUYBNkSkfBvjDd0ttPeR0mxREQ+OhfYOJ6EmL+l/qzn2kGli9cAF3BOfkAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAIKSURBVFjD7ZdBSgNRDIYLguAB7FLwAkXwBl0JgiDYjQcY8ARduBJKu3I5C0EoWDxAT9AL9AK9QBeCIHQlCM/3DZOSmeZNZ2r1bQyEGV7yXv7kJZlJq6XIOXfs+crzwPPTnvnR863n05ZFufDD/T595Q4eauM37u/pWYwfeX53cegcABcuHg0AkEQE8AKAu4gAXv8BrAEMh0PXbrddt9t1vV4v406nk62laeqm02n2LjKYIuK5WCyyfeiLDF32yLn6TJ5mBFarlev3+9nBMMqsabkYhmezWcEd2ctTE/tYBwhgt14BhtmAV2VaLpdrAHioCW+VdwWy9IMAUBQjJcQFTwGqvcTD+Xy+oc8askZJyAYrnKEokCeWLpQkSSZvBIANYgSDVVEQQJaeyHQu1QIgiQNb6AmrTtaQ9+RFSLa1D4iXgfsrVITloeSFFZlaAEjAUMaXo2DJWQtVRe1OKF5aJUkf0NdglXO5VzQGoI2USwwD3LEl590CtdO3QBoT5WSFV+Q63Oha17ITgMlkslGSGBWPdeNiDR2SL1B6zQFINmOAkFOW5eTSURCdvX6OdUlapaWjsKX0dgOg26/VWHSUKhrPz35ISKwq76R9Wx+kKgC1f0o5mISsypUG3kPj2L/lDzKYvEUwzoh2JtPRdQQAo1jD6afne88H1oTMeH6ZK+x7PB/lQ/CJtvkNEgDh1dr/bVYAAAAASUVORK5CYII= -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAYAAADovjFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjA3MkMyRDY5QjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjA3MkMyRDZBQjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDcyQzJENjdCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDcyQzJENjhCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7lkNGzAAAELklEQVR42uyYa4hUZRjHn3Nm13X2Mu6urtqutrTeVjRUQikoKUoQLIy8hybiBcVMRdFASPwgQTczsCiMvFYGffBDeANFUDEydc31viheat2dyVndmdmdy57+7/I/+HCcKaX1Q3Re+LHnOe9z3sv/PM/znlnLcRz5vzdb/OaL4Ivgi3C/WV01UCAQkNraWqmpGSCVVVWSl5cnZaXl4jgZaWpugp0viURcwpGIJJMpSba1SY+yUlmy5B3ZuGGDXGlokJKSYkmn0pJOp6UDBbsl2iJFRYVi25bEYjFpwzOtra3S3t4umUxGuqqo53WVCGZR9fX1nZgWDAaxgWIJhUpASGyIFLBtSWKDhcFCScTjuE5JXV2dhMNhSaVS2Kwt0WgUYiU6hTCiRSLNGM2BnYF4yccWCWPB6yAC9oGzYC2Iga/pNx/kg/fBs2AcSICvQOMjT2pZD7xFE0kFBd0lHo89zsiv5d8L3o4nwW+dcotUMDo+p11Jn3YKY/qeY9900P0/lv5hUJ+rswc3Nlnd6wDvgmHgR3V/GfgyS0RZf1NrrEeoR/ZD1rDAPzzrHX8wuEYhcr68E6BV2W9RGJMiI9T9wxzwFfAd+AyUgeFgK/iG9ovgAMcpAIvB92AVNzCJ9hoKu4LjjwabmYrGdwtYyb45nPM98DbYyHW4bSr7Pwb9PPszqTwGnGdUZ22DuekX1L074JSy3wC7eV1C/53clFHXVLEz7Hc3UsG38gz9x7O/F+25oC+vPzI1FVwGN0FP8Dz4gmO4fvPYN5X2LI5ZSvsTT9F/iveEgkZyhc8lTrxd3TPhM1LZ08C3vL7HxRplM6AN/AqOgVGgjhts5sKugyi4qvKzhaKZ4voHGMKCe5oF2qHfIj7TyDGucSM/sH5tY7/p+x1cBGm17vmMgikUsxw8kSv/ZoBqqjiCm7zLsBQ+vMuTl/nKbuTJcdIjpmnduIBuKmfNmfcy570BlrMvzpSap+Z2GG2WZ869nr3Ynn7TngZ7wACKbIRdl+s74QgddlPphVzgh6A/c1g8xbND2b24qD/BLVDk8XWUv8MIKuTCTNinVFjfBh+oY82mv+OZs1SNJ1n6ZzLi1nvWsgksyFUbXuVAO5RQjppENxNynyq7AfzE6xsMyyDtfhxDF1mHkZCtSJ9T9mLWIPeZibzuyejb5hlztVr7ZaaBtzlu5GU7Zi7xW8BU0CaqZt7wfnBI+b0GhvIb4iBD7SWOuYfKr+Px+zN4k3loJj/KojYIFINfmALu6TCW0dGbp0gNj+nZLHI203YCOA6WqtNhEF/OWc45ki/kHOuWzW+cgYyyK//mw8MtLEU8AkMqbIMeP5OjfWj3oU9flUL63C5XZ7zZaJXq66+eGajmdJvrG2LkuHNUco1uLapWdarC8v+z5P+U9kXwRfBF8EXwRfBFyNH+EmAA/FQ613UCCjYAAAAASUVORK5CYII= -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAYAAABGkOCVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjg5QzlEREIwQjUyNjExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjg5QzlEREIxQjUyNjExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6ODlDOUREQUVCNTI2MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6ODlDOUREQUZCNTI2MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz41D9uwAAAJWElEQVR42uxcCWxU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 diff -Nru firefox-45.0~b2+build1/layout/base/nsDisplayList.cpp firefox-45.0~b3+build1/layout/base/nsDisplayList.cpp --- firefox-45.0~b2+build1/layout/base/nsDisplayList.cpp 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/layout/base/nsDisplayList.cpp 2016-02-05 06:54:54.000000000 +0000 @@ -2198,30 +2198,11 @@ MOZ_COUNT_CTOR(nsDisplayBackgroundImage); mBounds = GetBoundsInternal(aBuilder); - mDestArea = GetDestAreaInternal(aBuilder); if (ShouldFixToViewport(aBuilder)) { mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(this); } } -nsRect -nsDisplayBackgroundImage::GetDestAreaInternal(nsDisplayListBuilder* aBuilder) -{ - if (!mBackgroundStyle) { - return nsRect(); - } - - nsPresContext* presContext = mFrame->PresContext(); - uint32_t flags = aBuilder->GetBackgroundPaintFlags(); - nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize()); - const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer]; - - nsBackgroundLayerState state = - nsCSSRendering::PrepareBackgroundLayer(presContext, mFrame, flags, - borderArea, borderArea, layer); - return state.mDestArea; -} - nsDisplayBackgroundImage::~nsDisplayBackgroundImage() { #ifdef NS_BUILD_REFCNT_LOGGING @@ -2522,7 +2503,7 @@ // layer pixel boundaries. This should be OK for now. int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); - mImageLayerDestRect = + mDestRect = LayoutDeviceRect::FromAppUnits(state.mDestArea, appUnitsPerDevPixel); // Ok, we can turn this into a layer if needed. @@ -2615,7 +2596,7 @@ mImage->GetHeight(&imageHeight); NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!"); - const LayerRect destLayerRect = mImageLayerDestRect * aParameters.Scale(); + const LayerRect destLayerRect = mDestRect * aParameters.Scale(); // Calculate the scaling factor for the frame. const gfxSize scale = gfxSize(destLayerRect.width / imageWidth, @@ -2677,10 +2658,10 @@ // aParameters.Offset() is always zero. MOZ_ASSERT(aParameters.Offset() == LayerIntPoint(0,0)); - const LayoutDevicePoint p = mImageLayerDestRect.TopLeft(); + const LayoutDevicePoint p = mDestRect.TopLeft(); Matrix transform = Matrix::Translation(p.x, p.y); - transform.PreScale(mImageLayerDestRect.width / imageWidth, - mImageLayerDestRect.height / imageHeight); + transform.PreScale(mDestRect.width / imageWidth, + mDestRect.height / imageHeight); aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); } @@ -2877,13 +2858,6 @@ } return; } - if (!mDestArea.IsEqualInterior(geometry->mDestArea)) { - // Dest area changed in a way that could cause everything to change, - // so invalidate everything (both old and new painting areas). - aInvalidRegion->Or(bounds, geometry->mBounds); - NotifyRenderingChanged(); - return; - } if (aBuilder->ShouldSyncDecodeImages()) { const nsStyleImage& image = mBackgroundStyle->mLayers[mLayer].mImage; if (image.GetType() == eStyleImageType_Image && diff -Nru firefox-45.0~b2+build1/layout/base/nsDisplayList.h firefox-45.0~b3+build1/layout/base/nsDisplayList.h --- firefox-45.0~b2+build1/layout/base/nsDisplayList.h 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/layout/base/nsDisplayList.h 2016-02-05 06:54:54.000000000 +0000 @@ -2438,11 +2438,6 @@ nsRect GetPositioningArea(); /** - * Return the destination area of one instance of the image. - */ - nsRect GetDestArea() const { return mDestArea; } - - /** * Returns true if existing rendered pixels of this display item may need * to be redrawn if the positioning area size changes but its position does * not. @@ -2486,7 +2481,6 @@ gfxRect* aDestRect); bool IsNonEmptyFixedImage() const; nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder); - nsRect GetDestAreaInternal(nsDisplayListBuilder* aBuilder); void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, const nsRect& aBounds, nsRect* aClipRect); @@ -2506,11 +2500,10 @@ const nsStyleBackground* mBackgroundStyle; nsCOMPtr mImage; RefPtr mImageContainer; - LayoutDeviceRect mImageLayerDestRect; + LayoutDeviceRect mDestRect; AnimatedGeometryRoot* mAnimatedGeometryRootForScrollMetadata; /* Bounds of this display item */ nsRect mBounds; - nsRect mDestArea; uint32_t mLayer; }; diff -Nru firefox-45.0~b2+build1/layout/base/nsDisplayListInvalidation.cpp firefox-45.0~b3+build1/layout/base/nsDisplayListInvalidation.cpp --- firefox-45.0~b2+build1/layout/base/nsDisplayListInvalidation.cpp 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/layout/base/nsDisplayListInvalidation.cpp 2016-02-05 06:54:54.000000000 +0000 @@ -63,7 +63,6 @@ : nsDisplayItemGeometry(aItem, aBuilder) , nsImageGeometryMixin(aItem, aBuilder) , mPositioningArea(aItem->GetPositioningArea()) - , mDestArea(aItem->GetDestArea()) {} void @@ -71,7 +70,6 @@ { nsDisplayItemGeometry::MoveBy(aOffset); mPositioningArea.MoveBy(aOffset); - mDestArea.MoveBy(aOffset); } nsDisplayThemedBackgroundGeometry::nsDisplayThemedBackgroundGeometry(nsDisplayThemedBackground* aItem, diff -Nru firefox-45.0~b2+build1/layout/base/nsDisplayListInvalidation.h firefox-45.0~b3+build1/layout/base/nsDisplayListInvalidation.h --- firefox-45.0~b2+build1/layout/base/nsDisplayListInvalidation.h 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/layout/base/nsDisplayListInvalidation.h 2016-02-05 06:54:54.000000000 +0000 @@ -194,7 +194,6 @@ virtual void MoveBy(const nsPoint& aOffset) override; nsRect mPositioningArea; - nsRect mDestArea; }; class nsDisplayThemedBackgroundGeometry : public nsDisplayItemGeometry diff -Nru firefox-45.0~b2+build1/layout/reftests/image-rect/reftest.list firefox-45.0~b3+build1/layout/reftests/image-rect/reftest.list --- firefox-45.0~b2+build1/layout/reftests/image-rect/reftest.list 2016-02-02 06:57:31.000000000 +0000 +++ firefox-45.0~b3+build1/layout/reftests/image-rect/reftest.list 2016-02-05 06:54:46.000000000 +0000 @@ -3,7 +3,7 @@ == background-common-usage-pixel.html background-common-usage-ref.html == background-draw-nothing-empty-rect.html background-draw-nothing-ref.html == background-draw-nothing-invalid-syntax.html background-draw-nothing-ref.html -asserts(0-6) == background-draw-nothing-malformed-images.html background-draw-nothing-ref.html # Bug 576419 +asserts(0-4) == background-draw-nothing-malformed-images.html background-draw-nothing-ref.html # Bug 576419 == background-monster-rect.html background-monster-rect-ref.html == background-over-size-rect.html background-over-size-rect-ref.html == background-test-parser.html background-test-parser-ref.html diff -Nru firefox-45.0~b2+build1/layout/reftests/invalidation/background-position-1.html firefox-45.0~b3+build1/layout/reftests/invalidation/background-position-1.html --- firefox-45.0~b2+build1/layout/reftests/invalidation/background-position-1.html 2016-02-02 06:57:31.000000000 +0000 +++ firefox-45.0~b3+build1/layout/reftests/invalidation/background-position-1.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ - - - -Changes to background-position should not cause things to repaint that don't intersect the background image. - - - -
-
-
- - diff -Nru firefox-45.0~b2+build1/layout/reftests/invalidation/background-position-1-ref.html firefox-45.0~b3+build1/layout/reftests/invalidation/background-position-1-ref.html --- firefox-45.0~b2+build1/layout/reftests/invalidation/background-position-1-ref.html 2016-02-02 06:57:31.000000000 +0000 +++ firefox-45.0~b3+build1/layout/reftests/invalidation/background-position-1-ref.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ - - - -Changes to background-position should not cause things to repaint that don't intersect the background image. - - - -
-
-
diff -Nru firefox-45.0~b2+build1/layout/reftests/invalidation/reftest.list firefox-45.0~b3+build1/layout/reftests/invalidation/reftest.list --- firefox-45.0~b2+build1/layout/reftests/invalidation/reftest.list 2016-02-02 06:57:31.000000000 +0000 +++ firefox-45.0~b3+build1/layout/reftests/invalidation/reftest.list 2016-02-05 06:54:46.000000000 +0000 @@ -70,6 +70,5 @@ != fractional-transform-1.html about:blank != fractional-transform-2.html about:blank != fractional-transform-3.html about:blank -== background-position-1.html background-position-1-ref.html == zero-opacity-animation.html about:blank == zero-opacity-text.html about:blank diff -Nru firefox-45.0~b2+build1/layout/style/nsCSSPropList.h firefox-45.0~b3+build1/layout/style/nsCSSPropList.h --- firefox-45.0~b2+build1/layout/style/nsCSSPropList.h 2016-02-02 06:57:34.000000000 +0000 +++ firefox-45.0~b3+build1/layout/style/nsCSSPropList.h 2016-02-05 06:54:48.000000000 +0000 @@ -3944,8 +3944,7 @@ fill, fill, Fill, - CSS_PROPERTY_PARSE_FUNCTION | - CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED, + CSS_PROPERTY_PARSE_FUNCTION, "", 0, kContextPatternKTable, @@ -4114,8 +4113,7 @@ stroke, stroke, Stroke, - CSS_PROPERTY_PARSE_FUNCTION | - CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED, + CSS_PROPERTY_PARSE_FUNCTION, "", 0, kContextPatternKTable, diff -Nru firefox-45.0~b2+build1/layout/style/nsStyleStruct.cpp firefox-45.0~b3+build1/layout/style/nsStyleStruct.cpp --- firefox-45.0~b2+build1/layout/style/nsStyleStruct.cpp 2016-02-02 06:57:34.000000000 +0000 +++ firefox-45.0~b3+build1/layout/style/nsStyleStruct.cpp 2016-02-05 06:54:49.000000000 +0000 @@ -2313,32 +2313,27 @@ const nsStyleBackground* lessLayers = mImageCount > aOther.mImageCount ? &aOther : this; - nsChangeHint hint = nsChangeHint(0); + bool hasVisualDifference = false; NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, moreLayers) { if (i < lessLayers->mImageCount) { - nsChangeHint layerDifference = moreLayers->mLayers[i].CalcDifference(lessLayers->mLayers[i]); - hint |= layerDifference; - if (layerDifference && - ((moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) || - (lessLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element))) { - hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame; + if (moreLayers->mLayers[i] != lessLayers->mLayers[i]) { + if ((moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) || + (lessLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element)) + return NS_CombineHint(nsChangeHint_UpdateEffects, + nsChangeHint_RepaintFrame); + hasVisualDifference = true; } } else { - hint |= nsChangeHint_RepaintFrame; - if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) { - hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame; - } + if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) + return NS_CombineHint(nsChangeHint_UpdateEffects, + nsChangeHint_RepaintFrame); + hasVisualDifference = true; } } - if (mBackgroundColor != aOther.mBackgroundColor) { - hint |= nsChangeHint_RepaintFrame; - } - - if (hint) { - return hint; - } + if (hasVisualDifference || mBackgroundColor != aOther.mBackgroundColor) + return nsChangeHint_RepaintFrame; if (mAttachmentCount != aOther.mAttachmentCount || mClipCount != aOther.mClipCount || @@ -2549,25 +2544,6 @@ mImage == aOther.mImage; } -nsChangeHint -nsStyleBackground::Layer::CalcDifference(const Layer& aOther) const -{ - nsChangeHint hint = nsChangeHint(0); - if (mAttachment != aOther.mAttachment || - mClip != aOther.mClip || - mOrigin != aOther.mOrigin || - mRepeat != aOther.mRepeat || - mBlendMode != aOther.mBlendMode || - mSize != aOther.mSize || - mImage != aOther.mImage) { - hint |= nsChangeHint_RepaintFrame; - } - if (mPosition != aOther.mPosition) { - hint |= nsChangeHint_SchedulePaint; - } - return hint; -} - // -------------------- // nsStyleDisplay // diff -Nru firefox-45.0~b2+build1/layout/style/nsStyleStruct.h firefox-45.0~b3+build1/layout/style/nsStyleStruct.h --- firefox-45.0~b2+build1/layout/style/nsStyleStruct.h 2016-02-02 06:57:34.000000000 +0000 +++ firefox-45.0~b3+build1/layout/style/nsStyleStruct.h 2016-02-05 06:54:49.000000000 +0000 @@ -405,10 +405,9 @@ nsChangeHint CalcDifference(const nsStyleBackground& aOther) const; static nsChangeHint MaxDifference() { - return nsChangeHint_UpdateEffects | - nsChangeHint_RepaintFrame | - nsChangeHint_SchedulePaint | - nsChangeHint_NeutralChange; + return NS_CombineHint(nsChangeHint_UpdateEffects, + NS_CombineHint(nsChangeHint_RepaintFrame, + nsChangeHint_NeutralChange)); } static nsChangeHint DifferenceAlwaysHandledForDescendants() { // CalcDifference never returns the reflow hints that are sometimes @@ -562,9 +561,6 @@ // whose root node has a viewBox. bool RenderingMightDependOnPositioningAreaSizeChange() const; - // Compute the change hint required by changes in just this layer. - nsChangeHint CalcDifference(const Layer& aOther) const; - // An equality operator that compares the images using URL-equality // rather than pointer-equality. bool operator==(const Layer& aOther) const; diff -Nru firefox-45.0~b2+build1/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp firefox-45.0~b3+build1/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp --- firefox-45.0~b2+build1/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp 2016-02-02 06:57:35.000000000 +0000 +++ firefox-45.0~b3+build1/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp 2016-02-05 06:54:49.000000000 +0000 @@ -651,14 +651,14 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { ALOGV("entering parseChunk %lld/%d", *offset, depth); uint32_t hdr[2]; - ssize_t nbytes; - if ((nbytes = mDataSource->readAt(*offset, hdr, 8)) < 8) { - if (nbytes == 4) { - if (!hdr[0]) { - *offset += 4; - return OK; - } - } + if (mDataSource->readAt(*offset, hdr, 4) < 4) { + return ERROR_IO; + } + if (!hdr[0]) { + *offset += 4; + return OK; + } + if (mDataSource->readAt(*offset + 4, hdr + 1, 4) < 4) { return ERROR_IO; } uint64_t chunk_size = ntohl(hdr[0]); diff -Nru firefox-45.0~b2+build1/mobile/android/app/mobile.js firefox-45.0~b3+build1/mobile/android/app/mobile.js --- firefox-45.0~b2+build1/mobile/android/app/mobile.js 2016-02-02 06:57:38.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/app/mobile.js 2016-02-05 06:54:51.000000000 +0000 @@ -766,6 +766,9 @@ pref("layers.enable-tiles", true); +// Speculative 'fix' to work around OOM issues +pref("layers.tiles.adjust", false); + // Enable the dynamic toolbar pref("browser.chrome.dynamictoolbar", true); diff -Nru firefox-45.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java firefox-45.0~b3+build1/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java --- firefox-45.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java 2016-02-02 06:57:38.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java 2016-02-05 06:54:52.000000000 +0000 @@ -1180,6 +1180,15 @@ return true; } + if (itemId == R.id.site_settings) { + // This can be selected from either the browser menu or the contextmenu, depending on the size and version (v11+) of the phone. + GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Permissions:Get", null)); + if (Versions.preHC) { + Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.CONTEXT_MENU, "site_settings"); + } + return true; + } + if (itemId == R.id.paste) { String text = Clipboard.getText(); if (!TextUtils.isEmpty(text)) { @@ -3053,6 +3062,7 @@ } MenuUtils.safeSetEnabled(aMenu, R.id.subscribe, false); MenuUtils.safeSetEnabled(aMenu, R.id.add_search_engine, false); + MenuUtils.safeSetEnabled(aMenu, R.id.site_settings, false); MenuUtils.safeSetEnabled(aMenu, R.id.add_to_launcher, false); return true; @@ -3140,6 +3150,7 @@ } MenuUtils.safeSetEnabled(aMenu, R.id.subscribe, tab.hasFeeds()); MenuUtils.safeSetEnabled(aMenu, R.id.add_search_engine, tab.hasOpenSearch()); + MenuUtils.safeSetEnabled(aMenu, R.id.site_settings, !isAboutHome(tab)); MenuUtils.safeSetEnabled(aMenu, R.id.add_to_launcher, !isAboutHome(tab)); // Action providers are available only ICS+. diff -Nru firefox-45.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/DynamicToolbar.java firefox-45.0~b3+build1/mobile/android/base/java/org/mozilla/gecko/DynamicToolbar.java --- firefox-45.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/DynamicToolbar.java 2016-02-02 06:57:38.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/base/java/org/mozilla/gecko/DynamicToolbar.java 2016-02-05 06:54:52.000000000 +0000 @@ -6,9 +6,13 @@ import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.util.ThreadUtils; +import android.os.Build; import android.os.Bundle; +import android.util.Log; public class DynamicToolbar { + private static final String LOGTAG = "DynamicToolbar"; + private static final String STATE_ENABLED = "dynamic_toolbar"; private static final String CHROME_PREF = "browser.chrome.dynamictoolbar"; @@ -17,6 +21,9 @@ // the pref from Gecko telling us to turn it on. private volatile boolean prefEnabled; private boolean accessibilityEnabled; + // On some device we have to force-disable the dynamic toolbar because of + // bugs in the Android code. See bug 1231554. + private final boolean forceDisabled; private final int prefObserverId; private final EnumSet pinFlags = EnumSet.noneOf(PinReason.class); @@ -48,6 +55,21 @@ public DynamicToolbar() { // Listen to the dynamic toolbar pref prefObserverId = PrefsHelper.getPref(CHROME_PREF, new PrefHandler()); + forceDisabled = isForceDisabled(); + if (forceDisabled) { + Log.i(LOGTAG, "Force-disabling dynamic toolbar for " + Build.MODEL + " (" + Build.DEVICE + "/" + Build.PRODUCT + ")"); + } + } + + public static boolean isForceDisabled() { + // Force-disable dynamic toolbar on the variants of the Galaxy Note 10.1 + // and Note 8.0 running Android 4.1.2. (Bug 1231554). This includes + // the following model numbers: + // GT-N8000, GT-N8005, GT-N8010, GT-N8013, GT-N8020 + // GT-N5100, GT-N5110, GT-N5120 + return Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN + && (Build.MODEL.startsWith("GT-N80") || + Build.MODEL.startsWith("GT-N51")); } public void destroy() { @@ -83,6 +105,10 @@ public boolean isEnabled() { ThreadUtils.assertOnUiThread(); + if (forceDisabled) { + return false; + } + return prefEnabled && !accessibilityEnabled; } diff -Nru firefox-45.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java firefox-45.0~b3+build1/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java --- firefox-45.0~b2+build1/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java 2016-02-02 06:57:38.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java 2016-02-05 06:54:52.000000000 +0000 @@ -13,6 +13,7 @@ import org.mozilla.gecko.BrowserApp; import org.mozilla.gecko.BrowserLocaleManager; import org.mozilla.gecko.DataReportingNotification; +import org.mozilla.gecko.DynamicToolbar; import org.mozilla.gecko.EventDispatcher; import org.mozilla.gecko.GeckoActivityStatus; import org.mozilla.gecko.GeckoAppShell; @@ -164,6 +165,8 @@ public static final String PREFS_TAB_QUEUE_LAST_SITE = NON_PREF_PREFIX + "last_site"; public static final String PREFS_TAB_QUEUE_LAST_TIME = NON_PREF_PREFIX + "last_time"; + private static final String PREFS_DYNAMIC_TOOLBAR = "browser.chrome.dynamictoolbar"; + // These values are chosen to be distinct from other Activity constants. private static final int REQUEST_CODE_PREF_SCREEN = 5; private static final int RESULT_CODE_EXIT_SETTINGS = 6; @@ -872,6 +875,12 @@ final String url = getResources().getString(R.string.faq_link, VERSION, OS, LOCALE); ((LinkPreference) pref).setUrl(url); + } else if (PREFS_DYNAMIC_TOOLBAR.equals(key)) { + if (DynamicToolbar.isForceDisabled()) { + preferences.removePreference(pref); + i--; + continue; + } } // Some Preference UI elements are not actually preferences, diff -Nru firefox-45.0~b2+build1/mobile/android/base/resources/menu/titlebar_contextmenu.xml firefox-45.0~b3+build1/mobile/android/base/resources/menu/titlebar_contextmenu.xml --- firefox-45.0~b2+build1/mobile/android/base/resources/menu/titlebar_contextmenu.xml 2016-02-02 06:57:38.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/base/resources/menu/titlebar_contextmenu.xml 2016-02-05 06:54:52.000000000 +0000 @@ -20,6 +20,9 @@ + + diff -Nru firefox-45.0~b2+build1/mobile/android/base/resources/menu-large-v11/browser_app_menu.xml firefox-45.0~b3+build1/mobile/android/base/resources/menu-large-v11/browser_app_menu.xml --- firefox-45.0~b2+build1/mobile/android/base/resources/menu-large-v11/browser_app_menu.xml 2016-02-02 06:57:38.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/base/resources/menu-large-v11/browser_app_menu.xml 2016-02-05 06:54:52.000000000 +0000 @@ -84,6 +84,9 @@ + + diff -Nru firefox-45.0~b2+build1/mobile/android/base/resources/menu-v11/browser_app_menu.xml firefox-45.0~b3+build1/mobile/android/base/resources/menu-v11/browser_app_menu.xml --- firefox-45.0~b2+build1/mobile/android/base/resources/menu-v11/browser_app_menu.xml 2016-02-02 06:57:38.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/base/resources/menu-v11/browser_app_menu.xml 2016-02-05 06:54:52.000000000 +0000 @@ -84,6 +84,9 @@ + + diff -Nru firefox-45.0~b2+build1/mobile/android/base/resources/menu-xlarge-v11/browser_app_menu.xml firefox-45.0~b3+build1/mobile/android/base/resources/menu-xlarge-v11/browser_app_menu.xml --- firefox-45.0~b2+build1/mobile/android/base/resources/menu-xlarge-v11/browser_app_menu.xml 2016-02-02 06:57:38.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/base/resources/menu-xlarge-v11/browser_app_menu.xml 2016-02-05 06:54:52.000000000 +0000 @@ -85,6 +85,9 @@ + + diff -Nru firefox-45.0~b2+build1/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/ToolbarComponent.java firefox-45.0~b3+build1/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/ToolbarComponent.java --- firefox-45.0~b2+build1/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/ToolbarComponent.java 2016-02-02 06:57:39.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/components/ToolbarComponent.java 2016-02-05 06:54:53.000000000 +0000 @@ -10,6 +10,7 @@ import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue; import org.mozilla.gecko.R; +import org.mozilla.gecko.tests.StringHelper; import org.mozilla.gecko.tests.UITestContext; import org.mozilla.gecko.tests.helpers.DeviceHelper; import org.mozilla.gecko.tests.helpers.NavigationHelper; diff -Nru firefox-45.0~b2+build1/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/StringHelper.java firefox-45.0~b3+build1/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/StringHelper.java --- firefox-45.0~b2+build1/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/StringHelper.java 2016-02-02 06:57:39.000000000 +0000 +++ firefox-45.0~b3+build1/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/StringHelper.java 2016-02-05 06:54:53.000000000 +0000 @@ -16,8 +16,6 @@ public static String STATIC_ABOUT_HOME_URL = "about:home"; public final String OK; - public final String CANCEL; - public final String CLEAR; // Note: DEFAULT_BOOKMARKS_TITLES.length == DEFAULT_BOOKMARKS_URLS.length public final String[] DEFAULT_BOOKMARKS_TITLES; @@ -220,8 +218,6 @@ private StringHelper(final Resources res) { OK = res.getString(R.string.button_ok); - CANCEL = res.getString(R.string.button_cancel); - CLEAR = res.getString(R.string.button_clear); // Note: DEFAULT_BOOKMARKS_TITLES.length == DEFAULT_BOOKMARKS_URLS.length DEFAULT_BOOKMARKS_TITLES = new String[] { diff -Nru firefox-45.0~b2+build1/modules/libpref/init/all.js firefox-45.0~b3+build1/modules/libpref/init/all.js --- firefox-45.0~b2+build1/modules/libpref/init/all.js 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/modules/libpref/init/all.js 2016-02-05 06:54:53.000000000 +0000 @@ -89,6 +89,11 @@ // The half life used to re-compute cache entries frecency in hours. pref("browser.cache.frecency_half_life_hours", 6); +// Number of seconds the cache spends writting pending data and closing files +// after the shutdown has been signalled. Past that time data are never written +// and files are left open given up to the OS to do the cleanup. +pref("browser.cache.max_shutdown_io_lag", 2); + pref("browser.cache.offline.enable", true); // enable offline apps by default, disable prompt pref("offline-apps.allow_by_default", true); diff -Nru firefox-45.0~b2+build1/netwerk/cache2/CacheFileIOManager.cpp firefox-45.0~b3+build1/netwerk/cache2/CacheFileIOManager.cpp --- firefox-45.0~b2+build1/netwerk/cache2/CacheFileIOManager.cpp 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/netwerk/cache2/CacheFileIOManager.cpp 2016-02-05 06:54:53.000000000 +0000 @@ -536,6 +536,7 @@ ShutdownEvent(mozilla::Mutex *aLock, mozilla::CondVar *aCondVar) : mLock(aLock) , mCondVar(aCondVar) + , mPrepare(true) { MOZ_COUNT_CTOR(ShutdownEvent); } @@ -549,6 +550,21 @@ public: NS_IMETHOD Run() { + if (mPrepare) { + MOZ_ASSERT(CacheFileIOManager::gInstance->mIOThread->IsCurrentThread()); + + mPrepare = false; + + // This event is first posted to the XPCOM level (executed ASAP) of the IO thread + // and sets the timestamp of the shutdown start. This will cause some operations + // to be bypassed when due (actually leak most of the open files). + CacheFileIOManager::gInstance->mShutdownDemandedTime = TimeStamp::NowLoRes(); + + // Redispatch to the right level to proceed with shutdown. + CacheFileIOManager::gInstance->mIOThread->Dispatch(this, CacheIOThread::CLOSE); + return NS_OK; + } + MutexAutoLock lock(*mLock); CacheFileIOManager::gInstance->ShutdownInternal(); @@ -560,6 +576,7 @@ protected: mozilla::Mutex *mLock; mozilla::CondVar *mCondVar; + bool mPrepare; }; class OpenFileEvent : public nsRunnable { @@ -697,7 +714,13 @@ nsresult rv; if (mHandle->IsClosed()) { - rv = NS_ERROR_NOT_INITIALIZED; + // We usually get here only after the internal shutdown + // (i.e. mShuttingDown == true). Pretend write has succeeded + // to avoid any past-shutdown file dooming. + rv = (CacheFileIOManager::gInstance->IsPastShutdownIOLag() || + CacheFileIOManager::gInstance->mShuttingDown) + ? NS_OK + : NS_ERROR_NOT_INITIALIZED; } else { rv = CacheFileIOManager::gInstance->WriteInternal( mHandle, mOffset, mBuf, mCount, mValidate, mTruncate); @@ -1148,7 +1171,9 @@ MutexAutoLock autoLock(lock); RefPtr ev = new ShutdownEvent(&lock, &condVar); DebugOnly rv; - rv = gInstance->mIOThread->Dispatch(ev, CacheIOThread::CLOSE); + nsCOMPtr ioTarget = gInstance->mIOThread->Target(); + MOZ_ASSERT(ioTarget); + rv = ioTarget->Dispatch(ev, nsIEventTarget::DISPATCH_NORMAL); MOZ_ASSERT(NS_SUCCEEDED(rv)); condVar.Wait(); } @@ -1240,6 +1265,26 @@ return NS_OK; } +bool +CacheFileIOManager::IsPastShutdownIOLag() +{ +#ifdef DEBUG + return false; +#endif + + if (mShutdownDemandedTime.IsNull()) { + return false; + } + + TimeDuration const& preferredIOLag = CacheObserver::MaxShutdownIOLag(); + if (preferredIOLag < TimeDuration(0)) { + return false; + } + + TimeDuration currentIOLag = TimeStamp::NowLoRes() - mShutdownDemandedTime; + return currentIOLag > preferredIOLag; +} + // static nsresult CacheFileIOManager::OnProfile() @@ -1925,6 +1970,13 @@ nsresult rv; + if (IsPastShutdownIOLag()) { + LOG((" past the shutdown I/O lag, nothing written")); + // Pretend the write has succeeded, otherwise upper layers will doom + // the file and we end up with I/O anyway. + return NS_OK; + } + if (!aHandle->mFileExists) { rv = CreateFile(aHandle); NS_ENSURE_SUCCESS(rv, rv); @@ -2082,7 +2134,7 @@ if (aHandle->mFileExists) { // we need to move the current file to the doomed directory if (aHandle->mFD) { - ReleaseNSPRHandleInternal(aHandle); + ReleaseNSPRHandleInternal(aHandle, true); } // find unused filename @@ -2229,7 +2281,8 @@ } nsresult -CacheFileIOManager::ReleaseNSPRHandleInternal(CacheFileHandle *aHandle) +CacheFileIOManager::ReleaseNSPRHandleInternal(CacheFileHandle *aHandle, + bool aIgnoreShutdownLag) { LOG(("CacheFileIOManager::ReleaseNSPRHandleInternal() [handle=%p]", aHandle)); @@ -2240,7 +2293,17 @@ found = mHandlesByLastUsed.RemoveElement(aHandle); MOZ_ASSERT(found); - PR_Close(aHandle->mFD); + if (aIgnoreShutdownLag || !IsPastShutdownIOLag()) { + PR_Close(aHandle->mFD); + } else { + // Pretend this file has been validated (the metadata has been written) + // to prevent removal I/O on this apparently used file. The entry will + // never be used, since it doesn't have correct metadata, thus we don't + // need to worry about removing it. + aHandle->mInvalid = false; + LOG((" past the shutdown I/O lag, leaking file handle")); + } + aHandle->mFD = nullptr; return NS_OK; @@ -2538,7 +2601,7 @@ } if (aHandle->mFD) { - ReleaseNSPRHandleInternal(aHandle); + ReleaseNSPRHandleInternal(aHandle, true); } rv = aHandle->mFile->MoveToNative(nullptr, aNewName); @@ -3731,7 +3794,7 @@ if (mHandlesByLastUsed.Length() == kOpenHandlesLimit) { // close handle that hasn't been used for the longest time - rv = ReleaseNSPRHandleInternal(mHandlesByLastUsed[0]); + rv = ReleaseNSPRHandleInternal(mHandlesByLastUsed[0], true); NS_ENSURE_SUCCESS(rv, rv); } diff -Nru firefox-45.0~b2+build1/netwerk/cache2/CacheFileIOManager.h firefox-45.0~b3+build1/netwerk/cache2/CacheFileIOManager.h --- firefox-45.0~b2+build1/netwerk/cache2/CacheFileIOManager.h 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/netwerk/cache2/CacheFileIOManager.h 2016-02-05 06:54:53.000000000 +0000 @@ -382,7 +382,8 @@ nsresult DoomFileInternal(CacheFileHandle *aHandle, PinningDoomRestriction aPinningStatusRestriction = NO_RESTRICTION); nsresult DoomFileByKeyInternal(const SHA1Sum::Hash *aHash); - nsresult ReleaseNSPRHandleInternal(CacheFileHandle *aHandle); + nsresult ReleaseNSPRHandleInternal(CacheFileHandle *aHandle, + bool aIgnoreShutdownLag = false); nsresult TruncateSeekSetEOFInternal(CacheFileHandle *aHandle, int64_t aTruncatePos, int64_t aEOFPos); nsresult RenameFileInternal(CacheFileHandle *aHandle, @@ -429,11 +430,18 @@ // before we start an eviction loop. nsresult UpdateSmartCacheSize(int64_t aFreeSpace); + // May return true after shutdown only when time for flushing all data + // has already passed. + bool IsPastShutdownIOLag(); + // Memory reporting (private part) size_t SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const; static CacheFileIOManager *gInstance; TimeStamp mStartTime; + // Shutdown time stamp, accessed only on the I/O thread. Used to bypass + // I/O after a certain time pass the shutdown has been demanded. + TimeStamp mShutdownDemandedTime; bool mShuttingDown; RefPtr mIOThread; nsCOMPtr mCacheDirectory; diff -Nru firefox-45.0~b2+build1/netwerk/cache2/CacheObserver.cpp firefox-45.0~b3+build1/netwerk/cache2/CacheObserver.cpp --- firefox-45.0~b2+build1/netwerk/cache2/CacheObserver.cpp 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/netwerk/cache2/CacheObserver.cpp 2016-02-05 06:54:53.000000000 +0000 @@ -11,6 +11,7 @@ #include "nsIObserverService.h" #include "mozilla/Services.h" #include "mozilla/Preferences.h" +#include "mozilla/TimeStamp.h" #include "nsServiceManagerUtils.h" #include "prsystem.h" #include @@ -91,6 +92,9 @@ static bool kDefaultHashStatsReported = false; bool CacheObserver::sHashStatsReported = kDefaultHashStatsReported; +static int32_t const kDefaultMaxShutdownIOLag = 2; // seconds +int32_t CacheObserver::sMaxShutdownIOLag = kDefaultMaxShutdownIOLag; + NS_IMPL_ISUPPORTS(CacheObserver, nsIObserver, nsISupportsWeakReference) @@ -237,6 +241,9 @@ &sSanitizeOnShutdown, "privacy.sanitize.sanitizeOnShutdown", kDefaultSanitizeOnShutdown); mozilla::Preferences::AddBoolVarCache( &sClearCacheOnShutdown, "privacy.clearOnShutdown.cache", kDefaultClearCacheOnShutdown); + + mozilla::Preferences::AddIntVarCache( + &sMaxShutdownIOLag, "browser.cache.max_shutdown_io_lag", kDefaultMaxShutdownIOLag); } // static @@ -466,6 +473,13 @@ return false; } +// static +TimeDuration const& CacheObserver::MaxShutdownIOLag() +{ + static TimeDuration period = TimeDuration::FromSeconds(sMaxShutdownIOLag); + return period; +} + NS_IMETHODIMP CacheObserver::Observe(nsISupports* aSubject, const char* aTopic, diff -Nru firefox-45.0~b2+build1/netwerk/cache2/CacheObserver.h firefox-45.0~b3+build1/netwerk/cache2/CacheObserver.h --- firefox-45.0~b2+build1/netwerk/cache2/CacheObserver.h 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/netwerk/cache2/CacheObserver.h 2016-02-05 06:54:53.000000000 +0000 @@ -71,6 +71,8 @@ static bool const EntryIsTooBig(int64_t aSize, bool aUsingDisk); + static TimeDuration const& MaxShutdownIOLag(); + private: static CacheObserver* sSelf; @@ -101,6 +103,7 @@ static bool sClearCacheOnShutdown; static bool sCacheFSReported; static bool sHashStatsReported; + static int32_t sMaxShutdownIOLag; // Non static properties, accessible via sSelf nsCOMPtr mCacheParentDirectoryOverride; diff -Nru firefox-45.0~b2+build1/netwerk/cache2/CacheStorageService.cpp firefox-45.0~b3+build1/netwerk/cache2/CacheStorageService.cpp --- firefox-45.0~b2+build1/netwerk/cache2/CacheStorageService.cpp 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/netwerk/cache2/CacheStorageService.cpp 2016-02-05 06:54:53.000000000 +0000 @@ -2115,7 +2115,9 @@ CacheStorageService::IOThreadSuspender::Run() { MonitorAutoLock mon(mMon); - mon.Wait(); + while (!mSignaled) { + mon.Wait(); + } return NS_OK; } @@ -2123,6 +2125,7 @@ CacheStorageService::IOThreadSuspender::Notify() { MonitorAutoLock mon(mMon); + mSignaled = true; mon.Notify(); } diff -Nru firefox-45.0~b2+build1/netwerk/cache2/CacheStorageService.h firefox-45.0~b3+build1/netwerk/cache2/CacheStorageService.h --- firefox-45.0~b2+build1/netwerk/cache2/CacheStorageService.h 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/netwerk/cache2/CacheStorageService.h 2016-02-05 06:54:53.000000000 +0000 @@ -366,13 +366,14 @@ class IOThreadSuspender : public nsRunnable { public: - IOThreadSuspender() : mMon("IOThreadSuspender") { } + IOThreadSuspender() : mMon("IOThreadSuspender"), mSignaled(false) { } void Notify(); private: virtual ~IOThreadSuspender() { } NS_IMETHOD Run() override; Monitor mMon; + bool mSignaled; }; RefPtr mActiveIOSuspender; diff -Nru firefox-45.0~b2+build1/netwerk/cookie/nsCookieService.cpp firefox-45.0~b3+build1/netwerk/cookie/nsCookieService.cpp --- firefox-45.0~b2+build1/netwerk/cookie/nsCookieService.cpp 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/netwerk/cookie/nsCookieService.cpp 2016-02-05 06:54:53.000000000 +0000 @@ -3176,7 +3176,7 @@ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, - 0x1F, 0x20, 0x00 }; + 0x1F, 0x00 }; if (cookieAttributes.name.FindCharInSet(illegalNameCharacters, 0) != -1) { COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "invalid name character"); return newCookie; diff -Nru firefox-45.0~b2+build1/netwerk/test/unit/test_cache2-30d-pinning-WasEvicted-API.js firefox-45.0~b3+build1/netwerk/test/unit/test_cache2-30d-pinning-WasEvicted-API.js --- firefox-45.0~b2+build1/netwerk/test/unit/test_cache2-30d-pinning-WasEvicted-API.js 2016-02-02 06:57:41.000000000 +0000 +++ firefox-45.0~b3+build1/netwerk/test/unit/test_cache2-30d-pinning-WasEvicted-API.js 2016-02-05 06:54:54.000000000 +0000 @@ -4,7 +4,7 @@ - We store 10+10 (pinned and non-pinned) entries to the cache, wait for them being written. - Then we purge the memory pools. -- Now the IO thread is suspended on the EVICT (8) level to prevent actual deletion of the files. +- Now the IO thread is suspended on the EVICT (7) level to prevent actual deletion of the files. - Index is disabled. - We do clear() of the cache, this creates the "ce_*" file and posts to the EVICT level the eviction loop mechanics. @@ -51,9 +51,9 @@ // (1), here we start + log_("first set of opens"); var i; for (i = 0; i < kENTRYCOUNT; ++i) { - log_("first set of opens"); // Callbacks 1-20 mc.add(); @@ -100,7 +100,9 @@ // an early check on CacheIOThread::YieldAndRerun() in that method. // CacheFileIOManager::OpenFileInternal should now run and CacheFileContextEvictor::WasEvicted // should be checked on. + log_("resuming"); testingInterface.resumeCacheIOThread(); + log_("resumed"); mc.fired(); // Finishes this test } diff -Nru firefox-45.0~b2+build1/testing/firefox-ui/tests/firefox_ui_tests/functional/locationbar/test_suggest_bookmarks.py firefox-45.0~b3+build1/testing/firefox-ui/tests/firefox_ui_tests/functional/locationbar/test_suggest_bookmarks.py --- firefox-45.0~b2+build1/testing/firefox-ui/tests/firefox_ui_tests/functional/locationbar/test_suggest_bookmarks.py 2016-02-02 06:57:32.000000000 +0000 +++ firefox-45.0~b3+build1/testing/firefox-ui/tests/firefox_ui_tests/functional/locationbar/test_suggest_bookmarks.py 2016-02-05 06:54:47.000000000 +0000 @@ -83,7 +83,7 @@ # Wait for the search string to be present, for the autocomplete results to appear # and for there to be exactly one autocomplete result Wait(self.marionette).until(lambda mn: locationbar.value == search_string) - Wait(self.marionette).until(lambda mn: autocomplete_results.is_open) + Wait(self.marionette).until(lambda mn: autocomplete_results.is_complete) Wait(self.marionette).until(lambda mn: len(autocomplete_results.visible_results) == 2) # Compare the highlighted text in the autocomplete result to the search string diff -Nru firefox-45.0~b2+build1/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py firefox-45.0~b3+build1/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py --- firefox-45.0~b2+build1/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py 2016-02-02 06:57:33.000000000 +0000 +++ firefox-45.0~b3+build1/testing/mozharness/mozharness/mozilla/testing/firefox_ui_tests.py 2016-02-05 06:54:47.000000000 +0000 @@ -393,7 +393,9 @@ # ZipFile doesn't preserve permissions: http://bugs.python.org/issue15795 fname = os.path.realpath(os.path.join(parent_dir, entry)) mode = bundle.getinfo(entry).external_attr >> 16 & 0x1FF - os.chmod(fname, mode) + # Only set permissions if attributes are available. + if mode: + os.chmod(fname, mode) except zipfile.BadZipfile as e: self.log('%s (%s)' % (e.message, zip), level=FATAL, exit_code=2) diff -Nru firefox-45.0~b2+build1/testing/mozharness/scripts/release/push-candidate-to-releases.py firefox-45.0~b3+build1/testing/mozharness/scripts/release/push-candidate-to-releases.py --- firefox-45.0~b2+build1/testing/mozharness/scripts/release/push-candidate-to-releases.py 2016-02-02 06:57:33.000000000 +0000 +++ firefox-45.0~b3+build1/testing/mozharness/scripts/release/push-candidate-to-releases.py 2016-02-05 06:54:47.000000000 +0000 @@ -81,7 +81,7 @@ self.config["excludes"] = [ r"^.*tests.*$", r"^.*crashreporter.*$", - r"^.*\.zip(\.asc)?$", + r"^.*[^k]\.zip(\.asc)?$", r"^.*\.log$", r"^.*\.txt$", r"^.*/partner-repacks.*$", diff -Nru firefox-45.0~b2+build1/toolkit/components/mediasniffer/nsMediaSniffer.cpp firefox-45.0~b3+build1/toolkit/components/mediasniffer/nsMediaSniffer.cpp --- firefox-45.0~b2+build1/toolkit/components/mediasniffer/nsMediaSniffer.cpp 2016-02-02 06:57:39.000000000 +0000 +++ firefox-45.0~b3+build1/toolkit/components/mediasniffer/nsMediaSniffer.cpp 2016-02-05 06:54:53.000000000 +0000 @@ -44,7 +44,8 @@ PATTERN_ENTRY("\xFF\xFF\xFF", "avc", VIDEO_MP4), // Could be avc1, avc2, ... PATTERN_ENTRY("\xFF\xFF\xFF", "3gp", VIDEO_3GPP), // Could be 3gp4, 3gp5, ... PATTERN_ENTRY("\xFF\xFF\xFF\xFF", "M4A ", AUDIO_MP4), - PATTERN_ENTRY("\xFF\xFF\xFF\xFF", "M4P ", AUDIO_MP4) + PATTERN_ENTRY("\xFF\xFF\xFF\xFF", "M4P ", AUDIO_MP4), + PATTERN_ENTRY("\xFF\xFF\xFF\xFF", "qt ", VIDEO_MP4), }; static bool MatchesBrands(const uint8_t aData[4], nsACString& aSniffedType) diff -Nru firefox-45.0~b2+build1/toolkit/components/telemetry/TelemetrySession.jsm firefox-45.0~b3+build1/toolkit/components/telemetry/TelemetrySession.jsm --- firefox-45.0~b2+build1/toolkit/components/telemetry/TelemetrySession.jsm 2016-02-02 06:57:40.000000000 +0000 +++ firefox-45.0~b3+build1/toolkit/components/telemetry/TelemetrySession.jsm 2016-02-05 06:54:53.000000000 +0000 @@ -58,6 +58,8 @@ const MESSAGE_TELEMETRY_PAYLOAD = "Telemetry:Payload"; const MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD = "Telemetry:GetChildPayload"; +const MESSAGE_TELEMETRY_THREAD_HANGS = "Telemetry:ChildThreadHangs"; +const MESSAGE_TELEMETRY_GET_CHILD_THREAD_HANGS = "Telemetry:GetChildThreadHangs"; const MESSAGE_TELEMETRY_USS = "Telemetry:USS"; const MESSAGE_TELEMETRY_GET_CHILD_USS = "Telemetry:GetChildUSS"; @@ -542,6 +544,17 @@ return Impl.requestChildPayloads(); }, /** + * Returns a promise that resolves to an array of thread hang stats from content processes, one entry per process. + * The structure of each entry is identical to that of "threadHangStats" in nsITelemetry. + * While thread hang stats are also part of the child payloads, this function is useful for cheaply getting this information, + * which is useful for realtime hang monitoring. + * Child processes that do not respond, or spawn/die during execution of this function are excluded from the result. + * @returns Promise + */ + getChildThreadHangs: function() { + return Impl.getChildThreadHangs(); + }, + /** * Save the session state to a pending file. * Used only for testing purposes. */ @@ -646,6 +659,15 @@ // where source is a weak reference to the child process, // and payload is the telemetry payload from that child process. _childTelemetry: [], + // Thread hangs from child processes. + // Each element is in the format {source: , payload: }, + // where source is a weak reference to the child process, + // and payload contains the thread hang stats from that child process. + _childThreadHangs: [], + // Array of the resolve functions of all the promises that are waiting for the child thread hang stats to arrive, used to resolve all those promises at once + _childThreadHangsResolveFunctions: [], + // Timeout function for child thread hang stats retrieval + _childThreadHangsTimeout: null, // Unique id that identifies this session so the server can cope with duplicate // submissions, orphaning and other oddities. The id is shared across subsessions. _sessionId: null, @@ -1377,6 +1399,7 @@ this._hasXulWindowVisibleObserver = true; ppml.addMessageListener(MESSAGE_TELEMETRY_PAYLOAD, this); + ppml.addMessageListener(MESSAGE_TELEMETRY_THREAD_HANGS, this); ppml.addMessageListener(MESSAGE_TELEMETRY_USS, this); // Delay full telemetry initialization to give the browser time to @@ -1443,6 +1466,7 @@ Services.obs.addObserver(this, "content-child-shutdown", false); cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD, this); + cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_THREAD_HANGS, this); cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_USS, this); this.gatherStartupHistograms(); @@ -1475,6 +1499,7 @@ switch (message.name) { case MESSAGE_TELEMETRY_PAYLOAD: { + // In parent process, receive Telemetry payload from child let source = message.data.childUUID; delete message.data.childUUID; @@ -1500,11 +1525,42 @@ } case MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD: { + // In child process, send the requested Telemetry payload this.sendContentProcessPing("saved-session"); break; } + case MESSAGE_TELEMETRY_THREAD_HANGS: + { + // Accumulate child thread hang stats from this child + this._childThreadHangs.push(message.data); + + // Check if we've got data from all the children, accounting for child processes dying + // if it happens before the last response is received and no new child processes are spawned at the exact same time + // If that happens, we can resolve the promise earlier rather than having to wait for the timeout to expire + // Basically, the number of replies is at most the number of messages sent out, this._childCount, + // and also at most the number of child processes that currently exist + if (this._childThreadHangs.length === Math.min(this._childCount, ppmm.childCount)) { + clearTimeout(this._childThreadHangsTimeout); + + // Resolve all the promises that are waiting on these thread hang stats + // We resolve here instead of rejecting because + for (let resolve of this._childThreadHangsResolveFunctions) { + resolve(this._childThreadHangs); + } + this._childThreadHangsResolveFunctions = []; + } + + break; + } + case MESSAGE_TELEMETRY_GET_CHILD_THREAD_HANGS: + { + // In child process, send the requested child thread hangs + this.sendContentProcessThreadHangs(); + break; + } case MESSAGE_TELEMETRY_USS: { + // In parent process, receive the USS report from the child if (this._totalMemoryTimeout && this._childrenToHearFrom.delete(message.data.id)) { this._totalMemory += message.data.bytes; if (this._childrenToHearFrom.size == 0) { @@ -1522,6 +1578,7 @@ } case MESSAGE_TELEMETRY_GET_CHILD_USS: { + // In child process, send the requested USS report this.sendContentProcessUSS(message.data.id); break } @@ -1558,6 +1615,15 @@ cpmm.sendAsyncMessage(MESSAGE_TELEMETRY_PAYLOAD, payload); }, + sendContentProcessThreadHangs: function sendContentProcessThreadHangs() { + this._log.trace("sendContentProcessThreadHangs"); + let payload = { + childUUID: this._processUUID, + hangs: Telemetry.threadHangStats, + }; + cpmm.sendAsyncMessage(MESSAGE_TELEMETRY_THREAD_HANGS, payload); + }, + /** * Save both the "saved-session" and the "shutdown" pings to disk. * This needs to be called after TelemetrySend shuts down otherwise pings @@ -1647,6 +1713,50 @@ ppmm.broadcastAsyncMessage(MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD, {}); }, + getChildThreadHangs: function getChildThreadHangs() { + return new Promise((resolve) => { + // Return immediately if there are no child processes to get stats from + if (ppmm.childCount === 0) { + resolve([]); + return; + } + + // Register our promise so it will be resolved when we receive the child thread hang stats on the parent process + // The resolve functions will all be called from "receiveMessage" when a MESSAGE_TELEMETRY_THREAD_HANGS message comes in + this._childThreadHangsResolveFunctions.push((threadHangStats) => { + let hangs = threadHangStats.map(child => child.hangs); + return resolve(hangs); + }); + + // If we (the parent) are not currently in the process of requesting child thread hangs, request them + // If we are, then the resolve function we registered above will receive the results without needing to request them again + if (this._childThreadHangsResolveFunctions.length === 1) { + // We have to cache the number of children we send messages to, in case the child count changes while waiting for messages to arrive + // This handles the case where the child count increases later on, in which case the new processes won't respond since we never sent messages to them + this._childCount = ppmm.childCount; + + this._childThreadHangs = []; // Clear the child hangs + for (let i = 0; i < this._childCount; i++) { + // If a child dies at exactly while we're running this loop, the message sending will fail but we won't get an exception + // In this case, since we won't know this has happened, we will simply rely on the timeout to handle it + ppmm.getChildAt(i).sendAsyncMessage(MESSAGE_TELEMETRY_GET_CHILD_THREAD_HANGS); + } + + // Set up a timeout in case one or more of the content processes never responds + this._childThreadHangsTimeout = setTimeout(() => { + // Resolve all the promises that are waiting on these thread hang stats + // We resolve here instead of rejecting because the purpose of this function is + // to retrieve the BHR stats from all processes that will give us stats + // As a result, one process failing simply means it doesn't get included in the result. + for (let resolve of this._childThreadHangsResolveFunctions) { + resolve(this._childThreadHangs); + } + this._childThreadHangsResolveFunctions = []; + }, 200); + } + }); + }, + gatherStartup: function gatherStartup() { this._log.trace("gatherStartup"); let counters = processInfo.getCounters(); diff -Nru firefox-45.0~b2+build1/toolkit/mozapps/extensions/test/browser/browser-common.ini firefox-45.0~b3+build1/toolkit/mozapps/extensions/test/browser/browser-common.ini --- firefox-45.0~b2+build1/toolkit/mozapps/extensions/test/browser/browser-common.ini 2016-02-02 06:57:41.000000000 +0000 +++ firefox-45.0~b3+build1/toolkit/mozapps/extensions/test/browser/browser-common.ini 2016-02-05 06:54:54.000000000 +0000 @@ -10,6 +10,7 @@ skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly [browser_bug562854.js] [browser_bug562890.js] +skip-if = os == 'win' && !debug # Disabled on Windows opt/PGO builds due to intermittent failures (bug 1135866) [browser_bug562899.js] skip-if = buildapp == 'mulet' [browser_bug562992.js] @@ -59,6 +60,7 @@ [browser_updateid.js] [browser_purchase.js] [browser_openDialog.js] +skip-if = os == 'win' && !debug # Disabled on Windows opt/PGO builds due to intermittent failures (bug 1135866) [browser_types.js] [browser_inlinesettings.js] [browser_inlinesettings_custom.js] diff -Nru firefox-45.0~b2+build1/toolkit/xre/nsAppRunner.cpp firefox-45.0~b3+build1/toolkit/xre/nsAppRunner.cpp --- firefox-45.0~b2+build1/toolkit/xre/nsAppRunner.cpp 2016-02-02 06:57:41.000000000 +0000 +++ firefox-45.0~b3+build1/toolkit/xre/nsAppRunner.cpp 2016-02-05 06:54:55.000000000 +0000 @@ -66,7 +66,6 @@ #include "nsIDOMWindow.h" #include "mozilla/ModuleUtils.h" #include "nsIIOService2.h" -#include "nsILocaleService.h" #include "nsIObserverService.h" #include "nsINativeAppSupport.h" #include "nsIProcess.h" @@ -4672,31 +4671,25 @@ * which currently doesn't work well with e10s. */ bool disabledForBidi = false; - do { // to allow 'break' to abort this block if a call fails - nsresult rv; - nsCOMPtr ls = - do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) - break; - - nsCOMPtr appLocale; - rv = ls->GetApplicationLocale(getter_AddRefs(appLocale)); - if (NS_FAILED(rv)) - break; - nsString localeStr; - rv = appLocale-> - GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr); - if (NS_FAILED(rv)) - break; - - if (localeStr.EqualsLiteral("ar") || - localeStr.EqualsLiteral("fa") || - localeStr.EqualsLiteral("he") || - localeStr.EqualsLiteral("ur")) { - disabledForBidi = true; - } - } while (0); + nsAutoCString locale; + nsCOMPtr registry = + mozilla::services::GetXULChromeRegistryService(); + if (registry) { + registry->GetSelectedLocale(NS_LITERAL_CSTRING("global"), locale); + } + + int32_t index = locale.FindChar('-'); + if (index >= 0) { + locale.Truncate(index); + } + + if (locale.EqualsLiteral("ar") || + locale.EqualsLiteral("fa") || + locale.EqualsLiteral("he") || + locale.EqualsLiteral("ur")) { + disabledForBidi = true; + } bool optInPref = Preferences::GetBool("browser.tabs.remote.autostart", false); bool trialPref = Preferences::GetBool("browser.tabs.remote.autostart.2", false); diff -Nru firefox-45.0~b2+build1/widget/windows/nsClipboard.cpp firefox-45.0~b3+build1/widget/windows/nsClipboard.cpp --- firefox-45.0~b2+build1/widget/windows/nsClipboard.cpp 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/widget/windows/nsClipboard.cpp 2016-02-05 06:54:55.000000000 +0000 @@ -92,8 +92,9 @@ { UINT format; - if (strcmp(aMimeStr, kTextMime) == 0 || - strcmp(aMimeStr, kUnicodeMime) == 0) + if (strcmp(aMimeStr, kTextMime) == 0) + format = CF_TEXT; + else if (strcmp(aMimeStr, kUnicodeMime) == 0) format = CF_UNICODETEXT; else if (strcmp(aMimeStr, kRTFMime) == 0) format = ::RegisterClipboardFormat(L"Rich Text Format"); @@ -179,7 +180,14 @@ // Do various things internal to the implementation, like map one // flavor to another or add additional flavors based on what's required // for the win32 impl. - if ( strcmp(flavorStr, kHTMLMime) == 0 ) { + if ( strcmp(flavorStr, kUnicodeMime) == 0 ) { + // if we find text/unicode, also advertise text/plain (which we will convert + // on our own in nsDataObj::GetText(). + FORMATETC textFE; + SET_FORMATETC(textFE, CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); + dObj->AddDataFlavor(kTextMime, &textFE); + } + else if ( strcmp(flavorStr, kHTMLMime) == 0 ) { // if we find text/html, also advertise win32's html flavor (which we will convert // on our own in nsDataObj::GetText(). FORMATETC htmlFE; @@ -191,10 +199,14 @@ // the "file" flavors so that the win32 shell knows to create an internet // shortcut when it sees one of these beasts. FORMATETC shortcutFE; + SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) + dObj->AddDataFlavor(kURLMime, &shortcutFE); SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(kURLMime, &shortcutFE); SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(kURLMime, &shortcutFE); + SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) + dObj->AddDataFlavor(kURLMime, &shortcutFE); SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(kURLMime, &shortcutFE); } @@ -607,9 +619,11 @@ // when directly asking for the flavor. Let's try digging around in other // flavors to help satisfy our craving for data. if ( !dataFound ) { - if ( strcmp(flavorStr, kURLMime) == 0 ) { + if ( strcmp(flavorStr, kUnicodeMime) == 0 ) + dataFound = FindUnicodeFromPlainText ( aDataObject, anIndex, &data, &dataLen ); + else if ( strcmp(flavorStr, kURLMime) == 0 ) { // drags from other windows apps expose the native - // CFSTR_INETURLW flavor + // CFSTR_INETURL{A,W} flavor dataFound = FindURLFromNativeURL ( aDataObject, anIndex, &data, &dataLen ); if ( !dataFound ) dataFound = FindURLFromLocalFile ( aDataObject, anIndex, &data, &dataLen ); @@ -760,6 +774,39 @@ // +// FindUnicodeFromPlainText +// +// we are looking for text/unicode and we failed to find it on the clipboard first, +// try again with text/plain. If that is present, convert it to unicode. +// +bool +nsClipboard :: FindUnicodeFromPlainText ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) +{ + // we are looking for text/unicode and we failed to find it on the clipboard first, + // try again with text/plain. If that is present, convert it to unicode. + nsresult rv = GetNativeDataOffClipboard(inDataObject, inIndex, GetFormat(kTextMime), nullptr, outData, outDataLen); + if (NS_FAILED(rv) || !*outData) { + return false; + } + + const char* castedText = static_cast(*outData); + nsAutoString tmp; + rv = NS_CopyNativeToUnicode(nsDependentCSubstring(castedText, *outDataLen), tmp); + if (NS_FAILED(rv)) { + return false; + } + + // out with the old, in with the new + free(*outData); + *outData = ToNewUnicode(tmp); + *outDataLen = tmp.Length() * sizeof(char16_t); + + return true; + +} // FindUnicodeFromPlainText + + +// // FindURLFromLocalFile // // we are looking for a URL and couldn't find it, try again with looking for @@ -825,7 +872,7 @@ // // we are looking for a URL and couldn't find it using our internal // URL flavor, so look for it using the native URL flavor, -// CF_INETURLSTRW +// CF_INETURLSTRW (We don't handle CF_INETURLSTRA currently) // bool nsClipboard :: FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) @@ -846,6 +893,29 @@ free(tempOutData); dataFound = true; } + else { + loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, ::RegisterClipboardFormat(CFSTR_INETURLA), nullptr, &tempOutData, &tempDataLen); + if ( NS_SUCCEEDED(loadResult) && tempOutData ) { + // CFSTR_INETURLA is (currently) equal to CFSTR_SHELLURL which is equal to CF_TEXT + // which is by definition ANSI encoded. + nsCString urlUnescapedA; + bool unescaped = NS_UnescapeURL(static_cast(tempOutData), tempDataLen, esc_OnlyNonASCII | esc_SkipControl, urlUnescapedA); + + nsString urlString; + if (unescaped) + NS_CopyNativeToUnicode(urlUnescapedA, urlString); + else + NS_CopyNativeToUnicode(nsDependentCString(static_cast(tempOutData), tempDataLen), urlString); + + // the internal mozilla URL format, text/x-moz-url, contains + // URL\ntitle. Since we don't actually have a title here, + // just repeat the URL to fake it. + *outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + urlString); + *outDataLen = NS_strlen(static_cast(*outData)) * sizeof(char16_t); + free(tempOutData); + dataFound = true; + } + } return dataFound; } // FindURLFromNativeURL @@ -942,6 +1012,16 @@ *_retval = true; break; } + else { + // We haven't found the exact flavor the client asked for, but maybe we can + // still find it from something else that's on the clipboard... + if (strcmp(aFlavorList[i], kUnicodeMime) == 0) { + // client asked for unicode and it wasn't present, check if we have CF_TEXT. + // We'll handle the actual data substitution in the data object. + if (IsClipboardFormatAvailable(GetFormat(kTextMime))) + *_retval = true; + } + } } return NS_OK; diff -Nru firefox-45.0~b2+build1/widget/windows/nsDataObj.cpp firefox-45.0~b3+build1/widget/windows/nsDataObj.cpp --- firefox-45.0~b2+build1/widget/windows/nsDataObj.cpp 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/widget/windows/nsDataObj.cpp 2016-02-05 06:54:55.000000000 +0000 @@ -1290,7 +1290,27 @@ // by the appropriate size to account for the null (one char for CF_TEXT, one char16_t for // CF_UNICODETEXT). DWORD allocLen = (DWORD)len; - if ( aFE.cfFormat == nsClipboard::CF_HTML ) { + if ( aFE.cfFormat == CF_TEXT ) { + // Someone is asking for text/plain; convert the unicode (assuming it's present) + // to text with the correct platform encoding. + size_t bufferSize = sizeof(char)*(len + 2); + char* plainTextData = static_cast(moz_xmalloc(bufferSize)); + char16_t* castedUnicode = reinterpret_cast(data); + int32_t plainTextLen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)castedUnicode, len / 2 + 1, plainTextData, bufferSize, NULL, NULL); + // replace the unicode data with our plaintext data. Recall that |plainTextLen| doesn't include + // the null in the length. + free(data); + if ( plainTextLen ) { + data = plainTextData; + allocLen = plainTextLen; + } + else { + free(plainTextData); + NS_WARNING ( "Oh no, couldn't convert unicode to plain text" ); + return S_OK; + } + } + else if ( aFE.cfFormat == nsClipboard::CF_HTML ) { // Someone is asking for win32's HTML flavor. Convert our html fragment // from unicode to UTF-8 then put it into a format specified by msft. NS_ConvertUTF16toUTF8 converter ( reinterpret_cast(data) ); diff -Nru firefox-45.0~b2+build1/xpcom/threads/nsThread.cpp firefox-45.0~b3+build1/xpcom/threads/nsThread.cpp --- firefox-45.0~b2+build1/xpcom/threads/nsThread.cpp 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/xpcom/threads/nsThread.cpp 2016-02-05 06:54:56.000000000 +0000 @@ -378,6 +378,9 @@ BackgroundChild::CloseForCurrentThread(); #endif // defined(MOZILLA_XPCOMRT_API) + // NB: The main thread does not shut down here! It shuts down via + // nsThreadManager::Shutdown. + // Do NS_ProcessPendingEvents but with special handling to set // mEventsAreDoomed atomically with the removal of the last event. The key // invariant here is that we will never permit PutEvent to succeed if the @@ -386,10 +389,7 @@ // as we have outstanding mRequestedShutdownContexts. while (true) { // Check and see if we're waiting on any threads. - while (self->mRequestedShutdownContexts.Length()) { - // We can't stop accepting events just yet. Block and check again. - NS_ProcessNextEvent(self, true); - } + self->WaitForAllAsynchronousShutdowns(); { MutexAutoLock lock(self->mLock); @@ -753,6 +753,14 @@ aContext->joiningThread->mRequestedShutdownContexts.RemoveElement(aContext)); } +void +nsThread::WaitForAllAsynchronousShutdowns() +{ + while (mRequestedShutdownContexts.Length()) { + NS_ProcessNextEvent(this, true); + } +} + NS_IMETHODIMP nsThread::Shutdown() { diff -Nru firefox-45.0~b2+build1/xpcom/threads/nsThread.h firefox-45.0~b3+build1/xpcom/threads/nsThread.h --- firefox-45.0~b2+build1/xpcom/threads/nsThread.h 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/xpcom/threads/nsThread.h 2016-02-05 06:54:56.000000000 +0000 @@ -79,6 +79,8 @@ void ShutdownComplete(struct nsThreadShutdownContext* aContext); + void WaitForAllAsynchronousShutdowns(); + protected: class nsChainedEventQueue; diff -Nru firefox-45.0~b2+build1/xpcom/threads/nsThreadManager.cpp firefox-45.0~b3+build1/xpcom/threads/nsThreadManager.cpp --- firefox-45.0~b2+build1/xpcom/threads/nsThreadManager.cpp 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/xpcom/threads/nsThreadManager.cpp 2016-02-05 06:54:56.000000000 +0000 @@ -155,6 +155,12 @@ } } + // NB: It's possible that there are events in the queue that want to *start* + // an asynchronous shutdown. But we have already shutdown the threads above, + // so there's no need to worry about them. We only have to wait for all + // in-flight asynchronous thread shutdowns to complete. + mMainThread->WaitForAllAsynchronousShutdowns(); + // In case there are any more events somehow... NS_ProcessPendingEvents(mMainThread); diff -Nru firefox-45.0~b2+build1/xpcom/threads/nsThreadPool.cpp firefox-45.0~b3+build1/xpcom/threads/nsThreadPool.cpp --- firefox-45.0~b2+build1/xpcom/threads/nsThreadPool.cpp 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/xpcom/threads/nsThreadPool.cpp 2016-02-05 06:54:56.000000000 +0000 @@ -122,7 +122,7 @@ if (killThread) { // We never dispatched any events to the thread, so we can shut it down // asynchronously without worrying about anything. - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->AsyncShutdown())); + ShutdownThread(thread); } else { thread->Dispatch(this, NS_DISPATCH_NORMAL); } @@ -135,12 +135,18 @@ { LOG(("THRD-P(%p) shutdown async [%p]\n", this, aThread)); - // This method is responsible for calling Shutdown on |aThread|. This must be - // done from some other thread, so we use the main thread of the application. - - MOZ_ASSERT(!NS_IsMainThread(), "wrong thread"); - - nsCOMPtr r = NS_NewRunnableMethod(aThread, &nsIThread::Shutdown); + // This is either called by a threadpool thread that is out of work, or + // a thread that attempted to create a threadpool thread and raced in + // such a way that the newly created thread is no longer necessary. + // In the first case, we must go to another thread to shut aThread down + // (because it is the current thread). In the second case, we cannot + // synchronously shut down the current thread (because then Dispatch() would + // spin the event loop, and that could blow up the world), and asynchronous + // shutdown requires this thread have an event loop (and it may not, see bug + // 10204784). The simplest way to cover all cases is to asynchronously + // shutdown aThread from the main thread. + nsCOMPtr r = NS_NewRunnableMethod(aThread, + &nsIThread::AsyncShutdown); NS_DispatchToMainThread(r); } diff -Nru firefox-45.0~b2+build1/xpcom/threads/TimerThread.cpp firefox-45.0~b3+build1/xpcom/threads/TimerThread.cpp --- firefox-45.0~b2+build1/xpcom/threads/TimerThread.cpp 2016-02-02 06:57:42.000000000 +0000 +++ firefox-45.0~b3+build1/xpcom/threads/TimerThread.cpp 2016-02-05 06:54:56.000000000 +0000 @@ -127,10 +127,23 @@ } // namespace -class nsTimerEvent : public nsRunnable +// This is a nsICancelableRunnable because we can dispatch it to Workers and +// those can be shut down at any time, and in these cases, Cancel() is called +// instead of Run(). +class nsTimerEvent : public nsCancelableRunnable { public: - NS_IMETHOD Run(); + NS_IMETHOD Run() override; + + NS_IMETHOD Cancel() override + { + // Since nsTimerImpl is not thread-safe, we should release |mTimer| + // here in the target thread to avoid race condition. Otherwise, + // ~nsTimerEvent() which calls nsTimerImpl::Release() could run in the + // timer thread and result in race condition. + mTimer = nullptr; + return NS_OK; + } nsTimerEvent() : mTimer() @@ -253,6 +266,8 @@ NS_IMETHODIMP nsTimerEvent::Run() { + MOZ_ASSERT(mTimer); + if (mGeneration != mTimer->GetGeneration()) { return NS_OK; } @@ -265,13 +280,10 @@ } mTimer->Fire(); - // Since nsTimerImpl is not thread-safe, we should release |mTimer| - // here in the target thread to avoid race condition. Otherwise, - // ~nsTimerEvent() which calls nsTimerImpl::Release() could run in the - // timer thread and result in race condition. - mTimer = nullptr; - return NS_OK; + // We call Cancel() to correctly release mTimer. + // Read more in the Cancel() implementation. + return Cancel(); } nsresult