зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound on a CLOSED TREE
This commit is contained in:
Коммит
edd9f3a3d9
|
@ -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(¬ifications);
|
||||
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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче