diff --git a/accessible/src/atk/nsAccessibleWrap.cpp b/accessible/src/atk/nsAccessibleWrap.cpp index 0311f1c0c9d..fb0b9e6ecec 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 0e8f3b73c2f..54bf72f131c 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 2c4b3636930..0dfc8fd5eba 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 ba56674df3f..25191eb55a6 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 30af40579a4..99695e4d6db 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 325e6b0a6da..a1842ab14dd 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 df566034f84..f3dc6d7f249 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 f5987f6fdc1..0a96d23d329 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 6194169f75c..25954318135 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 d7838594aa7..3fb34e0e645 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 484482f24b1..5a5617fe9a8 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 f4194ddb72f..f7d9845a084 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 3ac83cf5156..ea935fe7267 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 32310a307a7..ecd8a1a323a 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 4454fea47db..d7b37f59ba6 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 e29b2acdecd..89b9c510b3a 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 2f59976c62c..366267c60eb 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 1cec29a8209..06b03962ddc 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 f164d498c35..8c4cb3ba212 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 78dfb6f4bb4..2756f1d2ebc 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 c0a123fec23..1b65dc8b80f 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 f98fcbd4bc4..7a82b0082d2 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 01f88cb1296..d1de275ab42 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 d9b723b2c7c..1c1623f82fa 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 d2bf49060f8..59cee5577e4 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 d4e3c8b2d8e..93806e05ff0 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 9cbbf16d570..2977298e31d 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 9cf806b669c..501503d20a4 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 a922b45208b..9c0e9b57d29 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 61ef8cd7679..74dc85e9bd3 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 bac5b7bfe26..dd33d0643c9 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 d51b0e8ba0b..57e8ab340e5 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 9c33886c1be..8b2b2fe7bd4 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 6e383cf12ab..54618c33439 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 c002e6ba679..b0c7e0b48e0 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 00000000000..95be31c16af --- /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 8975b1b37ba..631dfb9403d 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 2242d9dade7..dce56c18bb6 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 719e76b7dc3..85100e844ee 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 399b6292778..c5546140ca3 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 dc1042b9b2b..751771749de 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 3ae1994898d..7ffc3423a89 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 - - - - - - - - - - - - - - - - -
- -