diff --git a/accessible/src/atk/nsAccessibleWrap.cpp b/accessible/src/atk/nsAccessibleWrap.cpp index 0311f1c0c9d5..fb0b9e6ecec2 100644 --- a/accessible/src/atk/nsAccessibleWrap.cpp +++ b/accessible/src/atk/nsAccessibleWrap.cpp @@ -976,9 +976,11 @@ refRelationSetCB(AtkObject *aAtkObj) while ((tempAcc = rel.Next())) targets.AppendElement(nsAccessibleWrap::GetAtkObject(tempAcc)); - atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType); - atk_relation_set_add(relation_set, atkRelation); - g_object_unref(atkRelation); + if (targets.Length()) { + atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType); + atk_relation_set_add(relation_set, atkRelation); + g_object_unref(atkRelation); + } } return relation_set; diff --git a/browser/base/content/sanitize.js b/browser/base/content/sanitize.js index 0e8f3b73c2f4..54bf72f131c1 100644 --- a/browser/base/content/sanitize.js +++ b/browser/base/content/sanitize.js @@ -156,10 +156,9 @@ Sanitizer.prototype = { } // Clear plugin data. - let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); const phInterface = Ci.nsIPluginHost; const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL; - ph.QueryInterface(phInterface); + let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface); // Determine age range in seconds. (-1 means clear all.) We don't know // that this.range[1] is actually now, so we compute age range based @@ -195,13 +194,13 @@ Sanitizer.prototype = { } catch (e) {} }, - + get canClear() { return true; } }, - + offlineApps: { clear: function () { diff --git a/browser/base/content/syncAddDevice.xul b/browser/base/content/syncAddDevice.xul index 2c4b36369308..0dfc8fd5eba5 100644 --- a/browser/base/content/syncAddDevice.xul +++ b/browser/base/content/syncAddDevice.xul @@ -120,20 +120,20 @@ label=" " onpageshow="gSyncAddDevice.onPageShow();"> - &addDevice.dialog.syncKey.label; + &addDevice.dialog.recoveryKey.label; - - &syncKeyBackup.description; + &recoveryKeyBackup.description; - &existingSyncKey.description; + &existingRecoveryKey.description; &addDevice.showMeHow.label; diff --git a/browser/base/content/syncSetup.xul b/browser/base/content/syncSetup.xul index ba56674df3f2..25191eb55a62 100644 --- a/browser/base/content/syncSetup.xul +++ b/browser/base/content/syncSetup.xul @@ -196,17 +196,17 @@ - - &setup.newSyncKeyPage.description.label; + &setup.newRecoveryKeyPage.description.label; - - &syncKeyBackup.description; + &recoveryKeyBackup.description; @@ -370,7 +370,7 @@ - &existingSyncKey.description; + &existingRecoveryKey.description; &addDevice.showMeHow.label; diff --git a/browser/base/content/syncUtils.js b/browser/base/content/syncUtils.js index 30af40579a4b..99695e4d6db3 100644 --- a/browser/base/content/syncUtils.js +++ b/browser/base/content/syncUtils.js @@ -193,8 +193,8 @@ let gSyncUtils = { * @param elid : ID of the form element containing the passphrase. */ passphraseSave: function(elid) { - let dialogTitle = this.bundle.GetStringFromName("save.synckey.title"); - let defaultSaveName = this.bundle.GetStringFromName("save.default.label"); + let dialogTitle = this.bundle.GetStringFromName("save.recoverykey.title"); + let defaultSaveName = this.bundle.GetStringFromName("save.recoverykey.defaultfilename"); this._preparePPiframe(elid, function(iframe) { let filepicker = Cc["@mozilla.org/filepicker;1"] .createInstance(Ci.nsIFilePicker); @@ -243,7 +243,7 @@ let gSyncUtils = { else if (val1 && val1 == Weave.Service.password) error = "change.password.pwSameAsPassword"; else if (val1 && val1 == Weave.Service.passphrase) - error = "change.password.pwSameAsSyncKey"; + error = "change.password.pwSameAsRecoveryKey"; else if (val1 && val2) { if (val1 == val2 && val1.length >= Weave.MIN_PASS_LENGTH) valid = true; diff --git a/browser/base/content/test/browser_sanitizeDialog.js b/browser/base/content/test/browser_sanitizeDialog.js index 325e6b0a6da8..a1842ab14dd0 100644 --- a/browser/base/content/test/browser_sanitizeDialog.js +++ b/browser/base/content/test/browser_sanitizeDialog.js @@ -56,8 +56,6 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"]. const dm = Cc["@mozilla.org/download-manager;1"]. getService(Ci.nsIDownloadManager); -const bhist = Cc["@mozilla.org/browser/global-history;2"]. - getService(Ci.nsIBrowserHistory); const formhist = Cc["@mozilla.org/satchel/form-history;1"]. getService(Ci.nsIFormHistory2); @@ -583,7 +581,7 @@ WindowHelper.prototype = { try { if (wh.onunload) wh.onunload(); - doNextTest(); + waitForAsyncUpdates(doNextTest); } catch (exc) { win.close(); @@ -698,10 +696,11 @@ function addFormEntryWithMinutesAgo(aMinutesAgo) { */ function addHistoryWithMinutesAgo(aMinutesAgo) { let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/"); - bhist.addPageWithDetails(pURI, - aMinutesAgo + " minutes ago", - now_uSec - (aMinutesAgo * 60 * 1000 * 1000)); - is(bhist.isVisited(pURI), true, + PlacesUtils.bhistory + .addPageWithDetails(pURI, + aMinutesAgo + " minutes ago", + now_uSec - (aMinutesAgo * 60 * 1000 * 1000)); + is(PlacesUtils.bhistory.isVisited(pURI), true, "Sanity check: history visit " + pURI.spec + " should exist after creating it"); return pURI; @@ -711,11 +710,45 @@ function addHistoryWithMinutesAgo(aMinutesAgo) { * Removes all history visits, downloads, and form entries. */ function blankSlate() { - bhist.removeAllPages(); + PlacesUtils.bhistory.removeAllPages(); dm.cleanUp(); formhist.removeAllEntries(); } +/** + * Waits for all pending async statements on the default connection, before + * proceeding with aCallback. + * + * @param aCallback + * Function to be called when done. + * @param aScope + * Scope for the callback. + * @param aArguments + * Arguments array for the callback. + * + * @note The result is achieved by asynchronously executing a query requiring + * a write lock. Since all statements on the same connection are + * serialized, the end of this write operation means that all writes are + * complete. Note that WAL makes so that writers don't block readers, but + * this is a problem only across different connections. + */ +function waitForAsyncUpdates(aCallback, aScope, aArguments) +{ + let scope = aScope || this; + let args = aArguments || []; + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + db.createAsyncStatement("BEGIN EXCLUSIVE").executeAsync(); + db.createAsyncStatement("COMMIT").executeAsync({ + handleResult: function() {}, + handleError: function() {}, + handleCompletion: function(aReason) + { + aCallback.apply(scope, args); + } + }); +} + /** * Ensures that the given pref is the expected value. * @@ -758,7 +791,7 @@ function downloadExists(aID) function doNextTest() { if (gAllTests.length <= gCurrTest) { blankSlate(); - finish(); + waitForAsyncUpdates(finish); } else { let ct = gCurrTest; @@ -810,7 +843,7 @@ function ensureFormEntriesClearedState(aFormEntries, aShouldBeCleared) { function ensureHistoryClearedState(aURIs, aShouldBeCleared) { let niceStr = aShouldBeCleared ? "no longer" : "still"; aURIs.forEach(function (aURI) { - is(bhist.isVisited(aURI), !aShouldBeCleared, + is(PlacesUtils.bhistory.isVisited(aURI), !aShouldBeCleared, "history visit " + aURI.spec + " should " + niceStr + " exist"); }); } @@ -836,5 +869,5 @@ function test() { blankSlate(); waitForExplicitFinish(); // Kick off all the tests in the gAllTests array. - doNextTest(); + waitForAsyncUpdates(doNextTest); } diff --git a/browser/base/content/test/browser_sanitizeDialog_treeView.js b/browser/base/content/test/browser_sanitizeDialog_treeView.js index df566034f84c..f3dc6d7f249a 100644 --- a/browser/base/content/test/browser_sanitizeDialog_treeView.js +++ b/browser/base/content/test/browser_sanitizeDialog_treeView.js @@ -55,8 +55,6 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"]. const dm = Cc["@mozilla.org/download-manager;1"]. getService(Ci.nsIDownloadManager); -const bhist = Cc["@mozilla.org/browser/global-history;2"]. - getService(Ci.nsIBrowserHistory); const formhist = Cc["@mozilla.org/satchel/form-history;1"]. getService(Ci.nsIFormHistory2); @@ -502,10 +500,11 @@ function addFormEntryWithMinutesAgo(aMinutesAgo) { */ function addHistoryWithMinutesAgo(aMinutesAgo) { let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/"); - bhist.addPageWithDetails(pURI, - aMinutesAgo + " minutes ago", - now_uSec - (aMinutesAgo * 60 * 1000 * 1000)); - is(bhist.isVisited(pURI), true, + PlacesUtils.bhistory + .addPageWithDetails(pURI, + aMinutesAgo + " minutes ago", + now_uSec - (aMinutesAgo * 60 * 1000 * 1000)); + is(PlacesUtils.bhistory.isVisited(pURI), true, "Sanity check: history visit " + pURI.spec + " should exist after creating it"); return pURI; @@ -515,11 +514,45 @@ function addHistoryWithMinutesAgo(aMinutesAgo) { * Removes all history visits, downloads, and form entries. */ function blankSlate() { - bhist.removeAllPages(); + PlacesUtils.bhistory.removeAllPages(); dm.cleanUp(); formhist.removeAllEntries(); } +/** + * Waits for all pending async statements on the default connection, before + * proceeding with aCallback. + * + * @param aCallback + * Function to be called when done. + * @param aScope + * Scope for the callback. + * @param aArguments + * Arguments array for the callback. + * + * @note The result is achieved by asynchronously executing a query requiring + * a write lock. Since all statements on the same connection are + * serialized, the end of this write operation means that all writes are + * complete. Note that WAL makes so that writers don't block readers, but + * this is a problem only across different connections. + */ +function waitForAsyncUpdates(aCallback, aScope, aArguments) +{ + let scope = aScope || this; + let args = aArguments || []; + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + db.createAsyncStatement("BEGIN EXCLUSIVE").executeAsync(); + db.createAsyncStatement("COMMIT").executeAsync({ + handleResult: function() {}, + handleError: function() {}, + handleCompletion: function(aReason) + { + aCallback.apply(scope, args); + } + }); +} + /** * Checks to see if the download with the specified ID exists. * @@ -548,7 +581,7 @@ function downloadExists(aID) function doNextTest() { if (gAllTests.length <= gCurrTest) { blankSlate(); - finish(); + waitForAsyncUpdates(finish); } else { let ct = gCurrTest; @@ -600,7 +633,7 @@ function ensureFormEntriesClearedState(aFormEntries, aShouldBeCleared) { function ensureHistoryClearedState(aURIs, aShouldBeCleared) { let niceStr = aShouldBeCleared ? "no longer" : "still"; aURIs.forEach(function (aURI) { - is(bhist.isVisited(aURI), !aShouldBeCleared, + is(PlacesUtils.bhistory.isVisited(aURI), !aShouldBeCleared, "history visit " + aURI.spec + " should " + niceStr + " exist"); }); } @@ -625,7 +658,7 @@ function openWindow(aOnloadCallback) { // ok()/is() do... try { aOnloadCallback(win); - doNextTest(); + waitForAsyncUpdates(doNextTest); } catch (exc) { win.close(); @@ -649,5 +682,5 @@ function test() { blankSlate(); waitForExplicitFinish(); // Kick off all the tests in the gAllTests array. - doNextTest(); + waitForAsyncUpdates(doNextTest); } diff --git a/browser/components/places/tests/browser/browser_bookmarksProperties.js b/browser/components/places/tests/browser/browser_bookmarksProperties.js index f5987f6fdc1f..0a96d23d3291 100644 --- a/browser/components/places/tests/browser/browser_bookmarksProperties.js +++ b/browser/components/places/tests/browser/browser_bookmarksProperties.js @@ -536,7 +536,7 @@ function runNextTest() { gCurrentTest.cleanup(); info("End of test: " + gCurrentTest.desc); gCurrentTest = null; - executeSoon(runNextTest); + waitForAsyncUpdates(runNextTest); return; } diff --git a/browser/components/places/tests/browser/browser_library_infoBox.js b/browser/components/places/tests/browser/browser_library_infoBox.js index 6194169f75cf..259543181359 100644 --- a/browser/components/places/tests/browser/browser_library_infoBox.js +++ b/browser/components/places/tests/browser/browser_library_infoBox.js @@ -146,8 +146,7 @@ gTests.push({ menuNode.containerOpen = false; - bhist.removeAllPages(); - nextTest(); + waitForClearHistory(nextTest); } }); diff --git a/browser/components/places/tests/browser/head.js b/browser/components/places/tests/browser/head.js index d7838594aa7c..3fb34e0e645a 100644 --- a/browser/components/places/tests/browser/head.js +++ b/browser/components/places/tests/browser/head.js @@ -29,6 +29,13 @@ function openLibrary(callback, aLeftPaneRoot) { return library; } +/** + * Waits for completion of a clear history operation, before + * proceeding with aCallback. + * + * @param aCallback + * Function to be called when done. + */ function waitForClearHistory(aCallback) { Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) { Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED); @@ -36,3 +43,37 @@ function waitForClearHistory(aCallback) { }, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false); PlacesUtils.bhistory.removeAllPages(); } + +/** + * Waits for all pending async statements on the default connection, before + * proceeding with aCallback. + * + * @param aCallback + * Function to be called when done. + * @param aScope + * Scope for the callback. + * @param aArguments + * Arguments array for the callback. + * + * @note The result is achieved by asynchronously executing a query requiring + * a write lock. Since all statements on the same connection are + * serialized, the end of this write operation means that all writes are + * complete. Note that WAL makes so that writers don't block readers, but + * this is a problem only across different connections. + */ +function waitForAsyncUpdates(aCallback, aScope, aArguments) +{ + let scope = aScope || this; + let args = aArguments || []; + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + db.createAsyncStatement("BEGIN EXCLUSIVE").executeAsync(); + db.createAsyncStatement("COMMIT").executeAsync({ + handleResult: function() {}, + handleError: function() {}, + handleCompletion: function(aReason) + { + aCallback.apply(scope, args); + } + }); +} diff --git a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js index 484482f24b13..5a5617fe9a80 100644 --- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js +++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js @@ -619,11 +619,9 @@ PrivateBrowsingService.prototype = { } // Plugin data - let (ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost)) { - const phInterface = Ci.nsIPluginHost; - const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL; - ph.QueryInterface(phInterface); - + const phInterface = Ci.nsIPluginHost; + const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL; + let (ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface)) { let tags = ph.getPluginTags(); for (let i = 0; i < tags.length; i++) { try { diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js index f4194ddb72f5..f7d9845a084c 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js @@ -42,34 +42,21 @@ function test() { // initialization let pb = Cc["@mozilla.org/privatebrowsing;1"]. getService(Ci.nsIPrivateBrowsingService); - let bhist = Cc["@mozilla.org/browser/global-history;2"]. - getService(Ci.nsIBrowserHistory); - let histsvc = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService). - QueryInterface(Ci.nsPIPlacesDatabase); let cm = Cc["@mozilla.org/cookiemanager;1"]. getService(Ci.nsICookieManager); waitForExplicitFinish(); const TEST_URL = "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/title.sjs"; - function cleanup() { - // delete all history items - bhist.removeAllPages(); + function waitForCleanup(aCallback) { // delete all cookies cm.removeAll(); + // delete all history items + waitForClearHistory(aCallback); } - cleanup(); let observer = { pass: 1, - onBeginUpdateBatch: function() { - }, - onEndUpdateBatch: function() { - }, - onVisit: function(aURI, aVisitID, aTime, aSessionId, aReferringId, - aTransitionType, _added) { - }, onTitleChanged: function(aURI, aPageTitle) { if (aURI.spec != TEST_URL) return; @@ -80,8 +67,9 @@ function test() { break; case 2: // the second time that the page is loaded is(aPageTitle, "Cookie", "The page should be loaded with a cookie for the second time"); - cleanup(); - gBrowser.selectedTab = gBrowser.addTab(TEST_URL); + waitForCleanup(function () { + gBrowser.selectedTab = gBrowser.addTab(TEST_URL); + }); break; case 3: // before entering the private browsing mode is(aPageTitle, "No Cookie", "The page should be loaded without any cookie again"); @@ -89,37 +77,33 @@ function test() { pb.privateBrowsingEnabled = true; gBrowser.selectedTab = gBrowser.addTab(TEST_URL); executeSoon(function() { - histsvc.removeObserver(observer); + PlacesUtils.history.removeObserver(observer); pb.privateBrowsingEnabled = false; - while (gBrowser.browsers.length > 1) + while (gBrowser.browsers.length > 1) { gBrowser.removeCurrentTab(); - cleanup(); - finish(); + } + waitForCleanup(finish); }); break; default: ok(false, "Unexpected pass: " + (this.pass - 1)); } }, - onBeforeDeleteURI: function(aURI) { - }, - onDeleteURI: function(aURI) { - }, - onClearHistory: function() { - }, - onPageChanged: function(aURI, aWhat, aValue) { - }, - onDeleteVisits: function() { - }, - QueryInterface: function(iid) { - if (iid.equals(Ci.nsINavHistoryObserver) || - iid.equals(Ci.nsISupports)) { - return this; - } - throw Cr.NS_ERROR_NO_INTERFACE; - } - }; - histsvc.addObserver(observer, false); - gBrowser.selectedTab = gBrowser.addTab(TEST_URL); + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onVisit: function () {}, + onBeforeDeleteURI: function () {}, + onDeleteURI: function () {}, + onClearHistory: function () {}, + onPageChanged: function () {}, + onDeleteVisits: function() {}, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]) + }; + PlacesUtils.history.addObserver(observer, false); + + waitForCleanup(function () { + gBrowser.selectedTab = gBrowser.addTab(TEST_URL); + }); } diff --git a/browser/components/privatebrowsing/test/browser/head.js b/browser/components/privatebrowsing/test/browser/head.js index 3ac83cf5156b..ea935fe72679 100644 --- a/browser/components/privatebrowsing/test/browser/head.js +++ b/browser/components/privatebrowsing/test/browser/head.js @@ -9,3 +9,17 @@ registerCleanupFunction(function() { } catch(e) {} }); +/** + * Waits for completion of a clear history operation, before + * proceeding with aCallback. + * + * @param aCallback + * Function to be called when done. + */ +function waitForClearHistory(aCallback) { + Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) { + Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED); + aCallback(); + }, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false); + PlacesUtils.bhistory.removeAllPages(); +} diff --git a/browser/locales/en-US/chrome/browser/syncGenericChange.properties b/browser/locales/en-US/chrome/browser/syncGenericChange.properties index 32310a307a7c..ecd8a1a323a9 100644 --- a/browser/locales/en-US/chrome/browser/syncGenericChange.properties +++ b/browser/locales/en-US/chrome/browser/syncGenericChange.properties @@ -1,25 +1,24 @@ -# LOCALIZATION NOTE (change.password.title): This (and associated change.password/passphrase) are used when the user elects to change their password. +#LOCALIZATION NOTE (change.password.title): This (and associated change.password/passphrase) are used when the user elects to change their password. change.password.title = Change your Password change.password.acceptButton = Change Password change.password.status.active = Changing your password… change.password.status.success = Your password has been changed. change.password.status.error = There was an error changing your password. -change.password2.introText = Your password must be at least 8 characters long. It cannot be the same as either your user name or your Sync Key. +change.password3.introText = Your password must be at least 8 characters long. It cannot be the same as either your user name or your Recovery Key. change.password.warningText = Note: All of your other devices will be unable to connect to your account once you change this password. -change.synckey2.title = My Sync Key -change.synckey.acceptButton = Change Sync Key -change.synckey.label = Changing Sync Key and uploading local data, please wait… -change.synckey2.error = There was an error while changing your Sync Key! -change.synckey2.success = Your Sync Key was successfully changed! +change.recoverykey.title = My Recovery Key +change.recoverykey.acceptButton = Change Recovery Key +change.recoverykey.label = Changing Recovery Key and uploading local data, please wait… +change.recoverykey.error = There was an error while changing your Recovery Key! +change.recoverykey.success = Your Recovery Key was successfully changed! -change.synckey.introText = Firefox Cares About Your Privacy change.synckey.introText2 = To ensure your total privacy, all of your data is encrypted prior to being uploaded. The key to decrypt your data is not uploaded. -# LOCALIZATION NOTE (change.synckey2.warningText) "Sync" should match &syncBrand.shortName.label; from syncBrand.dtd -change.synckey2.warningText = Note: Changing this will erase all data stored on the Sync server and upload new data secured by this Sync Key. Your other devices will not sync until the new Sync Key is entered for that device. +# LOCALIZATION NOTE (change.recoverykey.warningText) "Sync" should match &syncBrand.shortName.label; from syncBrand.dtd +change.recoverykey.warningText = Note: Changing this will erase all data stored on the Sync server and upload new data secured by this Recovery Key. Your other devices will not sync until the new Recovery Key is entered for that device. -new.synckey.label = Your Sync Key +new.recoverykey.label = Your Recovery Key # LOCALIZATION NOTE (new.password.title): This (and associated new.password/passphrase) are used on a second computer when it detects that your password or passphrase has been changed on a different device. new.password.title = Update Password @@ -29,7 +28,6 @@ new.password.confirm = Confirm your new password new.password.acceptButton = Update Password new.password.status.incorrect = Password incorrect, please try again. -new.synckey.title = Update Sync Key -new.synckey2.introText = Your Sync Key was changed using another device, please enter your updated Sync Key. -new.synckey.acceptButton = Update Sync Key -new.synckey.status.incorrect = Sync Key incorrect, please try again. +new.recoverykey.title = Update Recovery Key +new.recoverykey.introText = Your Recovery Key was changed using another device, please enter your updated Recovery Key. +new.recoverykey.acceptButton = Update Recovery Key diff --git a/browser/locales/en-US/chrome/browser/syncSetup.dtd b/browser/locales/en-US/chrome/browser/syncSetup.dtd index 4454fea47db3..d7b37f59ba65 100644 --- a/browser/locales/en-US/chrome/browser/syncSetup.dtd +++ b/browser/locales/en-US/chrome/browser/syncSetup.dtd @@ -19,8 +19,8 @@ - - + + @@ -41,12 +41,12 @@ - - - - + + + + - + @@ -65,12 +65,12 @@ - + - + diff --git a/browser/locales/en-US/chrome/browser/syncSetup.properties b/browser/locales/en-US/chrome/browser/syncSetup.properties index e29b2acdecd5..89b9c510b3a4 100644 --- a/browser/locales/en-US/chrome/browser/syncSetup.properties +++ b/browser/locales/en-US/chrome/browser/syncSetup.properties @@ -29,8 +29,8 @@ historyDaysCount.label = #1 day of history;#1 days of history # #1 is the number of passwords (was %S for a short while, use #1 instead, even if both work) passwordsCount.label = #1 password;#1 passwords -save.synckey.title = Save Sync Key -save.default.label = Firefox Sync Key.html +save.recoverykey.title = Save Recovery Key +save.recoverykey.defaultfilename = Firefox Recovery Key.html newAccount.action.label = Firefox Sync is now set up to automatically sync all of your browser data. newAccount.change.label = You can choose exactly what to sync by selecting Sync Options below. diff --git a/browser/themes/gnomestripe/browser/browser.css b/browser/themes/gnomestripe/browser/browser.css index 2f59976c62c5..366267c60eb9 100644 --- a/browser/themes/gnomestripe/browser/browser.css +++ b/browser/themes/gnomestripe/browser/browser.css @@ -603,18 +603,37 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button { #forward-button { list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar"); + -moz-transition: 250ms ease-out; } -#forward-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled"); -} - #forward-button:-moz-locale-dir(rtl) { list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar"); } -#forward-button[disabled="true"]:-moz-locale-dir(rtl) { + +toolbar:not([mode=icons]) #forward-button[disabled="true"] { + list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled"); +} +toolbar:not([mode=icons]) #forward-button[disabled="true"]:-moz-locale-dir(rtl) { list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled"); } +toolbar[mode=icons] #forward-button[disabled="true"] { + -moz-transform: scale(0); + opacity: 0; + pointer-events: none; +} +toolbar[mode=icons] #forward-button[disabled="true"]:-moz-locale-dir(ltr) { + margin-left: -36px; +} +toolbar[mode=icons] #forward-button[disabled="true"]:-moz-locale-dir(rtl) { + margin-right: -36px; +} +toolbar[mode=icons][iconsize=small] #forward-button[disabled="true"]:-moz-locale-dir(ltr) { + margin-left: -28px; +} +toolbar[mode=icons][iconsize=small] #forward-button[disabled="true"]:-moz-locale-dir(rtl) { + margin-right: -28px; +} + #reload-button { list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar"); } @@ -786,7 +805,7 @@ toolbar[iconsize="small"] #forward-button { .unified-nav-forward[_moz-menuactive] { list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu") !important; } -toolbar[iconsize="small"] #forward-button[disabled="true"] { +toolbar[iconsize="small"]:not([mode=icons]) #forward-button[disabled="true"] { list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu&state=disabled"); } @@ -796,7 +815,7 @@ toolbar[iconsize="small"] #forward-button:-moz-locale-dir(rtl) { .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) { list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu") !important; } -toolbar[iconsize="small"] #forward-button[disabled="true"]:-moz-locale-dir(rtl) { +toolbar[iconsize="small"]:not([mode=icons]) #forward-button[disabled="true"]:-moz-locale-dir(rtl) { list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled"); } diff --git a/browser/themes/pinstripe/browser/browser.css b/browser/themes/pinstripe/browser/browser.css index 1cec29a82095..06b03962ddc0 100644 --- a/browser/themes/pinstripe/browser/browser.css +++ b/browser/themes/pinstripe/browser/browser.css @@ -482,6 +482,7 @@ toolbar[mode="icons"] #forward-button:-moz-locale-dir(rtl):-moz-lwtheme { padding: 4px 5px 5px 3px; margin-bottom: -1px; background: url(chrome://browser/skin/keyhole-circle.png) 0 0 no-repeat; + border-radius: 0; } #navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:-moz-window-inactive:not(:-moz-lwtheme) { diff --git a/browser/themes/pinstripe/browser/keyhole-circle-lion.png b/browser/themes/pinstripe/browser/keyhole-circle-lion.png index f164d498c351..8c4cb3ba212f 100644 Binary files a/browser/themes/pinstripe/browser/keyhole-circle-lion.png and b/browser/themes/pinstripe/browser/keyhole-circle-lion.png differ diff --git a/build/macosx/mozconfig.leopard b/build/macosx/mozconfig.leopard index 78dfb6f4bb42..2756f1d2ebce 100644 --- a/build/macosx/mozconfig.leopard +++ b/build/macosx/mozconfig.leopard @@ -10,4 +10,6 @@ fi CC="$CC -arch i386" CXX="$CXX -arch i386" +# Note, the version (10) is used by libffi's configure. +ac_add_options --target=i386-apple-darwin10 ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk diff --git a/build/macosx/universal/mozconfig.common b/build/macosx/universal/mozconfig.common index c0a123fec238..1b65dc8b80fd 100644 --- a/build/macosx/universal/mozconfig.common +++ b/build/macosx/universal/mozconfig.common @@ -38,10 +38,10 @@ mk_add_options MOZ_UNIFY_BDATE=1 mk_add_options MOZ_POSTFLIGHT_ALL+=build/macosx/universal/flight.mk -DARWIN_VERSION=`uname -r` -ac_add_app_options ppc --target=powerpc-apple-darwin$DARWIN_VERSION -ac_add_app_options i386 --target=i386-apple-darwin$DARWIN_VERSION -ac_add_app_options x86_64 --target=x86_64-apple-darwin$DARWIN_VERSION +# Note, the version (10) is used by libffi's configure. +ac_add_app_options ppc --target=powerpc-apple-darwin10 +ac_add_app_options i386 --target=i386-apple-darwin10 +ac_add_app_options x86_64 --target=x86_64-apple-darwin10 ac_add_app_options ppc --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk ac_add_app_options i386 --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk diff --git a/build/mobile/devicemanagerADB.py b/build/mobile/devicemanagerADB.py index f98fcbd4bc45..7a82b0082d23 100644 --- a/build/mobile/devicemanagerADB.py +++ b/build/mobile/devicemanagerADB.py @@ -2,6 +2,7 @@ import subprocess from devicemanager import DeviceManager, DMError import re import os +import sys class DeviceManagerADB(DeviceManager): @@ -11,6 +12,7 @@ class DeviceManagerADB(DeviceManager): self.retrylimit = retrylimit self.retries = 0 self._sock = None + self.useRunAs = False if packageName == None: if os.getenv('USER'): packageName = 'org.mozilla.fennec_' + os.getenv('USER') @@ -22,14 +24,11 @@ class DeviceManagerADB(DeviceManager): # Initialization code that may fail: Catch exceptions here to allow # successful initialization even if, for example, adb is not installed. try: - root = self.getDeviceRoot() - self.verifyPackage(packageName) - self.tmpDir = root + "/tmp" - if (not self.dirExists(self.tmpDir)): - self.mkDir(self.tmpDir) + self.verifyADB() + self.verifyRunAs(packageName) except: + self.useRunAs = False self.packageName = None - self.tmpDir = None try: # a test to see if we have root privs files = self.listFiles("/data/data") @@ -51,7 +50,7 @@ class DeviceManagerADB(DeviceManager): try: if (os.name == "nt"): destname = destname.replace('\\', '/') - if (self.packageName): + if (self.useRunAs): remoteTmpFile = self.tmpDir + "/" + os.path.basename(localname) self.checkCmd(["push", os.path.realpath(localname), remoteTmpFile]) self.checkCmdAs(["shell", "cp", remoteTmpFile, destname]) @@ -498,7 +497,7 @@ class DeviceManagerADB(DeviceManager): return subprocess.check_call(args) def checkCmdAs(self, args): - if (self.packageName): + if (self.useRunAs): args.insert(1, "run-as") args.insert(2, self.packageName) return self.checkCmd(args) @@ -518,13 +517,44 @@ class DeviceManagerADB(DeviceManager): self.checkCmdAs(["shell", "chmod", "777", remoteDir.strip()]) print "chmod " + remoteDir.strip() - def verifyPackage(self, packageName): - # If a valid package name is specified, it will be used for certain - # file operations, so that pushed files and directories are created - # by the uid associated with the package. - self.packageName = None - if (packageName): - data = self.runCmd(["shell", "run-as", packageName, "pwd"]).stdout.read() - if (not re.search('is unknown', data)): + def verifyADB(self): + # Check to see if adb itself can be executed. + try: + self.runCmd(["version"]) + except Exception as (ex): + print "unable to execute ADB: ensure Android SDK is installed and adb is in your $PATH" + + def isCpAvailable(self): + # Some Android systems may not have a cp command installed, + # or it may not be executable by the user. + data = self.runCmd(["shell", "cp"]).stdout.read() + if (re.search('Usage', data)): + return True + else: + print "unable to execute 'cp' on device; consider installing busybox from Android Market" + return False + + def verifyRunAs(self, packageName): + # If a valid package name is available, and certain other + # conditions are met, devicemanagerADB can execute file operations + # via the "run-as" command, so that pushed files and directories + # are created by the uid associated with the package, more closely + # echoing conditions encountered by Fennec at run time. + # Check to see if run-as can be used here, by verifying a + # file copy via run-as. + self.useRunAs = False + devroot = self.getDeviceRoot() + if (packageName and self.isCpAvailable() and devroot): + self.tmpDir = devroot + "/tmp" + if (not self.dirExists(self.tmpDir)): + self.mkDir(self.tmpDir) + self.checkCmd(["shell", "run-as", packageName, "mkdir", devroot + "/sanity"]) + self.checkCmd(["push", os.path.abspath(sys.argv[0]), self.tmpDir + "/tmpfile"]) + self.checkCmd(["shell", "run-as", packageName, "cp", self.tmpDir + "/tmpfile", devroot + "/sanity"]) + if (self.fileExists(devroot + "/sanity/tmpfile")): + print "will execute commands via run-as " + packageName self.packageName = packageName - print "package set: " + self.packageName + self.useRunAs = True + self.checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"]) + self.checkCmd(["shell", "run-as", packageName, "rm", "-r", devroot + "/sanity"]) + diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 01f88cb12966..d1de275ab429 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -43,7 +43,6 @@ USE_AUTOCONF = 1 MOZILLA_CLIENT = 1 target = @target@ ac_configure_args = @ac_configure_args@ -BUILD_MODULES = @BUILD_MODULES@ MOZILLA_VERSION = @MOZILLA_VERSION@ FIREFOX_VERSION = @FIREFOX_VERSION@ diff --git a/config/nsinstall_win.c b/config/nsinstall_win.c index d9b723b2c7c5..1c1623f82fa0 100644 --- a/config/nsinstall_win.c +++ b/config/nsinstall_win.c @@ -41,6 +41,38 @@ static BOOL sh_DoCopy(wchar_t *srcFileName, DWORD srcFileAttributes, #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) #define STR_LEN(a) (ARRAY_LEN(a) - 1) +#ifdef __MINGW32__ + +/* MingW currently does not implement a wide version of the + startup routines. Workaround is to implement something like + it ourselves. */ + +#include + +int wmain(int argc, WCHAR **argv); + +int main(int argc, char **argv) +{ + int result; + wchar_t *commandLine = GetCommandLineW(); + int argcw = 0; + wchar_t **_argvw = CommandLineToArgvW( commandLine, &argcw ); + wchar_t *argvw[argcw + 1]; + int i; + if (!_argvw) + return 127; + /* CommandLineToArgvW doesn't output the ending NULL so + we have to manually add it on */ + for ( i = 0; i < argcw; i++ ) + argvw[i] = _argvw[i]; + argvw[argcw] = NULL; + + result = wmain(argcw, argvw); + LocalFree(_argvw); + return result; +} +#endif /* __MINGW32__ */ + /* changes all forward slashes in token to backslashes */ void changeForwardSlashesToBackSlashes ( wchar_t *arg ) { diff --git a/config/rules.mk b/config/rules.mk index d2bf49060f8d..59cee5577e46 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1153,8 +1153,9 @@ ifdef HAVE_DTRACE ifndef XP_MACOSX ifdef DTRACE_PROBE_OBJ ifndef DTRACE_LIB_DEPENDENT -$(DTRACE_PROBE_OBJ): - dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) +NON_DTRACE_OBJS := $(filter-out $(DTRACE_PROBE_OBJ),$(OBJS)) +$(DTRACE_PROBE_OBJ): $(NON_DTRACE_OBJS) + dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(NON_DTRACE_OBJS) endif endif endif @@ -1550,9 +1551,6 @@ export:: FORCE @echo; sleep 2; false endif -$(IDL_DIR):: - $(NSINSTALL) -D $@ - # generate .h files from into $(XPIDL_GEN_DIR), then export to $(DIST)/include; # warn against overriding existing .h file. $(XPIDL_GEN_DIR)/.done: @@ -1623,14 +1621,8 @@ endif # XPIDLSRCS -# # General rules for exporting idl files. -# -# WORK-AROUND ONLY, for mozilla/tools/module-deps/bootstrap.pl build. -# Bug to fix idl dependency problems w/o this extra build pass is -# http://bugzilla.mozilla.org/show_bug.cgi?id=145777 -# -$(IDL_DIR):: +$(IDL_DIR): $(NSINSTALL) -D $@ export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS) @@ -2097,7 +2089,6 @@ showhost: @echo "HOST_LIBRARY = $(HOST_LIBRARY)" showbuildmods:: - @echo "Build Modules = $(BUILD_MODULES)" @echo "Module dirs = $(BUILD_MODULE_DIRS)" documentation: diff --git a/configure.in b/configure.in index d4e3c8b2d8e6..93806e05ff0a 100644 --- a/configure.in +++ b/configure.in @@ -970,7 +970,6 @@ if test -n "$_WIN32_MSVC"; then AC_DEFINE(HAVE_IO_H) AC_DEFINE(HAVE_SETBUF) AC_DEFINE(HAVE_ISATTY) - AC_DEFINE(HAVE_STDCALL) fi fi # COMPILE_ENVIRONMENT @@ -2492,6 +2491,8 @@ ia64*-hpux*) if test -n "$GNU_CC"; then CFLAGS="$CFLAGS -mstackrealign" CXXFLAGS="$CXXFLAGS -mstackrealign" + else + AC_DEFINE(HAVE_STDCALL) fi MOZ_CHECK_HEADERS(mmintrin.h) @@ -5185,7 +5186,7 @@ incorrect]) MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS $_QTMOBILITY_CFLAGS" MOZ_QT_LIBS="$MOZ_QT_LIBS $_QTMOBILITY_LIBS" else - AC_CHECK_LIB(QtSensors QtFeedback QtLocation, main, [ + AC_CHECK_LIB(QtSensors, main, [ MOZ_ENABLE_QTMOBILITY=1 MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtMobility" MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtSensors" diff --git a/content/base/public/nsIFrameMessageManager.idl b/content/base/public/nsIFrameMessageManager.idl index 9cbbf16d570e..2977298e31d5 100644 --- a/content/base/public/nsIFrameMessageManager.idl +++ b/content/base/public/nsIFrameMessageManager.idl @@ -125,10 +125,10 @@ interface nsITreeItemFrameMessageManager : nsIFrameMessageManager nsITreeItemFrameMessageManager getChildAt(in unsigned long aIndex); }; -[scriptable, uuid(23e6ef7b-8cc5-4e8b-9391-453440a3b858)] +[scriptable, uuid(9e5c0526-aa4c-49f0-afbb-57f489cd9b59)] interface nsIChromeFrameMessageManager : nsITreeItemFrameMessageManager { - /* + /** * Load a script in the (remote) frame. aURL must be the absolute URL. * data: URLs are also supported. For example data:,dump("foo\n"); * If aAllowDelayedLoad is true, script will be loaded when the @@ -136,5 +136,10 @@ interface nsIChromeFrameMessageManager : nsITreeItemFrameMessageManager * only if the frame is already available. */ void loadFrameScript(in AString aURL, in boolean aAllowDelayedLoad); + + /** + * Removes aURL from the list of scripts which support delayed load. + */ + void removeDelayedFrameScript(in AString aURL); }; diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 9cf806b669cb..501503d20a48 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -6125,7 +6125,7 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) } while ((doc = doc->GetParentDocument())); // Remove from parent. - nsINode* parent = adoptedNode->GetNodeParent(); + nsCOMPtr parent = adoptedNode->GetNodeParent(); if (parent) { rv = parent->RemoveChildAt(parent->IndexOf(adoptedNode), PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index a922b45208b6..9c0e9b57d29d 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -177,6 +177,13 @@ nsFrameMessageManager::LoadFrameScript(const nsAString& aURL, return NS_OK; } +NS_IMETHODIMP +nsFrameMessageManager::RemoveDelayedFrameScript(const nsAString& aURL) +{ + mPendingScripts.RemoveElement(aURL); + return NS_OK; +} + static JSBool JSONCreator(const jschar* aBuf, uint32 aLen, void* aData) { diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 61ef8cd76792..74dc85e9bd35 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -620,7 +620,7 @@ nsINode::Normalize() } // Remove node - nsINode* parent = node->GetNodeParent(); + nsCOMPtr parent = node->GetNodeParent(); NS_ASSERTION(parent || hasRemoveListeners, "Should always have a parent unless " "mutation events messed us up"); @@ -3945,7 +3945,7 @@ nsINode::ReplaceOrInsertBefore(PRBool aReplace, nsINode* aNewChild, } // Remove the new child from the old parent if one exists - nsINode* oldParent = newContent->GetNodeParent(); + nsCOMPtr oldParent = newContent->GetNodeParent(); if (oldParent) { PRInt32 removeIndex = oldParent->IndexOf(newContent); if (removeIndex < 0) { diff --git a/content/base/test/chrome/file_bug549682.xul b/content/base/test/chrome/file_bug549682.xul index bac5b7bfe262..dd33d0643c91 100644 --- a/content/base/test/chrome/file_bug549682.xul +++ b/content/base/test/chrome/file_bug549682.xul @@ -67,6 +67,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549682 global.addMessageListener("sync", globalListener); global.addMessageListener("global-sync", globalListener); global.loadFrameScript("data:,sendSyncMessage('global-sync', { data: 1234 });", true); + var toBeRemovedScript = "data:,sendAsyncMessage('toberemoved', { data: 2345 })"; + var c = 0; + messageManager.addMessageListener("toberemoved", function() { + ++c; + opener.wrappedJSObject.is(c, 1, "Should be called only once!"); + }); + // This loads the script in the existing + messageManager.loadFrameScript(toBeRemovedScript, true); + // But it won't be loaded in the dynamically created + messageManager.removeDelayedFrameScript(toBeRemovedScript); var oldValue = globalListenerCallCount; var b = document.createElement("browser"); diff --git a/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index d51b0e8ba0b3..57e8ab340e51 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -2510,12 +2510,12 @@ nsHTMLInputElement::SanitizeValue(nsAString& aValue) case NS_FORM_INPUT_SEARCH: case NS_FORM_INPUT_TEL: case NS_FORM_INPUT_PASSWORD: - case NS_FORM_INPUT_EMAIL: { PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 }; aValue.StripChars(crlf); } break; + case NS_FORM_INPUT_EMAIL: case NS_FORM_INPUT_URL: { PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 }; diff --git a/content/html/content/test/forms/test_input_email.html b/content/html/content/test/forms/test_input_email.html index 9c33886c1be0..8b2b2fe7bd49 100644 --- a/content/html/content/test/forms/test_input_email.html +++ b/content/html/content/test/forms/test_input_email.html @@ -75,8 +75,12 @@ var email = document.forms[0].elements[0]; var values = [ [ '', true ], // The empty string shouldn't be considered as invalid. [ 'foo@bar.com', true ], - [ ' foo@bar.com', false ], - [ 'foo@bar.com ', false ], + [ ' foo@bar.com', true ], + [ 'foo@bar.com ', true ], + [ '\r\n foo@bar.com', true ], + [ 'foo@bar.com \n\r', true ], + [ '\n\n \r\rfoo@bar.com\n\n \r\r', true ], + [ '\n\r \n\rfoo@bar.com\n\r \n\r', true ], [ 'tulip', false ], // Some checks on the user part of the address. [ '@bar.com', false ], @@ -163,7 +167,7 @@ values.push(["foo@bar.com" + legalCharacters, true]); // Add domain illegal characters. illegalCharacters = "()<>[]:;@\\,!#$%&'*+/=?^_`{|}~ \t"; for each (c in illegalCharacters) { - values.push(['foo@foo.bar' + c, false]); + values.push(['foo@foo.ba' + c + 'r', false]); } values.forEach(function([value, valid]) { diff --git a/content/html/content/test/test_bug549475.html b/content/html/content/test/test_bug549475.html index 6e383cf12ab1..54618c33439e 100644 --- a/content/html/content/test/test_bug549475.html +++ b/content/html/content/test/test_bug549475.html @@ -47,9 +47,9 @@ function sanitizeValue(aType, aValue) case "password": case "search": case "tel": - case "email": return aValue.replace(/[\n\r]/g, ""); case "url": + case "email": return aValue.replace(/[\n\r]/g, "").replace(/^\s+|\s+$/g, ""); case "date": case "month": diff --git a/content/media/test/test_replay_metadata.html b/content/media/test/test_replay_metadata.html index c002e6ba6792..b0c7e0b48e07 100644 --- a/content/media/test/test_replay_metadata.html +++ b/content/media/test/test_replay_metadata.html @@ -32,7 +32,6 @@ function seekStarted(evt) { function seekEnded(evt) { var v = evt.target; v._gotSeekEnded = true; - v.play(); } function loadedData(evt) { diff --git a/content/smil/crashtests/650732-1.svg b/content/smil/crashtests/650732-1.svg new file mode 100644 index 000000000000..95be31c16af5 --- /dev/null +++ b/content/smil/crashtests/650732-1.svg @@ -0,0 +1,46 @@ + + + + + + + + diff --git a/content/smil/crashtests/crashtests.list b/content/smil/crashtests/crashtests.list index 8975b1b37bae..631dfb9403d2 100644 --- a/content/smil/crashtests/crashtests.list +++ b/content/smil/crashtests/crashtests.list @@ -34,6 +34,7 @@ load 608295-1.html load 611927-1.svg load 615002-1.svg load 615872-1.svg +load 650732-1.svg load 665334-1.svg load 669225-1.svg load 670313-1.svg diff --git a/content/smil/nsSMILCSSProperty.cpp b/content/smil/nsSMILCSSProperty.cpp index 2242d9dade7e..dce56c18bb65 100644 --- a/content/smil/nsSMILCSSProperty.cpp +++ b/content/smil/nsSMILCSSProperty.cpp @@ -146,8 +146,14 @@ nsSMILCSSProperty::GetBaseValue() const // (4) Populate our nsSMILValue from the computed style if (didGetComputedVal) { + // When we parse animation values we check if they are context-sensitive or + // not so that we don't cache animation values whose meaning may change. + // For base values however this is unnecessary since on each sample the + // compositor will fetch the (computed) base value and compare it against + // the cached (computed) value and detect changes for us. nsSMILCSSValueType::ValueFromString(mPropID, mElement, - computedStyleVal, baseValue); + computedStyleVal, baseValue, + nsnull); } return baseValue; } @@ -160,22 +166,17 @@ nsSMILCSSProperty::ValueFromString(const nsAString& aStr, { NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); - nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue); - if (aValue.IsNull()) { - return NS_ERROR_FAILURE; + nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue, + &aPreventCachingOfSandwich); + + // XXX Due to bug 536660 (or at least that seems to be the most likely + // culprit), when we have animation setting display:none on a element, + // if we DON'T set the property every sample, chaos ensues. + if (!aPreventCachingOfSandwich && mPropID == eCSSProperty_display) { + aPreventCachingOfSandwich = PR_TRUE; } - // XXXdholbert: For simplicity, just assume that all CSS values have to - // reparsed every sample. This prevents us from doing the "nothing's changed - // so don't recompose" optimization (bug 533291) for CSS properties & mapped - // attributes. If it ends up being expensive to always recompose those, we - // can be a little smarter here. We really only need to set - // aPreventCachingOfSandwich to true for "inherit" & "currentColor" (whose - // values could change at any time), for length-valued types (particularly - // those with em/ex/percent units, since their conversion ratios can change - // at any time), and for any value for 'font-family'. - aPreventCachingOfSandwich = PR_TRUE; - return NS_OK; + return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK; } nsresult diff --git a/content/smil/nsSMILCSSValueType.cpp b/content/smil/nsSMILCSSValueType.cpp index 719e76b7dc3b..85100e844eec 100644 --- a/content/smil/nsSMILCSSValueType.cpp +++ b/content/smil/nsSMILCSSValueType.cpp @@ -371,7 +371,8 @@ ValueFromStringHelper(nsCSSProperty aPropID, Element* aTargetElement, nsPresContext* aPresContext, const nsAString& aString, - nsStyleAnimation::Value& aStyleAnimValue) + nsStyleAnimation::Value& aStyleAnimValue, + PRBool* aIsContextSensitive) { // If value is negative, we'll strip off the "-" so the CSS parser won't // barf, and then manually make the parsed value negative. @@ -386,7 +387,8 @@ ValueFromStringHelper(nsCSSProperty aPropID, } nsDependentSubstring subString(aString, subStringBegin); if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString, - PR_TRUE, aStyleAnimValue)) { + PR_TRUE, aStyleAnimValue, + aIsContextSensitive)) { return PR_FALSE; } if (isNegative) { @@ -409,7 +411,8 @@ void nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID, Element* aTargetElement, const nsAString& aString, - nsSMILValue& aValue) + nsSMILValue& aValue, + PRBool* aIsContextSensitive) { NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed"); nsPresContext* presContext = GetPresContextForElement(aTargetElement); @@ -420,7 +423,7 @@ nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID, nsStyleAnimation::Value parsedValue; if (ValueFromStringHelper(aPropID, aTargetElement, presContext, - aString, parsedValue)) { + aString, parsedValue, aIsContextSensitive)) { sSingleton.Init(aValue); aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext); } diff --git a/content/smil/nsSMILCSSValueType.h b/content/smil/nsSMILCSSValueType.h index 399b6292778c..c5546140ca30 100644 --- a/content/smil/nsSMILCSSValueType.h +++ b/content/smil/nsSMILCSSValueType.h @@ -100,13 +100,20 @@ public: * @param aString The string to be parsed as a CSS value. * @param [out] aValue The nsSMILValue to be populated. Should * initially be null-typed. + * @param [out] aIsContextSensitive Set to PR_TRUE if |aString| may produce + * a different |aValue| depending on other + * CSS properties on |aTargetElement| + * or its ancestors (e.g. 'inherit). + * PR_FALSE otherwise. May be nsnull. + * Not set if the method fails. * @pre aValue.IsNull() * @post aValue.IsNull() || aValue.mType == nsSMILCSSValueType::sSingleton */ static void ValueFromString(nsCSSProperty aPropID, Element* aTargetElement, const nsAString& aString, - nsSMILValue& aValue); + nsSMILValue& aValue, + PRBool* aIsContextSensitive); /** * Creates a string representation of the given nsSMILValue. diff --git a/content/smil/nsSMILMappedAttribute.cpp b/content/smil/nsSMILMappedAttribute.cpp index dc1042b9b2b5..751771749de4 100644 --- a/content/smil/nsSMILMappedAttribute.cpp +++ b/content/smil/nsSMILMappedAttribute.cpp @@ -67,15 +67,9 @@ nsSMILMappedAttribute::ValueFromString(const nsAString& aStr, { NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); - nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue); - if (aValue.IsNull()) { - return NS_ERROR_FAILURE; - } - - // XXXdholbert: For simplicity, just assume that all CSS values have to - // reparsed every sample. See note in nsSMILCSSProperty::ValueFromString. - aPreventCachingOfSandwich = PR_TRUE; - return NS_OK; + nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue, + &aPreventCachingOfSandwich); + return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK; } nsSMILValue @@ -87,8 +81,12 @@ nsSMILMappedAttribute::GetBaseValue() const baseStringValue); nsSMILValue baseValue; if (success) { + // For base values, we don't need to worry whether the value returned is + // context-sensitive or not since the compositor will take care of comparing + // the returned (computed) base value and its cached value and determining + // if an update is required or not. nsSMILCSSValueType::ValueFromString(mPropID, mElement, - baseStringValue, baseValue); + baseStringValue, baseValue, nsnull); } else { // Attribute is unset -- use computed value. // FIRST: Temporarily clear animated value, to make sure it doesn't pollute diff --git a/content/smil/test/test_smilChangeAfterFrozen.xhtml b/content/smil/test/test_smilChangeAfterFrozen.xhtml index 3ae1994898df..7ffc3423a89c 100644 --- a/content/smil/test/test_smilChangeAfterFrozen.xhtml +++ b/content/smil/test/test_smilChangeAfterFrozen.xhtml @@ -8,7 +8,10 @@ Mozilla Bug 533291 - + + @@ -19,68 +22,99 @@ - - - -Mozilla Bug 508206 - - - - - - - - - - - - - - - - -
- - - -Mozilla Bug 508206 - - - - - - - - - - - - - - - - -
- -