зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
e232fcd2d4
|
@ -1291,9 +1291,6 @@ var gBrowserInit = {
|
|||
|
||||
gBrowserThumbnails.init();
|
||||
|
||||
// Add Devtools menuitems and listeners
|
||||
gDevToolsBrowser.registerBrowserWindow(window);
|
||||
|
||||
gMenuButtonBadgeManager.init();
|
||||
|
||||
gMenuButtonUpdateBadge.init();
|
||||
|
@ -1407,8 +1404,6 @@ var gBrowserInit = {
|
|||
if (!this._loadHandled)
|
||||
return;
|
||||
|
||||
gDevToolsBrowser.forgetBrowserWindow(window);
|
||||
|
||||
let desc = Object.getOwnPropertyDescriptor(window, "DeveloperToolbar");
|
||||
if (desc && !desc.get) {
|
||||
DeveloperToolbar.destroy();
|
||||
|
@ -2702,8 +2697,7 @@ var BrowserOnClick = {
|
|||
break;
|
||||
case "Browser:SendSSLErrorReport":
|
||||
this.onSSLErrorReport(msg.target,
|
||||
msg.data.documentURI,
|
||||
msg.data.location,
|
||||
msg.data.uri,
|
||||
msg.data.securityInfo);
|
||||
break;
|
||||
case "Browser:SetSSLErrorReportAuto":
|
||||
|
@ -2723,7 +2717,7 @@ var BrowserOnClick = {
|
|||
let weakCryptoOverride = Cc["@mozilla.org/security/weakcryptooverride;1"]
|
||||
.getService(Ci.nsIWeakCryptoOverride);
|
||||
weakCryptoOverride.addWeakCryptoOverride(
|
||||
msg.data.location.hostname,
|
||||
msg.data.uri.host,
|
||||
PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser));
|
||||
break;
|
||||
case "Browser:SSLErrorGoBack":
|
||||
|
@ -2732,7 +2726,7 @@ var BrowserOnClick = {
|
|||
}
|
||||
},
|
||||
|
||||
onSSLErrorReport: function(browser, documentURI, location, securityInfo) {
|
||||
onSSLErrorReport: function(browser, uri, securityInfo) {
|
||||
if (!Services.prefs.getBoolPref("security.ssl.errorReporting.enabled")) {
|
||||
Cu.reportError("User requested certificate error report sending, but certificate error reporting is disabled");
|
||||
return;
|
||||
|
@ -2745,11 +2739,8 @@ var BrowserOnClick = {
|
|||
|
||||
let errorReporter = Cc["@mozilla.org/securityreporter;1"]
|
||||
.getService(Ci.nsISecurityReporter);
|
||||
// if location.port is the empty string, set to -1 (for consistency with
|
||||
// port values from nsIURI)
|
||||
let port = location.port === "" ? -1 : location.port;
|
||||
errorReporter.reportTLSError(transportSecurityInfo,
|
||||
location.hostname, port);
|
||||
uri.host, uri.port);
|
||||
},
|
||||
|
||||
onAboutCertError: function (browser, elementId, isTopFrame, location, securityInfoAsString) {
|
||||
|
@ -6543,6 +6534,10 @@ var gIdentityHandler = {
|
|||
return this._state & Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT;
|
||||
},
|
||||
|
||||
get _isCertUserOverridden() {
|
||||
return this._state & Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN;
|
||||
},
|
||||
|
||||
get _hasInsecureLoginForms() {
|
||||
// checks if the page has been flagged for an insecure login. Also checks
|
||||
// if the pref to degrade the UI is set to true
|
||||
|
@ -6832,23 +6827,14 @@ var gIdentityHandler = {
|
|||
if (this._isMixedActiveContentBlocked) {
|
||||
this._identityBox.classList.add("mixedActiveBlocked");
|
||||
}
|
||||
|
||||
let iData = this.getIdentityData();
|
||||
|
||||
// Verifier is either the CA Org, for a normal cert, or a special string
|
||||
// for certs that are trusted because of a security exception.
|
||||
tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
|
||||
[iData.caOrg]);
|
||||
|
||||
let host = this._uri.host;
|
||||
let port = 443;
|
||||
try {
|
||||
if (this._uri.port > 0)
|
||||
port = this._uri.port;
|
||||
} catch (e) {}
|
||||
|
||||
if (this._overrideService.hasMatchingOverride(host, port, iData.cert, {}, {})) {
|
||||
if (this._isCertUserOverridden) {
|
||||
this._identityBox.classList.add("certUserOverridden");
|
||||
// Cert is trusted because of a security exception, verifier is a special string.
|
||||
tooltip = gNavigatorBundle.getString("identity.identified.verified_by_you");
|
||||
} else {
|
||||
// It's a normal cert, verifier is the CA Org.
|
||||
tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
|
||||
[this.getIdentityData().caOrg]);
|
||||
}
|
||||
} else {
|
||||
this._identityBox.className = "unknownIdentity";
|
||||
|
@ -6952,6 +6938,8 @@ var gIdentityHandler = {
|
|||
connection = "file";
|
||||
} else if (this._isEV) {
|
||||
connection = "secure-ev";
|
||||
} else if (this._isCertUserOverridden) {
|
||||
connection = "secure-cert-user-overridden";
|
||||
} else if (this._isSecure) {
|
||||
connection = "secure";
|
||||
}
|
||||
|
|
|
@ -99,7 +99,8 @@ var handleContentContextMenu = function (event) {
|
|||
Services.obs.notifyObservers(subject, "content-contextmenu", null);
|
||||
|
||||
let doc = event.target.ownerDocument;
|
||||
let docLocation = doc.location ? doc.location.href : undefined;
|
||||
let docLocation = doc.mozDocumentURIIfNotForErrorPages;
|
||||
docLocation = docLocation && docLocation.spec;
|
||||
let charSet = doc.characterSet;
|
||||
let baseURI = doc.baseURI;
|
||||
let referrer = doc.referrer;
|
||||
|
@ -276,9 +277,6 @@ var AboutCertErrorListener = {
|
|||
|
||||
// if we're enabling reports, send a report for this failure
|
||||
if (event.detail) {
|
||||
let doc = content.document;
|
||||
let location = doc.location.href;
|
||||
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
|
||||
|
@ -288,9 +286,9 @@ var AboutCertErrorListener = {
|
|||
|
||||
let serializedSecurityInfo = serhelper.serializeToString(serializable);
|
||||
|
||||
let {host, port} = content.document.mozDocumentURIIfNotForErrorPages;
|
||||
sendAsyncMessage("Browser:SendSSLErrorReport", {
|
||||
documentURI: doc.documentURI,
|
||||
location: {hostname: doc.location.hostname, port: doc.location.port},
|
||||
uri: { host, port },
|
||||
securityInfo: serializedSecurityInfo
|
||||
});
|
||||
}
|
||||
|
@ -349,10 +347,6 @@ var AboutNetErrorListener = {
|
|||
|
||||
// if we're enabling reports, send a report for this failure
|
||||
if (evt.detail) {
|
||||
let contentDoc = content.document;
|
||||
|
||||
let location = contentDoc.location.href;
|
||||
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
|
||||
|
@ -362,12 +356,9 @@ var AboutNetErrorListener = {
|
|||
|
||||
let serializedSecurityInfo = serhelper.serializeToString(serializable);
|
||||
|
||||
let {host, port} = content.document.mozDocumentURIIfNotForErrorPages;
|
||||
sendAsyncMessage("Browser:SendSSLErrorReport", {
|
||||
documentURI: contentDoc.documentURI,
|
||||
location: {
|
||||
hostname: contentDoc.location.hostname,
|
||||
port: contentDoc.location.port
|
||||
},
|
||||
uri: { host, port },
|
||||
securityInfo: serializedSecurityInfo
|
||||
});
|
||||
|
||||
|
@ -375,13 +366,8 @@ var AboutNetErrorListener = {
|
|||
},
|
||||
|
||||
onOverride: function(evt) {
|
||||
let contentDoc = content.document;
|
||||
let location = contentDoc.location;
|
||||
|
||||
sendAsyncMessage("Browser:OverrideWeakCrypto", {
|
||||
documentURI: contentDoc.documentURI,
|
||||
location: {hostname: location.hostname, port: location.port}
|
||||
});
|
||||
let {host, port} = content.document.mozDocumentURIIfNotForErrorPages;
|
||||
sendAsyncMessage("Browser:OverrideWeakCrypto", { uri: {host, port} });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -688,8 +688,9 @@ Sanitizer.PREF_SANITIZE_ON_SHUTDOWN = "privacy.sanitize.sanitizeOnShutdown";
|
|||
// by a crash.
|
||||
Sanitizer.PREF_SANITIZE_IN_PROGRESS = "privacy.sanitize.sanitizeInProgress";
|
||||
// Whether the previous shutdown sanitization completed successfully.
|
||||
// Note that PREF_SANITIZE_IN_PROGRESS would be enough to detect an interrupted
|
||||
// sanitization, but this is still supported for backwards compatibility.
|
||||
// This is used to detect cases where we were supposed to sanitize on shutdown
|
||||
// but due to a crash we were unable to. In such cases there may not be any
|
||||
// sanitization in progress, cause we didn't have a chance to start it yet.
|
||||
Sanitizer.PREF_SANITIZE_DID_SHUTDOWN = "privacy.sanitize.didShutdownSanitize";
|
||||
|
||||
// Time span constants corresponding to values of the privacy.sanitize.timeSpan
|
||||
|
@ -779,10 +780,14 @@ Sanitizer.onStartup = Task.async(function*() {
|
|||
let shutownSanitizationWasInterrupted =
|
||||
Preferences.get(Sanitizer.PREF_SANITIZE_ON_SHUTDOWN, false) &&
|
||||
!Preferences.has(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN);
|
||||
// Regardless, reset the pref, since we want to check it at the next startup
|
||||
// even if the browser exits abruptly.
|
||||
Preferences.reset(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN);
|
||||
Services.prefs.savePrefFile(null);
|
||||
|
||||
if (Preferences.has(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN)) {
|
||||
// Reset the pref, so that if we crash before having a chance to
|
||||
// sanitize on shutdown, we will do at the next startup.
|
||||
// Flushing prefs has a cost, so do this only if necessary.
|
||||
Preferences.reset(Sanitizer.PREF_SANITIZE_DID_SHUTDOWN);
|
||||
Services.prefs.savePrefFile(null);
|
||||
}
|
||||
|
||||
// Make sure that we are triggered during shutdown, at the right time,
|
||||
// and only once.
|
||||
|
@ -804,7 +809,7 @@ Sanitizer.onStartup = Task.async(function*() {
|
|||
}
|
||||
placesClient.addBlocker("sanitize.js: Sanitize on shutdown", doSanitize);
|
||||
|
||||
// Check if Firefox crashed before completing a sanitization.
|
||||
// Check if Firefox crashed during a sanitization.
|
||||
let lastInterruptedSanitization = Preferences.get(Sanitizer.PREF_SANITIZE_IN_PROGRESS, "");
|
||||
if (lastInterruptedSanitization) {
|
||||
let s = new Sanitizer();
|
||||
|
@ -812,11 +817,9 @@ Sanitizer.onStartup = Task.async(function*() {
|
|||
let itemsToClear = JSON.parse(lastInterruptedSanitization);
|
||||
yield s.sanitize(itemsToClear);
|
||||
} else if (shutownSanitizationWasInterrupted) {
|
||||
// Ideally lastInterruptedSanitization should always be set when a
|
||||
// sanitization is interrupted, but some add-ons or Firefox previous
|
||||
// versions may not set the pref.
|
||||
// In such a case, we can still detect an interrupted shutdown sanitization,
|
||||
// and just redo it.
|
||||
// Otherwise, could be we were supposed to sanitize on shutdown but we
|
||||
// didn't have a chance, due to an earlier crash.
|
||||
// In such a case, just redo a shutdown sanitize now, during startup.
|
||||
yield Sanitizer.onShutdown();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -64,6 +64,11 @@ SocialErrorListener = {
|
|||
},
|
||||
|
||||
receiveMessage(message) {
|
||||
if (!content) {
|
||||
Cu.reportError("Message received whilst `content` is null: " + message.name);
|
||||
return;
|
||||
}
|
||||
|
||||
let document = content.document;
|
||||
|
||||
switch (message.name) {
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
var chatbar = document.getElementById("pinnedchats");
|
||||
|
||||
add_chat_task(function* testOpenCloseChat() {
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
const CHAT_URL = "https://example.com/browser/browser/base/content/test/chat/chat.html";
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
// Is the currently opened tab focused?
|
||||
function isTabFocused() {
|
||||
let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
|
||||
|
|
|
@ -155,6 +155,7 @@ skip-if = os == "mac" # The Fitt's Law back button is not supported on OS X
|
|||
[browser_beforeunload_duplicate_dialogs.js]
|
||||
[browser_blob-channelname.js]
|
||||
[browser_bookmark_popup.js]
|
||||
skip-if = (os == "linux" && debug) # mouseover not reliable on linux debug builds
|
||||
[browser_bookmark_titles.js]
|
||||
skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)
|
||||
[browser_bug304198.js]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// a bad certificate, being redirected to the internal about:certerror page,
|
||||
// using the button contained therein to load the certificate exception
|
||||
// dialog, using that to add an exception, and finally successfully visiting
|
||||
// the site.
|
||||
// the site, including showing the right identity box and control center icons.
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
whenNewTabLoaded(window, loadBadCertPage);
|
||||
|
@ -67,6 +67,7 @@ var certExceptionDialogObserver = {
|
|||
var successfulLoadListener = {
|
||||
handleEvent: function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", this, true);
|
||||
checkControlPanelIcons();
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.clearValidityOverride("expired.example.com", -1);
|
||||
|
@ -75,6 +76,35 @@ var successfulLoadListener = {
|
|||
}
|
||||
};
|
||||
|
||||
// Check for the correct icons in the identity box and control center.
|
||||
function checkControlPanelIcons() {
|
||||
let { gIdentityHandler } = gBrowser.ownerGlobal;
|
||||
gIdentityHandler._identityBox.click();
|
||||
document.getElementById("identity-popup-security-expander").click();
|
||||
|
||||
is_element_visible(document.getElementById("connection-icon"));
|
||||
let connectionIconImage = gBrowser.ownerGlobal
|
||||
.getComputedStyle(document.getElementById("connection-icon"), "")
|
||||
.getPropertyValue("list-style-image");
|
||||
let securityViewBG = gBrowser.ownerGlobal
|
||||
.getComputedStyle(document.getElementById("identity-popup-securityView"), "")
|
||||
.getPropertyValue("background-image");
|
||||
let securityContentBG = gBrowser.ownerGlobal
|
||||
.getComputedStyle(document.getElementById("identity-popup-security-content"), "")
|
||||
.getPropertyValue("background-image");
|
||||
is(connectionIconImage,
|
||||
"url(\"chrome://browser/skin/identity-mixed-passive-loaded.svg\")",
|
||||
"Using expected icon image in the identity block");
|
||||
is(securityViewBG,
|
||||
"url(\"chrome://browser/skin/identity-mixed-passive-loaded.svg\")",
|
||||
"Using expected icon image in the Control Center main view");
|
||||
is(securityContentBG,
|
||||
"url(\"chrome://browser/skin/identity-mixed-passive-loaded.svg\")",
|
||||
"Using expected icon image in the Control Center subview");
|
||||
|
||||
gIdentityHandler._identityPopup.hidden = true;
|
||||
}
|
||||
|
||||
// Utility function to get a handle on the certificate exception dialog.
|
||||
// Modified from toolkit/components/passwordmgr/test/prompt_common.js
|
||||
function getDialog(aLocation) {
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<label observes="identity-popup-content-host"/>
|
||||
<description class="identity-popup-connection-not-secure"
|
||||
value="&identity.connectionNotSecure;"
|
||||
when-connection="not-secure"/>
|
||||
when-connection="not-secure secure-cert-user-overridden"/>
|
||||
<description class="identity-popup-connection-secure"
|
||||
value="&identity.connectionSecure;"
|
||||
when-connection="secure secure-ev"/>
|
||||
|
@ -47,14 +47,14 @@
|
|||
</vbox>
|
||||
<button id="identity-popup-security-expander"
|
||||
class="identity-popup-expander"
|
||||
when-connection="not-secure secure secure-ev"
|
||||
when-connection="not-secure secure secure-ev secure-cert-user-overridden"
|
||||
oncommand="gIdentityHandler.toggleSubView('security', this)"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Tracking Protection Section -->
|
||||
<hbox id="tracking-protection-container"
|
||||
class="identity-popup-section"
|
||||
when-connection="not-secure secure secure-ev file">
|
||||
when-connection="not-secure secure secure-ev secure-cert-user-overridden file">
|
||||
<vbox id="tracking-protection-content" flex="1">
|
||||
<description class="identity-popup-headline"
|
||||
crop="end"
|
||||
|
@ -99,7 +99,7 @@
|
|||
<label observes="identity-popup-content-host"/>
|
||||
<description class="identity-popup-connection-not-secure"
|
||||
value="&identity.connectionNotSecure;"
|
||||
when-connection="not-secure"/>
|
||||
when-connection="not-secure secure-cert-user-overridden"/>
|
||||
<description class="identity-popup-connection-secure"
|
||||
value="&identity.connectionSecure;"
|
||||
when-connection="secure secure-ev"/>
|
||||
|
@ -115,7 +115,7 @@
|
|||
<description id="identity-popup-content-supplemental"
|
||||
when-connection="secure-ev"/>
|
||||
<description id="identity-popup-content-verifier"
|
||||
when-connection="secure secure-ev"/>
|
||||
when-connection="secure secure-ev secure-cert-user-overridden"/>
|
||||
|
||||
<!-- Connection is Not Secure -->
|
||||
<description when-connection="not-secure"
|
||||
|
|
|
@ -240,9 +240,14 @@ DistributionCustomizer.prototype = {
|
|||
}
|
||||
}),
|
||||
|
||||
_newProfile: false,
|
||||
_customizationsApplied: false,
|
||||
applyCustomizations: function DIST_applyCustomizations() {
|
||||
this._customizationsApplied = true;
|
||||
|
||||
if (!Services.prefs.prefHasUserValue("browser.migration.version"))
|
||||
this._newProfile = true;
|
||||
|
||||
if (!this._ini)
|
||||
return this._checkCustomizationComplete();
|
||||
|
||||
|
@ -408,6 +413,25 @@ DistributionCustomizer.prototype = {
|
|||
},
|
||||
|
||||
_checkCustomizationComplete: function DIST__checkCustomizationComplete() {
|
||||
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
|
||||
|
||||
if (this._newProfile) {
|
||||
let xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
|
||||
|
||||
try {
|
||||
var showPersonalToolbar = Services.prefs.getBoolPref("browser.showPersonalToolbar");
|
||||
if (showPersonalToolbar) {
|
||||
xulStore.setValue(BROWSER_DOCURL, "PersonalToolbar", "collapsed", "false");
|
||||
}
|
||||
} catch(e) {}
|
||||
try {
|
||||
var showMenubar = Services.prefs.getBoolPref("browser.showMenubar");
|
||||
if (showMenubar) {
|
||||
xulStore.setValue(BROWSER_DOCURL, "toolbar-menubar", "collapsed", "false");
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
let prefDefaultsApplied = this._prefDefaultsApplied || !this._ini;
|
||||
if (this._customizationsApplied && this._bookmarksApplied &&
|
||||
prefDefaultsApplied) {
|
||||
|
|
|
@ -139,7 +139,11 @@ add_task(function* testWebNavigationFrames() {
|
|||
"number of frames found should equal the number onCompleted events collected");
|
||||
|
||||
// ordered by frameId
|
||||
let sortByFrameId = (el) => el ? el.frameId : -1;
|
||||
let sortByFrameId = (el1, el2) => {
|
||||
let val1 = el1 ? el1.frameId : -1;
|
||||
let val2 = el2 ? el2.frameId : -1;
|
||||
return val1 - val2;
|
||||
};
|
||||
|
||||
collectedDetails = collectedDetails.sort(sortByFrameId);
|
||||
getAllFramesDetails = getAllFramesDetails.sort(sortByFrameId);
|
||||
|
|
|
@ -117,9 +117,16 @@ var SessionCookiesInternal = {
|
|||
restore(cookies) {
|
||||
for (let cookie of cookies) {
|
||||
let expiry = "expiry" in cookie ? cookie.expiry : MAX_EXPIRY;
|
||||
Services.cookies.add(cookie.host, cookie.path || "", cookie.name || "",
|
||||
cookie.value, !!cookie.secure, !!cookie.httponly,
|
||||
/* isSession = */ true, expiry);
|
||||
let cookieObj = {
|
||||
host: cookie.host,
|
||||
path: cookie.path || "",
|
||||
name: cookie.name || ""
|
||||
};
|
||||
if (!Services.cookies.cookieExists(cookieObj)) {
|
||||
Services.cookies.add(cookie.host, cookie.path || "", cookie.name || "",
|
||||
cookie.value, !!cookie.secure, !!cookie.httponly,
|
||||
/* isSession = */ true, expiry);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -241,6 +248,8 @@ var SessionCookiesInternal = {
|
|||
|
||||
if (cookie.isSession) {
|
||||
CookieStore.set(cookie);
|
||||
} else {
|
||||
CookieStore.delete(cookie);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -658,6 +658,15 @@ nsWindowsShellService::LaunchModernSettingsDialogDefaultApps()
|
|||
L"windows.immersivecontrolpanel_cw5n1h2txyewy"
|
||||
L"!microsoft.windows.immersivecontrolpanel",
|
||||
L"page=SettingsPageAppsDefaults", AO_NONE, &pid);
|
||||
if (SUCCEEDED(hr)) {
|
||||
// Do not check error because we could at least open
|
||||
// the "Default apps" setting.
|
||||
pActivator->ActivateApplication(
|
||||
L"windows.immersivecontrolpanel_cw5n1h2txyewy"
|
||||
L"!microsoft.windows.immersivecontrolpanel",
|
||||
L"page=SettingsPageAppsDefaults"
|
||||
L"&target=SystemSettings_DefaultApps_Browser", AO_NONE, &pid);
|
||||
}
|
||||
pActivator->Release();
|
||||
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
|
@ -956,6 +956,11 @@ function loadDefaultPrefs() {
|
|||
var branch = Services.prefs.getDefaultBranch("");
|
||||
Services.scriptloader.loadSubScript("chrome://loop/content/preferences/prefs.js", {
|
||||
pref: (key, val) => {
|
||||
// If a previously set default pref exists don't overwrite it. This can
|
||||
// happen for ESR or distribution.ini.
|
||||
if (branch.getPrefType(key) != branch.PREF_INVALID) {
|
||||
return;
|
||||
}
|
||||
switch (typeof val) {
|
||||
case "boolean":
|
||||
branch.setBoolPref(key, val);
|
||||
|
@ -979,6 +984,9 @@ function startup(data) {
|
|||
WindowListener.addonVersion = data.version;
|
||||
|
||||
loadDefaultPrefs();
|
||||
if (!Services.prefs.getBoolPref("loop.enabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
createLoopButton();
|
||||
|
||||
|
|
|
@ -821,6 +821,22 @@ const kMessageHandlers = {
|
|||
reply();
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the Getting Started tour url.
|
||||
*
|
||||
* @param {Object} message Message meant for the handler function, containing
|
||||
* the following parameters in its `data` property:
|
||||
* [aSrc, aAdditionalParams]
|
||||
* @param {Function} reply Callback function, invoked with the result of this
|
||||
* message handler. The result will be sent back to
|
||||
* the senders' channel.
|
||||
*/
|
||||
GettingStartedURL: function(message, reply) {
|
||||
let aSrc = message.data[0] || null;
|
||||
let aAdditionalParams = message.data[1] || {};
|
||||
reply(MozLoopService.getTourURL(aSrc, aAdditionalParams).href);
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the FxA profile/ settings page.
|
||||
*
|
||||
|
|
|
@ -467,9 +467,15 @@ loop.panel = function (_, mozL10n) {
|
|||
}));
|
||||
|
||||
// Open url if needed.
|
||||
loop.request("getSelectedTabMetadata").then(function (metadata) {
|
||||
loop.requestMulti(
|
||||
["getSelectedTabMetadata"],
|
||||
["GettingStartedURL", null, {}]
|
||||
).then(function(results) {
|
||||
var contextURL = this.props.room.decryptedContext.urls && this.props.room.decryptedContext.urls[0].location;
|
||||
if (contextURL && metadata.url !== contextURL) {
|
||||
|
||||
contextURL = contextURL || (results[1] + "?noopenpanel=1");
|
||||
|
||||
if (results[0].url !== contextURL) {
|
||||
loop.request("OpenURL", contextURL);
|
||||
}
|
||||
this.closeWindow();
|
||||
|
|
|
@ -76,6 +76,7 @@ describe("loop.panel", function() {
|
|||
LogoutFromFxA: sinon.stub(),
|
||||
NotifyUITour: sinon.stub(),
|
||||
OpenURL: sinon.stub(),
|
||||
GettingStartedURL: sinon.stub().returns("http://fakeFTUUrl.com"),
|
||||
GetSelectedTabMetadata: sinon.stub().returns({}),
|
||||
GetUserProfile: function() { return null; }
|
||||
});
|
||||
|
@ -829,6 +830,40 @@ describe("loop.panel", function() {
|
|||
sinon.assert.calledWithExactly(openURLStub, "http://testurl.com");
|
||||
});
|
||||
|
||||
it("should open a new tab with the FTU Getting Started URL if the room context is blank", function() {
|
||||
var roomDataNoURL = {
|
||||
roomToken: "QzBbvGmIZWU",
|
||||
roomUrl: "http://sample/QzBbvGmIZWU",
|
||||
decryptedContext: {
|
||||
roomName: roomName,
|
||||
urls: [{
|
||||
location: ""
|
||||
}]
|
||||
},
|
||||
maxSize: 2,
|
||||
participants: [{
|
||||
displayName: "Alexis",
|
||||
account: "alexis@example.com",
|
||||
roomConnectionId: "2a1787a6-4a73-43b5-ae3e-906ec1e763cb"
|
||||
}, {
|
||||
displayName: "Adam",
|
||||
roomConnectionId: "781f012b-f1ea-4ce1-9105-7cfc36fb4ec7"
|
||||
}],
|
||||
ctime: 1405517418
|
||||
};
|
||||
roomEntry = mountRoomEntry({
|
||||
deleteRoom: sandbox.stub(),
|
||||
isOpenedRoom: false,
|
||||
room: new loop.store.Room(roomDataNoURL)
|
||||
});
|
||||
var ftuURL = requestStubs.GettingStartedURL() + "?noopenpanel=1";
|
||||
|
||||
TestUtils.Simulate.click(roomEntry.refs.roomEntry.getDOMNode());
|
||||
|
||||
sinon.assert.calledOnce(openURLStub);
|
||||
sinon.assert.calledWithExactly(openURLStub, ftuURL);
|
||||
});
|
||||
|
||||
it("should not open a new tab if the context is the same as the currently open tab", function() {
|
||||
LoopMochaUtils.stubLoopRequest({
|
||||
GetSelectedTabMetadata: function() {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
|
||||
var [, gHandlers] = LoopAPI.inspect();
|
||||
|
||||
add_task(function* test_mozLoop_gettingStartedURL() {
|
||||
let expectedURL = MozLoopService.getTourURL().href;
|
||||
// Test gettingStartedURL
|
||||
gHandlers.GettingStartedURL({ data: [] }, result => {
|
||||
Assert.equal(result, expectedURL, "should get mozLoopService GettingStartedURL value correctly");
|
||||
});
|
||||
});
|
|
@ -5,6 +5,7 @@ firefox-appdir = browser
|
|||
skip-if = toolkit == 'gonk'
|
||||
|
||||
[test_loopapi_doNotDisturb.js]
|
||||
[test_loopapi_ftu_url.js]
|
||||
[test_loopapi_internal.js]
|
||||
[test_loopapi_prefs.js]
|
||||
[test_looppush_initialize.js]
|
||||
|
|
|
@ -41,6 +41,10 @@ const PREFS = {
|
|||
function setDefaultPrefs() {
|
||||
let branch = Services.prefs.getDefaultBranch(PREF_BRANCH);
|
||||
for (let [key, val] in Iterator(PREFS)) {
|
||||
// If someone beat us to setting a default, don't overwrite it. This can
|
||||
// happen if distribution.ini sets the default first.
|
||||
if (branch.getPrefType(key) != branch.PREF_INVALID)
|
||||
continue;
|
||||
switch (typeof val) {
|
||||
case "boolean":
|
||||
branch.setBoolPref(key, val);
|
||||
|
@ -519,8 +523,7 @@ function startup(data, reason) {
|
|||
}
|
||||
// watch pref change and enable/disable if necessary
|
||||
Services.prefs.addObserver("extensions.pocket.enabled", prefObserver, false);
|
||||
if (Services.prefs.prefHasUserValue("extensions.pocket.enabled") &&
|
||||
!Services.prefs.getBoolPref("extensions.pocket.enabled"))
|
||||
if (!Services.prefs.getBoolPref("extensions.pocket.enabled"))
|
||||
return;
|
||||
PocketOverlay.startup(reason);
|
||||
});
|
||||
|
|
|
@ -375,8 +375,8 @@
|
|||
@RESPATH@/browser/components/nsBrowserGlue.js
|
||||
@RESPATH@/browser/components/nsSetDefaultBrowser.manifest
|
||||
@RESPATH@/browser/components/nsSetDefaultBrowser.js
|
||||
@RESPATH@/browser/components/devtools-clhandler.manifest
|
||||
@RESPATH@/browser/components/devtools-clhandler.js
|
||||
@RESPATH@/browser/components/devtools-startup.manifest
|
||||
@RESPATH@/browser/components/devtools-startup.js
|
||||
@RESPATH@/browser/components/webideCli.js
|
||||
@RESPATH@/browser/components/webideComponents.manifest
|
||||
@RESPATH@/browser/components/Experiments.manifest
|
||||
|
|
|
@ -6,7 +6,6 @@ support-files =
|
|||
[browser_ProcessHangNotifications.js]
|
||||
skip-if = !e10s
|
||||
[browser_ContentSearch.js]
|
||||
skip-if = e10s
|
||||
support-files =
|
||||
contentSearch.js
|
||||
contentSearchBadImage.xml
|
||||
|
|
|
@ -97,13 +97,15 @@ add_task(function* search() {
|
|||
healthReportKey: "ContentSearchTest",
|
||||
searchPurpose: "ContentSearchTest",
|
||||
};
|
||||
let submissionURL =
|
||||
engine.getSubmission(data.searchString, "", data.whence).uri.spec;
|
||||
gMsgMan.sendAsyncMessage(TEST_MSG, {
|
||||
type: "Search",
|
||||
data: data,
|
||||
expectedURL: submissionURL,
|
||||
});
|
||||
let submissionURL =
|
||||
engine.getSubmission(data.searchString, "", data.whence).uri.spec;
|
||||
yield waitForLoadAndStopIt(gBrowser.selectedBrowser, submissionURL);
|
||||
let msg = yield waitForTestMsg("loadStopped");
|
||||
Assert.equal(msg.data.url, submissionURL, "Correct search page loaded");
|
||||
});
|
||||
|
||||
add_task(function* searchInBackgroundTab() {
|
||||
|
@ -120,18 +122,20 @@ add_task(function* searchInBackgroundTab() {
|
|||
healthReportKey: "ContentSearchTest",
|
||||
searchPurpose: "ContentSearchTest",
|
||||
};
|
||||
let submissionURL =
|
||||
engine.getSubmission(data.searchString, "", data.whence).uri.spec;
|
||||
gMsgMan.sendAsyncMessage(TEST_MSG, {
|
||||
type: "Search",
|
||||
data: data,
|
||||
expectedURL: submissionURL,
|
||||
});
|
||||
|
||||
let newTab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = newTab;
|
||||
registerCleanupFunction(() => gBrowser.removeTab(newTab));
|
||||
|
||||
let submissionURL =
|
||||
engine.getSubmission(data.searchString, "", data.whence).uri.spec;
|
||||
yield waitForLoadAndStopIt(searchBrowser, submissionURL);
|
||||
let msg = yield waitForTestMsg("loadStopped");
|
||||
Assert.equal(msg.data.url, submissionURL, "Correct search page loaded");
|
||||
});
|
||||
|
||||
add_task(function* badImage() {
|
||||
|
@ -331,33 +335,6 @@ function waitForNewEngine(basename, numImages) {
|
|||
return Promise.all([addDeferred.promise].concat(eventPromises));
|
||||
}
|
||||
|
||||
function waitForLoadAndStopIt(browser, expectedURL) {
|
||||
let deferred = Promise.defer();
|
||||
let listener = {
|
||||
onStateChange: function (webProg, req, flags, status) {
|
||||
if (req instanceof Ci.nsIChannel) {
|
||||
let url = req.originalURI.spec;
|
||||
info("onStateChange " + url);
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if ((flags & docStart) && webProg.isTopLevel && url == expectedURL) {
|
||||
browser.removeProgressListener(listener);
|
||||
ok(true, "Expected URL loaded");
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference,
|
||||
]),
|
||||
};
|
||||
browser.addProgressListener(listener);
|
||||
info("Waiting for URL to load: " + expectedURL);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function addTab() {
|
||||
let deferred = Promise.defer();
|
||||
let tab = gBrowser.addTab();
|
||||
|
|
|
@ -23,4 +23,42 @@ addMessageListener(TEST_MSG, msg => {
|
|||
detail: msg.data,
|
||||
})
|
||||
);
|
||||
|
||||
// If the message is a search, stop the page from loading and then tell the
|
||||
// test that it loaded.
|
||||
if (msg.data.type == "Search") {
|
||||
waitForLoadAndStopIt(msg.data.expectedURL, url => {
|
||||
sendAsyncMessage(TEST_MSG, {
|
||||
type: "loadStopped",
|
||||
url: url,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function waitForLoadAndStopIt(expectedURL, callback) {
|
||||
let Ci = Components.interfaces;
|
||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
let listener = {
|
||||
onStateChange: function (webProg, req, flags, status) {
|
||||
if (req instanceof Ci.nsIChannel) {
|
||||
let url = req.originalURI.spec;
|
||||
dump("waitForLoadAndStopIt: onStateChange " + url + "\n");
|
||||
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
|
||||
Ci.nsIWebProgressListener.STATE_START;
|
||||
if ((flags & docStart) && webProg.isTopLevel && url == expectedURL) {
|
||||
webProgress.removeProgressListener(listener);
|
||||
req.cancel(Components.results.NS_ERROR_FAILURE);
|
||||
callback(url);
|
||||
}
|
||||
}
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference,
|
||||
]),
|
||||
};
|
||||
webProgress.addProgressListener(listener, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
dump("waitForLoadAndStopIt: Waiting for URL to load: " + expectedURL + "\n");
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
/* Show the right elements for the right connection states. */
|
||||
#identity-popup[connection=not-secure] [when-connection~=not-secure],
|
||||
#identity-popup[connection=secure-cert-user-overridden] [when-connection~=secure-cert-user-overridden],
|
||||
#identity-popup[connection=secure-ev] [when-connection~=secure-ev],
|
||||
#identity-popup[connection=secure] [when-connection~=secure],
|
||||
#identity-popup[connection=chrome] [when-connection~=chrome],
|
||||
|
@ -234,6 +235,11 @@
|
|||
background-image: url(chrome://browser/skin/controlcenter/conn-degraded.svg);
|
||||
}
|
||||
|
||||
#identity-popup[connection=secure-cert-user-overridden] #identity-popup-securityView,
|
||||
#identity-popup[connection=secure-cert-user-overridden] #identity-popup-security-content {
|
||||
background-image: url(chrome://browser/skin/identity-mixed-passive-loaded.svg);
|
||||
}
|
||||
|
||||
#identity-popup[loginforms=insecure] #identity-popup-securityView,
|
||||
#identity-popup[loginforms=insecure] #identity-popup-security-content,
|
||||
#identity-popup[mixedcontent~=active-loaded][isbroken] #identity-popup-securityView,
|
||||
|
|
|
@ -198,6 +198,7 @@ panelmultiview[nosubviews=true] > .panel-viewcontainer > .panel-viewstack > .pan
|
|||
overflow: visible;
|
||||
}
|
||||
|
||||
.cui-widget-panel > .panel-arrowcontainer > .panel-arrowcontent,
|
||||
#PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
|
@ -166,6 +166,7 @@
|
|||
}
|
||||
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon,
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon,
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon,
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon {
|
||||
list-style-image: url(chrome://browser/skin/identity-mixed-passive-loaded.svg);
|
||||
|
|
|
@ -33,8 +33,7 @@ function shouldCapture() {
|
|||
// Automation isn't able to schedule test jobs to only run on nightlies so we handle it here
|
||||
// (see also: bug 1116275).
|
||||
let capture = AppConstants.MOZ_UPDATE_CHANNEL == "nightly" ||
|
||||
AppConstants.SOURCE_REVISION_URL == "" ||
|
||||
AppConstants.SOURCE_REVISION_URL == "1"; // bug 1248027
|
||||
AppConstants.SOURCE_REVISION_URL == "";
|
||||
if (!capture) {
|
||||
ok(true, "Capturing is disabled for this MOZ_UPDATE_CHANNEL or REPO");
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ this.TestRunner = {
|
|||
_libDir: null,
|
||||
|
||||
init(extensionPath) {
|
||||
log.info("init");
|
||||
log.debug("init");
|
||||
this._extensionPath = extensionPath;
|
||||
},
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ var getServerTraits = Task.async(function*(target) {
|
|||
*/
|
||||
var AnimationsController = {
|
||||
PLAYERS_UPDATED_EVENT: "players-updated",
|
||||
ALL_ANIMATIONS_TOGGLED_EVENT: "all-animations-toggled",
|
||||
|
||||
initialize: Task.async(function*() {
|
||||
if (this.initialized) {
|
||||
|
@ -255,7 +256,9 @@ var AnimationsController = {
|
|||
return promise.resolve();
|
||||
}
|
||||
|
||||
return this.animationsFront.toggleAll().catch(e => console.error(e));
|
||||
return this.animationsFront.toggleAll()
|
||||
.then(() => this.emit(this.ALL_ANIMATIONS_TOGGLED_EVENT, this))
|
||||
.catch(e => console.error(e));
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,10 +52,10 @@ var AnimationsPanel = {
|
|||
}
|
||||
|
||||
// Binding functions that need to be called in scope.
|
||||
for (let functionName of ["onPickerStarted", "onPickerStopped",
|
||||
"refreshAnimationsUI", "toggleAll", "onTabNavigated",
|
||||
"onTimelineDataChanged", "playPauseTimeline", "rewindTimeline",
|
||||
"onRateChanged"]) {
|
||||
for (let functionName of ["onKeyDown", "onPickerStarted",
|
||||
"onPickerStopped", "refreshAnimationsUI", "onToggleAllClicked",
|
||||
"onTabNavigated", "onTimelineDataChanged", "onTimelinePlayClicked",
|
||||
"onTimelineRewindClicked", "onRateChanged"]) {
|
||||
this[functionName] = this[functionName].bind(this);
|
||||
}
|
||||
let hUtils = gToolbox.highlighterUtils;
|
||||
|
@ -114,9 +114,13 @@ var AnimationsPanel = {
|
|||
gToolbox.on("picker-started", this.onPickerStarted);
|
||||
gToolbox.on("picker-stopped", this.onPickerStopped);
|
||||
|
||||
this.toggleAllButtonEl.addEventListener("click", this.toggleAll);
|
||||
this.playTimelineButtonEl.addEventListener("click", this.playPauseTimeline);
|
||||
this.rewindTimelineButtonEl.addEventListener("click", this.rewindTimeline);
|
||||
this.toggleAllButtonEl.addEventListener("click", this.onToggleAllClicked);
|
||||
this.playTimelineButtonEl.addEventListener(
|
||||
"click", this.onTimelinePlayClicked);
|
||||
this.rewindTimelineButtonEl.addEventListener(
|
||||
"click", this.onTimelineRewindClicked);
|
||||
|
||||
document.addEventListener("keydown", this.onKeyDown, false);
|
||||
|
||||
gToolbox.target.on("navigate", this.onTabNavigated);
|
||||
|
||||
|
@ -136,9 +140,13 @@ var AnimationsPanel = {
|
|||
gToolbox.off("picker-started", this.onPickerStarted);
|
||||
gToolbox.off("picker-stopped", this.onPickerStopped);
|
||||
|
||||
this.toggleAllButtonEl.removeEventListener("click", this.toggleAll);
|
||||
this.playTimelineButtonEl.removeEventListener("click", this.playPauseTimeline);
|
||||
this.rewindTimelineButtonEl.removeEventListener("click", this.rewindTimeline);
|
||||
this.toggleAllButtonEl.removeEventListener("click", this.onToggleAllClicked);
|
||||
this.playTimelineButtonEl.removeEventListener(
|
||||
"click", this.onTimelinePlayClicked);
|
||||
this.rewindTimelineButtonEl.removeEventListener(
|
||||
"click", this.onTimelineRewindClicked);
|
||||
|
||||
document.removeEventListener("keydown", this.onKeyDown, false);
|
||||
|
||||
gToolbox.target.off("navigate", this.onTabNavigated);
|
||||
|
||||
|
@ -150,6 +158,22 @@ var AnimationsPanel = {
|
|||
}
|
||||
},
|
||||
|
||||
onKeyDown: function(event) {
|
||||
let keyEvent = Ci.nsIDOMKeyEvent;
|
||||
|
||||
// If the space key is pressed, it should toggle the play state of
|
||||
// the animations displayed in the panel, or of all the animations on
|
||||
// the page if the selected node does not have any animation on it.
|
||||
if (event.keyCode === keyEvent.DOM_VK_SPACE) {
|
||||
if (AnimationsController.animationPlayers.length > 0) {
|
||||
this.playPauseTimeline().catch(ex => console.error(ex));
|
||||
} else {
|
||||
this.toggleAll().catch(ex => console.error(ex));
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
togglePlayers: function(isVisible) {
|
||||
if (isVisible) {
|
||||
document.body.removeAttribute("empty");
|
||||
|
@ -168,32 +192,53 @@ var AnimationsPanel = {
|
|||
this.pickerButtonEl.removeAttribute("checked");
|
||||
},
|
||||
|
||||
onToggleAllClicked: function() {
|
||||
this.toggleAll().catch(ex => console.error(ex));
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle (pause/play) all animations in the current target
|
||||
* and update the UI the toggleAll button.
|
||||
*/
|
||||
toggleAll: Task.async(function*() {
|
||||
this.toggleAllButtonEl.classList.toggle("paused");
|
||||
yield AnimationsController.toggleAll();
|
||||
}),
|
||||
|
||||
onTimelinePlayClicked: function() {
|
||||
this.playPauseTimeline().catch(ex => console.error(ex));
|
||||
},
|
||||
|
||||
/**
|
||||
* Depending on the state of the timeline either pause or play the animations
|
||||
* displayed in it.
|
||||
* If the animations are finished, this will play them from the start again.
|
||||
* If the animations are playing, this will pause them.
|
||||
* If the animations are paused, this will resume them.
|
||||
*
|
||||
* @return {Promise} Resolves when the playState is changed and the UI
|
||||
* is refreshed
|
||||
*/
|
||||
playPauseTimeline: function() {
|
||||
AnimationsController.toggleCurrentAnimations(this.timelineData.isMoving)
|
||||
.then(() => this.refreshAnimationsStateAndUI())
|
||||
.catch(e => console.error(e));
|
||||
return AnimationsController
|
||||
.toggleCurrentAnimations(this.timelineData.isMoving)
|
||||
.then(() => this.refreshAnimationsStateAndUI());
|
||||
},
|
||||
|
||||
onTimelineRewindClicked: function() {
|
||||
this.rewindTimeline().catch(ex => console.error(ex));
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the startTime of all current animations shown in the timeline and
|
||||
* pause them.
|
||||
*
|
||||
* @return {Promise} Resolves when currentTime is set and the UI is refreshed
|
||||
*/
|
||||
rewindTimeline: function() {
|
||||
AnimationsController.setCurrentTimeAll(0, true)
|
||||
.then(() => this.refreshAnimationsStateAndUI())
|
||||
.catch(e => console.error(e));
|
||||
return AnimationsController
|
||||
.setCurrentTimeAll(0, true)
|
||||
.then(() => this.refreshAnimationsStateAndUI());
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -203,7 +248,7 @@ var AnimationsPanel = {
|
|||
onRateChanged: function(e, rate) {
|
||||
AnimationsController.setPlaybackRateAll(rate)
|
||||
.then(() => this.refreshAnimationsStateAndUI())
|
||||
.catch(e => console.error(e));
|
||||
.catch(ex => console.error(ex));
|
||||
},
|
||||
|
||||
onTabNavigated: function() {
|
||||
|
|
|
@ -31,6 +31,8 @@ skip-if = os == "linux" && !debug # Bug 1227792
|
|||
[browser_animation_running_on_compositor.js]
|
||||
[browser_animation_same_nb_of_playerWidgets_and_playerFronts.js]
|
||||
[browser_animation_shows_player_on_valid_node.js]
|
||||
[browser_animation_spacebar_toggles_animations.js]
|
||||
[browser_animation_spacebar_toggles_node_animations.js]
|
||||
[browser_animation_target_highlight_select.js]
|
||||
[browser_animation_target_highlighter_lock.js]
|
||||
[browser_animation_timeline_currentTime.js]
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the spacebar key press toggles the toggleAll button state
|
||||
// when a node with no animation is selected.
|
||||
// This test doesn't need to test if animations actually pause/resume
|
||||
// because there's an other test that does this :
|
||||
// browser_animation_toggle_button_toggles_animation.js
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {panel, inspector, window, controller} = yield openAnimationInspector();
|
||||
let {toggleAllButtonEl} = panel;
|
||||
|
||||
// select a node without animations
|
||||
yield selectNode(".still", inspector);
|
||||
|
||||
// ensure the focus is on the animation panel
|
||||
window.focus();
|
||||
|
||||
info("Simulate spacebar stroke and check toggleAll button" +
|
||||
" is in paused state");
|
||||
|
||||
// sending the key will lead to a ALL_ANIMATIONS_TOGGLED_EVENT
|
||||
let onToggled = once(controller, controller.ALL_ANIMATIONS_TOGGLED_EVENT);
|
||||
EventUtils.sendKey("SPACE", window);
|
||||
yield onToggled;
|
||||
ok(toggleAllButtonEl.classList.contains("paused"),
|
||||
"The toggle all button is in its paused state");
|
||||
|
||||
info("Simulate spacebar stroke and check toggleAll button" +
|
||||
" is in playing state");
|
||||
|
||||
// sending the key will lead to a ALL_ANIMATIONS_TOGGLED_EVENT
|
||||
onToggled = once(controller, controller.ALL_ANIMATIONS_TOGGLED_EVENT);
|
||||
EventUtils.sendKey("SPACE", window);
|
||||
yield onToggled;
|
||||
ok(!toggleAllButtonEl.classList.contains("paused"),
|
||||
"The toggle all button is in its playing state again");
|
||||
});
|
|
@ -0,0 +1,40 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the spacebar key press toggles the play/resume button state.
|
||||
// This test doesn't need to test if animations actually pause/resume
|
||||
// because there's an other test that does this.
|
||||
// There are animations in the test page and since, by default, the <body> node
|
||||
// is selected, animations will be displayed in the timeline, so the timeline
|
||||
// play/resume button will be displayed
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {panel, window} = yield openAnimationInspector();
|
||||
let {playTimelineButtonEl} = panel;
|
||||
|
||||
// ensure the focus is on the animation panel
|
||||
window.focus();
|
||||
|
||||
info("Simulate spacebar stroke and check playResume button" +
|
||||
" is in paused state");
|
||||
|
||||
// sending the key will lead to a UI_UPDATE_EVENT
|
||||
let onUpdated = panel.once(panel.UI_UPDATED_EVENT);
|
||||
EventUtils.sendKey("SPACE", window);
|
||||
yield onUpdated;
|
||||
ok(playTimelineButtonEl.classList.contains("paused"),
|
||||
"The play/resume button is in its paused state");
|
||||
|
||||
info("Simulate spacebar stroke and check playResume button" +
|
||||
" is in playing state");
|
||||
|
||||
// sending the key will lead to a UI_UPDATE_EVENT
|
||||
onUpdated = panel.once(panel.UI_UPDATED_EVENT);
|
||||
EventUtils.sendKey("SPACE", window);
|
||||
yield onUpdated;
|
||||
ok(!playTimelineButtonEl.classList.contains("paused"),
|
||||
"The play/resume button is in its play state again");
|
||||
});
|
|
@ -6,6 +6,15 @@
|
|||
bug 1242893 is fixed */
|
||||
/* globals BrowserToolboxProcess */
|
||||
|
||||
/**
|
||||
* This XPCOM component is loaded very early.
|
||||
* It handles command line arguments like -jsconsole, but also ensures starting
|
||||
* core modules like devtools/devtools-browser that listen for application
|
||||
* startup.
|
||||
*
|
||||
* Be careful to lazy load dependencies as much as possible.
|
||||
**/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { interfaces: Ci, utils: Cu } = Components;
|
||||
|
@ -16,9 +25,9 @@ const kDebuggerPrefs = [
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
|
||||
|
||||
function devtoolsCommandlineHandler() {}
|
||||
function DevToolsStartup() {}
|
||||
|
||||
devtoolsCommandlineHandler.prototype = {
|
||||
DevToolsStartup.prototype = {
|
||||
handle: function(cmdLine) {
|
||||
let consoleFlag = cmdLine.handleFlag("jsconsole", false);
|
||||
let debuggerFlag = cmdLine.handleFlag("jsdebugger", false);
|
||||
|
@ -30,9 +39,6 @@ devtoolsCommandlineHandler.prototype = {
|
|||
if (debuggerFlag) {
|
||||
this.handleDebuggerFlag(cmdLine);
|
||||
}
|
||||
if (devtoolsFlag) {
|
||||
this.handleDevToolsFlag();
|
||||
}
|
||||
let debuggerServerFlag;
|
||||
try {
|
||||
debuggerServerFlag =
|
||||
|
@ -45,19 +51,36 @@ devtoolsCommandlineHandler.prototype = {
|
|||
if (debuggerServerFlag) {
|
||||
this.handleDebuggerServerFlag(cmdLine, debuggerServerFlag);
|
||||
}
|
||||
|
||||
let onStartup = function(window) {
|
||||
Services.obs.removeObserver(onStartup,
|
||||
"browser-delayed-startup-finished");
|
||||
// Ensure loading core module once firefox is ready
|
||||
this.initDevTools();
|
||||
|
||||
if (devtoolsFlag) {
|
||||
this.handleDevToolsFlag(window);
|
||||
}
|
||||
}.bind(this);
|
||||
Services.obs.addObserver(onStartup, "browser-delayed-startup-finished",
|
||||
false);
|
||||
},
|
||||
|
||||
initDevTools: function() {
|
||||
let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
// Ensure loading main devtools module that hooks up into browser UI
|
||||
// and initialize all devtools machinery.
|
||||
// browser.xul or main top-level document used to load this module,
|
||||
// but this code may be called without/before it.
|
||||
require("devtools/client/framework/devtools-browser");
|
||||
},
|
||||
|
||||
handleConsoleFlag: function(cmdLine) {
|
||||
let window = Services.wm.getMostRecentWindow("devtools:webconsole");
|
||||
if (!window) {
|
||||
let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
// Ensure loading main devtools module that hooks up into browser UI
|
||||
// and initialize all devtools machinery.
|
||||
// browser.xul or main top-level document used to load this module,
|
||||
// but this code may be called without/before it.
|
||||
// Bug 1247203 should ease handling this.
|
||||
require("devtools/client/framework/devtools-browser");
|
||||
this.initDevTools();
|
||||
|
||||
let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
let hudservice = require("devtools/client/webconsole/hudservice");
|
||||
let { console } = Cu.import("resource://gre/modules/Console.jsm", {});
|
||||
hudservice.toggleBrowserConsole().then(null, console.error);
|
||||
|
@ -72,16 +95,12 @@ devtoolsCommandlineHandler.prototype = {
|
|||
},
|
||||
|
||||
// Open the toolbox on the selected tab once the browser starts up.
|
||||
handleDevToolsFlag: function() {
|
||||
Services.obs.addObserver(function onStartup(window) {
|
||||
Services.obs.removeObserver(onStartup,
|
||||
"browser-delayed-startup-finished");
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {gDevTools} = require("devtools/client/framework/devtools");
|
||||
const {TargetFactory} = require("devtools/client/framework/target");
|
||||
let target = TargetFactory.forTab(window.gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target);
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
handleDevToolsFlag: function(window) {
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {gDevTools} = require("devtools/client/framework/devtools");
|
||||
const {TargetFactory} = require("devtools/client/framework/target");
|
||||
let target = TargetFactory.forTab(window.gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target);
|
||||
},
|
||||
|
||||
_isRemoteDebuggingEnabled() {
|
||||
|
@ -168,4 +187,4 @@ devtoolsCommandlineHandler.prototype = {
|
|||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
|
||||
[devtoolsCommandlineHandler]);
|
||||
[DevToolsStartup]);
|
|
@ -1,2 +1,2 @@
|
|||
component {9e9a9283-0ce9-4e4a-8f1c-ba129a032c32} devtools-clhandler.js
|
||||
component {9e9a9283-0ce9-4e4a-8f1c-ba129a032c32} devtools-startup.js
|
||||
contract @mozilla.org/toolkit/console-clh;1 {9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}
|
|
@ -4,6 +4,14 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This is the main module loaded in Firefox desktop that handles browser
|
||||
* windows and coordinates devtools around each window.
|
||||
*
|
||||
* This module is loaded lazily by devtools-clhandler.js, once the first
|
||||
* browser window is ready (i.e. fired browser-delayed-startup-finished event)
|
||||
**/
|
||||
|
||||
const {Cc, Ci, Cu} = require("chrome");
|
||||
const Services = require("Services");
|
||||
const promise = require("promise");
|
||||
|
@ -116,10 +124,17 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
|
|||
},
|
||||
|
||||
observe: function(subject, topic, prefName) {
|
||||
if (prefName.endsWith("enabled")) {
|
||||
for (let win of this._trackedBrowserWindows) {
|
||||
this.updateCommandAvailability(win);
|
||||
}
|
||||
switch (topic) {
|
||||
case "browser-delayed-startup-finished":
|
||||
this._registerBrowserWindow(subject);
|
||||
break;
|
||||
case "nsPref:changed":
|
||||
if (prefName.endsWith("enabled")) {
|
||||
for (let win of this._trackedBrowserWindows) {
|
||||
this.updateCommandAvailability(win);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -319,11 +334,11 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
|
|||
* @param {XULDocument} doc
|
||||
* The document to which menuitems and handlers are to be added
|
||||
*/
|
||||
// Used by browser.js
|
||||
registerBrowserWindow: function DT_registerBrowserWindow(win) {
|
||||
_registerBrowserWindow: function(win) {
|
||||
this.updateCommandAvailability(win);
|
||||
this.ensurePrefObserver();
|
||||
gDevToolsBrowser._trackedBrowserWindows.add(win);
|
||||
win.addEventListener("unload", this);
|
||||
gDevToolsBrowser._addAllToolsToMenu(win.document);
|
||||
|
||||
if (this._isFirebugInstalled()) {
|
||||
|
@ -749,8 +764,9 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
|
|||
* @param {XULWindow} win
|
||||
* The window containing the menu entry
|
||||
*/
|
||||
forgetBrowserWindow: function DT_forgetBrowserWindow(win) {
|
||||
_forgetBrowserWindow: function(win) {
|
||||
gDevToolsBrowser._trackedBrowserWindows.delete(win);
|
||||
win.removeEventListener("unload", this);
|
||||
|
||||
// Destroy toolboxes for closed window
|
||||
for (let [target, toolbox] of gDevTools._toolboxes) {
|
||||
|
@ -792,6 +808,11 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
|
|||
break;
|
||||
case "TabSelect":
|
||||
gDevToolsBrowser._updateMenuCheckbox();
|
||||
break;
|
||||
case "unload":
|
||||
// top-level browser window unload
|
||||
gDevToolsBrowser._forgetBrowserWindow(event.target.defaultView);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -800,7 +821,12 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
|
|||
*/
|
||||
destroy: function() {
|
||||
Services.prefs.removeObserver("devtools.", gDevToolsBrowser);
|
||||
Services.obs.removeObserver(gDevToolsBrowser, "browser-delayed-startup-finished");
|
||||
Services.obs.removeObserver(gDevToolsBrowser.destroy, "quit-application");
|
||||
|
||||
for (let win of gDevToolsBrowser._trackedBrowserWindows) {
|
||||
gDevToolsBrowser._forgetBrowserWindow(win);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -820,6 +846,16 @@ gDevTools.on("toolbox-ready", gDevToolsBrowser._updateMenuCheckbox);
|
|||
gDevTools.on("toolbox-destroyed", gDevToolsBrowser._updateMenuCheckbox);
|
||||
|
||||
Services.obs.addObserver(gDevToolsBrowser.destroy, "quit-application", false);
|
||||
Services.obs.addObserver(gDevToolsBrowser, "browser-delayed-startup-finished", false);
|
||||
// Fake end of browser window load event for all already opened windows
|
||||
// that is already fully loaded.
|
||||
let enumerator = Services.wm.getEnumerator("navigator:browser");
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let win = enumerator.getNext();
|
||||
if (win.gBrowserInit && win.gBrowserInit.delayedStartupFinished) {
|
||||
gDevToolsBrowser._registerBrowserWindow(win);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the browser devtools main module as the loader's main module.
|
||||
// This is done precisely here as main.js ends up dispatching the
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
tooltiptext="&toolboxCloseButton.tooltip;"/>
|
||||
</hbox>
|
||||
</toolbar>
|
||||
<vbox flex="1">
|
||||
<vbox flex="1" class="theme-body">
|
||||
<!-- Set large flex to allow the toolbox-panel-webconsole to have a
|
||||
height set to a small value without flexing to fill up extra
|
||||
space. There must be a flex on both to ensure that the console
|
||||
|
|
|
@ -44,8 +44,8 @@ if CONFIG['MOZ_BUILD_APP'] == 'browser':
|
|||
DIRS += ['themes/shims']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'devtools-clhandler.js',
|
||||
'devtools-clhandler.manifest',
|
||||
'devtools-startup.js',
|
||||
'devtools-startup.manifest',
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
|
|
@ -27,26 +27,17 @@ xul|scrollbar[orient="horizontal"] {
|
|||
max-height: 10px;
|
||||
}
|
||||
|
||||
:root[platform="mac"] xul|slider {
|
||||
-moz-appearance: none !important;
|
||||
}
|
||||
|
||||
:root[platform="mac"] xul|thumb {
|
||||
-moz-appearance: none !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
xul|scrollbar xul|thumb {
|
||||
background-color: rgba(170,170,170,0.2) !important;
|
||||
}
|
||||
|
||||
:root[platform="win"] xul|thumb,
|
||||
:root[platform="linux"] xul|thumb {
|
||||
-moz-appearance: none !important;
|
||||
border-width: 0px !important;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
|
||||
:root[platform="mac"] xul|slider {
|
||||
-moz-appearance: none !important;
|
||||
}
|
||||
|
||||
:root[platform="win"] xul|scrollbar xul|scrollbarbutton,
|
||||
:root[platform="linux"] xul|scrollbar xul|scrollbarbutton,
|
||||
:root[platform="win"] xul|scrollbar xul|gripper,
|
||||
|
|
|
@ -832,7 +832,7 @@
|
|||
-moz-box-align: center;
|
||||
min-width: 32px;
|
||||
min-height: 24px;
|
||||
max-width: 95px;
|
||||
max-width: 100px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-style: solid;
|
||||
|
|
|
@ -1349,7 +1349,7 @@ Messages.JavaScriptEvalOutput = function(evalResponse, errorMessage)
|
|||
// be useful to extensions customizing the console output.
|
||||
this.response = evalResponse;
|
||||
|
||||
if (errorMessage) {
|
||||
if (typeof(errorMessage) !== "undefined") {
|
||||
severity = "error";
|
||||
msg = errorMessage;
|
||||
quoteStrings = false;
|
||||
|
|
|
@ -308,6 +308,11 @@ JSTerm.prototype = {
|
|||
return;
|
||||
}
|
||||
let errorMessage = response.exceptionMessage;
|
||||
// Wrap thrown strings in Error objects, so `throw "foo"` outputs
|
||||
// "Error: foo"
|
||||
if (typeof(response.exception) === "string") {
|
||||
errorMessage = new Error(errorMessage).toString();
|
||||
}
|
||||
let result = response.result;
|
||||
let helperResult = response.helperResult;
|
||||
let helperHasRawOutput = !!(helperResult || {}).rawOutput;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// On e10s, the exception is triggered in child process
|
||||
// and is ignored by test harness
|
||||
if (!Services.appinfo.browserTabsRemoteAutostart) {
|
||||
expectUncaughtException();
|
||||
SimpleTest.ignoreAllUncaughtExceptions();
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
@ -49,6 +49,37 @@ function test() {
|
|||
severity: SEVERITY_ERROR,
|
||||
collapsible: true,
|
||||
stacktrace: stack,
|
||||
}, {
|
||||
text: "An invalid or illegal string was specified",
|
||||
category: CATEGORY_JS,
|
||||
severity: SEVERITY_ERROR,
|
||||
collapsible: true,
|
||||
stacktrace: [{
|
||||
file: TEST_FILE,
|
||||
fn: "domAPI",
|
||||
line: 25,
|
||||
}, {
|
||||
file: TEST_FILE,
|
||||
fn: "onLoadDomAPI",
|
||||
line: 33,
|
||||
}
|
||||
]
|
||||
}, {
|
||||
text: "DOMException",
|
||||
category: CATEGORY_JS,
|
||||
severity: SEVERITY_ERROR,
|
||||
collapsible: true,
|
||||
stacktrace: [{
|
||||
file: TEST_FILE,
|
||||
fn: "domException",
|
||||
line: 29,
|
||||
}, {
|
||||
file: TEST_FILE,
|
||||
fn: "onLoadDomException",
|
||||
line: 36,
|
||||
},
|
||||
|
||||
]
|
||||
}],
|
||||
});
|
||||
|
||||
|
|
|
@ -142,4 +142,28 @@ function* testJSTerm(hud) {
|
|||
jsterm.clearOutput();
|
||||
yield jsterm.execute("undefined");
|
||||
yield checkResult("undefined", "undefined is printed");
|
||||
|
||||
// check that thrown strings produce error messages,
|
||||
// and the message text matches that of a stringified error object
|
||||
// bug 1099071
|
||||
jsterm.clearOutput();
|
||||
yield jsterm.execute("throw '';");
|
||||
yield checkResult((node) => {
|
||||
return node.parentNode.getAttribute("severity") === "error" &&
|
||||
node.textContent === new Error("").toString();
|
||||
}, "thrown empty string generates error message");
|
||||
|
||||
jsterm.clearOutput();
|
||||
yield jsterm.execute("throw 'tomatoes';");
|
||||
yield checkResult((node) => {
|
||||
return node.parentNode.getAttribute("severity") === "error" &&
|
||||
node.textContent === new Error("tomatoes").toString();
|
||||
}, "thrown non-empty string generates error message");
|
||||
|
||||
jsterm.clearOutput();
|
||||
yield jsterm.execute("throw { foo: 'bar' };");
|
||||
yield checkResult((node) => {
|
||||
return node.parentNode.getAttribute("severity") === "error" &&
|
||||
node.textContent === Object.prototype.toString();
|
||||
}, "thrown object generates error message");
|
||||
}
|
||||
|
|
|
@ -21,7 +21,20 @@
|
|||
nonExistingMethodCall();
|
||||
}
|
||||
|
||||
window.onload = firstCall;
|
||||
function domAPI() {
|
||||
document.querySelector("buggy;selector");
|
||||
}
|
||||
|
||||
function domException() {
|
||||
throw new DOMException("DOMException");
|
||||
}
|
||||
window.addEventListener("load", firstCall);
|
||||
window.addEventListener("load", function onLoadDomAPI() {
|
||||
domAPI();
|
||||
});
|
||||
window.addEventListener("load", function onLoadDomException() {
|
||||
domException();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft= javascript ts=2 et sw=2 tw=80: */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
const { Cc, Ci, Cu, components, ChromeWorker } = require("chrome");
|
||||
const { Cc, Ci, Cu, Cr, components, ChromeWorker } = require("chrome");
|
||||
const { ActorPool, OriginalLocation, GeneratedLocation } = require("devtools/server/actors/common");
|
||||
const { BreakpointActor } = require("devtools/server/actors/breakpoint");
|
||||
const { FrameActor } = require("devtools/server/actors/frame");
|
||||
|
@ -1846,10 +1846,17 @@ ThreadActor.prototype = {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// NS_ERROR_NO_INTERFACE exceptions are a special case in browser code,
|
||||
// since they're almost always thrown by QueryInterface functions, and
|
||||
// handled cleanly by native code.
|
||||
if (aValue == Cr.NS_ERROR_NO_INTERFACE) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const generatedLocation = this.sources.getFrameLocation(aFrame);
|
||||
const { sourceActor } = this.unsafeSynchronize(this.sources.getOriginalLocation(
|
||||
const { originalSourceActor } = this.unsafeSynchronize(this.sources.getOriginalLocation(
|
||||
generatedLocation));
|
||||
const url = sourceActor ? sourceActor.url : null;
|
||||
const url = originalSourceActor ? originalSourceActor.url : null;
|
||||
|
||||
if (this.sources.isBlackBoxed(url)) {
|
||||
return undefined;
|
||||
|
|
|
@ -73,8 +73,8 @@ function test_black_box_exception() {
|
|||
gThreadClient.pauseOnExceptions(true);
|
||||
|
||||
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
do_check_neq(aPacket.frame.where.url, BLACK_BOXED_URL,
|
||||
"We shouldn't pause while in the black boxed source.");
|
||||
do_check_eq(aPacket.frame.where.source.url, SOURCE_URL,
|
||||
"We shouldn't pause while in the black boxed source.");
|
||||
finishClient(gClient);
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that the debugger automatically ignores NS_ERROR_NO_INTERFACE
|
||||
* exceptions, but not normal ones.
|
||||
*/
|
||||
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-no-interface");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect().then(function() {
|
||||
attachTestTabAndResume(gClient, "test-no-interface", function(aResponse, aTabClient, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_pause_frame();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_pause_frame()
|
||||
{
|
||||
gThreadClient.pauseOnExceptions(true, false, function () {
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
do_check_eq(aPacket.why.type, "exception");
|
||||
do_check_eq(aPacket.why.exception, 42);
|
||||
gThreadClient.resume(function () {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function() {
|
||||
function QueryInterface() {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
function stopMe() {
|
||||
throw 42;
|
||||
};
|
||||
try {
|
||||
QueryInterface();
|
||||
} catch (e) {}
|
||||
try {
|
||||
stopMe();
|
||||
} catch (e) {}
|
||||
} + ")()");
|
||||
});
|
||||
}
|
|
@ -239,6 +239,7 @@ reason = bug 820380
|
|||
[test_unsafeDereference.js]
|
||||
[test_add_actors.js]
|
||||
[test_ignore_caught_exceptions.js]
|
||||
[test_ignore_no_interface_exceptions.js]
|
||||
[test_requestTypes.js]
|
||||
reason = bug 937197
|
||||
[test_layout-reflows-observer.js]
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
#include "nsGlobalWindow.h"
|
||||
#include "nsScriptNameSpaceManager.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/DOMExceptionBinding.h"
|
||||
#include "mozilla/dom/ErrorEvent.h"
|
||||
#include "nsAXPCNativeCallContext.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
|
@ -223,6 +225,41 @@ ProcessNameForCollectorLog()
|
|||
"default" : "content";
|
||||
}
|
||||
|
||||
// This handles JS Exceptions (via ExceptionStackOrNull), as well as DOM and XPC Exceptions.
|
||||
//
|
||||
// Note that the returned object is _not_ wrapped into the compartment of cx.
|
||||
static JSObject*
|
||||
FindExceptionStack(JSContext* cx, JS::HandleObject exceptionObject)
|
||||
{
|
||||
JSAutoCompartment ac(cx, exceptionObject);
|
||||
JS::RootedObject stackObject(cx, ExceptionStackOrNull(cx, exceptionObject));
|
||||
if (stackObject) {
|
||||
return stackObject;
|
||||
}
|
||||
|
||||
// It is not a JS Exception, try DOM Exception.
|
||||
RefPtr<Exception> exception;
|
||||
UNWRAP_OBJECT(DOMException, exceptionObject, exception);
|
||||
if (!exception) {
|
||||
// Not a DOM Exception, try XPC Exception.
|
||||
UNWRAP_OBJECT(Exception, exceptionObject, exception);
|
||||
if (!exception) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStackFrame> stack = exception->GetLocation();
|
||||
if (!stack) {
|
||||
return nullptr;
|
||||
}
|
||||
JS::RootedValue value(cx);
|
||||
stack->GetNativeSavedFrame(&value);
|
||||
if (value.isObject()) {
|
||||
stackObject = &value.toObject();
|
||||
}
|
||||
return stackObject;
|
||||
}
|
||||
|
||||
static PRTime
|
||||
GetCollectionTimeDelta()
|
||||
{
|
||||
|
@ -426,7 +463,7 @@ public:
|
|||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> exObj(cx, mError.toObjectOrNull());
|
||||
JS::RootedObject stack(cx, ExceptionStackOrNull(cx, exObj));
|
||||
JS::RootedObject stack(cx, FindExceptionStack(cx, exObj));
|
||||
mReport->LogToConsoleWithStack(stack);
|
||||
} else {
|
||||
mReport->LogToConsole();
|
||||
|
@ -512,7 +549,7 @@ SystemErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
|
|||
if (exception.isObject()) {
|
||||
JS::RootedObject exObj(cx, exception.toObjectOrNull());
|
||||
JSAutoCompartment ac(cx, exObj);
|
||||
JS::RootedObject stackVal(cx, ExceptionStackOrNull(cx, exObj));
|
||||
JS::RootedObject stackVal(cx, FindExceptionStack(cx, exObj));
|
||||
xpcReport->LogToConsoleWithStack(stackVal);
|
||||
} else {
|
||||
xpcReport->LogToConsole();
|
||||
|
|
|
@ -238,7 +238,9 @@ task syncPreprocessedCode(type: Sync, dependsOn: rootProject.generateCodeAndReso
|
|||
// entities. (Each locale produces its own .dtd file, backstopped by the en-US
|
||||
// .dtd file in tree.) Android Studio (and IntelliJ) don't handle these inline
|
||||
// entities smoothly. This filter merely expands the entities in place, making
|
||||
// them appear properly throughout the IDE.
|
||||
// them appear properly throughout the IDE. Be aware that this assumes that the
|
||||
// JVM's file.encoding is utf-8. See comments in
|
||||
// mobile/android/mach_commands.py.
|
||||
class ExpandXMLEntitiesFilter extends FilterReader {
|
||||
ExpandXMLEntitiesFilter(Reader input) {
|
||||
// Extremely inefficient, but whatever.
|
||||
|
|
|
@ -211,7 +211,6 @@ ifdef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
|
|||
.gradle.deps: .aapt.deps FORCE
|
||||
@$(TOUCH) $@
|
||||
$(topsrcdir)/mach gradle \
|
||||
$(if $(MOZILLA_OFFICIAL),--no-daemon --offline --info) \
|
||||
app:assembleAutomationDebug app:assembleAutomationDebugAndroidTest -x lint
|
||||
|
||||
classes.dex: .gradle.deps
|
||||
|
|
|
@ -161,6 +161,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BrowserApp extends GeckoApp
|
||||
implements TabsPanel.TabsLayoutChangeListener,
|
||||
|
@ -2433,6 +2434,11 @@ public class BrowserApp extends GeckoApp
|
|||
return;
|
||||
}
|
||||
|
||||
// Filter out URLs and long suggestions
|
||||
if (query.length() > 50 || Pattern.matches("^(https?|ftp|file)://.*", query)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final GeckoProfile profile = getProfile();
|
||||
// Don't bother storing search queries in guest mode
|
||||
if (profile.inGuestMode()) {
|
||||
|
|
|
@ -39,7 +39,9 @@ import android.widget.TextView;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
class SearchEngineRow extends AnimatedHeightLayout {
|
||||
// Duration for fade-in animation
|
||||
|
@ -383,6 +385,18 @@ class SearchEngineRow extends AnimatedHeightLayout {
|
|||
|
||||
// Remove duplicates of search engine suggestions from saved searches.
|
||||
List<String> searchHistorySuggestions = (rawSearchHistorySuggestions != null) ? rawSearchHistorySuggestions : new ArrayList<String>();
|
||||
|
||||
// Filter out URLs and long search suggestions
|
||||
Iterator<String> searchistoryIterator = searchHistorySuggestions.iterator();
|
||||
while (searchistoryIterator.hasNext()) {
|
||||
final String currentSearchHistory = searchistoryIterator.next();
|
||||
|
||||
if (currentSearchHistory.length() > 50 || Pattern.matches("^(https?|ftp|file)://.*", currentSearchHistory)) {
|
||||
searchHistorySuggestions.remove(currentSearchHistory);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<String> searchEngineSuggestions = new ArrayList<String>();
|
||||
for (String suggestion : searchEngine.getSuggestions()) {
|
||||
searchHistorySuggestions.remove(suggestion);
|
||||
|
|
|
@ -2283,6 +2283,11 @@ var NativeWindow = {
|
|||
aButtons = [];
|
||||
}
|
||||
|
||||
if (aButtons.length > 2) {
|
||||
console.log("Doorhanger can have a maximum of two buttons!");
|
||||
aButtons.length = 2;
|
||||
}
|
||||
|
||||
aButtons.forEach((function(aButton) {
|
||||
this._callbacks[this._callbacksId] = { cb: aButton.callback, prompt: this._promptId };
|
||||
aButton.callback = this._callbacksId;
|
||||
|
|
|
@ -38,5 +38,13 @@
|
|||
"unpack": true,
|
||||
"digest": "ef1d0038da879cc6840fced87671f8f6a18c51375498804f64d21fa48d7089ded4da2be36bd06a1457083e9110e59c0884f1e074dc609d29617c131caea8f234",
|
||||
"size": 50542140
|
||||
},
|
||||
{
|
||||
"algorithm": "sha512",
|
||||
"visibility": "public",
|
||||
"filename": "dotgradle.tar.xz",
|
||||
"unpack": true,
|
||||
"digest": "9f082ccd71ad18991eb71fcad355c6990f50a72a09ab9b79696521485656083a72faf5a8d4714de9c4b901ee2319b6786a51964846bb7075061642a8505501c2",
|
||||
"size": 512
|
||||
}
|
||||
]
|
||||
|
|
|
@ -57,6 +57,12 @@ class MachCommands(MachCommandBase):
|
|||
# Avoid logging the command
|
||||
self.log_manager.terminal_handler.setLevel(logging.CRITICAL)
|
||||
|
||||
|
||||
# In automation, JAVA_HOME is set via mozconfig, which needs
|
||||
# to be specially handled in each mach command. This turns
|
||||
# $JAVA_HOME/bin/java into $JAVA_HOME.
|
||||
java_home = os.path.dirname(os.path.dirname(self.substs['JAVA']))
|
||||
|
||||
# We force the Gradle JVM to run with the UTF-8 encoding, since we
|
||||
# filter strings.xml, which is really UTF-8; the ellipsis character is
|
||||
# replaced with ??? in some encodings (including ASCII). It's not yet
|
||||
|
@ -67,7 +73,10 @@ class MachCommands(MachCommandBase):
|
|||
# http://tools.android.com/knownissues/encoding. See
|
||||
# http://stackoverflow.com/a/21267635 for discussion of this approach.
|
||||
return self.run_process([self.substs['GRADLE']] + args,
|
||||
append_env={'GRADLE_OPTS': '-Dfile.encoding=utf-8'},
|
||||
append_env={
|
||||
'GRADLE_OPTS': '-Dfile.encoding=utf-8',
|
||||
'JAVA_HOME': java_home,
|
||||
},
|
||||
pass_thru=True, # Allow user to run gradle interactively.
|
||||
ensure_exit_code=False, # Don't throw on non-zero exit code.
|
||||
cwd=mozpath.join(self.topsrcdir))
|
||||
|
|
|
@ -293,18 +293,29 @@ public class AndroidFxAccount {
|
|||
}
|
||||
|
||||
public String getProfileServerURI() {
|
||||
return accountManager.getUserData(account, ACCOUNT_KEY_PROFILE_SERVER);
|
||||
String profileURI = accountManager.getUserData(account, ACCOUNT_KEY_PROFILE_SERVER);
|
||||
if (profileURI == null) {
|
||||
if (isStaging()) {
|
||||
return FxAccountConstants.STAGE_PROFILE_SERVER_ENDPOINT;
|
||||
}
|
||||
return FxAccountConstants.DEFAULT_PROFILE_SERVER_ENDPOINT;
|
||||
}
|
||||
return profileURI;
|
||||
}
|
||||
|
||||
public String getOAuthServerURI() {
|
||||
// Allow testing against stage.
|
||||
if (FxAccountConstants.STAGE_AUTH_SERVER_ENDPOINT.equals(getAccountServerURI())) {
|
||||
if (isStaging()) {
|
||||
return FxAccountConstants.STAGE_OAUTH_SERVER_ENDPOINT;
|
||||
} else {
|
||||
return FxAccountConstants.DEFAULT_OAUTH_SERVER_ENDPOINT;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStaging() {
|
||||
return FxAccountConstants.STAGE_AUTH_SERVER_ENDPOINT.equals(getAccountServerURI());
|
||||
}
|
||||
|
||||
private String constructPrefsPath(String product, long version, String extra) throws GeneralSecurityException, UnsupportedEncodingException {
|
||||
String profile = getProfile();
|
||||
String username = account.name;
|
||||
|
|
|
@ -5,22 +5,24 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsNSSCallbacks.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsNSSComponent.h"
|
||||
#include "nsNSSIOLayer.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsProtectedAuthThread.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsICertOverrideService.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIPrompt.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "nsITokenDialogs.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsIPrompt.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "PSMRunnable.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsNSSComponent.h"
|
||||
#include "nsNSSIOLayer.h"
|
||||
#include "nsProtectedAuthThread.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "PSMRunnable.h"
|
||||
#include "SharedSSLState.h"
|
||||
#include "ssl.h"
|
||||
#include "sslproto.h"
|
||||
|
@ -1235,6 +1237,17 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
|
|||
bool renegotiationUnsafe = !siteSupportsSafeRenego &&
|
||||
ioLayerHelpers.treatUnsafeNegotiationAsBroken();
|
||||
|
||||
|
||||
/* Set the SSL Status information */
|
||||
RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
|
||||
if (!status) {
|
||||
status = new nsSSLStatus();
|
||||
infoObject->SetSSLStatus(status);
|
||||
}
|
||||
|
||||
RememberCertErrorsTable::GetInstance().LookupCertErrorBits(infoObject,
|
||||
status);
|
||||
|
||||
uint32_t state;
|
||||
if (usesWeakCipher || renegotiationUnsafe) {
|
||||
state = nsIWebProgressListener::STATE_IS_BROKEN;
|
||||
|
@ -1252,6 +1265,39 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
|
|||
infoObject->GetPort());
|
||||
}
|
||||
}
|
||||
|
||||
if (status->HasServerCert()) {
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
||||
("HandshakeCallback KEEPING existing cert\n"));
|
||||
} else {
|
||||
ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
|
||||
RefPtr<nsNSSCertificate> nssc(nsNSSCertificate::Create(serverCert.get()));
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
||||
("HandshakeCallback using NEW cert %p\n", nssc.get()));
|
||||
status->SetServerCert(nssc, nsNSSCertificate::ev_status_unknown);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICertOverrideService> overrideService =
|
||||
do_GetService(NS_CERTOVERRIDE_CONTRACTID);
|
||||
|
||||
if (overrideService) {
|
||||
bool haveOverride;
|
||||
uint32_t overrideBits = 0; // Unused.
|
||||
bool isTemporaryOverride; // Unused.
|
||||
const nsACString& hostString(infoObject->GetHostName());
|
||||
const int32_t port(infoObject->GetPort());
|
||||
nsCOMPtr<nsIX509Cert> cert;
|
||||
status->GetServerCert(getter_AddRefs(cert));
|
||||
nsresult nsrv = overrideService->HasMatchingOverride(hostString, port,
|
||||
cert,
|
||||
&overrideBits,
|
||||
&isTemporaryOverride,
|
||||
&haveOverride);
|
||||
if (NS_SUCCEEDED(nsrv) && haveOverride) {
|
||||
state |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
infoObject->SetSecurityState(state);
|
||||
|
||||
// XXX Bug 883674: We shouldn't be formatting messages here in PSM; instead,
|
||||
|
@ -1270,27 +1316,6 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
|
|||
nsContentUtils::LogSimpleConsoleError(msg, "SSL");
|
||||
}
|
||||
|
||||
/* Set the SSL Status information */
|
||||
RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
|
||||
if (!status) {
|
||||
status = new nsSSLStatus();
|
||||
infoObject->SetSSLStatus(status);
|
||||
}
|
||||
|
||||
RememberCertErrorsTable::GetInstance().LookupCertErrorBits(infoObject,
|
||||
status);
|
||||
|
||||
if (status->HasServerCert()) {
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
||||
("HandshakeCallback KEEPING existing cert\n"));
|
||||
} else {
|
||||
ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
|
||||
RefPtr<nsNSSCertificate> nssc(nsNSSCertificate::Create(serverCert.get()));
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
|
||||
("HandshakeCallback using NEW cert %p\n", nssc.get()));
|
||||
status->SetServerCert(nssc, nsNSSCertificate::ev_status_unknown);
|
||||
}
|
||||
|
||||
infoObject->NoteTimeUntilReady();
|
||||
infoObject->SetHandshakeCompleted();
|
||||
}
|
||||
|
|
|
@ -1117,6 +1117,14 @@ nsNSSComponent::InitializeNSS()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Initialize the cert override service
|
||||
nsCOMPtr<nsICertOverrideService> coService =
|
||||
do_GetService(NS_CERTOVERRIDE_CONTRACTID);
|
||||
if (!coService) {
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Cannot initialize cert override service\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (PK11_IsFIPS()) {
|
||||
Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ nsSecureBrowserUIImpl::nsSecureBrowserUIImpl()
|
|||
, mIsViewSource(false)
|
||||
, mSubRequestsBrokenSecurity(0)
|
||||
, mSubRequestsNoSecurity(0)
|
||||
, mCertUserOverridden(false)
|
||||
, mRestoreSubrequests(false)
|
||||
, mOnLocationChangeSeen(false)
|
||||
#ifdef DEBUG
|
||||
|
@ -233,6 +234,10 @@ nsSecureBrowserUIImpl::MapInternalToExternalState(uint32_t* aState, lockIconStat
|
|||
if (ev && (*aState & STATE_IS_SECURE))
|
||||
*aState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL;
|
||||
|
||||
if (mCertUserOverridden && (*aState & STATE_IS_SECURE)) {
|
||||
*aState |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
|
||||
if (!docShell)
|
||||
return NS_OK;
|
||||
|
@ -260,6 +265,9 @@ nsSecureBrowserUIImpl::MapInternalToExternalState(uint32_t* aState, lockIconStat
|
|||
if (ev) {
|
||||
*aState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL;
|
||||
}
|
||||
if (mCertUserOverridden) {
|
||||
*aState |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
|
||||
}
|
||||
}
|
||||
// * If so, the state should be broken or insecure; overriding the previous
|
||||
// state set by the lock parameter.
|
||||
|
@ -793,6 +801,11 @@ nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
|
|||
f -= nsIWebProgressListener::STATE_SECURE_HIGH;
|
||||
info.AppendLiteral("SECURE_HIGH ");
|
||||
}
|
||||
if (f & nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN)
|
||||
{
|
||||
f -= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
|
||||
info.AppendLiteral("STATE_CERT_USER_OVERRIDDEN ");
|
||||
}
|
||||
if (f & nsIWebProgressListener::STATE_RESTORING)
|
||||
{
|
||||
f -= nsIWebProgressListener::STATE_RESTORING;
|
||||
|
@ -1131,6 +1144,9 @@ nsSecureBrowserUIImpl::UpdateSecurityState(nsIRequest* aRequest,
|
|||
newSecurityState = lis_broken_security;
|
||||
}
|
||||
|
||||
mCertUserOverridden =
|
||||
mNewToplevelSecurityState & STATE_CERT_USER_OVERRIDDEN;
|
||||
|
||||
MOZ_LOG(gSecureDocLog, LogLevel::Debug,
|
||||
("SecureUI:%p: UpdateSecurityState: old-new %d - %d\n", this,
|
||||
mNotifiedSecurityState, newSecurityState));
|
||||
|
|
|
@ -74,6 +74,7 @@ protected:
|
|||
int32_t mDocumentRequestsInProgress;
|
||||
int32_t mSubRequestsBrokenSecurity;
|
||||
int32_t mSubRequestsNoSecurity;
|
||||
bool mCertUserOverridden;
|
||||
bool mRestoreSubrequests;
|
||||
bool mOnLocationChangeSeen;
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -662,7 +662,11 @@ function add_cert_override(aHost, aExpectedBits, aSecurityInfo) {
|
|||
function add_cert_override_test(aHost, aExpectedBits, aExpectedError) {
|
||||
add_connection_test(aHost, aExpectedError, null,
|
||||
add_cert_override.bind(this, aHost, aExpectedBits));
|
||||
add_connection_test(aHost, PRErrorCodeSuccess);
|
||||
add_connection_test(aHost, PRErrorCodeSuccess, null, aSecurityInfo => {
|
||||
Assert.ok(aSecurityInfo.securityState &
|
||||
Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN,
|
||||
"Cert override flag should be set on the security state");
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function for add_prevented_cert_override_test. This is much like
|
||||
|
|
|
@ -5,4 +5,8 @@ config = {
|
|||
'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-15-frontend/nightly',
|
||||
'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android-frontend/releng.manifest',
|
||||
'multi_locale_config_platform': 'android',
|
||||
'postflight_build_mach_commands': [
|
||||
['gradle', 'app:lintAutomationDebug'],
|
||||
['gradle', 'app:testAutomationDebugUnitTest'],
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1881,6 +1881,26 @@ or run without that action (ie: --no-{action})"
|
|||
if self.config.get('enable_ccache'):
|
||||
self._ccache_s()
|
||||
|
||||
# A list of argument lists. Better names gratefully accepted!
|
||||
mach_commands = self.config.get('postflight_build_mach_commands', [])
|
||||
for mach_command in mach_commands:
|
||||
self._execute_postflight_build_mach_command(mach_command)
|
||||
|
||||
def _execute_postflight_build_mach_command(self, mach_command_args):
|
||||
env = self.query_build_env()
|
||||
env.update(self.query_mach_build_env())
|
||||
python = self.query_exe('python2.7')
|
||||
|
||||
command = [python, 'mach', '--log-no-times']
|
||||
command.extend(mach_command_args)
|
||||
|
||||
self.run_command_m(
|
||||
command=command,
|
||||
cwd=self.query_abs_dirs()['abs_src_dir'],
|
||||
env=env, output_timeout=self.config.get('max_build_output_timeout', 60 * 20),
|
||||
halt_on_failure=True,
|
||||
)
|
||||
|
||||
def preflight_package_source(self):
|
||||
self._get_mozconfig()
|
||||
|
||||
|
|
|
@ -39,11 +39,30 @@ task:
|
|||
MH_CUSTOM_BUILD_VARIANT_CFG: api-15-frontend
|
||||
MH_BRANCH: {{project}}
|
||||
MH_BUILD_POOL: taskcluster
|
||||
GRADLE_USER_HOME: '/home/worker/workspace/build/src/dotgradle'
|
||||
|
||||
maxRunTime: 36000
|
||||
|
||||
command: ["/bin/bash", "bin/build.sh"]
|
||||
|
||||
artifacts:
|
||||
'public/android/unittest':
|
||||
type: directory
|
||||
path: '/home/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/reports/tests'
|
||||
expires: '{{#from_now}}1 year{{/from_now}}'
|
||||
'public/android/lint/lint-results-automationDebug.html':
|
||||
type: file
|
||||
path: '/home/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/outputs/lint-results-automationDebug.html'
|
||||
expires: '{{#from_now}}1 year{{/from_now}}'
|
||||
'public/android/lint/lint-results-automationDebug.xml':
|
||||
type: file
|
||||
path: '/home/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/outputs/lint-results-automationDebug.xml'
|
||||
expires: '{{#from_now}}1 year{{/from_now}}'
|
||||
'public/android/lint/lint-results-automationDebug_files':
|
||||
type: directory
|
||||
path: '/home/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/outputs/lint-results-automationDebug_files'
|
||||
expires: '{{#from_now}}1 year{{/from_now}}'
|
||||
|
||||
extra:
|
||||
treeherderEnv:
|
||||
- production
|
||||
|
@ -51,7 +70,11 @@ task:
|
|||
treeherder:
|
||||
machine:
|
||||
# see https://github.com/mozilla/treeherder/blob/master/ui/js/values.js
|
||||
platform: android-4-0-armv7-api15-frontend
|
||||
platform: android-4-0-armv7-api15
|
||||
groupSymbol: tc
|
||||
groupName: Submitted by taskcluster
|
||||
symbol: Unit
|
||||
tier: 2
|
||||
# Rather then enforcing particular conventions we require that all build
|
||||
# tasks provide the "build" extra field to specify where the build and tests
|
||||
# files are located.
|
||||
|
|
|
@ -46,6 +46,7 @@ var {
|
|||
Messenger,
|
||||
injectAPI,
|
||||
flushJarCache,
|
||||
detectLanguage,
|
||||
} = ExtensionUtils;
|
||||
|
||||
function isWhenBeforeOrSame(when1, when2) {
|
||||
|
@ -122,6 +123,11 @@ var api = context => {
|
|||
getUILanguage: function() {
|
||||
return context.extension.localeData.uiLocale;
|
||||
},
|
||||
|
||||
detectLanguage: function(text, callback) {
|
||||
let result = detectLanguage(text);
|
||||
return context.wrapPromise(result, callback);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -16,7 +16,8 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LanguageDetector",
|
||||
"resource:///modules/translation/LanguageDetector.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Locale",
|
||||
"resource://gre/modules/Locale.jsm");
|
||||
|
||||
|
@ -433,7 +434,6 @@ LocaleData.prototype = {
|
|||
// locale code.
|
||||
return Locale.getLocale().replace(/-/g, "_");
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// This is a generic class for managing event listeners. Example usage:
|
||||
|
@ -961,6 +961,18 @@ const PlatformInfo = Object.freeze({
|
|||
})(),
|
||||
});
|
||||
|
||||
function detectLanguage(text) {
|
||||
return LanguageDetector.detectLanguage(text).then(result => ({
|
||||
isReliable: result.confident,
|
||||
languages: result.languages.map(lang => {
|
||||
return {
|
||||
language: lang.languageCode,
|
||||
percentage: lang.percent,
|
||||
};
|
||||
}),
|
||||
}));
|
||||
}
|
||||
|
||||
this.ExtensionUtils = {
|
||||
runSafeWithoutClone,
|
||||
runSafeSyncWithoutClone,
|
||||
|
@ -980,4 +992,5 @@ this.ExtensionUtils = {
|
|||
extend,
|
||||
flushJarCache,
|
||||
instanceOf,
|
||||
detectLanguage,
|
||||
};
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
var {
|
||||
detectLanguage,
|
||||
} = ExtensionUtils;
|
||||
|
||||
extensions.registerSchemaAPI("i18n", null, (extension, context) => {
|
||||
return {
|
||||
i18n: {
|
||||
|
@ -10,6 +15,10 @@ extensions.registerSchemaAPI("i18n", null, (extension, context) => {
|
|||
getUILanguage: function() {
|
||||
return extension.localeData.uiLocale;
|
||||
},
|
||||
|
||||
detectLanguage: function(text) {
|
||||
return detectLanguage(text);
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
@ -78,7 +78,6 @@
|
|||
},
|
||||
{
|
||||
"name": "detectLanguage",
|
||||
"unsupported": true,
|
||||
"type": "function",
|
||||
"description": "Detects the language of the provided text using CLD.",
|
||||
"async": "callback",
|
||||
|
|
|
@ -242,6 +242,119 @@ add_task(function* test_get_ui_language() {
|
|||
yield extension.unload();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_detect_language() {
|
||||
const af_string = " aam skukuza die naam beteken hy wat skoonvee of hy wat alles onderstebo keer wysig " +
|
||||
"bosveldkampe boskampe is kleiner afgeleë ruskampe wat oor min fasiliteite beskik daar is geen restaurante " +
|
||||
"of winkels nie en slegs oornagbesoekers word toegelaat bateleur";
|
||||
// String with intermixed French/English text
|
||||
const fr_en_string = "France is the largest country in Western Europe and the third-largest in Europe as a whole. " +
|
||||
"A accès aux chiens et aux frontaux qui lui ont été il peut consulter et modifier ses collections et exporter " +
|
||||
"Cet article concerne le pays européen aujourd’hui appelé République française. Pour d’autres usages du nom France, " +
|
||||
"Pour une aide rapide et effective, veuiller trouver votre aide dans le menu ci-dessus." +
|
||||
"Motoring events began soon after the construction of the first successful gasoline-fueled automobiles. The quick brown fox jumped over the lazy dog";
|
||||
|
||||
function backgroundScript() {
|
||||
function checkResult(source, result, expected) {
|
||||
browser.test.assertEq(expected.isReliable, result.isReliable, "result.confident is true");
|
||||
browser.test.assertEq(
|
||||
expected.languages.length,
|
||||
result.languages.length,
|
||||
`result.languages contains the expected number of languages in ${source}`);
|
||||
expected.languages.forEach((lang, index) => {
|
||||
browser.test.assertEq(
|
||||
lang.percentage,
|
||||
result.languages[index].percentage,
|
||||
`element ${index} of result.languages array has the expected percentage in ${source}`);
|
||||
browser.test.assertEq(
|
||||
lang.language,
|
||||
result.languages[index].language,
|
||||
`element ${index} of result.languages array has the expected language in ${source}`);
|
||||
});
|
||||
}
|
||||
|
||||
let tabId;
|
||||
|
||||
browser.tabs.query({currentWindow: true, active: true}, tabs => {
|
||||
tabId = tabs[0].id;
|
||||
browser.test.sendMessage("ready");
|
||||
});
|
||||
|
||||
browser.test.onMessage.addListener(([msg, expected]) => {
|
||||
Promise.all([
|
||||
browser.i18n.detectLanguage(msg),
|
||||
new Promise(
|
||||
resolve => browser.tabs.sendMessage(tabId, msg, resolve)),
|
||||
]).then(([backgroundResults, contentResults]) => {
|
||||
checkResult("background", backgroundResults, expected);
|
||||
checkResult("contentScript", contentResults, expected);
|
||||
|
||||
browser.test.sendMessage("done");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function content() {
|
||||
browser.runtime.onMessage.addListener((msg, sender, respond) => {
|
||||
browser.i18n.detectLanguage(msg, respond);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"run_at": "document_start",
|
||||
"js": ["content_script.js"],
|
||||
}],
|
||||
},
|
||||
|
||||
background: `(${backgroundScript})()`,
|
||||
|
||||
files: {
|
||||
"content_script.js": `(${content})()`,
|
||||
},
|
||||
});
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
let expected = {
|
||||
isReliable: true,
|
||||
languages: [
|
||||
{
|
||||
language: "fr",
|
||||
percentage: 67,
|
||||
},
|
||||
{
|
||||
language: "en",
|
||||
percentage: 32,
|
||||
},
|
||||
],
|
||||
};
|
||||
extension.sendMessage([fr_en_string, expected]);
|
||||
yield extension.awaitMessage("done");
|
||||
|
||||
expected = {
|
||||
isReliable: true,
|
||||
languages: [
|
||||
{
|
||||
language: "af",
|
||||
percentage: 99,
|
||||
},
|
||||
],
|
||||
};
|
||||
extension.sendMessage([af_string, expected]);
|
||||
yield extension.awaitMessage("done");
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -464,7 +464,7 @@ Database::Init()
|
|||
// like views, temp triggers or temp tables. The database should not be
|
||||
// considered corrupt if any of the following fails.
|
||||
|
||||
rv = InitTempTriggers();
|
||||
rv = InitTempEntities();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Notify we have finished database initialization.
|
||||
|
@ -1015,7 +1015,7 @@ Database::InitFunctions()
|
|||
}
|
||||
|
||||
nsresult
|
||||
Database::InitTempTriggers()
|
||||
Database::InitTempEntities()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -1027,6 +1027,10 @@ Database::InitTempTriggers()
|
|||
// Add the triggers that update the moz_hosts table as necessary.
|
||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERINSERT_TRIGGER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTS_TEMP);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTS_AFTERDELETE_TRIGGER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERDELETE_TRIGGER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERUPDATE_FRECENCY_TRIGGER);
|
||||
|
|
|
@ -242,9 +242,9 @@ protected:
|
|||
nsresult InitFunctions();
|
||||
|
||||
/**
|
||||
* Initializes triggers defined in nsPlacesTriggers.h
|
||||
* Initializes temp entities, like triggers, tables, views...
|
||||
*/
|
||||
nsresult InitTempTriggers();
|
||||
nsresult InitTempEntities();
|
||||
|
||||
/**
|
||||
* Helpers used by schema upgrades.
|
||||
|
|
|
@ -1884,16 +1884,29 @@ private:
|
|||
}
|
||||
#endif
|
||||
|
||||
nsCString query("DELETE FROM moz_places "
|
||||
"WHERE id IN (");
|
||||
query.Append(placeIdsToRemove);
|
||||
query.Append(')');
|
||||
{
|
||||
nsCString query("DELETE FROM moz_places "
|
||||
"WHERE id IN (");
|
||||
query.Append(placeIdsToRemove);
|
||||
query.Append(')');
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt = mHistory->GetStatement(query);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
nsresult rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<mozIStorageStatement> stmt = mHistory->GetStatement(query);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
nsresult rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
{
|
||||
// Hosts accumulated during the places delete are updated through a trigger
|
||||
// (see nsPlacesTriggers.h).
|
||||
nsAutoCString query("DELETE FROM moz_updatehosts_temp");
|
||||
nsCOMPtr<mozIStorageStatement> stmt = mHistory->GetStatement(query);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
nsresult rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -501,8 +501,12 @@ var removePagesById = Task.async(function*(db, idList) {
|
|||
if (idList.length == 0) {
|
||||
return;
|
||||
}
|
||||
// Note, we are already in a transaction, since callers create it.
|
||||
yield db.execute(`DELETE FROM moz_places
|
||||
WHERE id IN ( ${ sqlList(idList) } )`);
|
||||
// Hosts accumulated during the places delete are updated through a trigger
|
||||
// (see nsPlacesTriggers.h).
|
||||
yield db.execute(`DELETE FROM moz_updatehosts_temp`);
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -2455,6 +2455,13 @@ nsNavHistory::CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString)
|
|||
);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Hosts accumulated during the places delete are updated through a trigger
|
||||
// (see nsPlacesTriggers.h).
|
||||
rv = mDB->MainConn()->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("DELETE FROM moz_updatehosts_temp")
|
||||
);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Invalidate frecencies of touched places, since they need recalculation.
|
||||
rv = invalidateFrecencies(aPlaceIdsQueryString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -241,6 +241,15 @@ const EXPIRATION_QUERIES = {
|
|||
actions: ACTION.CLEAR_HISTORY
|
||||
},
|
||||
|
||||
// Hosts accumulated during the places delete are updated through a trigger
|
||||
// (see nsPlacesTriggers.h).
|
||||
QUERY_UPDATE_HOSTS: {
|
||||
sql: `DELETE FROM moz_updatehosts_temp`,
|
||||
actions: ACTION.CLEAR_HISTORY | ACTION.TIMED | ACTION.TIMED_OVERLIMIT |
|
||||
ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
|
||||
ACTION.DEBUG
|
||||
},
|
||||
|
||||
// Expire orphan icons from the database.
|
||||
QUERY_EXPIRE_FAVICONS: {
|
||||
sql: `DELETE FROM moz_favicons WHERE id IN (
|
||||
|
|
|
@ -144,4 +144,15 @@
|
|||
")" \
|
||||
)
|
||||
|
||||
// This table is used, along with moz_places_afterdelete_trigger, to update
|
||||
// hosts after places removals. During a DELETE FROM moz_places, hosts are
|
||||
// accumulated into this table, then a DELETE FROM moz_updatehosts_temp will
|
||||
// take care of updating the moz_hosts table for every modified host.
|
||||
// See CREATE_PLACES_AFTERDELETE_TRIGGER in nsPlacestriggers.h for details.
|
||||
#define CREATE_UPDATEHOSTS_TEMP NS_LITERAL_CSTRING( \
|
||||
"CREATE TEMP TABLE moz_updatehosts_temp (" \
|
||||
" host TEXT PRIMARY KEY " \
|
||||
") WITHOUT ROWID " \
|
||||
)
|
||||
|
||||
#endif // __nsPlacesTables_h__
|
||||
|
|
|
@ -110,12 +110,31 @@
|
|||
"END" \
|
||||
)
|
||||
|
||||
// This is a hack to workaround the lack of FOR EACH STATEMENT in Sqlite, until
|
||||
// bug 871908 can be fixed properly.
|
||||
// We store the modified hosts in a temp table, and after every DELETE FROM
|
||||
// moz_places, we issue a DELETE FROM moz_updatehosts_temp. The AFTER DELETE
|
||||
// trigger will then take care of updating the moz_hosts table.
|
||||
// Note this way we lose atomicity, crashing between the 2 queries may break the
|
||||
// hosts table coherency. So it's better to run those DELETE queries in a single
|
||||
// transaction.
|
||||
// Regardless, this is still better than hanging the browser for several minutes
|
||||
// on a fast machine.
|
||||
#define CREATE_PLACES_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
|
||||
"CREATE TEMP TRIGGER moz_places_afterdelete_trigger " \
|
||||
"AFTER DELETE ON moz_places FOR EACH ROW " \
|
||||
"BEGIN " \
|
||||
"INSERT OR IGNORE INTO moz_updatehosts_temp (host)" \
|
||||
"VALUES (fixup_url(get_unreversed_host(OLD.rev_host)));" \
|
||||
"END" \
|
||||
)
|
||||
|
||||
#define CREATE_UPDATEHOSTS_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
|
||||
"CREATE TEMP TRIGGER moz_updatehosts_afterdelete_trigger " \
|
||||
"AFTER DELETE ON moz_updatehosts_temp FOR EACH ROW " \
|
||||
"BEGIN " \
|
||||
"DELETE FROM moz_hosts " \
|
||||
"WHERE host = fixup_url(get_unreversed_host(OLD.rev_host)) " \
|
||||
"WHERE host = OLD.host " \
|
||||
"AND NOT EXISTS(" \
|
||||
"SELECT 1 FROM moz_places " \
|
||||
"WHERE rev_host = get_unreversed_host(host || '.') || '.' " \
|
||||
|
@ -123,7 +142,7 @@
|
|||
"); " \
|
||||
"UPDATE moz_hosts " \
|
||||
"SET prefix = (" HOSTS_PREFIX_PRIORITY_FRAGMENT ") " \
|
||||
"WHERE host = fixup_url(get_unreversed_host(OLD.rev_host)); " \
|
||||
"WHERE host = OLD.host; " \
|
||||
"END" \
|
||||
)
|
||||
|
||||
|
|
|
@ -660,13 +660,15 @@ var Impl = {
|
|||
// and payload is the telemetry payload from that child process.
|
||||
_childTelemetry: [],
|
||||
// Thread hangs from child processes.
|
||||
// Used for TelemetrySession.getChildThreadHangs(); not sent with Telemetry pings.
|
||||
// TelemetrySession.getChildThreadHangs() is used by extensions such as Statuser (https://github.com/chutten/statuser).
|
||||
// Each element is in the format {source: <weak-ref>, payload: <object>},
|
||||
// where source is a weak reference to the child process,
|
||||
// and payload contains the thread hang stats from that child process.
|
||||
_childThreadHangs: [],
|
||||
// Array of the resolve functions of all the promises that are waiting for the child thread hang stats to arrive, used to resolve all those promises at once
|
||||
// Array of the resolve functions of all the promises that are waiting for the child thread hang stats to arrive, used to resolve all those promises at once.
|
||||
_childThreadHangsResolveFunctions: [],
|
||||
// Timeout function for child thread hang stats retrieval
|
||||
// Timeout function for child thread hang stats retrieval.
|
||||
_childThreadHangsTimeout: null,
|
||||
// Unique id that identifies this session so the server can cope with duplicate
|
||||
// submissions, orphaning and other oddities. The id is shared across subsessions.
|
||||
|
|
|
@ -205,8 +205,6 @@ function isCorrectlySigned(aAddon) {
|
|||
return true;
|
||||
if (aAddon.signedState <= AddonManager.SIGNEDSTATE_MISSING)
|
||||
return false;
|
||||
if (aAddon.foreignInstall && aAddon.signedState < AddonManager.SIGNEDSTATE_SIGNED)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -693,8 +693,6 @@ function isUsableAddon(aAddon) {
|
|||
mustSign(aAddon.type)) {
|
||||
if (aAddon.signedState <= AddonManager.SIGNEDSTATE_MISSING)
|
||||
return false;
|
||||
if (aAddon.foreignInstall && aAddon.signedState < AddonManager.SIGNEDSTATE_SIGNED)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aAddon.blocklistState == Blocklist.STATE_BLOCKED)
|
||||
|
@ -8015,6 +8013,12 @@ Object.assign(SystemAddonInstallLocation.prototype, {
|
|||
* to cleanup again next time.
|
||||
*/
|
||||
cleanDirectories: Task.async(function*() {
|
||||
|
||||
// System add-ons directory does not exist
|
||||
if (!(yield OS.File.exists(this._baseDir.path))) {
|
||||
return;
|
||||
}
|
||||
|
||||
let iterator;
|
||||
try {
|
||||
iterator = new OS.File.DirectoryIterator(this._baseDir.path);
|
||||
|
|
|
@ -868,13 +868,11 @@ add_test(function() {
|
|||
is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
|
||||
is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
|
||||
|
||||
is_element_hidden(get("detail-warning"), "Warning message should be hidden");
|
||||
is_element_visible(get("detail-warning"), "Warning message should be visible");
|
||||
is(get("detail-warning").textContent, "Test add-on 11 is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
|
||||
is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
|
||||
is_element_visible(get("detail-error"), "Error message should be visible");
|
||||
is(get("detail-error").textContent, "Test add-on 11 could not be verified for use in " + gApp + " and has been disabled.", "Error message should be correct");
|
||||
is_element_visible(get("detail-error-link"), "Error link should be visible");
|
||||
is(get("detail-error-link").value, "More Information", "Error link text should be correct");
|
||||
is(get("detail-error-link").href, infoURL, "Error link should be correct");
|
||||
is_element_hidden(get("detail-error"), "Error message should be hidden");
|
||||
is_element_hidden(get("detail-error-link"), "Error link should be hidden");
|
||||
|
||||
close_manager(gManagerWindow, function() {
|
||||
Services.prefs.setBoolPref("xpinstall.signatures.required", false);
|
||||
|
|
|
@ -110,8 +110,6 @@ add_task(function*() {
|
|||
id: "addon12@tests.mozilla.org",
|
||||
name: "Test add-on 12",
|
||||
signedState: AddonManager.SIGNEDSTATE_PRELIMINARY,
|
||||
isActive: false,
|
||||
appDisabled: true,
|
||||
foreignInstall: true,
|
||||
}, {
|
||||
id: "addon13@tests.mozilla.org",
|
||||
|
@ -892,16 +890,13 @@ add_task(function*() {
|
|||
|
||||
is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
|
||||
is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
|
||||
is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
|
||||
is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
|
||||
is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
|
||||
|
||||
is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
|
||||
is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
|
||||
is_element_visible(get_node(addon, "error"), "Error message should be visible");
|
||||
is(get_node(addon, "error").textContent, "Test add-on 12 could not be verified for use in " + gApp + " and has been disabled.", "Error message should be correct");
|
||||
is_element_visible(get_node(addon, "error-link"), "Error link should be visible");
|
||||
is(get_node(addon, "error-link").value, "More Information", "Error link text should be correct");
|
||||
is(get_node(addon, "error-link").href, infoURL, "Error link should be correct");
|
||||
is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
|
||||
is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
|
||||
|
||||
info("Addon 13");
|
||||
addon = items["Test add-on 13"];
|
||||
|
@ -936,10 +931,9 @@ add_task(function*() {
|
|||
is_element_visible(signingInfoUI, "Signing info UI should be visible");
|
||||
|
||||
items = get_test_items();
|
||||
is(Object.keys(items).length, 3, "Two add-ons should be shown");
|
||||
is(Object.keys(items).length, 2, "Two add-ons should be shown");
|
||||
is(Object.keys(items)[0], "Test add-on 10", "The disabled unsigned extension should be shown");
|
||||
is(Object.keys(items)[1], "Test add-on 11", "The disabled unsigned extension should be shown");
|
||||
is(Object.keys(items)[2], "Test add-on 12", "The disabled foreign installed extension should be shown");
|
||||
|
||||
showAllButton.click();
|
||||
|
||||
|
|
|
@ -336,7 +336,7 @@ add_task(function*() {
|
|||
resetPrefs();
|
||||
});
|
||||
|
||||
// Only fully-signed sideloaded add-ons should work
|
||||
// Preliminarily-signed sideloaded add-ons should work
|
||||
add_task(function*() {
|
||||
let file = manuallyInstall(do_get_file(DATA + ADDONS.bootstrap.preliminary), profileDir, ID);
|
||||
|
||||
|
@ -345,10 +345,10 @@ add_task(function*() {
|
|||
// Currently we leave the sideloaded add-on there but just don't run it
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
do_check_true(addon.appDisabled);
|
||||
do_check_false(addon.isActive);
|
||||
do_check_false(addon.appDisabled);
|
||||
do_check_true(addon.isActive);
|
||||
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_PRELIMINARY);
|
||||
do_check_eq(getActiveVersion(), -1);
|
||||
do_check_eq(getActiveVersion(), 2);
|
||||
|
||||
addon.uninstall();
|
||||
yield promiseShutdownManager();
|
||||
|
|
|
@ -262,9 +262,13 @@ interface nsIWebProgressListener : nsISupports
|
|||
*
|
||||
* STATE_USES_WEAK_CRYPTO
|
||||
* The topmost document uses a weak cipher suite such as RC4.
|
||||
*
|
||||
* STATE_CERT_USER_OVERRIDDEN
|
||||
* The user has added a security exception for the site.
|
||||
*/
|
||||
const unsigned long STATE_USES_SSL_3 = 0x01000000;
|
||||
const unsigned long STATE_USES_WEAK_CRYPTO = 0x02000000;
|
||||
const unsigned long STATE_CERT_USER_OVERRIDDEN = 0x04000000;
|
||||
|
||||
/**
|
||||
* Notification indicating the state has changed for one of the requests
|
||||
|
|
Загрузка…
Ссылка в новой задаче