From 3aed3e9b9ce201237b78f6cdb4f027c77ab16f2b Mon Sep 17 00:00:00 2001 From: Patrick Brosset Date: Tue, 27 Aug 2013 13:34:17 +0200 Subject: [PATCH 1/8] Bug 902966 - Pressing escape while editing a style property should undo current changes; r=mratcliffe --- browser/devtools/shared/inplace-editor.js | 2 - browser/devtools/styleinspector/rule-view.js | 8 +- .../devtools/styleinspector/test/Makefile.in | 2 + ...alue_completion_new_property_value_pair.js | 2 +- ...ruleview_bug_902966_revert_value_on_ESC.js | 91 +++++++++++++++++++ .../test/browser_ruleview_livepreview.js | 90 ++++++++++++++++++ 6 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 browser/devtools/styleinspector/test/browser_ruleview_bug_902966_revert_value_on_ESC.js create mode 100644 browser/devtools/styleinspector/test/browser_ruleview_livepreview.js diff --git a/browser/devtools/shared/inplace-editor.js b/browser/devtools/shared/inplace-editor.js index a34ec0cc064..88c46b5e8fd 100644 --- a/browser/devtools/shared/inplace-editor.js +++ b/browser/devtools/shared/inplace-editor.js @@ -794,7 +794,6 @@ InplaceEditor.prototype = { let direction = FOCUS_FORWARD; if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB && aEvent.shiftKey) { - this.cancelled = true; direction = FOCUS_BACKWARD; } if (this.stopOnReturn && aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) { @@ -858,7 +857,6 @@ InplaceEditor.prototype = { // Validate the entered value. this.warning.hidden = this.validate(this.input.value); this._applied = false; - this._onBlur(null, true); }, /** diff --git a/browser/devtools/styleinspector/rule-view.js b/browser/devtools/styleinspector/rule-view.js index ca429a78683..7f3d7fec492 100644 --- a/browser/devtools/styleinspector/rule-view.js +++ b/browser/devtools/styleinspector/rule-view.js @@ -1449,8 +1449,9 @@ RuleEditor.prototype = { */ function TextPropertyEditor(aRuleEditor, aProperty) { - this.doc = aRuleEditor.doc; - this.popup = aRuleEditor.ruleView.popup; + this.ruleEditor = aRuleEditor; + this.doc = this.ruleEditor.doc; + this.popup = this.ruleEditor.ruleView.popup; this.prop = aProperty; this.prop.editor = this; this.browserWindow = this.doc.defaultView.top; @@ -1849,6 +1850,7 @@ TextPropertyEditor.prototype = { let name = this.prop.name; let value = typeof aValue == "undefined" ? this.prop.value : aValue; let val = this._parseValue(value); + let style = this.doc.createElementNS(HTML_NS, "div").style; let prefs = Services.prefs; @@ -1858,6 +1860,8 @@ TextPropertyEditor.prototype = { try { style.setProperty(name, val.value, val.priority); + // Live previewing the change without committing yet just yet, that'll be done in _onValueDone + this.ruleEditor.rule.setPropertyValue(this.prop, val.value, val.priority); } finally { prefs.setBoolPref("layout.css.report_errors", prefVal); } diff --git a/browser/devtools/styleinspector/test/Makefile.in b/browser/devtools/styleinspector/test/Makefile.in index 2a6ed7bb841..2db33c1792c 100644 --- a/browser/devtools/styleinspector/test/Makefile.in +++ b/browser/devtools/styleinspector/test/Makefile.in @@ -29,6 +29,7 @@ MOCHITEST_BROWSER_FILES = \ browser_ruleview_override.js \ browser_ruleview_ui.js \ browser_ruleview_update.js \ + browser_ruleview_livepreview.js \ browser_bug705707_is_content_stylesheet.js \ browser_bug722196_property_view_media_queries.js \ browser_bug722196_rule_view_media_queries.js \ @@ -41,6 +42,7 @@ MOCHITEST_BROWSER_FILES = \ browser_bug893965_css_property_completion_existing_property.js \ browser_bug894376_css_value_completion_new_property_value_pair.js \ browser_bug894376_css_value_completion_existing_property_value_pair.js \ + browser_ruleview_bug_902966_revert_value_on_ESC.js \ head.js \ $(NULL) diff --git a/browser/devtools/styleinspector/test/browser_bug894376_css_value_completion_new_property_value_pair.js b/browser/devtools/styleinspector/test/browser_bug894376_css_value_completion_new_property_value_pair.js index a37aba320cb..f3587187375 100644 --- a/browser/devtools/styleinspector/test/browser_bug894376_css_value_completion_new_property_value_pair.js +++ b/browser/devtools/styleinspector/test/browser_bug894376_css_value_completion_new_property_value_pair.js @@ -29,7 +29,7 @@ let testData = [ ["VK_BACK_SPACE", {}, "", -1, 0], ["c", {}, "caption-side", 0, 10], ["o", {}, "color", 0, 6], - ["VK_TAB", {}, "n", -1, 0], + ["VK_TAB", {}, "none", -1, 0], ["r", {}, "red", 0, 5], ["VK_DOWN", {}, "rgb", 1, 5], ["VK_DOWN", {}, "rgba", 2, 5], diff --git a/browser/devtools/styleinspector/test/browser_ruleview_bug_902966_revert_value_on_ESC.js b/browser/devtools/styleinspector/test/browser_ruleview_bug_902966_revert_value_on_ESC.js new file mode 100644 index 00000000000..bf36cc1af54 --- /dev/null +++ b/browser/devtools/styleinspector/test/browser_ruleview_bug_902966_revert_value_on_ESC.js @@ -0,0 +1,91 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test original value is correctly displayed when ESCaping out of the +// inplace editor in the style inspector. + +let doc; +let ruleWindow; +let ruleView; +let inspector; +let originalValue = "blue"; + +// Test data format +// { +// value: what char sequence to type, +// commitKey: what key to type to "commit" the change, +// modifiers: commitKey modifiers, +// expected: what value is expected as a result +// } +let testData = [ + {value: "red", commitKey: "VK_ESCAPE", modifiers: {}, expected: originalValue}, + {value: "red", commitKey: "VK_RETURN", modifiers: {}, expected: "red"}, + {value: "blue", commitKey: "VK_TAB", modifiers: {shiftKey: true}, expected: "blue"} +]; + +function startTests() +{ + let style = '' + + '#testid {' + + ' color: ' + originalValue + ';' + + '}'; + + let styleNode = addStyle(doc, style); + doc.body.innerHTML = '
Styled Node
'; + let testElement = doc.getElementById("testid"); + + openRuleView((aInspector, aRuleView) => { + inspector = aInspector; + ruleView = aRuleView; + ruleWindow = aRuleView.doc.defaultView; + inspector.selection.setNode(testElement); + inspector.once("inspector-updated", () => runTestData(0)); + }); +} + +function runTestData(index) +{ + if (index === testData.length) { + finishTest(); + return; + } + + let idRuleEditor = ruleView.element.children[1]._ruleEditor; + let propEditor = idRuleEditor.rule.textProps[0].editor; + waitForEditorFocus(propEditor.element, function(aEditor) { + is(inplaceEditor(propEditor.valueSpan), aEditor, "Focused editor should be the value."); + + for (let ch of testData[index].value) { + EventUtils.sendChar(ch, ruleWindow); + } + EventUtils.synthesizeKey(testData[index].commitKey, testData[index].modifiers); + + is(propEditor.valueSpan.innerHTML, testData[index].expected); + + runTestData(index + 1); + }); + + EventUtils.synthesizeMouse(propEditor.valueSpan, 1, 1, {}, ruleWindow); +} + +function finishTest() +{ + inspector = ruleWindow = ruleView = null; + doc = null; + gBrowser.removeCurrentTab(); + finish(); +} + +function test() +{ + waitForExplicitFinish(); + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.selectedBrowser.addEventListener("load", function escapePropertyChange_load(evt) { + gBrowser.selectedBrowser.removeEventListener(evt.type, escapePropertyChange_load, true); + doc = content.document; + waitForFocus(startTests, content); + }, true); + + content.location = "data:text/html,test escaping property change reverts back to original value"; +} diff --git a/browser/devtools/styleinspector/test/browser_ruleview_livepreview.js b/browser/devtools/styleinspector/test/browser_ruleview_livepreview.js new file mode 100644 index 00000000000..b9729c17855 --- /dev/null +++ b/browser/devtools/styleinspector/test/browser_ruleview_livepreview.js @@ -0,0 +1,90 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that changes are previewed when editing a property value + +let doc; +let testElement; +let ruleWindow; +let ruleView; +let inspector; + +// Format +// { +// value : what to type in the field +// expected : expected computed style on the targeted element +// } +let testData = [ + {value: "inline", expected: "inline"}, + {value: "something", expected: "inline"} +]; + +function startTest() +{ + let style = '#testid {display:block;}'; + + let styleNode = addStyle(doc, style); + doc.body.innerHTML = '
Styled Node
inline element'; + testElement = doc.getElementById("testid"); + + openRuleView((aInspector, aRuleView) => { + inspector = aInspector; + ruleView = aRuleView; + ruleWindow = aRuleView.doc.defaultView; + inspector.selection.setNode(testElement); + inspector.once("inspector-updated", () => loopTestData(0)); + }); +} + +function loopTestData(index) +{ + if(index === testData.length) { + finishTest(); + return; + } + + let idRuleEditor = ruleView.element.children[1]._ruleEditor; + let propEditor = idRuleEditor.rule.textProps[0].editor; + waitForEditorFocus(propEditor.element, function(aEditor) { + is(inplaceEditor(propEditor.valueSpan), aEditor, "Focused editor should be the value."); + + // Entering a correct value for the property + for (let ch of testData[index].value) { + EventUtils.sendChar(ch, ruleWindow); + } + + // While the editor is still focused in, the display should have changed already + executeSoon(() => { + is(content.getComputedStyle(testElement).display, + testData[index].expected, + "Element should be previewed as " + testData[index].expected); + + EventUtils.synthesizeKey("VK_RETURN", {}); + loopTestData(index + 1); + }); + }); + + EventUtils.synthesizeMouse(propEditor.valueSpan, 1, 1, {}, ruleWindow); +} + +function finishTest() +{ + inspector = ruleWindow = ruleView = null; + doc = null; + gBrowser.removeCurrentTab(); + finish(); +} + +function test() +{ + waitForExplicitFinish(); + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.selectedBrowser.addEventListener("load", function changedValues_load(evt) { + gBrowser.selectedBrowser.removeEventListener(evt.type, changedValues_load, true); + doc = content.document; + waitForFocus(startTest, content); + }, true); + + content.location = "data:text/html,test rule view live preview on user changes"; +} From cdea73e9688cb3bb00d792738529c0987edb2340 Mon Sep 17 00:00:00 2001 From: Avinash Kundaliya Date: Tue, 27 Aug 2013 13:39:44 +0200 Subject: [PATCH 2/8] Bug 889944 - Add "Open in New Tab" context menu item on resources; r=harth --- .../devtools/netmonitor/netmonitor-view.js | 11 +++++ browser/devtools/netmonitor/netmonitor.xul | 4 ++ browser/devtools/netmonitor/test/Makefile.in | 1 + .../test/browser_net_open_request_in_tab.js | 40 +++++++++++++++++++ .../chrome/browser/devtools/netmonitor.dtd | 10 +++++ 5 files changed, 66 insertions(+) create mode 100644 browser/devtools/netmonitor/test/browser_net_open_request_in_tab.js diff --git a/browser/devtools/netmonitor/netmonitor-view.js b/browser/devtools/netmonitor/netmonitor-view.js index 3e3761d9fd5..9c81c3bddaa 100644 --- a/browser/devtools/netmonitor/netmonitor-view.js +++ b/browser/devtools/netmonitor/netmonitor-view.js @@ -362,6 +362,17 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, { this.selectedItem = newItem; }, + /** + * Opens selected item in a new tab. + */ + openRequestInTab: function() { + let win = Services.wm.getMostRecentWindow("navigator:browser"); + + let selected = this.selectedItem.attachment; + + win.openUILinkIn(selected.url, "tab", { relatedToCurrent: true }); + }, + /** * Copy the request url from the currently selected item. */ diff --git a/browser/devtools/netmonitor/netmonitor.xul b/browser/devtools/netmonitor/netmonitor.xul index 5052b5fac2c..2f93f40fd3d 100644 --- a/browser/devtools/netmonitor/netmonitor.xul +++ b/browser/devtools/netmonitor/netmonitor.xul @@ -20,6 +20,10 @@ + { + info("Starting test..."); + + let { NetMonitorView } = aMonitor.panelWin; + let { RequestsMenu } = NetMonitorView; + + RequestsMenu.lazyUpdate = false; + + waitForNetworkEvents(aMonitor, 1).then(() => { + let requestItem = RequestsMenu.getItemAtIndex(0); + RequestsMenu.selectedItem = requestItem; + + gBrowser.tabContainer.addEventListener("TabOpen",function onOpen(event){ + ok(true, "A new tab has been opened "); + gBrowser.tabContainer.removeEventListener("TabOpen", onOpen, false); + cleanUp(); + }, false); + + RequestsMenu.openRequestInTab(); + }); + + aDebuggee.performRequests(1); + function cleanUp(){ + teardown(aMonitor).then(() => { + gBrowser.removeCurrentTab(); + finish(); + }); + } + }); +} diff --git a/browser/locales/en-US/chrome/browser/devtools/netmonitor.dtd b/browser/locales/en-US/chrome/browser/devtools/netmonitor.dtd index a265947962a..9d8d12abfc7 100644 --- a/browser/locales/en-US/chrome/browser/devtools/netmonitor.dtd +++ b/browser/locales/en-US/chrome/browser/devtools/netmonitor.dtd @@ -186,6 +186,16 @@ - for the "Edit and Resend" menu item displayed in the context menu for a request --> + + + + + + From 8aed309d710aeee014004b1ba701ec952ab4d8b5 Mon Sep 17 00:00:00 2001 From: Ben Brittain Date: Mon, 26 Aug 2013 14:54:55 -0400 Subject: [PATCH 3/8] Bug 874670 - Telemetry for call duration. r=derf --- .../src/peerconnection/PeerConnectionImpl.cpp | 20 +++++++++++++++++++ .../src/peerconnection/PeerConnectionImpl.h | 11 ++++++++++ toolkit/components/telemetry/Histograms.json | 6 ++++++ 3 files changed, 37 insertions(+) diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index e0e079999dd..dfaad58935d 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -36,6 +36,8 @@ #include "nsDOMDataChannelDeclarations.h" #ifdef MOZILLA_INTERNAL_API +#include "mozilla/TimeStamp.h" +#include "mozilla/Telemetry.h" #include "nsDOMJSUtils.h" #include "nsIDocument.h" #include "nsIScriptError.h" @@ -245,6 +247,9 @@ public: // providing non-fatal warnings. mPC->ClearSdpParseErrorMessages(); mObserver->OnSetRemoteDescriptionSuccess(); +#ifdef MOZILLA_INTERNAL_API + mPC->setStartTime(); +#endif break; case SETLOCALDESCERROR: @@ -1326,6 +1331,14 @@ PeerConnectionImpl::ShutdownMedia() if (!mMedia) return; +#ifdef MOZILLA_INTERNAL_API + // End of call to be recorded in Telemetry + if (!mStartTime.IsNull()){ + mozilla::TimeDuration timeDelta = mozilla::TimeStamp::Now() - mStartTime; + Telemetry::Accumulate(Telemetry::WEBRTC_CALL_DURATION, timeDelta.ToSeconds()); + } +#endif + // Forget the reference so that we can transfer it to // SelfDestruct(). mMedia.forget().get()->SelfDestruct(); @@ -1543,6 +1556,13 @@ PeerConnectionImpl::GetSdpParseErrors() { return mSDPParseErrorMessages; } +#ifdef MOZILLA_INTERNAL_API +//Telemetry set start time +void +PeerConnectionImpl::setStartTime() { + mStartTime = mozilla::TimeStamp::Now(); +} +#endif #ifdef MOZILLA_INTERNAL_API static nsresult diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index 49a6f5aea44..d2126cda118 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -29,6 +29,7 @@ #include "PeerConnectionMedia.h" #ifdef MOZILLA_INTERNAL_API +#include "mozilla/TimeStamp.h" #include "mozilla/net/DataChannel.h" #include "VideoUtils.h" #include "VideoSegment.h" @@ -281,6 +282,11 @@ public: // Sets the RTC Signaling State void SetSignalingState_m(SignalingState aSignalingState); +#ifdef MOZILLA_INTERNAL_API + // Set start time for Telemetry + void setStartTime(); +#endif + private: PeerConnectionImpl(const PeerConnectionImpl&rhs); PeerConnectionImpl& operator=(PeerConnectionImpl); @@ -366,6 +372,11 @@ private: nsRefPtr mMedia; +#ifdef MOZILLA_INTERNAL_API + // Start time of call used for Telemetry + mozilla::TimeStamp mStartTime; +#endif + // Temporary: used to prevent multiple audio streams or multiple video streams // in a single PC. This is tied up in the IETF discussion around proper // representation of multiple streams in SDP, and strongly related to diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 420d1f05c7e..3d231cede6a 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -3502,6 +3502,12 @@ "kind": "boolean", "description": "The number of failed ICE Connections (0) vs. number of successful ICE connections (1)." }, + "WEBRTC_CALL_DURATION":{ + "kind": "exponential", + "high": "10000", + "n_buckets": "1000", + "description": "The length of time (in seconds) that a call lasted." + }, "DEVTOOLS_DEBUGGER_RDP_LOCAL_TRACERDETACH_MS": { "kind": "exponential", "high": "10000", From f8ac457a4be8e7e1d0e128958ceca91f6126763c Mon Sep 17 00:00:00 2001 From: Marco Castelluccio Date: Tue, 27 Aug 2013 08:50:22 -0400 Subject: [PATCH 4/8] Bug 838210 - Don't use file.exists() when not necessary (mobile). r=bnicholson, r=mfinkle --- .../android/chrome/content/aboutDownloads.js | 37 +++++----- mobile/android/chrome/content/browser.js | 50 ++++---------- mobile/android/chrome/content/downloads.js | 6 +- .../android/components/AddonUpdateService.js | 18 ++--- mobile/android/components/HelperAppDialog.js | 5 +- mobile/android/components/SessionStore.js | 69 ++++++------------- 6 files changed, 62 insertions(+), 123 deletions(-) diff --git a/mobile/android/chrome/content/aboutDownloads.js b/mobile/android/chrome/content/aboutDownloads.js index 11b2282183f..95fbdb2b237 100644 --- a/mobile/android/chrome/content/aboutDownloads.js +++ b/mobile/android/chrome/content/aboutDownloads.js @@ -10,6 +10,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/PluralForm.jsm"); Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); + let gStrings = Services.strings.createBundle("chrome://browser/locale/aboutDownloads.properties"); let downloadTemplate = @@ -460,20 +462,15 @@ let Downloads = { removeDownload: function dl_removeDownload(aItem) { this._getDownloadForElement(aItem, function(aDownload) { - let f = null; - try { - f = aDownload.targetFile; - } catch (ex) { - // even if there is no file, pretend that there is so that we can remove - // it from the list - f = { leafName: "" }; + if (aDownload.targetFile) { + OS.File.remove(aDownload.targetFile.path).then(null, function onError(reason) { + if (!(reason instanceof OS.File.Error && reason.becauseNoSuchFile)) { + this.logError("removeDownload() " + reason, aDownload); + } + }.bind(this)); } + aDownload.remove(); - try { - if (f) f.remove(false); - } catch (ex) { - this.logError("removeDownload() " + ex, aDownload); - } }.bind(this)); }, @@ -531,17 +528,15 @@ let Downloads = { cancelDownload: function dl_cancelDownload(aItem) { this._getDownloadForElement(aItem, function(aDownload) { - try { - aDownload.cancel(); - let f = aDownload.targetFile; + OS.File.remove(aDownload.targetFile.path).then(null, function onError(reason) { + if (!(reason instanceof OS.File.Error && reason.becauseNoSuchFile)) { + this.logError("cancelDownload() " + reason, aDownload); + } + }.bind(this)); - if (f.exists()) - f.remove(false); + aDownload.cancel(); - this._updateDownloadRow(aItem, aDownload); - } catch (ex) { - this.logError("cancelDownload() " + ex, aDownload); - } + this._updateDownloadRow(aItem, aDownload); }.bind(this)); }, diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index bc832568ee3..5ea6241965c 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -35,8 +35,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "UserAgentOverrides", XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent", "resource://gre/modules/LoginManagerContent.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", - "resource://gre/modules/NetUtil.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); #ifdef MOZ_SAFE_BROWSING XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing", @@ -6907,18 +6907,9 @@ var WebappsUI = { _writeData: function(aFile, aPrefs) { if (aPrefs.length > 0) { - let data = JSON.stringify(aPrefs); - - let ostream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); - ostream.init(aFile, -1, -1, 0); - - let istream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream); - istream.setData(data, data.length); - - NetUtil.asyncCopy(istream, ostream, function(aResult) { - if (!Components.isSuccessCode(aResult)) { - console.log("Error writing default prefs: " + aResult); - } + let array = new TextEncoder().encode(JSON.stringify(aPrefs)); + OS.File.writeAtomic(aFile.path, array, { tmpPath: aFile.path + ".tmp" }).then(null, function onError(reason) { + console.log("Error writing default prefs: " + reason); }); } }, @@ -7738,16 +7729,9 @@ var Distribution = { return; } - // Save the data for the later sessions - let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); - ostream.init(this._file, 0x02 | 0x08 | 0x20, parseInt("600", 8), ostream.DEFER_OPEN); - - let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - // Asynchronously copy the data to the file. - let istream = converter.convertToInputStream(aData); - NetUtil.asyncCopy(istream, ostream, function(rc) { }); + let array = new TextEncoder().encode(aData); + OS.File.writeAtomic(this._file.path, array, { tmpPath: this._file.path + ".tmp" }); break; } } @@ -7837,25 +7821,19 @@ var Distribution = { // aFile is an nsIFile // aCallback takes the parsed JSON object as a parameter readJSON: function dc_readJSON(aFile, aCallback) { - if (!aFile.exists()) - return; - - let channel = NetUtil.newChannel(aFile); - channel.contentType = "application/json"; - NetUtil.asyncFetch(channel, function(aStream, aResult) { - if (!Components.isSuccessCode(aResult)) { - Cu.reportError("Distribution: Could not read from " + aFile.leafName + " file"); - return; - } - - let raw = NetUtil.readInputStreamToString(aStream, aStream.available(), { charset : "UTF-8" }) || ""; - aStream.close(); + Task.spawn(function() { + let bytes = yield OS.File.read(aFile.path); + let raw = new TextDecoder().decode(bytes) || ""; try { aCallback(JSON.parse(raw)); } catch (e) { Cu.reportError("Distribution: Could not parse JSON: " + e); } + }).then(null, function onError(reason) { + if (!(reason instanceof OS.File.Error && reason.becauseNoSuchFile)) { + Cu.reportError("Distribution: Could not read from " + aFile.leafName + " file"); + } }); } }; diff --git a/mobile/android/chrome/content/downloads.js b/mobile/android/chrome/content/downloads.js index 069ab293941..39daa62d061 100644 --- a/mobile/android/chrome/content/downloads.js +++ b/mobile/android/chrome/content/downloads.js @@ -11,6 +11,8 @@ function dump(a) { const URI_GENERIC_ICON_DOWNLOAD = "drawable://alert_download"; +XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); + var Downloads = { _initialized: false, _dlmgr: null, @@ -54,8 +56,8 @@ var Downloads = { let fileURI = aDownload.target.spec; let f = this._getLocalFile(fileURI); - if (f.exists()) - f.remove(false); + + OS.File.remove(f.path); }, showAlert: function dl_showAlert(aDownload, aMessage, aTitle, aIcon) { diff --git a/mobile/android/components/AddonUpdateService.js b/mobile/android/components/AddonUpdateService.js index 57ffc706a51..eef1dc18375 100644 --- a/mobile/android/components/AddonUpdateService.js +++ b/mobile/android/components/AddonUpdateService.js @@ -15,8 +15,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository", "resource://gre/modules/AddonRepository.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", - "resource://gre/modules/NetUtil.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); function getPref(func, preference, defaultValue) { try { @@ -130,19 +129,10 @@ var RecommendedSearchResults = { if (!aData) return; - // Initialize the file output stream. - let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); - ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN); - - // Obtain a converter to convert our data to a UTF-8 encoded input stream. - let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - // Asynchronously copy the data to the file. - let istream = converter.convertToInputStream(aData); - NetUtil.asyncCopy(istream, ostream, function(rc) { - if (Components.isSuccessCode(rc)) - Services.obs.notifyObservers(null, "recommended-addons-cache-updated", ""); + let array = new TextEncoder().encode(aData); + OS.File.writeAtomic(aFile.path, array, { tmpPath: aFile.path + ".tmp" }).then(function onSuccess() { + Services.obs.notifyObservers(null, "recommended-addons-cache-updated", ""); }); }, diff --git a/mobile/android/components/HelperAppDialog.js b/mobile/android/components/HelperAppDialog.js index cfc3d74d40b..767bcafab61 100644 --- a/mobile/android/components/HelperAppDialog.js +++ b/mobile/android/components/HelperAppDialog.js @@ -133,10 +133,9 @@ HelperAppLauncherDialog.prototype = { // Remove the file so that it's not there when we ensure non-existence later; // this is safe because for the file to exist, the user would have had to // confirm that he wanted the file overwritten. - if (file.exists()) - file.remove(false); + file.remove(false); } - catch (e) { } + catch (e) {} var newDir = file.parent.QueryInterface(Ci.nsILocalFile); prefs.setComplexValue("browser.download.lastDir", Ci.nsILocalFile, newDir); file = this.validateLeafName(newDir, file.leafName, null); diff --git a/mobile/android/components/SessionStore.js b/mobile/android/components/SessionStore.js index b80bf8214da..2a313bebc3f 100644 --- a/mobile/android/components/SessionStore.js +++ b/mobile/android/components/SessionStore.js @@ -15,8 +15,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", "@mozilla.org/xre/app-info;1", "nsICrashReporter"); #endif -XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", - "resource://gre/modules/NetUtil.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); function dump(a) { Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(a); @@ -66,17 +66,8 @@ SessionStore.prototype = { }, _clearDisk: function ss_clearDisk() { - if (this._sessionFile.exists()) { - try { - this._sessionFile.remove(false); - } catch (ex) { dump(ex + '\n'); } // couldn't remove the file - what now? - } - if (this._sessionFileBackup.exists()) { - try { - this._sessionFileBackup.remove(false); - } catch (ex) { dump(ex + '\n'); } // couldn't remove the file - what now? - } - + OS.File.remove(this._sessionFile.path); + OS.File.remove(this._sessionFileBackup.path); }, _sendMessageToJava: function (aMsg) { @@ -155,8 +146,11 @@ SessionStore.prototype = { // Move this session to sessionstore.bak so that: // 1) we can get "tabs from last time" from sessionstore.bak // 2) if sessionstore.js exists on next start, we know we crashed - if (this._sessionFile.exists()) - this._sessionFile.moveTo(null, this._sessionFileBackup.leafName); + OS.File.move(this._sessionFile.path, this._sessionFileBackup.path).then(null, function onError(reason) { + if (!(reason instanceof OS.File.Error && reason.becauseNoSuchFile)) { + Cu.reportError("Error moving sessionstore files: " + reason); + } + }); observerService.removeObserver(this, "domwindowopened"); observerService.removeObserver(this, "domwindowclosed"); @@ -564,20 +558,10 @@ SessionStore.prototype = { if (!stateString.data) return; - // Initialize the file output stream. - let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); - ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN); - - // Obtain a converter to convert our data to a UTF-8 encoded input stream. - let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - // Asynchronously copy the data to the file. - let istream = converter.convertToInputStream(aData); - NetUtil.asyncCopy(istream, ostream, function(rc) { - if (Components.isSuccessCode(rc)) { - Services.obs.notifyObservers(null, "sessionstore-state-write-complete", ""); - } + let array = new TextEncoder().encode(aData); + OS.File.writeAtomic(aFile.path, array, { tmpPath: aFile.path + ".tmp" }).then(function onSuccess() { + Services.obs.notifyObservers(null, "sessionstore-state-write-complete", ""); }); }, @@ -1006,26 +990,17 @@ SessionStore.prototype = { // session will be read from sessionstore.bak (which is also used for // "tabs from last time"). if (aSessionString == null) { - if (!this._sessionFileBackup.exists()) { - throw "Session file doesn't exist"; - } - - let channel = NetUtil.newChannel(this._sessionFileBackup); - channel.contentType = "application/json"; - NetUtil.asyncFetch(channel, function(aStream, aResult) { - try { - if (!Components.isSuccessCode(aResult)) { - throw "Could not fetch session file"; - } - - let data = NetUtil.readInputStreamToString(aStream, aStream.available(), { charset : "UTF-8" }) || ""; - aStream.close(); - - restoreWindow(data); - } catch (e) { - Cu.reportError("SessionStore: " + e.message); - notifyObservers("fail"); + Task.spawn(function() { + let bytes = yield OS.File.read(this._sessionFileBackup.path); + let data = JSON.parse(new TextDecoder().decode(bytes) || ""); + restoreWindow(data); + }.bind(this)).then(null, function onError(reason) { + if (reason instanceof OS.File.Error && reason.becauseNoSuchFile) { + Cu.reportError("Session file doesn't exist"); + } else { + Cu.reportError("SessionStore: " + reason.message); } + notifyObservers("fail"); }); } else { restoreWindow(aSessionString); From a1ece35580780cd1642850e036daa1c62ef2dd01 Mon Sep 17 00:00:00 2001 From: Shilpan Bhagat Date: Mon, 26 Aug 2013 13:23:33 -0700 Subject: [PATCH 5/8] Bug 909400 - Show helperapps relevant pageaction on tabswitch. r=wesj --- mobile/android/chrome/content/browser.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 5ea6241965c..1c5a87b0761 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2862,6 +2862,7 @@ Tab.prototype = { this.browser.focus(); this.browser.docShellIsActive = true; Reader.updatePageAction(this); + HelperApps.updatePageAction(this.browser.currentURI); } else { this.browser.setAttribute("type", "content-targetable"); this.browser.docShellIsActive = false; From 8c02d3c700cfad05136de9119f7026acfcf19ad7 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Mon, 26 Aug 2013 16:00:33 -0500 Subject: [PATCH 6/8] Bug 909482 - Fix for getViewId exception when running without apz. r=botond --- browser/metro/base/content/bindings/browser.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/browser/metro/base/content/bindings/browser.js b/browser/metro/base/content/bindings/browser.js index 39045349c2f..554abaed972 100644 --- a/browser/metro/base/content/bindings/browser.js +++ b/browser/metro/base/content/bindings/browser.js @@ -554,7 +554,9 @@ let ContentScroll = { addMessageListener("Content:SetCacheViewport", this); addMessageListener("Content:SetWindowSize", this); - addEventListener("scroll", this, false); + if (Services.prefs.getBoolPref("layers.async-pan-zoom.enabled")) { + addEventListener("scroll", this, false); + } addEventListener("pagehide", this, false); addEventListener("MozScrolledAreaChanged", this, false); }, From e779a2364d799105acc9280c3537fdd115b594c3 Mon Sep 17 00:00:00 2001 From: Marco Castelluccio Date: Tue, 27 Aug 2013 08:50:22 -0400 Subject: [PATCH 7/8] Bug 909512 - Wait appcache download before showing the installation notification. r=felipc --- browser/modules/webappsUI.jsm | 73 ++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/browser/modules/webappsUI.jsm b/browser/modules/webappsUI.jsm index 4fb64c7c9b9..e4623304e87 100644 --- a/browser/modules/webappsUI.jsm +++ b/browser/modules/webappsUI.jsm @@ -14,18 +14,36 @@ Cu.import("resource://gre/modules/Webapps.jsm"); Cu.import("resource://gre/modules/AppsUtils.jsm"); Cu.import("resource://gre/modules/WebappsInstaller.jsm"); Cu.import("resource://gre/modules/WebappOSUtils.jsm"); +Cu.import("resource://gre/modules/Task.jsm"); +Cu.import("resource://gre/modules/Promise.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "cpmm", + "@mozilla.org/childprocessmessagemanager;1", + "nsIMessageSender"); this.webappsUI = { + downloads: {}, + init: function webappsUI_init() { Services.obs.addObserver(this, "webapps-ask-install", false); Services.obs.addObserver(this, "webapps-launch", false); Services.obs.addObserver(this, "webapps-uninstall", false); + cpmm.addMessageListener("Webapps:OfflineCache", this); }, uninit: function webappsUI_uninit() { Services.obs.removeObserver(this, "webapps-ask-install"); Services.obs.removeObserver(this, "webapps-launch"); Services.obs.removeObserver(this, "webapps-uninstall"); + cpmm.removeMessageListener("Webapps:OfflineCache", this); + }, + + receiveMessage: function(aMessage) { + let data = aMessage.data; + + if (aMessage.name == "Webapps:OfflineCache" && data.installState == "installed") { + this.downloads[data.manifest].resolve(); + } }, observe: function webappsUI_observe(aSubject, aTopic, aData) { @@ -103,7 +121,12 @@ this.webappsUI = { let mainAction = { label: bundle.getString("webapps.install"), accessKey: bundle.getString("webapps.install.accesskey"), - callback: function() { + callback: () => { + let manifestURL = aData.app.manifestURL; + if (aData.app.manifest && aData.app.manifest.appcache_path) { + this.downloads[manifestURL] = Promise.defer(); + } + let app = WebappsInstaller.init(aData); if (app) { @@ -113,18 +136,22 @@ this.webappsUI = { } DOMApplicationRegistry.confirmInstall(aData, false, localDir, null, - function (aManifest) { - WebappsInstaller.install(aData, aManifest).then( - function() { - installationSuccessNotification(aData, app, chromeWin); - }, - function(error) { - Cu.reportError("Error installing webapp: " + error); + (aManifest) => { + Task.spawn(function() { + try { + yield WebappsInstaller.install(aData, aManifest); + if (this.downloads[manifestURL]) { + yield this.downloads[manifestURL].promise; + } + installationSuccessNotification(aData, app, bundle); + } catch (ex) { + Cu.reportError("Error installing webapp: " + ex); // TODO: Notify user that the installation has failed + } finally { + delete this.downloads[manifestURL]; } - ); - } - ); + }.bind(this)); + }); } else { DOMApplicationRegistry.denyInstall(aData); } @@ -151,7 +178,7 @@ this.webappsUI = { } } -function installationSuccessNotification(aData, app, aWindow) { +function installationSuccessNotification(aData, app, aBundle) { let launcher = { observe: function(aSubject, aTopic) { if (aTopic == "alertclickcallback") { @@ -160,19 +187,13 @@ function installationSuccessNotification(aData, app, aWindow) { } }; - let bundle = aWindow.gNavigatorBundle; + try { + let notifier = Cc["@mozilla.org/alerts-service;1"]. + getService(Ci.nsIAlertsService); - if (("@mozilla.org/alerts-service;1" in Cc)) { - let notifier; - try { - notifier = Cc["@mozilla.org/alerts-service;1"]. - getService(Ci.nsIAlertsService); - - notifier.showAlertNotification(app.iconURI.spec, - bundle.getString("webapps.install.success"), - app.appNameAsFilename, - true, null, launcher); - - } catch (ex) {} - } + notifier.showAlertNotification(app.iconURI.spec, + aBundle.getString("webapps.install.success"), + app.appNameAsFilename, + true, null, launcher); + } catch (ex) {} } From 8c04019c3e8fe5acef35faa5472c33a351be6d89 Mon Sep 17 00:00:00 2001 From: Mihnea Dobrescu-Balaur Date: Fri, 16 Aug 2013 13:42:04 -0700 Subject: [PATCH 8/8] Bug 906172 - Handle exceptions for sequential tests properly. r=ted --- testing/xpcshell/runxpcshelltests.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py index 9490518c9c3..c5b06aac5b1 100644 --- a/testing/xpcshell/runxpcshelltests.py +++ b/testing/xpcshell/runxpcshelltests.py @@ -1333,11 +1333,13 @@ class XPCShellTests(object): break test.start() test.join() + self.addTestResults(test) # did the test encounter any exception? if test.exception: - raise test.exception + exceptions.append(test.exception) + tracebacks.append(test.traceback) + break keep_going = test.keep_going - self.addTestResults(test) # restore default SIGINT behaviour signal.signal(signal.SIGINT, signal.SIG_DFL)