Merge mozilla-central to mozilla-inbound on a CLOSED TREE

This commit is contained in:
dvarga 2018-07-27 20:55:06 +03:00
Родитель 652dac8690 d78485112a
Коммит edd9f3a3d9
82 изменённых файлов: 3346 добавлений и 1665 удалений

Просмотреть файл

@ -741,26 +741,6 @@ pref("layout.spellcheckDefault", 1);
pref("browser.send_pings", false);
/* initial web feed readers list */
pref("browser.contentHandlers.types.0.title", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.0.uri", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.0.type", "application/vnd.mozilla.maybe.feed");
pref("browser.contentHandlers.types.1.title", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.1.uri", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.1.type", "application/vnd.mozilla.maybe.feed");
pref("browser.contentHandlers.types.2.title", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.2.uri", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.2.type", "application/vnd.mozilla.maybe.feed");
pref("browser.contentHandlers.types.3.title", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.3.uri", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.3.type", "application/vnd.mozilla.maybe.feed");
pref("browser.contentHandlers.types.4.title", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.4.uri", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.4.type", "application/vnd.mozilla.maybe.feed");
pref("browser.contentHandlers.types.5.title", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.5.uri", "chrome://browser-region/locale/region.properties");
pref("browser.contentHandlers.types.5.type", "application/vnd.mozilla.maybe.feed");
pref("browser.feeds.handler", "ask");
pref("browser.videoFeeds.handler", "ask");
pref("browser.audioFeeds.handler", "ask");

Просмотреть файл

@ -13,17 +13,14 @@ const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
const PREF_SHOW_FIRST_RUN_UI = "browser.feeds.showFirstRunUI";
const PREF_SELECTED_APP = "browser.feeds.handlers.application";
const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
const PREF_SELECTED_ACTION = "browser.feeds.handler";
const PREF_SELECTED_READER = "browser.feeds.handler.default";
const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application";
const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler";
const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default";
const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application";
const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler";
const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default";
@ -35,10 +32,7 @@ const SETTABLE_PREFS = new Set([
PREF_SELECTED_ACTION,
PREF_VIDEO_SELECTED_READER,
PREF_AUDIO_SELECTED_READER,
PREF_SELECTED_READER,
PREF_VIDEO_SELECTED_WEB,
PREF_AUDIO_SELECTED_WEB,
PREF_SELECTED_WEB
PREF_SELECTED_READER
]);
const EXECUTABLE_PREFS = new Set([
@ -48,7 +42,7 @@ const EXECUTABLE_PREFS = new Set([
]);
const VALID_ACTIONS = new Set(["ask", "reader", "bookmarks"]);
const VALID_READERS = new Set(["web", "client", "default", "bookmarks"]);
const VALID_READERS = new Set(["client", "default", "bookmarks"]);
XPCOMUtils.defineLazyPreferenceGetter(this, "SHOULD_LOG",
"feeds.log", false);
@ -84,19 +78,6 @@ function getPrefReaderForType(t) {
}
}
function getPrefWebForType(t) {
switch (t) {
case Ci.nsIFeed.TYPE_VIDEO:
return PREF_VIDEO_SELECTED_WEB;
case Ci.nsIFeed.TYPE_AUDIO:
return PREF_AUDIO_SELECTED_WEB;
default:
return PREF_SELECTED_WEB;
}
}
function getPrefAppForType(t) {
switch (t) {
case Ci.nsIFeed.TYPE_VIDEO:
@ -427,13 +408,10 @@ var FeedHandler = {
const prefs = Services.prefs;
prefs.addObserver(PREF_SELECTED_ACTION, this, true);
prefs.addObserver(PREF_SELECTED_READER, this, true);
prefs.addObserver(PREF_SELECTED_WEB, this, true);
prefs.addObserver(PREF_VIDEO_SELECTED_ACTION, this, true);
prefs.addObserver(PREF_VIDEO_SELECTED_READER, this, true);
prefs.addObserver(PREF_VIDEO_SELECTED_WEB, this, true);
prefs.addObserver(PREF_AUDIO_SELECTED_ACTION, this, true);
prefs.addObserver(PREF_AUDIO_SELECTED_READER, this, true);
prefs.addObserver(PREF_AUDIO_SELECTED_WEB, this, true);
},
uninit() {
@ -464,11 +442,8 @@ var FeedHandler = {
// Rather than the others which happen on subscription
switch (prefName) {
case PREF_SELECTED_READER:
case PREF_SELECTED_WEB:
case PREF_VIDEO_SELECTED_READER:
case PREF_VIDEO_SELECTED_WEB:
case PREF_AUDIO_SELECTED_READER:
case PREF_AUDIO_SELECTED_WEB:
case PREF_SELECTED_ACTION:
case PREF_VIDEO_SELECTED_ACTION:
case PREF_AUDIO_SELECTED_ACTION:
@ -484,23 +459,8 @@ var FeedHandler = {
},
_initSubscriptionUIResponse(feedType) {
const wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentConverterService);
const handlersRaw = wccr.getContentHandlers(getMimeTypeForFeedType(feedType));
const handlers = [];
for (let handler of handlersRaw) {
LOG(`Handler found: ${handler}`);
handlers.push({
name: handler.name,
uri: handler.uri
});
}
let showFirstRunUI = true;
// eslint-disable-next-line mozilla/use-default-preference-values
try {
showFirstRunUI = Services.prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI);
} catch (ex) { }
const response = { handlers, showFirstRunUI };
let showFirstRunUI = Services.prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI, true);
const response = { showFirstRunUI };
let selectedClientApp;
const feedTypePref = getPrefAppForType(feedType);
try {
@ -545,25 +505,10 @@ var FeedHandler = {
},
_getReaderForType(feedType) {
let prefs = Services.prefs;
let handler = "bookmarks";
let url;
// eslint-disable-next-line mozilla/use-default-preference-values
try {
handler = prefs.getCharPref(getPrefReaderForType(feedType));
} catch (ex) { }
if (handler === "web") {
try {
url = prefs.getStringPref(getPrefWebForType(feedType));
} catch (ex) {
LOG("FeedWriter._setSelectedHandler: invalid or no handler in prefs");
url = null;
}
}
let handler = Services.prefs.getCharPref(getPrefReaderForType(feedType), "bookmarks");
const alwaysUse = this._getAlwaysUseState(feedType);
const action = prefs.getCharPref(getPrefActionForType(feedType));
return { handler, url, alwaysUse, action };
const action = Services.prefs.getCharPref(getPrefActionForType(feedType));
return { handler, alwaysUse, action };
},
_getAlwaysUseState(feedType) {
@ -574,7 +519,6 @@ var FeedHandler = {
},
receiveMessage(msg) {
let handler;
switch (msg.name) {
case "FeedWriter:GetSubscriptionUI":
const response = this._initSubscriptionUIResponse(msg.data.feedType);
@ -605,40 +549,16 @@ var FeedHandler = {
this._setPref(actionPref, settings.action);
const readerPref = getPrefReaderForType(settings.feedType);
this._setPref(readerPref, settings.reader);
handler = null;
switch (settings.reader) {
case "web":
// This is a web set URI by content using window.registerContentHandler()
// Lets make sure we know about it before setting it
const webPref = getPrefWebForType(settings.feedType);
let wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentConverterService);
// If the user provided an invalid web URL this function won't give us a reference
handler = wccr.getWebContentHandlerByURI(getMimeTypeForFeedType(settings.feedType), settings.uri);
if (handler) {
this._setPref(webPref, settings.uri, true);
if (settings.useAsDefault) {
wccr.setAutoHandler(getMimeTypeForFeedType(settings.feedType), handler);
}
msg.target.messageManager
.sendAsyncMessage("FeedWriter:SetFeedPrefsAndSubscribeResponse",
{ redirect: handler.getHandlerURI(settings.feedLocation) });
} else {
LOG(`No handler found for web ${settings.feedType} ${settings.uri}`);
}
break;
default:
const feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
getService(Ci.nsIFeedResultService);
const feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
getService(Ci.nsIFeedResultService);
feedService.addToClientReader(settings.feedLocation,
settings.feedTitle,
settings.feedSubtitle,
settings.feedType,
settings.reader);
}
break;
feedService.addToClientReader(settings.feedLocation,
settings.feedTitle,
settings.feedSubtitle,
settings.feedType,
settings.reader);
break;
case "FeedConverter:ExecuteClientApp":
// Always check feedHandler is from a set array of executable prefs
if (EXECUTABLE_PREFS.has(msg.data.feedHandler)) {

Просмотреть файл

@ -31,7 +31,6 @@ const startupPhases = {
"MainProcessSingleton.js",
// Bugs to fix: The following components shouldn't be initialized that early.
"WebContentConverter.js", // bug 1369443
"nsSessionStartup.js", // bug 1369456
"PushComponents.js", // bug 1369436
]),

Просмотреть файл

@ -1,10 +1,3 @@
# This component must restrict its registration for the app-startup category
# to the specific list of apps that use it so it doesn't get loaded in xpcshell.
# Thus we restrict it to these apps:
#
# browser: {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110}
component {229fa115-9412-4d32-baf3-2fc407f76fb1} FeedConverter.js
contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.video.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
@ -15,4 +8,3 @@ component {49bb6593-3aff-4eb3-a068-2712c28bd58e} FeedWriter.js
contract @mozilla.org/browser/feeds/result-writer;1 {49bb6593-3aff-4eb3-a068-2712c28bd58e}
component {792a7e82-06a0-437c-af63-b2d12e808acc} WebContentConverter.js
contract @mozilla.org/embeddor.implemented/web-content-handler-registrar;1 {792a7e82-06a0-437c-af63-b2d12e808acc}
category app-startup WebContentConverter service,@mozilla.org/embeddor.implemented/web-content-handler-registrar;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110}

Просмотреть файл

@ -20,17 +20,14 @@ const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
const TYPE_ANY = "*/*";
const PREF_SELECTED_APP = "browser.feeds.handlers.application";
const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
const PREF_SELECTED_ACTION = "browser.feeds.handler";
const PREF_SELECTED_READER = "browser.feeds.handler.default";
const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application";
const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler";
const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default";
const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application";
const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler";
const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default";
@ -47,19 +44,6 @@ function getPrefAppForType(t) {
}
}
function getPrefWebForType(t) {
switch (t) {
case Ci.nsIFeed.TYPE_VIDEO:
return PREF_VIDEO_SELECTED_WEB;
case Ci.nsIFeed.TYPE_AUDIO:
return PREF_AUDIO_SELECTED_WEB;
default:
return PREF_SELECTED_WEB;
}
}
function getPrefActionForType(t) {
switch (t) {
case Ci.nsIFeed.TYPE_VIDEO:
@ -170,8 +154,7 @@ FeedConverter.prototype = {
// generic feed content, the system will prevent them from setting an auto-
// handler for other stream types. In those cases, the user will always see
// the preview page and have to select a handler. We can guess and show
// a client handler, but will not be able to show web handlers for those
// types.
// a client handler.
//
// If this is just a feed, not some kind of specialized application, then
// auto-handlers can be set and we should obey them.
@ -186,35 +169,12 @@ FeedConverter.prototype = {
if (handler != "ask") {
if (handler == "reader")
handler = Services.prefs.getCharPref(getPrefReaderForType(feed.type), "bookmarks");
switch (handler) {
case "web":
let wccr =
Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentConverterService);
if ((feed.type == Ci.nsIFeed.TYPE_FEED &&
wccr.getAutoHandler(TYPE_MAYBE_FEED)) ||
(feed.type == Ci.nsIFeed.TYPE_VIDEO &&
wccr.getAutoHandler(TYPE_MAYBE_VIDEO_FEED)) ||
(feed.type == Ci.nsIFeed.TYPE_AUDIO &&
wccr.getAutoHandler(TYPE_MAYBE_AUDIO_FEED))) {
wccr.loadPreferredHandler(this._request);
return;
}
break;
default:
LOG("unexpected handler: " + handler);
// fall through -- let feed service handle error
case "bookmarks":
case "client":
case "default":
try {
let title = feed.title ? feed.title.plainText() : "";
let desc = feed.subtitle ? feed.subtitle.plainText() : "";
feedService.addToClientReader(result.uri.spec, title, desc, feed.type, handler);
return;
} catch (ex) { /* fallback to preview mode */ }
}
try {
let title = feed.title ? feed.title.plainText() : "";
let desc = feed.subtitle ? feed.subtitle.plainText() : "";
feedService.addToClientReader(result.uri.spec, title, desc, feed.type, handler);
return;
} catch (ex) { /* fallback to preview mode */ }
}
}
@ -382,8 +342,6 @@ FeedResultService.prototype = {
feedHandler: "default" });
break;
default:
// "web" should have been handled elsewhere
LOG("unexpected handler: " + handler);
// fall through
case "bookmarks":
Services.cpmm.sendAsyncMessage("FeedConverter:addLiveBookmark",

Просмотреть файл

@ -575,26 +575,9 @@ FeedWriter.prototype = {
}
},
_getWebHandlerElementsForURL(aURL) {
return this._handlersList.querySelectorAll('[webhandlerurl="' + aURL + '"]');
},
_setSelectedHandlerResponse(handler, url) {
LOG(`Selecting handler response ${handler} ${url}`);
_setSelectedHandlerResponse(handler) {
LOG(`Selecting handler response ${handler}`);
switch (handler) {
case "web": {
if (this._handlersList) {
let handlers =
this._getWebHandlerElementsForURL(url);
if (handlers.length == 0) {
LOG(`Selected web handler isn't in the menulist ${url}`);
return;
}
handlers[0].selected = true;
}
break;
}
case "client":
case "default":
// do nothing, these are handled by the onchange event
@ -663,26 +646,7 @@ FeedWriter.prototype = {
this._handlersList.appendChild(menuItem);
// separator
let chooseAppSep = liveBookmarksMenuItem.nextElementSibling.cloneNode(false);
chooseAppSep.textContent = liveBookmarksMenuItem.nextElementSibling.textContent;
this._handlersList.appendChild(chooseAppSep);
for (let handler of setupMessage.handlers) {
if (!handler.uri) {
LOG("Handler with name " + handler.name + " has no URI!? Skipping...");
continue;
}
menuItem = liveBookmarksMenuItem.cloneNode(false);
menuItem.removeAttribute("selected");
menuItem.className = "menuitem-iconic";
menuItem.textContent = handler.name;
menuItem.setAttribute("handlerType", "web");
menuItem.setAttribute("webhandlerurl", handler.uri);
this._handlersList.appendChild(menuItem);
}
this._setSelectedHandlerResponse(setupMessage.reader.handler, setupMessage.reader.url);
this._setSelectedHandlerResponse(setupMessage.reader.handler);
if (setupMessage.defaultMenuItem) {
LOG(`Setting default menu item ${setupMessage.defaultMenuItem}`);
@ -800,7 +764,6 @@ FeedWriter.prototype = {
this._mm.addMessageListener("FeedWriter:PreferenceUpdated", this);
this._mm.addMessageListener("FeedWriter:SetApplicationLauncherMenuItem", this);
this._mm.addMessageListener("FeedWriter:GetSubscriptionUIResponse", this);
this._mm.addMessageListener("FeedWriter:SetFeedPrefsAndSubscribeResponse", this);
const feedType = this._getFeedType();
this._mm.sendAsyncMessage("FeedWriter:GetSubscriptionUI",
@ -830,13 +793,9 @@ FeedWriter.prototype = {
}
LOG(`Got pref ${JSON.stringify(feedTypePref)}`);
this._setCheckboxCheckedState(feedTypePref.alwaysUse);
this._setSelectedHandlerResponse(feedTypePref.handler, feedTypePref.url);
this._setSelectedHandlerResponse(feedTypePref.handler);
this._setAlwaysUseLabel();
break;
case "FeedWriter:SetFeedPrefsAndSubscribeResponse":
LOG(`FeedWriter:SetFeedPrefsAndSubscribeResponse - Redirecting ${msg.data.redirect}`);
this._window.location.href = msg.data.redirect;
break;
case "FeedWriter:GetSubscriptionUIResponse":
// Set up the subscription UI
this._initSubscriptionUI(msg.data);
@ -933,27 +892,22 @@ FeedWriter.prototype = {
feedSubtitle: this._document.getElementById(SUBTITLE_ID).textContent,
feedLocation: this._window.location.href
};
if (selectedItem.hasAttribute("webhandlerurl")) {
feedReader = "web";
settings.uri = selectedItem.getAttribute("webhandlerurl");
} else {
switch (selectedItem.id) {
case "selectedAppMenuItem":
feedReader = "client";
break;
case "defaultHandlerMenuItem":
feedReader = "default";
break;
case "liveBookmarksMenuItem":
defaultHandler = "bookmarks";
feedReader = "bookmarks";
break;
}
switch (selectedItem.id) {
case "selectedAppMenuItem":
feedReader = "client";
break;
case "defaultHandlerMenuItem":
feedReader = "default";
break;
case "liveBookmarksMenuItem":
defaultHandler = "bookmarks";
feedReader = "bookmarks";
break;
}
settings.reader = feedReader;
// If "Always use..." is checked, we should set PREF_*SELECTED_ACTION
// to either "reader" (If a web reader or if an application is selected),
// to either "reader" (If an application is selected),
// or to "bookmarks" (if the live bookmarks option is selected).
// Otherwise, we should set it to "ask"
if (!useAsDefault) {

Просмотреть файл

@ -12,20 +12,11 @@ function LOG(str) {
// dump("*** " + str + "\n");
}
const WCCR_CONTRACTID = "@mozilla.org/embeddor.implemented/web-content-handler-registrar;1";
const WCCR_CLASSID = Components.ID("{792a7e82-06a0-437c-af63-b2d12e808acc}");
const WCC_CLASSID = Components.ID("{db7ebf28-cc40-415f-8a51-1b111851df1e}");
const WCC_CLASSNAME = "Web Service Handler";
const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
const TYPE_ANY = "*/*";
const PREF_CONTENTHANDLERS_AUTO = "browser.contentHandlers.auto.";
const PREF_CONTENTHANDLERS_BRANCH = "browser.contentHandlers.types.";
const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
const PREF_SELECTED_ACTION = "browser.feeds.handler";
const PREF_SELECTED_READER = "browser.feeds.handler.default";
const PREF_HANDLER_EXTERNAL_PREFIX = "network.protocol-handler.external";
const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties";
@ -33,87 +24,6 @@ const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties";
const NS_ERROR_MODULE_DOM = 2152923136;
const NS_ERROR_DOM_SYNTAX_ERR = NS_ERROR_MODULE_DOM + 12;
function WebContentConverter() {
}
WebContentConverter.prototype = {
convert() { },
asyncConvertData() { },
onDataAvailable() { },
onStopRequest() { },
onStartRequest(request, context) {
let wccr =
Cc[WCCR_CONTRACTID].
getService(Ci.nsIWebContentConverterService);
wccr.loadPreferredHandler(request);
},
QueryInterface: ChromeUtils.generateQI(["nsIStreamConverter",
"nsIStreamListener"]),
};
let WebContentConverterFactory = {
createInstance(outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return new WebContentConverter().QueryInterface(iid);
},
QueryInterface: ChromeUtils.generateQI(["nsIFactory"]),
};
function ServiceInfo(contentType, uri, name) {
this._contentType = contentType;
this._uri = uri;
this._name = name;
}
ServiceInfo.prototype = {
/**
* See nsIHandlerApp
*/
get name() {
return this._name;
},
/**
* See nsIHandlerApp
*/
equals(aHandlerApp) {
if (!aHandlerApp)
throw Cr.NS_ERROR_NULL_POINTER;
if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo &&
aHandlerApp.contentType == this.contentType &&
aHandlerApp.uri == this.uri)
return true;
return false;
},
/**
* See nsIWebContentHandlerInfo
*/
get contentType() {
return this._contentType;
},
/**
* See nsIWebContentHandlerInfo
*/
get uri() {
return this._uri;
},
/**
* See nsIWebContentHandlerInfo
*/
getHandlerURI(uri) {
return this._uri.replace(/%s/gi, encodeURIComponent(uri));
},
QueryInterface: ChromeUtils.generateQI(["nsIWebContentHandlerInfo"]),
};
const Utils = {
makeURI(aURL, aOriginCharset, aBaseURI) {
return Services.io.newURI(aURL, aOriginCharset, aBaseURI);
@ -222,25 +132,9 @@ const Utils = {
return new aWindowOrNull.DOMException(errorString, "SecurityError");
},
/**
* Mappings from known feed types to our internal content type.
*/
_mappings: {
"application/rss+xml": TYPE_MAYBE_FEED,
"application/atom+xml": TYPE_MAYBE_FEED,
},
resolveContentType(aContentType) {
if (aContentType in this._mappings)
return this._mappings[aContentType];
return aContentType;
}
};
function WebContentConverterRegistrar() {
this._contentTypes = {};
this._autoHandleContentTypes = {};
}
WebContentConverterRegistrar.prototype = {
@ -259,77 +153,7 @@ WebContentConverterRegistrar.prototype = {
},
/**
* See nsIWebContentConverterService
*/
getAutoHandler(contentType) {
contentType = Utils.resolveContentType(contentType);
if (contentType in this._autoHandleContentTypes)
return this._autoHandleContentTypes[contentType];
return null;
},
/**
* See nsIWebContentConverterService
*/
setAutoHandler(contentType, handler) {
if (handler && !this._typeIsRegistered(contentType, handler.uri))
throw Cr.NS_ERROR_NOT_AVAILABLE;
contentType = Utils.resolveContentType(contentType);
this._setAutoHandler(contentType, handler);
let ps = Services.prefs;
let autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
if (handler)
autoBranch.setCharPref(contentType, handler.uri);
else if (autoBranch.prefHasUserValue(contentType))
autoBranch.clearUserPref(contentType);
ps.savePrefFile(null);
},
/**
* Update the internal data structure (not persistent)
*/
_setAutoHandler(contentType, handler) {
if (handler)
this._autoHandleContentTypes[contentType] = handler;
else if (contentType in this._autoHandleContentTypes)
delete this._autoHandleContentTypes[contentType];
},
/**
* See nsIWebContentConverterService
*/
getWebContentHandlerByURI(contentType, uri) {
return this.getContentHandlers(contentType)
.find(e => e.uri == uri) || null;
},
/**
* See nsIWebContentConverterService
*/
loadPreferredHandler(request) {
let channel = request.QueryInterface(Ci.nsIChannel);
let contentType = Utils.resolveContentType(channel.contentType);
let handler = this.getAutoHandler(contentType);
if (handler) {
request.cancel(Cr.NS_ERROR_FAILURE);
let triggeringPrincipal = channel.loadInfo
? channel.loadInfo.triggeringPrincipal
: Services.scriptSecurityManager.getSystemPrincipal();
let webNavigation =
channel.notificationCallbacks.getInterface(Ci.nsIWebNavigation);
webNavigation.loadURI(handler.getHandlerURI(channel.URI.spec),
Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
null, null, null, triggeringPrincipal);
}
},
/**
* See nsIWebContentConverterService
* See nsIWebContentHandlerRegistrar
*/
removeProtocolHandler(aProtocol, aURITemplate) {
let eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
@ -350,29 +174,6 @@ WebContentConverterRegistrar.prototype = {
}
},
/**
* See nsIWebContentConverterService
*/
removeContentHandler(contentType, uri) {
function notURI(serviceInfo) {
return serviceInfo.uri != uri;
}
if (contentType in this._contentTypes) {
this._contentTypes[contentType] =
this._contentTypes[contentType].filter(notURI);
}
},
/**
* These are types for which there is a separate content converter aside
* from our built in generic one. We should not automatically register
* a factory for creating a converter for these types.
*/
_blockedTypes: {
"application/vnd.mozilla.maybe.feed": true,
},
/**
* Determines if a web handler is already registered.
*
@ -482,51 +283,6 @@ WebContentConverterRegistrar.prototype = {
[addButton]);
},
/**
* See nsIWebContentHandlerRegistrar
* If a DOM window is provided, then the request came from content, so we
* prompt the user to confirm the registration.
*/
registerContentHandler(aContentType, aURIString, aTitle, aWindowOrBrowser) {
LOG("registerContentHandler(" + aContentType + "," + aURIString + "," + aTitle + ")");
// Make sure to do our URL checks up front, before our content type check,
// just like the WebContentConverterRegistrarContent does.
let haveWindow = aWindowOrBrowser &&
(aWindowOrBrowser instanceof Ci.nsIDOMWindow);
let uri;
if (haveWindow) {
uri = Utils.checkAndGetURI(aURIString, aWindowOrBrowser);
} else if (aWindowOrBrowser) {
// uri was vetted in the content process.
uri = Utils.makeURI(aURIString, null);
}
// We only support feed types at present.
let contentType = Utils.resolveContentType(aContentType);
// XXX We should be throwing a Utils.getSecurityError() here in at least
// some cases. See bug 1266492.
if (contentType != TYPE_MAYBE_FEED) {
return;
}
if (aWindowOrBrowser) {
let notificationBox;
if (haveWindow) {
let browserWindow = this._getBrowserWindowForContentWindow(aWindowOrBrowser);
let browserElement = this._getBrowserForContentWindow(browserWindow, aWindowOrBrowser);
notificationBox = browserElement.getTabBrowser().getNotificationBox(browserElement);
} else {
notificationBox = aWindowOrBrowser.getTabBrowser()
.getNotificationBox(aWindowOrBrowser);
}
this._appendFeedReaderNotification(uri, aTitle, notificationBox);
} else {
this._registerContentHandler(contentType, aURIString, aTitle);
}
},
/**
* Returns the browser chrome window in which the content window is in
*/
@ -557,323 +313,6 @@ WebContentConverterRegistrar.prototype = {
browser.contentWindow == aContentWindow);
},
/**
* Appends a notifcation for the given feed reader details.
*
* The notification could be either a pseudo-dialog which lets
* the user to add the feed reader:
* [ [icon] Add %feed-reader-name% (%feed-reader-host%) as a Feed Reader? (Add) [x] ]
*
* or a simple message for the case where the feed reader is already registered:
* [ [icon] %feed-reader-name% is already registered as a Feed Reader [x] ]
*
* A new notification isn't appended if the given notificationbox has a
* notification for the same feed reader.
*
* @param aURI
* The url of the feed reader as a nsIURI object
* @param aName
* The feed reader name as it was passed to registerContentHandler
* @param aNotificationBox
* The notification box to which a notification might be appended
* @return true if a notification has been appended, false otherwise.
*/
_appendFeedReaderNotification(aURI, aName, aNotificationBox) {
let uriSpec = aURI.spec;
let notificationValue = "feed reader notification: " + uriSpec;
let notificationIcon = aURI.prePath + "/favicon.ico";
// Don't append a new notification if the notificationbox
// has a notification for the given feed reader already
if (aNotificationBox.getNotificationWithValue(notificationValue))
return false;
let buttons;
let message;
if (this.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uriSpec))
message = this._getFormattedString("handlerRegistered", [aName]);
else {
message = this._getFormattedString("addHandler", [aName, aURI.host]);
let self = this;
let addButton = {
_outer: self,
label: self._getString("addHandlerAddButton"),
accessKey: self._getString("addHandlerAddButtonAccesskey"),
feedReaderInfo: { uri: uriSpec, name: aName },
/* static */
callback(aNotification, aButtonInfo) {
let uri = aButtonInfo.feedReaderInfo.uri;
let name = aButtonInfo.feedReaderInfo.name;
let outer = aButtonInfo._outer;
// The reader could have been added from another window mean while
if (!outer.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uri))
outer._registerContentHandler(TYPE_MAYBE_FEED, uri, name);
// avoid reference cycles
aButtonInfo._outer = null;
return false;
}
};
buttons = [addButton];
}
aNotificationBox.appendNotification(message,
notificationValue,
notificationIcon,
aNotificationBox.PRIORITY_INFO_LOW,
buttons);
return true;
},
/**
* Save Web Content Handler metadata to persistent preferences.
* @param contentType
* The content Type being handled
* @param uri
* The uri of the web service
* @param title
* The human readable name of the web service
*
* This data is stored under:
*
* browser.contentHandlers.type0 = content/type
* browser.contentHandlers.uri0 = http://www.foo.com/q=%s
* browser.contentHandlers.title0 = Foo 2.0alphr
*/
_saveContentHandlerToPrefs(contentType, uri, title) {
let ps = Services.prefs;
let i = 0;
let typeBranch = null;
while (true) {
typeBranch =
ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + i + ".");
try {
typeBranch.getCharPref("type");
++i;
} catch (e) {
// No more handlers
break;
}
}
if (typeBranch) {
typeBranch.setCharPref("type", contentType);
let pls =
Cc["@mozilla.org/pref-localizedstring;1"].
createInstance(Ci.nsIPrefLocalizedString);
pls.data = uri;
typeBranch.setComplexValue("uri", Ci.nsIPrefLocalizedString, pls);
pls.data = title;
typeBranch.setComplexValue("title", Ci.nsIPrefLocalizedString, pls);
ps.savePrefFile(null);
}
},
/**
* Determines if there is a type with a particular uri registered for the
* specified content type already.
* @param contentType
* The content type that the uri handles
* @param uri
* The uri of the content type
*/
_typeIsRegistered(contentType, uri) {
if (!(contentType in this._contentTypes))
return false;
return this._contentTypes[contentType]
.some(t => t.uri == uri);
},
/**
* Gets a stream converter contract id for the specified content type.
* @param contentType
* The source content type for the conversion.
* @returns A contract id to construct a converter to convert between the
* contentType and *\/*.
*/
_getConverterContractID(contentType) {
const template = "@mozilla.org/streamconv;1?from=%s&to=*/*";
return template.replace(/%s/, contentType);
},
/**
* Register a web service handler for a content type.
*
* @param contentType
* the content type being handled
* @param uri
* the URI of the web service
* @param title
* the human readable name of the web service
*/
_registerContentHandler(contentType, uri, title) {
this._updateContentTypeHandlerMap(contentType, uri, title);
this._saveContentHandlerToPrefs(contentType, uri, title);
if (contentType == TYPE_MAYBE_FEED) {
// Make the new handler the last-selected reader in the preview page
// and make sure the preview page is shown the next time a feed is visited
let pb = Services.prefs.getBranch(null);
pb.setCharPref(PREF_SELECTED_READER, "web");
pb.setStringPref(PREF_SELECTED_WEB, uri);
pb.setCharPref(PREF_SELECTED_ACTION, "ask");
this._setAutoHandler(TYPE_MAYBE_FEED, null);
}
},
/**
* Update the content type -> handler map. This mapping is not persisted, use
* registerContentHandler or _saveContentHandlerToPrefs for that purpose.
* @param contentType
* The content Type being handled
* @param uri
* The uri of the web service
* @param title
* The human readable name of the web service
*/
_updateContentTypeHandlerMap(contentType, uri, title) {
if (!(contentType in this._contentTypes))
this._contentTypes[contentType] = [];
// Avoid adding duplicates
if (this._typeIsRegistered(contentType, uri))
return;
this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title));
if (!(contentType in this._blockedTypes)) {
let converterContractID = this._getConverterContractID(contentType);
let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID,
WebContentConverterFactory);
}
},
/**
* See nsIWebContentConverterService
*/
getContentHandlers(contentType, countRef) {
if (countRef) {
countRef.value = 0;
}
if (!(contentType in this._contentTypes))
return [];
let handlers = this._contentTypes[contentType];
if (countRef) {
countRef.value = handlers.length;
}
return handlers;
},
/**
* See nsIWebContentConverterService
*/
resetHandlersForType(contentType) {
// currently unused within the tree, so only useful for extensions; previous
// impl. was buggy (and even infinite-looped!), so I argue that this is a
// definite improvement
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
/**
* Registers a handler from the settings on a preferences branch.
*
* Since we support up to six predefined readers, we need to handle gaps
* better, since the first branch with user-added values will be .6
*
* How we deal with that is to check to see if there's no prefs in the
* branch and stop cycling once that's true. This doesn't fix the case
* where a user manually removes a reader, but that's not supported yet!
*
* @param branch
* an nsIPrefBranch containing "type", "uri", and "title" preferences
* corresponding to the content handler to be registered
*/
_registerContentHandlerHavingBranch(branch) {
let vals = branch.getChildList("");
if (vals.length == 0)
return;
let type = branch.getCharPref("type");
let uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data;
let title = branch.getComplexValue("title",
Ci.nsIPrefLocalizedString).data;
this._updateContentTypeHandlerMap(type, uri, title);
},
/**
* Load the auto handler, content handler and protocol tables from
* preferences.
*/
_init() {
let ps = Services.prefs;
let children = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
.getChildList("");
// first get the numbers of the providers by getting all ###.uri prefs
let nums = children.map((child) => {
let match = /^(\d+)\.uri$/.exec(child);
return match ? match[1] : "";
}).filter(child => !!child)
.sort();
// now register them
for (let num of nums) {
let branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + num + ".");
try {
this._registerContentHandlerHavingBranch(branch);
} catch (ex) {
// do nothing, the next branch might have values
}
}
// We need to do this _after_ registering all of the available handlers,
// so that getWebContentHandlerByURI can return successfully.
let autoBranch;
try {
autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
} catch (e) {
// No auto branch yet, that's fine
// LOG("WCCR.init: There is no auto branch, benign");
}
if (autoBranch) {
for (let type of autoBranch.getChildList("")) {
let uri = autoBranch.getCharPref(type);
if (uri) {
let handler = this.getWebContentHandlerByURI(type, uri);
if (handler) {
this._setAutoHandler(type, handler);
}
}
}
}
},
/**
* See nsIObserver
*/
observe(subject, topic, data) {
let os = Services.obs;
switch (topic) {
case "app-startup":
os.addObserver(this, "browser-ui-startup-complete");
break;
case "browser-ui-startup-complete":
os.removeObserver(this, "browser-ui-startup-complete");
this._init();
break;
}
},
/**
* See nsIFactory
*/
@ -889,9 +328,7 @@ WebContentConverterRegistrar.prototype = {
* See nsISupports
*/
QueryInterface: ChromeUtils.generateQI(
[Ci.nsIWebContentConverterService,
Ci.nsIWebContentHandlerRegistrar,
Ci.nsIObserver,
[Ci.nsIWebContentHandlerRegistrar,
Ci.nsIFactory]),
_xpcom_categories: [{
@ -901,140 +338,9 @@ WebContentConverterRegistrar.prototype = {
};
function WebContentConverterRegistrarContent() {
this._contentTypes = {};
}
WebContentConverterRegistrarContent.prototype = {
/**
* Load the auto handler, content handler and protocol tables from
* preferences.
*/
_init() {
let ps = Services.prefs;
let children = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
.getChildList("");
// first get the numbers of the providers by getting all ###.uri prefs
let nums = children.map((child) => {
let match = /^(\d+)\.uri$/.exec(child);
return match ? match[1] : "";
}).filter(child => !!child)
.sort();
// now register them
for (let num of nums) {
let branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + num + ".");
try {
this._registerContentHandlerHavingBranch(branch);
} catch (ex) {
// do nothing, the next branch might have values
}
}
},
_typeIsRegistered(contentType, uri) {
return this._contentTypes[contentType]
.some(e => e.uri == uri);
},
/**
* Since we support up to six predefined readers, we need to handle gaps
* better, since the first branch with user-added values will be .6
*
* How we deal with that is to check to see if there's no prefs in the
* branch and stop cycling once that's true. This doesn't fix the case
* where a user manually removes a reader, but that's not supported yet!
*
* @param branch
* The pref branch to register the content handler under
*
*/
_registerContentHandlerHavingBranch(branch) {
let vals = branch.getChildList("");
if (vals.length == 0)
return;
let type = branch.getCharPref("type");
let uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data;
let title = branch.getComplexValue("title",
Ci.nsIPrefLocalizedString).data;
this._updateContentTypeHandlerMap(type, uri, title);
},
_updateContentTypeHandlerMap(contentType, uri, title) {
if (!(contentType in this._contentTypes))
this._contentTypes[contentType] = [];
// Avoid adding duplicates
if (this._typeIsRegistered(contentType, uri))
return;
this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title));
if (!(contentType in this._blockedTypes)) {
let converterContractID = this._getConverterContractID(contentType);
let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID,
WebContentConverterFactory);
}
},
/**
* See nsIWebContentConverterService
*/
getContentHandlers(contentType, countRef) {
this._init();
if (countRef) {
countRef.value = 0;
}
if (!(contentType in this._contentTypes))
return [];
let handlers = this._contentTypes[contentType];
if (countRef) {
countRef.value = handlers.length;
}
return handlers;
},
setAutoHandler(contentType, handler) {
Services.cpmm.sendAsyncMessage("WCCR:setAutoHandler",
{ contentType, handler });
},
getWebContentHandlerByURI(contentType, uri) {
return this.getContentHandlers(contentType)
.find(e => e.uri == uri) || null;
},
/**
* See nsIWebContentHandlerRegistrar
*/
registerContentHandler(aContentType, aURIString, aTitle, aBrowserOrWindow) {
// aBrowserOrWindow must be a window.
let messageManager = aBrowserOrWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsITabChild)
.messageManager;
let uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
// XXX We should be throwing a Utils.getSecurityError() here in at least
// some cases. See bug 1266492.
if (Utils.resolveContentType(aContentType) != TYPE_MAYBE_FEED) {
return;
}
messageManager.sendAsyncMessage("WCCR:registerContentHandler",
{ contentType: aContentType,
uri: uri.spec,
title: aTitle });
},
registerProtocolHandler(aProtocol, aURIString, aTitle, aBrowserOrWindow) {
aProtocol = (aProtocol || "").toLowerCase();
// aBrowserOrWindow must be a window.
@ -1070,7 +376,6 @@ WebContentConverterRegistrarContent.prototype = {
*/
QueryInterface: ChromeUtils.generateQI(
[Ci.nsIWebContentHandlerRegistrar,
Ci.nsIWebContentConverterService,
Ci.nsIFactory])
};

Просмотреть файл

@ -12,7 +12,6 @@ JAR_MANIFESTS += ['jar.mn']
XPIDL_SOURCES += [
'nsIFeedResultService.idl',
'nsIWebContentConverterRegistrar.idl',
]
XPIDL_MODULE = 'browser-feeds'

Просмотреть файл

@ -1,117 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "nsIMIMEInfo.idl"
#include "nsIWebContentHandlerRegistrar.idl"
interface nsIRequest;
[scriptable, uuid(eb361098-5158-4b21-8f98-50b445f1f0b2)]
interface nsIWebContentHandlerInfo : nsIHandlerApp
{
/**
* The content type handled by the handler
*/
readonly attribute AString contentType;
/**
* The uri of the handler, with an embedded %s where the URI of the loaded
* document will be encoded.
*/
readonly attribute AString uri;
/**
* Gets the service URL Spec, with the loading document URI encoded in it.
* @param uri
* The URI of the document being loaded
* @returns The URI of the service with the loading document URI encoded in
* it.
*/
AString getHandlerURI(in AString uri);
};
[scriptable, uuid(de7cc06e-e778-45cb-b7db-7a114e1e75b1)]
interface nsIWebContentConverterService : nsIWebContentHandlerRegistrar
{
/**
* Specifies the handler to be used to automatically handle all links of a
* certain content type from now on.
* @param contentType
* The content type to automatically load with the specified handler
* @param handler
* A web service handler. If this is null, no automatic action is
* performed and the user must choose.
* @throws NS_ERROR_NOT_AVAILABLE if the service refered to by |handler| is
* not already registered.
*/
void setAutoHandler(in AString contentType, in nsIWebContentHandlerInfo handler);
/**
* Gets the auto handler specified for a particular content type
* @param contentType
* The content type to look up an auto handler for.
* @returns The web service handler that will automatically handle all
* documents of the specified type. null if there is no automatic
* handler. (Handlers may be registered, just none of them specified
* as "automatic").
*/
nsIWebContentHandlerInfo getAutoHandler(in AString contentType);
/**
* Gets a web handler for the specified service URI
* @param contentType
* The content type of the service being located
* @param uri
* The service URI of the handler to locate.
* @returns A web service handler that uses the specified uri.
*/
nsIWebContentHandlerInfo getWebContentHandlerByURI(in AString contentType,
in AString uri);
/**
* Loads the preferred handler when content of a registered type is about
* to be loaded.
* @param request
* The nsIRequest for the load of the content
*/
void loadPreferredHandler(in nsIRequest request);
/**
* Removes a registered protocol handler
* @param protocol
* The protocol scheme to remove a service handler for
* @param uri
* The uri of the service handler to remove
*/
void removeProtocolHandler(in AString protocol, in AString uri);
/**
* Removes a registered content handler
* @param contentType
* The content type to remove a service handler for
* @param uri
* The uri of the service handler to remove
*/
void removeContentHandler(in AString contentType, in AString uri);
/**
* Gets the list of content handlers for a particular type.
* @param contentType
* The content type to get handlers for
* @returns An array of nsIWebContentHandlerInfo objects
*/
void getContentHandlers(in AString contentType,
[optional] out unsigned long count,
[retval,array,size_is(count)] out nsIWebContentHandlerInfo handlers);
/**
* Resets the list of available content handlers to the default set from
* the distribution.
* @param contentType
* The content type to reset handlers for
*/
void resetHandlersForType(in AString contentType);
};

Просмотреть файл

@ -7,7 +7,6 @@ support-files = sample_feed.atom
!/browser/components/feeds/test/valid-feed.xml
!/browser/components/feeds/test/valid-unsniffable-feed.xml
[test_423060.xul]
[test_bug368464.html]
[test_bug408328.html]
[test_maxSniffing.html]

Просмотреть файл

@ -1,53 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet
href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window title="Make sure feed preview works when a default reader is selected"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body xmlns="http://www.w3.org/1999/xhtml" />
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
var wccrID = "@mozilla.org/embeddor.implemented/web-content-handler-registrar;1";
/* abort the test if web feed handlers are not available */
if (!Cc[wccrID])
SimpleTest.finish()
/* Turn off the first run UI */
var prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
prefBranch.setBoolPref("browser.feeds.showFirstRunUI", false);
/* register a handler for the feed type */
const MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
var handlerPage = "http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/demohandler.html?feedurl=%s";
var wccr = Cc[wccrID].getService(Ci.nsIWebContentConverterService);
wccr.registerContentHandler(MAYBE_FEED, handlerPage, "Demo handler", null);
var demoHandler = wccr.getWebContentHandlerByURI(MAYBE_FEED, handlerPage);
wccr.setAutoHandler(MAYBE_FEED, demoHandler);
/* Don't show the preview page */
prefBranch.setCharPref("browser.feeds.handler", "reader");
function finishUp() {
var theframe = document.getElementById('theframe');
var previewURL = "http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/demohandler.html?feedurl=http%3A%2F%2Fmochi.test%3A8888%2Ftests%2Ftoolkit%2Fcomponents%2Fplaces%2Ftests%2Fchrome%2Fsample_feed.atom";
is(theframe.contentDocument.URL, previewURL);
/* remove our demoHandler */
wccr.setAutoHandler(MAYBE_FEED, null);
wccr.removeContentHandler(MAYBE_FEED, handlerPage);
prefBranch.setCharPref("browser.feeds.handler", "ask");
prefBranch.setBoolPref("browser.feeds.showFirstRunUI", true);
SimpleTest.finish();
}
</script>
<html:iframe src="http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/sample_feed.atom" height="400px"
id="theframe" onload="finishUp();">
</html:iframe>
</window>

Просмотреть файл

@ -23,10 +23,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=402788
// return false if an exception has been catched, true otherwise
function testRegisterHandler(aIsProtocol, aTxt, aUri, aTitle) {
try {
if (aIsProtocol)
navigator.registerProtocolHandler(aTxt, aUri, aTitle);
else
navigator.registerContentHandler(aTxt, aUri, aTitle);
navigator.registerProtocolHandler(aTxt, aUri, aTitle);
} catch (e) {
return false;
}
@ -37,41 +34,31 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=402788
async function tests() {
await SpecialPowers.pushPrefEnv({
set: [
["dom.registerContentHandler.enabled", true],
["dom.registerProtocolHandler.insecure.enabled", true],
]
});
ok(navigator.registerContentHandler, "navigator.registerContentHandler should be defined");
// testing a generic case
is(testRegisterHandler(true, "web+foo", "http://mochi.test:8888/%s", "Foo handler"), true, "registering a web+foo protocol handler should work");
is(testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/%s", "Foo handler"), true, "registering a foo content handler should work");
// testing with wrong uris
is(testRegisterHandler(true, "web+foo", "http://mochi.test:8888/", "Foo handler"), false, "a protocol handler uri should contain %s");
is(testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/", "Foo handler"), false, "a content handler uri should contain %s");
// the spec explicitly allows relative urls to be passed
is(testRegisterHandler(true, "web+foo", "foo/%s", "Foo handler"), true, "a protocol handler uri should be valid");
is(testRegisterHandler(false, "application/rss+xml", "foo/%s", "Foo handler"), true, "a content handler uri should be valid");
// we should only accept to register when the handler has the same host as the current page (bug 402287)
is(testRegisterHandler(true, "fweb+oo", "http://remotehost:8888/%s", "Foo handler"), false, "registering a web+foo protocol handler with a different host should not work");
is(testRegisterHandler(false, "application/rss+xml", "http://remotehost:8888/%s", "Foo handler"), false, "registering a foo content handler with a different host should not work");
// restriction to http(s) for the uri of the handler (bug 401343)
// https should work (http already tested in the generic case)
is(testRegisterHandler(true, "web+foo", "https://mochi.test:8888/%s", "Foo handler"), true, "registering a web+foo protocol handler with https scheme should work");
is(testRegisterHandler(false, "application/rss+xml", "https://mochi.test:8888/%s", "Foo handler"), true, "registering a foo content handler with https scheme should work");
// ftp should not work
is(testRegisterHandler(true, "web+foo", "ftp://mochi.test:8888/%s", "Foo handler"), false, "registering a web+foo protocol handler with ftp scheme should not work");
is(testRegisterHandler(false, "application/rss+xml", "ftp://mochi.test:8888/%s", "Foo handler"), false, "registering a foo content handler with ftp scheme should not work");
// chrome should not work
is(testRegisterHandler(true, "web+foo", "chrome://mochi.test:8888/%s", "Foo handler"), false, "registering a web+foo protocol handler with chrome scheme should not work");
is(testRegisterHandler(false, "application/rss+xml", "chrome://mochi.test:8888/%s", "Foo handler"), false, "registering a foo content handler with chrome scheme should not work");
// foo should not work
is(testRegisterHandler(true, "web+foo", "foo://mochi.test:8888/%s", "Foo handler"), false, "registering a web+foo protocol handler with foo scheme should not work");
is(testRegisterHandler(false, "application/rss+xml", "foo://mochi.test:8888/%s", "Foo handler"), false, "registering a foo content handler with foo scheme should not work");
// for security reasons, protocol handlers should never be registered for some schemes (chrome, vbscript, ...) (bug 402788)
is(testRegisterHandler(true, "chrome", "http://mochi.test:8888/%s", "chrome handler"), false, "registering a chrome protocol handler should not work");
@ -85,10 +72,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=402788
is(testRegisterHandler(true, "web+1", "http://mochi.test:8888/%s", "chrome handler"), false, "registering a 'web+1' protocol handler should not work");
// for security reasons, content handlers should never be registered for some types (html, ...)
is(testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/%s", "Foo handler"), true, "registering rss content handlers should work");
is(testRegisterHandler(false, "application/atom+xml", "http://mochi.test:8888/%s", "Foo handler"), true, "registering atom content handlers should work");
todo_is(testRegisterHandler(false, "text/html", "http://mochi.test:8888/%s", "Foo handler"), false, "registering html content handlers should not work"); // bug 403798
SimpleTest.finish();
}

Просмотреть файл

@ -207,7 +207,6 @@ const listeners = {
// PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN AsyncPrefs.init
"FeedConverter:addLiveBookmark": ["Feeds"],
"WCCR:setAutoHandler": ["Feeds"],
"webrtc:UpdateGlobalIndicators": ["webrtcUI"],
"webrtc:UpdatingIndicators": ["webrtcUI"],
},
@ -232,7 +231,6 @@ const listeners = {
"LoginStats:LoginEncountered": ["LoginManagerParent"],
// PLEASE KEEP THIS LIST IN SYNC WITH THE MOBILE LISTENERS IN BrowserCLH.js
"WCCR:registerProtocolHandler": ["Feeds"],
"WCCR:registerContentHandler": ["Feeds"],
"rtcpeer:CancelRequest": ["webrtcUI"],
"rtcpeer:Request": ["webrtcUI"],
"webrtc:CancelRequest": ["webrtcUI"],
@ -1813,7 +1811,7 @@ BrowserGlue.prototype = {
_migrateUI: function BG__migrateUI() {
// Use an increasing number to keep track of the current migration state.
// Completely unrelated to the current Firefox release number.
const UI_VERSION = 70;
const UI_VERSION = 71;
const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
let currentUIVersion;
@ -2136,6 +2134,14 @@ BrowserGlue.prototype = {
Services.prefs.setBoolPref("browser.ctrlTab.migrated", true);
}
if (currentUIVersion < 71) {
// Clear legacy saved prefs for content handlers.
let savedContentHandlers = Services.prefs.getChildList("browser.contentHandlers.types");
for (let savedHandlerPref of savedContentHandlers) {
Services.prefs.clearUserPref(savedHandlerPref);
}
}
// Update the migration version.
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
},

Просмотреть файл

@ -112,8 +112,6 @@ var gAppManagerDialog = {
address = app.executable.path;
else if (app instanceof Ci.nsIWebHandlerApp)
address = app.uriTemplate;
else if (app instanceof Ci.nsIWebContentHandlerInfo)
address = app.uri;
document.getElementById("appLocation").value = address;
const l10nId = app instanceof Ci.nsILocalHandlerApp ? "app-manager-local-app-info"
: "app-manager-web-app-info";

Просмотреть файл

@ -21,7 +21,6 @@ XPCOMUtils.defineLazyServiceGetters(this, {
gCategoryManager: ["@mozilla.org/categorymanager;1", "nsICategoryManager"],
gHandlerService: ["@mozilla.org/uriloader/handler-service;1", "nsIHandlerService"],
gMIMEService: ["@mozilla.org/mime;1", "nsIMIMEService"],
gWebContentContentConverterService: ["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1", "nsIWebContentConverterService"],
});
// Constants & Enumeration Values
@ -56,31 +55,25 @@ const CONTAINERS_KEY = "privacy.containers";
* set browser.feeds.handler.default to "bookmarks";
*
* browser.feeds.handler.default
* - "bookmarks", "client" or "web" -- indicates the chosen feed reader used
* - "bookmarks" or "client" -- indicates the chosen feed reader used
* to display feeds, either transiently (i.e., when the "use as default"
* checkbox is unchecked, corresponds to when browser.feeds.handler=="ask")
* or more permanently (i.e., the item displayed in the dropdown in Feeds
* preferences)
*
* browser.feeds.handler.webservice
* - the URL of the currently selected web service used to read feeds
*
* browser.feeds.handlers.application
* - nsIFile, stores the current client-side feed reading app if one has
* been chosen
*/
const PREF_FEED_SELECTED_APP = "browser.feeds.handlers.application";
const PREF_FEED_SELECTED_WEB = "browser.feeds.handlers.webservice";
const PREF_FEED_SELECTED_ACTION = "browser.feeds.handler";
const PREF_FEED_SELECTED_READER = "browser.feeds.handler.default";
const PREF_VIDEO_FEED_SELECTED_APP = "browser.videoFeeds.handlers.application";
const PREF_VIDEO_FEED_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
const PREF_VIDEO_FEED_SELECTED_ACTION = "browser.videoFeeds.handler";
const PREF_VIDEO_FEED_SELECTED_READER = "browser.videoFeeds.handler.default";
const PREF_AUDIO_FEED_SELECTED_APP = "browser.audioFeeds.handlers.application";
const PREF_AUDIO_FEED_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
const PREF_AUDIO_FEED_SELECTED_ACTION = "browser.audioFeeds.handler";
const PREF_AUDIO_FEED_SELECTED_READER = "browser.audioFeeds.handler.default";
@ -188,17 +181,14 @@ Preferences.addAll([
{ id: "browser.feeds.handler", type: "string" },
{ id: "browser.feeds.handler.default", type: "string" },
{ id: "browser.feeds.handlers.application", type: "file" },
{ id: "browser.feeds.handlers.webservice", type: "string" },
{ id: "browser.videoFeeds.handler", type: "string" },
{ id: "browser.videoFeeds.handler.default", type: "string" },
{ id: "browser.videoFeeds.handlers.application", type: "file" },
{ id: "browser.videoFeeds.handlers.webservice", type: "string" },
{ id: "browser.audioFeeds.handler", type: "string" },
{ id: "browser.audioFeeds.handler.default", type: "string" },
{ id: "browser.audioFeeds.handlers.application", type: "file" },
{ id: "browser.audioFeeds.handlers.webservice", type: "string" },
{ id: "pref.downloads.disable_button.edit_actions", type: "bool" },
@ -539,17 +529,14 @@ var gMainPane = {
Services.prefs.addObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
Services.prefs.addObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
Services.prefs.addObserver(PREF_FEED_SELECTED_APP, this);
Services.prefs.addObserver(PREF_FEED_SELECTED_WEB, this);
Services.prefs.addObserver(PREF_FEED_SELECTED_ACTION, this);
Services.prefs.addObserver(PREF_FEED_SELECTED_READER, this);
Services.prefs.addObserver(PREF_VIDEO_FEED_SELECTED_APP, this);
Services.prefs.addObserver(PREF_VIDEO_FEED_SELECTED_WEB, this);
Services.prefs.addObserver(PREF_VIDEO_FEED_SELECTED_ACTION, this);
Services.prefs.addObserver(PREF_VIDEO_FEED_SELECTED_READER, this);
Services.prefs.addObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
Services.prefs.addObserver(PREF_AUDIO_FEED_SELECTED_WEB, this);
Services.prefs.addObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
Services.prefs.addObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
@ -1204,17 +1191,14 @@ var gMainPane = {
Services.prefs.removeObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
Services.prefs.removeObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
Services.prefs.removeObserver(PREF_FEED_SELECTED_APP, this);
Services.prefs.removeObserver(PREF_FEED_SELECTED_WEB, this);
Services.prefs.removeObserver(PREF_FEED_SELECTED_ACTION, this);
Services.prefs.removeObserver(PREF_FEED_SELECTED_READER, this);
Services.prefs.removeObserver(PREF_VIDEO_FEED_SELECTED_APP, this);
Services.prefs.removeObserver(PREF_VIDEO_FEED_SELECTED_WEB, this);
Services.prefs.removeObserver(PREF_VIDEO_FEED_SELECTED_ACTION, this);
Services.prefs.removeObserver(PREF_VIDEO_FEED_SELECTED_READER, this);
Services.prefs.removeObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
Services.prefs.removeObserver(PREF_AUDIO_FEED_SELECTED_WEB, this);
Services.prefs.removeObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
Services.prefs.removeObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
@ -1488,9 +1472,6 @@ var gMainPane = {
if (aHandlerApp instanceof Ci.nsIWebHandlerApp)
return aHandlerApp.uriTemplate;
if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo)
return aHandlerApp.uri;
if (aHandlerApp instanceof Ci.nsIGIOMimeApp)
return aHandlerApp.command;
@ -1992,9 +1973,6 @@ var gMainPane = {
if (aHandlerApp instanceof Ci.nsIWebHandlerApp)
return this._getIconURLForWebApp(aHandlerApp.uriTemplate);
if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo)
return this._getIconURLForWebApp(aHandlerApp.uri);
// We know nothing about other kinds of handler apps.
return "";
},
@ -2871,12 +2849,6 @@ class FeedHandlerInfo extends HandlerInfoWrapper {
return null;
case "web":
var uri = Preferences.get(this._prefSelectedWeb).value;
if (!uri)
return null;
return gWebContentContentConverterService.getWebContentHandlerByURI(this.type, uri);
case "bookmarks":
default:
// When the pref is set to bookmarks, we handle feeds internally,
@ -2890,16 +2862,6 @@ class FeedHandlerInfo extends HandlerInfoWrapper {
if (aNewValue instanceof Ci.nsILocalHandlerApp) {
Preferences.get(this._prefSelectedApp).value = aNewValue.executable;
Preferences.get(this._prefSelectedReader).value = "client";
} else if (aNewValue instanceof Ci.nsIWebContentHandlerInfo) {
Preferences.get(this._prefSelectedWeb).value = aNewValue.uri;
Preferences.get(this._prefSelectedReader).value = "web";
// Make the web handler be the new "auto handler" for feeds.
// Note: we don't have to unregister the auto handler when the user picks
// a non-web handler (local app, Live Bookmarks, etc.) because the service
// only uses the "auto handler" when the selected reader is a web handler.
// We also don't have to unregister it when the user turns on "always ask"
// (i.e. preview in browser), since that also overrides the auto handler.
gWebContentContentConverterService.setAutoHandler(this.type, aNewValue);
}
}
@ -2951,11 +2913,6 @@ class FeedHandlerInfo extends HandlerInfoWrapper {
this._possibleApplicationHandlers.appendElement(preferredApp);
}
// Add the registered web handlers. There can be any number of these.
var webHandlers = gWebContentContentConverterService.getContentHandlers(this.type);
for (let webHandler of webHandlers)
this._possibleApplicationHandlers.appendElement(webHandler);
return this._possibleApplicationHandlers;
}
@ -3094,10 +3051,6 @@ class FeedHandlerInfo extends HandlerInfoWrapper {
if (app.equals(preferredApp))
pref.reset();
}
} else {
app.QueryInterface(Ci.nsIWebContentHandlerInfo);
gWebContentContentConverterService.removeContentHandler(app.contentType,
app.uri);
}
}
this._possibleApplicationHandlers._removed = [];
@ -3110,7 +3063,6 @@ class FeedHandlerInfo extends HandlerInfoWrapper {
var feedHandlerInfo = new FeedHandlerInfo(TYPE_MAYBE_FEED, {
_prefSelectedApp: PREF_FEED_SELECTED_APP,
_prefSelectedWeb: PREF_FEED_SELECTED_WEB,
_prefSelectedAction: PREF_FEED_SELECTED_ACTION,
_prefSelectedReader: PREF_FEED_SELECTED_READER,
_smallIcon: "chrome://browser/skin/feeds/feedIcon16.png",
@ -3119,7 +3071,6 @@ var feedHandlerInfo = new FeedHandlerInfo(TYPE_MAYBE_FEED, {
var videoFeedHandlerInfo = new FeedHandlerInfo(TYPE_MAYBE_VIDEO_FEED, {
_prefSelectedApp: PREF_VIDEO_FEED_SELECTED_APP,
_prefSelectedWeb: PREF_VIDEO_FEED_SELECTED_WEB,
_prefSelectedAction: PREF_VIDEO_FEED_SELECTED_ACTION,
_prefSelectedReader: PREF_VIDEO_FEED_SELECTED_READER,
_smallIcon: "chrome://browser/skin/feeds/videoFeedIcon16.png",
@ -3128,7 +3079,6 @@ var videoFeedHandlerInfo = new FeedHandlerInfo(TYPE_MAYBE_VIDEO_FEED, {
var audioFeedHandlerInfo = new FeedHandlerInfo(TYPE_MAYBE_AUDIO_FEED, {
_prefSelectedApp: PREF_AUDIO_FEED_SELECTED_APP,
_prefSelectedWeb: PREF_AUDIO_FEED_SELECTED_WEB,
_prefSelectedAction: PREF_AUDIO_FEED_SELECTED_ACTION,
_prefSelectedReader: PREF_AUDIO_FEED_SELECTED_READER,
_smallIcon: "chrome://browser/skin/feeds/audioFeedIcon16.png",

Просмотреть файл

@ -2,11 +2,6 @@
# 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/.
# This is the default set of web based feed handlers shown in the reader
# selection UI
browser.contentHandlers.types.0.title=My Yahoo!
browser.contentHandlers.types.0.uri=https://add.my.yahoo.com/rss?url=%s
# increment this number when anything gets changed in the list below. This will
# cause Firefox to re-read these prefs and inject any new handlers into the
# profile database. Note that "new" is defined as "has a different URL"; this

Просмотреть файл

@ -26,21 +26,6 @@ var Feeds = {
break;
}
case "WCCR:registerContentHandler": {
let registrar = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentHandlerRegistrar);
registrar.registerContentHandler(data.contentType, data.uri, data.title,
aMessage.target);
break;
}
case "WCCR:setAutoHandler": {
let registrar = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentConverterService);
registrar.setAutoHandler(data.contentType, data.handler);
break;
}
case "FeedConverter:addLiveBookmark": {
let topWindow = BrowserWindowTracker.getTopWindow();
topWindow.PlacesCommandHook.addLiveBookmark(data.spec, data.title)

Просмотреть файл

@ -1,22 +0,0 @@
{
"llvm_revision": "320874",
"stages": "3",
"build_libcxx": true,
"build_type": "Release",
"assertions": false,
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_501/final",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_501/final",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_501/final",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_501/final",
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_501/final",
"python_path": "/usr/bin/python2.7",
"gcc_dir": "/builds/worker/workspace/build/src/gcc",
"cc": "/builds/worker/workspace/build/src/gcc/bin/gcc",
"cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
"as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
"patches": [
"llvm-debug-frame-for-5.patch",
"r313872.patch",
"pr_set_ptracer.patch"
]
}

Просмотреть файл

@ -1,21 +1,23 @@
{
"llvm_revision": "326563",
"llvm_revision": "335538",
"stages": "3",
"build_libcxx": true,
"build_type": "Release",
"assertions": false,
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_600/final",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_600/final",
"lld_repo": "https://llvm.org/svn/llvm-project/lld/tags/RELEASE_600/final",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_600/final",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_600/final",
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_600/final",
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_601/final",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_601/final",
"lld_repo": "https://llvm.org/svn/llvm-project/lld/tags/RELEASE_601/final",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_601/final",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_601/final",
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_601/final",
"python_path": "/usr/bin/python2.7",
"gcc_dir": "/builds/worker/workspace/build/src/gcc",
"cc": "/builds/worker/workspace/build/src/gcc/bin/gcc",
"cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
"as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
"patches": [
"find_symbolizer_linux.patch"
"find_symbolizer_linux.patch",
"r322401.patch",
"r325356.patch"
]
}

Просмотреть файл

@ -1,16 +1,16 @@
{
"llvm_revision": "326563",
"llvm_revision": "335538",
"stages": "1",
"build_libcxx": true,
"build_type": "Release",
"assertions": false,
"osx_cross_compile": true,
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_600/final",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_600/final",
"lld_repo": "https://llvm.org/svn/llvm-project/lld/tags/RELEASE_600/final",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_600/final",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_600/final",
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_600/final",
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_601/final",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_601/final",
"lld_repo": "https://llvm.org/svn/llvm-project/lld/tags/RELEASE_601/final",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_601/final",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_601/final",
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_601/final",
"python_path": "/usr/bin/python2.7",
"gcc_dir": "/builds/worker/workspace/build/src/gcc",
"cc": "/builds/worker/workspace/build/src/clang/bin/clang",
@ -22,6 +22,8 @@
"ld": "/builds/worker/workspace/build/src/clang/bin/clang",
"patches": [
"compiler-rt-cross-compile.patch",
"compiler-rt-no-codesign.patch"
"compiler-rt-no-codesign.patch",
"r322401.patch",
"r325356.patch"
]
}

Просмотреть файл

@ -1,27 +0,0 @@
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -57,6 +57,14 @@
#include "sanitizer_mutex.h"
#include "sanitizer_placement_new.h"
+// Sufficiently old kernel headers don't provide this value, but we can still
+// call prctl with it. If the runtime kernel is new enough, the prctl call will
+// have the desired effect; if the kernel is too old, the call will error and we
+// can ignore said error.
+#ifndef PR_SET_PTRACER
+#define PR_SET_PTRACER 0x59616d61
+#endif
+
// This module works by spawning a Linux task which then attaches to every
// thread in the caller process with ptrace. This suspends the threads, and
// PTRACE_GETREGS can then be used to obtain their register state. The callback
@@ -433,9 +441,7 @@
ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid);
// On some systems we have to explicitly declare that we want to be traced
// by the tracer thread.
-#ifdef PR_SET_PTRACER
internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0);
-#endif
// Allow the tracer thread to start.
tracer_thread_argument.mutex.Unlock();
// NOTE: errno is shared between this thread and the tracer thread.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,308 @@
From 3dd7de023be43bca7d6d45140e4fde42e22bc336 Mon Sep 17 00:00:00 2001
From: "Brian M. Rzycki" <brzycki@gmail.com>
Date: Fri, 16 Feb 2018 16:35:17 +0000
Subject: [PATCH 2/2] [JumpThreading] PR36133 enable/disable DominatorTree for
LVI analysis
Summary:
The LazyValueInfo pass caches a copy of the DominatorTree when available.
Whenever there are pending DominatorTree updates within JumpThreading's
DeferredDominance object we cannot use the cached DT for LVI analysis.
This commit adds the new methods enableDT() and disableDT() to LVI.
JumpThreading also sets the appropriate usage model before calling LVI
analysis methods.
Fixes https://bugs.llvm.org/show_bug.cgi?id=36133
Reviewers: sebpop, dberlin, kuhar
Reviewed by: sebpop, kuhar
Subscribers: uabelho, llvm-commits, aprantl, hiraditya, a.elovikov
Differential Revision: https://reviews.llvm.org/D42717
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@325356 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/llvm/Analysis/LazyValueInfo.h | 7 ++++
include/llvm/IR/Dominators.h | 3 ++
lib/Analysis/LazyValueInfo.cpp | 30 +++++++++++++++-
lib/IR/Dominators.cpp | 3 ++
lib/Transforms/Scalar/JumpThreading.cpp | 37 ++++++++++++++++++++
test/Transforms/JumpThreading/pr36133.ll | 44 ++++++++++++++++++++++++
6 files changed, 123 insertions(+), 1 deletion(-)
create mode 100644 test/Transforms/JumpThreading/pr36133.ll
diff --git a/llvm/include/llvm/Analysis/LazyValueInfo.h b/llvm/include/llvm/Analysis/LazyValueInfo.h
index 787c88cc6ec..cea5bf0df80 100644
--- a/llvm/include/llvm/Analysis/LazyValueInfo.h
+++ b/llvm/include/llvm/Analysis/LazyValueInfo.h
@@ -113,6 +113,13 @@ public:
/// in LVI, so we need to pass it here as an argument.
void printLVI(Function &F, DominatorTree &DTree, raw_ostream &OS);
+ /// Disables use of the DominatorTree within LVI.
+ void disableDT();
+
+ /// Enables use of the DominatorTree within LVI. Does nothing if the class
+ /// instance was initialized without a DT pointer.
+ void enableDT();
+
// For old PM pass. Delete once LazyValueInfoWrapperPass is gone.
void releaseMemory();
diff --git a/llvm/include/llvm/IR/Dominators.h b/llvm/include/llvm/IR/Dominators.h
index c5373376ade..ccb18527abc 100644
--- a/llvm/include/llvm/IR/Dominators.h
+++ b/llvm/include/llvm/IR/Dominators.h
@@ -342,6 +342,9 @@ public:
/// \brief Returns true if DelBB is awaiting deletion at a flush() event.
bool pendingDeletedBB(BasicBlock *DelBB);
+ /// \brief Returns true if pending DT updates are queued for a flush() event.
+ bool pending();
+
/// \brief Flushes all pending updates and block deletions. Returns a
/// correct DominatorTree reference to be used by the caller for analysis.
DominatorTree &flush();
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index d7da669f6e7..fcbfb08cf1d 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -401,6 +401,7 @@ namespace {
AssumptionCache *AC; ///< A pointer to the cache of @llvm.assume calls.
const DataLayout &DL; ///< A mandatory DataLayout
DominatorTree *DT; ///< An optional DT pointer.
+ DominatorTree *DisabledDT; ///< Stores DT if it's disabled.
ValueLatticeElement getBlockValue(Value *Val, BasicBlock *BB);
bool getEdgeValue(Value *V, BasicBlock *F, BasicBlock *T,
@@ -463,13 +464,30 @@ namespace {
TheCache.eraseBlock(BB);
}
+ /// Disables use of the DominatorTree within LVI.
+ void disableDT() {
+ if (DT) {
+ assert(!DisabledDT && "Both DT and DisabledDT are not nullptr!");
+ std::swap(DT, DisabledDT);
+ }
+ }
+
+ /// Enables use of the DominatorTree within LVI. Does nothing if the class
+ /// instance was initialized without a DT pointer.
+ void enableDT() {
+ if (DisabledDT) {
+ assert(!DT && "Both DT and DisabledDT are not nullptr!");
+ std::swap(DT, DisabledDT);
+ }
+ }
+
/// This is the update interface to inform the cache that an edge from
/// PredBB to OldSucc has been threaded to be from PredBB to NewSucc.
void threadEdge(BasicBlock *PredBB,BasicBlock *OldSucc,BasicBlock *NewSucc);
LazyValueInfoImpl(AssumptionCache *AC, const DataLayout &DL,
DominatorTree *DT = nullptr)
- : AC(AC), DL(DL), DT(DT) {}
+ : AC(AC), DL(DL), DT(DT), DisabledDT(nullptr) {}
};
} // end anonymous namespace
@@ -1791,6 +1809,16 @@ void LazyValueInfo::printLVI(Function &F, DominatorTree &DTree, raw_ostream &OS)
}
}
+void LazyValueInfo::disableDT() {
+ if (PImpl)
+ getImpl(PImpl, AC, DL, DT).disableDT();
+}
+
+void LazyValueInfo::enableDT() {
+ if (PImpl)
+ getImpl(PImpl, AC, DL, DT).enableDT();
+}
+
// Print the LVI for the function arguments at the start of each basic block.
void LazyValueInfoAnnotatedWriter::emitBasicBlockStartAnnot(
const BasicBlock *BB, formatted_raw_ostream &OS) {
diff --git a/llvm/lib/IR/Dominators.cpp b/llvm/lib/IR/Dominators.cpp
index e44e845b324..5efd0df5db9 100644
--- a/llvm/lib/IR/Dominators.cpp
+++ b/llvm/lib/IR/Dominators.cpp
@@ -453,6 +453,9 @@ bool DeferredDominance::pendingDeletedBB(BasicBlock *DelBB) {
return DeletedBBs.count(DelBB) != 0;
}
+/// \brief Returns true if pending DT updates are queued for a flush() event.
+bool DeferredDominance::pending() { return !PendUpdates.empty(); }
+
/// \brief Flushes all pending updates and block deletions. Returns a
/// correct DominatorTree reference to be used by the caller for analysis.
DominatorTree &DeferredDominance::flush() {
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 4d366e8e392..9ff91cf4924 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -425,6 +425,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
LoopHeaders.clear();
DDT->flush();
+ LVI->enableDT();
return EverChanged;
}
@@ -617,6 +618,10 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
// "X < 4" and "X < 3" is known true but "X < 4" itself is not available.
// Perhaps getConstantOnEdge should be smart enough to do this?
+ if (DDT->pending())
+ LVI->disableDT();
+ else
+ LVI->enableDT();
for (BasicBlock *P : predecessors(BB)) {
// If the value is known by LazyValueInfo to be a constant in a
// predecessor, use that information to try to thread this block.
@@ -630,6 +635,10 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
/// If I is a PHI node, then we know the incoming values for any constants.
if (PHINode *PN = dyn_cast<PHINode>(I)) {
+ if (DDT->pending())
+ LVI->disableDT();
+ else
+ LVI->enableDT();
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
Value *InVal = PN->getIncomingValue(i);
if (Constant *KC = getKnownConstant(InVal, Preference)) {
@@ -759,6 +768,10 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
const DataLayout &DL = PN->getModule()->getDataLayout();
// We can do this simplification if any comparisons fold to true or false.
// See if any do.
+ if (DDT->pending())
+ LVI->disableDT();
+ else
+ LVI->enableDT();
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
BasicBlock *PredBB = PN->getIncomingBlock(i);
Value *LHS = PN->getIncomingValue(i);
@@ -792,6 +805,10 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
if (!isa<Instruction>(CmpLHS) ||
cast<Instruction>(CmpLHS)->getParent() != BB) {
+ if (DDT->pending())
+ LVI->disableDT();
+ else
+ LVI->enableDT();
for (BasicBlock *P : predecessors(BB)) {
// If the value is known by LazyValueInfo to be a constant in a
// predecessor, use that information to try to thread this block.
@@ -820,6 +837,10 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
match(CmpLHS, m_Add(m_Value(AddLHS), m_ConstantInt(AddConst)))) {
if (!isa<Instruction>(AddLHS) ||
cast<Instruction>(AddLHS)->getParent() != BB) {
+ if (DDT->pending())
+ LVI->disableDT();
+ else
+ LVI->enableDT();
for (BasicBlock *P : predecessors(BB)) {
// If the value is known by LazyValueInfo to be a ConstantRange in
// a predecessor, use that information to try to thread this
@@ -901,6 +922,10 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
}
// If all else fails, see if LVI can figure out a constant value for us.
+ if (DDT->pending())
+ LVI->disableDT();
+ else
+ LVI->enableDT();
Constant *CI = LVI->getConstant(V, BB, CxtI);
if (Constant *KC = getKnownConstant(CI, Preference)) {
for (BasicBlock *Pred : predecessors(BB))
@@ -1102,6 +1127,10 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
// threading is concerned.
assert(CondBr->isConditional() && "Threading on unconditional terminator");
+ if (DDT->pending())
+ LVI->disableDT();
+ else
+ LVI->enableDT();
LazyValueInfo::Tristate Ret =
LVI->getPredicateAt(CondCmp->getPredicate(), CondCmp->getOperand(0),
CondConst, CondBr);
@@ -1899,6 +1928,10 @@ bool JumpThreadingPass::ThreadEdge(BasicBlock *BB,
<< ", across block:\n "
<< *BB << "\n");
+ if (DDT->pending())
+ LVI->disableDT();
+ else
+ LVI->enableDT();
LVI->threadEdge(PredBB, BB, SuccBB);
// We are going to have to map operands from the original BB block to the new
@@ -2368,6 +2401,10 @@ bool JumpThreadingPass::TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB) {
// Now check if one of the select values would allow us to constant fold the
// terminator in BB. We don't do the transform if both sides fold, those
// cases will be threaded in any case.
+ if (DDT->pending())
+ LVI->disableDT();
+ else
+ LVI->enableDT();
LazyValueInfo::Tristate LHSFolds =
LVI->getPredicateOnEdge(CondCmp->getPredicate(), SI->getOperand(1),
CondRHS, Pred, BB, CondCmp);
diff --git a/llvm/test/Transforms/JumpThreading/pr36133.ll b/llvm/test/Transforms/JumpThreading/pr36133.ll
new file mode 100644
index 00000000000..b8d8c5fac46
--- /dev/null
+++ b/llvm/test/Transforms/JumpThreading/pr36133.ll
@@ -0,0 +1,44 @@
+; RUN: opt -jump-threading -S < %s | FileCheck %s
+@global = external global i8*, align 8
+
+define i32 @foo(i32 %arg) {
+; CHECK-LABEL: @foo
+; CHECK-LABEL: bb:
+; CHECK: icmp eq
+; CHECK-NEXT: br i1 %tmp1, label %bb7, label %bb7
+bb:
+ %tmp = load i8*, i8** @global, align 8
+ %tmp1 = icmp eq i8* %tmp, null
+ br i1 %tmp1, label %bb3, label %bb2
+
+; CHECK-NOT: bb2:
+bb2:
+ br label %bb3
+
+; CHECK-NOT: bb3:
+bb3:
+ %tmp4 = phi i8 [ 1, %bb2 ], [ 0, %bb ]
+ %tmp5 = icmp eq i8 %tmp4, 0
+ br i1 %tmp5, label %bb7, label %bb6
+
+; CHECK-NOT: bb6:
+bb6:
+ br label %bb7
+
+; CHECK-LABEL: bb7:
+bb7:
+ %tmp8 = icmp eq i32 %arg, -1
+ br i1 %tmp8, label %bb9, label %bb10
+
+; CHECK-LABEL: bb9:
+bb9:
+ ret i32 0
+
+; CHECK-LABEL: bb10:
+bb10:
+ %tmp11 = icmp sgt i32 %arg, -1
+ call void @llvm.assume(i1 %tmp11)
+ ret i32 1
+}
+
+declare void @llvm.assume(i1)
--
2.18.0

Просмотреть файл

@ -9,7 +9,6 @@ export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
export CC="$topsrcdir/clang/bin/clang"
export CXX="$topsrcdir/clang/bin/clang++"
export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer"
# Use a newer binutils, from the tooltool gcc package, if it's there
if [ -e "$topsrcdir/gcc/bin/ld" ]; then

Просмотреть файл

@ -9,7 +9,7 @@ const promise = require("promise");
const defer = require("devtools/shared/defer");
const {Task} = require("devtools/shared/task");
const EventEmitter = require("devtools/shared/event-emitter");
const Tooltip = require("devtools/client/shared/widgets/tooltip/Tooltip");
const { HTMLTooltip } = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
const Editor = require("devtools/client/sourceeditor/editor");
const {LocalizationHelper} = require("devtools/shared/l10n");
const {extend} = require("devtools/shared/extend");
@ -36,6 +36,7 @@ const EVENTS = {
};
exports.EVENTS = EVENTS;
const XHTML_NS = "http://www.w3.org/1999/xhtml";
const STRINGS_URI = "devtools/client/locales/shadereditor.properties";
const HIGHLIGHT_TINT = [1, 0, 0.25, 1]; // rgba
const TYPING_MAX_DELAY = 500; // ms
@ -579,9 +580,21 @@ class ShadersEditorsView {
return;
}
const tooltip = node._markerErrorsTooltip = new Tooltip(document);
tooltip.defaultOffsetX = GUTTER_ERROR_PANEL_OFFSET_X;
tooltip.setTextContent({ messages: messages });
const tooltip = node._markerErrorsTooltip = new HTMLTooltip(document, {
type: "arrow",
useXulWrapper: true
});
const div = document.createElementNS(XHTML_NS, "div");
div.className = "devtools-shader-tooltip-container";
for (const message of messages) {
const messageDiv = document.createElementNS(XHTML_NS, "div");
messageDiv.className = "devtools-tooltip-simple-text";
messageDiv.textContent = message;
div.appendChild(messageDiv);
}
tooltip.setContent(div);
tooltip.startTogglingOnHover(node, () => true, {
toggleDelay: GUTTER_ERROR_PANEL_DELAY
});

Просмотреть файл

@ -32,13 +32,11 @@ async function ifWebGLSupported() {
const tooltip = marker._markerErrorsTooltip;
ok(tooltip, "A tooltip was created successfully.");
const content = tooltip.content;
ok(tooltip.content,
"Some tooltip's content was set.");
ok(tooltip.content.className.includes("devtools-tooltip-simple-text-container"),
"The tooltip's content container was created correctly.");
const containerClass = ".devtools-shader-tooltip-container";
const container = tooltip.panel.querySelector(containerClass);
ok(container, "The tooltip's content container was created correctly.");
const messages = content.childNodes;
const messages = container.childNodes;
is(messages.length, 3,
"There are three messages displayed in the tooltip.");
ok(messages[0].className.includes("devtools-tooltip-simple-text"),

Просмотреть файл

@ -42,7 +42,7 @@ tags = usercontextid
[browser_storage_cookies_edit.js]
[browser_storage_cookies_edit_keyboard.js]
[browser_storage_cookies_samesite.js]
skip-if = (os == "win" && os_version == "10.0" && !debug) || (verify && !debug && (os == 'win' || os == 'mac')) # Bug 1448484
skip-if = true # Bug 1448484 - sameSite1 is "Unset" - Got undefined, expected Unset
[browser_storage_cookies_tab_navigation.js]
[browser_storage_delete.js]
[browser_storage_delete_all.js]

Просмотреть файл

@ -84,6 +84,15 @@
color: var(--theme-selection-color);
}
.devtools-shader-tooltip-container .devtools-tooltip-simple-text {
color: var(--theme-content-color1);
border-bottom: 1px solid var(--theme-splitter-color);
}
.devtools-shader-tooltip-container .devtools-tooltip-simple-text:last-child {
border-bottom: 0;
}
/* Responsive sidebar */
@media (max-width: 700px) {

Просмотреть файл

@ -96,10 +96,10 @@
/* Doorhangers */
/* These colors are based on the colors used for doorhangers elsewhere in
* Firefox. */
--theme-arrowpanel-background: white;
--theme-arrowpanel-background: -moz-field;
--theme-arrowpanel-color: -moz-fieldText;
--theme-arrowpanel-border-color: var(--grey-90-a20);
--theme-arrowpanel-separator: var(--grey-90-a20);
--theme-arrowpanel-border-color: ThreeDShadow;
--theme-arrowpanel-separator: ThreeDShadow;
--theme-arrowpanel-dimmed: hsla(0,0%,80%,.3);
--theme-arrowpanel-dimmed-further: hsla(0,0%,80%,.45);
--theme-arrowpanel-disabled-color: GrayText;
@ -113,13 +113,14 @@
}
/*
* For doorhangers elsewhere in Fireflox, Mac uses a fixed color different to
* -moz-fieldText and a slightly lighter border color (presumably since it
* combines with the platform shadow).
* For doorhangers elsewhere in Firefox, Mac uses fixed colors rather than
* system colors.
*/
:root[platform="mac"].theme-light {
--theme-arrowpanel-color: rgb(26,26,26);
--theme-arrowpanel-background: hsla(0,0%,99%,.975);
--theme-arrowpanel-color: hsl(0,0%,10%);
--theme-arrowpanel-border-color: hsla(210,4%,10%,.05);
--theme-arrowpanel-separator: hsla(210,4%,10%,.14);
}
:root.theme-dark {
@ -284,6 +285,5 @@
--grey-80: #2a2a2e;
--grey-90: #0c0c0d;
--grey-90-a10: rgba(12, 12, 13, 0.1);
--grey-90-a20: rgba(12, 12, 13, 0.2);
--grey-90-a80: rgba(12, 12, 13, 0.8);
}

Просмотреть файл

@ -878,18 +878,6 @@ Navigator::RegisterContentHandler(const nsAString& aMIMEType,
const nsAString& aTitle,
ErrorResult& aRv)
{
if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
return;
}
nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
if (!registrar) {
return;
}
aRv = registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
mWindow->GetOuterWindow());
}
void

Просмотреть файл

@ -22,17 +22,24 @@ interface nsIWebContentHandlerRegistrar : nsISupports
{
/**
* See documentation in Navigator.webidl
* The additional contentWindow param for both methods represents the dom
* The additional contentWindow param for this method represents the dom
* content window from which the method has been called.
*/
void registerContentHandler(in DOMString mimeType,
in DOMString uri,
in DOMString title,
in nsISupports windowOrBrowser);
void registerProtocolHandler(in DOMString protocol,
in DOMString uri,
in DOMString title,
in nsISupports windowOrBrowser);
/**
* Removes a registered protocol handler
*
* While registerProtocolHandler is exposed on Navigator, unregistering
* is exposed through the UI code.
* @param protocol
* The protocol scheme to remove a service handler for
* @param uri
* The uri of the service handler to remove
*/
void removeProtocolHandler(in AString protocol, in AString uri);
};
%{ C++

Просмотреть файл

@ -114,12 +114,27 @@ var BroadcastService = class {
if (typeof version !== "string") {
throw new TypeError("version should be a string");
}
if (!version) {
throw new TypeError("version should not be an empty string");
}
const isNew = !this.jsonFile.data.listeners.hasOwnProperty(broadcastId);
const oldVersion = !isNew && this.jsonFile.data.listeners[broadcastId].version;
if (!isNew && oldVersion != version) {
console.warn("Versions differ while adding listener for", broadcastId,
". Got", version, "but JSON file says", oldVersion, ".");
}
// Update listeners before telling the pushService to subscribe,
// in case it would disregard the update in the small window
// between getting listeners and setting state to RUNNING.
this.jsonFile.data.listeners[broadcastId] = {version, sourceInfo};
//
// Keep the old version (if we have it) because Megaphone is
// really the source of truth for the current version of this
// broadcaster, and the old version is whatever we've either
// gotten from Megaphone or what we've told to Megaphone and
// haven't been corrected.
this.jsonFile.data.listeners[broadcastId] = {version: oldVersion || version, sourceInfo};
this.jsonFile.saveSoon();
if (isNew) {

Просмотреть файл

@ -296,7 +296,7 @@ var PushService = {
CHANGING_SERVICE_EVENT)
);
} else if (aData == "dom.push.connection.enabled") {
} else if (aData == "dom.push.connection.enabled" || aData == "dom.push.alwaysConnect") {
this._stateChangeProcessEnqueue(_ =>
this._changeStateConnectionEnabledEvent(prefs.get("connection.enabled"))
);
@ -501,6 +501,8 @@ var PushService = {
// Used to monitor if the user wishes to disable Push.
prefs.observe("connection.enabled", this);
// Used to load-test the server-side infrastructure for broadcast.
prefs.observe("alwaysConnect", this);
// Prunes expired registrations and notifies dormant service workers.
Services.obs.addObserver(this, "idle-daily");
@ -584,6 +586,7 @@ var PushService = {
}
prefs.ignore("connection.enabled", this);
prefs.ignore("alwaysConnect", this);
Services.obs.removeObserver(this, "network:offline-status-changed");
Services.obs.removeObserver(this, "clear-origin-attributes-data");

Просмотреть файл

@ -265,3 +265,17 @@ add_task(async function test_broadcast_reject_invalid_sourceinfo() {
symbolName: "getGhi"
}), /moduleURI must be a string/, "rejects sourceInfo that doesn't have moduleURI");
});
add_task(async function test_broadcast_reject_version_not_string() {
await assert.rejects(broadcastService.addListener("ghi", {}, {
moduleURI: "resource://gre/modules/ghi.jsm",
symbolName: "getGhi"
}), /version should be a string/, "rejects version that isn't a string");
});
add_task(async function test_broadcast_reject_version_empty_string() {
await assert.rejects(broadcastService.addListener("ghi", "", {
moduleURI: "resource://gre/modules/ghi.jsm",
symbolName: "getGhi"
}), /version should not be an empty string/, "rejects version that is an empty string");
});

Просмотреть файл

@ -596,37 +596,40 @@ TextEditRules::GetTextNodeAroundSelectionStartContainer()
#define ASSERT_PASSWORD_LENGTHS_EQUAL()
#endif
// static
void
TextEditRules::HandleNewLines(nsString& aString,
int32_t aNewlineHandling)
TextEditRules::HandleNewLines(nsString& aString)
{
if (aNewlineHandling < 0) {
int32_t caretStyle;
TextEditor::GetDefaultEditorPrefs(aNewlineHandling, caretStyle);
static const char16_t kLF = static_cast<char16_t>('\n');
MOZ_ASSERT(IsEditorDataAvailable());
MOZ_ASSERT(aString.FindChar(static_cast<uint16_t>('\r')) == kNotFound);
// First of all, check if aString contains '\n' since if the string
// does not include it, we don't need to do nothing here.
int32_t firstLF = aString.FindChar(kLF, 0);
if (firstLF == kNotFound) {
return;
}
switch(aNewlineHandling) {
switch(TextEditorRef().mNewlineHandling) {
case nsIPlaintextEditor::eNewlinesReplaceWithSpaces:
// Default of Firefox:
// Strip trailing newlines first so we don't wind up with trailing spaces
aString.Trim(CRLF, false, true);
aString.ReplaceChar(CRLF, ' ');
aString.Trim(LFSTR, false, true);
aString.ReplaceChar(kLF, ' ');
break;
case nsIPlaintextEditor::eNewlinesStrip:
aString.StripCRLF();
aString.StripChar(kLF);
break;
case nsIPlaintextEditor::eNewlinesPasteToFirst:
default: {
int32_t firstCRLF = aString.FindCharInSet(CRLF);
// we get first *non-empty* line.
int32_t offset = 0;
while (firstCRLF == offset) {
while (firstLF == offset) {
offset++;
firstCRLF = aString.FindCharInSet(CRLF, offset);
firstLF = aString.FindChar(kLF, offset);
}
if (firstCRLF > 0) {
aString.Truncate(firstCRLF);
if (firstLF > 0) {
aString.Truncate(firstLF);
}
if (offset > 0) {
aString.Cut(0, offset);
@ -634,25 +637,27 @@ TextEditRules::HandleNewLines(nsString& aString,
break;
}
case nsIPlaintextEditor::eNewlinesReplaceWithCommas:
aString.Trim(CRLF, true, true);
aString.ReplaceChar(CRLF, ',');
// Default of Thunderbird:
aString.Trim(LFSTR, true, true);
aString.ReplaceChar(kLF, ',');
break;
case nsIPlaintextEditor::eNewlinesStripSurroundingWhitespace: {
nsAutoString result;
uint32_t offset = 0;
while (offset < aString.Length()) {
int32_t nextCRLF = aString.FindCharInSet(CRLF, offset);
if (nextCRLF < 0) {
int32_t nextLF =
!offset ? firstLF : aString.FindChar(kLF, offset);
if (nextLF < 0) {
result.Append(nsDependentSubstring(aString, offset));
break;
}
uint32_t wsBegin = nextCRLF;
uint32_t wsBegin = nextLF;
// look backwards for the first non-whitespace char
while (wsBegin > offset && NS_IS_SPACE(aString[wsBegin - 1])) {
--wsBegin;
}
result.Append(nsDependentSubstring(aString, offset, wsBegin - offset));
offset = nextCRLF + 1;
offset = nextLF + 1;
while (offset < aString.Length() && NS_IS_SPACE(aString[offset])) {
++offset;
}
@ -662,7 +667,7 @@ TextEditRules::HandleNewLines(nsString& aString,
}
case nsIPlaintextEditor::eNewlinesPasteIntact:
// even if we're pasting newlines, don't paste leading/trailing ones
aString.Trim(CRLF, true, true);
aString.Trim(LFSTR, true, true);
break;
}
}
@ -760,7 +765,15 @@ TextEditRules::WillInsertText(EditSubAction aEditSubAction,
// So find out what we're expected to do:
if (IsSingleLineEditor()) {
nsAutoString tString(*outString);
HandleNewLines(tString, TextEditorRef().mNewlineHandling);
// XXX Some callers of TextEditor::InsertTextAsAction() already make the
// string use only \n as a linebreaker. However, they are not hot
// path and nsContentUtils::PlatformToDOMLineBreaks() does nothing
// if the string doesn't include \r. So, let's convert linebreakers
// here. Note that there are too many callers of
// TextEditor::InsertTextAsAction(). So, it's difficult to keep
// maintaining all of them won't reach here without \r nor \r\n.
nsContentUtils::PlatformToDOMLineBreaks(tString);
HandleNewLines(tString);
outString->Assign(tString);
}
@ -885,6 +898,7 @@ TextEditRules::WillSetText(bool* aCancel,
MOZ_ASSERT(aCancel);
MOZ_ASSERT(aHandled);
MOZ_ASSERT(aString);
MOZ_ASSERT(aString->FindChar(static_cast<char16_t>('\r')) == kNotFound);
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
@ -923,7 +937,7 @@ TextEditRules::WillSetText(bool* aCancel,
mPasswordText.Assign(tString);
FillBufWithPWChars(&tString, tString.Length());
} else if (IsSingleLineEditor()) {
HandleNewLines(tString, TextEditorRef().mNewlineHandling);
HandleNewLines(tString);
}
if (!count) {

Просмотреть файл

@ -104,28 +104,26 @@ public:
void ResetIMETextPWBuf();
/**
* Handles the newline characters either according to aNewLineHandling
* or to the default system prefs if aNewLineHandling is negative.
* Handles the newline characters according to the default system prefs
* (editor.singleLine.pasteNewlines).
* Each value means:
* nsIPlaintextEditor::eNewlinesReplaceWithSpaces (2, Firefox default):
* replace newlines with spaces.
* nsIPlaintextEditor::eNewlinesStrip (3):
* remove newlines from the string.
* nsIPlaintextEditor::eNewlinesReplaceWithCommas (4, Thunderbird default):
* replace newlines with commas.
* nsIPlaintextEditor::eNewlinesStripSurroundingWhitespace (5):
* collapse newlines and surrounding whitespace characters and
* remove them from the string.
* nsIPlaintextEditor::eNewlinesPasteIntact (0):
* only remove the leading and trailing newlines.
* nsIPlaintextEditor::eNewlinesPasteToFirst (1) or any other value:
* remove the first newline and all characters following it.
*
* @param aString the string to be modified in place.
* @param aNewLineHandling determine the desired type of newline handling:
* * negative values:
* handle newlines according to platform defaults.
* * nsIPlaintextEditor::eNewlinesReplaceWithSpaces:
* replace newlines with spaces.
* * nsIPlaintextEditor::eNewlinesStrip:
* remove newlines from the string.
* * nsIPlaintextEditor::eNewlinesReplaceWithCommas:
* replace newlines with commas.
* * nsIPlaintextEditor::eNewlinesStripSurroundingWhitespace:
* collapse newlines and surrounding whitespace characters and
* remove them from the string.
* * nsIPlaintextEditor::eNewlinesPasteIntact:
* only remove the leading and trailing newlines.
* * nsIPlaintextEditor::eNewlinesPasteToFirst or any other value:
* remove the first newline and all characters following it.
*/
static void HandleNewLines(nsString& aString, int32_t aNewLineHandling);
void HandleNewLines(nsString& aString);
/**
* Prepare a string buffer for being displayed as the contents of a password

Просмотреть файл

@ -1114,6 +1114,8 @@ TextEditor::InsertParagraphSeparatorAsAction()
nsresult
TextEditor::SetText(const nsAString& aString)
{
MOZ_ASSERT(aString.FindChar(static_cast<char16_t>('\r')) == kNotFound);
if (NS_WARN_IF(!mRules)) {
return NS_ERROR_NOT_INITIALIZED;
}

Просмотреть файл

@ -271,6 +271,8 @@ skip-if = toolkit == 'android' # bug 1054087
[test_dom_input_event_on_texteditor.html]
[test_dragdrop.html]
skip-if = os == 'android'
[test_handle_new_lines.html]
subsuite = clipboard
[test_inline_style_cache.html]
[test_inlineTableEditing.html]
[test_insertParagraph_in_inline_editing_host.html]

Просмотреть файл

@ -0,0 +1,129 @@
<!DOCTYPE html>
<html>
<head>
<title>Test for TextEditRules::HandlingNewLines()</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none;">
</div>
<div id="container"></div>
<textarea id="toCopyPlaintext" style="display: none;"></textarea>
<pre id="test">
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
async function copyPlaintext(aText) {
return new Promise(resolve => {
SimpleTest.waitForClipboard(
() => { return true; }, // because of mismatch of linebreakers
() => {
let element = document.getElementById("toCopyPlaintext");
element.style.display = "block";
element.focus();
element.value = aText;
synthesizeKey("a", {accelKey: true});
synthesizeKey("c", {accelKey: true});
},
() => {
ok(true, `Succeeded to copy "${aText.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/ /g, "\u00A0")}" to clipboard`);
let element = document.getElementById("toCopyPlaintext");
element.style.display = "none";
resolve();
},
() => {
SimpleTest.finish();
});
});
}
async function doTests() {
// nsIPlaintextEditor::eNewlinesPasteIntact (0):
// only remove the leading and trailing newlines.
// nsIPlaintextEditor::eNewlinesPasteToFirst (1) or any other value:
// remove the first newline and all characters following it.
// nsIPlaintextEditor::eNewlinesReplaceWithSpaces (2, Firefox default):
// replace newlines with spaces.
// nsIPlaintextEditor::eNewlinesStrip (3):
// remove newlines from the string.
// nsIPlaintextEditor::eNewlinesReplaceWithCommas (4, Thunderbird default):
// replace newlines with commas.
// nsIPlaintextEditor::eNewlinesStripSurroundingWhitespace (5):
// collapse newlines and surrounding whitespace characters and
// remove them from the string.
// value: setting or pasting text.
// expected: array of final values for each above pref value.
// setValue: expected result when HTMLInputElement.value is set to the value.
// pasteValue: expected result when pasting the value from clipboard.
//
// Note that HTMLInputElement strips both \r and \n. Therefore, each expected
// result is different from pasting the value.
const kTests = [
{ value: "\nabc\ndef\n",
expected: [{ setValue: "abcdef", pasteValue: "abc\ndef" },
{ setValue: "abcdef", pasteValue: "abc" },
{ setValue: "abcdef", pasteValue: " abc def" },
{ setValue: "abcdef", pasteValue: "abcdef" },
{ setValue: "abcdef", pasteValue: "abc,def" },
{ setValue: "abcdef", pasteValue: "abcdef" }],
},
{ value: "\n abc \n def \n",
expected: [{ setValue: " abc def ", pasteValue: " abc \n def " },
{ setValue: " abc def ", pasteValue: " abc " },
{ setValue: " abc def ", pasteValue: " abc def " },
{ setValue: " abc def ", pasteValue: " abc def " },
{ setValue: " abc def ", pasteValue: " abc , def " },
{ setValue: " abc def ", pasteValue: "abcdef" }],
},
{ value: " abc \n def ",
expected: [{ setValue: " abc def ", pasteValue: " abc \n def " },
{ setValue: " abc def ", pasteValue: " abc " },
{ setValue: " abc def ", pasteValue: " abc def " },
{ setValue: " abc def ", pasteValue: " abc def " },
{ setValue: " abc def ", pasteValue: " abc , def " },
{ setValue: " abc def ", pasteValue: " abcdef " }],
},
];
let container = document.getElementById("container");
for (let i = 0; i <= 5; i++) {
await SpecialPowers.pushPrefEnv({"set": [["editor.singleLine.pasteNewlines", i]]});
container.innerHTML = `<input id="input${i}" type="text">`;
let input = document.getElementById(`input${i}`);
input.focus();
let editor = SpecialPowers.wrap(input).editor;
for (const kLineBreaker of ["\n", "\r", "\r\n"]) {
for (let kTest of kTests) {
let value = kTest.value.replace(/\n/g, kLineBreaker);
input.value = value;
is(editor.rootElement.firstChild.wholeText, kTest.expected[i].setValue,
`Setting value to "${value.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/ /g, "\u00A0")}" when pref is ${i}`);
input.value = "";
await copyPlaintext(value);
input.focus();
synthesizeKey("v", {accelKey: true});
is(editor.rootElement.firstChild.wholeText, kTest.expected[i].pasteValue,
`Pasting "${value.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/ /g, "\u00A0")}" when pref is ${i}`);
input.value = "";
}
}
}
SimpleTest.finish();
}
SimpleTest.waitForFocus(doTests);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1805,16 +1805,14 @@ CompositorBridgeParent::RecvAdoptChild(const LayersId& child)
MOZ_ASSERT(mWrBridge);
RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
api = api->Clone();
childWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(),
wr::Epoch newEpoch = childWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(),
api,
mWrBridge->AsyncImageManager(),
GetAnimationStorage(),
mWrBridge->GetTextureFactoryIdentifier());
// Pretend we composited, since parent CompositorBridgeParent was replaced.
if (cpcp) {
TimeStamp now = TimeStamp::Now();
cpcp->DidComposite(child, now, now);
}
TimeStamp now = TimeStamp::Now();
NotifyPipelineRendered(childWrBridge->PipelineId(), newEpoch, now, now);
}
if (oldApzUpdater) {
@ -2132,7 +2130,7 @@ CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
TimeStamp& aCompositeEnd)
{
if (mWrBridge) {
NotifyDidComposite(mWrBridge->FlushPendingTransactionIds(), aCompositeStart, aCompositeEnd);
MOZ_ASSERT(false); // This should never get called for a WR compositor
} else {
NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd);
#if defined(ENABLE_FRAME_LATENCY_LOG)
@ -2206,6 +2204,8 @@ CompositorBridgeParent::GetAsyncImagePipelineManager() const
void
CompositorBridgeParent::NotifyDidComposite(TransactionId aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
{
MOZ_ASSERT(!mWrBridge); // We should be going through NotifyPipelineRendered instead
Unused << SendDidComposite(LayersId{0}, aTransactionId, aCompositeStart, aCompositeEnd);
if (mLayerManager) {
@ -2216,14 +2216,6 @@ CompositorBridgeParent::NotifyDidComposite(TransactionId aTransactionId, TimeSta
}
}
if (mWrBridge) {
nsTArray<ImageCompositeNotificationInfo> notifications;
mWrBridge->ExtractImageCompositeNotifications(&notifications);
if (!notifications.IsEmpty()) {
Unused << ImageBridgeParent::NotifyImageComposites(notifications);
}
}
MonitorAutoLock lock(*sIndirectLayerTreesLock);
ForEachIndirectLayerTree([&] (LayerTreeState* lts, const LayersId& aLayersId) -> void {
if (lts->mCrossProcessParent && lts->mParent == this) {

Просмотреть файл

@ -398,11 +398,8 @@ CrossProcessCompositorBridgeParent::DidCompositeLocked(
if (transactionId.IsValid()) {
Unused << SendDidComposite(aId, transactionId, aCompositeStart, aCompositeEnd);
}
} else if (WebRenderBridgeParent* wrbridge = sIndirectLayerTrees[aId].mWrBridge) {
TransactionId transactionId = wrbridge->FlushPendingTransactionIds();
if (transactionId.IsValid()) {
Unused << SendDidComposite(aId, transactionId, aCompositeStart, aCompositeEnd);
}
} else if (sIndirectLayerTrees[aId].mWrBridge) {
MOZ_ASSERT(false); // this should never get called for a WR compositor
}
}

Просмотреть файл

@ -822,8 +822,10 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
if (mIdNamespace != aIdNamespace) {
// Pretend we composited since someone is wating for this event,
// though DisplayList was not pushed to webrender.
TimeStamp now = TimeStamp::Now();
mCompositorBridge->DidComposite(GetLayersId(), now, now);
if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
TimeStamp now = TimeStamp::Now();
cbp->NotifyPipelineRendered(mPipelineId, wrEpoch, now, now);
}
}
if (ShouldParentObserveEpoch()) {
@ -896,13 +898,18 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget,
sendDidComposite = false;
}
HoldPendingTransactionId(WrEpoch(), aTransactionId, aRefreshStartTime, aTxnStartTime, aFwdTime);
HoldPendingTransactionId(mWrEpoch, aTransactionId, aRefreshStartTime, aTxnStartTime, aFwdTime);
if (scheduleComposite) {
ScheduleGenerateFrame();
} else if (sendDidComposite) {
TimeStamp now = TimeStamp::Now();
mCompositorBridge->DidComposite(GetLayersId(), now, now);
// The only thing in the pending transaction id queue should be the entry
// we just added, and now we're going to pretend we rendered it
MOZ_ASSERT(mPendingTransactionIds.size() == 1);
if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
TimeStamp now = TimeStamp::Now();
cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, now, now);
}
}
if (ShouldParentObserveEpoch()) {
@ -1246,7 +1253,7 @@ WebRenderBridgeParent::RecvClearCachedResources()
return IPC_OK();
}
void
wr::Epoch
WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler,
wr::WebRenderAPI* aApi,
AsyncImagePipelineManager* aImageMgr,
@ -1260,7 +1267,7 @@ WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler,
MOZ_ASSERT(aAnimStorage);
if (mDestroyed) {
return;
return mWrEpoch;
}
// Update id name space to identify obsoleted keys.
@ -1284,9 +1291,10 @@ WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler,
mAsyncImageManager = aImageMgr;
mAnimStorage = aAnimStorage;
Unused << GetNextWrEpoch(); // Update webrender epoch
// Register pipeline to updated AsyncImageManager.
mAsyncImageManager->AddPipeline(mPipelineId);
return GetNextWrEpoch(); // Update webrender epoch
}
mozilla::ipc::IPCResult
@ -1611,17 +1619,6 @@ WebRenderBridgeParent::LastPendingTransactionId()
return id;
}
TransactionId
WebRenderBridgeParent::FlushPendingTransactionIds()
{
TransactionId id{0};
if (!mPendingTransactionIds.empty()) {
id = mPendingTransactionIds.back().mId;
std::queue<PendingTransactionId>().swap(mPendingTransactionIds); // clear queue
}
return id;
}
TransactionId
WebRenderBridgeParent::FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch, const TimeStamp& aEndTime)
{

Просмотреть файл

@ -61,7 +61,6 @@ public:
wr::PipelineId PipelineId() { return mPipelineId; }
already_AddRefed<wr::WebRenderAPI> GetWebRenderAPI() { return do_AddRef(mApi); }
wr::Epoch WrEpoch() const { return mWrEpoch; }
AsyncImagePipelineManager* AsyncImageManager() { return mAsyncImageManager; }
CompositorVsyncScheduler* CompositorScheduler() { return mCompositorScheduler.get(); }
@ -158,7 +157,6 @@ public:
const TimeStamp& aTxnStartTime,
const TimeStamp& aFwdTime);
TransactionId LastPendingTransactionId();
TransactionId FlushPendingTransactionIds();
TransactionId FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch, const TimeStamp& aEndTime);
TextureFactoryIdentifier GetTextureFactoryIdentifier();
@ -186,11 +184,11 @@ public:
*/
void ScheduleGenerateFrame();
void UpdateWebRender(CompositorVsyncScheduler* aScheduler,
wr::WebRenderAPI* aApi,
AsyncImagePipelineManager* aImageMgr,
CompositorAnimationStorage* aAnimStorage,
const TextureFactoryIdentifier& aTextureFactoryIdentifier);
wr::Epoch UpdateWebRender(CompositorVsyncScheduler* aScheduler,
wr::WebRenderAPI* aApi,
AsyncImagePipelineManager* aImageMgr,
CompositorAnimationStorage* aAnimStorage,
const TextureFactoryIdentifier& aTextureFactoryIdentifier);
void RemoveEpochDataPriorTo(const wr::Epoch& aRenderedEpoch);

Просмотреть файл

@ -42,7 +42,7 @@ ifdef MOZ_ASAN
JITTEST_SANITIZER_ENV=ASAN_SYMBOLIZER_PATH='$(LLVM_SYMBOLIZER)'
endif
ifdef MOZ_TSAN
JITTEST_SANITIZER_ENV=TSAN_OPTIONS="external_symbolizer_path=$(LLVM_SYMBOLIZER) $$TSAN_OPTIONS"
JITTEST_SANITIZER_ENV=TSAN_OPTIONS="external_symbolizer_path=$(LLVM_SYMBOLIZER) handle_segv=0 $$TSAN_OPTIONS"
endif
ifdef MOZ_MSAN
JITTEST_SANITIZER_ENV=MSAN_SYMBOLIZER_PATH='$(LLVM_SYMBOLIZER)'

Просмотреть файл

@ -19,6 +19,7 @@ import android.text.TextUtils;
import android.text.style.StyleSpan;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.notifications.NotificationHelper;
import org.mozilla.gecko.preferences.GeckoPreferences;
public class DataReportingNotification {
@ -109,7 +110,8 @@ public class DataReportingNotification {
.setTicker(tickerText);
if (!AppConstants.Versions.preO) {
notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
notificationBuilder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

Просмотреть файл

@ -5,11 +5,8 @@
package org.mozilla.gecko;
import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@ -77,8 +74,6 @@ public class GeckoApplication extends Application
public static final String ACTION_DEBUG = "org.mozilla.gecko.DEBUG";
private static final String MEDIA_DECODING_PROCESS_CRASH = "MEDIA_DECODING_PROCESS_CRASH";
private static NotificationChannel defaultNotificationChannel = null;
private boolean mInBackground;
private boolean mPausedGecko;
private boolean mIsInitialResume;
@ -356,10 +351,6 @@ public class GeckoApplication extends Application
IntentHelper.init();
if (!AppConstants.Versions.preO) {
createDefaultNotificationChannel();
}
EventDispatcher.getInstance().registerGeckoThreadListener(mListener,
"Distribution:GetDirectories",
null);
@ -433,20 +424,6 @@ public class GeckoApplication extends Application
}
}
@TargetApi(26)
private void createDefaultNotificationChannel() {
final String DEFAULT_CHANNEL = AppConstants.MOZ_APP_DISPLAYNAME;
final String DEFAULT_NAME = AppConstants.MOZ_APP_DISPLAYNAME;
final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_HIGH;
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
defaultNotificationChannel = notificationManager.getNotificationChannel(DEFAULT_CHANNEL);
if (defaultNotificationChannel == null) {
defaultNotificationChannel = new NotificationChannel(DEFAULT_CHANNEL, DEFAULT_NAME, DEFAULT_IMPORTANCE);
notificationManager.createNotificationChannel(defaultNotificationChannel);
}
}
public void onDelayedStartup() {
if (AppConstants.MOZ_ANDROID_GCM) {
// TODO: only run in main process.
@ -642,10 +619,6 @@ public class GeckoApplication extends Application
}
}
public static NotificationChannel getDefaultNotificationChannel() {
return defaultNotificationChannel;
}
public boolean isApplicationInBackground() {
return mInBackground;
}

Просмотреть файл

@ -11,6 +11,8 @@ import android.content.Intent;
import android.content.res.Resources;
import android.support.v7.app.NotificationCompat;
import org.mozilla.gecko.notifications.NotificationHelper;
// Utility methods for entering/exiting guest mode.
public final class GuestSession {
private static final String LOGTAG = "GeckoGuestSession";
@ -34,7 +36,8 @@ public final class GuestSession {
.setContentIntent(getNotificationIntent(context));
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
final NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

Просмотреть файл

@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.overlays.ui.ShareDialog;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
@ -241,6 +242,13 @@ public final class IntentHelper implements BundleEventListener {
return intent;
}
public static Intent getPrivacySettingsIntent() {
final Intent intent = new Intent(GeckoApp.ACTION_LAUNCH_SETTINGS);
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
GeckoPreferences.setResourceToOpen(intent, "preferences_privacy");
return intent;
}
public static Intent getAudioCaptureIntent() {
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}

Просмотреть файл

@ -31,12 +31,12 @@ import android.util.Log;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.IntentHelper;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.notifications.NotificationHelper;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
@ -396,7 +396,8 @@ public class GeckoMediaControlAgent {
.setVisibility(visibility);
if (!AppConstants.Versions.preO) {
notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
notificationBuilder.setChannelId(NotificationHelper.getInstance(mContext)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
currentNotification = notificationBuilder.build();

Просмотреть файл

@ -25,9 +25,9 @@ import com.leanplum.internal.Constants;
import com.leanplum.internal.LeanplumInternal;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.MmaConstants;
import org.mozilla.gecko.firstrun.PanelConfig;
import org.mozilla.gecko.notifications.NotificationHelper;
import java.lang.ref.WeakReference;
import java.util.Map;
@ -92,7 +92,8 @@ public class MmaLeanplumImp implements MmaInterface {
builder.setSmallIcon(iconResId);
builder.setDefaults(Notification.DEFAULT_SOUND);
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(builder.mContext)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
}
});

Просмотреть файл

@ -20,7 +20,6 @@ import android.support.v4.app.NotificationManagerCompat;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoActivityMonitor;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoService;
import org.mozilla.gecko.NotificationListener;
import org.mozilla.gecko.R;
@ -156,7 +155,8 @@ public final class NotificationClient implements NotificationListener {
.setSummaryText(host));
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(mContext)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
// Fetch icon.
@ -237,7 +237,8 @@ public final class NotificationClient implements NotificationListener {
.setProgress((int) progressMax, (int) progress, false);
if (!AppConstants.Versions.preO) {
notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
notificationBuilder.setChannelId(NotificationHelper.getInstance(mContext)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
notification = notificationBuilder.build();

Просмотреть файл

@ -5,7 +5,10 @@
package org.mozilla.gecko.notifications;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@ -23,7 +26,7 @@ import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoActivityMonitor;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.R;
import org.mozilla.gecko.mozglue.SafeIntent;
import org.mozilla.gecko.util.BitmapUtils;
import org.mozilla.gecko.util.BundleEventListener;
@ -35,7 +38,9 @@ import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class NotificationHelper implements BundleEventListener {
public static final String HELPER_BROADCAST_ACTION = AppConstants.ANDROID_PACKAGE_NAME + ".helperBroadcastAction";
@ -78,6 +83,26 @@ public final class NotificationHelper implements BundleEventListener {
private final Context mContext;
public enum Channel {
/**
* Default notification channel.
*/
DEFAULT,
/**
* Mozilla Location Services notification channel.
*/
MLS
}
private final Map<Channel, String> mDefinedNotificationChannels = new HashMap<Channel, String>() {{
final String DEFAULT_CHANNEL_TAG = "default-notification-channel";
put(Channel.DEFAULT, DEFAULT_CHANNEL_TAG);
final String MLS_CHANNEL_TAG = "mls-notification-channel";
put(Channel.MLS, MLS_CHANNEL_TAG);
}};
// Holds a list of notifications that should be cleared if the Fennec Activity is shut down.
// Will not include ongoing or persistent notifications that are tied to Gecko's lifecycle.
private SimpleArrayMap<String, GeckoBundle> mClearableNotifications;
@ -98,6 +123,11 @@ public final class NotificationHelper implements BundleEventListener {
EventDispatcher.getInstance().registerUiThreadListener(this,
"Notification:Show",
"Notification:Hide");
if (!AppConstants.Versions.preO) {
initNotificationChannels();
}
mInitialized = true;
}
@ -113,6 +143,44 @@ public final class NotificationHelper implements BundleEventListener {
return sInstance;
}
private void initNotificationChannels() {
for (Channel mozChannel : mDefinedNotificationChannels.keySet()) {
createChannel(mozChannel);
}
}
@TargetApi(26)
private void createChannel(Channel definedChannel) {
final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = notificationManager.getNotificationChannel(mDefinedNotificationChannels.get(definedChannel));
if (channel == null) {
switch (definedChannel) {
case MLS: {
channel = new NotificationChannel(mDefinedNotificationChannels.get(definedChannel),
mContext.getString(R.string.mls_notification_channel), NotificationManager.IMPORTANCE_LOW);
}
break;
case DEFAULT:
default: {
channel = new NotificationChannel(mDefinedNotificationChannels.get(definedChannel),
mContext.getString(R.string.default_notification_channel), NotificationManager.IMPORTANCE_HIGH);
}
break;
}
notificationManager.createNotificationChannel(channel);
}
}
@TargetApi(26)
public NotificationChannel getNotificationChannel(Channel definedChannel) {
final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
return notificationManager.getNotificationChannel(mDefinedNotificationChannels.get(definedChannel));
}
@Override // BundleEventListener
public void handleMessage(final String event, final GeckoBundle message,
final EventCallback callback) {
@ -252,7 +320,7 @@ public final class NotificationHelper implements BundleEventListener {
}
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(getNotificationChannel(Channel.DEFAULT).getId());
}
final boolean ongoing = message.getBoolean(ONGOING_ATTR);

Просмотреть файл

@ -5,7 +5,6 @@
package org.mozilla.gecko.notifications;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@ -15,7 +14,6 @@ import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.switchboard.SwitchBoard;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoSharedPrefs;
@ -71,7 +69,8 @@ public class WhatsNewReceiver extends BroadcastReceiver {
.setDeleteIntent(getDeleteIntent(context));
if (!AppConstants.Versions.preO) {
notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
notificationBuilder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
final int notificationID = EXTRA_WHATSNEW_NOTIFICATION.hashCode();

Просмотреть файл

@ -23,10 +23,10 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
import org.mozilla.gecko.notifications.NotificationHelper;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
@ -255,7 +255,8 @@ public class TabQueueHelper {
.setContentIntent(pendingIntent);
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

Просмотреть файл

@ -7,7 +7,6 @@ package org.mozilla.gecko.tabqueue;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
@ -23,7 +22,6 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
@ -35,13 +33,13 @@ import android.widget.TextView;
import android.widget.Toast;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.mozglue.SafeIntent;
import org.mozilla.gecko.notifications.NotificationHelper;
import org.mozilla.gecko.preferences.GeckoPreferences;
import java.util.List;
@ -264,7 +262,8 @@ public class TabQueueService extends Service {
.addAction(R.drawable.ic_action_settings, getString(R.string.tab_queue_prompt_settings_button), pendingIntent);
if (!AppConstants.Versions.preO) {
notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
notificationBuilder.setChannelId(NotificationHelper.getInstance(this)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

Просмотреть файл

@ -22,10 +22,10 @@ import android.util.Log;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.BrowserLocaleManager;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.notifications.NotificationHelper;
/**
* A JobIntentService that displays a notification for a tab sent to this device.
@ -69,7 +69,8 @@ public class TabReceivedService extends JobIntentService {
builder.setContentIntent(contentIntent);
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(this)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
// Trigger "heads-up" notification mode on supported Android versions.

Просмотреть файл

@ -8,7 +8,6 @@ package org.mozilla.gecko.updater;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@ -31,9 +30,9 @@ import android.support.v4.net.ConnectivityManagerCompat;
import android.util.Log;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoUpdateReceiver;
import org.mozilla.gecko.R;
import org.mozilla.gecko.notifications.NotificationHelper;
import org.mozilla.gecko.permissions.Permissions;
import org.mozilla.gecko.updater.UpdateServiceHelper.AutoDownloadPolicy;
import org.mozilla.gecko.updater.UpdateServiceHelper.CheckUpdateResult;
@ -235,7 +234,8 @@ public class Updater {
.setContentIntent(pendingIntent);
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
NotificationManagerCompat.from(context)
@ -277,7 +277,8 @@ public class Updater {
builder.setContentIntent(contentIntent);
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
notificationManager.notify(notificationId, builder.build());
@ -318,7 +319,8 @@ public class Updater {
builder.setContentIntent(contentIntent);
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
notificationManager.notify(notificationId, builder.build());
@ -472,7 +474,8 @@ public class Updater {
.setDeleteIntent(deleteIntent);
if (!AppConstants.Versions.preO) {
notifBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
notifBuilder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
notifBuilder.setProgress(100, 0, true);
@ -494,7 +497,8 @@ public class Updater {
builder.setContentIntent(contentIntent);
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
notificationManager.notify(notificationId, builder.build());

Просмотреть файл

@ -892,3 +892,7 @@ Picture-in-picture mini window -->
<!ENTITY pip_play_button_description "Resume playing">
<!ENTITY pip_pause_button_title "Pause">
<!ENTITY pip_pause_button_description "Pause playing">
<!-- Notification channels names -->
<!ENTITY default_notification_channel "&brandShortName;">
<!ENTITY mls_notification_channel "&vendorShortName; Location Service">

Просмотреть файл

@ -646,4 +646,7 @@
<string name="pip_play_button_description">&pip_play_button_description;</string>
<string name="pip_pause_button_title">&pip_pause_button_title;</string>
<string name="pip_pause_button_description">&pip_pause_button_description;</string>
<string name="default_notification_channel">&default_notification_channel;</string>
<string name="mls_notification_channel">&mls_notification_channel;</string>
</resources>

Просмотреть файл

@ -4,7 +4,6 @@
package org.mozilla.gecko.fxa.sync;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
@ -12,7 +11,6 @@ import android.content.Intent;
import android.support.v7.app.NotificationCompat;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.Locales;
import org.mozilla.gecko.R;
import org.mozilla.gecko.background.common.log.Logger;
@ -22,6 +20,7 @@ import org.mozilla.gecko.fxa.activities.FxAccountWebFlowActivity;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.login.State;
import org.mozilla.gecko.fxa.login.State.Action;
import org.mozilla.gecko.notifications.NotificationHelper;
/**
* Abstraction that manages notifications shown or hidden for a Firefox Account.
@ -113,7 +112,8 @@ public class FxAccountNotificationManager {
.setContentIntent(pendingIntent);
if (!AppConstants.Versions.preO) {
builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
builder.setChannelId(NotificationHelper.getInstance(context)
.getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
}
notificationManager.notify(notificationId, builder.build());

Просмотреть файл

@ -7,6 +7,7 @@ package org.mozilla.mozstumbler.service.stumblerthread;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@ -19,8 +20,9 @@ import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.IntentHelper;
import org.mozilla.gecko.R;
import org.mozilla.gecko.notifications.NotificationHelper;
import org.mozilla.mozstumbler.service.AppGlobals;
import org.mozilla.mozstumbler.service.Prefs;
import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface;
@ -142,9 +144,12 @@ public class StumblerService extends PersistentIntentService
@SuppressLint("NewApi")
public int onStartCommand(Intent intent, int flags, int startId) {
if (!AppConstants.Versions.preO) {
final Notification notification = new NotificationCompat.Builder(this, GeckoApplication.getDefaultNotificationChannel().getId())
final Notification notification = new NotificationCompat.Builder(this,
NotificationHelper.getInstance(this)
.getNotificationChannel(NotificationHelper.Channel.MLS).getId())
.setSmallIcon(R.drawable.ic_status_logo)
.setContentTitle(getString(R.string.datareporting_stumbler_notification_title))
.setContentIntent(createContentIntent())
.setOngoing(true)
.setShowWhen(false)
.setWhen(0)
@ -274,4 +279,9 @@ public class StumblerService extends PersistentIntentService
private boolean hasLocationPermission() {
return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
private PendingIntent createContentIntent() {
Intent intent = IntentHelper.getPrivacySettingsIntent();
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}

Просмотреть файл

@ -620,8 +620,12 @@ function remoteSettingsFunction() {
const { bucketName } = rsOptions;
const key = `${bucketName}/${collectionName}`;
if (!_clients.has(key)) {
// Register a new client!
const c = new RemoteSettingsClient(collectionName, rsOptions);
_clients.set(key, c);
// Invalidate the polling status, since we want the new collection to
// be taken into account.
Services.prefs.clearUserPref(PREF_SETTINGS_LAST_ETAG);
}
return _clients.get(key);
};

Просмотреть файл

@ -519,3 +519,45 @@ add_task(async function test_syncs_clients_with_local_dump() {
Assert.equal(error.details.collection, "example");
});
add_task(clear_state);
add_task(async function test_adding_client_resets_last_etag() {
function serve200or304(request, response) {
const entries = [{
id: "aa71e6cc-9f37-447a-b6e0-c025e8eabd03",
last_modified: 42,
host: "localhost",
bucket: "main",
collection: "a-collection"
}];
if (request.queryString == `_since=${encodeURIComponent('"42"')}`) {
response.write(JSON.stringify({
data: entries.slice(0, 1)
}));
response.setHeader("ETag", '"42"');
response.setStatusLine(null, 304, "Not Modified");
} else {
response.write(JSON.stringify({
data: entries
}));
response.setHeader("ETag", '"42"');
response.setStatusLine(null, 200, "OK");
}
response.setHeader("Date", (new Date()).toUTCString());
}
server.registerPathHandler(CHANGES_PATH, serve200or304);
// Poll once, without any client for "a-collection"
await RemoteSettings.pollChanges();
// Register a new client.
let maybeSyncCalled = false;
const c = RemoteSettings("a-collection");
c.maybeSync = () => { maybeSyncCalled = true; };
// Poll again.
await RemoteSettings.pollChanges();
// The new client was called, even if the server data didn't change.
Assert.ok(maybeSyncCalled);
});

Просмотреть файл

@ -139,8 +139,6 @@ sm-tsan-linux64/opt:
platform: linux64/opt
run:
spidermonkey-variant: tsan
toolchains:
- linux64-clang-5
sm-rootanalysis-linux64/debug:
description: "Spidermonkey Root Analysis"

Просмотреть файл

@ -27,27 +27,6 @@ linux64-clang-3.9:
toolchains:
- linux64-gcc-4.9
linux64-clang-5:
description: "Clang 5 toolchain build"
treeherder:
kind: build
platform: toolchains/opt
symbol: TL(clang5)
tier: 1
worker-type: aws-provisioner-v1/gecko-{level}-b-linux-xlarge
worker:
max-run-time: 7200
run:
using: toolchain-script
script: build-clang-5-linux.sh
resources:
- 'build/build-clang/build-clang.py'
- 'build/build-clang/clang-5-linux64.json'
- 'taskcluster/scripts/misc/tooltool-download.sh'
toolchain-artifact: public/build/clang.tar.xz
toolchains:
- linux64-gcc-4.9
linux64-clang-6:
description: "Clang 6 toolchain build"
treeherder:

Просмотреть файл

@ -26,6 +26,8 @@ mkdir -p $CROSSTOOLS_BUILD_DIR
git clone --no-checkout $CROSSTOOL_PORT_REPOSITORY $CROSSTOOLS_SOURCE_DIR
cd $CROSSTOOLS_SOURCE_DIR
git checkout $CROSSTOOL_PORT_REV
# Cherry pick a fix for LTO.
git cherry-pick -n 82381f5038a340025ae145745ae5b325cd1b749a
echo "Building from commit hash `git rev-parse $CROSSTOOL_PORT_REV`..."
# Fetch clang from tooltool

Просмотреть файл

@ -22,6 +22,8 @@ mkdir -p $CROSSTOOLS_BUILD_DIR
git clone --no-checkout $CROSSTOOL_PORT_REPOSITORY $CROSSTOOLS_SOURCE_DIR
cd $CROSSTOOLS_SOURCE_DIR
git checkout $CROSSTOOL_PORT_REV
# Cherry pick a fix for LTO.
git cherry-pick -n 82381f5038a340025ae145745ae5b325cd1b749a
echo "Building from commit hash `git rev-parse $CROSSTOOL_PORT_REV`..."
# Fetch clang from tooltool

Просмотреть файл

@ -1,25 +0,0 @@
#!/bin/bash
set -x -e -v
# This script is for building clang for Linux.
WORKSPACE=$HOME/workspace
HOME_DIR=$WORKSPACE/build
UPLOAD_DIR=$HOME/artifacts
cd $HOME_DIR/src
. taskcluster/scripts/misc/tooltool-download.sh
# gets a bit too verbose here
set +x
cd build/build-clang
# |mach python| sets up a virtualenv for us!
../../mach python ./build-clang.py -c clang-5-linux64.json
set -x
# Put a tarball in the artifacts dir
mkdir -p $UPLOAD_DIR
cp clang.tar.* $UPLOAD_DIR

Просмотреть файл

@ -987,6 +987,7 @@ GeckoDriver.prototype.execute_ = async function(
}
assert.open(this.getCurrentWindow());
this._handleUserPrompts();
assert.string(script, pprint`Expected "script" to be a string: ${script}`);
assert.array(args, pprint`Expected script args to be an array: ${args}`);

Просмотреть файл

@ -54,9 +54,15 @@ class TestUnhandledPromptBehavior(MarionetteTestCase):
self.assertEqual(self.alert_present, not expected_close)
prompt_result = self.marionette.execute_script(
"return window.return_value", new_sandbox=False)
self.assertEqual(prompt_result, expected_result)
# Close an expected left-over user prompt
if not expected_close:
alert = self.marionette.switch_to_alert()
alert.dismiss()
else:
prompt_result = self.marionette.execute_script(
"return window.return_value", new_sandbox=False)
self.assertEqual(prompt_result, expected_result)
@parameterized("alert", "alert", None)
@parameterized("confirm", "confirm", True)

Просмотреть файл

@ -408785,6 +408785,12 @@
{}
]
],
"webdriver/tests/execute_async_script/execute_async.py": [
[
"/webdriver/tests/execute_async_script/execute_async.py",
{}
]
],
"webdriver/tests/execute_async_script/user_prompts.py": [
[
"/webdriver/tests/execute_async_script/user_prompts.py",
@ -408805,6 +408811,12 @@
{}
]
],
"webdriver/tests/execute_script/execute.py": [
[
"/webdriver/tests/execute_script/execute.py",
{}
]
],
"webdriver/tests/execute_script/json_serialize_windowproxy.py": [
[
"/webdriver/tests/execute_script/json_serialize_windowproxy.py",
@ -552663,7 +552675,7 @@
"testharness"
],
"css/cssom/computed-style-005.html": [
"690ce1465de338f19b1e7282b4a221e7fe374a12",
"6bf8f129c83cb014918b3af9ccb296de4fa67577",
"testharness"
],
"css/cssom/computed-style-set-property.html": [
@ -622783,7 +622795,7 @@
"testharness"
],
"web-animations/timing-model/timelines/document-timelines.html": [
"d0fcb390c19c9ede7288278dc11ea5b3d33671cb",
"44b64478e81fd9c7933b865cb6ad3d62f06bc993",
"testharness"
],
"web-animations/timing-model/timelines/timelines.html": [
@ -624322,8 +624334,12 @@
"f88643f6266714b078d161ee5039c689a937e0a3",
"wdspec"
],
"webdriver/tests/execute_async_script/execute_async.py": [
"bd982562266d49b71fc70944b8565ad9b8d62633",
"wdspec"
],
"webdriver/tests/execute_async_script/user_prompts.py": [
"900c47893fa2f506fc8275338c540725b5c3f2a6",
"09d4a1c77401f2e5e1aefa79f1c6134aeffb2d50",
"wdspec"
],
"webdriver/tests/execute_script/__init__.py": [
@ -624338,12 +624354,16 @@
"145a8a67226f31e0c1023aa0609947486be5c319",
"wdspec"
],
"webdriver/tests/execute_script/execute.py": [
"3b940aeb18c1939740ae3d903172004e8c8dc10d",
"wdspec"
],
"webdriver/tests/execute_script/json_serialize_windowproxy.py": [
"20db10d82ed2b28a22674fcdc37cac0323d33c95",
"wdspec"
],
"webdriver/tests/execute_script/user_prompts.py": [
"d4f627cda9669efc7fb8197bf6adde5d65b0aa1f",
"530c424e10cd0e7e065e97ceb14f690f65301d3f",
"wdspec"
],
"webdriver/tests/find_element/__init__.py": [

Просмотреть файл

@ -0,0 +1,12 @@
[execute_async.py]
[test_abort_by_user_prompt_twice[alert\]]
expected: FAIL
disabled: Bug 1459118
[test_abort_by_user_prompt_twice[confirm\]]
expected: FAIL
disabled: Bug 1459118
[test_abort_by_user_prompt_twice[prompt\]]
expected: FAIL
disabled: Bug 1459118

Просмотреть файл

@ -1,15 +0,0 @@
[user_prompts.py]
disabled:
if webrender: bug 1425588
[test_handle_prompt_twice[capabilities0-alert\]]
expected: FAIL
disabled: Bug 1459118
[test_handle_prompt_twice[capabilities0-confirm\]]
expected: FAIL
disabled: Bug 1459118
[test_handle_prompt_twice[capabilities0-prompt\]]
expected: FAIL
disabled: Bug 1459118

Просмотреть файл

@ -0,0 +1,12 @@
[execute.py]
[test_abort_by_user_prompt_twice[alert\]]
expected: FAIL
disabled: Bug 1459118
[test_abort_by_user_prompt_twice[confirm\]]
expected: FAIL
disabled: Bug 1459118
[test_abort_by_user_prompt_twice[prompt\]]
expected: FAIL
disabled: Bug 1459118

Просмотреть файл

@ -1,15 +0,0 @@
[user_prompts.py]
disabled:
if webrender: bug 1425588
[test_handle_prompt_twice[capabilities0-alert\]]
expected: FAIL
disabled: Bug 1459118
[test_handle_prompt_twice[capabilities0-confirm\]]
expected: FAIL
disabled: Bug 1459118
[test_handle_prompt_twice[capabilities0-prompt\]]
expected: FAIL
disabled: Bug 1459118

Просмотреть файл

@ -0,0 +1,40 @@
import pytest
from tests.support.asserts import assert_success
def execute_async_script(session, script, args=None):
if args is None:
args = []
body = {"script": script, "args": args}
return session.transport.send(
"POST", "/session/{session_id}/execute/async".format(**vars(session)),
body)
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_abort_by_user_prompt(session, dialog_type):
response = execute_async_script(
session,
"window.{}('Hello'); arguments[0](1);".format(dialog_type))
assert_success(response, None)
session.alert.accept()
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_abort_by_user_prompt_twice(session, dialog_type):
response = execute_async_script(
session,
"window.{0}('Hello'); window.{0}('Bye'); arguments[0](1);".format(dialog_type))
assert_success(response, None)
session.alert.accept()
# The first alert has been accepted by the user prompt handler, the second one remains.
# FIXME: this is how browsers currently work, but the spec should clarify if this is the
# expected behavior, see https://github.com/w3c/webdriver/issues/1153.
assert session.alert.text == "Bye"
session.alert.accept()

Просмотреть файл

@ -2,9 +2,7 @@
import pytest
from webdriver import error
from tests.support.asserts import assert_success
from tests.support.asserts import assert_dialog_handled, assert_error, assert_success
def execute_async_script(session, script, args=None):
@ -19,82 +17,57 @@ def execute_async_script(session, script, args=None):
@pytest.mark.capabilities({"unhandledPromptBehavior": "accept"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_accept(session, dialog_type):
response = execute_async_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_accept(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.accept()
response = execute_async_script(session, "arguments[0]()")
assert_success(response)
assert_dialog_handled(session, expected_text="dialog")
@pytest.mark.capabilities({"unhandledPromptBehavior": "accept and notify"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_accept_and_notify(session, dialog_type):
response = execute_async_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_accept_and_notify(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
with pytest.raises(error.UnexpectedAlertOpenException):
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.accept()
response = execute_async_script(session, "arguments[0]()")
assert_error(response, "unexpected alert open")
assert_dialog_handled(session, expected_text="dialog")
@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_dismiss(session, dialog_type):
response = execute_async_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_dismiss(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.dismiss()
response = execute_async_script(session, "arguments[0]()")
assert_success(response)
assert_dialog_handled(session, expected_text="dialog")
@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss and notify"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_dismiss_and_notify(session, dialog_type):
response = execute_async_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_dissmiss_and_notify(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
with pytest.raises(error.UnexpectedAlertOpenException):
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.dismiss()
response = execute_async_script(session, "arguments[0]()")
assert_error(response, "unexpected alert open")
assert_dialog_handled(session, expected_text="dialog")
@pytest.mark.capabilities({"unhandledPromptBehavior": "ignore"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_ignore(session, dialog_type):
response = execute_async_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
with pytest.raises(error.UnexpectedAlertOpenException):
session.title
session.alert.dismiss()
def test_handle_prompt_ignore():
"""TODO"""
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_default(session, dialog_type):
response = execute_async_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_default(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
with pytest.raises(error.UnexpectedAlertOpenException):
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.dismiss()
response = execute_async_script(session, "arguments[0]()")
assert_error(response, "unexpected alert open")
@pytest.mark.capabilities({"unhandledPromptBehavior": "accept"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_twice(session, dialog_type):
response = execute_async_script(
session, "window.{0}('Hello');window.{0}('Bye');".format(dialog_type))
assert_success(response, None)
session.alert.dismiss()
# The first alert has been accepted by the user prompt handler, the second one remains.
# FIXME: this is how browsers currently work, but the spec should clarify if this is the
# expected behavior, see https://github.com/w3c/webdriver/issues/1153.
assert session.alert.text == "Bye"
session.alert.dismiss()
assert_dialog_handled(session, expected_text="dialog")

Просмотреть файл

@ -0,0 +1,39 @@
import pytest
from tests.support.asserts import assert_success
def execute_script(session, script, args=None):
if args is None:
args = []
body = {"script": script, "args": args}
return session.transport.send(
"POST", "/session/{session_id}/execute/sync".format(
session_id=session.session_id),
body)
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_abort_by_user_prompt(session, dialog_type):
response = execute_script(
session, "window.{}('Hello'); return 1;".format(dialog_type))
assert_success(response, None)
session.alert.accept()
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_abort_by_user_prompt_twice(session, dialog_type):
response = execute_script(
session, "window.{0}('Hello'); window.{0}('Bye'); return 1;".format(dialog_type))
assert_success(response, None)
session.alert.accept()
# The first alert has been accepted by the user prompt handler, the second one remains.
# FIXME: this is how browsers currently work, but the spec should clarify if this is the
# expected behavior, see https://github.com/w3c/webdriver/issues/1153.
assert session.alert.text == "Bye"
session.alert.accept()

Просмотреть файл

@ -2,9 +2,7 @@
import pytest
from webdriver import error
from tests.support.asserts import assert_success
from tests.support.asserts import assert_dialog_handled, assert_error, assert_success
def execute_script(session, script, args=None):
@ -20,82 +18,57 @@ def execute_script(session, script, args=None):
@pytest.mark.capabilities({"unhandledPromptBehavior": "accept"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_accept(session, dialog_type):
response = execute_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_accept(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.accept()
response = execute_script(session, "return")
assert_success(response)
assert_dialog_handled(session, expected_text="dialog")
@pytest.mark.capabilities({"unhandledPromptBehavior": "accept and notify"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_accept_and_notify(session, dialog_type):
response = execute_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_accept_and_notify(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
with pytest.raises(error.UnexpectedAlertOpenException):
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.accept()
response = execute_script(session, "return")
assert_error(response, "unexpected alert open")
assert_dialog_handled(session, expected_text="dialog")
@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_dismiss(session, dialog_type):
response = execute_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_dismiss(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.dismiss()
response = execute_script(session, "return")
assert_success(response)
assert_dialog_handled(session, expected_text="dialog")
@pytest.mark.capabilities({"unhandledPromptBehavior": "dismiss and notify"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_dismiss_and_notify(session, dialog_type):
response = execute_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_dissmiss_and_notify(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
with pytest.raises(error.UnexpectedAlertOpenException):
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.dismiss()
response = execute_script(session, "return")
assert_error(response, "unexpected alert open")
assert_dialog_handled(session, expected_text="dialog")
@pytest.mark.capabilities({"unhandledPromptBehavior": "ignore"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_ignore(session, dialog_type):
response = execute_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
with pytest.raises(error.UnexpectedAlertOpenException):
session.title
session.alert.dismiss()
def test_handle_prompt_ignore():
"""TODO"""
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_default(session, dialog_type):
response = execute_script(session, "window.{}('Hello');".format(dialog_type))
assert_success(response, None)
def test_handle_prompt_default(session, create_dialog, dialog_type):
create_dialog(dialog_type, text="dialog")
with pytest.raises(error.UnexpectedAlertOpenException):
session.title
with pytest.raises(error.NoSuchAlertException):
session.alert.dismiss()
response = execute_script(session, "return")
assert_error(response, "unexpected alert open")
@pytest.mark.capabilities({"unhandledPromptBehavior": "accept"})
@pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"])
def test_handle_prompt_twice(session, dialog_type):
response = execute_script(
session, "window.{0}('Hello');window.{0}('Bye');".format(dialog_type))
assert_success(response, None)
session.alert.dismiss()
# The first alert has been accepted by the user prompt handler, the second one remains.
# FIXME: this is how browsers currently work, but the spec should clarify if this is the
# expected behavior, see https://github.com/w3c/webdriver/issues/1153.
assert session.alert.text == "Bye"
session.alert.dismiss()
assert_dialog_handled(session, expected_text="dialog")

Просмотреть файл

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
#include "CombinedStacks.h"
#include "ProcessedStack.h"
using namespace mozilla::Telemetry;
using namespace TelemetryTestHelpers;
TEST_F(TelemetryTestFixture, CombinedStacks) {
const size_t kMaxStacksKept = 10;
CombinedStacks stacks(kMaxStacksKept);
size_t iterations = kMaxStacksKept * 2;
for (size_t i = 0; i < iterations; ++i) {
ProcessedStack stack;
ProcessedStack::Frame frame = {static_cast<uint16_t>(i)};
const nsAutoString& name = NS_ConvertUTF8toUTF16(nsPrintfCString("test%zu", i));
ProcessedStack::Module module = {name};
stack.AddFrame(frame);
stack.AddModule(module);
stacks.AddStack(stack);
}
ASSERT_EQ(stacks.GetStackCount(), kMaxStacksKept) << "Wrong number of stacks";
ASSERT_EQ(stacks.GetModuleCount(), kMaxStacksKept * 2) << "Wrong number of modules";
for (size_t i = 0; i < kMaxStacksKept; ++i) {
ProcessedStack::Frame frame = stacks.GetStack(i)[0];
ASSERT_EQ(frame.mOffset, kMaxStacksKept + i) << "Frame is not returning expected value";
ProcessedStack::Module module = stacks.GetModule(frame.mModIndex);
nsPrintfCString moduleName("test%hu", frame.mModIndex);
ASSERT_TRUE(module.mName.Equals(NS_ConvertUTF8toUTF16(moduleName))) << "Module should have expected name";
}
for (size_t i = 0; i < kMaxStacksKept; ++i) {
stacks.RemoveStack(kMaxStacksKept - i - 1);
ASSERT_EQ(stacks.GetStackCount(), kMaxStacksKept - i - 1) <<"Stack should be removed";
}
}

Просмотреть файл

@ -13,6 +13,7 @@ LOCAL_INCLUDES += [
UNIFIED_SOURCES = [
'TelemetryFixture.cpp',
'TelemetryTestHelpers.cpp',
'TestCombinedStacks.cpp',
'TestCounters.cpp',
'TestHistograms.cpp',
'TestScalars.cpp'

Просмотреть файл

@ -276,7 +276,7 @@ function run_test() {
// This falls to the case where test_partialUpdateV4 is running.
// We are supposed to have verified the update request contains
// the state we set in the previous request.
run_next_test();
waitForUpdateSuccess(run_next_test);
return;
}
@ -296,6 +296,13 @@ function run_test() {
gHttpServV4.start(5555);
registerCleanupFunction(function() {
return (async function() {
await Promise.all([gHttpServ.stop(),
gHttpServV4.stop()]);
})();
});
run_next_test();
}
@ -314,16 +321,11 @@ function disableAllUpdates() {
gListManager.disableUpdate(TEST_TABLE_DATA_V4.tableName);
}
// Since there's no public interface on listmanager to know the update success,
// we could only rely on the refresh of "nextupdatetime".
function waitForUpdateSuccess(callback) {
let nextupdatetime = parseInt(Services.prefs.getCharPref(PREF_NEXTUPDATETIME));
info("nextupdatetime: " + nextupdatetime);
if (nextupdatetime !== 1) {
Services.obs.addObserver(function listener() {
Services.obs.removeObserver(listener, "safebrowsing-update-finished");
callback();
return;
}
do_timeout(1000, waitForUpdateSuccess.bind(null, callback));
}, "safebrowsing-update-finished");
}
// Construct an update from a file.