Merge m-c to b2ginbound, a=merge

This commit is contained in:
Wes Kocher 2015-10-12 11:32:53 -07:00
Родитель 0c2f1c79db a2f9e79936
Коммит 74267b146f
131 изменённых файлов: 6015 добавлений и 1259 удалений

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

@ -1657,6 +1657,9 @@ pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/
// endpoint to send newtab click and view pings
pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v3/links/");
// activates the remote-hosted newtab page
pref("browser.newtabpage.remote", false);
// Enable the DOM fullscreen API.
pref("full-screen-api.enabled", true);

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

@ -34,6 +34,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "GMPInstallManager",
"resource://gre/modules/GMPInstallManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabUtils",
"resource:///modules/RemoteNewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
"resource:///modules/ContentSearch.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
@ -3511,8 +3513,11 @@ const BrowserSearch = {
if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField) {
let url = gBrowser.currentURI.spec.toLowerCase();
let mm = gBrowser.selectedBrowser.messageManager;
let newTabRemoted = Services.prefs.getBoolPref("browser.newtabpage.remote");
if (url === "about:home" ||
(url === "about:newtab" && NewTabUtils.allPages.enabled)) {
(url === "about:newtab" &&
((!newTabRemoted && NewTabUtils.allPages.enabled) ||
(newTabRemoted && RemoteNewTabUtils.allPages.enabled)))) {
ContentSearch.focusInput(mm);
} else {
openUILinkIn("about:home", "current");

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

@ -0,0 +1,23 @@
/* 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/. */
html {
width: 100%;
height: 100%;
}
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
position: relative;
}
#remotedoc {
width: 100%;
height: 100%;
border: none;
position: absolute;
}

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

@ -0,0 +1,126 @@
/* 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/. */
/*globals XPCOMUtils, Components, sendAsyncMessage, addMessageListener, removeMessageListener,
Services, PrivateBrowsingUtils*/
"use strict";
const {utils: Cu, interfaces: Ci} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
(function() {
let remoteNewTabLocation;
let remoteIFrame;
/**
* Attempts to handle commands sent from the remote IFrame within this content frame.
* Expected commands below, with data types explained.
*
* @returns {Boolean} whether or not the command was handled
* @param {String} command
* The command passed from the remote IFrame
* @param {Object} data
* Parameters to the command
*/
function handleCommand(command, data) {
let commandHandled = true;
switch (command) {
case "NewTab:UpdateTelemetryProbe":
/**
* Update a given Telemetry histogram
*
* @param {String} data.probe
* Probe name to update
* @param {Number} data.value
* Value to update histogram by
*/
Services.telemetry.getHistogramById(data.probe).add(data.value);
break;
case "NewTab:Register":
registerEvent(data.type);
break;
case "NewTab:GetInitialState":
getInitialState();
break;
default:
commandHandled = false;
}
return commandHandled;
}
function initRemotePage(initData) {
// Messages that the iframe sends the browser will be passed onto
// the privileged parent process
remoteNewTabLocation = initData;
remoteIFrame = document.querySelector("#remotedoc");
let loadHandler = () => {
if (remoteIFrame.src !== remoteNewTabLocation.href) {
return;
}
remoteIFrame.removeEventListener("load", loadHandler);
remoteIFrame.contentDocument.addEventListener("NewTabCommand", (e) => {
// If the commands are not handled within this content frame, the command will be
// passed on to main process, in RemoteAboutNewTab.jsm
let handled = handleCommand(e.detail.command, e.detail.data);
if (!handled) {
sendAsyncMessage(e.detail.command, e.detail.data);
}
});
registerEvent("NewTab:Observe");
let ev = new CustomEvent("NewTabCommandReady");
remoteIFrame.contentDocument.dispatchEvent(ev);
};
remoteIFrame.src = remoteNewTabLocation.href;
remoteIFrame.addEventListener("load", loadHandler);
}
/**
* Allows the content IFrame to register a listener to an event sent by
* the privileged parent process, in RemoteAboutNewTab.jsm
*
* @param {String} eventName
* Event name to listen to
*/
function registerEvent(eventName) {
addMessageListener(eventName, (message) => {
remoteIFrame.contentWindow.postMessage(message, remoteNewTabLocation.origin);
});
}
/**
* Sends the initial data payload to a content IFrame so it can bootstrap
*/
function getInitialState() {
let prefs = Services.prefs;
let isPrivate = PrivateBrowsingUtils.isContentWindowPrivate(window);
let state = {
enabled: prefs.getBoolPref("browser.newtabpage.enabled"),
enhanced: prefs.getBoolPref("browser.newtabpage.enhanced"),
rows: prefs.getIntPref("browser.newtabpage.rows"),
columns: prefs.getIntPref("browser.newtabpage.columns"),
introShown: prefs.getBoolPref("browser.newtabpage.introShown"),
windowID: window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils).outerWindowID,
privateBrowsingMode: isPrivate
};
remoteIFrame.contentWindow.postMessage({
name: "NewTab:State",
data: state
}, remoteNewTabLocation.origin);
}
addMessageListener("NewTabFrame:Init", function loadHandler(message) {
// Everything is loaded. Initialize the New Tab Page.
removeMessageListener("NewTabFrame:Init", loadHandler);
initRemotePage(message.data);
});
sendAsyncMessage("NewTabFrame:GetInit");
}());

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

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html [
<!ENTITY % newTabDTD SYSTEM "chrome://browser/locale/newTab.dtd">
%newTabDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&newtab.pageTitle;</title>
<link rel="stylesheet" href="chrome://browser/content/remote-newtab/newTab.css"/>
</head>
<body>
<iframe id="remotedoc"/>
<script type="text/javascript;version=1.8"
src="chrome://browser/content/remote-newtab/newTab.js">
</script>
</body>
</html>

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

@ -109,6 +109,9 @@ browser.jar:
* content/browser/newtab/newTab.js (content/newtab/newTab.js)
content/browser/newtab/newTab.css (content/newtab/newTab.css)
content/browser/newtab/newTab.inadjacent.json (content/newtab/newTab.inadjacent.json)
content/browser/remote-newtab/newTab.xhtml (content/remote-newtab/newTab.xhtml)
* content/browser/remote-newtab/newTab.js (content/remote-newtab/newTab.js)
content/browser/remote-newtab/newTab.css (content/remote-newtab/newTab.css)
* content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul)
content/browser/pageinfo/pageInfo.js (content/pageinfo/pageInfo.js)
content/browser/pageinfo/pageInfo.css (content/pageinfo/pageInfo.css)

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

@ -87,6 +87,9 @@ static RedirEntry kRedirMap[] = {
nsIAboutModule::ENABLE_INDEXED_DB },
{ "newtab", "chrome://browser/content/newtab/newTab.xhtml",
nsIAboutModule::ALLOW_SCRIPT },
{ "remote-newtab", "chrome://browser/content/remote-newtab/newTab.xhtml",
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
nsIAboutModule::ALLOW_SCRIPT },
{ "permissions", "chrome://browser/content/preferences/aboutPermissions.xul",
nsIAboutModule::ALLOW_SCRIPT },
{ "preferences", "chrome://browser/content/preferences/in-content/preferences.xul",

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

@ -107,6 +107,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
#endif
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "home", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "remote-newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },

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

@ -13,6 +13,7 @@ DIRS += [
'feeds',
'loop',
'migration',
'newtab',
'places',
'pocket',
'preferences',

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

@ -14,10 +14,15 @@ Components.utils.import("resource://gre/modules/Services.jsm");
this.NewTabURL = {
_url: "about:newtab",
_remoteUrl: "about:remote-newtab",
_overridden: false,
get: function() {
return this._url;
let output = this._url;
if (Services.prefs.getBoolPref("browser.newtabpage.remote")) {
output = this._remoteUrl;
}
return output;
},
get overridden() {

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

@ -0,0 +1,271 @@
/* 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/. */
/* global XPCOMUtils, Services, BinarySearch, PlacesUtils, gPrincipal, EventEmitter */
/* global gLinks */
/* exported PlacesProvider */
"use strict";
this.EXPORTED_SYMBOLS = ["PlacesProvider"];
const {interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BinarySearch",
"resource://gre/modules/BinarySearch.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js", {});
return EventEmitter;
});
XPCOMUtils.defineLazyGetter(this, "gPrincipal", function() {
let uri = Services.io.newURI("about:newtab", null, null);
return Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
});
// The maximum number of results PlacesProvider retrieves from history.
const HISTORY_RESULTS_LIMIT = 100;
/**
* Singleton that checks if a given link should be displayed on about:newtab
* or if we should rather not do it for security reasons. URIs that inherit
* their caller's principal will be filtered.
*/
let LinkChecker = {
_cache: new Map(),
get flags() {
return Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL |
Ci.nsIScriptSecurityManager.DONT_REPORT_ERRORS;
},
checkLoadURI: function LinkChecker_checkLoadURI(aURI) {
if (!this._cache.has(aURI)) {
this._cache.set(aURI, this._doCheckLoadURI(aURI));
}
return this._cache.get(aURI);
},
_doCheckLoadURI: function LinkChecker_doCheckLoadURI(aURI) {
let result = false;
try {
Services.scriptSecurityManager.
checkLoadURIStrWithPrincipal(gPrincipal, aURI, this.flags);
result = true;
} catch (e) {
// We got a weird URI or one that would inherit the caller's principal.
Cu.reportError(e);
}
return result;
}
};
/**
* Singleton that provides utility functions for links.
* A link is a plain object that looks like this:
*
* {
* url: "http://www.mozilla.org/",
* title: "Mozilla",
* frecency: 1337,
* lastVisitDate: 1394678824766431,
* }
*/
const LinkUtils = {
_sortProperties: [
"frecency",
"lastVisitDate",
"url",
],
/**
* Compares two links.
*
* @param {String} aLink1 The first link.
* @param {String} aLink2 The second link.
* @return {Number} A negative number if aLink1 is ordered before aLink2, zero if
* aLink1 and aLink2 have the same ordering, or a positive number if
* aLink1 is ordered after aLink2.
* Order is ascending.
*/
compareLinks: function LinkUtils_compareLinks(aLink1, aLink2) {
for (let prop of LinkUtils._sortProperties) {
if (!aLink1.hasOwnProperty(prop) || !aLink2.hasOwnProperty(prop)) {
throw new Error("Comparable link missing required property: " + prop);
}
}
return aLink2.frecency - aLink1.frecency ||
aLink2.lastVisitDate - aLink1.lastVisitDate ||
aLink1.url.localeCompare(aLink2.url);
},
};
/* Queries history to retrieve the most visited sites. Emits events when the
* history changes.
* Implements the EventEmitter interface.
*/
let Links = function Links() {
EventEmitter.decorate(this);
};
Links.prototype = {
/**
* Set this to change the maximum number of links the provider will provide.
*/
get maxNumLinks() {
// getter, so it can't be replaced dynamically
return HISTORY_RESULTS_LIMIT;
},
/**
* A set of functions called by @mozilla.org/browser/nav-historyservice
* All history events are emitted from this object.
*/
historyObserver: {
onDeleteURI: function historyObserver_onDeleteURI(aURI) {
// let observers remove sensetive data associated with deleted visit
gLinks.emit("deleteURI", {
url: aURI.spec,
});
},
onClearHistory: function historyObserver_onClearHistory() {
gLinks.emit("clearHistory");
},
onFrecencyChanged: function historyObserver_onFrecencyChanged(aURI,
aNewFrecency, aGUID, aHidden, aLastVisitDate) { // jshint ignore:line
// The implementation of the query in getLinks excludes hidden and
// unvisited pages, so it's important to exclude them here, too.
if (!aHidden && aLastVisitDate) {
gLinks.emit("linkChanged", {
url: aURI.spec,
frecency: aNewFrecency,
lastVisitDate: aLastVisitDate,
type: "history",
});
}
},
onManyFrecenciesChanged: function historyObserver_onManyFrecenciesChanged() {
// Called when frecencies are invalidated and also when clearHistory is called
// See toolkit/components/places/tests/unit/test_frecency_observers.js
gLinks.emit("manyLinksChanged");
},
onTitleChanged: function historyObserver_onTitleChanged(aURI, aNewTitle) {
gLinks.emit("linkChanged", {
url: aURI.spec,
title: aNewTitle
});
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver,
Ci.nsISupportsWeakReference])
},
/**
* Must be called before the provider is used.
* Makes it easy to disable under pref
*/
init: function PlacesProvider_init() {
PlacesUtils.history.addObserver(this.historyObserver, true);
},
/**
* Must be called before the provider is unloaded.
*/
destroy: function PlacesProvider_destroy() {
PlacesUtils.history.removeObserver(this.historyObserver);
},
/**
* Gets the current set of links delivered by this provider.
*
* @returns {Promise} Returns a promise with the array of links as payload.
*/
getLinks: function PlacesProvider_getLinks() {
let getLinksPromise = new Promise((resolve, reject) => {
let options = PlacesUtils.history.getNewQueryOptions();
options.maxResults = this.maxNumLinks;
// Sort by frecency, descending.
options.sortingMode = Ci.nsINavHistoryQueryOptions
.SORT_BY_FRECENCY_DESCENDING;
let links = [];
let queryHandlers = {
handleResult: function(aResultSet) {
for (let row = aResultSet.getNextRow(); row; row = aResultSet.getNextRow()) {
let url = row.getResultByIndex(1);
if (LinkChecker.checkLoadURI(url)) {
let link = {
url: url,
title: row.getResultByIndex(2),
frecency: row.getResultByIndex(12),
lastVisitDate: row.getResultByIndex(5),
type: "history",
};
links.push(link);
}
}
},
handleError: function(aError) {
reject(aError);
},
handleCompletion: function(aReason) { // jshint ignore:line
// The Places query breaks ties in frecency by place ID descending, but
// that's different from how Links.compareLinks breaks ties, because
// compareLinks doesn't have access to place IDs. It's very important
// that the initial list of links is sorted in the same order imposed by
// compareLinks, because Links uses compareLinks to perform binary
// searches on the list. So, ensure the list is so ordered.
let i = 1;
let outOfOrder = [];
while (i < links.length) {
if (LinkUtils.compareLinks(links[i - 1], links[i]) > 0) {
outOfOrder.push(links.splice(i, 1)[0]);
} else {
i++;
}
}
for (let link of outOfOrder) {
i = BinarySearch.insertionIndexOf(LinkUtils.compareLinks, links, link);
links.splice(i, 0, link);
}
resolve(links);
}
};
// Execute the query.
let query = PlacesUtils.history.getNewQuery();
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase);
db.asyncExecuteLegacyQueries([query], 1, options, queryHandlers);
});
return getLinksPromise;
}
};
/**
* Singleton that serves as the default link provider for the grid.
*/
const gLinks = new Links(); // jshint ignore:line
let PlacesProvider = {
LinkChecker: LinkChecker,
LinkUtils: LinkUtils,
links: gLinks,
};

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

@ -0,0 +1,233 @@
/* 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/. */
/* globals Services, XPCOMUtils, RemotePages, RemoteNewTabLocation, RemoteNewTabUtils, Task */
/* globals BackgroundPageThumbs, PageThumbs, RemoteDirectoryLinksProvider */
/* exported RemoteAboutNewTab */
"use strict";
let Ci = Components.interfaces;
let Cu = Components.utils;
const XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
this.EXPORTED_SYMBOLS = ["RemoteAboutNewTab"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.importGlobalProperties(["URL"]);
XPCOMUtils.defineLazyModuleGetter(this, "RemotePages",
"resource://gre/modules/RemotePageManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabUtils",
"resource:///modules/RemoteNewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BackgroundPageThumbs",
"resource://gre/modules/BackgroundPageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource://gre/modules/PageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteDirectoryLinksProvider",
"resource:///modules/RemoteDirectoryLinksProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabLocation",
"resource:///modules/RemoteNewTabLocation.jsm");
let RemoteAboutNewTab = {
pageListener: null,
/**
* Initialize the RemotePageManager and add all message listeners for this page
*/
init: function() {
this.pageListener = new RemotePages("about:remote-newtab");
this.pageListener.addMessageListener("NewTab:InitializeGrid", this.initializeGrid.bind(this));
this.pageListener.addMessageListener("NewTab:UpdateGrid", this.updateGrid.bind(this));
this.pageListener.addMessageListener("NewTab:CaptureBackgroundPageThumbs",
this.captureBackgroundPageThumb.bind(this));
this.pageListener.addMessageListener("NewTab:PageThumbs", this.createPageThumb.bind(this));
this.pageListener.addMessageListener("NewTabFrame:GetInit", this.initContentFrame.bind(this));
this._addObservers();
},
/**
* Initializes the grid for the first time when the page loads.
* Fetch all the links and send them down to the child to populate
* the grid with.
*
* @param {Object} message
* A RemotePageManager message.
*/
initializeGrid: function(message) {
RemoteNewTabUtils.links.populateCache(() => {
message.target.sendAsyncMessage("NewTab:InitializeLinks", {
links: RemoteNewTabUtils.links.getLinks(),
enhancedLinks: this.getEnhancedLinks(),
});
});
},
/**
* Inits the content iframe with the newtab location
*/
initContentFrame: function(message) {
message.target.sendAsyncMessage("NewTabFrame:Init", {
href: RemoteNewTabLocation.href,
origin: RemoteNewTabLocation.origin
});
},
/**
* Updates the grid by getting a new set of links.
*
* @param {Object} message
* A RemotePageManager message.
*/
updateGrid: function(message) {
message.target.sendAsyncMessage("NewTab:UpdateLinks", {
links: RemoteNewTabUtils.links.getLinks(),
enhancedLinks: this.getEnhancedLinks(),
});
},
/**
* Captures the site's thumbnail in the background, then attemps to show the thumbnail.
*
* @param {Object} message
* A RemotePageManager message with the following data:
*
* link (Object):
* A link object that contains:
*
* baseDomain (String)
* blockState (Boolean)
* frecency (Integer)
* lastVisiteDate (Integer)
* pinState (Boolean)
* title (String)
* type (String)
* url (String)
*/
captureBackgroundPageThumb: Task.async(function* (message) {
try {
yield BackgroundPageThumbs.captureIfMissing(message.data.link.url);
this.createPageThumb(message);
} catch (err) {
Cu.reportError("error: " + err);
}
}),
/**
* Creates the thumbnail to display for each site based on the unique URL
* of the site and it's type (regular or enhanced). If the thumbnail is of
* type "regular", we create a blob and send that down to the child. If the
* thumbnail is of type "enhanced", get the file path for the URL and create
* and enhanced URI that will be sent down to the child.
*
* @param {Object} message
* A RemotePageManager message with the following data:
*
* link (Object):
* A link object that contains:
*
* baseDomain (String)
* blockState (Boolean)
* frecency (Integer)
* lastVisiteDate (Integer)
* pinState (Boolean)
* title (String)
* type (String)
* url (String)
*/
createPageThumb: function(message) {
let imgSrc = PageThumbs.getThumbnailURL(message.data.link.url);
let doc = Services.appShell.hiddenDOMWindow.document;
let img = doc.createElementNS(XHTML_NAMESPACE, "img");
let canvas = doc.createElementNS(XHTML_NAMESPACE, "canvas");
let enhanced = Services.prefs.getBoolPref("browser.newtabpage.enhanced");
img.onload = function(e) { // jshint ignore:line
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0, this.naturalWidth, this.naturalHeight);
canvas.toBlob(function(blob) {
let host = new URL(message.data.link.url).host;
RemoteAboutNewTab.pageListener.sendAsyncMessage("NewTab:RegularThumbnailURI", {
thumbPath: "/pagethumbs/" + host,
enhanced,
url: message.data.link.url,
blob,
});
});
};
img.src = imgSrc;
},
/**
* Get the set of enhanced links (if any) from the Directory Links Provider.
*/
getEnhancedLinks: function() {
let enhancedLinks = [];
for (let link of RemoteNewTabUtils.links.getLinks()) {
if (link) {
enhancedLinks.push(RemoteDirectoryLinksProvider.getEnhancedLink(link));
}
}
return enhancedLinks;
},
/**
* Listens for a preference change or session purge for all pages and sends
* a message to update the pages that are open. If a session purge occured,
* also clear the links cache and update the set of links to display, as they
* may have changed, then proceed with the page update.
*/
observe: function(aSubject, aTopic, aData) { // jshint ignore:line
let extraData;
let refreshPage = false;
if (aTopic === "browser:purge-session-history") {
RemoteNewTabUtils.links.resetCache();
RemoteNewTabUtils.links.populateCache(() => {
this.pageListener.sendAsyncMessage("NewTab:UpdateLinks", {
links: RemoteNewTabUtils.links.getLinks(),
enhancedLinks: this.getEnhancedLinks(),
});
});
}
if (extraData !== undefined || aTopic === "page-thumbnail:create") {
if (aTopic !== "page-thumbnail:create") {
// Change the topic for enhanced and enabled observers.
aTopic = aData;
}
this.pageListener.sendAsyncMessage("NewTab:Observe", {topic: aTopic, data: extraData});
}
},
/**
* Add all observers that about:newtab page must listen for.
*/
_addObservers: function() {
Services.obs.addObserver(this, "page-thumbnail:create", true);
Services.obs.addObserver(this, "browser:purge-session-history", true);
},
/**
* Remove all observers on the page.
*/
_removeObservers: function() {
Services.obs.removeObserver(this, "page-thumbnail:create");
Services.obs.removeObserver(this, "browser:purge-session-history");
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
uninit: function() {
this._removeObservers();
this.pageListener.destroy();
this.pageListener = null;
},
};

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

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

@ -0,0 +1,42 @@
/* globals Services */
"use strict";
this.EXPORTED_SYMBOLS = ["RemoteNewTabLocation"];
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.importGlobalProperties(["URL"]);
// TODO: will get dynamically set in bug 1210478
const DEFAULT_PAGE_LOCATION = "https://newtab.cdn.mozilla.net/v0/nightly/en-US/index.html";
this.RemoteNewTabLocation = {
_url: new URL(DEFAULT_PAGE_LOCATION),
_overridden: false,
get href() {
return this._url.href;
},
get origin() {
return this._url.origin;
},
get overridden() {
return this._overridden;
},
override: function(newURL) {
this._url = new URL(newURL);
this._overridden = true;
Services.obs.notifyObservers(null, "remote-new-tab-location-changed",
this._url.href);
},
reset: function() {
this._url = new URL(DEFAULT_PAGE_LOCATION);
this._overridden = false;
Services.obs.notifyObservers(null, "remote-new-tab-location-changed",
this._url.href);
}
};

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

@ -0,0 +1,766 @@
/* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["RemoteNewTabUtils"];
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource://gre/modules/PageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BinarySearch",
"resource://gre/modules/BinarySearch.jsm");
XPCOMUtils.defineLazyGetter(this, "gPrincipal", function () {
let uri = Services.io.newURI("about:newtab", null, null);
return Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
});
// The maximum number of results PlacesProvider retrieves from history.
const HISTORY_RESULTS_LIMIT = 100;
// The maximum number of links Links.getLinks will return.
const LINKS_GET_LINKS_LIMIT = 100;
/**
* Singleton that serves as the default link provider for the grid. It queries
* the history to retrieve the most frequently visited sites.
*/
let PlacesProvider = {
/**
* A count of how many batch updates are under way (batches may be nested, so
* we keep a counter instead of a simple bool).
**/
_batchProcessingDepth: 0,
/**
* A flag that tracks whether onFrecencyChanged was notified while a batch
* operation was in progress, to tell us whether to take special action after
* the batch operation completes.
**/
_batchCalledFrecencyChanged: false,
/**
* Set this to change the maximum number of links the provider will provide.
*/
maxNumLinks: HISTORY_RESULTS_LIMIT,
/**
* Must be called before the provider is used.
*/
init: function PlacesProvider_init() {
PlacesUtils.history.addObserver(this, true);
},
/**
* Gets the current set of links delivered by this provider.
* @param aCallback The function that the array of links is passed to.
*/
getLinks: function PlacesProvider_getLinks(aCallback) {
let options = PlacesUtils.history.getNewQueryOptions();
options.maxResults = this.maxNumLinks;
// Sort by frecency, descending.
options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_FRECENCY_DESCENDING
let links = [];
let callback = {
handleResult: function (aResultSet) {
let row;
while ((row = aResultSet.getNextRow())) {
let url = row.getResultByIndex(1);
if (LinkChecker.checkLoadURI(url)) {
let title = row.getResultByIndex(2);
let frecency = row.getResultByIndex(12);
let lastVisitDate = row.getResultByIndex(5);
links.push({
url: url,
title: title,
frecency: frecency,
lastVisitDate: lastVisitDate,
type: "history",
});
}
}
},
handleError: function (aError) {
// Should we somehow handle this error?
aCallback([]);
},
handleCompletion: function (aReason) {
// The Places query breaks ties in frecency by place ID descending, but
// that's different from how Links.compareLinks breaks ties, because
// compareLinks doesn't have access to place IDs. It's very important
// that the initial list of links is sorted in the same order imposed by
// compareLinks, because Links uses compareLinks to perform binary
// searches on the list. So, ensure the list is so ordered.
let i = 1;
let outOfOrder = [];
while (i < links.length) {
if (Links.compareLinks(links[i - 1], links[i]) > 0)
outOfOrder.push(links.splice(i, 1)[0]);
else
i++;
}
for (let link of outOfOrder) {
i = BinarySearch.insertionIndexOf(Links.compareLinks, links, link);
links.splice(i, 0, link);
}
aCallback(links);
}
};
// Execute the query.
let query = PlacesUtils.history.getNewQuery();
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase);
db.asyncExecuteLegacyQueries([query], 1, options, callback);
},
/**
* Registers an object that will be notified when the provider's links change.
* @param aObserver An object with the following optional properties:
* * onLinkChanged: A function that's called when a single link
* changes. It's passed the provider and the link object. Only the
* link's `url` property is guaranteed to be present. If its `title`
* property is present, then its title has changed, and the
* property's value is the new title. If any sort properties are
* present, then its position within the provider's list of links may
* have changed, and the properties' values are the new sort-related
* values. Note that this link may not necessarily have been present
* in the lists returned from any previous calls to getLinks.
* * onManyLinksChanged: A function that's called when many links
* change at once. It's passed the provider. You should call
* getLinks to get the provider's new list of links.
*/
addObserver: function PlacesProvider_addObserver(aObserver) {
this._observers.push(aObserver);
},
_observers: [],
/**
* Called by the history service.
*/
onBeginUpdateBatch: function() {
this._batchProcessingDepth += 1;
},
onEndUpdateBatch: function() {
this._batchProcessingDepth -= 1;
if (this._batchProcessingDepth == 0 && this._batchCalledFrecencyChanged) {
this.onManyFrecenciesChanged();
this._batchCalledFrecencyChanged = false;
}
},
onDeleteURI: function PlacesProvider_onDeleteURI(aURI, aGUID, aReason) {
// let observers remove sensetive data associated with deleted visit
this._callObservers("onDeleteURI", {
url: aURI.spec,
});
},
onClearHistory: function() {
this._callObservers("onClearHistory")
},
/**
* Called by the history service.
*/
onFrecencyChanged: function PlacesProvider_onFrecencyChanged(aURI, aNewFrecency, aGUID, aHidden, aLastVisitDate) {
// If something is doing a batch update of history entries we don't want
// to do lots of work for each record. So we just track the fact we need
// to call onManyFrecenciesChanged() once the batch is complete.
if (this._batchProcessingDepth > 0) {
this._batchCalledFrecencyChanged = true;
return;
}
// The implementation of the query in getLinks excludes hidden and
// unvisited pages, so it's important to exclude them here, too.
if (!aHidden && aLastVisitDate) {
this._callObservers("onLinkChanged", {
url: aURI.spec,
frecency: aNewFrecency,
lastVisitDate: aLastVisitDate,
type: "history",
});
}
},
/**
* Called by the history service.
*/
onManyFrecenciesChanged: function PlacesProvider_onManyFrecenciesChanged() {
this._callObservers("onManyLinksChanged");
},
/**
* Called by the history service.
*/
onTitleChanged: function PlacesProvider_onTitleChanged(aURI, aNewTitle, aGUID) {
this._callObservers("onLinkChanged", {
url: aURI.spec,
title: aNewTitle
});
},
_callObservers: function PlacesProvider__callObservers(aMethodName, aArg) {
for (let obs of this._observers) {
if (obs[aMethodName]) {
try {
obs[aMethodName](this, aArg);
} catch (err) {
Cu.reportError(err);
}
}
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver,
Ci.nsISupportsWeakReference]),
};
/**
* Singleton that provides access to all links contained in the grid (including
* the ones that don't fit on the grid). A link is a plain object that looks
* like this:
*
* {
* url: "http://www.mozilla.org/",
* title: "Mozilla",
* frecency: 1337,
* lastVisitDate: 1394678824766431,
* }
*/
let Links = {
/**
* The maximum number of links returned by getLinks.
*/
maxNumLinks: LINKS_GET_LINKS_LIMIT,
/**
* A mapping from each provider to an object { sortedLinks, siteMap, linkMap }.
* sortedLinks is the cached, sorted array of links for the provider.
* siteMap is a mapping from base domains to URL count associated with the domain.
* siteMap is used to look up a user's top sites that can be targeted
* with a suggested tile.
* linkMap is a Map from link URLs to link objects.
*/
_providers: new Map(),
/**
* The properties of link objects used to sort them.
*/
_sortProperties: [
"frecency",
"lastVisitDate",
"url",
],
/**
* List of callbacks waiting for the cache to be populated.
*/
_populateCallbacks: [],
/**
* A list of objects that are observing links updates.
*/
_observers: [],
/**
* Registers an object that will be notified when links updates.
*/
addObserver: function (aObserver) {
this._observers.push(aObserver);
},
/**
* Adds a link provider.
* @param aProvider The link provider.
*/
addProvider: function Links_addProvider(aProvider) {
this._providers.set(aProvider, null);
aProvider.addObserver(this);
},
/**
* Removes a link provider.
* @param aProvider The link provider.
*/
removeProvider: function Links_removeProvider(aProvider) {
if (!this._providers.delete(aProvider))
throw new Error("Unknown provider");
},
/**
* Populates the cache with fresh links from the providers.
* @param aCallback The callback to call when finished (optional).
* @param aForce When true, populates the cache even when it's already filled.
*/
populateCache: function Links_populateCache(aCallback, aForce) {
let callbacks = this._populateCallbacks;
// Enqueue the current callback.
callbacks.push(aCallback);
// There was a callback waiting already, thus the cache has not yet been
// populated.
if (callbacks.length > 1)
return;
function executeCallbacks() {
while (callbacks.length) {
let callback = callbacks.shift();
if (callback) {
try {
callback();
} catch (e) {
// We want to proceed even if a callback fails.
}
}
}
}
let numProvidersRemaining = this._providers.size;
for (let [provider, links] of this._providers) {
this._populateProviderCache(provider, () => {
if (--numProvidersRemaining == 0)
executeCallbacks();
}, aForce);
}
},
/**
* Gets the current set of links contained in the grid.
* @return The links in the grid.
*/
getLinks: function Links_getLinks() {
let links = this._getMergedProviderLinks();
let sites = new Set();
// Filter duplicate base domains.
links = links.filter(function (link) {
let site = RemoteNewTabUtils.extractSite(link.url);
link.baseDomain = site;
if (site == null || sites.has(site))
return false;
sites.add(site);
return true;
});
return links;
},
/**
* Resets the links cache.
*/
resetCache: function Links_resetCache() {
for (let provider of this._providers.keys()) {
this._providers.set(provider, null);
}
},
/**
* Compares two links.
* @param aLink1 The first link.
* @param aLink2 The second link.
* @return A negative number if aLink1 is ordered before aLink2, zero if
* aLink1 and aLink2 have the same ordering, or a positive number if
* aLink1 is ordered after aLink2.
*
* @note compareLinks's this object is bound to Links below.
*/
compareLinks: function Links_compareLinks(aLink1, aLink2) {
for (let prop of this._sortProperties) {
if (!(prop in aLink1) || !(prop in aLink2))
throw new Error("Comparable link missing required property: " + prop);
}
return aLink2.frecency - aLink1.frecency ||
aLink2.lastVisitDate - aLink1.lastVisitDate ||
aLink1.url.localeCompare(aLink2.url);
},
_incrementSiteMap: function(map, link) {
let site = RemoteNewTabUtils.extractSite(link.url);
map.set(site, (map.get(site) || 0) + 1);
},
_decrementSiteMap: function(map, link) {
let site = RemoteNewTabUtils.extractSite(link.url);
let previousURLCount = map.get(site);
if (previousURLCount === 1) {
map.delete(site);
} else {
map.set(site, previousURLCount - 1);
}
},
/**
* Update the siteMap cache based on the link given and whether we need
* to increment or decrement it. We do this by iterating over all stored providers
* to find which provider this link already exists in. For providers that
* have this link, we will adjust siteMap for them accordingly.
*
* @param aLink The link that will affect siteMap
* @param increment A boolean for whether to increment or decrement siteMap
*/
_adjustSiteMapAndNotify: function(aLink, increment=true) {
for (let [provider, cache] of this._providers) {
// We only update siteMap if aLink is already stored in linkMap.
if (cache.linkMap.get(aLink.url)) {
if (increment) {
this._incrementSiteMap(cache.siteMap, aLink);
continue;
}
this._decrementSiteMap(cache.siteMap, aLink);
}
}
this._callObservers("onLinkChanged", aLink);
},
populateProviderCache: function(provider, callback) {
if (!this._providers.has(provider)) {
throw new Error("Can only populate provider cache for existing provider.");
}
return this._populateProviderCache(provider, callback, false);
},
/**
* Calls getLinks on the given provider and populates our cache for it.
* @param aProvider The provider whose cache will be populated.
* @param aCallback The callback to call when finished.
* @param aForce When true, populates the provider's cache even when it's
* already filled.
*/
_populateProviderCache: function (aProvider, aCallback, aForce) {
let cache = this._providers.get(aProvider);
let createCache = !cache;
if (createCache) {
cache = {
// Start with a resolved promise.
populatePromise: new Promise(resolve => resolve()),
};
this._providers.set(aProvider, cache);
}
// Chain the populatePromise so that calls are effectively queued.
cache.populatePromise = cache.populatePromise.then(() => {
return new Promise(resolve => {
if (!createCache && !aForce) {
aCallback();
resolve();
return;
}
aProvider.getLinks(links => {
// Filter out null and undefined links so we don't have to deal with
// them in getLinks when merging links from providers.
links = links.filter((link) => !!link);
cache.sortedLinks = links;
cache.siteMap = links.reduce((map, link) => {
this._incrementSiteMap(map, link);
return map;
}, new Map());
cache.linkMap = links.reduce((map, link) => {
map.set(link.url, link);
return map;
}, new Map());
aCallback();
resolve();
});
});
});
},
/**
* Merges the cached lists of links from all providers whose lists are cached.
* @return The merged list.
*/
_getMergedProviderLinks: function Links__getMergedProviderLinks() {
// Build a list containing a copy of each provider's sortedLinks list.
let linkLists = [];
for (let provider of this._providers.keys()) {
let links = this._providers.get(provider);
if (links && links.sortedLinks) {
linkLists.push(links.sortedLinks.slice());
}
}
function getNextLink() {
let minLinks = null;
for (let links of linkLists) {
if (links.length &&
(!minLinks || Links.compareLinks(links[0], minLinks[0]) < 0))
minLinks = links;
}
return minLinks ? minLinks.shift() : null;
}
let finalLinks = [];
for (let nextLink = getNextLink();
nextLink && finalLinks.length < this.maxNumLinks;
nextLink = getNextLink()) {
finalLinks.push(nextLink);
}
return finalLinks;
},
/**
* Called by a provider to notify us when a single link changes.
* @param aProvider The provider whose link changed.
* @param aLink The link that changed. If the link is new, it must have all
* of the _sortProperties. Otherwise, it may have as few or as
* many as is convenient.
* @param aIndex The current index of the changed link in the sortedLinks
cache in _providers. Defaults to -1 if the provider doesn't know the index
* @param aDeleted Boolean indicating if the provider has deleted the link.
*/
onLinkChanged: function Links_onLinkChanged(aProvider, aLink, aIndex=-1, aDeleted=false) {
if (!("url" in aLink))
throw new Error("Changed links must have a url property");
let links = this._providers.get(aProvider);
if (!links)
// This is not an error, it just means that between the time the provider
// was added and the future time we call getLinks on it, it notified us of
// a change.
return;
let { sortedLinks, siteMap, linkMap } = links;
let existingLink = linkMap.get(aLink.url);
let insertionLink = null;
if (existingLink) {
// Update our copy's position in O(lg n) by first removing it from its
// list. It's important to do this before modifying its properties.
if (this._sortProperties.some(prop => prop in aLink)) {
let idx = aIndex;
if (idx < 0) {
idx = this._indexOf(sortedLinks, existingLink);
} else if (this.compareLinks(aLink, sortedLinks[idx]) != 0) {
throw new Error("aLink should be the same as sortedLinks[idx]");
}
if (idx < 0) {
throw new Error("Link should be in _sortedLinks if in _linkMap");
}
sortedLinks.splice(idx, 1);
if (aDeleted) {
linkMap.delete(existingLink.url);
this._decrementSiteMap(siteMap, existingLink);
} else {
// Update our copy's properties.
Object.assign(existingLink, aLink);
// Finally, reinsert our copy below.
insertionLink = existingLink;
}
}
// Update our copy's title in O(1).
if ("title" in aLink && aLink.title != existingLink.title) {
existingLink.title = aLink.title;
}
}
else if (this._sortProperties.every(prop => prop in aLink)) {
// Before doing the O(lg n) insertion below, do an O(1) check for the
// common case where the new link is too low-ranked to be in the list.
if (sortedLinks.length && sortedLinks.length == aProvider.maxNumLinks) {
let lastLink = sortedLinks[sortedLinks.length - 1];
if (this.compareLinks(lastLink, aLink) < 0) {
return;
}
}
// Copy the link object so that changes later made to it by the caller
// don't affect our copy.
insertionLink = {};
for (let prop in aLink) {
insertionLink[prop] = aLink[prop];
}
linkMap.set(aLink.url, insertionLink);
this._incrementSiteMap(siteMap, aLink);
}
if (insertionLink) {
let idx = this._insertionIndexOf(sortedLinks, insertionLink);
sortedLinks.splice(idx, 0, insertionLink);
if (sortedLinks.length > aProvider.maxNumLinks) {
let lastLink = sortedLinks.pop();
linkMap.delete(lastLink.url);
this._decrementSiteMap(siteMap, lastLink);
}
}
},
/**
* Called by a provider to notify us when many links change.
*/
onManyLinksChanged: function Links_onManyLinksChanged(aProvider) {
this._populateProviderCache(aProvider, () => {}, true);
},
_indexOf: function Links__indexOf(aArray, aLink) {
return this._binsearch(aArray, aLink, "indexOf");
},
_insertionIndexOf: function Links__insertionIndexOf(aArray, aLink) {
return this._binsearch(aArray, aLink, "insertionIndexOf");
},
_binsearch: function Links__binsearch(aArray, aLink, aMethod) {
return BinarySearch[aMethod](this.compareLinks, aArray, aLink);
},
_callObservers(methodName, ...args) {
for (let obs of this._observers) {
if (typeof(obs[methodName]) == "function") {
try {
obs[methodName](this, ...args);
} catch (err) {
Cu.reportError(err);
}
}
}
},
};
Links.compareLinks = Links.compareLinks.bind(Links);
/**
* Singleton that checks if a given link should be displayed on about:newtab
* or if we should rather not do it for security reasons. URIs that inherit
* their caller's principal will be filtered.
*/
let LinkChecker = {
_cache: {},
get flags() {
return Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL |
Ci.nsIScriptSecurityManager.DONT_REPORT_ERRORS;
},
checkLoadURI: function LinkChecker_checkLoadURI(aURI) {
if (!(aURI in this._cache))
this._cache[aURI] = this._doCheckLoadURI(aURI);
return this._cache[aURI];
},
_doCheckLoadURI: function Links_doCheckLoadURI(aURI) {
try {
Services.scriptSecurityManager.
checkLoadURIStrWithPrincipal(gPrincipal, aURI, this.flags);
return true;
} catch (e) {
// We got a weird URI or one that would inherit the caller's principal.
return false;
}
}
};
let ExpirationFilter = {
init: function ExpirationFilter_init() {
PageThumbs.addExpirationFilter(this);
},
filterForThumbnailExpiration:
function ExpirationFilter_filterForThumbnailExpiration(aCallback) {
Links.populateCache(function () {
let urls = [];
// Add all URLs to the list that we want to keep thumbnails for.
for (let link of Links.getLinks().slice(0, 25)) {
if (link && link.url)
urls.push(link.url);
}
aCallback(urls);
});
}
};
/**
* Singleton that provides the public API of this JSM.
*/
this.RemoteNewTabUtils = {
_initialized: false,
/**
* Extract a "site" from a url in a way that multiple urls of a "site" returns
* the same "site."
* @param aUrl Url spec string
* @return The "site" string or null
*/
extractSite: function Links_extractSite(url) {
let host;
try {
// Note that nsIURI.asciiHost throws NS_ERROR_FAILURE for some types of
// URIs, including jar and moz-icon URIs.
host = Services.io.newURI(url, null, null).asciiHost;
} catch (ex) {
return null;
}
// Strip off common subdomains of the same site (e.g., www, load balancer)
return host.replace(/^(m|mobile|www\d*)\./, "");
},
init: function RemoteNewTabUtils_init() {
if (this.initWithoutProviders()) {
PlacesProvider.init();
Links.addProvider(PlacesProvider);
}
},
initWithoutProviders: function RemoteNewTabUtils_initWithoutProviders() {
if (!this._initialized) {
this._initialized = true;
ExpirationFilter.init();
return true;
}
return false;
},
getProviderLinks: function(aProvider) {
let cache = Links._providers.get(aProvider);
if (cache && cache.sortedLinks) {
return cache.sortedLinks;
}
return [];
},
isTopSiteGivenProvider: function(aSite, aProvider) {
let cache = Links._providers.get(aProvider);
if (cache && cache.siteMap) {
return cache.siteMap.has(aSite);
}
return false;
},
isTopPlacesSite: function(aSite) {
return this.isTopSiteGivenProvider(aSite, PlacesProvider);
},
links: Links,
linkChecker: LinkChecker,
placesProvider: PlacesProvider
};

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

@ -0,0 +1,20 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
XPCSHELL_TESTS_MANIFESTS += [
'tests/xpcshell/xpcshell.ini',
]
EXTRA_JS_MODULES += [
'NewTabURL.jsm',
'PlacesProvider.jsm',
'RemoteAboutNewTab.jsm',
'RemoteDirectoryLinksProvider.jsm',
'RemoteNewTabLocation.jsm',
'RemoteNewTabUtils.jsm',
]

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

@ -0,0 +1,5 @@
[DEFAULT]
support-files =
dummy_page.html
[browser_remotenewtab_pageloads.js]

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

@ -0,0 +1,46 @@
/* globals XPCOMUtils, Task, RemoteAboutNewTab, RemoteNewTabLocation, ok */
"use strict";
let Cu = Components.utils;
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabLocation",
"resource:///modules/RemoteNewTabLocation.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteAboutNewTab",
"resource:///modules/RemoteAboutNewTab.jsm");
const TEST_URL = "https://example.com/browser/browser/components/newtab/tests/browser/dummy_page.html";
const NEWTAB_URL = "about:remote-newtab";
let tests = [];
/*
* Tests that:
* 1. overriding the RemoteNewTabPageLocation url causes a remote newtab page
* to load with the new url.
* 2. Messages pass between remote page <--> newTab.js <--> RemoteAboutNewTab.js
*/
tests.push(Task.spawn(function* testMessage() {
yield new Promise(resolve => {
RemoteAboutNewTab.pageListener.addMessageListener("NewTab:testMessage", () => {
ok(true, "message received");
resolve();
});
});
}));
add_task(function* open_newtab() {
RemoteNewTabLocation.override(TEST_URL);
ok(RemoteNewTabLocation.href === TEST_URL, "RemoteNewTabLocation has been overridden");
let tabOptions = {
gBrowser,
url: NEWTAB_URL,
};
for (let test of tests) {
yield BrowserTestUtils.withNewTab(tabOptions, function* (browser) { // jshint ignore:line
yield test;
}); // jshint ignore:line
}
});

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

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<p>Dummy Page</p>
<script type="text/javascript;version=1.8">
document.addEventListener("NewTabCommandReady", function readyCmd() {
document.removeEventListener("NewTabCommandReady", readyCmd);
let event = new CustomEvent("NewTabCommand", {
detail: {
command: "NewTab:testMessage"
}
});
document.dispatchEvent(event);
});
</script>
</body>
</html>

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

@ -20,6 +20,11 @@ add_task(function* () {
yield notificationPromise;
Assert.ok(!NewTabURL.overridden, "Newtab URL should not be overridden");
Assert.equal(NewTabURL.get(), "about:newtab", "Newtab URL should be the about:newtab");
// change newtab page to remote
Services.prefs.setBoolPref("browser.newtabpage.remote", true);
Assert.equal(NewTabURL.get(), "about:remote-newtab", "Newtab URL should be the about:remote-newtab");
Assert.ok(!NewTabURL.overridden, "Newtab URL should not be overridden");
});
function promiseNewtabURLNotification(aNewURL) {

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

@ -0,0 +1,307 @@
"use strict";
/* global XPCOMUtils, PlacesUtils, PlacesTestUtils, PlacesProvider, NetUtil */
/* global do_get_profile, run_next_test, add_task */
/* global equal, ok */
/* exported run_test */
const {
utils: Cu,
interfaces: Ci,
} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesProvider",
"resource:///modules/PlacesProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
"resource://testing-common/PlacesTestUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
// ensure a profile exists
do_get_profile();
function run_test() {
run_next_test();
}
/** Test LinkChecker **/
add_task(function test_LinkChecker_securityCheck() {
let urls = [
{url: "file://home/file/image.png", expected: false},
{url: "resource:///modules/PlacesProvider.jsm", expected: false},
{url: "javascript:alert('hello')", expected: false}, // jshint ignore:line
{url: "data:image/png;base64,XXX", expected: false},
{url: "about:newtab", expected: true},
{url: "https://example.com", expected: true},
{url: "ftp://example.com", expected: true},
];
for (let {url, expected} of urls) {
let observed = PlacesProvider.LinkChecker.checkLoadURI(url);
equal(observed , expected, `can load "${url}"?`);
}
});
/** Test LinkUtils **/
add_task(function test_LinkUtils_compareLinks() {
let fixtures = {
firstOlder: {
url: "http://www.mozilla.org/firstolder",
title: "Mozilla",
frecency: 1337,
lastVisitDate: 1394678824766431,
},
older: {
url: "http://www.mozilla.org/older",
title: "Mozilla",
frecency: 1337,
lastVisitDate: 1394678824766431,
},
newer: {
url: "http://www.mozilla.org/newer",
title: "Mozilla",
frecency: 1337,
lastVisitDate: 1494678824766431,
},
moreFrecent: {
url: "http://www.mozilla.org/moreFrecent",
title: "Mozilla",
frecency: 1337357,
lastVisitDate: 1394678824766431,
}
};
let links = [
// tests string ordering, f is before o
{link1: fixtures.firstOlder, link2: fixtures.older, expected: false},
// test identity
{link1: fixtures.older, link2: fixtures.older, expected: false},
// test ordering by date
{link1: fixtures.older, link2: fixtures.newer, expected: true},
{link1: fixtures.newer, link2: fixtures.older, expected: false},
// test frecency
{link1: fixtures.moreFrecent, link2: fixtures.older, expected: false},
];
for (let {link1, link2, expected} of links) {
let observed = PlacesProvider.LinkUtils.compareLinks(link1, link2) > 0;
equal(observed , expected, `comparing ${link1.url} and ${link2.url}`);
}
// test error scenarios
let errorFixtures = {
missingFrecency: {
url: "http://www.mozilla.org/firstolder",
title: "Mozilla",
lastVisitDate: 1394678824766431,
},
missingVisitDate: {
url: "http://www.mozilla.org/firstolder",
title: "Mozilla",
frecency: 1337,
},
missingURL: {
title: "Mozilla",
frecency: 1337,
lastVisitDate: 1394678824766431,
}
};
let errorLinks = [
{link1: fixtures.older, link2: errorFixtures.missingFrecency},
{link2: fixtures.older, link1: errorFixtures.missingFrecency},
{link1: fixtures.older, link2: errorFixtures.missingVisitDate},
{link1: fixtures.older, link2: errorFixtures.missingURL},
{link1: errorFixtures.missingFrecency, link2: errorFixtures.missingVisitDate}
];
let errorCount = 0;
for (let {link1, link2} of errorLinks) {
try {
let observed = PlacesProvider.LinkUtils.compareLinks(link1, link2) > 0; // jshint ignore:line
} catch (e) {
ok(true, `exception for comparison of ${link1.url} and ${link2.url}`);
errorCount += 1;
}
}
equal(errorCount, errorLinks.length);
});
/** Test Provider **/
add_task(function* test_Links_getLinks() {
yield PlacesTestUtils.clearHistory();
let provider = PlacesProvider.links;
let links = yield provider.getLinks();
equal(links.length, 0, "empty history yields empty links");
// add a visit
let testURI = NetUtil.newURI("http://mozilla.com");
yield PlacesTestUtils.addVisits(testURI);
links = yield provider.getLinks();
equal(links.length, 1, "adding a visit yields a link");
equal(links[0].url, testURI.spec, "added visit corresponds to added url");
});
add_task(function* test_Links_getLinks_Order() {
yield PlacesTestUtils.clearHistory();
let provider = PlacesProvider.links;
let {
TRANSITION_TYPED,
TRANSITION_LINK
} = PlacesUtils.history;
function timeDaysAgo(numDays) {
let now = new Date();
return now.getTime() - (numDays * 24 * 60 * 60 * 1000);
}
let timeEarlier = timeDaysAgo(0);
let timeLater = timeDaysAgo(2);
let visits = [
// frecency 200
{uri: NetUtil.newURI("https://mozilla.com/0"), visitDate: timeEarlier, transition: TRANSITION_TYPED},
// sort by url, frecency 200
{uri: NetUtil.newURI("https://mozilla.com/1"), visitDate: timeEarlier, transition: TRANSITION_TYPED},
// sort by last visit date, frecency 200
{uri: NetUtil.newURI("https://mozilla.com/2"), visitDate: timeLater, transition: TRANSITION_TYPED},
// sort by frecency, frecency 10
{uri: NetUtil.newURI("https://mozilla.com/3"), visitDate: timeLater, transition: TRANSITION_LINK},
];
let links = yield provider.getLinks();
equal(links.length, 0, "empty history yields empty links");
yield PlacesTestUtils.addVisits(visits);
links = yield provider.getLinks();
equal(links.length, visits.length, "number of links added is the same as obtain by getLinks");
for (let i = 0; i < links.length; i++) {
equal(links[i].url, visits[i].uri.spec, "links are obtained in the expected order");
}
});
add_task(function* test_Links_onLinkChanged() {
let provider = PlacesProvider.links;
provider.init();
let url = "https://example.com/onFrecencyChanged1";
let linkChangedMsgCount = 0;
let linkChangedPromise = new Promise(resolve => {
let handler = (_, link) => { // jshint ignore:line
/* There are 3 linkChanged events:
* 1. visit insertion (-1 frecency by default)
* 2. frecency score update (after transition type calculation etc)
* 3. title change
*/
if (link.url === url) {
equal(link.url, url, `expected url on linkChanged event`);
linkChangedMsgCount += 1;
if (linkChangedMsgCount === 3) {
ok(true, `all linkChanged events captured`);
provider.off("linkChanged", this);
resolve();
}
}
};
provider.on("linkChanged", handler);
});
// add a visit
let testURI = NetUtil.newURI(url);
yield PlacesTestUtils.addVisits(testURI);
yield linkChangedPromise;
yield PlacesTestUtils.clearHistory();
provider.destroy();
});
add_task(function* test_Links_onClearHistory() {
let provider = PlacesProvider.links;
provider.init();
let clearHistoryPromise = new Promise(resolve => {
let handler = () => {
ok(true, `clearHistory event captured`);
provider.off("clearHistory", handler);
resolve();
};
provider.on("clearHistory", handler);
});
// add visits
for (let i = 0; i <= 10; i++) {
let url = `https://example.com/onClearHistory${i}`;
let testURI = NetUtil.newURI(url);
yield PlacesTestUtils.addVisits(testURI);
}
yield PlacesTestUtils.clearHistory();
yield clearHistoryPromise;
provider.destroy();
});
add_task(function* test_Links_onDeleteURI() {
let provider = PlacesProvider.links;
provider.init();
let testURL = "https://example.com/toDelete";
let deleteURIPromise = new Promise(resolve => {
let handler = (_, {url}) => { // jshint ignore:line
equal(testURL, url, "deleted url and expected url are the same");
provider.off("deleteURI", handler);
resolve();
};
provider.on("deleteURI", handler);
});
let testURI = NetUtil.newURI(testURL);
yield PlacesTestUtils.addVisits(testURI);
yield PlacesUtils.history.remove(testURL);
yield deleteURIPromise;
provider.destroy();
});
add_task(function* test_Links_onManyLinksChanged() {
let provider = PlacesProvider.links;
provider.init();
let promise = new Promise(resolve => {
let handler = () => {
ok(true);
provider.off("manyLinksChanged", handler);
resolve();
};
provider.on("manyLinksChanged", handler);
});
let testURL = "https://example.com/toDelete";
let testURI = NetUtil.newURI(testURL);
yield PlacesTestUtils.addVisits(testURI);
// trigger DecayFrecency
PlacesUtils.history.QueryInterface(Ci.nsIObserver).
observe(null, "idle-daily", "");
yield promise;
provider.destroy();
});

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

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

@ -0,0 +1,40 @@
/* globals ok, equal, RemoteNewTabLocation, Services */
"use strict";
Components.utils.import("resource:///modules/RemoteNewTabLocation.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.importGlobalProperties(["URL"]);
add_task(function* () {
var notificationPromise;
let defaultHref = RemoteNewTabLocation.href;
ok(RemoteNewTabLocation.href, "Default location has an href");
ok(RemoteNewTabLocation.origin, "Default location has an origin");
ok(!RemoteNewTabLocation.overridden, "Default location is not overridden");
let testURL = new URL("https://example.com/");
notificationPromise = changeNotificationPromise(testURL.href);
RemoteNewTabLocation.override(testURL.href);
yield notificationPromise;
ok(RemoteNewTabLocation.overridden, "Remote location should be overridden");
equal(RemoteNewTabLocation.href, testURL.href, "Remote href should be the custom URL");
equal(RemoteNewTabLocation.origin, testURL.origin, "Remote origin should be the custom URL");
notificationPromise = changeNotificationPromise(defaultHref);
RemoteNewTabLocation.reset();
yield notificationPromise;
ok(!RemoteNewTabLocation.overridden, "Newtab URL should not be overridden");
equal(RemoteNewTabLocation.href, defaultHref, "Remote href should be reset");
});
function changeNotificationPromise(aNewURL) {
return new Promise(resolve => {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint ignore:line
Services.obs.removeObserver(observer, aTopic);
equal(aData, aNewURL, "remote-new-tab-location-changed data should be new URL.");
resolve();
}, "remote-new-tab-location-changed", false);
});
}

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

@ -0,0 +1,375 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// See also browser/base/content/test/newtab/.
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Cu.import("resource:///modules/RemoteNewTabUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function run_test() {
run_next_test();
}
add_task(function validCacheMidPopulation() {
let expectedLinks = makeLinks(0, 3, 1);
let provider = new TestProvider(done => done(expectedLinks));
provider.maxNumLinks = expectedLinks.length;
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
let promise = new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
// isTopSiteGivenProvider() and getProviderLinks() should still return results
// even when cache is empty or being populated.
do_check_false(RemoteNewTabUtils.isTopSiteGivenProvider("example1.com", provider));
do_check_links(RemoteNewTabUtils.getProviderLinks(provider), []);
yield promise;
// Once the cache is populated, we get the expected results
do_check_true(RemoteNewTabUtils.isTopSiteGivenProvider("example1.com", provider));
do_check_links(RemoteNewTabUtils.getProviderLinks(provider), expectedLinks);
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function notifyLinkDelete() {
let expectedLinks = makeLinks(0, 3, 1);
let provider = new TestProvider(done => done(expectedLinks));
provider.maxNumLinks = expectedLinks.length;
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Remove a link.
let removedLink = expectedLinks[2];
provider.notifyLinkChanged(removedLink, 2, true);
let links = RemoteNewTabUtils.links._providers.get(provider);
// Check that sortedLinks is correctly updated.
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks.slice(0, 2));
// Check that linkMap is accurately updated.
do_check_eq(links.linkMap.size, 2);
do_check_true(links.linkMap.get(expectedLinks[0].url));
do_check_true(links.linkMap.get(expectedLinks[1].url));
do_check_false(links.linkMap.get(removedLink.url));
// Check that siteMap is correctly updated.
do_check_eq(links.siteMap.size, 2);
do_check_true(links.siteMap.has(RemoteNewTabUtils.extractSite(expectedLinks[0].url)));
do_check_true(links.siteMap.has(RemoteNewTabUtils.extractSite(expectedLinks[1].url)));
do_check_false(links.siteMap.has(RemoteNewTabUtils.extractSite(removedLink.url)));
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function populatePromise() {
let count = 0;
let expectedLinks = makeLinks(0, 10, 2);
let getLinksFcn = Task.async(function* (callback) {
//Should not be calling getLinksFcn twice
count++;
do_check_eq(count, 1);
yield Promise.resolve();
callback(expectedLinks);
});
let provider = new TestProvider(getLinksFcn);
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
RemoteNewTabUtils.links.populateProviderCache(provider, () => {});
RemoteNewTabUtils.links.populateProviderCache(provider, () => {
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
RemoteNewTabUtils.links.removeProvider(provider);
});
});
add_task(function isTopSiteGivenProvider() {
let expectedLinks = makeLinks(0, 10, 2);
// The lowest 2 frecencies have the same base domain.
expectedLinks[expectedLinks.length - 2].url = expectedLinks[expectedLinks.length - 1].url + "Test";
let provider = new TestProvider(done => done(expectedLinks));
provider.maxNumLinks = expectedLinks.length;
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example2.com", provider), true);
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example1.com", provider), false);
// Push out frecency 2 because the maxNumLinks is reached when adding frecency 3
let newLink = makeLink(3);
provider.notifyLinkChanged(newLink);
// There is still a frecent url with example2 domain, so it's still frecent.
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example3.com", provider), true);
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example2.com", provider), true);
// Push out frecency 3
newLink = makeLink(5);
provider.notifyLinkChanged(newLink);
// Push out frecency 4
newLink = makeLink(9);
provider.notifyLinkChanged(newLink);
// Our count reached 0 for the example2.com domain so it's no longer a frecent site.
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example5.com", provider), true);
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example2.com", provider), false);
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function multipleProviders() {
// Make each provider generate RemoteNewTabUtils.links.maxNumLinks links to check
// that no more than maxNumLinks are actually returned in the merged list.
let evenLinks = makeLinks(0, 2 * RemoteNewTabUtils.links.maxNumLinks, 2);
let evenProvider = new TestProvider(done => done(evenLinks));
let oddLinks = makeLinks(0, 2 * RemoteNewTabUtils.links.maxNumLinks - 1, 2);
let oddProvider = new TestProvider(done => done(oddLinks));
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(evenProvider);
RemoteNewTabUtils.links.addProvider(oddProvider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
let links = RemoteNewTabUtils.links.getLinks();
let expectedLinks = makeLinks(RemoteNewTabUtils.links.maxNumLinks,
2 * RemoteNewTabUtils.links.maxNumLinks,
1);
do_check_eq(links.length, RemoteNewTabUtils.links.maxNumLinks);
do_check_links(links, expectedLinks);
RemoteNewTabUtils.links.removeProvider(evenProvider);
RemoteNewTabUtils.links.removeProvider(oddProvider);
});
add_task(function changeLinks() {
let expectedLinks = makeLinks(0, 20, 2);
let provider = new TestProvider(done => done(expectedLinks));
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of a new link.
let newLink = makeLink(19);
expectedLinks.splice(1, 0, newLink);
provider.notifyLinkChanged(newLink);
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of a link that's changed sort criteria.
newLink.frecency = 17;
expectedLinks.splice(1, 1);
expectedLinks.splice(2, 0, newLink);
provider.notifyLinkChanged({
url: newLink.url,
frecency: 17,
});
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of a link that's changed title.
newLink.title = "My frecency is now 17";
provider.notifyLinkChanged({
url: newLink.url,
title: newLink.title,
});
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of a new link again, but this time make it overflow maxNumLinks.
provider.maxNumLinks = expectedLinks.length;
newLink = makeLink(21);
expectedLinks.unshift(newLink);
expectedLinks.pop();
do_check_eq(expectedLinks.length, provider.maxNumLinks); // Sanity check.
provider.notifyLinkChanged(newLink);
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of many links changed.
expectedLinks = makeLinks(0, 3, 1);
provider.notifyManyLinksChanged();
// Since _populateProviderCache() is async, we must wait until the provider's
// populate promise has been resolved.
yield RemoteNewTabUtils.links._providers.get(provider).populatePromise;
// RemoteNewTabUtils.links will now repopulate its cache
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function oneProviderAlreadyCached() {
let links1 = makeLinks(0, 10, 1);
let provider1 = new TestProvider(done => done(links1));
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider1);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), links1);
let links2 = makeLinks(10, 20, 1);
let provider2 = new TestProvider(done => done(links2));
RemoteNewTabUtils.links.addProvider(provider2);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), links2.concat(links1));
RemoteNewTabUtils.links.removeProvider(provider1);
RemoteNewTabUtils.links.removeProvider(provider2);
});
add_task(function newLowRankedLink() {
// Init a provider with 10 links and make its maximum number also 10.
let links = makeLinks(0, 10, 1);
let provider = new TestProvider(done => done(links));
provider.maxNumLinks = links.length;
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), links);
// Notify of a new link that's low-ranked enough not to make the list.
let newLink = makeLink(0);
provider.notifyLinkChanged(newLink);
do_check_links(RemoteNewTabUtils.links.getLinks(), links);
// Notify about the new link's title change.
provider.notifyLinkChanged({
url: newLink.url,
title: "a new title",
});
do_check_links(RemoteNewTabUtils.links.getLinks(), links);
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function extractSite() {
// All these should extract to the same site
[ "mozilla.org",
"m.mozilla.org",
"mobile.mozilla.org",
"www.mozilla.org",
"www3.mozilla.org",
].forEach(host => {
let url = "http://" + host;
do_check_eq(RemoteNewTabUtils.extractSite(url), "mozilla.org", "extracted same " + host);
});
// All these should extract to the same subdomain
[ "bugzilla.mozilla.org",
"www.bugzilla.mozilla.org",
].forEach(host => {
let url = "http://" + host;
do_check_eq(RemoteNewTabUtils.extractSite(url), "bugzilla.mozilla.org", "extracted eTLD+2 " + host);
});
// All these should not extract to the same site
[ "bugzilla.mozilla.org",
"bug123.bugzilla.mozilla.org",
"too.many.levels.bugzilla.mozilla.org",
"m2.mozilla.org",
"mobile30.mozilla.org",
"ww.mozilla.org",
"ww2.mozilla.org",
"wwwww.mozilla.org",
"wwwww50.mozilla.org",
"wwws.mozilla.org",
"secure.mozilla.org",
"secure10.mozilla.org",
"many.levels.deep.mozilla.org",
"just.check.in",
"192.168.0.1",
"localhost",
].forEach(host => {
let url = "http://" + host;
do_check_neq(RemoteNewTabUtils.extractSite(url), "mozilla.org", "extracted diff " + host);
});
// All these should not extract to the same site
[ "about:blank",
"file:///Users/user/file",
"chrome://browser/something",
"ftp://ftp.mozilla.org/",
].forEach(url => {
do_check_neq(RemoteNewTabUtils.extractSite(url), "mozilla.org", "extracted diff url " + url);
});
});
function TestProvider(getLinksFn) {
this.getLinks = getLinksFn;
this._observers = new Set();
}
TestProvider.prototype = {
addObserver: function (observer) {
this._observers.add(observer);
},
notifyLinkChanged: function (link, index=-1, deleted=false) {
this._notifyObservers("onLinkChanged", link, index, deleted);
},
notifyManyLinksChanged: function () {
this._notifyObservers("onManyLinksChanged");
},
_notifyObservers: function () {
let observerMethodName = arguments[0];
let args = Array.prototype.slice.call(arguments, 1);
args.unshift(this);
for (let obs of this._observers) {
if (obs[observerMethodName])
obs[observerMethodName].apply(RemoteNewTabUtils.links, args);
}
},
};
function do_check_links(actualLinks, expectedLinks) {
do_check_true(Array.isArray(actualLinks));
do_check_eq(actualLinks.length, expectedLinks.length);
for (let i = 0; i < expectedLinks.length; i++) {
let expected = expectedLinks[i];
let actual = actualLinks[i];
do_check_eq(actual.url, expected.url);
do_check_eq(actual.title, expected.title);
do_check_eq(actual.frecency, expected.frecency);
do_check_eq(actual.lastVisitDate, expected.lastVisitDate);
}
}
function makeLinks(frecRangeStart, frecRangeEnd, step) {
let links = [];
// Remember, links are ordered by frecency descending.
for (let i = frecRangeEnd; i > frecRangeStart; i -= step) {
links.push(makeLink(i));
}
return links;
}
function makeLink(frecency) {
return {
url: "http://example" + frecency + ".com/",
title: "My frecency is " + frecency,
frecency: frecency,
lastVisitDate: 0,
};
}

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

@ -0,0 +1,11 @@
[DEFAULT]
head =
tail =
firefox-appdir = browser
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_NewTabURL.js]
[test_PlacesProvider.js]
[test_RemoteDirectoryLinksProvider.js]
[test_RemoteNewTabLocation.js]
[test_RemoteNewTabUtils.js]

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

@ -20,6 +20,21 @@ XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
XPCOMUtils.defineLazyModuleGetter(this, "AboutNewTab",
"resource:///modules/AboutNewTab.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DirectoryLinksProvider",
"resource:///modules/DirectoryLinksProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteAboutNewTab",
"resource:///modules/RemoteAboutNewTab.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteDirectoryLinksProvider",
"resource:///modules/RemoteDirectoryLinksProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabUtils",
"resource:///modules/RemoteNewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
"resource:///modules/UITour.jsm");
@ -29,9 +44,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
XPCOMUtils.defineLazyModuleGetter(this, "ContentClick",
"resource:///modules/ContentClick.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DirectoryLinksProvider",
"resource:///modules/DirectoryLinksProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
@ -53,9 +65,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebappManager",
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource://gre/modules/PageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
"resource:///modules/CustomizationTabPreloader.jsm");
@ -591,7 +600,7 @@ BrowserGlue.prototype = {
}
},
// initialization (called on application startup)
// initialization (called on application startup)
_init: function BG__init() {
let os = Services.obs;
os.addObserver(this, "notifications-open-settings", false);
@ -811,7 +820,7 @@ BrowserGlue.prototype = {
this._sanitizer.onStartup();
// check if we're in safe mode
if (Services.appinfo.inSafeMode) {
Services.ww.openWindow(null, "chrome://browser/content/safeMode.xul",
Services.ww.openWindow(null, "chrome://browser/content/safeMode.xul",
"_blank", "chrome,centerscreen,modal,resizable=no", null);
}
@ -826,9 +835,6 @@ BrowserGlue.prototype = {
WebappManager.init();
PageThumbs.init();
NewTabUtils.init();
DirectoryLinksProvider.init();
NewTabUtils.links.addProvider(DirectoryLinksProvider);
#ifdef NIGHTLY_BUILD
if (Services.prefs.getBoolPref("dom.identity.enabled")) {
SignInToWebsiteUX.init();
@ -836,7 +842,17 @@ BrowserGlue.prototype = {
#endif
webrtcUI.init();
AboutHome.init();
RemoteDirectoryLinksProvider.init();
RemoteNewTabUtils.init();
RemoteNewTabUtils.links.addProvider(RemoteDirectoryLinksProvider);
RemoteAboutNewTab.init();
DirectoryLinksProvider.init();
NewTabUtils.init();
NewTabUtils.links.addProvider(DirectoryLinksProvider);
AboutNewTab.init();
SessionStore.init();
BrowserUITelemetry.init();
ContentSearch.init();
@ -1161,6 +1177,8 @@ BrowserGlue.prototype = {
CustomizationTabPreloader.uninit();
WebappManager.uninit();
RemoteAboutNewTab.uninit();
AboutNewTab.uninit();
#ifdef NIGHTLY_BUILD
if (Services.prefs.getBoolPref("dom.identity.enabled")) {
@ -2043,7 +2061,7 @@ BrowserGlue.prototype = {
}
if (currentUIVersion < 19) {
let detector = null;
let detector = null;
try {
detector = Services.prefs.getComplexValue("intl.charset.detector",
Ci.nsIPrefLocalizedString).data;
@ -2205,7 +2223,7 @@ BrowserGlue.prototype = {
Services.prefs.clearUserPref("browser.devedition.showCustomizeButton");
}
if (currentUIVersion < 31) {
xulStore.removeValue(BROWSER_DOCURL, "bookmarks-menu-button", "class");
xulStore.removeValue(BROWSER_DOCURL, "home-button", "class");

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

@ -30,7 +30,6 @@ EXTRA_JS_MODULES += [
'FormValidationHandler.jsm',
'HiddenFrame.jsm',
'NetworkPrioritizer.jsm',
'NewTabURL.jsm',
'offlineAppCache.jsm',
'PanelFrame.jsm',
'PluginContent.jsm',

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

@ -5,5 +5,4 @@ firefox-appdir = browser
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_DirectoryLinksProvider.js]
[test_NewTabURL.js]
[test_SitePermissions.js]

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

@ -21,15 +21,15 @@
:root {
--backbutton-urlbar-overlap: 6px;
--toolbarbutton-hover-background: hsla(0,0%,100%,.3) linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.2));
--toolbarbutton-hover-boxshadow: 0 1px 0 hsla(0,0%,100%,.3) inset, 0 0 0 1px hsla(0,0%,100%,.2) inset, 0 1px 0 hsla(0,0%,0%,.03);
--toolbarbutton-hover-bordercolor: rgb(154,154,154);
--toolbarbutton-hover-background: rgba(255,255,255,.5) linear-gradient(rgba(255,255,255,.5), transparent);
--toolbarbutton-hover-bordercolor: rgba(0,0,0,.25);
--toolbarbutton-hover-boxshadow: none;
--toolbarbutton-active-boxshadow: 0 1px 1px hsla(0,0%,0%,.1) inset, 0 0 1px hsla(0,0%,0%,.3) inset;
--toolbarbutton-active-bordercolor: rgb(154,154,154);
--toolbarbutton-active-background: rgba(154,154,154,.5) linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.4));
--toolbarbutton-active-background: rgba(154,154,154,.5) linear-gradient(rgba(255,255,255,.7), rgba(255,255,255,.4));
--toolbarbutton-active-bordercolor: rgba(0,0,0,.3);
--toolbarbutton-active-boxshadow: 0 1px 1px rgba(0,0,0,.1) inset, 0 0 1px rgba(0,0,0,.3) inset;
--toolbarbutton-checkedhover-backgroundcolor: rgba(154,154,154,.15);
--toolbarbutton-checkedhover-backgroundcolor: rgba(200,200,200,.5);
--identity-box-verified-background-color: #fff;
@ -626,8 +626,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-badge-stack,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-icon {
background: var(--toolbarbutton-hover-background);
border-width: 1px;
border-style: solid;
background-clip: padding-box;
border-color: var(--toolbarbutton-hover-bordercolor);
box-shadow: var(--toolbarbutton-hover-boxshadow);
}
@ -644,9 +643,8 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon {
background: var(--toolbarbutton-active-background);
background-clip: padding-box;
box-shadow: var(--toolbarbutton-active-boxshadow);
border-width: 1px;
border-style: solid;
border-color: var(--toolbarbutton-active-bordercolor);
transition-duration: 10ms;
}

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

@ -3244,26 +3244,26 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
bool value;
nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
if (parentAsDocShell) {
if (NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) {
if (mAllowPlugins && NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) {
SetAllowPlugins(value);
}
if (NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) {
if (mAllowJavascript && NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) {
SetAllowJavascript(value);
}
if (NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) {
if (mAllowMetaRedirects && NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) {
SetAllowMetaRedirects(value);
}
if (NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) {
if (mAllowSubframes && NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) {
SetAllowSubframes(value);
}
if (NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))) {
if (mAllowImages && NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))) {
SetAllowImages(value);
}
SetAllowMedia(parentAsDocShell->GetAllowMedia());
if (NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) {
SetAllowMedia(parentAsDocShell->GetAllowMedia() && mAllowMedia);
if (mAllowWindowControl && NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) {
SetAllowWindowControl(value);
}
SetAllowContentRetargeting(
SetAllowContentRetargeting(mAllowContentRetargeting &&
parentAsDocShell->GetAllowContentRetargetingOnChildren());
if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) {
SetIsActive(value);
@ -3274,7 +3274,7 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
value = false;
}
SetAllowDNSPrefetch(value);
SetAllowDNSPrefetch(mAllowDNSPrefetch && value);
value = parentAsDocShell->GetAffectPrivateSessionLifetime();
SetAffectPrivateSessionLifetime(value);
uint32_t flags;

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

@ -723,6 +723,7 @@ GK_ATOM(onconfigurationchange, "onconfigurationchange")
GK_ATOM(onconnect, "onconnect")
GK_ATOM(onconnected, "onconnected")
GK_ATOM(onconnecting, "onconnecting")
GK_ATOM(onconnectionavailable, "onconnectionavailable")
GK_ATOM(onconnectionstatechanged, "onconnectionstatechanged")
GK_ATOM(oncontextmenu, "oncontextmenu")
GK_ATOM(oncopy, "oncopy")
@ -898,8 +899,6 @@ GK_ATOM(onselectionchange, "onselectionchange")
GK_ATOM(onselectstart, "onselectstart")
GK_ATOM(onsending, "onsending")
GK_ATOM(onsent, "onsent")
GK_ATOM(onsessionavailable, "onsessionavailable")
GK_ATOM(onsessionconnect, "onsessionconnect")
GK_ATOM(onset, "onset")
GK_ATOM(onshow, "onshow")
GK_ATOM(onshutter, "onshutter")

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

@ -7,10 +7,11 @@ var LB;
function run_test() {
if(("@mozilla.org/windows-registry-key;1" in C) || ("nsILocalFileOS2" in I))
if (mozinfo.os == "win") {
LB = "\r\n";
else
} else {
LB = "\n";
}
for (var i = 0; i < tests.length && tests[i]; ++i) {
tests[i].call();

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

@ -183,7 +183,7 @@ ContentBridgeParent::GetCPOWManager()
if (ManagedPJavaScriptParent().Length()) {
return CPOWManagerFor(ManagedPJavaScriptParent()[0]);
}
return CPOWManagerFor(SendPJavaScriptConstructor());
return nullptr;
}
NS_IMETHODIMP

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

@ -41,6 +41,8 @@ parent:
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (StructuredCloneData[] retval);
async PJavaScript();
both:
// Both the parent and the child can construct the PBrowser.
// See the comment in PContent::PBrowser().
@ -49,8 +51,6 @@ both:
async PBlob(BlobConstructorParams params);
async PJavaScript();
AsyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal);
};

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

@ -54,8 +54,6 @@ public:
virtual bool OnStateMachineTaskQueue() const = 0;
virtual bool OnDecodeTaskQueue() const = 0;
// Get the current MediaResource being used. Its URI will be returned
// by currentSrc. Returns what was passed to Load(), if Load() has been called.
virtual MediaResource* GetResource() const = 0;
@ -124,10 +122,6 @@ public:
// Called from HTMLMediaElement when owner document activity changes
virtual void SetElementVisibility(bool aIsVisible) {}
// Called by some MediaDecoderReader to determine if we can rely
// on the resource length to limit reads.
virtual bool HasInitializationData() { return false; }
// Stack based class to assist in notifying the frame statistics of
// parsed and decoded frames. Use inside video demux & decode functions
// to ensure all parsed and decoded frames are reported on all return paths.

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

@ -1238,12 +1238,6 @@ MediaDecoder::SetPreservesPitch(bool aPreservesPitch)
mPreservesPitch = aPreservesPitch;
}
bool
MediaDecoder::OnDecodeTaskQueue() const {
NS_WARN_IF_FALSE(mDecoderStateMachine, "mDecoderStateMachine is null");
return mDecoderStateMachine ? mDecoderStateMachine->OnDecodeTaskQueue() : false;
}
void
MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine)
{

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

@ -519,8 +519,6 @@ public:
bool OnStateMachineTaskQueue() const override;
bool OnDecodeTaskQueue() const override;
MediaDecoderStateMachine* GetStateMachine() const;
void SetStateMachine(MediaDecoderStateMachine* aStateMachine);

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

@ -2864,11 +2864,6 @@ MediaDecoderStateMachine::ScheduleStateMachineIn(int64_t aMicroseconds)
mDelayedScheduler.Ensure(target);
}
bool MediaDecoderStateMachine::OnDecodeTaskQueue() const
{
return !DecodeTaskQueue() || DecodeTaskQueue()->IsCurrentThreadIn();
}
bool MediaDecoderStateMachine::OnTaskQueue() const
{
return OwnerThread()->IsCurrentThreadIn();

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

@ -235,8 +235,6 @@ public:
// Functions used by assertions to ensure we're calling things
// on the appropriate threads.
bool OnDecodeTaskQueue() const;
bool OnTaskQueue() const;
size_t SizeOfVideoQueue() {

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

@ -98,18 +98,17 @@ MP4Decoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
// etc output).
const bool isMP4Audio = aMIMETypeExcludingCodecs.EqualsASCII("audio/mp4") ||
aMIMETypeExcludingCodecs.EqualsASCII("audio/x-m4a");
const bool isMP4Video = aMIMETypeExcludingCodecs.EqualsASCII("video/mp4") ||
aMIMETypeExcludingCodecs.EqualsASCII("video/x-m4v");
const bool isMP4Video =
// On B2G, treat 3GPP as MP4 when Gonk PDM is available.
#ifdef MOZ_GONK_MEDIACODEC
aMIMETypeExcludingCodecs.EqualsASCII(VIDEO_3GPP) ||
#endif
aMIMETypeExcludingCodecs.EqualsASCII("video/mp4") ||
aMIMETypeExcludingCodecs.EqualsASCII("video/x-m4v");
if (!isMP4Audio && !isMP4Video) {
return false;
}
#ifdef MOZ_GONK_MEDIACODEC
if (aMIMETypeExcludingCodecs.EqualsASCII(VIDEO_3GPP)) {
return Preferences::GetBool("media.fragmented-mp4.gonk.enabled", false);
}
#endif
nsTArray<nsCString> codecMimes;
if (aCodecs.IsEmpty()) {
// No codecs specified. Assume AAC/H.264

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

@ -38,7 +38,7 @@ struct AudioTimelineEvent final
};
AudioTimelineEvent(Type aType, double aTime, float aValue, double aTimeConstant = 0.0,
float aDuration = 0.0, const float* aCurve = nullptr,
double aDuration = 0.0, const float* aCurve = nullptr,
uint32_t aCurveLength = 0)
: mType(aType)
, mTimeConstant(aTimeConstant)
@ -209,6 +209,8 @@ public:
// curve event.
for (unsigned i = 0; i < mEvents.Length(); ++i) {
if (mEvents[i].mType == AudioTimelineEvent::SetValueCurve &&
!(aEvent.mType == AudioTimelineEvent::SetValueCurve &&
aEvent.template Time<double>() == mEvents[i].template Time<double>()) &&
mEvents[i].template Time<double>() <= aEvent.template Time<double>() &&
(mEvents[i].template Time<double>() + mEvents[i].mDuration) >= aEvent.template Time<double>()) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
@ -220,6 +222,11 @@ public:
// events.
if (aEvent.mType == AudioTimelineEvent::SetValueCurve) {
for (unsigned i = 0; i < mEvents.Length(); ++i) {
// In case we have two curve at the same time
if (mEvents[i].mType == AudioTimelineEvent::SetValueCurve &&
mEvents[i].template Time<double>() == aEvent.template Time<double>()) {
continue;
}
if (mEvents[i].template Time<double>() > aEvent.template Time<double>() &&
mEvents[i].template Time<double>() < (aEvent.template Time<double>() + aEvent.mDuration)) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);

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

@ -40,13 +40,6 @@ BufferDecoder::OnStateMachineTaskQueue() const
return true;
}
bool
BufferDecoder::OnDecodeTaskQueue() const
{
MOZ_ASSERT(mTaskQueueIdentity, "Forgot to call BeginDecoding?");
return mTaskQueueIdentity->IsCurrentThreadIn();
}
MediaResource*
BufferDecoder::GetResource() const
{

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

@ -33,8 +33,6 @@ public:
virtual bool OnStateMachineTaskQueue() const final override;
virtual bool OnDecodeTaskQueue() const final override;
virtual MediaResource* GetResource() const final override;
virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) final override;

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

@ -145,7 +145,8 @@ void TestSpecExample()
is(timeline.GetValueAtTime(0.6), 0.75f, "Correct value");
is(timeline.GetValueAtTime(0.65), (0.75f * powf(0.05f / 0.75f, 0.5f)), "Correct value");
is(timeline.GetValueAtTime(0.7), -1.0f, "Correct value");
is(timeline.GetValueAtTime(0.9), 0.0f, "Correct value");
is(timeline.GetValueAtTime(0.8), 0.0f, "Correct value");
is(timeline.GetValueAtTime(0.9), 1.0f, "Correct value");
is(timeline.GetValueAtTime(1.0), 1.0f, "Correct value");
}
@ -431,6 +432,19 @@ void TestExponentialInvalidPreviousZeroValue()
is(rv, NS_OK, "Should succeed this time");
}
void
TestSettingValueCurveTwice()
{
Timeline timeline(0.f);
float curve[] = { -1.0f, 0.0f, 1.0f };
ErrorResultMock rv;
timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 0.0f, 0.3f, rv);
timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 0.0f, 0.3f, rv);
is(rv, NS_OK, "SetValueCurveAtTime succeeded");
}
int main()
{
ScopedXPCOM xpcom("TestAudioEventTimeline");
@ -456,6 +470,7 @@ int main()
TestExponentialRampAtSameTime();
TestSetTargetZeroTimeConstant();
TestExponentialInvalidPreviousZeroValue();
TestSettingValueCurveTwice();
return gFailCount > 0;
}

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

@ -57,6 +57,7 @@ tags=capturestream
[test_audioParamGain.html]
[test_audioParamLinearRamp.html]
[test_audioParamSetCurveAtTime.html]
[test_audioParamSetCurveAtTimeTwice.html]
[test_audioParamSetCurveAtTimeZeroDuration.html]
[test_audioParamSetTargetAtTime.html]
[test_audioParamSetValueAtTime.html]

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

@ -0,0 +1,62 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test AudioParam.linearRampToValue</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var T0 = 0;
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
sourceBuffer.getChannelData(0)[i] = 1;
}
var curve2 = new Float32Array(100);
for (var i = 0; i < 100; ++i) {
curve2[i] = Math.sin(220 * 6 * Math.PI * i / context.sampleRate);
}
var source = context.createBufferSource();
source.buffer = sourceBuffer;
var gain = context.createGain();
gain.gain.setValueCurveAtTime(curve2, T0, this.duration/2);
//Set a diffrent curve from the first one
gain.gain.setValueCurveAtTime(this.curve, T0, this.duration);
source.connect(gain);
source.start(0);
return gain;
},
createExpectedBuffers: function(context) {
this.duration = 1024 / context.sampleRate;
this.curve = new Float32Array(100);
for (var i = 0; i < 100; ++i) {
this.curve[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
var t = i / context.sampleRate;
expectedBuffer.getChannelData(0)[i] = this.curve[Math.min(99, Math.floor(100 * Math.min(1.0, (t - T0) / this.duration)))];
}
return expectedBuffer;
},
};
runTest();
</script>
</pre>
</body>
</html>

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

@ -248,19 +248,14 @@ WebMReader::AsyncReadMetadata()
nsresult
WebMReader::RetrieveWebMMetadata(MediaInfo* aInfo)
{
// We can't use OnTaskQueue() here because of the wacky initialization task
// queue that TrackBuffer uses. We should be able to fix this when we do
// bug 1148234.
MOZ_ASSERT(mDecoder->OnDecodeTaskQueue());
MOZ_ASSERT(OnTaskQueue());
nestegg_io io;
io.read = webm_read;
io.seek = webm_seek;
io.tell = webm_tell;
io.userdata = &mResource;
int64_t maxOffset = mDecoder->HasInitializationData() ?
mBufferedState->GetInitEndOffset() : -1;
int r = nestegg_init(&mContext, io, &webm_log, maxOffset);
int r = nestegg_init(&mContext, io, &webm_log, -1);
if (r == -1) {
return NS_ERROR_FAILURE;
}

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

@ -7,10 +7,9 @@ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Promise.jsm");
const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
const gIsOSX = ("nsILocalFileMac" in Ci);
const gIsLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc) ||
("@mozilla.org/gio-service;1" in Cc);
const gIsWindows = mozinfo.os == "win";
const gIsOSX = mozinfo.os == "mac";
const gIsLinux = mozinfo.os == "linux";
const gDirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
// Finds the test plugin library

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

@ -6,9 +6,7 @@
Components.utils.import("resource://gre/modules/Services.jsm");
// Plugin registry uses different field delimeters on different platforms
var DELIM = ":";
if ("@mozilla.org/windows-registry-key;1" in Components.classes)
DELIM = "|";
var DELIM = mozinfo.os == "win" ? "|" : ":";
var gProfD = do_get_profile_startup();

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

@ -6,9 +6,7 @@
Components.utils.import("resource://gre/modules/Services.jsm");
// Plugin registry uses different field delimeters on different platforms
var DELIM = ":";
if ("@mozilla.org/windows-registry-key;1" in Components.classes)
DELIM = "|";
var DELIM = mozinfo.os == "win" ? "|" : ":";
var gProfD = do_get_profile_startup();

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

@ -6,9 +6,7 @@
Components.utils.import("resource://gre/modules/Services.jsm");
// Plugin registry uses different field delimeters on different platforms
var DELIM = ":";
if ("@mozilla.org/windows-registry-key;1" in Components.classes)
DELIM = "|";
var DELIM = mozinfo.os == "win" ? "|" : ":";
var gProfD = do_get_profile_startup();

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

@ -12,7 +12,7 @@
#include "nsServiceManagerUtils.h"
#include "PresentationCallbacks.h"
#include "PresentationRequest.h"
#include "PresentationSession.h"
#include "PresentationConnection.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -47,18 +47,18 @@ PresentationRequesterCallback::NotifySuccess()
MOZ_ASSERT(NS_IsMainThread());
// At the sender side, this function must get called after the transport
// channel is ready. So we simply set the session state as connected.
nsRefPtr<PresentationSession> session =
PresentationSession::Create(mRequest->GetOwner(), mSessionId,
PresentationSessionState::Connected);
if (NS_WARN_IF(!session)) {
// channel is ready. So we simply set the connection state as connected.
nsRefPtr<PresentationConnection> connection =
PresentationConnection::Create(mRequest->GetOwner(), mSessionId,
PresentationConnectionState::Connected);
if (NS_WARN_IF(!connection)) {
mPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
return NS_OK;
}
mPromise->MaybeResolve(session);
mPromise->MaybeResolve(connection);
return mRequest->DispatchSessionConnectEvent(session);
return mRequest->DispatchConnectionAvailableEvent(connection);
}
NS_IMETHODIMP

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

@ -10,52 +10,52 @@
#include "nsIPresentationService.h"
#include "nsServiceManagerUtils.h"
#include "nsStringStream.h"
#include "PresentationSession.h"
#include "PresentationConnection.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationSession)
NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationConnection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationSession, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationConnection, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationSession, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationConnection, DOMEventTargetHelper)
tmp->Shutdown();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(PresentationSession, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(PresentationSession, DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(PresentationConnection, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(PresentationConnection, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationSession)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationConnection)
NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionListener)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
PresentationSession::PresentationSession(nsPIDOMWindow* aWindow,
const nsAString& aId,
PresentationSessionState aState)
PresentationConnection::PresentationConnection(nsPIDOMWindow* aWindow,
const nsAString& aId,
PresentationConnectionState aState)
: DOMEventTargetHelper(aWindow)
, mId(aId)
, mState(aState)
{
}
/* virtual */ PresentationSession::~PresentationSession()
/* virtual */ PresentationConnection::~PresentationConnection()
{
}
/* static */ already_AddRefed<PresentationSession>
PresentationSession::Create(nsPIDOMWindow* aWindow,
const nsAString& aId,
PresentationSessionState aState)
/* static */ already_AddRefed<PresentationConnection>
PresentationConnection::Create(nsPIDOMWindow* aWindow,
const nsAString& aId,
PresentationConnectionState aState)
{
nsRefPtr<PresentationSession> session =
new PresentationSession(aWindow, aId, aState);
return NS_WARN_IF(!session->Init()) ? nullptr : session.forget();
nsRefPtr<PresentationConnection> connection =
new PresentationConnection(aWindow, aId, aState);
return NS_WARN_IF(!connection->Init()) ? nullptr : connection.forget();
}
bool
PresentationSession::Init()
PresentationConnection::Init()
{
if (NS_WARN_IF(mId.IsEmpty())) {
return false;
@ -76,7 +76,7 @@ PresentationSession::Init()
}
void
PresentationSession::Shutdown()
PresentationConnection::Shutdown()
{
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
@ -89,37 +89,37 @@ PresentationSession::Shutdown()
}
/* virtual */ void
PresentationSession::DisconnectFromOwner()
PresentationConnection::DisconnectFromOwner()
{
Shutdown();
DOMEventTargetHelper::DisconnectFromOwner();
}
/* virtual */ JSObject*
PresentationSession::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto)
PresentationConnection::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto)
{
return PresentationSessionBinding::Wrap(aCx, this, aGivenProto);
return PresentationConnectionBinding::Wrap(aCx, this, aGivenProto);
}
void
PresentationSession::GetId(nsAString& aId) const
PresentationConnection::GetId(nsAString& aId) const
{
aId = mId;
}
PresentationSessionState
PresentationSession::State() const
PresentationConnectionState
PresentationConnection::State() const
{
return mState;
}
void
PresentationSession::Send(const nsAString& aData,
PresentationConnection::Send(const nsAString& aData,
ErrorResult& aRv)
{
// Sending is not allowed if the session is not connected.
if (NS_WARN_IF(mState != PresentationSessionState::Connected)) {
if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
@ -153,10 +153,10 @@ PresentationSession::Send(const nsAString& aData,
}
void
PresentationSession::Close(ErrorResult& aRv)
PresentationConnection::Close(ErrorResult& aRv)
{
// It only works when the state is CONNECTED.
if (NS_WARN_IF(mState != PresentationSessionState::Connected)) {
if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
return;
}
@ -165,10 +165,10 @@ PresentationSession::Close(ErrorResult& aRv)
}
void
PresentationSession::Terminate(ErrorResult& aRv)
PresentationConnection::Terminate(ErrorResult& aRv)
{
// It only works when the state is CONNECTED.
if (NS_WARN_IF(mState != PresentationSessionState::Connected)) {
if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
return;
}
@ -183,23 +183,23 @@ PresentationSession::Terminate(ErrorResult& aRv)
}
NS_IMETHODIMP
PresentationSession::NotifyStateChange(const nsAString& aSessionId,
PresentationConnection::NotifyStateChange(const nsAString& aSessionId,
uint16_t aState)
{
if (!aSessionId.Equals(mId)) {
return NS_ERROR_INVALID_ARG;
}
PresentationSessionState state;
PresentationConnectionState state;
switch (aState) {
case nsIPresentationSessionListener::STATE_CONNECTED:
state = PresentationSessionState::Connected;
state = PresentationConnectionState::Connected;
break;
case nsIPresentationSessionListener::STATE_CLOSED:
state = PresentationSessionState::Closed;
state = PresentationConnectionState::Closed;
break;
case nsIPresentationSessionListener::STATE_TERMINATED:
state = PresentationSessionState::Terminated;
state = PresentationConnectionState::Terminated;
break;
default:
NS_WARNING("Unknown presentation session state.");
@ -213,7 +213,7 @@ PresentationSession::NotifyStateChange(const nsAString& aSessionId,
mState = state;
// Unregister session listener if the session is no longer connected.
if (mState == PresentationSessionState::Terminated) {
if (mState == PresentationConnectionState::Terminated) {
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if (NS_WARN_IF(!service)) {
@ -230,7 +230,7 @@ PresentationSession::NotifyStateChange(const nsAString& aSessionId,
}
NS_IMETHODIMP
PresentationSession::NotifyMessage(const nsAString& aSessionId,
PresentationConnection::NotifyMessage(const nsAString& aSessionId,
const nsACString& aData)
{
if (!aSessionId.Equals(mId)) {
@ -238,7 +238,7 @@ PresentationSession::NotifyMessage(const nsAString& aSessionId,
}
// No message should be expected when the session is not connected.
if (NS_WARN_IF(mState != PresentationSessionState::Connected)) {
if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
@ -258,7 +258,7 @@ PresentationSession::NotifyMessage(const nsAString& aSessionId,
}
nsresult
PresentationSession::DispatchStateChangeEvent()
PresentationConnection::DispatchStateChangeEvent()
{
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, NS_LITERAL_STRING("statechange"), false);
@ -266,7 +266,7 @@ PresentationSession::DispatchStateChangeEvent()
}
nsresult
PresentationSession::DispatchMessageEvent(JS::Handle<JS::Value> aData)
PresentationConnection::DispatchMessageEvent(JS::Handle<JS::Value> aData)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
if (NS_WARN_IF(!global)) {

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

@ -4,28 +4,28 @@
* 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/. */
#ifndef mozilla_dom_PresentationSession_h
#define mozilla_dom_PresentationSession_h
#ifndef mozilla_dom_PresentationConnection_h
#define mozilla_dom_PresentationConnection_h
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/PresentationSessionBinding.h"
#include "mozilla/dom/PresentationConnectionBinding.h"
#include "nsIPresentationListener.h"
namespace mozilla {
namespace dom {
class PresentationSession final : public DOMEventTargetHelper
, public nsIPresentationSessionListener
class PresentationConnection final : public DOMEventTargetHelper
, public nsIPresentationSessionListener
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationSession,
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationConnection,
DOMEventTargetHelper)
NS_DECL_NSIPRESENTATIONSESSIONLISTENER
static already_AddRefed<PresentationSession> Create(nsPIDOMWindow* aWindow,
const nsAString& aId,
PresentationSessionState aState);
static already_AddRefed<PresentationConnection> Create(nsPIDOMWindow* aWindow,
const nsAString& aId,
PresentationConnectionState aState);
virtual void DisconnectFromOwner() override;
@ -35,7 +35,7 @@ public:
// WebIDL (public APIs)
void GetId(nsAString& aId) const;
PresentationSessionState State() const;
PresentationConnectionState State() const;
void Send(const nsAString& aData,
ErrorResult& aRv);
@ -48,11 +48,11 @@ public:
IMPL_EVENT_HANDLER(message);
private:
PresentationSession(nsPIDOMWindow* aWindow,
const nsAString& aId,
PresentationSessionState aState);
PresentationConnection(nsPIDOMWindow* aWindow,
const nsAString& aId,
PresentationConnectionState aState);
~PresentationSession();
~PresentationConnection();
bool Init();
@ -63,10 +63,10 @@ private:
nsresult DispatchMessageEvent(JS::Handle<JS::Value> aData);
nsString mId;
PresentationSessionState mState;
PresentationConnectionState mState;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PresentationSession_h
#endif // mozilla_dom_PresentationConnection_h

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

@ -11,7 +11,7 @@
#include "nsIPresentationService.h"
#include "nsServiceManagerUtils.h"
#include "PresentationReceiver.h"
#include "PresentationSession.h"
#include "PresentationConnection.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -19,14 +19,14 @@ using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationReceiver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationReceiver, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessions)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingGetSessionPromises)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnections)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingGetConnectionPromises)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationReceiver, DOMEventTargetHelper)
tmp->Shutdown();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessions)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingGetSessionPromises)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConnections)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingGetConnectionPromises)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(PresentationReceiver, DOMEventTargetHelper)
@ -86,8 +86,8 @@ PresentationReceiver::Init(const nsAString& aSessionId)
void PresentationReceiver::Shutdown()
{
mSessions.Clear();
mPendingGetSessionPromises.Clear();
mConnections.Clear();
mPendingGetConnectionPromises.Clear();
// Unregister listener for incoming sessions.
nsCOMPtr<nsIPresentationService> service =
@ -115,7 +115,7 @@ PresentationReceiver::WrapObject(JSContext* aCx,
}
already_AddRefed<Promise>
PresentationReceiver::GetSession(ErrorResult& aRv)
PresentationReceiver::GetConnection(ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
if (NS_WARN_IF(!global)) {
@ -128,20 +128,20 @@ PresentationReceiver::GetSession(ErrorResult& aRv)
return nullptr;
}
// If there's no existing session, leave the promise pending until a
// If there's no existing connection, leave the promise pending until a
// connecting request arrives from the controlling browsing context (sender).
// http://w3c.github.io/presentation-api/#dom-presentation-getsession
if (!mSessions.IsEmpty()) {
promise->MaybeResolve(mSessions[0]);
// http://w3c.github.io/presentation-api/#dom-presentation-getconnection
if (!mConnections.IsEmpty()) {
promise->MaybeResolve(mConnections[0]);
} else {
mPendingGetSessionPromises.AppendElement(promise);
mPendingGetConnectionPromises.AppendElement(promise);
}
return promise.forget();
}
already_AddRefed<Promise>
PresentationReceiver::GetSessions(ErrorResult& aRv) const
PresentationReceiver::GetConnections(ErrorResult& aRv) const
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
if (NS_WARN_IF(!global)) {
@ -154,7 +154,7 @@ PresentationReceiver::GetSessions(ErrorResult& aRv) const
return nullptr;
}
promise->MaybeResolve(mSessions);
promise->MaybeResolve(mConnections);
return promise.forget();
}
@ -166,29 +166,29 @@ PresentationReceiver::NotifySessionConnect(uint64_t aWindowId,
return NS_ERROR_INVALID_ARG;
}
nsRefPtr<PresentationSession> session =
PresentationSession::Create(GetOwner(), aSessionId,
PresentationSessionState::Closed);
if (NS_WARN_IF(!session)) {
nsRefPtr<PresentationConnection> connection =
PresentationConnection::Create(GetOwner(), aSessionId,
PresentationConnectionState::Closed);
if (NS_WARN_IF(!connection)) {
return NS_ERROR_NOT_AVAILABLE;
}
mSessions.AppendElement(session);
mConnections.AppendElement(connection);
// Resolve pending |GetSession| promises if any.
if (!mPendingGetSessionPromises.IsEmpty()) {
for(uint32_t i = 0; i < mPendingGetSessionPromises.Length(); i++) {
mPendingGetSessionPromises[i]->MaybeResolve(session);
// Resolve pending |GetConnection| promises if any.
if (!mPendingGetConnectionPromises.IsEmpty()) {
for(uint32_t i = 0; i < mPendingGetConnectionPromises.Length(); i++) {
mPendingGetConnectionPromises[i]->MaybeResolve(connection);
}
mPendingGetSessionPromises.Clear();
mPendingGetConnectionPromises.Clear();
}
return DispatchSessionAvailableEvent();
return DispatchConnectionAvailableEvent();
}
nsresult
PresentationReceiver::DispatchSessionAvailableEvent()
PresentationReceiver::DispatchConnectionAvailableEvent()
{
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, NS_LITERAL_STRING("sessionavailable"), false);
new AsyncEventDispatcher(this, NS_LITERAL_STRING("connectionavailable"), false);
return asyncDispatcher->PostDOMEvent();
}

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

@ -14,7 +14,7 @@ namespace mozilla {
namespace dom {
class Promise;
class PresentationSession;
class PresentationConnection;
class PresentationReceiver final : public DOMEventTargetHelper
, public nsIPresentationRespondingListener
@ -34,11 +34,11 @@ public:
JS::Handle<JSObject*> aGivenProto) override;
// WebIDL (public APIs)
already_AddRefed<Promise> GetSession(ErrorResult& aRv);
already_AddRefed<Promise> GetConnection(ErrorResult& aRv);
already_AddRefed<Promise> GetSessions(ErrorResult& aRv) const;
already_AddRefed<Promise> GetConnections(ErrorResult& aRv) const;
IMPL_EVENT_HANDLER(sessionavailable);
IMPL_EVENT_HANDLER(connectionavailable);
private:
explicit PresentationReceiver(nsPIDOMWindow* aWindow);
@ -49,14 +49,14 @@ private:
void Shutdown();
nsresult DispatchSessionAvailableEvent();
nsresult DispatchConnectionAvailableEvent();
// Store the inner window ID for |UnregisterRespondingListener| call in
// |Shutdown| since the inner window may not exist at that moment.
uint64_t mWindowId;
nsTArray<nsRefPtr<PresentationSession>> mSessions;
nsTArray<nsRefPtr<Promise>> mPendingGetSessionPromises;
nsTArray<nsRefPtr<PresentationConnection>> mConnections;
nsTArray<nsRefPtr<Promise>> mPendingGetConnectionPromises;
};
} // namespace dom

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

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/PresentationRequestBinding.h"
#include "mozilla/dom/PresentationSessionConnectEvent.h"
#include "mozilla/dom/PresentationConnectionAvailableEvent.h"
#include "mozilla/dom/Promise.h"
#include "mozIThirdPartyUtil.h"
#include "nsCycleCollectionParticipant.h"
@ -151,15 +151,15 @@ PresentationRequest::GetAvailability(ErrorResult& aRv)
}
nsresult
PresentationRequest::DispatchSessionConnectEvent(PresentationSession* aSession)
PresentationRequest::DispatchConnectionAvailableEvent(PresentationConnection* aConnection)
{
PresentationSessionConnectEventInit init;
init.mSession = aSession;
PresentationConnectionAvailableEventInit init;
init.mConnection = aConnection;
nsRefPtr<PresentationSessionConnectEvent> event =
PresentationSessionConnectEvent::Constructor(this,
NS_LITERAL_STRING("sessionconnect"),
init);
nsRefPtr<PresentationConnectionAvailableEvent> event =
PresentationConnectionAvailableEvent::Constructor(this,
NS_LITERAL_STRING("connectionavailable"),
init);
if (NS_WARN_IF(!event)) {
return NS_ERROR_FAILURE;
}

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

@ -14,7 +14,7 @@ namespace dom {
class Promise;
class PresentationAvailability;
class PresentationSession;
class PresentationConnection;
class PresentationRequest final : public DOMEventTargetHelper
{
@ -35,9 +35,9 @@ public:
already_AddRefed<Promise> GetAvailability(ErrorResult& aRv);
IMPL_EVENT_HANDLER(sessionconnect);
IMPL_EVENT_HANDLER(connectionavailable);
nsresult DispatchSessionConnectEvent(PresentationSession* aSession);
nsresult DispatchConnectionAvailableEvent(PresentationConnection* aConnection);
private:
PresentationRequest(nsPIDOMWindow* aWindow,

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

@ -16,11 +16,11 @@ EXPORTS.mozilla.dom += [
'Presentation.h',
'PresentationAvailability.h',
'PresentationCallbacks.h',
'PresentationConnection.h',
'PresentationDeviceManager.h',
'PresentationReceiver.h',
'PresentationRequest.h',
'PresentationService.h',
'PresentationSession.h',
'PresentationSessionInfo.h',
'PresentationSessionTransport.h',
]
@ -32,11 +32,11 @@ UNIFIED_SOURCES += [
'Presentation.cpp',
'PresentationAvailability.cpp',
'PresentationCallbacks.cpp',
'PresentationConnection.cpp',
'PresentationDeviceManager.cpp',
'PresentationReceiver.cpp',
'PresentationRequest.cpp',
'PresentationService.cpp',
'PresentationSession.cpp',
'PresentationSessionInfo.cpp',
'PresentationSessionRequest.cpp',
'PresentationSessionTransport.cpp',

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

@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Session API on a non-receiver page at receiver side (OOP)</title>
<title>Test for B2G PresentationReceiver on a non-receiver page at receiver side (OOP)</title>
</head>
<body>
<div id="content"></div>
@ -26,7 +26,7 @@ function finish() {
alert('DONE');
}
function testSessionAvailable() {
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available in OOP pages.");
ok(!navigator.presentation.receiver, "Non-receiving OOP pages shouldn't get a presentation receiver instance.");
@ -34,7 +34,7 @@ function testSessionAvailable() {
});
}
testSessionAvailable().
testConnectionAvailable().
then(finish);
</script>

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

@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Session API at receiver side</title>
<title>Test for B2G PresentationReceiver at receiver side</title>
</head>
<body>
<div id="content"></div>
@ -30,23 +30,23 @@ function finish() {
window.parent.postMessage('DONE', '*');
}
var session;
var connection;
function testSessionAvailable() {
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available.");
ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available.");
navigator.presentation.receiver.getSession().then(
function(aSession) {
session = aSession;
navigator.presentation.receiver.getConnection().then(
function(aConnection) {
connection = aConnection;
ok(session.id, "Session ID should be set: " + session.id);
is(session.state, "closed", "Session state at receiver side should be closed by default.");
ok(connection.id, "Connection ID should be set: " + connection.id);
is(connection.state, "closed", "Connection state at receiver side should be closed by default.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when getting the session: " + aError);
ok(false, "Error occurred when getting the connection: " + aError);
finish();
aReject();
}
@ -54,11 +54,11 @@ function testSessionAvailable() {
});
}
function testSessionReady() {
function testConnectionReady() {
return new Promise(function(aResolve, aReject) {
session.onstatechange = function() {
session.onstatechange = null;
is(session.state, "connected", "Session state should become connected.");
connection.onstatechange = function() {
connection.onstatechange = null;
is(connection.state, "connected", "Connection state should become connected.");
aResolve();
};
@ -70,8 +70,8 @@ function testIncomingMessage() {
return new Promise(function(aResolve, aReject) {
const incomingMessage = "test incoming message";
session.addEventListener('message', function messageHandler(aEvent) {
session.removeEventListener('message', messageHandler);
connection.addEventListener('message', function messageHandler(aEvent) {
connection.removeEventListener('message', messageHandler);
is(aEvent.data, incomingMessage, "An incoming message should be received.");
aResolve();
});
@ -81,22 +81,22 @@ function testIncomingMessage() {
});
}
function testTerminateSession() {
function testTerminateConnection() {
return new Promise(function(aResolve, aReject) {
session.onstatechange = function() {
session.onstatechange = null;
is(session.state, "terminated", "Session should be terminated.");
connection.onstatechange = function() {
connection.onstatechange = null;
is(connection.state, "terminated", "Connection should be terminated.");
aResolve();
};
session.terminate();
connection.terminate();
});
}
testSessionAvailable().
then(testSessionReady).
testConnectionAvailable().
then(testConnectionReady).
then(testIncomingMessage).
then(testTerminateSession).
then(testTerminateConnection).
then(finish);
</script>

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

@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<title>Test for startSession errors of B2G Presentation API at receiver side</title>
<title>Test for connection establishing errors of B2G Presentation API at receiver side</title>
</head>
<body>
<div id="content"></div>
@ -30,23 +30,23 @@ function finish() {
window.parent.postMessage('DONE', '*');
}
var session;
var connection;
function testSessionAvailable() {
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available.");
ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available.");
navigator.presentation.receiver.getSession().then(
function(aSession) {
session = aSession;
navigator.presentation.receiver.getConnection().then(
function(aConnection) {
connection = aConnection;
ok(session.id, "Session ID should be set: " + session.id);
is(session.state, "closed", "Session state at receiver side should be closed by default.");
ok(connection.id, "Connection ID should be set: " + connection.id);
is(connection.state, "closed", "Connection state at receiver side should be closed by default.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when getting the session: " + aError);
ok(false, "Error occurred when getting the connection: " + aError);
finish();
aReject();
}
@ -56,9 +56,9 @@ function testSessionAvailable() {
function testUnexpectedControlChannelClose() {
return new Promise(function(aResolve, aReject) {
session.onstatechange = function() {
session.onstatechange = null;
is(session.state, "terminated", "Session state should become terminated.");
connection.onstatechange = function() {
connection.onstatechange = null;
is(connection.state, "terminated", "Connection state should become terminated.");
aResolve();
};
@ -67,7 +67,7 @@ function testUnexpectedControlChannelClose() {
});
}
testSessionAvailable().
testConnectionAvailable().
then(testUnexpectedControlChannelClose).
then(finish);

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

@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Session API at receiver side (OOP)</title>
<title>Test for B2G PresentationReceiver at receiver side (OOP)</title>
</head>
<body>
<div id="content"></div>
@ -30,23 +30,23 @@ function finish() {
alert('DONE');
}
var session;
var connection;
function testSessionAvailable() {
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available.");
ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available.");
navigator.presentation.receiver.getSession().then(
function(aSession) {
session = aSession;
navigator.presentation.receiver.getConnection().then(
function(aConnection) {
connection = aConnection;
ok(session.id, "Session ID should be set: " + session.id);
is(session.state, "closed", "Session state at receiver side should be closed by default.");
ok(connection.id, "Connection ID should be set: " + connection.id);
is(connection.state, "closed", "Connection state at receiver side should be closed by default.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when getting the session: " + aError);
ok(false, "Error occurred when getting the connection: " + aError);
finish();
aReject();
}
@ -54,11 +54,11 @@ function testSessionAvailable() {
});
}
function testSessionReady() {
function testConnectionReady() {
return new Promise(function(aResolve, aReject) {
session.onstatechange = function() {
session.onstatechange = null;
is(session.state, "connected", "Session state should become connected.");
connection.onstatechange = function() {
connection.onstatechange = null;
is(connection.state, "connected", "Connection state should become connected.");
aResolve();
};
@ -70,8 +70,8 @@ function testIncomingMessage() {
return new Promise(function(aResolve, aReject) {
const incomingMessage = "test incoming message";
session.addEventListener('message', function messageHandler(aEvent) {
session.removeEventListener('message', messageHandler);
connection.addEventListener('message', function messageHandler(aEvent) {
connection.removeEventListener('message', messageHandler);
is(aEvent.data, incomingMessage, "An incoming message should be received.");
aResolve();
});
@ -81,22 +81,22 @@ function testIncomingMessage() {
});
}
function testTerminateSession() {
function testTerminateConnection() {
return new Promise(function(aResolve, aReject) {
session.onstatechange = function() {
session.onstatechange = null;
is(session.state, "terminated", "Session should be terminated.");
connection.onstatechange = function() {
connection.onstatechange = null;
is(connection.state, "terminated", "Connection should be terminated.");
aResolve();
};
session.terminate();
connection.terminate();
});
}
testSessionAvailable().
then(testSessionReady).
testConnectionAvailable().
then(testConnectionReady).
then(testIncomingMessage).
then(testTerminateSession).
then(testTerminateConnection).
then(finish);
</script>

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

@ -5,21 +5,21 @@ support-files =
file_presentation_receiver.html
file_presentation_receiver_oop.html
file_presentation_non_receiver_oop.html
file_presentation_receiver_start_session_error.html
file_presentation_receiver_establish_connection_error.html
[test_presentation_device_info.html]
[test_presentation_device_info_permission.html]
[test_presentation_sender_disconnect.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_sender_start_session_error.html]
[test_presentation_sender_establish_connection_error.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_sender.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_sender_default_request.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_receiver_start_session_error.html]
[test_presentation_receiver_establish_connection_error.html]
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android' || os == 'mac' || os == 'win' || buildapp == 'mulet') # Bug 1129785, Bug 1204709
[test_presentation_receiver_start_session_timeout.html]
[test_presentation_receiver_establish_connection_timeout.html]
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
[test_presentation_receiver.html]
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785

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

@ -4,12 +4,12 @@
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Session API at receiver side</title>
<title>Test for B2G PresentationConnection API at receiver side</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for B2G Presentation Session API at receiver side</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for B2G PresentationConnection API at receiver side</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>

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

@ -4,22 +4,21 @@
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for startSession errors of B2G Presentation API at receiver side</title>
<title>Test for connection establishing errors of B2G Presentation API at receiver side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for startSession errors of B2G Presentation API at receiver side</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for connection establishing errors of B2G Presentation API at receiver side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver_start_session_error.html');
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver_establish_connection_error.html');
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
var session;
function setup() {
return new Promise(function(aResolve, aReject) {

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

@ -4,12 +4,12 @@
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for startSession timeout of B2G Presentation API at receiver side</title>
<title>Test for connection establishing timeout of B2G Presentation API at receiver side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for startSession timeout of B2G Presentation API at receiver side</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for connection establishing timeout of B2G Presentation API at receiver side</a>
<script type="application/javascript;version=1.8">
'use strict';

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

@ -4,12 +4,12 @@
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Session API at receiver side (OOP)</title>
<title>Test for B2G PresentationConnection API at receiver side (OOP)</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test B2G Presentation Session API at receiver side (OOP)</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test B2G PresentationConnection API at receiver side (OOP)</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>

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

@ -16,7 +16,7 @@
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var request;
var session;
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
@ -41,7 +41,7 @@ function testSetup() {
});
}
function testStartSession() {
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
@ -87,32 +87,32 @@ function testStartSession() {
info("Data notification is enabled for data transport channel.");
});
var sessionFromEvent;
request.onsessionconnect = function(aEvent) {
request.onsessionconnect = null;
sessionFromEvent = aEvent.session;
ok(sessionFromEvent, "|sessionconnect| event is fired with a session.");
var connectionFromEvent;
request.onconnectionavailable = function(aEvent) {
request.onconnectionavailable = null;
connectionFromEvent = aEvent.connection;
ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
if (session) {
is(session, sessionFromEvent, "The session from promise and the one from |sessionconnect| event should be the same.");
if (connection) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
aResolve();
}
};
request.start().then(
function(aSession) {
session = aSession;
ok(session, "Session should be availlable.");
ok(session.id, "Session ID should be set.");
is(session.state, "connected", "Session state at sender side should be connected by default.");
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connected", "Connection state at sender side should be connected by default.");
if (sessionFromEvent) {
is(session, sessionFromEvent, "The session from promise and the one from |sessionconnect| event should be the same.");
if (connectionFromEvent) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
aResolve();
}
},
function(aError) {
ok(false, "Error occurred when starting session: " + aError);
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
@ -130,7 +130,7 @@ function testSend() {
aResolve();
});
session.send(outgoingMessage);
connection.send(outgoingMessage);
});
}
@ -138,8 +138,8 @@ function testIncomingMessage() {
return new Promise(function(aResolve, aReject) {
const incomingMessage = "test incoming message";
session.addEventListener('message', function messageHandler(aEvent) {
session.removeEventListener('message', messageHandler);
connection.addEventListener('message', function messageHandler(aEvent) {
connection.removeEventListener('message', messageHandler);
is(aEvent.data, incomingMessage, "An incoming message should be received.");
aResolve();
});
@ -148,20 +148,20 @@ function testIncomingMessage() {
});
}
function testTerminateSession() {
function testTerminateConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
session.onstatechange = function() {
session.onstatechange = null;
is(session.state, "terminated", "Session should be terminated.");
connection.onstatechange = function() {
connection.onstatechange = null;
is(connection.state, "terminated", "Connection should be terminated.");
aResolve();
};
session.terminate();
connection.terminate();
});
}
@ -179,10 +179,10 @@ function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testSetup().
then(testStartSession).
then(testStartConnection).
then(testSend).
then(testIncomingMessage).
then(testTerminateSession).
then(testTerminateConnection).
then(teardown);
}

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

@ -15,7 +15,7 @@
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var session;
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
@ -40,7 +40,7 @@ function testSetup() {
});
}
function testStartSession() {
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
@ -83,12 +83,12 @@ function testStartSession() {
ok(!navigator.presentation.receiver, "Sender shouldn't get a presentation receiver instance.");
navigator.presentation.defaultRequest.onsessionconnect = function(aEvent) {
navigator.presentation.defaultRequest.onsessionconnect = null;
session = aEvent.session;
ok(session, "|sessionconnect| event is fired with a session.");
ok(session.id, "Session ID should be set.");
is(session.state, "connected", "Session state at sender side should be connected by default.");
navigator.presentation.defaultRequest.onconnectionavailable = function(aEvent) {
navigator.presentation.defaultRequest.onconnectionavailable = null;
connection = aEvent.connection;
ok(connection, "|connectionavailable| event is fired with a connection.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connected", "Connection state at sender side should be connected by default.");
aResolve();
};
@ -97,20 +97,20 @@ function testStartSession() {
});
}
function testTerminateSession() {
function testTerminateConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
session.onstatechange = function() {
session.onstatechange = null;
is(session.state, "terminated", "Session should be terminated.");
connection.onstatechange = function() {
connection.onstatechange = null;
is(connection.state, "terminated", "Connection should be terminated.");
aResolve();
};
session.terminate();
connection.terminate();
});
}
@ -129,8 +129,8 @@ function runTests() {
ok(navigator.presentation, "navigator.presentation should be available.");
testSetup().
then(testStartSession).
then(testTerminateSession).
then(testStartConnection).
then(testTerminateConnection).
then(teardown);
}

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

@ -4,19 +4,19 @@
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for session disconnection of B2G Presentation API at sender side</title>
<title>Test for disconnection of B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for session disconnection of B2G Presentation API at sender side</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for disconnection of B2G Presentation API at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var request;
var session;
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
@ -41,7 +41,7 @@ function testSetup() {
});
}
function testStartSession() {
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
@ -88,15 +88,15 @@ function testStartSession() {
});
request.start().then(
function(aSession) {
session = aSession;
ok(session, "Session should be availlable.");
ok(session.id, "Session ID should be set.");
is(session.state, "connected", "Session state at sender side should be connected by default.");
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connected", "Connection state at sender side should be connected by default.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when starting session: " + aError);
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
@ -104,16 +104,16 @@ function testStartSession() {
});
}
function testSessionDisconnection() {
function testDisconnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
session.onstatechange = function() {
session.onstatechange = null;
is(session.state, "closed", "Session should be closed.");
connection.onstatechange = function() {
connection.onstatechange = null;
is(connection.state, "closed", "Connection should be closed.");
aResolve();
};
@ -135,8 +135,8 @@ function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testSetup().
then(testStartSession).
then(testSessionDisconnection).
then(testStartConnection).
then(testDisconnection).
then(teardown);
}

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

@ -4,12 +4,12 @@
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for startSession errors of B2G Presentation API at sender side</title>
<title>Test for connection establishing errors of B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for startSession errors of B2G Presentation API at sender side</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for connection establishing errors of B2G Presentation API at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
@ -51,7 +51,7 @@ function testCreateRequestWithEmptyURL() {
});
}
function testStartSessionCancelPrompt() {
function testStartConnectionCancelPrompt() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
@ -60,7 +60,7 @@ function testStartSessionCancelPrompt() {
});
request.start().then(
function(aSession) {
function(aConnection) {
ok(false, "|start| shouldn't succeed in this case.");
aReject();
},
@ -72,7 +72,7 @@ function testStartSessionCancelPrompt() {
});
}
function testStartSessionUnexpectedControlChannelCloseBeforeDataTransportInit() {
function testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
@ -103,19 +103,19 @@ function testStartSessionUnexpectedControlChannelCloseBeforeDataTransportInit()
});
request.start().then(
function(aSession) {
function(aConnection) {
ok(false, "|start| shouldn't succeed in this case.");
aReject();
},
function(aError) {
is(aError.name, "OperationError", "OperationError is expected when a connection error happens during starting session.");
is(aError.name, "OperationError", "OperationError is expected when a connection error happens during establishing a connection.");
aResolve();
}
);
});
}
function testStartSessionUnexpectedControlChannelCloseBeforeDataTransportReady() {
function testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
@ -157,19 +157,19 @@ function testStartSessionUnexpectedControlChannelCloseBeforeDataTransportReady()
});
request.start().then(
function(aSession) {
function(aConnection) {
ok(false, "|start| shouldn't succeed in this case.");
aReject();
},
function(aError) {
is(aError.name, "OperationError", "OperationError is expected when a connection error happens during starting session.");
is(aError.name, "OperationError", "OperationError is expected when a connection error happens during establishing a connection.");
aResolve();
}
);
});
}
function testStartSessionUnexpectedDataTransportClose() {
function testStartConnectionUnexpectedDataTransportClose() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
@ -211,12 +211,12 @@ function testStartSessionUnexpectedDataTransportClose() {
});
request.start().then(
function(aSession) {
function(aConnection) {
ok(false, "|start| shouldn't succeed in this case.");
aReject();
},
function(aError) {
is(aError.name, "OperationError", "OperationError is expected when a connection error happens during starting session.");
is(aError.name, "OperationError", "OperationError is expected when a connection error happens during establishing a connection.");
aResolve();
}
);
@ -238,10 +238,10 @@ function runTests() {
testCreateRequestWithEmptyURL().
then(setup).
then(testStartSessionCancelPrompt).
then(testStartSessionUnexpectedControlChannelCloseBeforeDataTransportInit).
then(testStartSessionUnexpectedControlChannelCloseBeforeDataTransportReady).
then(testStartSessionUnexpectedDataTransportClose).
then(testStartConnectionCancelPrompt).
then(testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit).
then(testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady).
then(testStartConnectionUnexpectedDataTransportClose).
then(teardown);
}

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

@ -9,8 +9,8 @@
interface Presentation : EventTarget {
/*
* This should be used by the UA as the default presentation request for the
* controller. When the UA wishes to initiate a PresentationSession on the
* controller's behalf, it MUST start a presentation session using the default
* controller. When the UA wishes to initiate a PresentationConnection on the
* controller's behalf, it MUST start a presentation connection using the default
* presentation request (as if the controller had called |defaultRequest.start()|).
*
* Only used by controlling browsing context (senders).

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

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
enum PresentationSessionState
enum PresentationConnectionState
{
// Existing presentation, and the communication channel is active.
"connected",
@ -19,9 +19,9 @@ enum PresentationSessionState
[Pref="dom.presentation.enabled",
CheckAnyPermissions="presentation"]
interface PresentationSession : EventTarget {
interface PresentationConnection : EventTarget {
/*
* Unique id for all existing sessions.
* Unique id for all existing connections.
*/
[Constant]
readonly attribute DOMString id;
@ -29,10 +29,10 @@ interface PresentationSession : EventTarget {
/*
* @value "connected", "closed", or "terminated".
*/
readonly attribute PresentationSessionState state;
readonly attribute PresentationConnectionState state;
/*
* It is called when session state changes.
* It is called when connection state changes.
*/
attribute EventHandler onstatechange;
@ -55,8 +55,8 @@ interface PresentationSession : EventTarget {
attribute EventHandler onmessage;
/*
* Both the controlling and receving browsing context can close the session.
* Then, the session state should turn into "closed".
* Both the controlling and receiving browsing context can close the
* connection. Then the connection state should turn into "closed".
*
* This function only works when the state is not "connected".
*/
@ -65,8 +65,8 @@ interface PresentationSession : EventTarget {
// void close();
/*
* Both the controlling and receving browsing context can terminate the session.
* Then the session state should turn into "terminated".
* Both the controlling and receiving browsing context can terminate the
* connection. Then the connection state should turn into "terminated".
*
* This function only works when the state is not "connected".
*/

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

@ -5,16 +5,16 @@
*/
[Constructor(DOMString type,
optional PresentationSessionConnectEventInit eventInitDict),
optional PresentationConnectionAvailableEventInit eventInitDict),
Pref="dom.presentation.enabled",
CheckAnyPermissions="presentation"]
interface PresentationSessionConnectEvent : Event
interface PresentationConnectionAvailableEvent : Event
{
[SameObject]
readonly attribute PresentationSession session;
readonly attribute PresentationConnection connection;
};
dictionary PresentationSessionConnectEventInit : EventInit
dictionary PresentationConnectionAvailableEventInit : EventInit
{
required PresentationSession session;
required PresentationConnection connection;
};

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

@ -8,20 +8,20 @@
CheckAnyPermissions="presentation"]
interface PresentationReceiver : EventTarget {
/*
* Get the first connected presentation session in a receiving browsing
* Get the first connected presentation connection in a receiving browsing
* context.
*/
[Throws]
Promise<PresentationSession> getSession();
Promise<PresentationConnection> getConnection();
/*
* Get all connected presentation sessions in a receiving browsing context.
* Get all connected presentation connections in a receiving browsing context.
*/
[Throws]
Promise<sequence<PresentationSession>> getSessions();
Promise<sequence<PresentationConnection>> getConnections();
/*
* It is called when an incoming session is connecting.
* It is called when an incoming connection is connecting.
*/
attribute EventHandler onsessionavailable;
attribute EventHandler onconnectionavailable;
};

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

@ -9,13 +9,13 @@
CheckAnyPermissions="presentation"]
interface PresentationRequest : EventTarget {
/*
* A requesting page use start() to start a new session, and the session will
* be returned with the promise. UA may show a prompt box with a list of
* A requesting page use start() to start a new connection, and it will be
* returned with the promise. UA may show a prompt box with a list of
* available devices and ask the user to grant permission, choose a device, or
* cancel the operation.
*
* The promise is resolved when the presenting page is successfully loaded and
* the communication channel is established, i.e., the session state is
* the communication channel is established, i.e., the connection state is
* "connected".
*
* The promise may be rejected duo to one of the following reasons:
@ -26,7 +26,7 @@ interface PresentationRequest : EventTarget {
* - "TimeoutError": Presenting page takes too long to load.
*/
[Throws]
Promise<PresentationSession> start();
Promise<PresentationConnection> start();
/*
* UA triggers device discovery mechanism periodically and monitor device
@ -39,8 +39,8 @@ interface PresentationRequest : EventTarget {
Promise<PresentationAvailability> getAvailability();
/*
* It is called when a session associated with a PresentationRequest is created.
* The event is fired for all sessions that are created for the controller.
* It is called when a connection associated with a PresentationRequest is created.
* The event is fired for all connections that are created for the controller.
*/
attribute EventHandler onsessionconnect;
attribute EventHandler onconnectionavailable;
};

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

@ -374,10 +374,10 @@ WEBIDL_FILES = [
'PositionError.webidl',
'Presentation.webidl',
'PresentationAvailability.webidl',
'PresentationConnection.webidl',
'PresentationDeviceInfoManager.webidl',
'PresentationReceiver.webidl',
'PresentationRequest.webidl',
'PresentationSession.webidl',
'ProcessingInstruction.webidl',
'ProfileTimelineMarker.webidl',
'Promise.webidl',
@ -801,7 +801,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'PluginCrashedEvent.webidl',
'PopStateEvent.webidl',
'PopupBlockedEvent.webidl',
'PresentationSessionConnectEvent.webidl',
'PresentationConnectionAvailableEvent.webidl',
'ProgressEvent.webidl',
'RecordErrorEvent.webidl',
'ScrollViewChangeEvent.webidl',

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

@ -130,7 +130,7 @@ if (!imgTools)
// different set of reference images. nsIXULRuntime.OS doesn't seem to be
// available in xpcshell, so we'll use this as a kludgy way to figure out if
// we're running on Windows.
var isWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
var isWindows = mozinfo.os == "win";
/* ========== 1 ========== */

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

@ -520,16 +520,6 @@ js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp)
jsid id;
if (args.thisv().isObject() && ValueToId<NoGC>(cx, idValue, &id)) {
JSObject* obj = &args.thisv().toObject();
#ifndef RELEASE_BUILD
if (obj->is<RegExpObject>() && id == NameToId(cx->names().source)) {
if (JSScript* script = cx->currentScript()) {
const char* filename = script->filename();
cx->compartment()->addTelemetry(filename, JSCompartment::RegExpSourceProperty);
}
}
#endif
Shape* prop;
if (obj->isNative() &&
NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop))

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

@ -8466,10 +8466,11 @@ CodeGenerator::visitNameIC(OutOfLineUpdateCache* ool, DataPtr<NameIC>& ic)
void
CodeGenerator::addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
PropertyName* name, TypedOrValueRegister output,
bool monitoredResult, jsbytecode* profilerLeavePc)
ConstantOrRegister id, TypedOrValueRegister output,
bool monitoredResult, bool allowDoubleResult,
jsbytecode* profilerLeavePc)
{
GetPropertyIC cache(liveRegs, objReg, name, output, monitoredResult);
GetPropertyIC cache(liveRegs, objReg, id, output, monitoredResult, allowDoubleResult);
cache.setProfilerLeavePC(profilerLeavePc);
addCache(ins, allocateCache(cache));
}
@ -8497,17 +8498,30 @@ CodeGenerator::addSetElementCache(LInstruction* ins, Register obj, Register unbo
addCache(ins, allocateCache(cache));
}
ConstantOrRegister
CodeGenerator::toConstantOrRegister(LInstruction* lir, size_t n, MIRType type)
{
if (type == MIRType_Value)
return TypedOrValueRegister(ToValue(lir, n));
const LAllocation* value = lir->getOperand(n);
if (value->isConstant())
return ConstantOrRegister(*value->toConstant());
return TypedOrValueRegister(type, ToAnyRegister(value));
}
void
CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV* ins)
{
LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
Register objReg = ToRegister(ins->getOperand(0));
PropertyName* name = ins->mir()->name();
ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheV::Id, ins->mir()->idval()->type());
bool monitoredResult = ins->mir()->monitoredResult();
TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
addGetPropertyCache(ins, liveRegs, objReg, name, output, monitoredResult,
ins->mir()->profilerLeavePc());
addGetPropertyCache(ins, liveRegs, objReg, id, output, monitoredResult,
ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
}
void
@ -8515,15 +8529,15 @@ CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT* ins)
{
LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
Register objReg = ToRegister(ins->getOperand(0));
PropertyName* name = ins->mir()->name();
ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheT::Id, ins->mir()->idval()->type());
bool monitoredResult = ins->mir()->monitoredResult();
TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->getDef(0)));
addGetPropertyCache(ins, liveRegs, objReg, name, output, monitoredResult,
ins->mir()->profilerLeavePc());
addGetPropertyCache(ins, liveRegs, objReg, id, output, monitoredResult,
ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
}
typedef bool (*GetPropertyICFn)(JSContext*, HandleScript, size_t, HandleObject,
typedef bool (*GetPropertyICFn)(JSContext*, HandleScript, size_t, HandleObject, HandleValue,
MutableHandleValue);
const VMFunction GetPropertyIC::UpdateInfo = FunctionInfo<GetPropertyICFn>(GetPropertyIC::update);
@ -8541,6 +8555,7 @@ CodeGenerator::visitGetPropertyIC(OutOfLineUpdateCache* ool, DataPtr<GetProperty
saveLive(lir);
pushArg(ic->id());
pushArg(ic->object());
pushArg(Imm32(ool->getCacheIndex()));
pushArg(ImmGCPtr(gen->info().script()));
@ -8551,62 +8566,6 @@ CodeGenerator::visitGetPropertyIC(OutOfLineUpdateCache* ool, DataPtr<GetProperty
masm.jump(ool->rejoin());
}
void
CodeGenerator::addGetElementCache(LInstruction* ins, Register obj, TypedOrValueRegister index,
TypedOrValueRegister output, bool monitoredResult,
bool allowDoubleResult, jsbytecode* profilerLeavePc)
{
LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
GetElementIC cache(liveRegs, obj, index, output, monitoredResult, allowDoubleResult);
cache.setProfilerLeavePC(profilerLeavePc);
addCache(ins, allocateCache(cache));
}
void
CodeGenerator::visitGetElementCacheV(LGetElementCacheV* ins)
{
Register obj = ToRegister(ins->object());
TypedOrValueRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
const MGetElementCache* mir = ins->mir();
addGetElementCache(ins, obj, index, output, mir->monitoredResult(),
mir->allowDoubleResult(), mir->profilerLeavePc());
}
void
CodeGenerator::visitGetElementCacheT(LGetElementCacheT* ins)
{
Register obj = ToRegister(ins->object());
TypedOrValueRegister index = TypedOrValueRegister(MIRType_Int32, ToAnyRegister(ins->index()));
TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output()));
const MGetElementCache* mir = ins->mir();
addGetElementCache(ins, obj, index, output, mir->monitoredResult(),
mir->allowDoubleResult(), mir->profilerLeavePc());
}
typedef bool (*GetElementICFn)(JSContext*, HandleScript, size_t, HandleObject, HandleValue,
MutableHandleValue);
const VMFunction GetElementIC::UpdateInfo = FunctionInfo<GetElementICFn>(GetElementIC::update);
void
CodeGenerator::visitGetElementIC(OutOfLineUpdateCache* ool, DataPtr<GetElementIC>& ic)
{
LInstruction* lir = ool->lir();
saveLive(lir);
pushArg(ic->index());
pushArg(ic->object());
pushArg(Imm32(ool->getCacheIndex()));
pushArg(ImmGCPtr(gen->info().script()));
callVM(GetElementIC::UpdateInfo, lir);
StoreValueTo(ic->output()).generate(this);
restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
masm.jump(ool->rejoin());
}
void
CodeGenerator::visitSetElementCacheV(LSetElementCacheV* ins)
{

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

@ -52,6 +52,8 @@ class CodeGenerator : public CodeGeneratorSpecific
void generateArgumentsChecks(bool bailout = true);
bool generateBody();
ConstantOrRegister toConstantOrRegister(LInstruction* lir, size_t n, MIRType type);
public:
CodeGenerator(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm = nullptr);
~CodeGenerator();
@ -355,8 +357,6 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitGetPropertyCacheV(LGetPropertyCacheV* ins);
void visitGetPropertyCacheT(LGetPropertyCacheT* ins);
void visitGetElementCacheV(LGetElementCacheV* ins);
void visitGetElementCacheT(LGetElementCacheT* ins);
void visitSetElementCacheV(LSetElementCacheV* ins);
void visitSetElementCacheT(LSetElementCacheT* ins);
void visitBindNameCache(LBindNameCache* ins);
@ -367,7 +367,6 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitGetPropertyIC(OutOfLineUpdateCache* ool, DataPtr<GetPropertyIC>& ic);
void visitSetPropertyIC(OutOfLineUpdateCache* ool, DataPtr<SetPropertyIC>& ic);
void visitGetElementIC(OutOfLineUpdateCache* ool, DataPtr<GetElementIC>& ic);
void visitSetElementIC(OutOfLineUpdateCache* ool, DataPtr<SetElementIC>& ic);
void visitBindNameIC(OutOfLineUpdateCache* ool, DataPtr<BindNameIC>& ic);
void visitNameIC(OutOfLineUpdateCache* ool, DataPtr<NameIC>& ic);
@ -397,11 +396,9 @@ class CodeGenerator : public CodeGeneratorSpecific
private:
void addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
PropertyName* name, TypedOrValueRegister output,
bool monitoredResult, jsbytecode* profilerLeavePc);
void addGetElementCache(LInstruction* ins, Register obj, TypedOrValueRegister index,
TypedOrValueRegister output, bool monitoredResult,
bool allowDoubleResult, jsbytecode* profilerLeavePc);
ConstantOrRegister id, TypedOrValueRegister output,
bool monitoredResult, bool allowDoubleResult,
jsbytecode* profilerLeavePc);
void addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
PropertyName* name, ConstantOrRegister value, bool strict,
bool needsTypeBarrier, jsbytecode* profilerLeavePc);

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

@ -6063,7 +6063,8 @@ IonBuilder::createThisScripted(MDefinition* callee, MDefinition* newTarget)
// and thus invalidation.
MInstruction* getProto;
if (!invalidatedIdempotentCache()) {
MGetPropertyCache* getPropCache = MGetPropertyCache::New(alloc(), newTarget, names().prototype,
MConstant* id = constant(StringValue(names().prototype));
MGetPropertyCache* getPropCache = MGetPropertyCache::New(alloc(), newTarget, id,
/* monitored = */ false);
getPropCache->setIdempotent();
getProto = getPropCache;
@ -9097,8 +9098,8 @@ IonBuilder::getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index)
if (index->mightBeType(MIRType_String) || index->mightBeType(MIRType_Symbol))
barrier = BarrierKind::TypeSet;
MInstruction* ins = MGetElementCache::New(alloc(), obj, index, barrier == BarrierKind::TypeSet);
MGetPropertyCache* ins = MGetPropertyCache::New(alloc(), obj, index,
barrier == BarrierKind::TypeSet);
current->add(ins);
current->push(ins);
@ -10498,12 +10499,10 @@ IonBuilder::replaceMaybeFallbackFunctionGetter(MGetPropertyCache* cache)
}
bool
IonBuilder::annotateGetPropertyCache(MDefinition* obj, MGetPropertyCache* getPropCache,
TemporaryTypeSet* objTypes,
IonBuilder::annotateGetPropertyCache(MDefinition* obj, PropertyName* name,
MGetPropertyCache* getPropCache, TemporaryTypeSet* objTypes,
TemporaryTypeSet* pushedTypes)
{
PropertyName* name = getPropCache->name();
// Ensure every pushed value is a singleton.
if (pushedTypes->unknownObject() || pushedTypes->baseFlags() != 0)
return true;
@ -11756,7 +11755,8 @@ IonBuilder::getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name,
}
}
MGetPropertyCache* load = MGetPropertyCache::New(alloc(), obj, name,
MConstant* id = constant(StringValue(name));
MGetPropertyCache* load = MGetPropertyCache::New(alloc(), obj, id,
barrier == BarrierKind::TypeSet);
// Try to mark the cache as idempotent.
@ -11779,7 +11779,7 @@ IonBuilder::getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name,
// to do the GetPropertyCache, and we can dispatch based on the JSFunction
// value.
if (JSOp(*pc) == JSOP_CALLPROP && load->idempotent()) {
if (!annotateGetPropertyCache(obj, load, obj->resultTypeSet(), types))
if (!annotateGetPropertyCache(obj, name, load, obj->resultTypeSet(), types))
return false;
}

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

@ -956,8 +956,8 @@ class IonBuilder
const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
bool isOwnProperty);
bool annotateGetPropertyCache(MDefinition* obj, MGetPropertyCache* getPropCache,
TemporaryTypeSet* objTypes,
bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name,
MGetPropertyCache* getPropCache, TemporaryTypeSet* objTypes,
TemporaryTypeSet* pushedTypes);
MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo);

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

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

@ -29,7 +29,6 @@ class LInstruction;
#define IONCACHE_KIND_LIST(_) \
_(GetProperty) \
_(SetProperty) \
_(GetElement) \
_(SetElement) \
_(BindName) \
_(Name)
@ -382,37 +381,51 @@ class GetPropertyIC : public IonCache
LiveRegisterSet liveRegs_;
Register object_;
PropertyName* name_;
ConstantOrRegister id_;
TypedOrValueRegister output_;
// Only valid if idempotent
size_t locationsIndex_;
size_t numLocations_;
static const size_t MAX_FAILED_UPDATES = 16;
uint16_t failedUpdates_;
bool monitoredResult_ : 1;
bool allowDoubleResult_ : 1;
bool hasTypedArrayLengthStub_ : 1;
bool hasSharedTypedArrayLengthStub_ : 1;
bool hasMappedArgumentsLengthStub_ : 1;
bool hasUnmappedArgumentsLengthStub_ : 1;
bool hasMappedArgumentsElementStub_ : 1;
bool hasUnmappedArgumentsElementStub_ : 1;
bool hasGenericProxyStub_ : 1;
bool hasDenseStub_ : 1;
void emitIdGuard(MacroAssembler& masm, jsid id, Label* fail);
public:
GetPropertyIC(LiveRegisterSet liveRegs,
Register object, PropertyName* name,
Register object, ConstantOrRegister id,
TypedOrValueRegister output,
bool monitoredResult)
bool monitoredResult, bool allowDoubleResult)
: liveRegs_(liveRegs),
object_(object),
name_(name),
id_(id),
output_(output),
locationsIndex_(0),
numLocations_(0),
failedUpdates_(0),
monitoredResult_(monitoredResult),
allowDoubleResult_(allowDoubleResult),
hasTypedArrayLengthStub_(false),
hasSharedTypedArrayLengthStub_(false),
hasMappedArgumentsLengthStub_(false),
hasUnmappedArgumentsLengthStub_(false),
hasGenericProxyStub_(false)
hasMappedArgumentsElementStub_(false),
hasUnmappedArgumentsElementStub_(false),
hasGenericProxyStub_(false),
hasDenseStub_(false)
{
}
@ -423,8 +436,8 @@ class GetPropertyIC : public IonCache
Register object() const {
return object_;
}
PropertyName* name() const {
return name_;
ConstantOrRegister id() const {
return id_;
}
TypedOrValueRegister output() const {
return output_;
@ -438,10 +451,21 @@ class GetPropertyIC : public IonCache
bool hasArgumentsLengthStub(bool mapped) const {
return mapped ? hasMappedArgumentsLengthStub_ : hasUnmappedArgumentsLengthStub_;
}
bool hasArgumentsElementStub(bool mapped) const {
return mapped ? hasMappedArgumentsElementStub_ : hasUnmappedArgumentsElementStub_;
}
bool hasGenericProxyStub() const {
return hasGenericProxyStub_;
}
bool hasDenseStub() const {
return hasDenseStub_;
}
void setHasDenseStub() {
MOZ_ASSERT(!hasDenseStub());
hasDenseStub_ = true;
}
void setHasTypedArrayLengthStub(HandleObject obj) {
if (obj->is<TypedArrayObject>()) {
MOZ_ASSERT(!hasTypedArrayLengthStub_);
@ -478,49 +502,64 @@ class GetPropertyIC : public IonCache
return monitoredResult() && !idempotent();
}
void maybeDisable(bool emitted);
// Attach the proper stub, if possible
bool tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name, bool* emitted);
HandleObject obj, HandleValue idval, bool* emitted);
bool tryAttachProxy(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name,
void* returnAddr, bool* emitted);
HandleObject obj, HandleId id, void* returnAddr, bool* emitted);
bool tryAttachGenericProxy(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name,
void* returnAddr, bool* emitted);
HandleObject obj, HandleId id, void* returnAddr, bool* emitted);
bool tryAttachDOMProxyShadowed(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, void* returnAddr, bool* emitted);
HandleObject obj, HandleId id, void* returnAddr, bool* emitted);
bool tryAttachDOMProxyUnshadowed(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name, bool resetNeeded,
HandleObject obj, HandleId id, bool resetNeeded,
void* returnAddr, bool* emitted);
bool tryAttachNative(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name,
void* returnAddr, bool* emitted);
HandleObject obj, HandleId id, void* returnAddr, bool* emitted);
bool tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name,
void* returnAddr, bool* emitted);
HandleObject obj, HandleId id, void* returnAddr, bool* emitted);
bool tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name,
void* returnAddr, bool* emitted);
HandleObject obj, HandleId id, void* returnAddr, bool* emitted);
bool tryAttachUnboxedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name,
void* returnAddr, bool* emitted);
HandleObject obj, HandleId id, void* returnAddr,
bool* emitted);
bool tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name, bool* emitted);
HandleObject obj, HandleId id, bool* emitted);
bool tryAttachArgumentsLength(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandlePropertyName name, bool* emitted);
HandleObject obj, HandleId id, bool* emitted);
bool tryAttachArgumentsElement(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleValue idval, bool* emitted);
bool tryAttachDenseElement(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleValue idval, bool* emitted);
static bool canAttachDenseElementHole(JSObject* obj, HandleValue idval,
TypedOrValueRegister output);
bool tryAttachDenseElementHole(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, HandleValue idval, bool* emitted);
static bool canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& idval,
TypedOrValueRegister output);
bool tryAttachTypedOrUnboxedArrayElement(JSContext* cx, HandleScript outerScript,
IonScript* ion, HandleObject obj,
HandleValue idval, bool* emitted);
static bool update(JSContext* cx, HandleScript outerScript, size_t cacheIndex,
HandleObject obj, MutableHandleValue vp);
HandleObject obj, HandleValue id, MutableHandleValue vp);
};
class SetPropertyIC : public IonCache
@ -610,117 +649,6 @@ class SetPropertyIC : public IonCache
HandleObject obj, HandleValue value);
};
class GetElementIC : public IonCache
{
protected:
LiveRegisterSet liveRegs_;
Register object_;
TypedOrValueRegister index_;
TypedOrValueRegister output_;
bool monitoredResult_ : 1;
bool allowDoubleResult_ : 1;
bool hasDenseStub_ : 1;
bool hasMappedArgumentsStub_ : 1;
bool hasUnmappedArgumentsStub_ : 1;
size_t failedUpdates_;
static const size_t MAX_FAILED_UPDATES;
public:
GetElementIC(LiveRegisterSet liveRegs, Register object, TypedOrValueRegister index,
TypedOrValueRegister output, bool monitoredResult, bool allowDoubleResult)
: liveRegs_(liveRegs),
object_(object),
index_(index),
output_(output),
monitoredResult_(monitoredResult),
allowDoubleResult_(allowDoubleResult),
hasDenseStub_(false),
hasMappedArgumentsStub_(false),
hasUnmappedArgumentsStub_(false),
failedUpdates_(0)
{
}
CACHE_HEADER(GetElement)
void reset(ReprotectCode reprotect);
Register object() const {
return object_;
}
TypedOrValueRegister index() const {
return index_;
}
TypedOrValueRegister output() const {
return output_;
}
bool monitoredResult() const {
return monitoredResult_;
}
bool allowDoubleResult() const {
return allowDoubleResult_;
}
bool hasDenseStub() const {
return hasDenseStub_;
}
bool hasArgumentsStub(bool mapped) const {
return mapped ? hasMappedArgumentsStub_ : hasUnmappedArgumentsStub_;
}
void setHasDenseStub() {
MOZ_ASSERT(!hasDenseStub());
hasDenseStub_ = true;
}
// Helpers for CanAttachNativeGetProp
typedef JSContext * Context;
bool allowGetters() const { MOZ_ASSERT(!idempotent()); return true; }
bool allowArrayLength(Context) const { return false; }
bool canMonitorSingletonUndefinedSlot(HandleObject holder, HandleShape shape) const {
return monitoredResult();
}
static bool canAttachGetProp(JSObject* obj, const Value& idval, jsid id);
static bool canAttachDenseElement(JSObject* obj, const Value& idval);
static bool canAttachDenseElementHole(JSObject* obj, const Value& idval,
TypedOrValueRegister output);
static bool canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& idval,
TypedOrValueRegister output);
bool attachGetProp(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, const Value& idval, HandlePropertyName name);
bool attachDenseElement(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, const Value& idval);
bool attachDenseElementHole(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj, const Value& idval);
bool attachTypedOrUnboxedArrayElement(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject tarr, const Value& idval);
bool attachArgumentsElement(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject obj);
static bool
update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, HandleObject obj,
HandleValue idval, MutableHandleValue vp);
void incFailedUpdates() {
failedUpdates_++;
}
void resetFailedUpdates() {
failedUpdates_ = 0;
}
bool shouldDisable() const {
return !canAttachStub() ||
(stubCount_ == 0 && failedUpdates_ > MAX_FAILED_UPDATES);
}
};
class SetElementIC : public IonCache
{
protected:

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

@ -3252,6 +3252,12 @@ LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins)
{
MOZ_ASSERT(ins->object()->type() == MIRType_Object);
MDefinition* id = ins->idval();
MOZ_ASSERT(id->type() == MIRType_String ||
id->type() == MIRType_Symbol ||
id->type() == MIRType_Int32 ||
id->type() == MIRType_Value);
if (ins->monitoredResult()) {
// Set the performs-call flag so that we don't omit the overrecursed
// check. This is necessary because the cache can attach a scripted
@ -3259,12 +3265,18 @@ LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins)
gen->setPerformsCall();
}
// If this is a GETPROP, the id is a constant string. Allow passing it as a
// constant to reduce register allocation pressure.
bool useConstId = id->type() == MIRType_String || id->type() == MIRType_Symbol;
if (ins->type() == MIRType_Value) {
LGetPropertyCacheV* lir = new(alloc()) LGetPropertyCacheV(useRegister(ins->object()));
useBoxOrTypedOrConstant(lir, LGetPropertyCacheV::Id, id, useConstId);
defineBox(lir, ins);
assignSafepoint(lir, ins);
} else {
LGetPropertyCacheT* lir = new(alloc()) LGetPropertyCacheT(useRegister(ins->object()));
useBoxOrTypedOrConstant(lir, LGetPropertyCacheT::Id, id, useConstId);
define(lir, ins);
assignSafepoint(lir, ins);
}
@ -3310,29 +3322,6 @@ LIRGenerator::visitSetPropertyPolymorphic(MSetPropertyPolymorphic* ins)
}
}
void
LIRGenerator::visitGetElementCache(MGetElementCache* ins)
{
MOZ_ASSERT(ins->object()->type() == MIRType_Object);
if (ins->monitoredResult())
gen->setPerformsCall(); // See visitGetPropertyCache.
if (ins->type() == MIRType_Value) {
MOZ_ASSERT(ins->index()->type() == MIRType_Value);
LGetElementCacheV* lir = new(alloc()) LGetElementCacheV(useRegister(ins->object()));
useBox(lir, LGetElementCacheV::Index, ins->index());
defineBox(lir, ins);
assignSafepoint(lir, ins);
} else {
MOZ_ASSERT(ins->index()->type() == MIRType_Int32);
LGetElementCacheT* lir = new(alloc()) LGetElementCacheT(useRegister(ins->object()),
useRegister(ins->index()));
define(lir, ins);
assignSafepoint(lir, ins);
}
}
void
LIRGenerator::visitBindNameCache(MBindNameCache* ins)
{

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

@ -226,7 +226,6 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitGetPropertyCache(MGetPropertyCache* ins);
void visitGetPropertyPolymorphic(MGetPropertyPolymorphic* ins);
void visitSetPropertyPolymorphic(MSetPropertyPolymorphic* ins);
void visitGetElementCache(MGetElementCache* ins);
void visitBindNameCache(MBindNameCache* ins);
void visitGuardObjectIdentity(MGuardObjectIdentity* ins);
void visitGuardClass(MGuardClass* ins);

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

@ -4607,7 +4607,7 @@ MStoreTypedArrayElementStatic::base() const
}
bool
MGetElementCache::allowDoubleResult() const
MGetPropertyCache::allowDoubleResult() const
{
if (!resultTypeSet())
return true;
@ -4668,7 +4668,8 @@ MGetPropertyCache::setBlock(MBasicBlock* block)
}
bool
MGetPropertyCache::updateForReplacement(MDefinition* ins) {
MGetPropertyCache::updateForReplacement(MDefinition* ins)
{
MGetPropertyCache* other = ins->toGetPropertyCache();
location_.append(&other->location_);
return true;

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

@ -10238,20 +10238,18 @@ class CacheLocationList : public InlineConcatList<CacheLocationList>
};
class MGetPropertyCache
: public MUnaryInstruction,
public SingleObjectPolicy::Data
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>>::Data
{
CompilerPropertyName name_;
bool idempotent_;
bool monitoredResult_;
bool idempotent_ : 1;
bool monitoredResult_ : 1;
CacheLocationList location_;
InlinePropertyTable* inlinePropertyTable_;
MGetPropertyCache(MDefinition* obj, PropertyName* name, bool monitoredResult)
: MUnaryInstruction(obj),
name_(name),
MGetPropertyCache(MDefinition* obj, MDefinition* id, bool monitoredResult)
: MBinaryInstruction(obj, id),
idempotent_(false),
monitoredResult_(monitoredResult),
location_(),
@ -10268,9 +10266,9 @@ class MGetPropertyCache
public:
INSTRUCTION_HEADER(GetPropertyCache)
static MGetPropertyCache* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name,
static MGetPropertyCache* New(TempAllocator& alloc, MDefinition* obj, MDefinition* id,
bool monitoredResult) {
return new(alloc) MGetPropertyCache(obj, name, monitoredResult);
return new(alloc) MGetPropertyCache(obj, id, monitoredResult);
}
InlinePropertyTable* initInlinePropertyTable(TempAllocator& alloc, jsbytecode* pc) {
@ -10290,9 +10288,10 @@ class MGetPropertyCache
MDefinition* object() const {
return getOperand(0);
}
PropertyName* name() const {
return name_;
MDefinition* idval() const {
return getOperand(1);
}
bool idempotent() const {
return idempotent_;
}
@ -10312,8 +10311,6 @@ class MGetPropertyCache
return false;
if (!ins->isGetPropertyCache())
return false;
if (name() != ins->toGetPropertyCache()->name())
return false;
return congruentIfOperandsEqual(ins);
}
@ -10328,6 +10325,8 @@ class MGetPropertyCache
void setBlock(MBasicBlock* block) override;
bool updateForReplacement(MDefinition* ins) override;
bool allowDoubleResult() const;
};
// Emit code to load a value from an object if it matches one of the receivers
@ -10646,44 +10645,6 @@ class MFunctionDispatch : public MDispatchInstruction
}
};
class MGetElementCache
: public MBinaryInstruction
{
MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data PolicyV;
MixPolicy<ObjectPolicy<0>, IntPolicy<1> >::Data PolicyT;
TypePolicy* thisTypePolicy();
// See the comment in IonBuilder::jsop_getelem.
bool monitoredResult_;
MGetElementCache(MDefinition* obj, MDefinition* value, bool monitoredResult)
: MBinaryInstruction(obj, value), monitoredResult_(monitoredResult)
{
setResultType(MIRType_Value);
}
public:
INSTRUCTION_HEADER(GetElementCache)
static MGetElementCache* New(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
bool monitoredResult)
{
return new(alloc) MGetElementCache(obj, value, monitoredResult);
}
MDefinition* object() const {
return getOperand(0);
}
MDefinition* index() const {
return getOperand(1);
}
bool monitoredResult() const {
return monitoredResult_;
}
bool allowDoubleResult() const;
};
class MBindNameCache
: public MUnaryInstruction,
public SingleObjectPolicy::Data

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

@ -161,7 +161,6 @@ namespace jit {
_(GetPropertyCache) \
_(GetPropertyPolymorphic) \
_(SetPropertyPolymorphic) \
_(GetElementCache) \
_(SetElementCache) \
_(BindNameCache) \
_(GuardShape) \

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

@ -625,6 +625,23 @@ template bool BoxExceptPolicy<1, MIRType_String>::staticAdjustInputs(TempAllocat
template bool BoxExceptPolicy<2, MIRType_String>::staticAdjustInputs(TempAllocator& alloc,
MInstruction* ins);
template <unsigned Op>
bool
CacheIdPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
{
MDefinition* in = ins->getOperand(Op);
switch (in->type()) {
case MIRType_Int32:
case MIRType_String:
case MIRType_Symbol:
return true;
default:
return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
}
}
template bool CacheIdPolicy<1>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
bool
ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
{
@ -1209,6 +1226,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
_(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>>) \
_(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >) \
@ -1275,14 +1293,6 @@ thisTypeSpecialization()
} // namespace
TypePolicy*
MGetElementCache::thisTypePolicy()
{
if (type() == MIRType_Value)
return PolicyV.thisTypePolicy();
return PolicyT.thisTypePolicy();
}
// For each MIR Instruction, this macro define the |typePolicy| method which is
// using the |thisTypePolicy| method. The |thisTypePolicy| method is either a
// member of the MIR Instruction, such as with MGetElementCache, a member

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

@ -385,6 +385,18 @@ class BoxExceptPolicy final : public TypePolicy
}
};
// Box if not a typical property id (string, symbol, int32).
template <unsigned Op>
class CacheIdPolicy final : public TypePolicy
{
public:
EMPTY_DATA_;
static bool staticAdjustInputs(TempAllocator& alloc, MInstruction* ins);
bool adjustInputs(TempAllocator& alloc, MInstruction* ins) {
return staticAdjustInputs(alloc, ins);
}
};
// Combine multiple policies.
template <class Lhs, class Rhs>
class MixPolicy final : public TypePolicy

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

@ -5482,11 +5482,13 @@ class LCallGetIntrinsicValue : public LCallInstructionHelper<BOX_PIECES, 0, 0>
// Patchable jump to stubs generated for a GetProperty cache, which loads a
// boxed value.
class LGetPropertyCacheV : public LInstructionHelper<BOX_PIECES, 1, 0>
class LGetPropertyCacheV : public LInstructionHelper<BOX_PIECES, 1 + BOX_PIECES, 0>
{
public:
LIR_HEADER(GetPropertyCacheV)
static const size_t Id = 1;
explicit LGetPropertyCacheV(const LAllocation& object) {
setOperand(0, object);
}
@ -5497,11 +5499,13 @@ class LGetPropertyCacheV : public LInstructionHelper<BOX_PIECES, 1, 0>
// Patchable jump to stubs generated for a GetProperty cache, which loads a
// value of a known type, possibly into an FP register.
class LGetPropertyCacheT : public LInstructionHelper<1, 1, 0>
class LGetPropertyCacheT : public LInstructionHelper<1, 1 + BOX_PIECES, 0>
{
public:
LIR_HEADER(GetPropertyCacheT)
static const size_t Id = 1;
explicit LGetPropertyCacheT(const LAllocation& object) {
setOperand(0, object);
}
@ -5613,47 +5617,6 @@ class LSetPropertyPolymorphicT : public LInstructionHelper<0, 2, 1>
}
};
class LGetElementCacheV : public LInstructionHelper<BOX_PIECES, 1 + BOX_PIECES, 0>
{
public:
LIR_HEADER(GetElementCacheV)
static const size_t Index = 1;
explicit LGetElementCacheV(const LAllocation& object) {
setOperand(0, object);
}
const LAllocation* object() {
return getOperand(0);
}
const MGetElementCache* mir() const {
return mir_->toGetElementCache();
}
};
class LGetElementCacheT : public LInstructionHelper<1, 2, 0>
{
public:
LIR_HEADER(GetElementCacheT)
LGetElementCacheT(const LAllocation& object, const LAllocation& index) {
setOperand(0, object);
setOperand(1, index);
}
const LAllocation* object() {
return getOperand(0);
}
const LAllocation* index() {
return getOperand(1);
}
const LDefinition* output() {
return getDef(0);
}
const MGetElementCache* mir() const {
return mir_->toGetElementCache();
}
};
class LBindNameCache : public LInstructionHelper<1, 1, 0>
{
public:

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

@ -274,8 +274,6 @@
_(GetPropertyCacheT) \
_(GetPropertyPolymorphicV) \
_(GetPropertyPolymorphicT) \
_(GetElementCacheV) \
_(GetElementCacheT) \
_(BindNameCache) \
_(CallGetProperty) \
_(GetNameCache) \

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

@ -619,6 +619,25 @@ LIRGeneratorShared::useBox(LInstruction* lir, size_t n, MDefinition* mir,
#endif
}
void
LIRGeneratorShared::useBoxOrTypedOrConstant(LInstruction* lir, size_t n, MDefinition* mir,
bool useConstant)
{
if (mir->type() == MIRType_Value) {
useBox(lir, n, mir);
return;
}
if (useConstant && mir->isConstant())
lir->setOperand(n, LAllocation(mir->toConstant()->vp()));
else
lir->setOperand(n, useRegister(mir));
#if defined(JS_NUNBOX32)
lir->setOperand(n + 1, LAllocation());
#endif
}
} // namespace jit
} // namespace js

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

@ -163,6 +163,11 @@ class LIRGeneratorShared : public MDefinitionVisitor
inline void useBox(LInstruction* lir, size_t n, MDefinition* mir,
LUse::Policy policy = LUse::REGISTER, bool useAtStart = false);
// Adds a use at operand |n|. The use is either typed, a Value, or a
// constant (if useConstant is true).
inline void useBoxOrTypedOrConstant(LInstruction* lir, size_t n, MDefinition* mir,
bool useConstant);
// Rather than defining a new virtual register, sets |ins| to have the same
// virtual register as |as|.
inline void redefine(MDefinition* ins, MDefinition* as);

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

@ -753,7 +753,7 @@ struct JSCompartment
// NO LONGER USING 5
DeprecatedNoSuchMethod = 6, // JS 1.7+
DeprecatedFlagsArgument = 7, // JS 1.3 or older
RegExpSourceProperty = 8, // ES5
// NO LONGER USING 8
DeprecatedLanguageExtensionCount
};

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

@ -2551,15 +2551,6 @@ js::GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
return ok;
}
#ifndef RELEASE_BUILD
if (obj->is<RegExpObject>() && id == NameToId(cx->names().source)) {
if (JSScript* script = cx->currentScript()) {
const char* filename = script->filename();
cx->compartment()->addTelemetry(filename, JSCompartment::RegExpSourceProperty);
}
}
#endif
RootedNativeObject nobj(cx, obj.as<NativeObject>());
RootedShape shape(cx);
if (!NativeLookupOwnProperty<CanGC>(cx, nobj, id, &shape))

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

@ -1673,19 +1673,19 @@
/*
* Bind the |this| value of a function to the supplied value.
*
* Category: Variables and Scopes
* Type: This
* Operands:
* Stack: this => this
* Category: Variables and Scopes
* Type: This
* Operands:
* Stack: this => this
*/ \
macro(JSOP_SETTHIS , 163,"setthis", NULL, 1, 1, 1, JOF_BYTE) \
macro(JSOP_SETTHIS, 163,"setthis", NULL, 1, 1, 1, JOF_BYTE) \
/*
* Find the function to invoke with |super()| on the scope chain.
*
* Category: Variables and Scopes
* Type: Super
* Operands:
* Stack: => superFun
* Category: Variables and Scopes
* Type: Super
* Operands:
* Stack: => superFun
*/ \
macro(JSOP_SUPERFUN, 164,"superfun", NULL, 1, 0, 1, JOF_BYTE) \
/*

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше