Merge fx-team to mozilla-central a=merge

This commit is contained in:
Wes Kocher 2015-01-08 16:58:52 -08:00
commit 0474fa769c
52 changed files with 4908 additions and 3054 deletions

View File

@ -862,7 +862,7 @@ pref("browser.preferences.animateFadeIn", false);
#endif
// Toggles between the two Preferences implementations, pop-up window and in-content
#ifndef RELEASE_BUILD
#ifdef EARLY_BETA_OR_EARLIER
pref("browser.preferences.inContent", true);
pref("browser.preferences.instantApply", true);
#else
@ -1644,6 +1644,7 @@ pref("image.mem.max_decoded_image_kb", 256000);
pref("loop.enabled", true);
pref("loop.server", "https://loop.services.mozilla.com/v0");
pref("loop.seenToS", "unseen");
pref("loop.showPartnerLogo", true);
pref("loop.gettingStarted.seen", false);
pref("loop.gettingStarted.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/hello/start/");
pref("loop.gettingStarted.resumeOnFirstJoin", false);

View File

@ -266,11 +266,6 @@ let gFxAccounts = {
Weave.Notifications.removeAll(this.SYNC_MIGRATION_NOTIFICATION_TITLE);
return;
}
if (gBrowser.currentURI.spec.split("?")[0] == "about:accounts") {
// If the current tab is about:accounts, assume the user just completed a
// migration step and don't bother them with a redundant notification.
return;
}
let note = null;
switch (this._migrationInfo.state) {
case this.fxaMigrator.STATE_USER_FXA: {

View File

@ -201,13 +201,29 @@ loop.panel = (function(_, mozL10n) {
return {
seenToS: getPref("seenToS"),
gettingStartedSeen: getPref("gettingStarted.seen")
gettingStartedSeen: getPref("gettingStarted.seen"),
showPartnerLogo: getPref("showPartnerLogo")
};
},
renderPartnerLogo: function() {
if (!this.state.showPartnerLogo) {
return null;
}
var locale = mozL10n.getLanguage();
navigator.mozLoop.setLoopPref('showPartnerLogo', false);
return (
React.createElement("p", {id: "powered-by", className: "powered-by"},
mozL10n.get("powered_by_beforeLogo"),
React.createElement("img", {id: "powered-by-logo", className: locale}),
mozL10n.get("powered_by_afterLogo")
)
);
},
render: function() {
if (!this.state.gettingStartedSeen || this.state.seenToS == "unseen") {
var locale = mozL10n.getLanguage();
var terms_of_use_url = navigator.mozLoop.getLoopPref('legal.ToS_url');
var privacy_notice_url = navigator.mozLoop.getLoopPref('legal.privacy_url');
var tosHTML = mozL10n.get("legal_text_and_links3", {
@ -224,11 +240,7 @@ loop.panel = (function(_, mozL10n) {
),
});
return React.createElement("div", {id: "powered-by-wrapper"},
React.createElement("p", {id: "powered-by"},
mozL10n.get("powered_by_beforeLogo"),
React.createElement("img", {id: "powered-by-logo", className: locale}),
mozL10n.get("powered_by_afterLogo")
),
this.renderPartnerLogo(),
React.createElement("p", {className: "terms-service",
dangerouslySetInnerHTML: {__html: tosHTML}})
);

View File

@ -201,13 +201,29 @@ loop.panel = (function(_, mozL10n) {
return {
seenToS: getPref("seenToS"),
gettingStartedSeen: getPref("gettingStarted.seen")
gettingStartedSeen: getPref("gettingStarted.seen"),
showPartnerLogo: getPref("showPartnerLogo")
};
},
renderPartnerLogo: function() {
if (!this.state.showPartnerLogo) {
return null;
}
var locale = mozL10n.getLanguage();
navigator.mozLoop.setLoopPref('showPartnerLogo', false);
return (
<p id="powered-by" className="powered-by">
{mozL10n.get("powered_by_beforeLogo")}
<img id="powered-by-logo" className={locale} />
{mozL10n.get("powered_by_afterLogo")}
</p>
);
},
render: function() {
if (!this.state.gettingStartedSeen || this.state.seenToS == "unseen") {
var locale = mozL10n.getLanguage();
var terms_of_use_url = navigator.mozLoop.getLoopPref('legal.ToS_url');
var privacy_notice_url = navigator.mozLoop.getLoopPref('legal.privacy_url');
var tosHTML = mozL10n.get("legal_text_and_links3", {
@ -224,11 +240,7 @@ loop.panel = (function(_, mozL10n) {
),
});
return <div id="powered-by-wrapper">
<p id="powered-by">
{mozL10n.get("powered_by_beforeLogo")}
<img id="powered-by-logo" className={locale} />
{mozL10n.get("powered_by_afterLogo")}
</p>
{this.renderPartnerLogo()}
<p className="terms-service"
dangerouslySetInnerHTML={{__html: tosHTML}}></p>
</div>;

View File

@ -203,6 +203,11 @@ loop.store.ActiveRoomStore = (function() {
* @param {sharedActions.SetupRoomInfo} actionData
*/
setupRoomInfo: function(actionData) {
if (this._onUpdateListener) {
console.error("Room info already set up!");
return;
}
this.setStoreState({
roomName: actionData.roomName,
roomOwner: actionData.roomOwner,
@ -211,10 +216,11 @@ loop.store.ActiveRoomStore = (function() {
roomUrl: actionData.roomUrl
});
this._mozLoop.rooms.on("update:" + actionData.roomToken,
this._handleRoomUpdate.bind(this));
this._mozLoop.rooms.on("delete:" + actionData.roomToken,
this._handleRoomDelete.bind(this));
this._onUpdateListener = this._handleRoomUpdate.bind(this);
this._onDeleteListener = this._handleRoomDelete.bind(this);
this._mozLoop.rooms.on("update:" + actionData.roomToken, this._onUpdateListener);
this._mozLoop.rooms.on("delete:" + actionData.roomToken, this._onDeleteListener);
},
/**
@ -390,10 +396,16 @@ loop.store.ActiveRoomStore = (function() {
windowUnload: function() {
this._leaveRoom(ROOM_STATES.CLOSING);
if (!this._onUpdateListener) {
return;
}
// If we're closing the window, we can stop listening to updates.
var roomToken = this.getStoreState().roomToken;
this._mozLoop.rooms.off("update:" + roomToken);
this._mozLoop.rooms.off("delete:" + roomToken);
this._mozLoop.rooms.off("update:" + roomToken, this._onUpdateListener);
this._mozLoop.rooms.off("delete:" + roomToken, this._onDeleteListener);
delete this._onUpdateListener;
delete this._onDeleteListener;
},
/**

View File

@ -1052,5 +1052,21 @@ describe("loop.panel", function() {
TestUtils.findRenderedDOMComponentWithClass(view, "terms-service");
});
it("should render the telefonica logo after the first time use",
function() {
navigator.mozLoop.getLoopPref = function(key) {
return {
"gettingStarted.seen": false,
"seenToS": "unseen",
"showPartnerLogo": false
}[key];
};
var view = TestUtils.renderIntoDocument(
React.createElement(loop.panel.ToSView));
expect(view.getDOMNode().querySelector(".powered-by")).eql(null);
});
});
});

View File

@ -555,7 +555,8 @@ var gCookiesWindow = {
let buttonLabel = this._bundle.getString("removeSelectedCookies");
let removeSelectedCookies = document.getElementById("removeSelectedCookies");
removeSelectedCookies.label = PluralForm.get(selectedCookieCount, buttonLabel);
removeSelectedCookies.label = PluralForm.get(selectedCookieCount, buttonLabel)
.replace("#1", selectedCookieCount);
removeSelectedCookies.disabled = !(seln.count > 0);
},

View File

@ -35,8 +35,9 @@ function prettyPrintSource() {
}
function testPrettyPrinted({ error, source }) {
ok(!error);
ok(source.contains("\n "));
ok(!error, "Should not get an error while pretty-printing");
ok(source.contains("\n "),
"Source should be pretty-printed");
disablePrettyPrint();
}
@ -45,8 +46,9 @@ function disablePrettyPrint() {
}
function testUgly({ error, source }) {
ok(!error);
ok(!source.contains("\n "));
ok(!error, "Should not get an error while disabling pretty-printing");
ok(!source.contains("\n "),
"Source should not be pretty after disabling pretty-printing");
closeDebuggerAndFinish(gPanel);
}

View File

@ -1,4 +1,4 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function stopMe(){throw Error("boom");}try{stopMe();var a=1;a=a*2;}catch(e){};
//# sourceMappingURL=bogus.map

View File

@ -15,28 +15,38 @@ function test()
openScratchpad(runTests);
}, true);
content.location = "data:text/html;charset=utf8,test Scratchpad pretty print error goto line.";
content.location = "data:text/html;charset=utf8,"
+ "test Scratchpad pretty print error goto line.";
}
function testJumpToPrettyPrintError(sp, error, remark) {
info("will test jumpToLine after prettyPrint error" + remark);
// CodeMirror lines and columns are 0-based, Scratchpad UI and error
// stack are 1-based.
is(/Invalid regexp flag \(3:10\)/.test(error), true, "prettyPrint expects error in editor text:\n" + error);
const errorLine = 3, errorColumn = 10;
const editorDoc = sp.editor.container.contentDocument;
sp.editor.jumpToLine();
const lineInput = editorDoc.querySelector("input");
const errorLocation = lineInput.value;
const [ inputLine, inputColumn ] = errorLocation.split(":");
is(inputLine, errorLine, "jumpToLine input field is set from editor selection (line)");
is(inputColumn, errorColumn, "jumpToLine input field is set from editor selection (column)");
EventUtils.synthesizeKey("VK_RETURN", { }, editorDoc.defaultView);
// CodeMirror lines and columns are 0-based, Scratchpad UI and error
// stack are 1-based.
const cursor = sp.editor.getCursor();
is(inputLine, cursor.line + 1, "jumpToLine goto error location (line)");
is(inputColumn, cursor.ch + 1, "jumpToLine goto error location (column)");
// CodeMirror lines and columns are 0-based, Scratchpad UI and error
// stack are 1-based.
is(/Invalid regular expression flag \(3:10\)/.test(error), true,
"prettyPrint expects error in editor text:\n" + error);
sp.editor.jumpToLine();
const editorDoc = sp.editor.container.contentDocument;
const lineInput = editorDoc.querySelector("input");
const errorLocation = lineInput.value;
const [ inputLine, inputColumn ] = errorLocation.split(":");
const errorLine = 3, errorColumn = 10;
is(inputLine, errorLine,
"jumpToLine input field is set from editor selection (line)");
is(inputColumn, errorColumn,
"jumpToLine input field is set from editor selection (column)");
EventUtils.synthesizeKey("VK_RETURN", { }, editorDoc.defaultView);
// CodeMirror lines and columns are 0-based, Scratchpad UI and error
// stack are 1-based.
const cursor = sp.editor.getCursor();
is(inputLine, cursor.line + 1, "jumpToLine goto error location (line)");
is(inputColumn, cursor.ch + 1, "jumpToLine goto error location (column)");
}
function runTests(sw, sp)
@ -49,12 +59,14 @@ function runTests(sw, sp)
"// line 5",
""
].join("\n"));
sp.prettyPrint().then(aFulfill => {
ok(false, "Expecting Invalid regexp flag (3:10)");
finish();
}, error => {
testJumpToPrettyPrintError(sp, error, " (Bug 1005471, first time)");
});
sp.prettyPrint().then(aFulfill => {
ok(false, "Expecting Invalid regexp flag (3:10)");
finish();

View File

@ -13,26 +13,30 @@ add_task(function*() {
get3(front, "create-node")
]);
let t0 = 0, t1 = 0.1, t2 = 0.2, t3 = 0.3, t4 = 0.4, t5 = 0.6, t6 = 0.7, t7 = 1;
yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.2, t0]);
yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.3, t1]);
yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.4, t2]);
yield oscNode.addAutomationEvent("frequency", "linearRampToValueAtTime", [1, t3]);
yield oscNode.addAutomationEvent("frequency", "linearRampToValueAtTime", [0.15, t4]);
yield oscNode.addAutomationEvent("frequency", "exponentialRampToValueAtTime", [0.75, t5]);
yield oscNode.addAutomationEvent("frequency", "exponentialRampToValueAtTime", [0.05, t6]);
yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [300, 0.1]);
yield oscNode.addAutomationEvent("frequency", "linearRampToValueAtTime", [500, 0.4]);
yield oscNode.addAutomationEvent("frequency", "exponentialRampToValueAtTime", [200, 0.6]);
// End with a setTargetAtTime event, as the target approaches infinity, which will
// give us more points to render than the default 2000
yield oscNode.addAutomationEvent("frequency", "setTargetAtTime", [1, t7, 0.5]);
yield oscNode.addAutomationEvent("frequency", "setTargetAtTime", [1000, 2, 0.5]);
let { events, values } = yield oscNode.getAutomationData("frequency");
var { events, values } = yield oscNode.getAutomationData("frequency");
is(events.length, 8, "8 recorded events returned.");
is(values.length, 4000, "6000 value points returned when ending with exponentiall approaching automator.");
is(events.length, 4, "4 recorded events returned.");
is(values.length, 4000, "4000 value points returned when ending with exponentiall approaching automator.");
checkAutomationValue(values, 1, 0.05);
checkAutomationValue(values, 2, 0.87);
checkAutomationValue(values, 3, 0.98);
checkAutomationValue(values, 2.01, 215.055)
checkAutomationValue(values, 2.1, 345.930);
checkAutomationValue(values, 3, 891.601);
checkAutomationValue(values, 5, 998.01);
// Refetch the automation data to ensure it recalculates correctly (bug 1118071)
var { events, values } = yield oscNode.getAutomationData("frequency");
checkAutomationValue(values, 2.01, 215.055)
checkAutomationValue(values, 2.1, 345.930);
checkAutomationValue(values, 3, 891.601);
checkAutomationValue(values, 5, 998.01);
yield removeTab(target.tab);
});

View File

@ -7,6 +7,10 @@
<!ENTITY cookiesonsystem.label "The following cookies are stored on your computer:">
<!ENTITY cookiename.label "Cookie Name">
<!ENTITY cookiedomain.label "Site">
<!-- LOCALIZATION NOTE (button.removeSelectedCookies.accesskey):
The label associated with this accesskey can be found in
preferences.properties as removeSelectedCookies.
-->
<!ENTITY button.removeSelectedCookies.accesskey "R">
<!ENTITY button.removeAllCookies.label "Remove All">
<!ENTITY button.removeAllCookies.accesskey "A">

View File

@ -95,6 +95,10 @@ cookiesFiltered=The following cookies match your search:
# LOCALIZATION NOTE (removeSelectedCookies):
# Semicolon-separated list of plural forms. See:
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
# If you need to display the number of selected elements in your language,
# you can use #1 in your localization as a placeholder for the number.
# For example this is the English string with numbers:
# removeSelectedCookied=Remove #1 Selected;Remove #1 Selected
removeSelectedCookies=Remove Selected;Remove Selected
#### Offline apps

View File

@ -177,3 +177,7 @@ toolbarpaletteitem:-moz-any([place="palette"], [place="panel"]) > toolbaritem[sd
width: 32px;
height: 32px;
}
toolbarpaletteitem[place="palette"] > .toolbarbutton-1 > .toolbarbutton-menubutton-button {
padding: 3px 1px;
}

View File

@ -194,6 +194,10 @@ description > html|a {
padding-bottom: 0; /* no padding needed in inContent prefs */
}
#tabsElement {
-moz-margin-end: 4px; /* add the 4px end-margin of other elements */
}
#encryptionPanel {
margin-top: 15px;
}

View File

@ -8,6 +8,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.R;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountUtils;
@ -59,6 +60,7 @@ public class FxAccountStatusFragment
// schedule the sync as usual. See also comment below about garbage
// collection.
private static final long DELAY_IN_MILLISECONDS_BEFORE_REQUESTING_SYNC = 5 * 1000;
private static final long LAST_SYNCED_TIME_UPDATE_INTERVAL_IN_MILLISECONDS = 60 * 1000;
// By default, the auth/account server preference is only shown when the
// account is configured to use a custom server. In debug mode, this is set.
@ -104,6 +106,9 @@ public class FxAccountStatusFragment
// single account. (That is, it does not capture a single account instance.)
protected Runnable requestSyncRunnable;
// Runnable to update last synced time.
protected Runnable lastSyncedTimeUpdateRunnable;
protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate();
protected Preference ensureFindPreference(String key) {
@ -333,6 +338,9 @@ public class FxAccountStatusFragment
protected void showNeedsMasterSyncAutomaticallyEnabled() {
syncCategory.setTitle(R.string.fxaccount_status_sync);
needsMasterSyncAutomaticallyEnabledPreference.setTitle(AppConstants.Versions.preLollipop ?
R.string.fxaccount_status_needs_master_sync_automatically_enabled :
R.string.fxaccount_status_needs_master_sync_automatically_enabled_v21);
showOnlyOneErrorPreference(needsMasterSyncAutomaticallyEnabledPreference);
setCheckboxesEnabled(false);
}
@ -421,6 +429,7 @@ public class FxAccountStatusFragment
// a reference to this fragment alive, but we expect posted runnables to be
// serviced very quickly, so this is not an issue.
requestSyncRunnable = new RequestSyncRunnable();
lastSyncedTimeUpdateRunnable = new LastSyncTimeUpdateRunnable();
// We would very much like register these status observers in bookended
// onResume/onPause calls, but because the Fragment gets onResume during the
@ -437,6 +446,11 @@ public class FxAccountStatusFragment
public void onPause() {
super.onPause();
FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusDelegate);
// Focus lost, remove scheduled update if any.
if (lastSyncedTimeUpdateRunnable != null) {
handler.removeCallbacks(lastSyncedTimeUpdateRunnable);
}
}
protected void hardRefresh() {
@ -531,8 +545,13 @@ public class FxAccountStatusFragment
} else {
syncNowPreference.setTitle(R.string.fxaccount_status_sync_now);
}
scheduleAndUpdateLastSyncedTime();
}
private void scheduleAndUpdateLastSyncedTime() {
final String lastSynced = getLastSyncedString(fxAccount.getLastSyncedTimestamp());
syncNowPreference.setSummary(lastSynced);
handler.postDelayed(lastSyncedTimeUpdateRunnable, LAST_SYNCED_TIME_UPDATE_INTERVAL_IN_MILLISECONDS);
}
protected void updateAuthServerPreference() {
@ -694,6 +713,16 @@ public class FxAccountStatusFragment
}
}
/**
* The Runnable that schedules a future update and updates the last synced time.
*/
protected class LastSyncTimeUpdateRunnable implements Runnable {
@Override
public void run() {
scheduleAndUpdateLastSyncedTime();
}
}
/**
* A separate listener to separate debug logic from main code paths.
*/

View File

@ -206,6 +206,7 @@
<!ENTITY fxaccount_status_needs_credentials 'Cannot connect. Tap to sign in.'>
<!ENTITY fxaccount_status_needs_upgrade 'You need to upgrade &brandShortName; to sign in.'>
<!ENTITY fxaccount_status_needs_master_sync_automatically_enabled '&syncBrand.shortName.label; is set up, but not syncing automatically. Toggle “Auto-sync data” in Android Settings &gt; Data Usage.'>
<!ENTITY fxaccount_status_needs_master_sync_automatically_enabled_v21 '&syncBrand.shortName.label; is set up, but not syncing automatically. Toggle “Auto-sync data” in the menu of Android Settings &gt; Accounts.'>
<!ENTITY fxaccount_status_needs_account_enabled '&syncBrand.shortName.label; is set up, but not syncing automatically. Tap to start syncing.'>
<!ENTITY fxaccount_status_needs_finish_migrating 'Tap to sign in to your new Firefox Account.'>
<!ENTITY fxaccount_status_bookmarks 'Bookmarks'>

View File

@ -0,0 +1,147 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils, Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function init() {
// Include the build date and a warning about Telemetry
// if this is an "a#" (nightly or aurora) build
#expand const version = "__MOZ_APP_VERSION__";
if (/a\d+$/.test(version)) {
let buildID = Services.appinfo.appBuildID;
let buildDate = buildID.slice(0, 4) + "-" + buildID.slice(4, 6) + "-" + buildID.slice(6, 8);
let br = document.createElement("br");
let versionPara = document.getElementById("version");
versionPara.appendChild(br);
let date = document.createTextNode("(" + buildDate + ")");
versionPara.appendChild(date);
document.getElementById("telemetry").hidden = false;
}
// Include the Distribution information if available
try {
let distroId = Services.prefs.getCharPref("distribution.id");
if (distroId) {
let distroVersion = Services.prefs.getCharPref("distribution.version");
let distroIdField = document.getElementById("distributionID");
distroIdField.textContent = distroId + " - " + distroVersion;
distroIdField.hidden = false;
let distroAbout = Services.prefs.getComplexValue("distribution.about", Ci.nsISupportsString);
let distroField = document.getElementById("distributionAbout");
distroField.textContent = distroAbout;
distroField.hidden = false;
}
} catch (e) {
// Pref is unset
}
// get URLs from prefs
try {
let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
let links = [
{id: "releaseNotesURL", pref: "app.releaseNotesURL"},
{id: "supportURL", pref: "app.support.baseURL"},
{id: "faqURL", pref: "app.faqURL"},
{id: "privacyURL", pref: "app.privacyURL"},
{id: "creditsURL", pref: "app.creditsURL"},
];
links.forEach(function(link) {
let url = formatter.formatURLPref(link.pref);
let element = document.getElementById(link.id);
element.setAttribute("href", url);
});
} catch (ex) {}
#ifdef MOZ_UPDATER
let Updater = {
update: null,
init: function() {
Services.obs.addObserver(this, "Update:CheckResult", false);
},
observe: function(aSubject, aTopic, aData) {
if (aTopic == "Update:CheckResult") {
showUpdateMessage(aData);
}
},
};
Updater.init();
function checkForUpdates() {
showCheckingMessage();
Services.androidBridge.handleGeckoMessage({ type: "Update:Check" });
}
function downloadUpdate() {
Services.androidBridge.handleGeckoMessage({ type: "Update:Download" });
}
function installUpdate() {
showCheckAction();
Services.androidBridge.handleGeckoMessage({ type: "Update:Install" });
}
let updateLink = document.getElementById("updateLink");
let checkingSpan = document.getElementById("update-message-checking");
let noneSpan = document.getElementById("update-message-none");
let foundSpan = document.getElementById("update-message-found");
let downloadingSpan = document.getElementById("update-message-downloading");
let downloadedSpan = document.getElementById("update-message-downloaded");
function showCheckAction() {
checkingSpan.style.display = "none";
noneSpan.style.display = "none";
foundSpan.style.display = "none";
downloadingSpan.style.display = "none";
downloadedSpan.style.display = "none";
updateLink.style.display = "block";
}
function showCheckingMessage() {
updateLink.style.display = "none";
noneSpan.style.display = "none";
foundSpan.style.display = "none";
downloadingSpan.style.display = "none";
downloadedSpan.style.display = "none";
checkingSpan.style.display = "block";
}
function showUpdateMessage(aResult) {
updateLink.style.display = "none";
checkingSpan.style.display = "none";
noneSpan.style.display = "none";
foundSpan.style.display = "none";
downloadingSpan.style.display = "none";
downloadedSpan.style.display = "none";
// the aResult values come from mobile/android/base/UpdateServiceHelper.java
switch (aResult) {
case "NOT_AVAILABLE":
noneSpan.style.display = "block";
setTimeout(showCheckAction, 2000);
break;
case "AVAILABLE":
foundSpan.style.display = "block";
break;
case "DOWNLOADING":
downloadingSpan.style.display = "block";
break;
case "DOWNLOADED":
downloadedSpan.style.display = "block";
break;
}
}
#endif
}
document.addEventListener("DOMContentLoaded", init, false);

View File

@ -71,146 +71,7 @@
</div>
#endif
<script type="application/javascript;version=1.8"><![CDATA[
let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils, Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
<script type="application/javascript;version=1.8" src="chrome://browser/content/about.js" />
// Include the build date and a warning about Telemetry
// if this is an "a#" (nightly or aurora) build
#expand const version = "__MOZ_APP_VERSION__";
if (/a\d+$/.test(version)) {
let buildID = Services.appinfo.appBuildID;
let buildDate = buildID.slice(0,4) + "-" + buildID.slice(4,6) + "-" + buildID.slice(6,8);
let br = document.createElement("br");
let versionPara = document.getElementById("version");
versionPara.appendChild(br);
let date = document.createTextNode("(" + buildDate + ")");
versionPara.appendChild(date);
document.getElementById("telemetry").hidden = false;
}
// Include the Distribution information if available
try {
let distroId = Services.prefs.getCharPref("distribution.id");
if (distroId) {
let distroVersion = Services.prefs.getCharPref("distribution.version");
let distroIdField = document.getElementById("distributionID");
distroIdField.textContent = distroId + " - " + distroVersion;
distroIdField.hidden = false;
let distroAbout = Services.prefs.getComplexValue("distribution.about", Ci.nsISupportsString);
let distroField = document.getElementById("distributionAbout");
distroField.textContent = distroAbout;
distroField.hidden = false;
}
} catch (e) {
// Pref is unset
}
// get URLs from prefs
try {
let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
let links = [
{id: "releaseNotesURL", pref: "app.releaseNotesURL"},
{id: "supportURL", pref: "app.support.baseURL"},
{id: "faqURL", pref: "app.faqURL"},
{id: "privacyURL", pref: "app.privacyURL"},
{id: "creditsURL", pref: "app.creditsURL"},
];
links.forEach(function (link) {
let url = formatter.formatURLPref(link.pref);
let element = document.getElementById(link.id);
element.setAttribute("href", url);
});
} catch (ex) {}
#ifdef MOZ_UPDATER
let Updater = {
update: null,
init: function() {
Services.obs.addObserver(this, "Update:CheckResult", false);
},
observe: function(aSubject, aTopic, aData) {
if (aTopic == "Update:CheckResult") {
showUpdateMessage(aData);
}
},
};
Updater.init();
function checkForUpdates() {
showCheckingMessage();
Services.androidBridge.handleGeckoMessage({ type: "Update:Check" });
}
function downloadUpdate() {
Services.androidBridge.handleGeckoMessage({ type: "Update:Download" });
}
function installUpdate() {
showCheckAction();
Services.androidBridge.handleGeckoMessage({ type: "Update:Install" });
}
let updateLink = document.getElementById("updateLink");
let checkingSpan = document.getElementById("update-message-checking");
let noneSpan = document.getElementById("update-message-none");
let foundSpan = document.getElementById("update-message-found");
let downloadingSpan = document.getElementById("update-message-downloading");
let downloadedSpan = document.getElementById("update-message-downloaded");
function showCheckAction() {
checkingSpan.style.display = "none";
noneSpan.style.display = "none";
foundSpan.style.display = "none";
downloadingSpan.style.display = "none";
downloadedSpan.style.display = "none";
updateLink.style.display = "block";
}
function showCheckingMessage() {
updateLink.style.display = "none";
noneSpan.style.display = "none";
foundSpan.style.display = "none";
downloadingSpan.style.display = "none";
downloadedSpan.style.display = "none";
checkingSpan.style.display = "block";
}
function showUpdateMessage(aResult) {
updateLink.style.display = "none";
checkingSpan.style.display = "none";
noneSpan.style.display = "none";
foundSpan.style.display = "none";
downloadingSpan.style.display = "none";
downloadedSpan.style.display = "none";
// the aResult values come from mobile/android/base/UpdateServiceHelper.java
switch (aResult) {
case "NOT_AVAILABLE":
noneSpan.style.display = "block";
setTimeout(showCheckAction, 2000);
break;
case "AVAILABLE":
foundSpan.style.display = "block";
break;
case "DOWNLOADING":
downloadingSpan.style.display = "block";
break;
case "DOWNLOADED":
downloadedSpan.style.display = "block";
break;
}
}
#endif
]]></script>
</body>
</html>

View File

@ -369,13 +369,16 @@ var BrowserApp = {
// Queue up some other performance-impacting initializations
Services.tm.mainThread.dispatch(function() {
// Init LoginManager
Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
CastingApps.init();
}, Ci.nsIThread.DISPATCH_NORMAL);
BrowserApp.gmpInstallManager = new GMPInstallManager();
BrowserApp.gmpInstallManager.simpleCheckAndInstall().then(null, () => {});
CastingApps.init();
// Delay this a minute because there's no rush
setTimeout(() => {
BrowserApp.gmpInstallManager = new GMPInstallManager();
BrowserApp.gmpInstallManager.simpleCheckAndInstall().then(null, () => {});
}, 1000 * 60);
}, Ci.nsIThread.DISPATCH_NORMAL);
#ifdef MOZ_SAFE_BROWSING
Services.tm.mainThread.dispatch(function() {

View File

@ -8,6 +8,7 @@ chrome.jar:
% content browser %content/ contentaccessible=yes
* content/about.xhtml (content/about.xhtml)
* content/about.js (content/about.js)
content/config.xhtml (content/config.xhtml)
content/config.js (content/config.js)
content/content.js (content/content.js)

View File

@ -196,6 +196,7 @@
<string name="fxaccount_status_needs_credentials">&fxaccount_status_needs_credentials;</string>
<string name="fxaccount_status_needs_upgrade">&fxaccount_status_needs_upgrade;</string>
<string name="fxaccount_status_needs_master_sync_automatically_enabled">&fxaccount_status_needs_master_sync_automatically_enabled;</string>
<string name="fxaccount_status_needs_master_sync_automatically_enabled_v21">&fxaccount_status_needs_master_sync_automatically_enabled_v21;</string>
<string name="fxaccount_status_needs_account_enabled">&fxaccount_status_needs_account_enabled;</string>
<string name="fxaccount_status_needs_finish_migrating">&fxaccount_status_needs_finish_migrating;</string>
<string name="fxaccount_status_bookmarks">&fxaccount_status_bookmarks;</string>

View File

@ -67,5 +67,16 @@ public class AppGlobals {
public static final String ACTION_TEST_SETTING_ENABLED = "stumbler-test-setting-enabled";
public static final String ACTION_TEST_SETTING_DISABLED = "stumbler-test-setting-disabled";
// Histogram values
public static final String TELEMETRY_TIME_BETWEEN_UPLOADS_SEC = "STUMBLER_TIME_BETWEEN_UPLOADS_SEC";
public static final String TELEMETRY_BYTES_UPLOADED_PER_SEC = "STUMBLER_VOLUME_BYTES_UPLOADED_PER_SEC";
public static final String TELEMETRY_TIME_BETWEEN_STARTS_SEC = "STUMBLER_TIME_BETWEEN_START_SEC";
public static final String TELEMETRY_BYTES_PER_UPLOAD = "STUMBLER_UPLOAD_BYTES";
public static final String TELEMETRY_OBSERVATIONS_PER_UPLOAD = "STUMBLER_UPLOAD_OBSERVATION_COUNT";
public static final String TELEMETRY_CELLS_PER_UPLOAD = "STUMBLER_UPLOAD_CELL_COUNT";
public static final String TELEMETRY_WIFIS_PER_UPLOAD = "STUMBLER_UPLOAD_WIFI_AP_COUNT";
public static final String TELEMETRY_OBSERVATIONS_PER_DAY = "STUMBLER_OBSERVATIONS_PER_DAY";
public static final String TELEMETRY_TIME_BETWEEN_RECEIVED_LOCATIONS_SEC = "STUMBLER_TIME_BETWEEN_RECEIVED_LOCATIONS_SEC";
}

View File

@ -21,12 +21,13 @@ public final class DataStorageContract {
public static class Stats {
public static final String KEY_VERSION = "version_code";
public static final int VERSION_CODE = 1;
public static final int VERSION_CODE = 2;
public static final String KEY_BYTES_SENT = "bytes_sent";
public static final String KEY_LAST_UPLOAD_TIME = "last_upload_time";
public static final String KEY_OBSERVATIONS_SENT = "observations_sent";
public static final String KEY_WIFIS_SENT = "wifis_sent";
public static final String KEY_CELLS_SENT = "cells_sent";
public static final String KEY_OBSERVATIONS_PER_DAY = "obs_per_day";
}
private DataStorageContract() {

View File

@ -69,6 +69,7 @@ public class DataStorageManager {
private ReportBatchIterator mReportBatchIterator;
private final ReportFileList mFileList;
private Timer mFlushMemoryBuffersToDiskTimer;
private final PersistedStats mPersistedOnDiskUploadStats;
static final String SEP_REPORT_COUNT = "-r";
static final String SEP_WIFI_COUNT = "-w";
@ -242,6 +243,7 @@ public class DataStorageManager {
}
mFileList = new ReportFileList();
mFileList.update(mReportsDir);
mPersistedOnDiskUploadStats = new PersistedStats(baseDir);
}
public synchronized int getMaxWeeksStored() {
@ -448,51 +450,6 @@ public class DataStorageManager {
}
}
public synchronized Properties readSyncStats() throws IOException {
if (!mStatsFile.exists()) {
return new Properties();
}
final FileInputStream input = new FileInputStream(mStatsFile);
try {
final Properties props = new Properties();
props.load(input);
return props;
} finally {
input.close();
}
}
public synchronized void incrementSyncStats(long bytesSent, long reports, long cells, long wifis) throws IOException {
if (reports + cells + wifis < 1) {
return;
}
final Properties properties = readSyncStats();
final long time = System.currentTimeMillis();
writeSyncStats(time,
Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_BYTES_SENT, "0")) + bytesSent,
Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_SENT, "0")) + reports,
Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_CELLS_SENT, "0")) + cells,
Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_WIFIS_SENT, "0")) + wifis);
}
public void writeSyncStats(long time, long bytesSent, long totalObs, long totalCells, long totalWifis) throws IOException {
final FileOutputStream out = new FileOutputStream(mStatsFile);
try {
final Properties props = new Properties();
props.setProperty(DataStorageContract.Stats.KEY_LAST_UPLOAD_TIME, String.valueOf(time));
props.setProperty(DataStorageContract.Stats.KEY_BYTES_SENT, String.valueOf(bytesSent));
props.setProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_SENT, String.valueOf(totalObs));
props.setProperty(DataStorageContract.Stats.KEY_CELLS_SENT, String.valueOf(totalCells));
props.setProperty(DataStorageContract.Stats.KEY_WIFIS_SENT, String.valueOf(totalWifis));
props.setProperty(DataStorageContract.Stats.KEY_VERSION, String.valueOf(DataStorageContract.Stats.VERSION_CODE));
props.store(out, null);
} finally {
out.close();
}
}
public synchronized void deleteAll() {
if (mFileList.mFiles == null) {
return;
@ -509,4 +466,8 @@ public class DataStorageManager {
mTracker.notifyStorageStateEmpty(isEmpty);
}
}
public synchronized void incrementSyncStats(long bytesSent, long reports, long cells, long wifis) throws IOException {
mPersistedOnDiskUploadStats.incrementSyncStats(bytesSent, reports, cells, wifis);
}
}

View File

@ -0,0 +1,99 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.mozstumbler.service.stumblerthread.datahandling;
import org.mozilla.mozstumbler.service.AppGlobals;
import org.mozilla.mozstumbler.service.utils.TelemetryWrapper;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
class PersistedStats {
private final File mStatsFile;
public PersistedStats(String baseDir) {
mStatsFile = new File(baseDir, "upload_stats.ini");
}
public synchronized Properties readSyncStats() throws IOException {
if (!mStatsFile.exists()) {
return new Properties();
}
final FileInputStream input = new FileInputStream(mStatsFile);
try {
final Properties props = new Properties();
props.load(input);
return props;
} finally {
input.close();
}
}
public synchronized void incrementSyncStats(long bytesSent, long reports, long cells, long wifis) throws IOException {
if (reports + cells + wifis < 1) {
return;
}
final Properties properties = readSyncStats();
final long time = System.currentTimeMillis();
final long lastUploadTime = Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_LAST_UPLOAD_TIME, "0"));
final long storedObsPerDay = Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_PER_DAY, "0"));
long observationsToday = reports;
if (lastUploadTime > 0) {
long dayLastUploaded = TimeUnit.MILLISECONDS.toDays(lastUploadTime);
long dayDiff = TimeUnit.MILLISECONDS.toDays(time) - dayLastUploaded;
if (dayDiff > 0) {
// send value of store obs per day
TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_OBSERVATIONS_PER_DAY,
Long.valueOf(storedObsPerDay / dayDiff).intValue());
} else {
observationsToday += storedObsPerDay;
}
}
writeSyncStats(time,
Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_BYTES_SENT, "0")) + bytesSent,
Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_SENT, "0")) + reports,
Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_CELLS_SENT, "0")) + cells,
Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_WIFIS_SENT, "0")) + wifis,
observationsToday);
final long lastUploadMs = Long.parseLong(properties.getProperty(DataStorageContract.Stats.KEY_LAST_UPLOAD_TIME, "0"));
final int timeDiffSec = Long.valueOf((time - lastUploadMs) / 1000).intValue();
if (lastUploadMs > 0 && timeDiffSec > 0) {
TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_TIME_BETWEEN_UPLOADS_SEC, timeDiffSec);
TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_BYTES_UPLOADED_PER_SEC, Long.valueOf(bytesSent).intValue() / timeDiffSec);
}
TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_BYTES_PER_UPLOAD, Long.valueOf(bytesSent).intValue());
TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_OBSERVATIONS_PER_UPLOAD, Long.valueOf(reports).intValue());
TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_WIFIS_PER_UPLOAD, Long.valueOf(wifis).intValue());
TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_CELLS_PER_UPLOAD, Long.valueOf(cells).intValue());
}
public synchronized void writeSyncStats(long time, long bytesSent, long totalObs,
long totalCells, long totalWifis, long obsPerDay) throws IOException {
final FileOutputStream out = new FileOutputStream(mStatsFile);
try {
final Properties props = new Properties();
props.setProperty(DataStorageContract.Stats.KEY_LAST_UPLOAD_TIME, String.valueOf(time));
props.setProperty(DataStorageContract.Stats.KEY_BYTES_SENT, String.valueOf(bytesSent));
props.setProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_SENT, String.valueOf(totalObs));
props.setProperty(DataStorageContract.Stats.KEY_CELLS_SENT, String.valueOf(totalCells));
props.setProperty(DataStorageContract.Stats.KEY_WIFIS_SENT, String.valueOf(totalWifis));
props.setProperty(DataStorageContract.Stats.KEY_VERSION, String.valueOf(DataStorageContract.Stats.VERSION_CODE));
props.setProperty(DataStorageContract.Stats.KEY_OBSERVATIONS_PER_DAY, String.valueOf(obsPerDay));
props.store(out, null);
} finally {
out.close();
}
}
}

View File

@ -15,10 +15,10 @@ import android.location.LocationProvider;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import org.mozilla.mozstumbler.service.AppGlobals;
import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
import org.mozilla.mozstumbler.service.Prefs;
import org.mozilla.mozstumbler.service.utils.TelemetryWrapper;
import java.text.SimpleDateFormat;
import java.util.Date;
@ -48,7 +48,7 @@ public class GPSScanner implements LocationListener {
private Location mLocation = new Location("internal");
private boolean mAutoGeofencing;
private boolean mIsPassiveMode;
private long mTelemetry_lastStartedMs;
private final ScanManager mScanManager;
public GPSScanner(Context context, ScanManager scanManager) {
@ -82,9 +82,13 @@ public class GPSScanner implements LocationListener {
return;
}
locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
0,
0, this);
locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this);
final int timeDiffSec = Long.valueOf((System.currentTimeMillis() - mTelemetry_lastStartedMs) / 1000).intValue();
if (mTelemetry_lastStartedMs > 0 && timeDiffSec > 0) {
TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_TIME_BETWEEN_STARTS_SEC, timeDiffSec);
}
mTelemetry_lastStartedMs = System.currentTimeMillis();
}
private void startActiveMode() {
@ -195,13 +199,14 @@ public class GPSScanner implements LocationListener {
return;
}
final long timeDeltaMs = location.getTime() - mLocation.getTime();
// Seem to get greater likelihood of non-fused location with higher update freq.
// Check dist and time threshold here, not set on the listener.
if (mIsPassiveMode) {
final long timeDelta = location.getTime() - mLocation.getTime();
final boolean hasMoved = location.distanceTo(mLocation) > PASSIVE_GPS_MOVEMENT_MIN_DELTA_M;
if (timeDelta < PASSIVE_GPS_MIN_UPDATE_FREQ_MS || !hasMoved) {
if (timeDeltaMs < PASSIVE_GPS_MIN_UPDATE_FREQ_MS || !hasMoved) {
return;
}
}
@ -228,6 +233,11 @@ public class GPSScanner implements LocationListener {
if (mIsPassiveMode) {
mScanManager.newPassiveGpsLocation();
}
if (timeDeltaMs > 0) {
TelemetryWrapper.addToHistogram(AppGlobals.TELEMETRY_TIME_BETWEEN_RECEIVED_LOCATIONS_SEC,
Long.valueOf(timeDeltaMs).intValue() / 1000);
}
}
@Override

View File

@ -0,0 +1,35 @@
package org.mozilla.mozstumbler.service.utils;
import android.util.Log;
import org.mozilla.mozstumbler.service.AppGlobals;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TelemetryWrapper {
private static final String LOG_TAG = AppGlobals.makeLogTag(TelemetryWrapper.class.getSimpleName());
private static Method mAddToHistogram;
public static void addToHistogram(String key, int value) {
if (mAddToHistogram == null) {
try {
Class<?> telemetry = Class.forName("org.mozilla.gecko.Telemetry");
mAddToHistogram = telemetry.getMethod("addToHistogram", String.class, int.class);
} catch (ClassNotFoundException e) {
Log.d(LOG_TAG, "Class not found!");
return;
} catch (NoSuchMethodException e) {
Log.d(LOG_TAG, "Method not found!");
return;
}
}
if (mAddToHistogram != null) {
try {
mAddToHistogram.invoke(null, key, value);
}
catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
Log.d(LOG_TAG, "Got exception invoking.");
}
}
}
}

View File

@ -13,6 +13,7 @@ stumbler_sources = [
'java/org/mozilla/mozstumbler/service/stumblerthread/blocklist/WifiBlockListInterface.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageContract.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/PersistedStats.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/StumblerBundle.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java',
@ -28,5 +29,6 @@ stumbler_sources = [
'java/org/mozilla/mozstumbler/service/utils/AbstractCommunicator.java',
'java/org/mozilla/mozstumbler/service/utils/NetworkUtils.java',
'java/org/mozilla/mozstumbler/service/utils/PersistentIntentService.java',
'java/org/mozilla/mozstumbler/service/utils/TelemetryWrapper.java',
'java/org/mozilla/mozstumbler/service/utils/Zipper.java',
]

View File

@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: virtualenv
Version: 12.0.2
Version: 12.0.5
Summary: Virtual Python Environment builder
Home-page: https://virtualenv.pypa.io/
Author: Jannis Leidel, Carl Meyer and Brian Rosner
@ -47,6 +47,30 @@ Description: Virtualenv
Release History
===============
12.0.5 (2015-01-03)
~~~~~~~~~~~~~~~~~~~
* Upgrade pip to 6.0.6
* Upgrade setuptools to 11.0
12.0.4 (2014-22-23)
~~~~~~~~~~~~~~~~~~~
* Revert the fix to ``-p`` on Debian based pythons as it was broken in other
situations.
* Revert several sys.path changes new in 12.0 which were breaking virtualenv.
12.0.3 (2014-22-23)
~~~~~~~~~~~~~~~~~~~
* Fix an issue where Debian based Pythons would fail when using -p with the
host Python.
* Upgrade pip to 6.0.3
12.0.2 (2014-12-23)
~~~~~~~~~~~~~~~~~~~

View File

@ -1,6 +1,30 @@
Release History
===============
12.0.5 (2015-01-03)
~~~~~~~~~~~~~~~~~~~
* Upgrade pip to 6.0.6
* Upgrade setuptools to 11.0
12.0.4 (2014-22-23)
~~~~~~~~~~~~~~~~~~~
* Revert the fix to ``-p`` on Debian based pythons as it was broken in other
situations.
* Revert several sys.path changes new in 12.0 which were breaking virtualenv.
12.0.3 (2014-22-23)
~~~~~~~~~~~~~~~~~~~
* Fix an issue where Debian based Pythons would fail when using -p with the
host Python.
* Upgrade pip to 6.0.3
12.0.2 (2014-12-23)
~~~~~~~~~~~~~~~~~~~

View File

@ -1,5 +1,5 @@
[egg_info]
tag_svn_revision = 0
tag_build =
tag_svn_revision = 0
tag_date = 0

View File

@ -2,35 +2,12 @@
"""Create a "virtual" Python installation
"""
__version__ = "12.0.2"
__version__ = "12.0.5"
virtualenv_version = __version__ # legacy
# NB: avoid placing additional imports here, before sys.path is fixed!
import base64
import sys
import os
#
# RATIONALE:
# This script is both it's own "host" and "guest". If it's running in "guest
# mode" (inside the virtualenv interpreter), it's essentially invoked via:
# /path/to/python /path/to/this/script.py
#
# Which, by the nature of Python, will put `/path/to/this` on the system path
# as the first argument. Now this can cause many subtle bugs, because the
# rest of the script is now looking to import from the "host" Python version
# first. This has been especially troublesome when trying to create a Python
# 3 "guest" env using a Python 2 "host", but even with minor Python
# differences, there may been some bleeding between environments that doesn't
# stand out as obviously.
#
# This removes the first argument off the system path, to avoid any accidental
# usage of the "host" library directories.
#
if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
del sys.path[0]
import base64
import codecs
import optparse
import re
@ -1108,33 +1085,45 @@ def change_prefix(filename, dst_prefix):
def copy_required_modules(dst_prefix, symlink):
import imp
for modname in REQUIRED_MODULES:
if modname in sys.builtin_module_names:
logger.info("Ignoring built-in bootstrap module: %s" % modname)
continue
try:
f, filename, _ = imp.find_module(modname)
except ImportError:
logger.info("Cannot import bootstrap module: %s" % modname)
else:
if f is not None:
f.close()
# special-case custom readline.so on OS X, but not for pypy:
if modname == 'readline' and sys.platform == 'darwin' and not (
is_pypy or filename.endswith(join('lib-dynload', 'readline.so'))):
dst_filename = join(dst_prefix, 'lib', 'python%s' % sys.version[:3], 'readline.so')
elif modname == 'readline' and sys.platform == 'win32':
# special-case for Windows, where readline is not a
# standard module, though it may have been installed in
# site-packages by a third-party package
pass
# If we are running under -p, we need to remove the current
# directory from sys.path temporarily here, so that we
# definitely get the modules from the site directory of
# the interpreter we are running under, not the one
# virtualenv.py is installed under (which might lead to py2/py3
# incompatibility issues)
_prev_sys_path = sys.path
if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
sys.path = sys.path[1:]
try:
for modname in REQUIRED_MODULES:
if modname in sys.builtin_module_names:
logger.info("Ignoring built-in bootstrap module: %s" % modname)
continue
try:
f, filename, _ = imp.find_module(modname)
except ImportError:
logger.info("Cannot import bootstrap module: %s" % modname)
else:
dst_filename = change_prefix(filename, dst_prefix)
copyfile(filename, dst_filename, symlink)
if filename.endswith('.pyc'):
pyfile = filename[:-1]
if os.path.exists(pyfile):
copyfile(pyfile, dst_filename[:-1], symlink)
if f is not None:
f.close()
# special-case custom readline.so on OS X, but not for pypy:
if modname == 'readline' and sys.platform == 'darwin' and not (
is_pypy or filename.endswith(join('lib-dynload', 'readline.so'))):
dst_filename = join(dst_prefix, 'lib', 'python%s' % sys.version[:3], 'readline.so')
elif modname == 'readline' and sys.platform == 'win32':
# special-case for Windows, where readline is not a
# standard module, though it may have been installed in
# site-packages by a third-party package
pass
else:
dst_filename = change_prefix(filename, dst_prefix)
copyfile(filename, dst_filename, symlink)
if filename.endswith('.pyc'):
pyfile = filename[:-1]
if os.path.exists(pyfile):
copyfile(pyfile, dst_filename[:-1], symlink)
finally:
sys.path = _prev_sys_path
def subst_path(prefix_path, prefix, home_dir):

View File

@ -7069,5 +7069,68 @@
"kind": "count",
"keyed": true,
"description": "Counts of plugin and content process crashes which are reported with a crash dump."
},
"STUMBLER_TIME_BETWEEN_UPLOADS_SEC": {
"expires_in_version": "45",
"kind": "exponential",
"n_buckets": 50,
"high": 259200,
"description": "Stumbler: The time in seconds between uploads."
},
"STUMBLER_VOLUME_BYTES_UPLOADED_PER_SEC": {
"expires_in_version": "45",
"kind": "exponential",
"n_buckets": 50,
"high": 1000000,
"description": "Stumbler: Volume measurement of bytes uploaded, normalized to per-second."
},
"STUMBLER_TIME_BETWEEN_START_SEC": {
"expires_in_version": "45",
"kind": "exponential",
"n_buckets": 50,
"high": 259200,
"description": "Stumbler: The time between the service starts."
},
"STUMBLER_UPLOAD_BYTES": {
"expires_in_version": "45",
"kind": "exponential",
"n_buckets": 50,
"high": 1000000,
"description": "Stumbler: The bytes per upload."
},
"STUMBLER_UPLOAD_OBSERVATION_COUNT": {
"expires_in_version": "45",
"kind": "exponential",
"n_buckets": 50,
"high": 10000,
"description": "Stumbler: The observations per upload."
},
"STUMBLER_UPLOAD_CELL_COUNT": {
"expires_in_version": "45",
"kind": "exponential",
"n_buckets": 50,
"high": 10000,
"description": "Stumbler: The cells per upload."
},
"STUMBLER_UPLOAD_WIFI_AP_COUNT": {
"expires_in_version": "45",
"kind": "exponential",
"n_buckets": 50,
"high": 10000,
"description": "Stumbler: The Wi-Fi APs per upload."
},
"STUMBLER_OBSERVATIONS_PER_DAY": {
"expires_in_version": "45",
"kind": "exponential",
"n_buckets": 50,
"high": 10000,
"description": "Stumbler: The number of observations between upload events, normalized to per day."
},
"STUMBLER_TIME_BETWEEN_RECEIVED_LOCATIONS_SEC": {
"expires_in_version": "45",
"kind": "exponential",
"n_buckets": 50,
"high": 86400,
"description": "Stumbler: The time between receiving passive locations."
}
}

View File

@ -9,7 +9,6 @@
var { Ci, Cu, Cc, components } = require("chrome");
var Services = require("Services");
var promise = require("promise");
var { setTimeout } = require("Timer");
/**
* Turn the error |aError| into a string, without fail.
@ -121,7 +120,7 @@ exports.zip = function zip(a, b) {
*/
exports.executeSoon = function executeSoon(aFn) {
if (isWorker) {
setTimeout(aFn, 0);
require("Timer").setTimeout(aFn, 0);
} else {
Services.tm.mainThread.dispatch({
run: exports.makeInfallible(aFn)
@ -151,7 +150,7 @@ exports.waitForTick = function waitForTick() {
*/
exports.waitForTime = function waitForTime(aDelay) {
let deferred = promise.defer();
setTimeout(deferred.resolve, aDelay);
require("Timer").setTimeout(deferred.resolve, aDelay);
return deferred.promise;
};

View File

@ -10,25 +10,12 @@
let { Constructor: CC, classes: Cc, interfaces: Ci, utils: Cu } = Components;
// addDebuggerToGlobal only allows adding the Debugger object to a global. The
// this object is not guaranteed to be a global (in particular on B2G, due to
// compartment sharing), so add the Debugger object to a sandbox instead.
let sandbox = Cu.Sandbox(CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')());
Cu.evalInSandbox(
"Components.utils.import('resource://gre/modules/jsdebugger.jsm');" +
"addDebuggerToGlobal(this);",
sandbox
);
let Debugger = sandbox.Debugger;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console", "resource://gre/modules/devtools/Console.jsm");
let xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
let loader = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {}).Loader;
let promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
@ -40,23 +27,43 @@ this.EXPORTED_SYMBOLS = ["DevToolsLoader", "devtools", "BuiltinProvider",
* Providers are different strategies for loading the devtools.
*/
let Timer = Cu.import("resource://gre/modules/Timer.jsm", {});
let loaderModules = {
"Debugger": Debugger,
"Services": Object.create(Services),
"Timer": Object.create(Timer),
"toolkit/loader": loader,
"xpcInspector": xpcInspector,
"promise": promise,
"PromiseDebugging": PromiseDebugging
};
try {
let { indexedDB } = Cu.Sandbox(this, {wantGlobalProperties:["indexedDB"]});
loaderModules.indexedDB = indexedDB;
} catch(e) {
XPCOMUtils.defineLazyGetter(loaderModules, "Debugger", () => {
// addDebuggerToGlobal only allows adding the Debugger object to a global. The
// this object is not guaranteed to be a global (in particular on B2G, due to
// compartment sharing), so add the Debugger object to a sandbox instead.
let sandbox = Cu.Sandbox(CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')());
Cu.evalInSandbox(
"Components.utils.import('resource://gre/modules/jsdebugger.jsm');" +
"addDebuggerToGlobal(this);",
sandbox
);
return sandbox.Debugger;
});
XPCOMUtils.defineLazyGetter(loaderModules, "Timer", () => {
let {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
// Do not return Cu.import result, as SDK loader would freeze Timer.jsm globals...
return {
setTimeout,
clearTimeout
};
});
XPCOMUtils.defineLazyGetter(loaderModules, "xpcInspector", () => {
return Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
});
XPCOMUtils.defineLazyGetter(loaderModules, "indexedDB", () => {
// On xpcshell, we can't instantiate indexedDB without crashing
}
try {
return Cu.Sandbox(this, {wantGlobalProperties:["indexedDB"]}).indexedDB;
} catch(e) {
return {};
}
});
let sharedGlobalBlacklist = ["sdk/indexed-db"];
@ -356,7 +363,6 @@ DevToolsLoader.prototype = {
isWorker: false,
reportError: Cu.reportError,
btoa: btoa,
console: console,
_Iterator: Iterator,
loader: {
lazyGetter: this.lazyGetter,
@ -365,6 +371,10 @@ DevToolsLoader.prototype = {
lazyRequireGetter: this.lazyRequireGetter
},
};
// Lazy define console in order to load Console.jsm only when it is used
XPCOMUtils.defineLazyGetter(this._provider.globals, "console", () => {
return Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
});
this._provider.load();
this.require = loader.Require(this._provider.loader, { id: "devtools" });

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,23 @@
c(node, state);
};
// An ancestor walk builds up an array of ancestor nodes (including
// the current node) and passes them to the callback as the state parameter.
exports.ancestor = function(node, visitors, base, state) {
if (!base) base = exports.base;
if (!state) state = [];
function c(node, st, override) {
var type = override || node.type, found = visitors[type];
if (node != st[st.length - 1]) {
st = st.slice();
st.push(node);
}
base[type](node, st, c);
if (found) found(node, st);
}
c(node, state);
};
// A recursive walk is one where your functions override the default
// walkers. They can modify and replace the state parameter that's
// threaded through the walk, and can opt how and whether to walk
@ -180,10 +197,10 @@
c(cs.consequent[j], st, "Statement");
}
};
base.ReturnStatement = function(node, st, c) {
base.ReturnStatement = base.YieldExpression = function(node, st, c) {
if (node.argument) c(node.argument, st, "Expression");
};
base.ThrowStatement = function(node, st, c) {
base.ThrowStatement = base.SpreadElement = function(node, st, c) {
c(node.argument, st, "Expression");
};
base.TryStatement = function(node, st, c) {
@ -202,7 +219,7 @@
if (node.update) c(node.update, st, "Expression");
c(node.body, st, "Statement");
};
base.ForInStatement = function(node, st, c) {
base.ForInStatement = base.ForOfStatement = function(node, st, c) {
c(node.left, st, "ForInit");
c(node.right, st, "Expression");
c(node.body, st, "Statement");
@ -240,10 +257,10 @@
};
base.ObjectExpression = function(node, st, c) {
for (var i = 0; i < node.properties.length; ++i)
c(node.properties[i].value, st, "Expression");
c(node.properties[i], st);
};
base.FunctionExpression = base.FunctionDeclaration;
base.SequenceExpression = function(node, st, c) {
base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration;
base.SequenceExpression = base.TemplateLiteral = function(node, st, c) {
for (var i = 0; i < node.expressions.length; ++i)
c(node.expressions[i], st, "Expression");
};
@ -268,7 +285,28 @@
c(node.object, st, "Expression");
if (node.computed) c(node.property, st, "Expression");
};
base.Identifier = base.Literal = ignore;
base.Identifier = base.Literal = base.ExportDeclaration = base.ImportDeclaration = ignore;
base.TaggedTemplateExpression = function(node, st, c) {
c(node.tag, st, "Expression");
c(node.quasi, st);
};
base.ClassDeclaration = base.ClassExpression = function(node, st, c) {
if (node.superClass) c(node.superClass, st, "Expression");
for (var i = 0; i < node.body.body.length; i++)
c(node.body.body[i], st);
};
base.MethodDefinition = base.Property = function(node, st, c) {
if (node.computed) c(node.key, st, "Expression");
c(node.value, st, "Expression");
};
base.ComprehensionExpression = function(node, st, c) {
for (var i = 0; i < node.blocks.length; i++)
c(node.blocks[i].right, st, "Expression");
c(node.body, st, "Expression");
};
// NOTE: the stuff below is deprecated, and will be removed when 1.0 is released
// A custom walker that keeps track of the scope chain and the
// variables defined in it.

View File

@ -5,9 +5,11 @@
* http://opensource.org/licenses/BSD-2-Clause
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
"use strict";
if (typeof define === "function" && define.amd) {
define(factory);
} else if (typeof exports === 'object') {
} else if (typeof exports === "object") {
module.exports = factory();
} else {
root.prettyFast = factory();
@ -92,7 +94,9 @@
if (lastToken.type.isAssign) {
return true;
}
return !!PRE_ARRAY_LITERAL_TOKENS[lastToken.type.keyword || lastToken.type.type];
return !!PRE_ARRAY_LITERAL_TOKENS[
lastToken.type.keyword || lastToken.type.type
];
}
// If any of these tokens are followed by a token on a new line, we know that
@ -209,7 +213,9 @@
if (token.startLoc.line === lastToken.startLoc.line) {
return false;
}
if (PREVENT_ASI_AFTER_TOKENS[lastToken.type.type || lastToken.type.keyword]) {
if (PREVENT_ASI_AFTER_TOKENS[
lastToken.type.type || lastToken.type.keyword
]) {
return false;
}
if (PREVENT_ASI_BEFORE_TOKENS[token.type.type || token.type.keyword]) {
@ -490,8 +496,8 @@
}
/**
* Make sure that we output the escaped character combination inside string literals
* instead of various problematic characters.
* Make sure that we output the escaped character combination inside string
* literals instead of various problematic characters.
*/
var sanitize = (function () {
var escapeCharacters = {
@ -520,11 +526,11 @@
+ ")";
var escapeCharactersRegExp = new RegExp(regExpString, "g");
return function(str) {
return function (str) {
return str.replace(escapeCharactersRegExp, function (_, c) {
return escapeCharacters[c];
});
}
};
}());
/**
* Add the given token to the pretty printed results.
@ -533,14 +539,16 @@
* The token to add.
* @param Function write
* The function to write pretty printed code to the result SourceNode.
* @param Object options
* The options object.
*/
function addToken(token, write, options) {
function addToken(token, write) {
if (token.type.type == "string") {
write("'" + sanitize(token.value) + "'",
token.startLoc.line,
token.startLoc.column);
} else if (token.type.type == "regexp") {
write(String(token.value.value),
token.startLoc.line,
token.startLoc.column);
} else {
write(String(token.value != null ? token.value : token.type.type),
token.startLoc.line,
@ -584,7 +592,7 @@
*/
function decrementsIndent(tokenType, stack) {
return tokenType == "}"
|| (tokenType == "]" && stack[stack.length - 1] == "[\n")
|| (tokenType == "]" && stack[stack.length - 1] == "[\n");
}
/**
@ -690,12 +698,13 @@
for (var i = 0, len = buffer.length; i < len; i++) {
lineStr += buffer[i];
}
result.add(new SourceNode(bufferLine, bufferColumn, options.url, lineStr));
result.add(new SourceNode(bufferLine, bufferColumn, options.url,
lineStr));
buffer.splice(0, buffer.length);
bufferLine = -1;
bufferColumn = -1;
}
}
};
}());
// Whether or not we added a newline on after we added the last token.
@ -773,7 +782,7 @@
}
});
while (true) {
for (;;) {
token = getToken();
ttk = token.type.keyword;
@ -807,8 +816,8 @@
prependWhiteSpace(token, lastToken, addedNewline, write, options,
indentLevel, stack);
addToken(token, write, options);
if (commentQueue.length == 0 || !commentQueue[0].trailing) {
addToken(token, write);
if (commentQueue.length === 0 || !commentQueue[0].trailing) {
addedNewline = appendNewline(token, write, stack);
}

View File

@ -1,4 +1,4 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
"use strict";

View File

@ -10,15 +10,11 @@ const { Cc, Ci, Cu } = require("chrome");
const Services = require("Services");
const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/server/actors/common");
const { DebuggerServer } = require("devtools/server/main");
const { dumpProtocolSpec } = require("devtools/server/protocol");
const makeDebugger = require("./utils/make-debugger");
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
DevToolsUtils.defineLazyGetter(this, "StyleSheetActor", () => {
return require("devtools/server/actors/stylesheets").StyleSheetActor;
});
loader.lazyRequireGetter(this, "StyleSheetActor", "devtools/server/actors/stylesheets", true);
DevToolsUtils.defineLazyGetter(this, "ppmm", () => {
loader.lazyGetter(this, "ppmm", () => {
return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
});
@ -402,7 +398,9 @@ RootActor.prototype = {
return Cu.cloneInto(aRequest, {});
},
onProtocolDescription: dumpProtocolSpec,
onProtocolDescription: function () {
return require("devtools/server/protocol").dumpProtocolSpec();
},
/* Support for DebuggerServer.addGlobalActor. */
_createExtraActors: createExtraActors,

View File

@ -13,16 +13,22 @@ const { DebuggerServer } = require("devtools/server/main");
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
const { dbg_assert, dumpn, update, fetch } = DevToolsUtils;
const { dirname, joinURI } = require("devtools/toolkit/path");
const { SourceMapConsumer, SourceMapGenerator } = require("source-map");
const promise = require("promise");
const PromiseDebugging = require("PromiseDebugging");
const Debugger = require("Debugger");
const xpcInspector = require("xpcInspector");
const mapURIToAddonID = require("./utils/map-uri-to-addon-id");
const ScriptStore = require("./utils/ScriptStore");
const { defer, resolve, reject, all } = require("devtools/toolkit/deprecated-sync-thenables");
const { CssLogic } = require("devtools/styleinspector/css-logic");
loader.lazyGetter(this, "Debugger", () => {
let Debugger = require("Debugger");
hackDebugger(Debugger);
return Debugger;
});
loader.lazyRequireGetter(this, "SourceMapConsumer", "source-map", true);
loader.lazyRequireGetter(this, "SourceMapGenerator", "source-map", true);
loader.lazyRequireGetter(this, "CssLogic", "devtools/styleinspector/css-logic", true);
let TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array",
"Uint32Array", "Int8Array", "Int16Array", "Int32Array", "Float32Array",
@ -44,18 +50,18 @@ let OBJECT_PREVIEW_MAX_ITEMS = 10;
* - { state: "fulfilled", value }
* - { state: "rejected", reason }
*/
Debugger.Object.prototype.getPromiseState = function () {
if (this.class != "Promise") {
function getPromiseState(obj) {
if (obj.class != "Promise") {
throw new Error(
"Can't call `getPromiseState` on `Debugger.Object`s that don't " +
"refer to Promise objects.");
}
const state = PromiseDebugging.getState(this.unsafeDereference());
const state = PromiseDebugging.getState(obj.unsafeDereference());
return {
state: state.state,
value: this.makeDebuggeeValue(state.value),
reason: this.makeDebuggeeValue(state.reason)
value: obj.makeDebuggeeValue(state.value),
reason: obj.makeDebuggeeValue(state.reason)
};
};
@ -1191,7 +1197,7 @@ ThreadActor.prototype = {
*/
_breakOnEnter: function(script) {
let offsets = script.getAllOffsets();
let sourceActor = this.sources.source({ source: script.source });
let sourceActor = this.sources.createNonSourceMappedActor(script.source);
for (let line = 0, n = offsets.length; line < n; line++) {
if (offsets[line]) {
@ -1342,7 +1348,7 @@ ThreadActor.prototype = {
}
}
return all([this.sources.sourcesForScript(script)
return all([this.sources.createSourceActors(script.source)
for (script of sourcesToScripts.values())]);
},
@ -1957,8 +1963,6 @@ ThreadActor.prototype = {
* A Debugger.Object instance whose referent is the global object.
*/
onNewScript: function (aScript, aGlobal) {
this.sources.sourcesForScript(aScript);
// XXX: The scripts must be added to the ScriptStore before restoring
// breakpoints in _addScript. If we try to add them to the ScriptStore
// inside _addScript, we can accidentally set a breakpoint in a top level
@ -2023,9 +2027,8 @@ ThreadActor.prototype = {
}
// Set any stored breakpoints.
let endLine = aScript.startLine + aScript.lineCount - 1;
let source = this.sources.source({ source: aScript.source });
let source = this.sources.createNonSourceMappedActor(aScript.source);
for (let bpActor of this.breakpointActorMap.findActors({ source: source.form() })) {
// Limit the search to the line numbers contained in the new script.
if (bpActor.location.line >= aScript.startLine
@ -2034,6 +2037,11 @@ ThreadActor.prototype = {
}
}
// Go ahead and establish the source actors for this script, which
// fetches sourcemaps if available and sends onNewSource
// notifications
this.sources.createSourceActors(aScript.source);
return true;
},
@ -3245,7 +3253,7 @@ let stringifiers = {
'nsresult: "0x' + result + ' (' + name + ')"]';
},
Promise: obj => {
const { state, value, reason } = obj.getPromiseState();
const { state, value, reason } = getPromiseState(obj);
let statePreview = state;
if (state != "pending") {
const settledValue = state === "fulfilled" ? value : reason;
@ -3293,7 +3301,7 @@ ObjectActor.prototype = {
if (this.obj.class != "DeadObject") {
// Expose internal Promise state.
if (this.obj.class == "Promise") {
const { state, value, reason } = this.obj.getPromiseState();
const { state, value, reason } = getPromiseState(this.obj);
g.promiseState = { state };
if (state == "fulfilled") {
g.promiseState.value = this.threadActor.createValueGrip(value);
@ -4979,44 +4987,54 @@ EnvironmentActor.prototype.requestTypes = {
exports.EnvironmentActor = EnvironmentActor;
/**
* Override the toString method in order to get more meaningful script output
* for debugging the debugger.
*/
Debugger.Script.prototype.toString = function() {
let output = "";
if (this.url) {
output += this.url;
}
if (typeof this.staticLevel != "undefined") {
output += ":L" + this.staticLevel;
}
if (typeof this.startLine != "undefined") {
output += ":" + this.startLine;
if (this.lineCount && this.lineCount > 1) {
output += "-" + (this.startLine + this.lineCount - 1);
}
}
if (this.strictMode) {
output += ":strict";
}
return output;
};
function hackDebugger(Debugger) {
// TODO: Improve native code instead of hacking on top of it
/**
* Helper property for quickly getting to the line number a stack frame is
* currently paused at.
*/
Object.defineProperty(Debugger.Frame.prototype, "line", {
configurable: true,
get: function() {
if (this.script) {
return this.script.getOffsetLine(this.offset);
} else {
return null;
/**
* Override the toString method in order to get more meaningful script output
* for debugging the debugger.
*/
Debugger.Script.prototype.toString = function() {
let output = "";
if (this.url) {
output += this.url;
}
}
});
if (typeof this.staticLevel != "undefined") {
output += ":L" + this.staticLevel;
}
if (typeof this.startLine != "undefined") {
output += ":" + this.startLine;
if (this.lineCount && this.lineCount > 1) {
output += "-" + (this.startLine + this.lineCount - 1);
}
}
if (typeof this.startLine != "undefined") {
output += ":" + this.startLine;
if (this.lineCount && this.lineCount > 1) {
output += "-" + (this.startLine + this.lineCount - 1);
}
}
if (this.strictMode) {
output += ":strict";
}
return output;
};
/**
* Helper property for quickly getting to the line number a stack frame is
* currently paused at.
*/
Object.defineProperty(Debugger.Frame.prototype, "line", {
configurable: true,
get: function() {
if (this.script) {
return this.script.getOffsetLine(this.offset);
} else {
return null;
}
}
});
}
/**
@ -5107,7 +5125,10 @@ function ThreadSources(aThreadActor, aOptions, aAllowPredicate,
this._useSourceMaps = aOptions.useSourceMaps;
this._autoBlackBox = aOptions.autoBlackBox;
this._allow = aAllowPredicate;
this._onNewSource = aOnNewSource;
this._onNewSource = DevToolsUtils.makeInfallible(
aOnNewSource,
"ThreadSources.prototype._onNewSource"
);
this._anonSourceMapId = 1;
// generated Debugger.Source -> promise of SourceMapConsumer
@ -5222,21 +5243,35 @@ ThreadSources.prototype = {
this._sourceMappedSourceActors[originalUrl] = actor;
}
// Don't notify a new source if it's a generated one, as it has
// sourcemapped sources. The generated one is created to set
// breakpoints.
if (!source || !this._sourceMaps.has(source)) {
try {
this._onNewSource(actor);
} catch (e) {
reportError(e);
}
}
this._emitNewSource(actor);
return actor;
},
getSource: function(source) {
_emitNewSource: function(actor) {
if(!actor.source) {
// Always notify if we don't have a source because that means
// it's something that has been sourcemapped, or it represents
// the HTML file that contains inline sources.
this._onNewSource(actor);
}
else {
// If sourcemapping is enabled and a source has sourcemaps, we
// create `SourceActor` instances for both the original and
// generated sources. The source actors for the generated
// sources are only for internal use, however; breakpoints are
// managed by these internal actors. We only want to notify the
// user of the original sources though, so if the actor has a
// `Debugger.Source` instance and a valid source map (meaning
// it's a generated source), don't send the notification.
this.fetchSourceMap(actor.source).then(map => {
if(!map) {
this._onNewSource(actor);
}
});
}
},
getSourceActor: function(source) {
if (source.url in this._sourceMappedSourceActors) {
return this._sourceMappedSourceActors[source.url];
}
@ -5249,7 +5284,7 @@ ThreadSources.prototype = {
(source.url || 'source'));
},
getSourceByURL: function(url) {
getSourceActorByURL: function(url) {
if (url) {
for (let [source, actor] of this._sourceActors) {
if (source.url === url) {
@ -5286,15 +5321,23 @@ ThreadSources.prototype = {
},
/**
* Only to be used when we aren't source mapping.
* Create a source actor representing this source. This ignores
* source mapping and always returns an actor representing this real
* source. Use `createSourceActors` if you want to respect source maps.
*
* @param Debugger.Source aSource
* The source instance to create an actor for.
* @returns SourceActor
*/
_sourceForScript: function (aScript) {
createNonSourceMappedActor: function (aSource) {
// Don't use getSourceURL because we don't want to consider the
// displayURL property if it's an eval source
let url = isEvalSource(aScript.source) ? null : aScript.source.url;
let spec = {
source: aScript.source
};
// displayURL property if it's an eval source. We only want to
// consider real URLs, otherwise if there is a URL but it's
// invalid the code below will not set the content type, and we
// will later try to fetch the contents of the URL to figure out
// the content type, but it's a made up URL for eval sources.
let url = isEvalSource(aSource) ? null : aSource.url;
let spec = { source: aSource };
// XXX bug 915433: We can't rely on Debugger.Source.prototype.text
// if the source is an HTML-embedded <script> tag. Since we don't
@ -5324,31 +5367,48 @@ ThreadSources.prototype = {
},
/**
* Return a promise of an array of source actors representing all the
* sources of |aScript|.
* This is an internal function that returns a promise of an array
* of source actors representing all the source mapped sources of
* `aSource`, or `null` if the source is not sourcemapped or
* sourcemapping is disabled. Users should call `createSourceActors`
* instead of this.
*
* If source map handling is enabled and |aScript| has a source map, then
* use it to find all of |aScript|'s *original* sources; return a promise
* of an array of source actors for those.
* @param Debugger.Source aSource
* The source instance to create actors for.
* @return Promise of an array of source actors
*/
sourcesForScript: function (aScript) {
if (!this._useSourceMaps || !aScript.source.sourceMapURL) {
return resolve([this._sourceForScript(aScript)].filter(isNotNull));
_createSourceMappedActors: function (aSource) {
if (!this._useSourceMaps || !aSource.sourceMapURL) {
return resolve(null);
}
return this.fetchSourceMap(aScript.source)
return this.fetchSourceMap(aSource)
.then(map => {
if (map) {
return [
this.source({ originalUrl: s,
generatedSource: aScript.source })
this.source({ originalUrl: s, generatedSource: aSource })
for (s of map.sources)
];
].filter(isNotNull);
}
return null;
});
},
return [this._sourceForScript(aScript)];
})
.then(ss => ss.filter(isNotNull));
/**
* Creates the source actors representing the appropriate sources
* of `aSource`. If sourcemapped, returns actors for all of the original
* sources, otherwise returns a 1-element array with the actor for
* `aSource`.
*
* @param Debugger.Source aSource
* The source instance to create actors for.
* @param Promise of an array of source actors
*/
createSourceActors: function(aSource) {
return this._createSourceMappedActors(aSource).then(actors => {
let actor = this.createNonSourceMappedActor(aSource);
return (actors || [actor]).filter(isNotNull);
});
},
/**
@ -5356,6 +5416,10 @@ ThreadSources.prototype = {
* `aSource`; if we already have such a promise extant, return that.
* This will fetch the source map if we don't have a cached object
* and source maps are enabled (see `_fetchSourceMap`).
*
* @param Debugger.Source aSource
* The source instance to get sourcemaps for.
* @return Promise of a SourceMapConsumer
*/
fetchSourceMap: function (aSource) {
if (this._sourceMaps.has(aSource)) {
@ -5369,13 +5433,12 @@ ThreadSources.prototype = {
if (aSource.url) {
sourceMapURL = this._normalize(sourceMapURL, aSource.url);
}
let result = this._fetchSourceMap(sourceMapURL, aSource.url);
let map = this._fetchSourceMap(sourceMapURL, aSource.url);
if (map) {
this._sourceMaps.set(aSource, map);
return map;
}
return resolve(null);
// The promises in `_sourceMaps` must be the exact same instances
// as returned by `_fetchSourceMap` for `clearSourceMapCache` to work.
this._sourceMaps.set(aSource, result);
return result;
},
/**
@ -5413,7 +5476,7 @@ ThreadSources.prototype = {
return this._sourceMapCache[aAbsSourceMapURL];
}
else if (!this._useSourceMaps) {
return null;
return resolve(null);
}
let fetching = fetch(aAbsSourceMapURL, { loadFromCache: false })
@ -5424,7 +5487,7 @@ ThreadSources.prototype = {
})
.then(null, error => {
if (!DevToolsUtils.reportingDisabled) {
DevToolsUtils.reportException("ThreadSources.prototype.getOriginalLocation", error);
DevToolsUtils.reportException("ThreadSources.prototype._fetchSourceMap", error);
}
return null;
});
@ -5517,7 +5580,10 @@ ThreadSources.prototype = {
/**
* Returns a promise of the location in the original source if the source is
* source mapped, otherwise a promise of the same location.
* source mapped, otherwise a promise of the same location. This can
* be called with a source from *any* Debugger instance and we make
* sure to that it works properly, reusing source maps if already
* fetched. Use this from any actor that needs sourcemapping.
*/
getOriginalLocation: function ({ source, line, column }) {
// In certain scenarios the source map may have not been fetched
@ -5538,7 +5604,17 @@ ThreadSources.prototype = {
});
return {
sourceActor: sourceUrl && this.source({ originalUrl: sourceUrl }),
// Since the `Debugger.Source` instance may come from a
// different `Debugger` instance (any actor can call this
// method), we can't rely on any of the source discovery
// setup (`_discoverSources`, etc) to have been run yet. So
// we have to assume that the actor may not already exist,
// and we might need to create it, so use `source` and give
// it the required parameters for a sourcemapped source.
sourceActor: (!sourceUrl) ? null : this.source({
originalUrl: sourceUrl,
generatedSource: source
}),
url: sourceUrl,
line: sourceLine,
column: sourceCol,
@ -5548,9 +5624,7 @@ ThreadSources.prototype = {
// No source map
return resolve({
// Don't use `getSource` because sources may have not been
// created yet
sourceActor: this.source({ source }),
sourceActor: this.createNonSourceMappedActor(source),
url: source.url,
line: line,
column: column
@ -5584,9 +5658,7 @@ ThreadSources.prototype = {
});
return {
// Don't use `getSource` because this could intentionally
// create a generated source
sourceActor: this.source({ source: source }),
sourceActor: this.createNonSourceMappedActor(source),
line: genLine,
column: genColumn
};

View File

@ -1,5 +1,5 @@
/**
* web-audio-automation-timeline - 1.0.2
* web-audio-automation-timeline - 1.0.3
* https://github.com/jsantell/web-audio-automation-timeline
* MIT License, copyright (c) 2014 Jordan Santell
*/
@ -68,6 +68,8 @@ exports.fuzzyEqual = function (lhs, rhs) {
return Math.abs(lhs - rhs) < EPSILON;
};
exports.EPSILON = EPSILON;
},{}],4:[function(require,module,exports){
var TimelineEvent = require("./event").TimelineEvent;
var F = require("./formulas");
@ -78,11 +80,6 @@ function Timeline (defaultValue) {
this.events = [];
this._value = defaultValue || 0;
// This is the value of this AudioParam we computed at the last call.
this._computedValue = defaultValue || 0;
// This is the value of this AudioParam at the last tick of the previous event.
this._lastComputedValue = defaultValue || 0;
}
Timeline.prototype.getEventCount = function () {
@ -95,7 +92,7 @@ Timeline.prototype.value = function () {
Timeline.prototype.setValue = function (value) {
if (this.events.length === 0) {
this._computedValue = this._lastComputedValue = this._value = value;
this._value = value;
}
};
@ -108,21 +105,19 @@ Timeline.prototype.getValue = function () {
};
Timeline.prototype.getValueAtTime = function (time) {
this._computedValue = this._getValueAtTimeHelper(time);
return this._computedValue;
return this._getValueAtTimeHelper(time);
};
Timeline.prototype._getValueAtTimeHelper = function (time) {
var bailOut = false;
var previous = null;
var next = null;
var lastComputedValue = null; // Used for `setTargetAtTime` nodes
var events = this.events;
var e;
for (var i = 0; !bailOut && i < events.length; i++) {
if (F.fuzzyEqual(time, events[i].time)) {
this._lastComputedValue = this._computedValue;
// Find the last event with the same time as `time`
do {
++i;
@ -132,7 +127,8 @@ Timeline.prototype._getValueAtTimeHelper = function (time) {
// `setTargetAtTime` can be handled no matter what their next event is (if they have one)
if (e.type === "setTargetAtTime") {
return e.exponentialApproach(this._lastComputedValue, time);
lastComputedValue = this._lastComputedValue(e);
return e.exponentialApproach(lastComputedValue, time);
}
// `setValueCurveAtTime` events can be handled no matter what their next event node is
@ -170,7 +166,8 @@ Timeline.prototype._getValueAtTimeHelper = function (time) {
// `setTargetAtTime` can be handled no matter what their next event is (if they have one)
if (previous.type === "setTargetAtTime") {
return previous.exponentialApproach(this._lastComputedValue, time);
lastComputedValue = this._lastComputedValue(previous);
return previous.exponentialApproach(lastComputedValue, time);
}
// `setValueCurveAtTime` events can be handled no matter what their next event node is
@ -316,6 +313,29 @@ Timeline.prototype._getPreviousEvent = function (time) {
return previous;
};
/**
* Calculates the previous value of the timeline, used for
* `setTargetAtTime` nodes. Takes an event, and returns
* the previous computed value for any sample taken during that
* exponential approach node.
*/
Timeline.prototype._lastComputedValue = function (event) {
// If equal times, return the value for the previous event, before
// the `setTargetAtTime` node.
var lastEvent = this._getPreviousEvent(event.time - F.EPSILON);
// If no event before the setTargetAtTime event, then return the
// intrinsic value.
if (!lastEvent) {
return this._value;
}
// Otherwise, return the value for the previous event, which should
// always be the last computed value (? I think?)
else {
return lastEvent.value;
}
};
Timeline.prototype.setValueAtTime = function (value, startTime) {
this._insertEvent(new TimelineEvent("setValueAtTime", value, startTime));
};

View File

@ -10,7 +10,6 @@ let { Ci, Cu } = require("chrome");
let Services = require("Services");
let { ActorPool, createExtraActors, appendExtraActors } = require("devtools/server/actors/common");
let { RootActor } = require("devtools/server/actors/root");
let { AddonThreadActor, ThreadActor } = require("devtools/server/actors/script");
let { DebuggerServer } = require("devtools/server/main");
let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
let { dbg_assert } = DevToolsUtils;
@ -20,18 +19,16 @@ let mapURIToAddonID = require("./utils/map-uri-to-addon-id");
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
loader.lazyRequireGetter(this, "AddonThreadActor", "devtools/server/actors/script", true);
loader.lazyRequireGetter(this, "ThreadActor", "devtools/server/actors/script", true);
loader.lazyImporter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
// Assumptions on events module:
// events needs to be dispatched synchronously,
// by calling the listeners in the order or registration.
XPCOMUtils.defineLazyGetter(this, "events", () => {
return require("sdk/event/core");
});
loader.lazyRequireGetter(this, "events", "sdk/event/core");
XPCOMUtils.defineLazyGetter(this, "StyleSheetActor", () => {
return require("devtools/server/actors/stylesheets").StyleSheetActor;
});
loader.lazyRequireGetter(this, "StyleSheetActor", "devtools/server/actors/stylesheets", true);
function getWindowID(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)

View File

@ -33,7 +33,6 @@ this.Cc = Cc;
this.CC = CC;
this.Cu = Cu;
this.Cr = Cr;
this.Debugger = Debugger;
this.Services = Services;
this.ActorPool = ActorPool;
this.DevToolsUtils = DevToolsUtils;
@ -76,7 +75,8 @@ function loadSubScript(aURL)
}
}
let events = require("sdk/event/core");
loader.lazyRequireGetter(this, "events", "sdk/event/core");
let {defer, resolve, reject, all} = require("devtools/toolkit/deprecated-sync-thenables");
this.defer = defer;
this.resolve = resolve;
@ -176,7 +176,7 @@ var DebuggerServer = {
this._initialized = true;
},
protocol: require("devtools/server/protocol"),
get protocol() require("devtools/server/protocol"),
/**
* Initialize the debugger server's transport variables. This can be

View File

@ -307,11 +307,32 @@ if (typeof Components === "object") {
const xpcInspector = Cc["@mozilla.org/jsinspector;1"].
getService(Ci.nsIJSInspector);
this.worker = new WorkerDebuggerLoader({
let worker = this.worker = new WorkerDebuggerLoader({
createSandbox: createSandbox,
globals: {
"isWorker": true,
"reportError": Cu.reportError,
"loader": {
lazyGetter: function (aObject, aName, aLambda) {
Object.defineProperty(aObject, aName, {
get: function () {
delete aObject[aName];
return aObject[aName] = aLambda.apply(aObject);
},
configurable: true,
enumerable: true
});
},
lazyImporter: function () { throw new Error("Can't import JSM from worker debugger server") },
lazyServiceGetter: function () { throw new Error("Can't import XPCOM from worker debugger server") },
lazyRequireGetter: function (obj, property, module, destructure) {
Object.defineProperty(obj, property, {
get: () => destructure
? worker.require(module)[property]
: worker.require(module || property)
});
}
}
},
loadInSandbox: loadInSandbox,
modules: {

View File

@ -31,6 +31,10 @@ xul|*.help-button > xul|*.button-box > xul|*.button-icon {
-moz-margin-end: 0;
}
xul|*.groupbox-body {
-moz-padding-start: 0;
}
xul|menulist {
font-size: inherit;
}

View File

@ -20,6 +20,16 @@ xul|menulist {
margin-top: 3px;
}
xul|button {
/* use the same margin of other elements for the alignment */
margin-left: 4px;
margin-right: 4px;
}
xul|groupbox > xul|*.groupbox-body {
padding: 0;
}
xul|menulist:not([editable="true"]) > xul|menupopup > xul|menuitem[checked="true"]::before,
xul|menulist:not([editable="true"]) > xul|menupopup > xul|menuitem[selected="true"]::before {
display: none;

View File

@ -40,8 +40,15 @@ xul|caption > xul|label {
margin: 0 !important;
}
xul|description {
-moz-margin-start: 0;
}
*|*.main-content {
padding: 40px 48px 48px;
padding-top: 40px;
-moz-padding-end: 44px; /* compensate the 4px margin of child elements */
padding-bottom: 48px;
-moz-padding-start: 48px;
overflow: auto;
}
@ -54,9 +61,7 @@ xul|prefpane > xul|*.content-box {
xul|groupbox {
-moz-appearance: none;
border: none;
margin-top: 15px;
margin-bottom: 15px;
-moz-margin-end: 0;
margin: 15px 0;
-moz-padding-start: 0;
-moz-padding-end: 0;
font-size: 1.25rem;
@ -524,6 +529,7 @@ xul|*#categories[keyboard-navigation="true"]:-moz-focusring > xul|*.category[cur
*|*.header {
border-bottom: 1px solid #c8c8c8;
-moz-margin-end: 4px; /* add the 4px end-margin of other elements */
margin-bottom: 15px;
padding-bottom: 15px;
}
@ -584,6 +590,7 @@ xul|filefield + xul|button {
xul|richlistbox,
xul|listbox {
-moz-appearance: none;
-moz-margin-start: 0;
background-color: #fff;
border: 1px solid #c1c1c1;
color: #333;