mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
commit
31ad3140c9
@ -20,6 +20,12 @@ var Utilities = {
|
||||
return this.bookmarks;
|
||||
},
|
||||
|
||||
get bookmarksObserver() {
|
||||
let bookmarksObserver = new BookmarksObserver();
|
||||
this.__defineGetter__("bookmarksObserver", function() bookmarksObserver);
|
||||
return this.bookmarksObserver;
|
||||
},
|
||||
|
||||
get livemarks() {
|
||||
let livemarks = Cc["@mozilla.org/browser/livemark-service;2"].
|
||||
getService[Ci.mozIAsyncLivemarks].
|
||||
@ -49,15 +55,16 @@ var Utilities = {
|
||||
return this.windowMediator;
|
||||
},
|
||||
|
||||
makeURI : function(aSpec) {
|
||||
makeURI: function fuelutil_makeURI(aSpec) {
|
||||
if (!aSpec)
|
||||
return null;
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
return ios.newURI(aSpec, null, null);
|
||||
},
|
||||
|
||||
free : function() {
|
||||
free: function fuelutil_free() {
|
||||
delete this.bookmarks;
|
||||
delete this.bookmarksObserver;
|
||||
delete this.livemarks
|
||||
delete this.annotations;
|
||||
delete this.history;
|
||||
@ -68,19 +75,26 @@ var Utilities = {
|
||||
|
||||
//=================================================
|
||||
// Window implementation
|
||||
|
||||
var fuelWindowMap = new WeakMap();
|
||||
function getWindow(aWindow) {
|
||||
let fuelWindow = fuelWindowMap.get(aWindow);
|
||||
if (!fuelWindow) {
|
||||
fuelWindow = new Window(aWindow);
|
||||
fuelWindowMap.set(aWindow, fuelWindow);
|
||||
}
|
||||
return fuelWindow;
|
||||
}
|
||||
|
||||
// Don't call new Window() directly; use getWindow instead.
|
||||
function Window(aWindow) {
|
||||
this._window = aWindow;
|
||||
this._tabbrowser = aWindow.getBrowser();
|
||||
this._events = new Events();
|
||||
this._cleanup = {};
|
||||
|
||||
this._watch("TabOpen");
|
||||
this._watch("TabMove");
|
||||
this._watch("TabClose");
|
||||
this._watch("TabSelect");
|
||||
|
||||
var self = this;
|
||||
gShutdown.push(function() { self._shutdown(); });
|
||||
}
|
||||
|
||||
Window.prototype = {
|
||||
@ -88,65 +102,75 @@ Window.prototype = {
|
||||
return this._events;
|
||||
},
|
||||
|
||||
get _tabbrowser() {
|
||||
return this._window.getBrowser();
|
||||
},
|
||||
|
||||
/*
|
||||
* Helper used to setup event handlers on the XBL element. Note that the events
|
||||
* are actually dispatched to tabs, so we capture them.
|
||||
*/
|
||||
_watch : function win_watch(aType) {
|
||||
var self = this;
|
||||
this._tabbrowser.tabContainer.addEventListener(aType,
|
||||
this._cleanup[aType] = function(e){ self._event(e); },
|
||||
true);
|
||||
_watch: function win_watch(aType) {
|
||||
this._tabbrowser.tabContainer.addEventListener(aType, this,
|
||||
/* useCapture = */ true);
|
||||
},
|
||||
|
||||
/*
|
||||
* Helper event callback used to redirect events made on the XBL element
|
||||
*/
|
||||
_event : function win_event(aEvent) {
|
||||
this._events.dispatch(aEvent.type, new BrowserTab(this, aEvent.originalTarget.linkedBrowser));
|
||||
handleEvent: function win_handleEvent(aEvent) {
|
||||
this._events.dispatch(aEvent.type, getBrowserTab(this, aEvent.originalTarget.linkedBrowser));
|
||||
},
|
||||
|
||||
get tabs() {
|
||||
var tabs = [];
|
||||
var browsers = this._tabbrowser.browsers;
|
||||
for (var i=0; i<browsers.length; i++)
|
||||
tabs.push(new BrowserTab(this, browsers[i]));
|
||||
tabs.push(getBrowserTab(this, browsers[i]));
|
||||
return tabs;
|
||||
},
|
||||
|
||||
get activeTab() {
|
||||
return new BrowserTab(this, this._tabbrowser.selectedBrowser);
|
||||
},
|
||||
open : function win_open(aURI) {
|
||||
return new BrowserTab(this, this._tabbrowser.addTab(aURI.spec).linkedBrowser);
|
||||
},
|
||||
_shutdown : function win_shutdown() {
|
||||
for (var type in this._cleanup)
|
||||
this._tabbrowser.removeEventListener(type, this._cleanup[type], true);
|
||||
this._cleanup = null;
|
||||
|
||||
this._window = null;
|
||||
this._tabbrowser = null;
|
||||
this._events = null;
|
||||
return getBrowserTab(this, this._tabbrowser.selectedBrowser);
|
||||
},
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.fuelIWindow])
|
||||
open: function win_open(aURI) {
|
||||
return getBrowserTab(this, this._tabbrowser.addTab(aURI.spec).linkedBrowser);
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.fuelIWindow])
|
||||
};
|
||||
|
||||
//=================================================
|
||||
// BrowserTab implementation
|
||||
|
||||
var fuelBrowserTabMap = new WeakMap();
|
||||
function getBrowserTab(aFUELWindow, aBrowser) {
|
||||
let fuelBrowserTab = fuelBrowserTabMap.get(aBrowser);
|
||||
if (!fuelBrowserTab) {
|
||||
fuelBrowserTab = new BrowserTab(aFUELWindow, aBrowser);
|
||||
fuelBrowserTabMap.set(aBrowser, fuelBrowserTab);
|
||||
}
|
||||
else {
|
||||
// This tab may have moved to another window, so make sure its cached
|
||||
// window is up-to-date.
|
||||
fuelBrowserTab._window = aFUELWindow;
|
||||
}
|
||||
|
||||
return fuelBrowserTab;
|
||||
}
|
||||
|
||||
// Don't call new BrowserTab() directly; call getBrowserTab instead.
|
||||
function BrowserTab(aFUELWindow, aBrowser) {
|
||||
this._window = aFUELWindow;
|
||||
this._tabbrowser = aFUELWindow._tabbrowser;
|
||||
this._browser = aBrowser;
|
||||
this._events = new Events();
|
||||
this._cleanup = {};
|
||||
|
||||
this._watch("load");
|
||||
|
||||
var self = this;
|
||||
gShutdown.push(function() { self._shutdown(); });
|
||||
}
|
||||
|
||||
BrowserTab.prototype = {
|
||||
get _tabbrowser() {
|
||||
return this._window._tabbrowser;
|
||||
},
|
||||
|
||||
get uri() {
|
||||
return this._browser.currentURI;
|
||||
},
|
||||
@ -175,17 +199,12 @@ BrowserTab.prototype = {
|
||||
/*
|
||||
* Helper used to setup event handlers on the XBL element
|
||||
*/
|
||||
_watch : function bt_watch(aType) {
|
||||
var self = this;
|
||||
this._browser.addEventListener(aType,
|
||||
this._cleanup[aType] = function(e){ self._event(e); },
|
||||
true);
|
||||
_watch: function bt_watch(aType) {
|
||||
this._browser.addEventListener(aType, this,
|
||||
/* useCapture = */ true);
|
||||
},
|
||||
|
||||
/*
|
||||
* Helper event callback used to redirect events made on the XBL element
|
||||
*/
|
||||
_event : function bt_event(aEvent) {
|
||||
handleEvent: function bt_handleEvent(aEvent) {
|
||||
if (aEvent.type == "load") {
|
||||
if (!(aEvent.originalTarget instanceof Ci.nsIDOMDocument))
|
||||
return;
|
||||
@ -199,44 +218,33 @@ BrowserTab.prototype = {
|
||||
/*
|
||||
* Helper used to determine the index offset of the browsertab
|
||||
*/
|
||||
_getTab : function bt_gettab() {
|
||||
_getTab: function bt_gettab() {
|
||||
var tabs = this._tabbrowser.tabs;
|
||||
return tabs[this.index] || null;
|
||||
},
|
||||
|
||||
load : function bt_load(aURI) {
|
||||
load: function bt_load(aURI) {
|
||||
this._browser.loadURI(aURI.spec, null, null);
|
||||
},
|
||||
|
||||
focus : function bt_focus() {
|
||||
focus: function bt_focus() {
|
||||
this._tabbrowser.selectedTab = this._getTab();
|
||||
this._tabbrowser.focus();
|
||||
},
|
||||
|
||||
close : function bt_close() {
|
||||
close: function bt_close() {
|
||||
this._tabbrowser.removeTab(this._getTab());
|
||||
},
|
||||
|
||||
moveBefore : function bt_movebefore(aBefore) {
|
||||
moveBefore: function bt_movebefore(aBefore) {
|
||||
this._tabbrowser.moveTabTo(this._getTab(), aBefore.index);
|
||||
},
|
||||
|
||||
moveToEnd : function bt_moveend() {
|
||||
moveToEnd: function bt_moveend() {
|
||||
this._tabbrowser.moveTabTo(this._getTab(), this._tabbrowser.browsers.length);
|
||||
},
|
||||
|
||||
_shutdown : function bt_shutdown() {
|
||||
for (var type in this._cleanup)
|
||||
this._browser.removeEventListener(type, this._cleanup[type], true);
|
||||
this._cleanup = null;
|
||||
|
||||
this._window = null;
|
||||
this._tabbrowser = null;
|
||||
this._browser = null;
|
||||
this._events = null;
|
||||
},
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBrowserTab])
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.fuelIBrowserTab])
|
||||
};
|
||||
|
||||
|
||||
@ -251,52 +259,177 @@ Annotations.prototype = {
|
||||
return Utilities.annotations.getItemAnnotationNames(this._id);
|
||||
},
|
||||
|
||||
has : function ann_has(aName) {
|
||||
has: function ann_has(aName) {
|
||||
return Utilities.annotations.itemHasAnnotation(this._id, aName);
|
||||
},
|
||||
|
||||
get : function(aName) {
|
||||
get: function ann_get(aName) {
|
||||
if (this.has(aName))
|
||||
return Utilities.annotations.getItemAnnotation(this._id, aName);
|
||||
return null;
|
||||
},
|
||||
|
||||
set : function(aName, aValue, aExpiration) {
|
||||
set: function ann_set(aName, aValue, aExpiration) {
|
||||
Utilities.annotations.setItemAnnotation(this._id, aName, aValue, 0, aExpiration);
|
||||
},
|
||||
|
||||
remove : function ann_remove(aName) {
|
||||
remove: function ann_remove(aName) {
|
||||
if (aName)
|
||||
Utilities.annotations.removeItemAnnotation(this._id, aName);
|
||||
},
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.fuelIAnnotations])
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.fuelIAnnotations])
|
||||
};
|
||||
|
||||
|
||||
//=================================================
|
||||
// BookmarksObserver implementation (internal class)
|
||||
//
|
||||
// BookmarksObserver is a global singleton which watches the browser's
|
||||
// bookmarks and sends you events when things change.
|
||||
//
|
||||
// You can register three different kinds of event listeners on
|
||||
// BookmarksObserver, using addListener, addFolderListener, and
|
||||
// addRootlistener.
|
||||
//
|
||||
// - addListener(aId, aEvent, aListener) lets you listen to a specific
|
||||
// bookmark. You can listen to the "change", "move", and "remove" events.
|
||||
//
|
||||
// - addFolderListener(aId, aEvent, aListener) lets you listen to a specific
|
||||
// bookmark folder. You can listen to "addchild" and "removechild".
|
||||
//
|
||||
// - addRootListener(aEvent, aListener) lets you listen to the root bookmark
|
||||
// node. This lets you hear "add", "remove", and "change" events on all
|
||||
// bookmarks.
|
||||
//
|
||||
|
||||
function BookmarksObserver() {
|
||||
this._eventsDict = {};
|
||||
this._folderEventsDict = {};
|
||||
this._rootEvents = new Events();
|
||||
Utilities.bookmarks.addObserver(this, /* ownsWeak = */ true);
|
||||
}
|
||||
|
||||
BookmarksObserver.prototype = {
|
||||
onBeginUpdateBatch: function () {},
|
||||
onEndUpdateBatch: function () {},
|
||||
onBeforeItemRemoved: function () {},
|
||||
onItemVisited: function () {},
|
||||
|
||||
onItemAdded: function bo_onItemAdded(aId, aFolder, aIndex, aItemType, aURI) {
|
||||
this._rootEvents.dispatch("add", aId);
|
||||
this._dispatchToEvents("addchild", aId, this._folderEventsDict[aFolder]);
|
||||
},
|
||||
|
||||
onItemRemoved: function bo_onItemRemoved(aId, aFolder, aIndex) {
|
||||
this._rootEvents.dispatch("remove", aId);
|
||||
this._dispatchToEvents("remove", aId, this._eventsDict[aId]);
|
||||
this._dispatchToEvents("removechild", aId, this._folderEventsDict[aFolder]);
|
||||
},
|
||||
|
||||
onItemChanged: function bo_onItemChanged(aId, aProperty, aIsAnnotationProperty, aValue) {
|
||||
this._rootEvents.dispatch("change", aProperty);
|
||||
this._dispatchToEvents("change", aProperty, this._eventsDict[aId]);
|
||||
},
|
||||
|
||||
onItemMoved: function bo_onItemMoved(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
|
||||
this._dispatchToEvents("move", aId, this._eventsDict[aId]);
|
||||
},
|
||||
|
||||
_dispatchToEvents: function bo_dispatchToEvents(aEvent, aData, aEvents) {
|
||||
if (aEvents) {
|
||||
aEvents.dispatch(aEvent, aData);
|
||||
}
|
||||
},
|
||||
|
||||
_addListenerToDict: function bo_addListenerToDict(aId, aEvent, aListener, aDict) {
|
||||
var events = aDict[aId];
|
||||
if (!events) {
|
||||
events = new Events();
|
||||
aDict[aId] = events;
|
||||
}
|
||||
events.addListener(aEvent, aListener);
|
||||
},
|
||||
|
||||
_removeListenerFromDict: function bo_removeListenerFromDict(aId, aEvent, aListener, aDict) {
|
||||
var events = aDict[aId];
|
||||
if (!events) {
|
||||
return;
|
||||
}
|
||||
events.removeListener(aEvent, aListener);
|
||||
if (events._listeners.length == 0) {
|
||||
delete aDict[aId];
|
||||
}
|
||||
},
|
||||
|
||||
addListener: function bo_addListener(aId, aEvent, aListener) {
|
||||
this._addListenerToDict(aId, aEvent, aListener, this._eventsDict);
|
||||
},
|
||||
|
||||
removeListener: function bo_removeListener(aId, aEvent, aListener) {
|
||||
this._removeListenerFromDict(aId, aEvent, aListener, this._eventsDict);
|
||||
},
|
||||
|
||||
addFolderListener: function addFolderListener(aId, aEvent, aListener) {
|
||||
this._addListenerToDict(aId, aEvent, aListener, this._folderEventsDict);
|
||||
},
|
||||
|
||||
removeFolderListener: function removeFolderListener(aId, aEvent, aListener) {
|
||||
this._removeListenerFromDict(aId, aEvent, aListener, this._folderEventsDict);
|
||||
},
|
||||
|
||||
addRootListener: function addRootListener(aEvent, aListener) {
|
||||
this._rootEvents.addListener(aEvent, aListener);
|
||||
},
|
||||
|
||||
removeRootListener: function removeRootListener(aEvent, aListener) {
|
||||
this._rootEvents.removeListener(aEvent, aListener);
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarksObserver,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
//=================================================
|
||||
// Bookmark implementation
|
||||
//
|
||||
// Bookmark event listeners are stored in BookmarksObserver, not in the
|
||||
// Bookmark objects themselves. Thus, you don't have to hold on to a Bookmark
|
||||
// object in order for your event listener to stay valid, and Bookmark objects
|
||||
// not kept alive by the extension can be GC'ed.
|
||||
//
|
||||
// A consequence of this is that if you have two different Bookmark objects x
|
||||
// and y for the same bookmark (i.e., x != y but x.id == y.id), and you do
|
||||
//
|
||||
// x.addListener("foo", fun);
|
||||
// y.removeListener("foo", fun);
|
||||
//
|
||||
// the second line will in fact remove the listener added in the first line.
|
||||
//
|
||||
|
||||
function Bookmark(aId, aParent, aType) {
|
||||
this._id = aId;
|
||||
this._parent = aParent;
|
||||
this._type = aType || "bookmark";
|
||||
this._annotations = new Annotations(this._id);
|
||||
this._events = new Events();
|
||||
|
||||
Utilities.bookmarks.addObserver(this, false);
|
||||
|
||||
// Our _events object forwards to bookmarksObserver.
|
||||
var self = this;
|
||||
gShutdown.push(function() { self._shutdown(); });
|
||||
this._events = {
|
||||
addListener: function bookmarkevents_al(aEvent, aListener) {
|
||||
Utilities.bookmarksObserver.addListener(self._id, aEvent, aListener);
|
||||
},
|
||||
removeListener: function bookmarkevents_rl(aEvent, aListener) {
|
||||
Utilities.bookmarksObserver.removeListener(self._id, aEvent, aListener);
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents])
|
||||
};
|
||||
|
||||
// For our onItemMoved listener, which updates this._parent.
|
||||
Utilities.bookmarks.addObserver(this, /* ownsWeak = */ true);
|
||||
}
|
||||
|
||||
Bookmark.prototype = {
|
||||
_shutdown : function bm_shutdown() {
|
||||
this._annotations = null;
|
||||
this._events = null;
|
||||
|
||||
Utilities.bookmarks.removeObserver(this);
|
||||
},
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
},
|
||||
@ -358,66 +491,86 @@ Bookmark.prototype = {
|
||||
Utilities.bookmarks.removeItem(this._id);
|
||||
},
|
||||
|
||||
// observer
|
||||
onBeginUpdateBatch : function bm_obub() {
|
||||
},
|
||||
onBeginUpdateBatch: function () {},
|
||||
onEndUpdateBatch: function () {},
|
||||
onItemAdded: function () {},
|
||||
onBeforeItemRemoved: function () {},
|
||||
onItemVisited: function () {},
|
||||
onItemRemoved: function () {},
|
||||
onItemChanged: function () {},
|
||||
|
||||
onEndUpdateBatch : function bm_oeub() {
|
||||
},
|
||||
|
||||
onItemAdded : function bm_oia(aId, aFolder, aIndex, aItemType, aURI) {
|
||||
// bookmark object doesn't exist at this point
|
||||
},
|
||||
|
||||
onBeforeItemRemoved : function bm_obir(aId) {
|
||||
},
|
||||
|
||||
onItemRemoved : function bm_oir(aId, aFolder, aIndex) {
|
||||
if (this._id == aId)
|
||||
this._events.dispatch("remove", aId);
|
||||
},
|
||||
|
||||
onItemChanged : function bm_oic(aId, aProperty, aIsAnnotationProperty, aValue) {
|
||||
if (this._id == aId)
|
||||
this._events.dispatch("change", aProperty);
|
||||
},
|
||||
|
||||
onItemVisited: function bm_oiv(aId, aVisitID, aTime) {
|
||||
},
|
||||
|
||||
onItemMoved: function bm_oim(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
|
||||
if (this._id == aId) {
|
||||
onItemMoved: function(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
|
||||
if (aId == this._id) {
|
||||
this._parent = new BookmarkFolder(aNewParent, Utilities.bookmarks.getFolderIdForItem(aNewParent));
|
||||
this._events.dispatch("move", aId);
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBookmark, Ci.nsINavBookmarkObserver])
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.fuelIBookmark,
|
||||
Ci.nsINavBookmarksObserver,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
|
||||
//=================================================
|
||||
// BookmarkFolder implementation
|
||||
//
|
||||
// As with Bookmark, events on BookmarkFolder are handled by the
|
||||
// BookmarksObserver singleton.
|
||||
//
|
||||
|
||||
function BookmarkFolder(aId, aParent) {
|
||||
this._id = aId;
|
||||
this._parent = aParent;
|
||||
this._annotations = new Annotations(this._id);
|
||||
this._events = new Events();
|
||||
|
||||
Utilities.bookmarks.addObserver(this, false);
|
||||
// Our event listeners are handled by the BookmarksObserver singleton. This
|
||||
// is a bit complicated because there are three different kinds of events we
|
||||
// might want to listen to here:
|
||||
//
|
||||
// - If this._parent is null, we're the root bookmark folder, and all our
|
||||
// listeners should be root listeners.
|
||||
//
|
||||
// - Otherwise, events ending with "child" (addchild, removechild) are
|
||||
// handled by a folder listener.
|
||||
//
|
||||
// - Other events are handled by a vanilla bookmark listener.
|
||||
|
||||
var self = this;
|
||||
gShutdown.push(function() { self._shutdown(); });
|
||||
this._events = {
|
||||
addListener: function bmfevents_al(aEvent, aListener) {
|
||||
if (self._parent) {
|
||||
if (/child$/.test(aEvent)) {
|
||||
Utilities.bookmarksObserver.addFolderListener(self._id, aEvent, aListener);
|
||||
}
|
||||
else {
|
||||
Utilities.bookmarksObserver.addListener(self._id, aEvent, aListener);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Utilities.bookmarksObserver.addRootListener(aEvent, aListener);
|
||||
}
|
||||
},
|
||||
removeListener: function bmfevents_rl(aEvent, aListener) {
|
||||
if (self._parent) {
|
||||
if (/child$/.test(aEvent)) {
|
||||
Utilities.bookmarksObserver.removeFolderListener(self._id, aEvent, aListener);
|
||||
}
|
||||
else {
|
||||
Utilities.bookmarksObserver.removeListener(self._id, aEvent, aListener);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Utilities.bookmarksObserver.removeRootListener(aEvent, aListener);
|
||||
}
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents])
|
||||
};
|
||||
|
||||
// For our onItemMoved listener, which updates this._parent.
|
||||
Utilities.bookmarks.addObserver(this, /* ownsWeak = */ true);
|
||||
}
|
||||
|
||||
BookmarkFolder.prototype = {
|
||||
_shutdown : function bmf_shutdown() {
|
||||
this._annotations = null;
|
||||
this._events = null;
|
||||
|
||||
Utilities.bookmarks.removeObserver(this);
|
||||
},
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
},
|
||||
@ -489,93 +642,53 @@ BookmarkFolder.prototype = {
|
||||
return items;
|
||||
},
|
||||
|
||||
addBookmark : function bmf_addbm(aTitle, aUri) {
|
||||
addBookmark: function bmf_addbm(aTitle, aUri) {
|
||||
var newBookmarkID = Utilities.bookmarks.insertBookmark(this._id, aUri, Utilities.bookmarks.DEFAULT_INDEX, aTitle);
|
||||
var newBookmark = new Bookmark(newBookmarkID, this, "bookmark");
|
||||
return newBookmark;
|
||||
},
|
||||
|
||||
addSeparator : function bmf_addsep() {
|
||||
addSeparator: function bmf_addsep() {
|
||||
var newBookmarkID = Utilities.bookmarks.insertSeparator(this._id, Utilities.bookmarks.DEFAULT_INDEX);
|
||||
var newBookmark = new Bookmark(newBookmarkID, this, "separator");
|
||||
return newBookmark;
|
||||
},
|
||||
|
||||
addFolder : function bmf_addfolder(aTitle) {
|
||||
addFolder: function bmf_addfolder(aTitle) {
|
||||
var newFolderID = Utilities.bookmarks.createFolder(this._id, aTitle, Utilities.bookmarks.DEFAULT_INDEX);
|
||||
var newFolder = new BookmarkFolder(newFolderID, this);
|
||||
return newFolder;
|
||||
},
|
||||
|
||||
remove : function bmf_remove() {
|
||||
remove: function bmf_remove() {
|
||||
Utilities.bookmarks.removeItem(this._id);
|
||||
},
|
||||
|
||||
// observer
|
||||
onBeginUpdateBatch : function bmf_obub() {
|
||||
},
|
||||
onBeginUpdateBatch: function () {},
|
||||
onEndUpdateBatch : function () {},
|
||||
onItemAdded : function () {},
|
||||
onBeforeItemRemoved : function () {},
|
||||
onItemRemoved : function () {},
|
||||
onItemChanged : function () {},
|
||||
|
||||
onEndUpdateBatch : function bmf_oeub() {
|
||||
},
|
||||
|
||||
onItemAdded : function bmf_oia(aId, aFolder, aIndex, aItemType, aURI) {
|
||||
// handle root folder events
|
||||
if (!this._parent)
|
||||
this._events.dispatch("add", aId);
|
||||
|
||||
// handle this folder events
|
||||
if (this._id == aFolder)
|
||||
this._events.dispatch("addchild", aId);
|
||||
},
|
||||
|
||||
onBeforeItemRemoved : function bmf_oir(aId) {
|
||||
},
|
||||
|
||||
onItemRemoved : function bmf_oir(aId, aFolder, aIndex) {
|
||||
// handle root folder events
|
||||
if (!this._parent || this._id == aId)
|
||||
this._events.dispatch("remove", aId);
|
||||
|
||||
// handle this folder events
|
||||
if (this._id == aFolder)
|
||||
this._events.dispatch("removechild", aId);
|
||||
},
|
||||
|
||||
onItemChanged : function bmf_oic(aId, aProperty, aIsAnnotationProperty, aValue) {
|
||||
// handle root folder and this folder events
|
||||
if (!this._parent || this._id == aId)
|
||||
this._events.dispatch("change", aProperty);
|
||||
},
|
||||
|
||||
onItemVisited: function bmf_oiv(aId, aVisitID, aTime) {
|
||||
},
|
||||
|
||||
onItemMoved: function bmf_oim(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
|
||||
// handle this folder event, root folder cannot be moved
|
||||
onItemMoved: function bf_onItemMoved(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
|
||||
if (this._id == aId) {
|
||||
this._parent = new BookmarkFolder(aNewParent, Utilities.bookmarks.getFolderIdForItem(aNewParent));
|
||||
this._events.dispatch("move", aId);
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBookmarkFolder, Ci.nsINavBookmarkObserver])
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.fuelIBookmarkFolder,
|
||||
Ci.nsINavBookmarksObserver,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
//=================================================
|
||||
// BookmarkRoots implementation
|
||||
function BookmarkRoots() {
|
||||
var self = this;
|
||||
gShutdown.push(function() { self._shutdown(); });
|
||||
}
|
||||
|
||||
BookmarkRoots.prototype = {
|
||||
_shutdown : function bmr_shutdown() {
|
||||
this._menu = null;
|
||||
this._toolbar = null;
|
||||
this._tags = null;
|
||||
this._unfiled = null;
|
||||
},
|
||||
|
||||
get menu() {
|
||||
if (!this._menu)
|
||||
this._menu = new BookmarkFolder(Utilities.bookmarks.bookmarksMenuFolder, null);
|
||||
@ -604,7 +717,7 @@ BookmarkRoots.prototype = {
|
||||
return this._unfiled;
|
||||
},
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBookmarkRoots])
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.fuelIBookmarkRoots])
|
||||
};
|
||||
|
||||
|
||||
@ -632,21 +745,20 @@ var ApplicationFactory = {
|
||||
// Application constructor
|
||||
function Application() {
|
||||
this.initToolkitHelpers();
|
||||
this._bookmarks = null;
|
||||
}
|
||||
|
||||
//=================================================
|
||||
// Application implementation
|
||||
Application.prototype = {
|
||||
// for nsIClassInfo + XPCOMUtils
|
||||
classID: APPLICATION_CID,
|
||||
classID: APPLICATION_CID,
|
||||
|
||||
// redefine the default factory for XPCOMUtils
|
||||
_xpcom_factory: ApplicationFactory,
|
||||
|
||||
// for nsISupports
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.fuelIApplication, Ci.extIApplication,
|
||||
Ci.nsIObserver]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.fuelIApplication, Ci.extIApplication,
|
||||
Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
||||
|
||||
// for nsIClassInfo
|
||||
classInfo: XPCOMUtils.generateCI({classID: APPLICATION_CID,
|
||||
@ -662,7 +774,6 @@ Application.prototype = {
|
||||
this.__proto__.__proto__.observe.call(this, aSubject, aTopic, aData);
|
||||
if (aTopic == "xpcom-shutdown") {
|
||||
this._obs.removeObserver(this, "xpcom-shutdown");
|
||||
this._bookmarks = null;
|
||||
Utilities.free();
|
||||
}
|
||||
},
|
||||
@ -678,13 +789,13 @@ Application.prototype = {
|
||||
var browserEnum = Utilities.windowMediator.getEnumerator("navigator:browser");
|
||||
|
||||
while (browserEnum.hasMoreElements())
|
||||
win.push(new Window(browserEnum.getNext()));
|
||||
win.push(getWindow(browserEnum.getNext()));
|
||||
|
||||
return win;
|
||||
},
|
||||
|
||||
get activeWindow() {
|
||||
return new Window(Utilities.windowMediator.getMostRecentWindow("navigator:browser"));
|
||||
return getWindow(Utilities.windowMediator.getMostRecentWindow("navigator:browser"));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -148,9 +148,6 @@ function test() {
|
||||
pref.locked = false;
|
||||
ok(!pref.locked, "A single preference is unlocked.");
|
||||
|
||||
// Preference events tests disabled until bug 533290 is fixed
|
||||
return;
|
||||
|
||||
// check for change event when setting a value
|
||||
waitForExplicitFinish();
|
||||
Application.prefs.events.addListener("change", onPrefChange);
|
||||
@ -177,4 +174,6 @@ function onPrefChange2(evt) {
|
||||
finish();
|
||||
}
|
||||
|
||||
function onPrefChangeDummy(evt) { }
|
||||
function onPrefChangeDummy(evt) {
|
||||
ok(false, "onPrefChangeDummy shouldn't be invoked!");
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
var gLastFolderAction = "";
|
||||
var gLastBookmarkAction = "";
|
||||
var gLastRootAction = "";
|
||||
|
||||
function url(spec) {
|
||||
return Services.io.newURI(spec, null, null);
|
||||
@ -187,6 +188,24 @@ function test() {
|
||||
testFolderA.parent = testFolderB;
|
||||
is(testFolderA.parent.title, "folder-b", "Checking for new parent after moving folder");
|
||||
is(gLastFolderAction, "move", "Checking for event handler after moving folder");
|
||||
|
||||
// test events on the root
|
||||
root.events.addListener("add", onRootAdd);
|
||||
root.events.addListener("remove", onRootRemove);
|
||||
root.events.addListener("change", onRootChange);
|
||||
var testFolderC = root.addFolder("folder-c");
|
||||
is(gLastRootAction, "add");
|
||||
|
||||
root.events.removeListener("add", onRootAdd);
|
||||
gLastRootAction = "";
|
||||
var testFolderD = root.addFolder("folder-d");
|
||||
is(gLastRootAction, "");
|
||||
|
||||
testFolderC.remove();
|
||||
is(gLastRootAction, "remove");
|
||||
|
||||
testFolderD.description = "Foo";
|
||||
is(gLastRootAction, "bookmarkProperties/description");
|
||||
}
|
||||
|
||||
function onFolderChange(evt) {
|
||||
@ -220,3 +239,15 @@ function onBookmarkRemove(evt) {
|
||||
function onBookmarkMove(evt) {
|
||||
gLastBookmarkAction = evt.type;
|
||||
}
|
||||
|
||||
function onRootAdd(evt) {
|
||||
gLastRootAction = evt.type;
|
||||
}
|
||||
|
||||
function onRootRemove(evt) {
|
||||
gLastRootAction = evt.type;
|
||||
}
|
||||
|
||||
function onRootChange(evt) {
|
||||
gLastRootAction = evt.data;
|
||||
}
|
||||
|
@ -2380,45 +2380,32 @@ private void CancelNotification()
|
||||
|
||||
public String KillProcess(String sProcName, OutputStream out)
|
||||
{
|
||||
String sTmp = "";
|
||||
String sCmd = "kill";
|
||||
|
||||
String sRet = sErrorPrefix + "Unable to kill " + sProcName + "\n";
|
||||
ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
|
||||
List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses();
|
||||
int lcv = 0;
|
||||
String strProcName = "";
|
||||
int nPID = 0;
|
||||
String sFoundProcName = "";
|
||||
int nProcs = 0;
|
||||
boolean bFoundAppProcess = false;
|
||||
|
||||
if (lProcesses != null)
|
||||
if (lProcesses != null)
|
||||
nProcs = lProcesses.size();
|
||||
|
||||
for (lcv = 0; lcv < nProcs; lcv++)
|
||||
{
|
||||
if (lProcesses.get(lcv).processName.contains(sProcName))
|
||||
{
|
||||
strProcName = lProcesses.get(lcv).processName;
|
||||
nPID = lProcesses.get(lcv).pid;
|
||||
sRet = sErrorPrefix + "Failed to kill " + nPID + " " + strProcName + "\n";
|
||||
|
||||
sCmd += " " + nPID;
|
||||
sFoundProcName = lProcesses.get(lcv).processName;
|
||||
bFoundAppProcess = true;
|
||||
|
||||
try
|
||||
{
|
||||
pProc = Runtime.getRuntime().exec(this.getSuArgs(sCmd));
|
||||
pProc = Runtime.getRuntime().exec(this.getSuArgs("kill " + lProcesses.get(lcv).pid));
|
||||
RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
|
||||
outThrd.start();
|
||||
outThrd.join(15000);
|
||||
sTmp = outThrd.strOutput;
|
||||
String sTmp = outThrd.strOutput;
|
||||
Log.e("KILLPROCESS", sTmp);
|
||||
if (outThrd.nExitCode == 0) {
|
||||
sRet = "Successfully killed " + nPID + " " + strProcName + "\n";
|
||||
nPID = 0;
|
||||
break;
|
||||
} else {
|
||||
sRet = sErrorPrefix + "Failed to kill " + nPID + " " + strProcName + "\n";
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
@ -2429,31 +2416,30 @@ private void CancelNotification()
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Give the messages a chance to be processed
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nPID > 0)
|
||||
if (bFoundAppProcess)
|
||||
{
|
||||
sRet = "Successfully killed " + nPID + " " + strProcName + "\n";
|
||||
// Give the messages a chance to be processed
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
sRet = "Successfully killed " + sProcName + "\n";
|
||||
lProcesses = aMgr.getRunningAppProcesses();
|
||||
nProcs = 0;
|
||||
if (lProcesses != null)
|
||||
if (lProcesses != null)
|
||||
nProcs = lProcesses.size();
|
||||
for (lcv = 0; lcv < nProcs; lcv++)
|
||||
{
|
||||
if (lProcesses.get(lcv).processName.contains(sProcName))
|
||||
{
|
||||
sRet = sErrorPrefix + "Unable to kill " + nPID + " " + strProcName + "\n";
|
||||
sRet = sErrorPrefix + "Unable to kill " + sProcName + " (couldn't kill " + sFoundProcName +")\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2469,7 +2455,7 @@ private void CancelNotification()
|
||||
RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
|
||||
outThrd.start();
|
||||
outThrd.join(10000);
|
||||
sTmp = outThrd.strOutput;
|
||||
String sTmp = outThrd.strOutput;
|
||||
StringTokenizer stokLines = new StringTokenizer(sTmp, "\n");
|
||||
while(stokLines.hasMoreTokens())
|
||||
{
|
||||
@ -2490,7 +2476,7 @@ private void CancelNotification()
|
||||
if (sName.contains(sProcName))
|
||||
{
|
||||
NewKillProc(sPid, out);
|
||||
sRet = "Successfully killed " + sPid + " " + sName + "\n";
|
||||
sRet = "Successfully killed " + sName + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FileIOObject,
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(abort)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(progress)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mError)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileIOObject,
|
||||
@ -46,6 +47,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileIOObject,
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(abort)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(progress)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mError)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
FileIOObject::FileIOObject()
|
||||
|
@ -1160,31 +1160,6 @@ PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
|
||||
return SetAttrHelper(nsGkAtoms::_atom, aValue); \
|
||||
}
|
||||
|
||||
/**
|
||||
* A macro to implement the getter and setter for a given content
|
||||
* property that needs to set a positive integer. The method uses
|
||||
* the generic GetAttr and SetAttr methods. This macro is much like
|
||||
* the NS_IMPL_NON_NEGATIVE_INT_ATTR macro except the exception is
|
||||
* thrown also when the value is equal to 0.
|
||||
*/
|
||||
#define NS_IMPL_POSITIVE_INT_ATTR(_class, _method, _atom) \
|
||||
NS_IMPL_POSITIVE_INT_ATTR_DEFAULT_VALUE(_class, _method, _atom, 1)
|
||||
|
||||
#define NS_IMPL_POSITIVE_INT_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default) \
|
||||
NS_IMETHODIMP \
|
||||
_class::Get##_method(PRInt32* aValue) \
|
||||
{ \
|
||||
return GetIntAttr(nsGkAtoms::_atom, _default, aValue); \
|
||||
} \
|
||||
NS_IMETHODIMP \
|
||||
_class::Set##_method(PRInt32 aValue) \
|
||||
{ \
|
||||
if (aValue <= 0) { \
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR; \
|
||||
} \
|
||||
return SetIntAttr(nsGkAtoms::_atom, aValue); \
|
||||
}
|
||||
|
||||
/**
|
||||
* QueryInterface() implementation helper macros
|
||||
*/
|
||||
|
@ -8046,6 +8046,23 @@ private:
|
||||
bool mFirstParty;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if we started an asynchronous load (i.e., from the network), but
|
||||
* the document we're loading there hasn't yet become this docshell's active
|
||||
* document.
|
||||
*
|
||||
* When JustStartedNetworkLoad is true, you should be careful about modifying
|
||||
* mLoadType and mLSHE. These are both set when the asynchronous load first
|
||||
* starts, and the load expects that, when it eventually runs InternalLoad,
|
||||
* mLoadType and mLSHE will have their original values.
|
||||
*/
|
||||
bool
|
||||
nsDocShell::JustStartedNetworkLoad()
|
||||
{
|
||||
return mDocumentRequest &&
|
||||
mDocumentRequest != GetCurrentDocChannel();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::InternalLoad(nsIURI * aURI,
|
||||
nsIURI * aReferrer,
|
||||
@ -8462,7 +8479,16 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
||||
// See bug 737307.
|
||||
AutoRestore<PRUint32> loadTypeResetter(mLoadType);
|
||||
|
||||
mLoadType = aLoadType;
|
||||
// If a non-short-circuit load (i.e., a network load) is pending,
|
||||
// make this a replacement load, so that we don't add a SHEntry here
|
||||
// and the network load goes into the SHEntry it expects to.
|
||||
if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) {
|
||||
mLoadType = LOAD_NORMAL_REPLACE;
|
||||
}
|
||||
else {
|
||||
mLoadType = aLoadType;
|
||||
}
|
||||
|
||||
mURIResultedInDocument = true;
|
||||
|
||||
/* we need to assign mLSHE to aSHEntry right here, so that on History loads,
|
||||
@ -9662,6 +9688,16 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// Don't clobber the load type of an existing network load.
|
||||
AutoRestore<PRUint32> loadTypeResetter(mLoadType);
|
||||
|
||||
// pushState effectively becomes replaceState when we've started a network
|
||||
// load but haven't adopted its document yet. This mirrors what we do with
|
||||
// changes to the hash at this stage of the game.
|
||||
if (JustStartedNetworkLoad()) {
|
||||
aReplace = true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
|
||||
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
|
||||
|
||||
|
@ -660,6 +660,8 @@ protected:
|
||||
nsRefPtr<nsDocShell> mDocShell;
|
||||
};
|
||||
|
||||
bool JustStartedNetworkLoad();
|
||||
|
||||
// hash of session storages, keyed by domain
|
||||
nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorage> mStorages;
|
||||
|
||||
|
@ -7455,7 +7455,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
// binding a name) a new undefined property that's not already
|
||||
// defined on our prototype chain. This way we can access this
|
||||
// expando w/o ever getting back into XPConnect.
|
||||
if ((flags & JSRESOLVE_ASSIGNING) && !(flags & JSRESOLVE_WITH)) {
|
||||
if (flags & JSRESOLVE_ASSIGNING) {
|
||||
JSObject *realObj;
|
||||
wrapper->GetJSObject(&realObj);
|
||||
|
||||
|
@ -8992,7 +8992,175 @@ nsGlobalWindow::SetTimeoutOrInterval(bool aIsInterval, PRInt32 *aReturn)
|
||||
return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
|
||||
nsIScriptContext* aScx)
|
||||
{
|
||||
// Hold on to the timeout in case mExpr or mFunObj releases its
|
||||
// doc.
|
||||
nsRefPtr<nsTimeout> timeout = aTimeout;
|
||||
nsTimeout* last_running_timeout = mRunningTimeout;
|
||||
mRunningTimeout = timeout;
|
||||
timeout->mRunning = true;
|
||||
|
||||
// Push this timeout's popup control state, which should only be
|
||||
// eabled the first time a timeout fires that was created while
|
||||
// popups were enabled and with a delay less than
|
||||
// "dom.disable_open_click_delay".
|
||||
nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
|
||||
|
||||
// Clear the timeout's popup state, if any, to prevent interval
|
||||
// timeouts from repeatedly opening poups.
|
||||
timeout->mPopupState = openAbused;
|
||||
|
||||
++gRunningTimeoutDepth;
|
||||
++mTimeoutFiringDepth;
|
||||
|
||||
bool trackNestingLevel = !timeout->mIsInterval;
|
||||
PRUint32 nestingLevel;
|
||||
if (trackNestingLevel) {
|
||||
nestingLevel = sNestingLevel;
|
||||
sNestingLevel = timeout->mNestingLevel;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
|
||||
JSObject* scriptObject = handler->GetScriptObject();
|
||||
if (!scriptObject) {
|
||||
// Evaluate the timeout expression.
|
||||
const PRUnichar* script = handler->GetHandlerText();
|
||||
NS_ASSERTION(script, "timeout has no script nor handler text!");
|
||||
|
||||
const char* filename = nsnull;
|
||||
PRUint32 lineNo = 0;
|
||||
handler->GetLocation(&filename, &lineNo);
|
||||
|
||||
NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo);
|
||||
|
||||
bool is_undefined;
|
||||
aScx->EvaluateString(nsDependentString(script), FastGetGlobalJSObject(),
|
||||
timeout->mPrincipal, timeout->mPrincipal,
|
||||
filename, lineNo, JSVERSION_DEFAULT, nsnull,
|
||||
&is_undefined);
|
||||
} else {
|
||||
nsCOMPtr<nsIVariant> dummy;
|
||||
nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
|
||||
aScx->CallEventHandler(me, FastGetGlobalJSObject(),
|
||||
scriptObject, handler->GetArgv(),
|
||||
// XXXmarkh - consider allowing CallEventHandler to
|
||||
// accept nsnull?
|
||||
getter_AddRefs(dummy));
|
||||
|
||||
}
|
||||
|
||||
// We ignore any failures from calling EvaluateString() or
|
||||
// CallEventHandler() on the context here since we're in a loop
|
||||
// where we're likely to be running timeouts whose OS timers
|
||||
// didn't fire in time and we don't want to not fire those timers
|
||||
// now just because execution of one timer failed. We can't
|
||||
// propagate the error to anyone who cares about it from this
|
||||
// point anyway, and the script context should have already reported
|
||||
// the script error in the usual way - so we just drop it.
|
||||
|
||||
if (trackNestingLevel) {
|
||||
sNestingLevel = nestingLevel;
|
||||
}
|
||||
|
||||
--mTimeoutFiringDepth;
|
||||
--gRunningTimeoutDepth;
|
||||
|
||||
mRunningTimeout = last_running_timeout;
|
||||
timeout->mRunning = false;
|
||||
return timeout->mCleared;
|
||||
}
|
||||
|
||||
bool
|
||||
nsGlobalWindow::RescheduleTimeout(nsTimeout* aTimeout, const TimeStamp& now,
|
||||
bool aRunningPendingTimeouts)
|
||||
{
|
||||
if (!aTimeout->mIsInterval) {
|
||||
if (aTimeout->mTimer) {
|
||||
// The timeout still has an OS timer, and it's not an interval,
|
||||
// that means that the OS timer could still fire; cancel the OS
|
||||
// timer and release its reference to the timeout.
|
||||
aTimeout->mTimer->Cancel();
|
||||
aTimeout->mTimer = nsnull;
|
||||
aTimeout->Release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute time to next timeout for interval timer.
|
||||
// Make sure nextInterval is at least DOMMinTimeoutValue().
|
||||
TimeDuration nextInterval =
|
||||
TimeDuration::FromMilliseconds(NS_MAX(aTimeout->mInterval,
|
||||
PRUint32(DOMMinTimeoutValue())));
|
||||
|
||||
// If we're running pending timeouts, set the next interval to be
|
||||
// relative to "now", and not to when the timeout that was pending
|
||||
// should have fired.
|
||||
TimeStamp firingTime;
|
||||
if (aRunningPendingTimeouts) {
|
||||
firingTime = now + nextInterval;
|
||||
} else {
|
||||
firingTime = aTimeout->mWhen + nextInterval;
|
||||
}
|
||||
|
||||
TimeStamp currentNow = TimeStamp::Now();
|
||||
TimeDuration delay = firingTime - currentNow;
|
||||
|
||||
// And make sure delay is nonnegative; that might happen if the timer
|
||||
// thread is firing our timers somewhat early or if they're taking a long
|
||||
// time to run the callback.
|
||||
if (delay < TimeDuration(0)) {
|
||||
delay = TimeDuration(0);
|
||||
}
|
||||
|
||||
if (!aTimeout->mTimer) {
|
||||
NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
|
||||
"How'd our timer end up null if we're not frozen or "
|
||||
"suspended?");
|
||||
|
||||
aTimeout->mTimeRemaining = delay;
|
||||
return true;
|
||||
}
|
||||
|
||||
aTimeout->mWhen = currentNow + delay;
|
||||
|
||||
// Reschedule the OS timer. Don't bother returning any error codes if
|
||||
// this fails since the callers of this method don't care about them.
|
||||
|
||||
// Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
|
||||
// PRTime to make the division do the right thing on 64-bit
|
||||
// platforms whether delay is positive or negative (which we
|
||||
// know is always positive here, but cast anyways for
|
||||
// consistency).
|
||||
nsresult rv = aTimeout->mTimer->
|
||||
InitWithFuncCallback(TimerCallback, aTimeout,
|
||||
delay.ToMilliseconds(),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Error initializing timer for DOM timeout!");
|
||||
|
||||
// We failed to initialize the new OS timer, this timer does
|
||||
// us no good here so we just cancel it (just in case) and
|
||||
// null out the pointer to the OS timer, this will release the
|
||||
// OS timer. As we continue executing the code below we'll end
|
||||
// up deleting the timeout since it's not an interval timeout
|
||||
// any more (since timeout->mTimer == nsnull).
|
||||
aTimeout->mTimer->Cancel();
|
||||
aTimeout->mTimer = nsnull;
|
||||
|
||||
// Now that the OS timer no longer has a reference to the
|
||||
// timeout we need to drop that reference.
|
||||
aTimeout->Release();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
|
||||
{
|
||||
@ -9133,90 +9301,8 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
|
||||
}
|
||||
|
||||
// This timeout is good to run
|
||||
nsTimeout *last_running_timeout = mRunningTimeout;
|
||||
mRunningTimeout = timeout;
|
||||
timeout->mRunning = true;
|
||||
++timeoutsRan;
|
||||
|
||||
// Push this timeout's popup control state, which should only be
|
||||
// eabled the first time a timeout fires that was created while
|
||||
// popups were enabled and with a delay less than
|
||||
// "dom.disable_open_click_delay".
|
||||
nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
|
||||
|
||||
// Clear the timeout's popup state, if any, to prevent interval
|
||||
// timeouts from repeatedly opening poups.
|
||||
timeout->mPopupState = openAbused;
|
||||
|
||||
// Hold on to the timeout in case mExpr or mFunObj releases its
|
||||
// doc.
|
||||
timeout->AddRef();
|
||||
|
||||
++gRunningTimeoutDepth;
|
||||
++mTimeoutFiringDepth;
|
||||
|
||||
bool trackNestingLevel = !timeout->mIsInterval;
|
||||
PRUint32 nestingLevel;
|
||||
if (trackNestingLevel) {
|
||||
nestingLevel = sNestingLevel;
|
||||
sNestingLevel = timeout->mNestingLevel;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
|
||||
JSObject* scriptObject = handler->GetScriptObject();
|
||||
if (!scriptObject) {
|
||||
// Evaluate the timeout expression.
|
||||
const PRUnichar *script = handler->GetHandlerText();
|
||||
NS_ASSERTION(script, "timeout has no script nor handler text!");
|
||||
|
||||
const char *filename = nsnull;
|
||||
PRUint32 lineNo = 0;
|
||||
handler->GetLocation(&filename, &lineNo);
|
||||
|
||||
NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo);
|
||||
|
||||
bool is_undefined;
|
||||
scx->EvaluateString(nsDependentString(script), FastGetGlobalJSObject(),
|
||||
timeout->mPrincipal, timeout->mPrincipal,
|
||||
filename, lineNo, JSVERSION_DEFAULT, nsnull,
|
||||
&is_undefined);
|
||||
} else {
|
||||
nsCOMPtr<nsIVariant> dummy;
|
||||
nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
|
||||
scx->CallEventHandler(me, FastGetGlobalJSObject(),
|
||||
scriptObject, handler->GetArgv(),
|
||||
// XXXmarkh - consider allowing CallEventHandler to
|
||||
// accept nsnull?
|
||||
getter_AddRefs(dummy));
|
||||
|
||||
}
|
||||
handler = nsnull; // drop reference before dropping timeout refs.
|
||||
|
||||
if (trackNestingLevel) {
|
||||
sNestingLevel = nestingLevel;
|
||||
}
|
||||
|
||||
--mTimeoutFiringDepth;
|
||||
--gRunningTimeoutDepth;
|
||||
|
||||
mRunningTimeout = last_running_timeout;
|
||||
timeout->mRunning = false;
|
||||
|
||||
// We ignore any failures from calling EvaluateString() or
|
||||
// CallEventHandler() on the context here since we're in a loop
|
||||
// where we're likely to be running timeouts whose OS timers
|
||||
// didn't fire in time and we don't want to not fire those timers
|
||||
// now just because execution of one timer failed. We can't
|
||||
// propagate the error to anyone who cares about it from this
|
||||
// point anyway, and the script context should have already reported
|
||||
// the script error in the usual way - so we just drop it.
|
||||
|
||||
// If all timeouts were cleared and |timeout != aTimeout| then
|
||||
// |timeout| may be the last reference to the timeout so check if
|
||||
// it was cleared before releasing it.
|
||||
bool timeout_was_cleared = timeout->mCleared;
|
||||
|
||||
timeout->Release();
|
||||
bool timeout_was_cleared = RunTimeoutHandler(timeout, scx);
|
||||
|
||||
if (timeout_was_cleared) {
|
||||
// The running timeout's window was cleared, this means that
|
||||
@ -9229,96 +9315,9 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
|
||||
return;
|
||||
}
|
||||
|
||||
bool isInterval = false;
|
||||
|
||||
// If we have a regular interval timer, we re-schedule the
|
||||
// timeout, accounting for clock drift.
|
||||
if (timeout->mIsInterval) {
|
||||
// Compute time to next timeout for interval timer.
|
||||
// Make sure nextInterval is at least DOMMinTimeoutValue().
|
||||
TimeDuration nextInterval =
|
||||
TimeDuration::FromMilliseconds(NS_MAX(timeout->mInterval,
|
||||
PRUint32(DOMMinTimeoutValue())));
|
||||
|
||||
// If we're running pending timeouts because they've been temporarily
|
||||
// disabled (!aTimeout), set the next interval to be relative to "now",
|
||||
// and not to when the timeout that was pending should have fired.
|
||||
TimeStamp firingTime;
|
||||
if (!aTimeout)
|
||||
firingTime = now + nextInterval;
|
||||
else
|
||||
firingTime = timeout->mWhen + nextInterval;
|
||||
|
||||
TimeStamp currentNow = TimeStamp::Now();
|
||||
TimeDuration delay = firingTime - currentNow;
|
||||
|
||||
// And make sure delay is nonnegative; that might happen if the timer
|
||||
// thread is firing our timers somewhat early or if they're taking a long
|
||||
// time to run the callback.
|
||||
if (delay < TimeDuration(0)) {
|
||||
delay = TimeDuration(0);
|
||||
}
|
||||
|
||||
if (timeout->mTimer) {
|
||||
timeout->mWhen = currentNow + delay; // firingTime unless delay got
|
||||
// clamped, in which case it's
|
||||
// currentNow.
|
||||
|
||||
// Reschedule the OS timer. Don't bother returning any error
|
||||
// codes if this fails since the callers of this method
|
||||
// doesn't care about them nobody who cares about them
|
||||
// anyways.
|
||||
|
||||
// Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
|
||||
// PRTime to make the division do the right thing on 64-bit
|
||||
// platforms whether delay is positive or negative (which we
|
||||
// know is always positive here, but cast anyways for
|
||||
// consistency).
|
||||
nsresult rv = timeout->mTimer->
|
||||
InitWithFuncCallback(TimerCallback, timeout,
|
||||
delay.ToMilliseconds(),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Error initializing timer for DOM timeout!");
|
||||
|
||||
// We failed to initialize the new OS timer, this timer does
|
||||
// us no good here so we just cancel it (just in case) and
|
||||
// null out the pointer to the OS timer, this will release the
|
||||
// OS timer. As we continue executing the code below we'll end
|
||||
// up deleting the timeout since it's not an interval timeout
|
||||
// any more (since timeout->mTimer == nsnull).
|
||||
timeout->mTimer->Cancel();
|
||||
timeout->mTimer = nsnull;
|
||||
|
||||
// Now that the OS timer no longer has a reference to the
|
||||
// timeout we need to drop that reference.
|
||||
timeout->Release();
|
||||
}
|
||||
} else {
|
||||
NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
|
||||
"How'd our timer end up null if we're not frozen or "
|
||||
"suspended?");
|
||||
|
||||
timeout->mTimeRemaining = delay;
|
||||
isInterval = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout->mTimer) {
|
||||
if (timeout->mIsInterval) {
|
||||
isInterval = true;
|
||||
} else {
|
||||
// The timeout still has an OS timer, and it's not an
|
||||
// interval, that means that the OS timer could still fire (if
|
||||
// it didn't already, i.e. aTimeout == timeout), cancel the OS
|
||||
// timer and release its reference to the timeout.
|
||||
timeout->mTimer->Cancel();
|
||||
timeout->mTimer = nsnull;
|
||||
|
||||
timeout->Release();
|
||||
}
|
||||
}
|
||||
bool needsReinsertion = RescheduleTimeout(timeout, now, !aTimeout);
|
||||
|
||||
// Running a timeout can cause another timeout to be deleted, so
|
||||
// we need to reset the pointer to the following timeout.
|
||||
@ -9326,9 +9325,10 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
|
||||
|
||||
PR_REMOVE_LINK(timeout);
|
||||
|
||||
if (isInterval) {
|
||||
// Reschedule an interval timeout. Insert interval timeout
|
||||
// onto list sorted in deadline order.
|
||||
if (needsReinsertion) {
|
||||
NS_ASSERTION(timeout->mTimer,
|
||||
"rescheduling interval timeout without a timer!");
|
||||
// Insert interval timeout onto list sorted in deadline order.
|
||||
// AddRefs timeout.
|
||||
InsertTimeoutIntoList(timeout);
|
||||
}
|
||||
|
@ -659,6 +659,11 @@ protected:
|
||||
// The timeout implementation functions.
|
||||
void RunTimeout(nsTimeout *aTimeout);
|
||||
void RunTimeout() { RunTimeout(nsnull); }
|
||||
// Return true if |aTimeout| was cleared while its handler ran.
|
||||
bool RunTimeoutHandler(nsTimeout* aTimeout, nsIScriptContext* aScx);
|
||||
// Return true if |aTimeout| needs to be reinserted into the timeout list.
|
||||
bool RescheduleTimeout(nsTimeout* aTimeout, const TimeStamp& now,
|
||||
bool aRunningPendingTimeouts);
|
||||
|
||||
void ClearAllTimeouts();
|
||||
// Insert aTimeout into the list, before all timeouts that would
|
||||
|
@ -13,6 +13,8 @@
|
||||
* the generated code itself.
|
||||
*/
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsString.h"
|
||||
@ -63,10 +65,19 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Ditto for flat strings.
|
||||
*/
|
||||
explicit nsDependentJSString(JSFlatString* fstr)
|
||||
: nsDependentString(JS_GetFlatStringChars(fstr),
|
||||
JS_GetStringLength(JS_FORGET_STRING_FLATNESS(fstr)))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* For all other strings, the nsDependentJSString object should be default
|
||||
* constructed, which leaves it empty (this->IsEmpty()), and initialized with
|
||||
* one of the fallible init() methods below.
|
||||
* one of the init() methods below.
|
||||
*/
|
||||
|
||||
nsDependentJSString()
|
||||
@ -91,6 +102,12 @@ public:
|
||||
return init(aContext, JSVAL_TO_STRING(v));
|
||||
}
|
||||
|
||||
void init(JSFlatString* fstr)
|
||||
{
|
||||
MOZ_ASSERT(IsEmpty(), "init() on initialized string");
|
||||
new(this) nsDependentJSString(fstr);
|
||||
}
|
||||
|
||||
~nsDependentJSString()
|
||||
{
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ XPIDLSRCS = \
|
||||
nsIPluginHost.idl \
|
||||
nsIPluginInputStream.idl \
|
||||
nsIPluginInstanceOwner.idl \
|
||||
nsIPluginStreamInfo.idl \
|
||||
nsIPluginTag.idl \
|
||||
nsIPluginTagInfo.idl \
|
||||
nspluginroot.idl \
|
||||
|
@ -1,39 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* nsIPluginStreamInfo
|
||||
*
|
||||
* @status DEPRECATED
|
||||
*
|
||||
* Originally published XPCOM Plugin API is now deprecated
|
||||
* Developers are welcome to use NPAPI, please refer to:
|
||||
* http://mozilla.org/projects/plugins/
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nspluginroot.idl"
|
||||
|
||||
%{C++
|
||||
#include "npapi.h"
|
||||
%}
|
||||
|
||||
[uuid(A700845F-0E26-44EA-84F5-3BE5381F98D5)]
|
||||
interface nsIPluginStreamInfo : nsISupports
|
||||
{
|
||||
readonly attribute string contentType;
|
||||
|
||||
void isSeekable(out boolean aSeekable);
|
||||
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
readonly attribute unsigned long lastModified;
|
||||
|
||||
void getURL(out constCharPtr aURL);
|
||||
|
||||
void requestRead(in NPByteRangePtr aRangeList);
|
||||
|
||||
attribute long streamOffset;
|
||||
};
|
@ -19,6 +19,7 @@
|
||||
#include "nsNPAPIPlugin.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsNPAPIPluginStreamListener.h"
|
||||
#include "nsPluginStreamListenerPeer.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -533,11 +534,12 @@ nsNPAPIPlugin::RetainStream(NPStream *pstream, nsISupports **aRetainedPeer)
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
nsPluginStreamListenerPeer* peer = listener->GetStreamListenerPeer();
|
||||
if (!peer)
|
||||
nsIStreamListener* streamListener = listener->GetStreamListenerPeer();
|
||||
if (!streamListener) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
*aRetainedPeer = (nsISupports*) peer;
|
||||
*aRetainedPeer = streamListener;
|
||||
NS_ADDREF(*aRetainedPeer);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2510,10 +2512,10 @@ _requestread(NPStream *pstream, NPByteRange *rangeList)
|
||||
if (streamtype != NP_SEEK)
|
||||
return NPERR_STREAM_NOT_SEEKABLE;
|
||||
|
||||
if (!streamlistener->mStreamInfo)
|
||||
if (!streamlistener->mStreamListenerPeer)
|
||||
return NPERR_GENERIC_ERROR;
|
||||
|
||||
nsresult rv = streamlistener->mStreamInfo->RequestRead((NPByteRange *)rangeList);
|
||||
nsresult rv = streamlistener->mStreamListenerPeer->RequestRead((NPByteRange *)rangeList);
|
||||
if (NS_FAILED(rv))
|
||||
return NPERR_GENERIC_ERROR;
|
||||
|
||||
|
@ -137,7 +137,6 @@ nsNPAPIPluginStreamListener::nsNPAPIPluginStreamListener(nsNPAPIPluginInstance*
|
||||
: mStreamBuffer(nsnull),
|
||||
mNotifyURL(aURL ? PL_strdup(aURL) : nsnull),
|
||||
mInst(inst),
|
||||
mStreamListenerPeer(nsnull),
|
||||
mStreamBufferSize(0),
|
||||
mStreamBufferByteCount(0),
|
||||
mStreamType(NP_NORMAL),
|
||||
@ -215,7 +214,7 @@ nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason)
|
||||
if (!mInst || !mInst->CanFireNotifications())
|
||||
return rv;
|
||||
|
||||
mStreamInfo = NULL;
|
||||
mStreamListenerPeer = nsnull;
|
||||
|
||||
PluginDestructionGuard guard(mInst);
|
||||
|
||||
@ -279,7 +278,7 @@ nsNPAPIPluginStreamListener::CallURLNotify(NPReason reason)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNPAPIPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
|
||||
nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPeer)
|
||||
{
|
||||
if (!mInst || !mInst->CanFireNotifications())
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -303,18 +302,18 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
|
||||
PRUint16 streamType = NP_NORMAL;
|
||||
NPError error;
|
||||
|
||||
pluginInfo->GetURL(&mNPStreamWrapper->mNPStream.url);
|
||||
pluginInfo->GetLength((PRUint32*)&(mNPStreamWrapper->mNPStream.end));
|
||||
pluginInfo->GetLastModified((PRUint32*)&(mNPStreamWrapper->mNPStream.lastmodified));
|
||||
pluginInfo->IsSeekable(&seekable);
|
||||
pluginInfo->GetContentType(&contentType);
|
||||
streamPeer->GetURL(&mNPStreamWrapper->mNPStream.url);
|
||||
streamPeer->GetLength((PRUint32*)&(mNPStreamWrapper->mNPStream.end));
|
||||
streamPeer->GetLastModified((PRUint32*)&(mNPStreamWrapper->mNPStream.lastmodified));
|
||||
streamPeer->IsSeekable(&seekable);
|
||||
streamPeer->GetContentType(&contentType);
|
||||
|
||||
if (!mResponseHeaders.IsEmpty()) {
|
||||
mResponseHeaderBuf = PL_strdup(mResponseHeaders.get());
|
||||
mNPStreamWrapper->mNPStream.headers = mResponseHeaderBuf;
|
||||
}
|
||||
|
||||
mStreamInfo = pluginInfo;
|
||||
mStreamListenerPeer = streamPeer;
|
||||
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
@ -360,31 +359,22 @@ nsNPAPIPluginStreamListener::SuspendRequest()
|
||||
{
|
||||
NS_ASSERTION(!mIsSuspended,
|
||||
"Suspending a request that's already suspended!");
|
||||
|
||||
nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
|
||||
do_QueryInterface(mStreamInfo);
|
||||
|
||||
if (!pluginInfoNPAPI) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
nsresult rv = StartDataPump();
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
mIsSuspended = true;
|
||||
|
||||
pluginInfoNPAPI->SuspendRequests();
|
||||
|
||||
if (mStreamListenerPeer) {
|
||||
mStreamListenerPeer->SuspendRequests();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsNPAPIPluginStreamListener::ResumeRequest()
|
||||
{
|
||||
nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
|
||||
do_QueryInterface(mStreamInfo);
|
||||
|
||||
pluginInfoNPAPI->ResumeRequests();
|
||||
|
||||
mStreamListenerPeer->ResumeRequests();
|
||||
mIsSuspended = false;
|
||||
}
|
||||
|
||||
@ -436,7 +426,7 @@ nsNPAPIPluginStreamListener::PluginInitJSLoadInProgress()
|
||||
// and the length will be the number of bytes available in our
|
||||
// internal buffer.
|
||||
nsresult
|
||||
nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
nsNPAPIPluginStreamListener::OnDataAvailable(nsPluginStreamListenerPeer* streamPeer,
|
||||
nsIInputStream* input,
|
||||
PRUint32 length)
|
||||
{
|
||||
@ -446,7 +436,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
PluginDestructionGuard guard(mInst);
|
||||
|
||||
// Just in case the caller switches plugin info on us.
|
||||
mStreamInfo = pluginInfo;
|
||||
mStreamListenerPeer = streamPeer;
|
||||
|
||||
nsNPAPIPlugin* plugin = mInst->GetPlugin();
|
||||
if (!plugin || !plugin->GetLibrary())
|
||||
@ -466,7 +456,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
// consecutive Read() calls form input stream into our buff.
|
||||
|
||||
PRUint32 contentLength;
|
||||
pluginInfo->GetLength(&contentLength);
|
||||
streamPeer->GetLength(&contentLength);
|
||||
|
||||
mStreamBufferSize = NS_MAX(length, contentLength);
|
||||
|
||||
@ -486,7 +476,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
mInst->GetNPP(&npp);
|
||||
|
||||
PRInt32 streamPosition;
|
||||
pluginInfo->GetStreamOffset(&streamPosition);
|
||||
streamPeer->GetStreamOffset(&streamPosition);
|
||||
PRInt32 streamOffset = streamPosition;
|
||||
|
||||
if (input) {
|
||||
@ -501,7 +491,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
//
|
||||
// Note: there is a special case when data flow should be
|
||||
// temporarily stopped if NPP_WriteReady returns 0 (bug #89270)
|
||||
pluginInfo->SetStreamOffset(streamOffset);
|
||||
streamPeer->SetStreamOffset(streamOffset);
|
||||
|
||||
// set new end in case the content is compressed
|
||||
// initial end is less than end of decompressed stream
|
||||
@ -695,10 +685,10 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
// NPN_RequestRead() call.
|
||||
|
||||
PRInt32 postWriteStreamPosition;
|
||||
pluginInfo->GetStreamOffset(&postWriteStreamPosition);
|
||||
streamPeer->GetStreamOffset(&postWriteStreamPosition);
|
||||
|
||||
if (postWriteStreamPosition == streamOffset) {
|
||||
pluginInfo->SetStreamOffset(streamPosition);
|
||||
streamPeer->SetStreamOffset(streamPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,7 +696,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNPAPIPluginStreamListener::OnFileAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
nsNPAPIPluginStreamListener::OnFileAvailable(nsPluginStreamListenerPeer* streamPeer,
|
||||
const char* fileName)
|
||||
{
|
||||
if (!mInst || !mInst->CanFireNotifications())
|
||||
@ -736,7 +726,7 @@ nsNPAPIPluginStreamListener::OnFileAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNPAPIPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo,
|
||||
nsNPAPIPluginStreamListener::OnStopBinding(nsPluginStreamListenerPeer* streamPeer,
|
||||
nsresult status)
|
||||
{
|
||||
StopDataPump();
|
||||
@ -744,9 +734,8 @@ nsNPAPIPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo,
|
||||
if (NS_FAILED(status)) {
|
||||
// The stream was destroyed, or died for some reason. Make sure we
|
||||
// cancel the underlying request.
|
||||
nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI = do_QueryInterface(mStreamInfo);
|
||||
if (pluginInfoNPAPI) {
|
||||
pluginInfoNPAPI->CancelRequests(status);
|
||||
if (mStreamListenerPeer) {
|
||||
mStreamListenerPeer->CancelRequests(status);
|
||||
}
|
||||
}
|
||||
|
||||
@ -788,7 +777,7 @@ nsNPAPIPluginStreamListener::Notify(nsITimer *aTimer)
|
||||
|
||||
PRInt32 oldStreamBufferByteCount = mStreamBufferByteCount;
|
||||
|
||||
nsresult rv = OnDataAvailable(mStreamInfo, nsnull, mStreamBufferByteCount);
|
||||
nsresult rv = OnDataAvailable(mStreamListenerPeer, nsnull, mStreamBufferByteCount);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// We ran into an error, no need to keep firing this timer then.
|
||||
|
@ -7,7 +7,6 @@
|
||||
#define nsNPAPIPluginStreamListener_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsIPluginStreamInfo.h"
|
||||
#include "nsIHTTPHeaderListener.h"
|
||||
#include "nsIRequest.h"
|
||||
#include "nsITimer.h"
|
||||
@ -22,7 +21,6 @@
|
||||
|
||||
#define MAX_PLUGIN_NECKO_BUFFER 16384
|
||||
|
||||
class nsINPAPIPluginStreamInfo;
|
||||
class nsPluginStreamListenerPeer;
|
||||
class nsNPAPIPluginStreamListener;
|
||||
|
||||
@ -42,64 +40,6 @@ protected:
|
||||
nsNPAPIPluginStreamListener* mStreamListener; // only valid if browser initiated
|
||||
};
|
||||
|
||||
// nsINPAPIPluginStreamInfo is an internal helper interface that exposes
|
||||
// the underlying necko request to consumers of nsIPluginStreamInfo's.
|
||||
#define NS_INPAPIPLUGINSTREAMINFO_IID \
|
||||
{ 0x097fdaaa, 0xa2a3, 0x49c2, \
|
||||
{0x91, 0xee, 0xeb, 0xc5, 0x7d, 0x6c, 0x9c, 0x97} }
|
||||
|
||||
class nsINPAPIPluginStreamInfo : public nsIPluginStreamInfo
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPAPIPLUGINSTREAMINFO_IID)
|
||||
|
||||
void TrackRequest(nsIRequest* request)
|
||||
{
|
||||
mRequests.AppendObject(request);
|
||||
}
|
||||
|
||||
void ReplaceRequest(nsIRequest* oldRequest, nsIRequest* newRequest)
|
||||
{
|
||||
PRInt32 i = mRequests.IndexOfObject(oldRequest);
|
||||
if (i == -1) {
|
||||
NS_ASSERTION(mRequests.Count() == 0,
|
||||
"Only our initial stream should be unknown!");
|
||||
mRequests.AppendObject(oldRequest);
|
||||
}
|
||||
else {
|
||||
mRequests.ReplaceObjectAt(newRequest, i);
|
||||
}
|
||||
}
|
||||
|
||||
void CancelRequests(nsresult status)
|
||||
{
|
||||
// Copy the array to avoid modification during the loop.
|
||||
nsCOMArray<nsIRequest> requestsCopy(mRequests);
|
||||
for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
|
||||
requestsCopy[i]->Cancel(status);
|
||||
}
|
||||
|
||||
void SuspendRequests() {
|
||||
nsCOMArray<nsIRequest> requestsCopy(mRequests);
|
||||
for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
|
||||
requestsCopy[i]->Suspend();
|
||||
}
|
||||
|
||||
void ResumeRequests() {
|
||||
nsCOMArray<nsIRequest> requestsCopy(mRequests);
|
||||
for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
|
||||
requestsCopy[i]->Resume();
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class nsPluginByteRangeStreamListener;
|
||||
|
||||
nsCOMArray<nsIRequest> mRequests;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsINPAPIPluginStreamInfo,
|
||||
NS_INPAPIPLUGINSTREAMINFO_IID)
|
||||
|
||||
// Used to handle NPN_NewStream() - writes the stream as received by the plugin
|
||||
// to a file and at completion (NPN_DestroyStream), tells the browser to load it into
|
||||
// a plugin-specified target
|
||||
@ -134,13 +74,13 @@ public:
|
||||
const char* aURL);
|
||||
virtual ~nsNPAPIPluginStreamListener();
|
||||
|
||||
nsresult OnStartBinding(nsIPluginStreamInfo* pluginInfo);
|
||||
nsresult OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
nsresult OnStartBinding(nsPluginStreamListenerPeer* streamPeer);
|
||||
nsresult OnDataAvailable(nsPluginStreamListenerPeer* streamPeer,
|
||||
nsIInputStream* input,
|
||||
PRUint32 length);
|
||||
nsresult OnFileAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
nsresult OnFileAvailable(nsPluginStreamListenerPeer* streamPeer,
|
||||
const char* fileName);
|
||||
nsresult OnStopBinding(nsIPluginStreamInfo* pluginInfo,
|
||||
nsresult OnStopBinding(nsPluginStreamListenerPeer* streamPeer,
|
||||
nsresult status);
|
||||
nsresult GetStreamType(PRInt32 *result);
|
||||
|
||||
@ -167,7 +107,6 @@ protected:
|
||||
char* mStreamBuffer;
|
||||
char* mNotifyURL;
|
||||
nsRefPtr<nsNPAPIPluginInstance> mInst;
|
||||
nsPluginStreamListenerPeer* mStreamListenerPeer;
|
||||
nsNPAPIStreamWrapper *mNPStreamWrapper;
|
||||
PRUint32 mStreamBufferSize;
|
||||
PRInt32 mStreamBufferByteCount;
|
||||
@ -184,7 +123,7 @@ protected:
|
||||
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mHTTPRedirectCallback;
|
||||
|
||||
public:
|
||||
nsCOMPtr<nsIPluginStreamInfo> mStreamInfo;
|
||||
nsRefPtr<nsPluginStreamListenerPeer> mStreamListenerPeer;
|
||||
};
|
||||
|
||||
#endif // nsNPAPIPluginStreamListener_h_
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "nsNPAPIPlugin.h"
|
||||
#include "nsNPAPIPluginStreamListener.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
#include "nsIHTTPHeaderListener.h"
|
||||
#include "nsIHttpHeaderVisitor.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsPluginNativeWindow.h"
|
||||
#include "sampler.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
|
||||
#define MAGIC_REQUEST_CONTEXT 0x01020304
|
||||
|
||||
@ -264,13 +265,11 @@ public:
|
||||
|
||||
// nsPluginStreamListenerPeer
|
||||
|
||||
NS_IMPL_ISUPPORTS8(nsPluginStreamListenerPeer,
|
||||
NS_IMPL_ISUPPORTS6(nsPluginStreamListenerPeer,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver,
|
||||
nsIHttpHeaderVisitor,
|
||||
nsISupportsWeakReference,
|
||||
nsIPluginStreamInfo,
|
||||
nsINPAPIPluginStreamInfo,
|
||||
nsIInterfaceRequestor,
|
||||
nsIChannelEventSink)
|
||||
|
||||
@ -635,7 +634,7 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStatus(nsIRequest *request,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsPluginStreamListenerPeer::GetContentType(char** result)
|
||||
{
|
||||
*result = const_cast<char*>(mContentType.get());
|
||||
@ -643,28 +642,28 @@ nsPluginStreamListenerPeer::GetContentType(char** result)
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsPluginStreamListenerPeer::IsSeekable(bool* result)
|
||||
{
|
||||
*result = mSeekable;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsPluginStreamListenerPeer::GetLength(PRUint32* result)
|
||||
{
|
||||
*result = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsPluginStreamListenerPeer::GetLastModified(PRUint32* result)
|
||||
{
|
||||
*result = mModified;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsPluginStreamListenerPeer::GetURL(const char** result)
|
||||
{
|
||||
*result = mURLSpec.get();
|
||||
@ -707,7 +706,7 @@ nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACStr
|
||||
return;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
|
||||
{
|
||||
nsCAutoString rangeString;
|
||||
@ -770,14 +769,14 @@ nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsPluginStreamListenerPeer::GetStreamOffset(PRInt32* result)
|
||||
{
|
||||
*result = mStreamOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsPluginStreamListenerPeer::SetStreamOffset(PRInt32 value)
|
||||
{
|
||||
mStreamOffset = value;
|
||||
@ -1289,11 +1288,11 @@ nsPluginStreamListenerPeer::GetInterface(const nsIID& aIID, void** result)
|
||||
class ChannelRedirectProxyCallback : public nsIAsyncVerifyRedirectCallback
|
||||
{
|
||||
public:
|
||||
ChannelRedirectProxyCallback(nsINPAPIPluginStreamInfo* listener,
|
||||
ChannelRedirectProxyCallback(nsPluginStreamListenerPeer* listener,
|
||||
nsIAsyncVerifyRedirectCallback* parent,
|
||||
nsIChannel* oldChannel,
|
||||
nsIChannel* newChannel)
|
||||
: mWeakListener(do_GetWeakReference(listener))
|
||||
: mWeakListener(do_GetWeakReference(static_cast<nsIStreamListener*>(listener)))
|
||||
, mParent(parent)
|
||||
, mOldChannel(oldChannel)
|
||||
, mNewChannel(newChannel)
|
||||
@ -1308,9 +1307,9 @@ public:
|
||||
NS_IMETHODIMP OnRedirectVerifyCallback(nsresult result)
|
||||
{
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
nsCOMPtr<nsINPAPIPluginStreamInfo> listener = do_QueryReferent(mWeakListener);
|
||||
nsCOMPtr<nsIStreamListener> listener = do_QueryReferent(mWeakListener);
|
||||
if (listener)
|
||||
listener->ReplaceRequest(mOldChannel, mNewChannel);
|
||||
static_cast<nsPluginStreamListenerPeer*>(listener.get())->ReplaceRequest(mOldChannel, mNewChannel);
|
||||
}
|
||||
return mParent->OnRedirectVerifyCallback(result);
|
||||
}
|
||||
|
@ -17,9 +17,10 @@
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
#include "nsIObjectLoadingContent.h"
|
||||
|
||||
class nsIChannel;
|
||||
class nsObjectLoadingContent;
|
||||
|
||||
/**
|
||||
* When a plugin requests opens multiple requests to the same URL and
|
||||
@ -47,7 +48,6 @@ class nsPluginStreamListenerPeer : public nsIStreamListener,
|
||||
public nsIProgressEventSink,
|
||||
public nsIHttpHeaderVisitor,
|
||||
public nsSupportsWeakReference,
|
||||
public nsINPAPIPluginStreamInfo,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIChannelEventSink
|
||||
{
|
||||
@ -63,9 +63,6 @@ public:
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
|
||||
// nsINPAPIPluginStreamInfo interface
|
||||
NS_DECL_NSIPLUGINSTREAMINFO
|
||||
|
||||
// Called by RequestRead
|
||||
void
|
||||
MakeByteRangeString(NPByteRange* aRangeList, nsACString &string, PRInt32 *numRequests);
|
||||
@ -89,6 +86,53 @@ public:
|
||||
|
||||
nsNPAPIPluginInstance *GetPluginInstance() { return mPluginInstance; }
|
||||
|
||||
nsresult RequestRead(NPByteRange* rangeList);
|
||||
nsresult GetLength(PRUint32* result);
|
||||
nsresult GetURL(const char** result);
|
||||
nsresult GetLastModified(PRUint32* result);
|
||||
nsresult IsSeekable(bool* result);
|
||||
nsresult GetContentType(char** result);
|
||||
nsresult GetStreamOffset(PRInt32* result);
|
||||
nsresult SetStreamOffset(PRInt32 value);
|
||||
|
||||
void TrackRequest(nsIRequest* request)
|
||||
{
|
||||
mRequests.AppendObject(request);
|
||||
}
|
||||
|
||||
void ReplaceRequest(nsIRequest* oldRequest, nsIRequest* newRequest)
|
||||
{
|
||||
PRInt32 i = mRequests.IndexOfObject(oldRequest);
|
||||
if (i == -1) {
|
||||
NS_ASSERTION(mRequests.Count() == 0,
|
||||
"Only our initial stream should be unknown!");
|
||||
mRequests.AppendObject(oldRequest);
|
||||
}
|
||||
else {
|
||||
mRequests.ReplaceObjectAt(newRequest, i);
|
||||
}
|
||||
}
|
||||
|
||||
void CancelRequests(nsresult status)
|
||||
{
|
||||
// Copy the array to avoid modification during the loop.
|
||||
nsCOMArray<nsIRequest> requestsCopy(mRequests);
|
||||
for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
|
||||
requestsCopy[i]->Cancel(status);
|
||||
}
|
||||
|
||||
void SuspendRequests() {
|
||||
nsCOMArray<nsIRequest> requestsCopy(mRequests);
|
||||
for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
|
||||
requestsCopy[i]->Suspend();
|
||||
}
|
||||
|
||||
void ResumeRequests() {
|
||||
nsCOMArray<nsIRequest> requestsCopy(mRequests);
|
||||
for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
|
||||
requestsCopy[i]->Resume();
|
||||
}
|
||||
|
||||
private:
|
||||
nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
|
||||
nsresult SetupPluginCacheFile(nsIChannel* channel);
|
||||
@ -132,6 +176,7 @@ public:
|
||||
PRInt32 mPendingRequests;
|
||||
nsWeakPtr mWeakPtrChannelCallbacks;
|
||||
nsWeakPtr mWeakPtrChannelLoadGroup;
|
||||
nsCOMArray<nsIRequest> mRequests;
|
||||
};
|
||||
|
||||
#endif // nsPluginStreamListenerPeer_h_
|
||||
|
@ -192,6 +192,10 @@ let libnetutils = (function () {
|
||||
serverbuf,
|
||||
lease.address());
|
||||
|
||||
if (ret && DEBUG) {
|
||||
let error = iface.dhcp_get_errmsg();
|
||||
dump("dhcp_do_request failed - " + error.readString());
|
||||
}
|
||||
let obj = {
|
||||
ret: ret | 0,
|
||||
ipaddr_str: ipaddrbuf.readString(),
|
||||
@ -246,6 +250,10 @@ let libnetutils = (function () {
|
||||
ints.addressOfElement(4),
|
||||
ints.addressOfElement(5),
|
||||
ints.addressOfElement(6));
|
||||
if (ret && DEBUG) {
|
||||
let error = iface.dhcp_get_errmsg();
|
||||
dump("dhcp_do_request_* failed - " + error.readString());
|
||||
}
|
||||
return {ret: ret | 0,
|
||||
ipaddr: ints[0] | 0,
|
||||
gateway: ints[1] | 0,
|
||||
|
@ -160,9 +160,11 @@ nsDeviceSensors::Notify(const mozilla::hal::SensorData& aSensorData)
|
||||
{
|
||||
PRUint32 type = aSensorData.sensor();
|
||||
|
||||
double x = aSensorData.values()[0];
|
||||
double y = aSensorData.values()[1];
|
||||
double z = aSensorData.values()[2];
|
||||
const InfallibleTArray<float>& values = aSensorData.values();
|
||||
size_t len = values.Length();
|
||||
double x = len > 0 ? values[0] : 0.0;
|
||||
double y = len > 1 ? values[1] : 0.0;
|
||||
double z = len > 2 ? values[2] : 0.0;
|
||||
|
||||
nsCOMArray<nsIDOMWindow> windowListeners;
|
||||
for (PRUint32 i = 0; i < mWindowListeners[type]->Length(); i++) {
|
||||
|
@ -1,150 +0,0 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
"use strict";
|
||||
|
||||
let libnetutils = (function () {
|
||||
let library = ctypes.open("libnetutils.so");
|
||||
let cutils = ctypes.open("libcutils.so");
|
||||
|
||||
let cbuf = ctypes.char.array(4096)();
|
||||
let c_property_get = cutils.declare("property_get", ctypes.default_abi,
|
||||
ctypes.int, // return value: length
|
||||
ctypes.char.ptr, // key
|
||||
ctypes.char.ptr, // value
|
||||
ctypes.char.ptr); // default
|
||||
let property_get = function (key, defaultValue) {
|
||||
if (defaultValue === undefined) {
|
||||
defaultValue = null;
|
||||
}
|
||||
c_property_get(key, cbuf, defaultValue);
|
||||
return cbuf.readString();
|
||||
}
|
||||
|
||||
let sdkVersion = parseInt(property_get("ro.build.version.sdk"));
|
||||
|
||||
let iface = {
|
||||
ifc_enable: library.declare("ifc_enable", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
|
||||
ifc_disable: library.declare("ifc_disable", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
|
||||
ifc_add_host_route: library.declare("ifc_add_host_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int),
|
||||
ifc_remove_host_routes: library.declare("ifc_remove_host_routes", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
|
||||
ifc_set_default_route: library.declare("ifc_set_default_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int),
|
||||
ifc_get_default_route: library.declare("ifc_get_default_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
|
||||
ifc_remove_default_route: library.declare("ifc_remove_default_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
|
||||
ifc_reset_connections: library.declare("ifc_reset_connections", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
|
||||
ifc_configure: library.declare("ifc_configure", ctypes.default_abi, ctypes.int, ctypes.char.ptr,
|
||||
ctypes.int, ctypes.int, ctypes.int, ctypes.int, ctypes.int),
|
||||
dhcp_stop: library.declare("dhcp_stop", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
|
||||
dhcp_release_lease: library.declare("dhcp_release_lease", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
|
||||
dhcp_get_errmsg: library.declare("dhcp_get_errmsg", ctypes.default_abi, ctypes.char.ptr),
|
||||
};
|
||||
|
||||
if (sdkVersion >= 15) {
|
||||
let ipaddrbuf = ctypes.char.array(4096)();
|
||||
let gatewaybuf = ctypes.char.array(4096)();
|
||||
let prefixLen = ctypes.int();
|
||||
let dns1buf = ctypes.char.array(4096)();
|
||||
let dns2buf = ctypes.char.array(4096)();
|
||||
let serverbuf = ctypes.char.array(4096)();
|
||||
let lease = ctypes.int();
|
||||
let c_dhcp_do_request =
|
||||
library.declare("dhcp_do_request", ctypes.default_abi,
|
||||
ctypes.int, // [return]
|
||||
ctypes.char.ptr, // ifname
|
||||
ctypes.char.ptr, // ipaddr
|
||||
ctypes.char.ptr, // gateway
|
||||
ctypes.int.ptr, // prefixlen
|
||||
ctypes.char.ptr, // dns1
|
||||
ctypes.char.ptr, // dns2
|
||||
ctypes.char.ptr, // server
|
||||
ctypes.int.ptr); // lease
|
||||
|
||||
let stringToIp = function (s) {
|
||||
if (!s) return 0;
|
||||
let comps = s.split(".");
|
||||
return ((parseInt(comps[0]) & 0xff) << 0 |
|
||||
(parseInt(comps[1]) & 0xff) << 8 |
|
||||
(parseInt(comps[2]) & 0xff) << 16 |
|
||||
(parseInt(comps[3]) & 0xff) << 24);
|
||||
}
|
||||
|
||||
let makeMask = function (len) {
|
||||
let mask = 0;
|
||||
for (let i = 0; i < len; ++i)
|
||||
mask |= (1 << i);
|
||||
return mask;
|
||||
}
|
||||
|
||||
iface.dhcp_do_request = function (ifname) {
|
||||
let ret = c_dhcp_do_request(ifname,
|
||||
ipaddrbuf,
|
||||
gatewaybuf,
|
||||
prefixLen.address(),
|
||||
dns1buf,
|
||||
dns2buf,
|
||||
serverbuf,
|
||||
lease.address());
|
||||
return {
|
||||
ret: ret |0,
|
||||
ipaddr: stringToIp(ipaddrbuf.readString()),
|
||||
gateway: stringToIp(gatewaybuf.readString()),
|
||||
mask: makeMask(prefixLen),
|
||||
dns1: stringToIp(dns1buf.readString()),
|
||||
dns2: stringToIp(dns2buf.readString()),
|
||||
server: stringToIp(serverbuf.readString()),
|
||||
lease: lease |0
|
||||
};
|
||||
};
|
||||
// dhcp_do_request_renew() went away in newer libnetutils.
|
||||
iface.dhcp_do_request_renew = iface.dhcp_do_request;
|
||||
} else {
|
||||
let ints = ctypes.int.array(8)();
|
||||
let c_dhcp_do_request =
|
||||
library.declare("dhcp_do_request", ctypes.default_abi,
|
||||
ctypes.int, // [return]
|
||||
ctypes.char.ptr, // ifname
|
||||
ctypes.int.ptr, // ipaddr
|
||||
ctypes.int.ptr, // gateway
|
||||
ctypes.int.ptr, // mask
|
||||
ctypes.int.ptr, // dns1
|
||||
ctypes.int.ptr, // dns2
|
||||
ctypes.int.ptr, // server
|
||||
ctypes.int.ptr); // lease
|
||||
let c_dhcp_do_request_renew =
|
||||
library.declare("dhcp_do_request_renew", ctypes.default_abi,
|
||||
ctypes.int, // [return]
|
||||
ctypes.char.ptr, // ifname
|
||||
ctypes.int.ptr, // ipaddr
|
||||
ctypes.int.ptr, // gateway
|
||||
ctypes.int.ptr, // mask
|
||||
ctypes.int.ptr, // dns1
|
||||
ctypes.int.ptr, // dns2
|
||||
ctypes.int.ptr, // server
|
||||
ctypes.int.ptr); // lease
|
||||
|
||||
let makeRequestWrapper = function (c_fn) {
|
||||
return function (ifname) {
|
||||
let ret = c_fn(ifname,
|
||||
ints.addressOfElement(0),
|
||||
ints.addressOfElement(1),
|
||||
ints.addressOfElement(2),
|
||||
ints.addressOfElement(3),
|
||||
ints.addressOfElement(4),
|
||||
ints.addressOfElement(5),
|
||||
ints.addressOfElement(6));
|
||||
return { ret: ret |0, ipaddr: ints[0] |0, gateway: ints[1] |0,
|
||||
mask: ints[2] |0, dns1: ints[3] |0, dns2: ints[4] |0,
|
||||
server: ints[5] |0, lease: ints[6] |0 };
|
||||
};
|
||||
}
|
||||
|
||||
iface.dhcp_do_request = makeRequestWrapper(c_dhcp_do_request);
|
||||
iface.dhcp_do_request_renew = makeRequestWrapper(c_dhcp_do_request_renew);
|
||||
}
|
||||
|
||||
return iface;
|
||||
})();
|
@ -1,15 +0,0 @@
|
||||
#
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -1,3 +0,0 @@
|
||||
This folder contains sample applications developed using the Gecko embedding
|
||||
APIs.
|
||||
|
@ -295,12 +295,13 @@ regexp_compile(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, regexp_compile, &RegExpClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, regexp_compile, &RegExpClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
RegExpObjectBuilder builder(cx, &obj->asRegExp());
|
||||
RegExpObjectBuilder builder(cx, &thisObj->asRegExp());
|
||||
return CompileRegExpObject(cx, builder, args);
|
||||
}
|
||||
|
||||
@ -333,12 +334,13 @@ regexp_toString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, regexp_toString, &RegExpClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, regexp_toString, &RegExpClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
JSString *str = obj->asRegExp().toString(cx);
|
||||
JSString *str = thisObj->asRegExp().toString(cx);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
@ -540,12 +542,13 @@ ExecuteRegExp(JSContext *cx, Native native, unsigned argc, Value *vp)
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
/* Step 1. */
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, native, &RegExpClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, native, &RegExpClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
Rooted<RegExpObject*> reobj(cx, &obj->asRegExp());
|
||||
Rooted<RegExpObject*> reobj(cx, &thisObj->asRegExp());
|
||||
|
||||
RegExpGuard re;
|
||||
if (StartsWithGreedyStar(reobj->getSource())) {
|
||||
|
@ -122,6 +122,7 @@ class Handle
|
||||
|
||||
typedef Handle<JSObject*> HandleObject;
|
||||
typedef Handle<JSFunction*> HandleFunction;
|
||||
typedef Handle<JSScript*> HandleScript;
|
||||
typedef Handle<JSString*> HandleString;
|
||||
typedef Handle<jsid> HandleId;
|
||||
typedef Handle<Value> HandleValue;
|
||||
@ -224,6 +225,7 @@ Handle<T>::Handle(const Rooted<S> &root)
|
||||
|
||||
typedef Rooted<JSObject*> RootedObject;
|
||||
typedef Rooted<JSFunction*> RootedFunction;
|
||||
typedef Rooted<JSScript*> RootedScript;
|
||||
typedef Rooted<JSString*> RootedString;
|
||||
typedef Rooted<jsid> RootedId;
|
||||
typedef Rooted<Value> RootedValue;
|
||||
|
5
js/src/jit-test/tests/basic/testBug761439.js
Normal file
5
js/src/jit-test/tests/basic/testBug761439.js
Normal file
@ -0,0 +1,5 @@
|
||||
var b = new ArrayBuffer(4);
|
||||
var dv = new DataView(b);
|
||||
dv.setInt32(0, 42);
|
||||
var w = wrap(dv);
|
||||
assertEq(DataView.prototype.getInt32.call(w, 0), 42);
|
@ -18,7 +18,9 @@ CPPSRCS = \
|
||||
selfTest.cpp \
|
||||
testAddPropertyPropcache.cpp \
|
||||
testArgumentsObject.cpp \
|
||||
testBindCallable.cpp \
|
||||
testBug604087.cpp \
|
||||
testCallNonGenericMethodOnProxy.cpp \
|
||||
testChromeBuffer.cpp \
|
||||
testClassGetter.cpp \
|
||||
testCloneScript.cpp \
|
||||
@ -61,7 +63,6 @@ CPPSRCS = \
|
||||
testValueABI.cpp \
|
||||
testVersion.cpp \
|
||||
testXDR.cpp \
|
||||
testBindCallable.cpp \
|
||||
$(NULL)
|
||||
|
||||
CSRCS = \
|
||||
|
82
js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
Normal file
82
js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "tests.h"
|
||||
|
||||
using namespace JS;
|
||||
|
||||
static JSClass CustomClass = {
|
||||
"CustomClass",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(1),
|
||||
JS_PropertyStub,
|
||||
JS_PropertyStub,
|
||||
JS_PropertyStub,
|
||||
JS_StrictPropertyStub,
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub
|
||||
};
|
||||
|
||||
static const uint32_t CUSTOM_SLOT = 0;
|
||||
|
||||
static JSBool
|
||||
CustomMethod(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
const Value &thisv = JS_THIS_VALUE(cx, vp);
|
||||
JSObject *thisObj;
|
||||
if (!thisv.isObject() || JS_GetClass((thisObj = &thisv.toObject())) != &CustomClass)
|
||||
return JS_CallNonGenericMethodOnProxy(cx, argc, vp, CustomMethod, &CustomClass);
|
||||
|
||||
JS_SET_RVAL(cx, vp, JS_GetReservedSlot(thisObj, CUSTOM_SLOT));
|
||||
return true;
|
||||
}
|
||||
|
||||
BEGIN_TEST(test_CallNonGenericMethodOnProxy)
|
||||
{
|
||||
// Create the first global object and compartment
|
||||
JSObject *globalA = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
|
||||
CHECK(globalA);
|
||||
|
||||
JSObject *customA = JS_NewObject(cx, &CustomClass, NULL, NULL);
|
||||
CHECK(customA);
|
||||
JS_SetReservedSlot(customA, CUSTOM_SLOT, Int32Value(17));
|
||||
|
||||
JSFunction *customMethodA = JS_NewFunction(cx, CustomMethod, 0, 0, customA, "customMethodA");
|
||||
CHECK(customMethodA);
|
||||
|
||||
jsval rval;
|
||||
CHECK(JS_CallFunction(cx, customA, customMethodA, 0, NULL, &rval));
|
||||
CHECK_SAME(rval, Int32Value(17));
|
||||
|
||||
// Now create the second global object and compartment...
|
||||
{
|
||||
JSObject *globalB = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
|
||||
CHECK(globalB);
|
||||
|
||||
// ...and enter it.
|
||||
JSAutoEnterCompartment enter;
|
||||
CHECK(enter.enter(cx, globalB));
|
||||
|
||||
JSObject *customB = JS_NewObject(cx, &CustomClass, NULL, NULL);
|
||||
CHECK(customB);
|
||||
JS_SetReservedSlot(customB, CUSTOM_SLOT, Int32Value(42));
|
||||
|
||||
JSFunction *customMethodB = JS_NewFunction(cx, CustomMethod, 0, 0, customB, "customMethodB");
|
||||
CHECK(customMethodB);
|
||||
|
||||
jsval rval;
|
||||
CHECK(JS_CallFunction(cx, customB, customMethodB, 0, NULL, &rval));
|
||||
CHECK_SAME(rval, Int32Value(42));
|
||||
|
||||
JSObject *wrappedCustomA = customA;
|
||||
CHECK(JS_WrapObject(cx, &wrappedCustomA));
|
||||
|
||||
jsval rval2;
|
||||
CHECK(JS_CallFunction(cx, wrappedCustomA, customMethodB, 0, NULL, &rval2));
|
||||
CHECK_SAME(rval, Int32Value(42));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(test_CallNonGenericMethodOnProxy)
|
@ -3440,49 +3440,6 @@ JS_DeepFreezeObject(JSContext *cx, JSObject *obj)
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *parent)
|
||||
{
|
||||
return JS_ConstructObjectWithArguments(cx, jsclasp, parent, 0, NULL);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *parent,
|
||||
unsigned argc, jsval *argv)
|
||||
{
|
||||
AssertNoGC(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, parent, JSValueArray(argv, argc));
|
||||
|
||||
AutoArrayRooter argtvr(cx, argc, argv);
|
||||
|
||||
Class *clasp = Valueify(jsclasp);
|
||||
if (!clasp)
|
||||
clasp = &ObjectClass; /* default class is Object */
|
||||
|
||||
JSProtoKey protoKey = GetClassProtoKey(clasp);
|
||||
|
||||
/* Protect constructor in case a crazy getter for .prototype uproots it. */
|
||||
RootedValue value(cx);
|
||||
if (!js_FindClassObject(cx, parent, protoKey, value.address(), clasp))
|
||||
return NULL;
|
||||
|
||||
Value rval;
|
||||
if (!InvokeConstructor(cx, value, argc, argv, &rval))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If the instance's class differs from what was requested, throw a type
|
||||
* error.
|
||||
*/
|
||||
if (!rval.isObject() || rval.toObject().getClass() != clasp) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_WRONG_CONSTRUCTOR, clasp->name);
|
||||
return NULL;
|
||||
}
|
||||
return &rval.toObject();
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LookupPropertyById(JSContext *cx, JSObject *obj, HandleId id, unsigned flags,
|
||||
JSObject **objp, JSProperty **propp)
|
||||
@ -4845,6 +4802,14 @@ JS_DefineFunctionById(JSContext *cx, JSObject *obj_, jsid id_, JSNative call,
|
||||
return js_DefineFunction(cx, obj, id, call, nargs, attrs);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_CallNonGenericMethodOnProxy(JSContext *cx, unsigned argc, jsval *vp, JSNative native,
|
||||
JSClass *clasp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return HandleNonGenericMethodClassMismatch(cx, args, native, Valueify(clasp));
|
||||
}
|
||||
|
||||
struct AutoLastFrameCheck {
|
||||
AutoLastFrameCheck(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: cx(cx) {
|
||||
@ -5344,7 +5309,8 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *scriptArg, jsval *rval)
|
||||
* mozilla, but there doesn't seem to be one, so we handle it here.
|
||||
*/
|
||||
if (scriptArg->compartment() != obj->compartment()) {
|
||||
script = CloneScript(cx, scriptArg);
|
||||
RootedScript scriptArgRoot(cx, scriptArg);
|
||||
script = CloneScript(cx, scriptArgRoot);
|
||||
if (!script.get())
|
||||
return false;
|
||||
} else {
|
||||
|
@ -3811,7 +3811,6 @@ JS_IdToValue(JSContext *cx, jsid id, jsval *vp);
|
||||
#define JSRESOLVE_ASSIGNING 0x02 /* resolve on the left of assignment */
|
||||
#define JSRESOLVE_DETECTING 0x04 /* 'if (o.p)...' or '(o.p) ?...:...' */
|
||||
#define JSRESOLVE_DECLARING 0x08 /* var, const, or function prolog op */
|
||||
#define JSRESOLVE_WITH 0x10 /* resolve inside a with statement */
|
||||
|
||||
/*
|
||||
* Invoke the [[DefaultValue]] hook (see ES5 8.6.2) with the provided hint on
|
||||
@ -3976,13 +3975,6 @@ JS_DeepFreezeObject(JSContext *cx, JSObject *obj);
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_FreezeObject(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *parent);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *parent,
|
||||
unsigned argc, jsval *argv);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_New(JSContext *cx, JSObject *ctor, unsigned argc, jsval *argv);
|
||||
|
||||
@ -4473,6 +4465,66 @@ JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
|
||||
|
||||
/*
|
||||
* Methods usually act upon |this| objects only from a single global object and
|
||||
* compartment. Sometimes, however, a method must act upon |this| values from
|
||||
* multiple global objects or compartments. In such cases the |this| value a
|
||||
* method might see will be wrapped, such that various access to the object --
|
||||
* to its class, its private data, its reserved slots, and so on -- will not
|
||||
* work properly without entering that object's compartment. This method
|
||||
* implements a solution to this problem.
|
||||
*
|
||||
* When called, this method attempts to unwrap |this| and call |native| on the
|
||||
* underlying object with the provided arguments, entering |this|'s compartment
|
||||
* in the process. It is critical that |this|-checking occur right at the
|
||||
* start of |native| so that reentrant invocation is idempotent! If the call
|
||||
* fails because |this| isn't a proxy to another object, a TypeError is thrown.
|
||||
*
|
||||
* The following example demonstrates the most common way this method might be
|
||||
* used, to accept objects having only a particular class but which might be
|
||||
* found in another compartment/global object or might be a proxy of some sort:
|
||||
*
|
||||
* static JSClass MyClass = { "MyClass", JSCLASS_HAS_PRIVATE, ... };
|
||||
*
|
||||
* inline bool
|
||||
* RequireMyClassThis(JSContext *cx, unsigned argc, JSObject **thisObj)
|
||||
* {
|
||||
* const Value &thisv = JS_THIS_VALUE(cx, vp);
|
||||
* if (!thisv.isObject()) {
|
||||
* JS_ReportError(cx, "this must be an object");
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* JSObject *obj = &thisv.toObject();
|
||||
* if (JS_GetClass(obj) == &MyClass) {
|
||||
* *thisObj = obj;
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* *thisObj = NULL; // prevent infinite recursion into calling method
|
||||
* return JS_CallNonGenericMethodOnProxy(cx, argc, vp, method, &MyClass);
|
||||
* }
|
||||
*
|
||||
* static JSBool
|
||||
* Method(JSContext *cx, unsigned argc, jsval *vp)
|
||||
* {
|
||||
* if (!RequireMyClassThis(cx, argc, vp, &thisObj))
|
||||
* return false;
|
||||
* if (!thisObj)
|
||||
* return true; // method invocation was performed by nested call
|
||||
*
|
||||
* // thisObj definitely has MyClass: implement the guts of the method.
|
||||
* void *priv = JS_GetPrivate(thisObj);
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* This method doesn't do any checking of its own, except to throw a TypeError
|
||||
* if the |this| in the arguments isn't a proxy that can be unwrapped for the
|
||||
* recursive call. The client is responsible for performing all type-checks!
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_CallNonGenericMethodOnProxy(JSContext *cx, unsigned argc, jsval *vp, JSNative native, JSClass *clasp);
|
||||
|
||||
/*
|
||||
* Given a buffer, return JS_FALSE if the buffer might become a valid
|
||||
* javascript statement with the addition of more lines. Otherwise return
|
||||
|
@ -1385,12 +1385,13 @@ date_getTime(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getTime, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getTime, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
args.rval() = obj->getDateUTCTime();
|
||||
args.rval() = thisObj->getDateUTCTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1399,15 +1400,16 @@ date_getYear(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getYear, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getYear, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj))
|
||||
if (!GetAndCacheLocalTime(cx, thisObj))
|
||||
return false;
|
||||
|
||||
Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
||||
Value yearVal = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
||||
if (yearVal.isInt32()) {
|
||||
/* Follow ECMA-262 to the letter, contrary to IE JScript. */
|
||||
int year = yearVal.toInt32() - 1900;
|
||||
@ -1424,15 +1426,16 @@ date_getFullYear(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getFullYear, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getFullYear, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj))
|
||||
if (!GetAndCacheLocalTime(cx, thisObj))
|
||||
return false;
|
||||
|
||||
args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
||||
args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1441,12 +1444,13 @@ date_getUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCFullYear, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getUTCFullYear, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
if (MOZ_DOUBLE_IS_FINITE(result))
|
||||
result = YearFromTime(result);
|
||||
|
||||
@ -1459,15 +1463,16 @@ date_getMonth(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getMonth, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getMonth, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj))
|
||||
if (!GetAndCacheLocalTime(cx, thisObj))
|
||||
return false;
|
||||
|
||||
args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
|
||||
args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1476,12 +1481,13 @@ date_getUTCMonth(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMonth, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getUTCMonth, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
if (MOZ_DOUBLE_IS_FINITE(result))
|
||||
result = MonthFromTime(result);
|
||||
|
||||
@ -1494,15 +1500,16 @@ date_getDate(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getDate, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getDate, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj))
|
||||
if (!GetAndCacheLocalTime(cx, thisObj))
|
||||
return false;
|
||||
|
||||
args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
|
||||
args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1511,12 +1518,13 @@ date_getUTCDate(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDate, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getUTCDate, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
if (MOZ_DOUBLE_IS_FINITE(result))
|
||||
result = DateFromTime(result);
|
||||
|
||||
@ -1529,15 +1537,16 @@ date_getDay(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getDay, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getDay, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj))
|
||||
if (!GetAndCacheLocalTime(cx, thisObj))
|
||||
return false;
|
||||
|
||||
args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
|
||||
args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1546,12 +1555,13 @@ date_getUTCDay(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDay, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getUTCDay, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
if (MOZ_DOUBLE_IS_FINITE(result))
|
||||
result = WeekDay(result);
|
||||
|
||||
@ -1564,15 +1574,16 @@ date_getHours(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getHours, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getHours, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj))
|
||||
if (!GetAndCacheLocalTime(cx, thisObj))
|
||||
return false;
|
||||
|
||||
args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
|
||||
args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1581,12 +1592,13 @@ date_getUTCHours(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCHours, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getUTCHours, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
if (MOZ_DOUBLE_IS_FINITE(result))
|
||||
result = HourFromTime(result);
|
||||
|
||||
@ -1599,15 +1611,16 @@ date_getMinutes(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getMinutes, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getMinutes, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj))
|
||||
if (!GetAndCacheLocalTime(cx, thisObj))
|
||||
return false;
|
||||
|
||||
args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
|
||||
args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1616,12 +1629,13 @@ date_getUTCMinutes(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMinutes, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getUTCMinutes, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
if (MOZ_DOUBLE_IS_FINITE(result))
|
||||
result = MinFromTime(result);
|
||||
|
||||
@ -1636,15 +1650,16 @@ date_getUTCSeconds(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCSeconds, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getUTCSeconds, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!GetAndCacheLocalTime(cx, obj))
|
||||
if (!GetAndCacheLocalTime(cx, thisObj))
|
||||
return false;
|
||||
|
||||
args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
|
||||
args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1655,12 +1670,13 @@ date_getUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMilliseconds, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getUTCMilliseconds, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
if (MOZ_DOUBLE_IS_FINITE(result))
|
||||
result = msFromTime(result);
|
||||
|
||||
@ -1673,15 +1689,16 @@ date_getTimezoneOffset(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_getTimezoneOffset, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_getTimezoneOffset, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double utctime = obj->getDateUTCTime().toNumber();
|
||||
double utctime = thisObj->getDateUTCTime().toNumber();
|
||||
|
||||
double localtime;
|
||||
if (!GetAndCacheLocalTime(cx, obj, &localtime))
|
||||
if (!GetAndCacheLocalTime(cx, thisObj, &localtime))
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -1699,13 +1716,14 @@ date_setTime(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
RootedObject obj(cx, NonGenericMethodGuard(cx, args, date_setTime, &DateClass, &ok));
|
||||
if (!obj)
|
||||
return ok;
|
||||
RootedObject thisObj(cx);
|
||||
if (!NonGenericMethodGuard(cx, args, date_setTime, &DateClass, thisObj.address()))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (args.length() == 0) {
|
||||
SetDateToNaN(cx, obj, &args.rval());
|
||||
SetDateToNaN(cx, thisObj, &args.rval());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1713,7 +1731,7 @@ date_setTime(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!ToNumber(cx, args[0], &result))
|
||||
return false;
|
||||
|
||||
return SetUTCTime(cx, obj, TimeClip(result), &args.rval());
|
||||
return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -1721,12 +1739,13 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
RootedObject obj(cx, NonGenericMethodGuard(cx, args, native, &DateClass, &ok));
|
||||
if (!obj)
|
||||
return ok;
|
||||
RootedObject thisObj(cx);
|
||||
if (!NonGenericMethodGuard(cx, args, native, &DateClass, thisObj.address()))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
|
||||
/*
|
||||
* Satisfy the ECMA rule that if a function is called with
|
||||
@ -1738,7 +1757,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
|
||||
* d.setMilliseconds()" returns NaN. Blech.
|
||||
*/
|
||||
if (args.length() == 0) {
|
||||
SetDateToNaN(cx, obj, &args.rval());
|
||||
SetDateToNaN(cx, thisObj, &args.rval());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1767,7 +1786,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
|
||||
|
||||
/* set Date to NaN, after argument evaluation. */
|
||||
if (argIsNotFinite) {
|
||||
SetDateToNaN(cx, obj, &args.rval());
|
||||
SetDateToNaN(cx, thisObj, &args.rval());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1809,7 +1828,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
|
||||
if (local)
|
||||
result = UTC(result, cx);
|
||||
|
||||
return SetUTCTime(cx, obj, TimeClip(result), &args.rval());
|
||||
return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -1865,16 +1884,17 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
RootedObject obj(cx, NonGenericMethodGuard(cx, args, native, &DateClass, &ok));
|
||||
if (!obj)
|
||||
return ok;
|
||||
RootedObject thisObj(cx);
|
||||
if (!NonGenericMethodGuard(cx, args, native, &DateClass, thisObj.address()))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
|
||||
/* See complaint about ECMA in date_makeTime. */
|
||||
if (args.length() == 0) {
|
||||
SetDateToNaN(cx, obj, &args.rval());
|
||||
SetDateToNaN(cx, thisObj, &args.rval());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1894,7 +1914,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
|
||||
|
||||
/* If we found a non-finite argument, set the date to NaN and return. */
|
||||
if (argIsNotFinite) {
|
||||
SetDateToNaN(cx, obj, &args.rval());
|
||||
SetDateToNaN(cx, thisObj, &args.rval());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1939,7 +1959,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
|
||||
if (local)
|
||||
result = UTC(result, cx);
|
||||
|
||||
return SetUTCTime(cx, obj, TimeClip(result), &args.rval());
|
||||
return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -1983,24 +2003,25 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
RootedObject obj(cx, NonGenericMethodGuard(cx, args, date_setYear, &DateClass, &ok));
|
||||
if (!obj)
|
||||
return ok;
|
||||
RootedObject thisObj(cx);
|
||||
if (!NonGenericMethodGuard(cx, args, date_setYear, &DateClass, thisObj.address()))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (args.length() == 0) {
|
||||
/* Call this only after verifying that obj.[[Class]] = "Date". */
|
||||
SetDateToNaN(cx, obj, &args.rval());
|
||||
SetDateToNaN(cx, thisObj, &args.rval());
|
||||
return true;
|
||||
}
|
||||
|
||||
double result = obj->getDateUTCTime().toNumber();
|
||||
double result = thisObj->getDateUTCTime().toNumber();
|
||||
|
||||
double year;
|
||||
if (!ToNumber(cx, args[0], &year))
|
||||
return false;
|
||||
if (!MOZ_DOUBLE_IS_FINITE(year)) {
|
||||
SetDateToNaN(cx, obj, &args.rval());
|
||||
SetDateToNaN(cx, thisObj, &args.rval());
|
||||
return true;
|
||||
}
|
||||
year = ToInteger(year);
|
||||
@ -2012,7 +2033,7 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp)
|
||||
result = MakeDate(day, TimeWithinDay(t));
|
||||
result = UTC(result, cx);
|
||||
|
||||
return SetUTCTime(cx, obj, TimeClip(result), &args.rval());
|
||||
return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval());
|
||||
}
|
||||
|
||||
/* constants for toString, toUTCString */
|
||||
@ -2059,12 +2080,13 @@ static JSBool
|
||||
date_utc_format(JSContext *cx, Native native, CallArgs args,
|
||||
void (*printFunc)(char*, size_t, double))
|
||||
{
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, native, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double utctime = obj->getDateUTCTime().toNumber();
|
||||
double utctime = thisObj->getDateUTCTime().toNumber();
|
||||
|
||||
char buf[100];
|
||||
if (!MOZ_DOUBLE_IS_FINITE(utctime)) {
|
||||
@ -2338,12 +2360,13 @@ date_toLocaleHelper(JSContext *cx, unsigned argc, Value *vp, Native native, cons
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, native, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
return ToLocaleHelper(cx, args, obj, format);
|
||||
return ToLocaleHelper(cx, args, thisObj, format);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -2398,10 +2421,11 @@ date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp)
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_toLocaleFormat, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_toLocaleFormat, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
JSString *fmt = ToString(cx, args[0]);
|
||||
if (!fmt)
|
||||
@ -2412,7 +2436,7 @@ date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!fmtbytes)
|
||||
return false;
|
||||
|
||||
return ToLocaleHelper(cx, args, obj, fmtbytes.ptr());
|
||||
return ToLocaleHelper(cx, args, thisObj, fmtbytes.ptr());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -2420,12 +2444,13 @@ date_toTimeString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_toTimeString, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_toTimeString, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_TIME, args);
|
||||
return date_format(cx, thisObj->getDateUTCTime().toNumber(), FORMATSPEC_TIME, args);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -2433,12 +2458,13 @@ date_toDateString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_toDateString, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_toDateString, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_DATE, args);
|
||||
return date_format(cx, thisObj->getDateUTCTime().toNumber(), FORMATSPEC_DATE, args);
|
||||
}
|
||||
|
||||
#if JS_HAS_TOSOURCE
|
||||
@ -2447,13 +2473,15 @@ date_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_toSource, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_toSource, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.append("(new Date(") || !NumberValueToStringBuffer(cx, obj->getDateUTCTime(), sb) ||
|
||||
if (!sb.append("(new Date(") ||
|
||||
!NumberValueToStringBuffer(cx, thisObj->getDateUTCTime(), sb) ||
|
||||
!sb.append("))"))
|
||||
{
|
||||
return false;
|
||||
@ -2472,12 +2500,13 @@ date_toString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_toString, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_toString, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args);
|
||||
return date_format(cx, thisObj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -2485,14 +2514,15 @@ date_valueOf(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, date_valueOf, &DateClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, date_valueOf, &DateClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
/* If called directly with no arguments, convert to a time number. */
|
||||
if (argc == 0) {
|
||||
args.rval() = obj->getDateUTCTime();
|
||||
args.rval() = thisObj->getDateUTCTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2505,10 +2535,10 @@ date_valueOf(JSContext *cx, unsigned argc, Value *vp)
|
||||
return false;
|
||||
JSAtom *number_str = cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER];
|
||||
if (EqualStrings(linear_str, number_str)) {
|
||||
args.rval() = obj->getDateUTCTime();
|
||||
args.rval() = thisObj->getDateUTCTime();
|
||||
return true;
|
||||
}
|
||||
return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args);
|
||||
return date_format(cx, thisObj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args);
|
||||
}
|
||||
|
||||
static JSFunctionSpec date_static_methods[] = {
|
||||
|
@ -167,6 +167,12 @@ JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc)
|
||||
return cx->compartment->wrap(cx, desc);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
JS_WrapAutoIdVector(JSContext *cx, js::AutoIdVector &props)
|
||||
{
|
||||
return cx->compartment->wrap(cx, props);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape)
|
||||
{
|
||||
|
@ -130,6 +130,9 @@ JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc);
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_WrapAutoIdVector(JSContext *cx, JS::AutoIdVector &props);
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_EnumerateState(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, js::Value *statep, jsid *idp);
|
||||
|
||||
|
@ -426,7 +426,7 @@ js::CloneInterpretedFunction(JSContext *cx, JSFunction *srcFun)
|
||||
if (!clone->clearType(cx))
|
||||
return NULL;
|
||||
|
||||
JSScript *clonedScript = CloneScript(cx, srcFun->script());
|
||||
JSScript *clonedScript = CloneScript(cx, RootedScript(cx, srcFun->script()));
|
||||
if (!clonedScript)
|
||||
return NULL;
|
||||
|
||||
@ -1295,7 +1295,7 @@ js_CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
|
||||
* functions.
|
||||
*/
|
||||
if (clone->isInterpreted()) {
|
||||
JSScript *script = clone->script();
|
||||
RootedScript script(cx, clone->script());
|
||||
JS_ASSERT(script);
|
||||
JS_ASSERT(script->compartment() == fun->compartment());
|
||||
JS_ASSERT(script->compartment() != cx->compartment);
|
||||
|
@ -5508,15 +5508,18 @@ JSObject::shouldSplicePrototype(JSContext *cx)
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::splicePrototype(JSContext *cx, JSObject *proto)
|
||||
JSObject::splicePrototype(JSContext *cx, JSObject *proto_)
|
||||
{
|
||||
RootedObject proto(cx, proto_);
|
||||
RootedObject self(cx, this);
|
||||
|
||||
/*
|
||||
* For singleton types representing only a single JSObject, the proto
|
||||
* can be rearranged as needed without destroying type information for
|
||||
* the old or new types. Note that type constraints propagating properties
|
||||
* from the old prototype are not removed.
|
||||
*/
|
||||
JS_ASSERT_IF(cx->typeInferenceEnabled(), hasSingletonType());
|
||||
JS_ASSERT_IF(cx->typeInferenceEnabled(), self->hasSingletonType());
|
||||
|
||||
/* Inner objects may not appear on prototype chains. */
|
||||
JS_ASSERT_IF(proto, !proto->getClass()->ext.outerObject);
|
||||
@ -5525,7 +5528,7 @@ JSObject::splicePrototype(JSContext *cx, JSObject *proto)
|
||||
* Force type instantiation when splicing lazy types. This may fail,
|
||||
* in which case inference will be disabled for the compartment.
|
||||
*/
|
||||
TypeObject *type = getType(cx);
|
||||
TypeObject *type = self->getType(cx);
|
||||
TypeObject *protoType = NULL;
|
||||
if (proto) {
|
||||
protoType = proto->getType(cx);
|
||||
@ -5537,7 +5540,7 @@ JSObject::splicePrototype(JSContext *cx, JSObject *proto)
|
||||
TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx);
|
||||
if (!type)
|
||||
return false;
|
||||
type_ = type;
|
||||
self->type_ = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2329,11 +2329,11 @@ BEGIN_CASE(JSOP_GETXPROP)
|
||||
BEGIN_CASE(JSOP_LENGTH)
|
||||
BEGIN_CASE(JSOP_CALLPROP)
|
||||
{
|
||||
Value rval;
|
||||
if (!GetPropertyOperation(cx, regs.pc, regs.sp[-1], &rval))
|
||||
RootedValue rval(cx);
|
||||
if (!GetPropertyOperation(cx, regs.pc, regs.sp[-1], rval.address()))
|
||||
goto error;
|
||||
|
||||
TypeScript::Monitor(cx, script, regs.pc, rval);
|
||||
TypeScript::Monitor(cx, script, regs.pc, rval.reference());
|
||||
|
||||
regs.sp[-1] = rval;
|
||||
assertSameCompartment(cx, regs.sp[-1]);
|
||||
|
@ -287,9 +287,9 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val
|
||||
/* Fast path for, e.g., plain Object instance properties. */
|
||||
obj->nativeSetSlotWithType(cx, shape, rval);
|
||||
} else {
|
||||
Value rref = rval;
|
||||
RootedValue rref(cx, rval);
|
||||
bool strict = cx->stack.currentScript()->strictModeCode;
|
||||
if (!js_NativeSet(cx, obj, shape, false, strict, &rref))
|
||||
if (!js_NativeSet(cx, obj, shape, false, strict, rref.address()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -828,12 +828,13 @@ iterator_next(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
RootedObject obj(cx, NonGenericMethodGuard(cx, args, iterator_next, &IteratorClass, &ok));
|
||||
if (!obj)
|
||||
return ok;
|
||||
RootedObject thisObj(cx);
|
||||
if (!NonGenericMethodGuard(cx, args, iterator_next, &IteratorClass, thisObj.address()))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!js_IteratorMore(cx, obj, &args.rval()))
|
||||
if (!js_IteratorMore(cx, thisObj, &args.rval()))
|
||||
return false;
|
||||
|
||||
if (!args.rval().toBoolean()) {
|
||||
@ -841,7 +842,7 @@ iterator_next(JSContext *cx, unsigned argc, Value *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
return js_IteratorNext(cx, obj, &args.rval());
|
||||
return js_IteratorNext(cx, thisObj, &args.rval());
|
||||
}
|
||||
|
||||
#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT)
|
||||
@ -1582,12 +1583,13 @@ generator_op(JSContext *cx, Native native, JSGeneratorOp op, Value *vp, unsigned
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, native, &GeneratorClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, native, &GeneratorClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
JSGenerator *gen = (JSGenerator *) obj->getPrivate();
|
||||
JSGenerator *gen = (JSGenerator *) thisObj->getPrivate();
|
||||
if (!gen) {
|
||||
/* This happens when obj is the generator prototype. See bug 352885. */
|
||||
goto closed_generator;
|
||||
@ -1630,7 +1632,7 @@ generator_op(JSContext *cx, Native native, JSGeneratorOp op, Value *vp, unsigned
|
||||
}
|
||||
|
||||
bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && args.length() != 0);
|
||||
if (!SendToGenerator(cx, op, obj, gen, undef ? args[0] : UndefinedValue()))
|
||||
if (!SendToGenerator(cx, op, thisObj, gen, undef ? args[0] : UndefinedValue()))
|
||||
return false;
|
||||
|
||||
args.rval() = gen->fp->returnValue();
|
||||
|
@ -1930,7 +1930,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD
|
||||
|
||||
JS_ASSERT(obj == obj2);
|
||||
|
||||
const Shape *shape = reinterpret_cast<Shape *>(current);
|
||||
Rooted<const Shape *> shape(cx, reinterpret_cast<Shape *>(current));
|
||||
do {
|
||||
if (desc.isAccessorDescriptor()) {
|
||||
if (!shape->isAccessorDescriptor())
|
||||
@ -3040,10 +3040,8 @@ Detecting(JSContext *cx, jsbytecode *pc)
|
||||
}
|
||||
|
||||
/*
|
||||
* Infer lookup flags from the currently executing bytecode. This does
|
||||
* not attempt to infer JSRESOLVE_WITH, because the current bytecode
|
||||
* does not indicate whether we are in a with statement. Return defaultFlags
|
||||
* if a currently executing bytecode cannot be determined.
|
||||
* Infer lookup flags from the currently executing bytecode, returning
|
||||
* defaultFlags if a currently executing bytecode cannot be determined.
|
||||
*/
|
||||
unsigned
|
||||
js_InferFlags(JSContext *cx, unsigned defaultFlags)
|
||||
@ -4974,7 +4972,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, bool
|
||||
Rooted<const Shape *> shapeRoot(cx, shape);
|
||||
|
||||
int32_t sample = cx->runtime->propertyRemovals;
|
||||
if (!shape->set(cx, RootedObject(cx, obj), strict, vp))
|
||||
if (!shapeRoot->set(cx, RootedObject(cx, obj), strict, vp))
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
@ -459,6 +459,7 @@ bool
|
||||
IndirectProxyHandler::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp,
|
||||
Native native, CallArgs args)
|
||||
{
|
||||
args.thisv() = ObjectValue(*GetProxyTargetObject(proxy));
|
||||
return CallJSNative(cx, native, args);
|
||||
}
|
||||
|
||||
|
@ -965,7 +965,7 @@ JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *n
|
||||
RootedShape newRoot(cx, newShape);
|
||||
if (!toDictionaryMode(cx))
|
||||
return NULL;
|
||||
oldShape = self->lastProperty();
|
||||
oldShape = selfRoot->lastProperty();
|
||||
self = selfRoot;
|
||||
newShape = newRoot;
|
||||
}
|
||||
@ -976,7 +976,7 @@ JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *n
|
||||
newShape = js_NewGCShape(cx);
|
||||
if (!newShape)
|
||||
return NULL;
|
||||
new (newShape) Shape(oldShape->base()->unowned(), 0);
|
||||
new (newShape) Shape(oldRoot->base()->unowned(), 0);
|
||||
self = selfRoot;
|
||||
oldShape = oldRoot;
|
||||
}
|
||||
@ -1315,7 +1315,7 @@ EmptyShape::getInitialShape(JSContext *cx, Class *clasp, JSObject *proto, JSObje
|
||||
}
|
||||
|
||||
void
|
||||
NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto)
|
||||
NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto_)
|
||||
{
|
||||
Class *clasp = shape->getObjectClass();
|
||||
|
||||
@ -1323,7 +1323,8 @@ NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject
|
||||
if (CanBeFinalizedInBackground(kind, clasp))
|
||||
kind = GetBackgroundAllocKind(kind);
|
||||
|
||||
GlobalObject *global = &shape->getObjectParent()->global();
|
||||
Rooted<GlobalObject *> global(cx, &shape->getObjectParent()->global());
|
||||
RootedObject proto(cx, proto_);
|
||||
types::TypeObject *type = proto->getNewType(cx);
|
||||
|
||||
EntryIndex entry;
|
||||
|
@ -1110,8 +1110,8 @@ Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
|
||||
if (start->isBigEnoughForAShapeTable()) {
|
||||
RootedShape startRoot(cx, start);
|
||||
RootedId idRoot(cx, id);
|
||||
if (start->hashify(cx)) {
|
||||
Shape **spp = start->table().search(id, adding);
|
||||
if (startRoot->hashify(cx)) {
|
||||
Shape **spp = startRoot->table().search(id, adding);
|
||||
return SHAPE_FETCH(spp);
|
||||
}
|
||||
start = startRoot;
|
||||
|
@ -259,7 +259,7 @@ Shape::getUserId(JSContext *cx, jsid *idp) const
|
||||
return ValueToId(cx, Int32Value(id), idp);
|
||||
*idp = INT_TO_JSID(id);
|
||||
} else {
|
||||
*idp = propid();
|
||||
*idp = self->propid();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -274,11 +274,12 @@ Shape::get(JSContext* cx, HandleObject receiver, JSObject* obj, JSObject *pobj,
|
||||
return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
|
||||
}
|
||||
|
||||
Rooted<const Shape *> self(cx, this);
|
||||
RootedId id(cx);
|
||||
if (!getUserId(cx, id.address()))
|
||||
if (!self->getUserId(cx, id.address()))
|
||||
return false;
|
||||
|
||||
return CallJSPropertyOp(cx, getterOp(), receiver, id, vp);
|
||||
return CallJSPropertyOp(cx, self->getterOp(), receiver, id, vp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
@ -294,8 +295,9 @@ Shape::set(JSContext* cx, HandleObject obj, bool strict, Value* vp) const
|
||||
if (attrs & JSPROP_GETTER)
|
||||
return js_ReportGetterOnlyAssignment(cx);
|
||||
|
||||
Rooted<const Shape *> self(cx, this);
|
||||
RootedId id(cx);
|
||||
if (!getUserId(cx, id.address()))
|
||||
if (!self->getUserId(cx, id.address()))
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -304,10 +306,10 @@ Shape::set(JSContext* cx, HandleObject obj, bool strict, Value* vp) const
|
||||
*/
|
||||
if (obj->isWith()) {
|
||||
RootedObject nobj(cx, &obj->asWith().object());
|
||||
return CallJSPropertyOpSetter(cx, setterOp(), nobj, id, strict, vp);
|
||||
return CallJSPropertyOpSetter(cx, self->setterOp(), nobj, id, strict, vp);
|
||||
}
|
||||
|
||||
return CallJSPropertyOpSetter(cx, setterOp(), obj, id, strict, vp);
|
||||
return CallJSPropertyOpSetter(cx, self->setterOp(), obj, id, strict, vp);
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -1684,7 +1684,7 @@ Rebase(JSScript *dst, JSScript *src, T *srcp)
|
||||
}
|
||||
|
||||
JSScript *
|
||||
js::CloneScript(JSContext *cx, JSScript *src)
|
||||
js::CloneScript(JSContext *cx, HandleScript src)
|
||||
{
|
||||
/* NB: Keep this in sync with XDRScript. */
|
||||
|
||||
@ -1707,6 +1707,7 @@ js::CloneScript(JSContext *cx, JSScript *src)
|
||||
/* Bindings */
|
||||
|
||||
Bindings bindings(cx);
|
||||
Bindings::AutoRooter bindingsRoot(cx, &bindings);
|
||||
BindingNames names(cx);
|
||||
if (!src->bindings.getLocalNameArray(cx, &names))
|
||||
return NULL;
|
||||
|
@ -1050,7 +1050,7 @@ inline void
|
||||
CurrentScriptFileLineOrigin(JSContext *cx, unsigned *linenop, LineOption = NOT_CALLED_FROM_JSOP_EVAL);
|
||||
|
||||
extern JSScript *
|
||||
CloneScript(JSContext *cx, JSScript *script);
|
||||
CloneScript(JSContext *cx, HandleScript script);
|
||||
|
||||
/*
|
||||
* NB: after a successful XDR_DECODE, XDRScript callers must do any required
|
||||
|
@ -134,12 +134,13 @@ ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_slice, &ArrayBufferClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_slice, &ArrayBufferClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
ArrayBufferObject &arrayBuffer = obj->asArrayBuffer();
|
||||
ArrayBufferObject &arrayBuffer = thisObj->asArrayBuffer();
|
||||
|
||||
// these are the default values
|
||||
int32_t length = int32_t(arrayBuffer.byteLength());
|
||||
@ -485,7 +486,8 @@ JSBool
|
||||
ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj,
|
||||
HandleObject receiver, uint32_t index, Value *vp)
|
||||
{
|
||||
RootedObject delegate(cx, DelegateObject(cx, RootedObject(cx, getArrayBuffer(obj))));
|
||||
RootedObject buffer(cx, getArrayBuffer(obj));
|
||||
RootedObject delegate(cx, DelegateObject(cx, buffer));
|
||||
if (!delegate)
|
||||
return false;
|
||||
return baseops::GetElement(cx, delegate, receiver, index, vp);
|
||||
@ -495,7 +497,8 @@ JSBool
|
||||
ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
|
||||
uint32_t index, Value *vp, bool *present)
|
||||
{
|
||||
JSObject *delegate = DelegateObject(cx, RootedObject(cx, getArrayBuffer(obj)));
|
||||
RootedObject buffer(cx, getArrayBuffer(obj));
|
||||
RootedObject delegate(cx, DelegateObject(cx, buffer));
|
||||
if (!delegate)
|
||||
return false;
|
||||
return delegate->getElementIfPresent(cx, receiver, index, vp, present);
|
||||
@ -1419,14 +1422,14 @@ class TypedArrayTemplate
|
||||
obj->setSlot(FIELD_BUFFER, ObjectValue(*bufobj));
|
||||
|
||||
JS_ASSERT(bufobj->isArrayBuffer());
|
||||
ArrayBufferObject &buffer = bufobj->asArrayBuffer();
|
||||
Rooted<ArrayBufferObject *> buffer(cx, &bufobj->asArrayBuffer());
|
||||
|
||||
/*
|
||||
* N.B. The base of the array's data is stored in the object's
|
||||
* private data rather than a slot, to avoid alignment restrictions
|
||||
* on private Values.
|
||||
*/
|
||||
obj->setPrivate(buffer.dataPointer() + byteOffset);
|
||||
obj->setPrivate(buffer->dataPointer() + byteOffset);
|
||||
|
||||
obj->setSlot(FIELD_LENGTH, Int32Value(len));
|
||||
obj->setSlot(FIELD_BYTEOFFSET, Int32Value(byteOffset));
|
||||
@ -1442,10 +1445,10 @@ class TypedArrayTemplate
|
||||
return NULL;
|
||||
obj->setLastPropertyInfallible(empty);
|
||||
|
||||
DebugOnly<uint32_t> bufferByteLength = buffer.byteLength();
|
||||
DebugOnly<uint32_t> bufferByteLength = buffer->byteLength();
|
||||
JS_ASSERT(bufferByteLength - getByteOffset(obj) >= getByteLength(obj));
|
||||
JS_ASSERT(getByteOffset(obj) <= bufferByteLength);
|
||||
JS_ASSERT(buffer.dataPointer() <= getDataOffset(obj));
|
||||
JS_ASSERT(buffer->dataPointer() <= getDataOffset(obj));
|
||||
JS_ASSERT(getDataOffset(obj) <= offsetData(obj, bufferByteLength));
|
||||
|
||||
JS_ASSERT(obj->numFixedSlots() == NUM_FIXED_SLOTS);
|
||||
@ -1453,6 +1456,13 @@ class TypedArrayTemplate
|
||||
return obj;
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
makeInstance(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len)
|
||||
{
|
||||
RootedObject nullproto(cx, NULL);
|
||||
return makeInstance(cx, bufobj, byteOffset, len, nullproto);
|
||||
}
|
||||
|
||||
/*
|
||||
* new [Type]Array(length)
|
||||
* new [Type]Array(otherTypedArray)
|
||||
@ -1474,8 +1484,9 @@ class TypedArrayTemplate
|
||||
fromBuffer(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
JSObject *obj = fromBuffer(cx, RootedObject(cx, &args[0].toObject()),
|
||||
args[1].toInt32(), args[2].toInt32(), RootedObject(cx, &args[3].toObject()));
|
||||
RootedObject buffer(cx, &args[0].toObject());
|
||||
RootedObject proto(cx, &args[3].toObject());
|
||||
JSObject *obj = fromBuffer(cx, buffer, args[1].toInt32(), args[2].toInt32(), proto);
|
||||
if (!obj)
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
@ -1544,12 +1555,13 @@ class TypedArrayTemplate
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_subarray, fastClass(), &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_subarray, fastClass(), &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
JSObject *tarray = getTypedArray(obj);
|
||||
JSObject *tarray = getTypedArray(thisObj);
|
||||
if (!tarray)
|
||||
return true;
|
||||
|
||||
@ -1583,12 +1595,13 @@ class TypedArrayTemplate
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
RootedObject obj(cx, NonGenericMethodGuard(cx, args, fun_set, fastClass(), &ok));
|
||||
if (!obj)
|
||||
return ok;
|
||||
RootedObject thisObj(cx);
|
||||
if (!NonGenericMethodGuard(cx, args, fun_set, fastClass(), thisObj.address()))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
RootedObject tarray(cx, getTypedArray(obj));
|
||||
RootedObject tarray(cx, getTypedArray(thisObj));
|
||||
if (!tarray)
|
||||
return true;
|
||||
|
||||
@ -1623,7 +1636,7 @@ class TypedArrayTemplate
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!copyFromTypedArray(cx, obj, src, offset))
|
||||
if (!copyFromTypedArray(cx, thisObj, src, offset))
|
||||
return false;
|
||||
} else {
|
||||
src = arg0;
|
||||
@ -1637,7 +1650,7 @@ class TypedArrayTemplate
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!copyFromArray(cx, obj, src, len, offset))
|
||||
if (!copyFromArray(cx, thisObj, src, len, offset))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1743,7 +1756,7 @@ class TypedArrayTemplate
|
||||
RootedObject buffer(cx, createBufferWithSizeAndCount(cx, nelements));
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
return makeInstance(cx, buffer, 0, nelements, RootedObject(cx, NULL));
|
||||
return makeInstance(cx, buffer, 0, nelements);
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
@ -1757,7 +1770,7 @@ class TypedArrayTemplate
|
||||
if (!bufobj)
|
||||
return NULL;
|
||||
|
||||
RootedObject obj(cx, makeInstance(cx, bufobj, 0, len, RootedObject(cx)));
|
||||
RootedObject obj(cx, makeInstance(cx, bufobj, 0, len));
|
||||
if (!obj || !copyFromArray(cx, obj, other, len))
|
||||
return NULL;
|
||||
return obj;
|
||||
@ -1795,7 +1808,7 @@ class TypedArrayTemplate
|
||||
JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= getByteOffset(tarray));
|
||||
uint32_t byteOffset = getByteOffset(tarray) + begin * sizeof(NativeType);
|
||||
|
||||
return makeInstance(cx, bufobj, byteOffset, length, RootedObject(cx));
|
||||
return makeInstance(cx, bufobj, byteOffset, length);
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -2287,6 +2300,9 @@ DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
|
||||
argv[argc + 2].setObject(*proto);
|
||||
argv[0].setUndefined(); // We want to use a different callee (avoid an assertion)
|
||||
|
||||
// Appease 'thisv' assertion in CrossCompartmentWrapper::nativeCall
|
||||
argv[1].setMagic(JS_IS_CONSTRUCTING);
|
||||
|
||||
CallArgs proxyArgs = CallArgsFromVp(argc + 1, argv.begin());
|
||||
if (!Proxy::nativeCall(cx, bufobj, &DataViewClass, constructWithProto, proxyArgs))
|
||||
return false;
|
||||
@ -2481,13 +2497,14 @@ DataViewObject::fun_getInt8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_getInt8, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getInt8, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
int8_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getInt8"))
|
||||
if (!thisObj->asDataView().read(cx, args, &val, "getInt8"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
@ -2498,13 +2515,14 @@ DataViewObject::fun_getUint8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_getUint8, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getUint8, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
uint8_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getUint8"))
|
||||
if (!thisObj->asDataView().read(cx, args, &val, "getUint8"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
@ -2515,13 +2533,14 @@ DataViewObject::fun_getInt16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_getInt16, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getInt16, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
int16_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getInt16"))
|
||||
if (!thisObj->asDataView().read(cx, args, &val, "getInt16"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
@ -2532,13 +2551,14 @@ DataViewObject::fun_getUint16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_getUint16, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getUint16, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
uint16_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getUint16"))
|
||||
if (!thisObj->asDataView().read(cx, args, &val, "getUint16"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
@ -2549,13 +2569,14 @@ DataViewObject::fun_getInt32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_getInt32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getInt32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
int32_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getInt32"))
|
||||
if (!thisObj->asDataView().read(cx, args, &val, "getInt32"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
@ -2566,13 +2587,14 @@ DataViewObject::fun_getUint32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_getUint32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getUint32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
uint32_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getUint32"))
|
||||
if (!thisObj->asDataView().read(cx, args, &val, "getUint32"))
|
||||
return false;
|
||||
args.rval().setNumber(val);
|
||||
return true;
|
||||
@ -2583,13 +2605,14 @@ DataViewObject::fun_getFloat32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_getFloat32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getFloat32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
float val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getFloat32"))
|
||||
if (!thisObj->asDataView().read(cx, args, &val, "getFloat32"))
|
||||
return false;
|
||||
|
||||
args.rval().setDouble(JS_CANONICALIZE_NAN(val));
|
||||
@ -2601,13 +2624,14 @@ DataViewObject::fun_getFloat64(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_getFloat64, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_getFloat64, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
double val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getFloat64"))
|
||||
if (!thisObj->asDataView().read(cx, args, &val, "getFloat64"))
|
||||
return false;
|
||||
|
||||
args.rval().setDouble(JS_CANONICALIZE_NAN(val));
|
||||
@ -2619,12 +2643,13 @@ DataViewObject::fun_setInt8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_setInt8, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setInt8, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!obj->asDataView().write<int8_t>(cx, args, "setInt8"))
|
||||
if (!thisObj->asDataView().write<int8_t>(cx, args, "setInt8"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2635,12 +2660,13 @@ DataViewObject::fun_setUint8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_setUint8, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setUint8, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!obj->asDataView().write<uint8_t>(cx, args, "setUint8"))
|
||||
if (!thisObj->asDataView().write<uint8_t>(cx, args, "setUint8"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2651,12 +2677,13 @@ DataViewObject::fun_setInt16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_setInt16, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setInt16, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!obj->asDataView().write<int16_t>(cx, args, "setInt16"))
|
||||
if (!thisObj->asDataView().write<int16_t>(cx, args, "setInt16"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2667,12 +2694,13 @@ DataViewObject::fun_setUint16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_setUint16, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setUint16, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!obj->asDataView().write<uint16_t>(cx, args, "setUint16"))
|
||||
if (!thisObj->asDataView().write<uint16_t>(cx, args, "setUint16"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2683,12 +2711,13 @@ DataViewObject::fun_setInt32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_setInt32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setInt32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!obj->asDataView().write<int32_t>(cx, args, "setInt32"))
|
||||
if (!thisObj->asDataView().write<int32_t>(cx, args, "setInt32"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2699,12 +2728,13 @@ DataViewObject::fun_setUint32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_setUint32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setUint32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!obj->asDataView().write<uint32_t>(cx, args, "setUint32"))
|
||||
if (!thisObj->asDataView().write<uint32_t>(cx, args, "setUint32"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2715,12 +2745,13 @@ DataViewObject::fun_setFloat32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_setFloat32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setFloat32, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!obj->asDataView().write<float>(cx, args, "setFloat32"))
|
||||
if (!thisObj->asDataView().write<float>(cx, args, "setFloat32"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2731,12 +2762,13 @@ DataViewObject::fun_setFloat64(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, fun_setFloat64, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, fun_setFloat64, &DataViewClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (!obj->asDataView().write<double>(cx, args, "setFloat64"))
|
||||
if (!thisObj->asDataView().write<double>(cx, args, "setFloat64"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2918,6 +2950,7 @@ IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double)
|
||||
#_typedArray, \
|
||||
JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) | \
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | \
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray) | \
|
||||
JSCLASS_FOR_OF_ITERATION | \
|
||||
Class::NON_NATIVE, \
|
||||
JS_PropertyStub, /* addProperty */ \
|
||||
|
@ -12,8 +12,6 @@
|
||||
* Implementation details for js::Value in jsapi.h.
|
||||
*/
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
@ -125,10 +125,11 @@ WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_has, &WeakMapClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, WeakMap_has, &WeakMapClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||
@ -139,7 +140,7 @@ WeakMap_has(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
ObjectValueMap *map = GetObjectMap(obj);
|
||||
ObjectValueMap *map = GetObjectMap(thisObj);
|
||||
if (map) {
|
||||
ObjectValueMap::Ptr ptr = map->lookup(key);
|
||||
if (ptr) {
|
||||
@ -157,10 +158,11 @@ WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_get, &WeakMapClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, WeakMap_get, &WeakMapClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||
@ -171,7 +173,7 @@ WeakMap_get(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
ObjectValueMap *map = GetObjectMap(obj);
|
||||
ObjectValueMap *map = GetObjectMap(thisObj);
|
||||
if (map) {
|
||||
ObjectValueMap::Ptr ptr = map->lookup(key);
|
||||
if (ptr) {
|
||||
@ -189,10 +191,11 @@ WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_delete, &WeakMapClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, WeakMap_delete, &WeakMapClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||
@ -203,7 +206,7 @@ WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
ObjectValueMap *map = GetObjectMap(obj);
|
||||
ObjectValueMap *map = GetObjectMap(thisObj);
|
||||
if (map) {
|
||||
ObjectValueMap::Ptr ptr = map->lookup(key);
|
||||
if (ptr) {
|
||||
@ -222,10 +225,11 @@ WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_set, &WeakMapClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
JSObject *thisObj;
|
||||
if (!NonGenericMethodGuard(cx, args, WeakMap_set, &WeakMapClass, &thisObj))
|
||||
return false;
|
||||
if (!thisObj)
|
||||
return true;
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||
@ -238,14 +242,14 @@ WeakMap_set(JSContext *cx, unsigned argc, Value *vp)
|
||||
|
||||
Value value = (args.length() > 1) ? args[1] : UndefinedValue();
|
||||
|
||||
ObjectValueMap *map = GetObjectMap(obj);
|
||||
ObjectValueMap *map = GetObjectMap(thisObj);
|
||||
if (!map) {
|
||||
map = cx->new_<ObjectValueMap>(cx, obj);
|
||||
map = cx->new_<ObjectValueMap>(cx, thisObj);
|
||||
if (!map->init()) {
|
||||
cx->delete_(map);
|
||||
goto out_of_memory;
|
||||
}
|
||||
obj->setPrivate(map);
|
||||
thisObj->setPrivate(map);
|
||||
}
|
||||
|
||||
if (!map->put(key, value))
|
||||
|
@ -706,7 +706,7 @@ CrossCompartmentWrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *cla
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DirectWrapper::nativeCall(cx, wrapper, clasp, native, dstArgs))
|
||||
if (!CallJSNative(cx, native, dstArgs))
|
||||
return false;
|
||||
|
||||
srcArgs.rval() = dstArgs.rval();
|
||||
|
@ -491,6 +491,37 @@ NewXMLAttributeName(JSContext *cx, JSLinearString *uri, JSLinearString *prefix,
|
||||
return obj;
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
ConstructObjectWithArguments(JSContext *cx, Class *clasp, JSObject *parent,
|
||||
unsigned argc, jsval *argv)
|
||||
{
|
||||
assertSameCompartment(cx, parent, JSValueArray(argv, argc));
|
||||
|
||||
AutoArrayRooter argtvr(cx, argc, argv);
|
||||
|
||||
JSProtoKey protoKey = GetClassProtoKey(clasp);
|
||||
|
||||
/* Protect constructor in case a crazy getter for .prototype uproots it. */
|
||||
RootedValue value(cx);
|
||||
if (!js_FindClassObject(cx, parent, protoKey, value.address(), clasp))
|
||||
return NULL;
|
||||
|
||||
Value rval;
|
||||
if (!InvokeConstructor(cx, value, argc, argv, &rval))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If the instance's class differs from what was requested, throw a type
|
||||
* error.
|
||||
*/
|
||||
if (!rval.isObject() || rval.toObject().getClass() != clasp) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_WRONG_CONSTRUCTOR, clasp->name);
|
||||
return NULL;
|
||||
}
|
||||
return &rval.toObject();
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_ConstructXMLQNameObject(JSContext *cx, const Value &nsval, const Value &lnval)
|
||||
{
|
||||
@ -508,7 +539,7 @@ js_ConstructXMLQNameObject(JSContext *cx, const Value &nsval, const Value &lnval
|
||||
argv[0] = nsval;
|
||||
}
|
||||
argv[1] = lnval;
|
||||
return JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 2, argv);
|
||||
return ConstructObjectWithArguments(cx, &QNameClass, NULL, 2, argv);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -2250,7 +2281,7 @@ GetNamespace(JSContext *cx, JSObject *qn, const JSXMLArray<JSObject> *inScopeNSe
|
||||
if (!match) {
|
||||
argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID;
|
||||
argv[1] = STRING_TO_JSVAL(uri);
|
||||
ns = JS_ConstructObjectWithArguments(cx, Jsvalify(&NamespaceClass), NULL, 2, argv);
|
||||
ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, 2, argv);
|
||||
if (!ns)
|
||||
return NULL;
|
||||
match = ns;
|
||||
@ -2929,7 +2960,7 @@ ToXMLName(JSContext *cx, jsval v, jsid *funidp)
|
||||
|
||||
construct:
|
||||
v = STRING_TO_JSVAL(name);
|
||||
obj = JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 1, &v);
|
||||
obj = ConstructObjectWithArguments(cx, &QNameClass, NULL, 1, &v);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
@ -6713,7 +6744,7 @@ xml_setName(JSContext *cx, unsigned argc, jsval *vp)
|
||||
}
|
||||
}
|
||||
|
||||
nameqn = JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 1, &name);
|
||||
nameqn = ConstructObjectWithArguments(cx, &QNameClass, NULL, 1, &name);
|
||||
if (!nameqn)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -6818,8 +6849,7 @@ xml_setNamespace(JSContext *cx, unsigned argc, jsval *vp)
|
||||
if (!JSXML_HAS_NAME(xml))
|
||||
return JS_TRUE;
|
||||
|
||||
ns = JS_ConstructObjectWithArguments(cx, Jsvalify(&NamespaceClass), NULL,
|
||||
argc == 0 ? 0 : 1, vp + 2);
|
||||
ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, argc == 0 ? 0 : 1, vp + 2);
|
||||
if (!ns)
|
||||
return JS_FALSE;
|
||||
vp[0] = OBJECT_TO_JSVAL(ns);
|
||||
@ -6827,7 +6857,7 @@ xml_setNamespace(JSContext *cx, unsigned argc, jsval *vp)
|
||||
|
||||
qnargv[0] = OBJECT_TO_JSVAL(ns);
|
||||
qnargv[1] = OBJECT_TO_JSVAL(xml->name);
|
||||
qn = JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 2, qnargv);
|
||||
qn = ConstructObjectWithArguments(cx, &QNameClass, NULL, 2, qnargv);
|
||||
if (!qn)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -7569,7 +7599,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
|
||||
obj = tmp;
|
||||
}
|
||||
|
||||
ns = JS_ConstructObjectWithArguments(cx, Jsvalify(&NamespaceClass), NULL, 0, NULL);
|
||||
ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, 0, NULL);
|
||||
if (!ns)
|
||||
return JS_FALSE;
|
||||
v = OBJECT_TO_JSVAL(ns);
|
||||
@ -7587,7 +7617,7 @@ js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
|
||||
Value argv[2];
|
||||
argv[0].setString(cx->runtime->emptyString);
|
||||
argv[1] = v;
|
||||
JSObject *ns = JS_ConstructObjectWithArguments(cx, Jsvalify(&NamespaceClass), NULL, 2, argv);
|
||||
JSObject *ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, 2, argv);
|
||||
if (!ns)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -7705,7 +7735,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i
|
||||
nameobj = &nameval.toObject();
|
||||
if (nameobj->getClass() == &AnyNameClass) {
|
||||
v = STRING_TO_JSVAL(cx->runtime->atomState.starAtom);
|
||||
nameobj = JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 1, &v);
|
||||
nameobj = ConstructObjectWithArguments(cx, &QNameClass, NULL, 1, &v);
|
||||
if (!nameobj)
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
|
@ -2143,7 +2143,7 @@ DumpStack(JSContext *cx, unsigned argc, Value *vp)
|
||||
|
||||
uint32_t index = 0;
|
||||
for (; !iter.done(); ++index, ++iter) {
|
||||
Value v;
|
||||
RootedValue v(cx);
|
||||
if (iter.isNonEvalFunctionFrame() || iter.isNativeCall()) {
|
||||
v = iter.calleev();
|
||||
} else if (iter.isEvalFrame()) {
|
||||
@ -2151,9 +2151,9 @@ DumpStack(JSContext *cx, unsigned argc, Value *vp)
|
||||
} else {
|
||||
v = StringValue(globalStr);
|
||||
}
|
||||
if (!JS_WrapValue(cx, &v))
|
||||
if (!JS_WrapValue(cx, v.address()))
|
||||
return false;
|
||||
if (!JS_SetElement(cx, arr, index, &v))
|
||||
if (!JS_SetElement(cx, arr, index, v.address()))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1631,6 +1631,14 @@ function test() {
|
||||
assertEq(av.getUint8(4), 100);
|
||||
assertEq(Object.getPrototypeOf(av), DataView.prototype);
|
||||
|
||||
// Bug 760904: call another compartment's constructor with an ArrayBuffer
|
||||
// from this compartment, both as a constructor and as a regular call. (The
|
||||
// latter is what was broken in that bug.)
|
||||
var alien_constructor = alien.DataView;
|
||||
var local_buffer = (new Int8Array(3)).buffer;
|
||||
var foreign_exchange_student_1 = alien_constructor(local_buffer);
|
||||
var foreign_exchange_student_2 = new alien_constructor(local_buffer);
|
||||
|
||||
reportCompare(0, 0, 'done.');
|
||||
exitFunc ('test');
|
||||
}
|
||||
|
@ -941,7 +941,7 @@ Debugger::fireEnterFrame(JSContext *cx, Value *vp)
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::fireNewScript(JSContext *cx, Handle<JSScript*> script)
|
||||
Debugger::fireNewScript(JSContext *cx, HandleScript script)
|
||||
{
|
||||
RootedObject hook(cx, getHook(OnNewScript));
|
||||
JS_ASSERT(hook);
|
||||
@ -2376,7 +2376,7 @@ Class DebuggerScript_class = {
|
||||
};
|
||||
|
||||
JSObject *
|
||||
Debugger::newDebuggerScript(JSContext *cx, Handle<JSScript*> script)
|
||||
Debugger::newDebuggerScript(JSContext *cx, HandleScript script)
|
||||
{
|
||||
assertSameCompartment(cx, object.get());
|
||||
|
||||
@ -2392,7 +2392,7 @@ Debugger::newDebuggerScript(JSContext *cx, Handle<JSScript*> script)
|
||||
}
|
||||
|
||||
JSObject *
|
||||
Debugger::wrapScript(JSContext *cx, Handle<JSScript*> script)
|
||||
Debugger::wrapScript(JSContext *cx, HandleScript script)
|
||||
{
|
||||
assertSameCompartment(cx, object.get());
|
||||
JS_ASSERT(cx->compartment != script->compartment());
|
||||
@ -4396,7 +4396,7 @@ DebuggerEnv_getVariable(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!ValueToIdentifier(cx, args[0], id.address()))
|
||||
return false;
|
||||
|
||||
Value v;
|
||||
RootedValue v(cx);
|
||||
{
|
||||
AutoCompartment ac(cx, env);
|
||||
if (!ac.enter() || !cx->compartment->wrapId(cx, id.address()))
|
||||
@ -4404,11 +4404,11 @@ DebuggerEnv_getVariable(JSContext *cx, unsigned argc, Value *vp)
|
||||
|
||||
/* This can trigger getters. */
|
||||
ErrorCopier ec(ac, dbg->toJSObject());
|
||||
if (!env->getGeneric(cx, id, &v))
|
||||
if (!env->getGeneric(cx, id, v.address()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dbg->wrapDebuggeeValue(cx, &v))
|
||||
if (!dbg->wrapDebuggeeValue(cx, v.address()))
|
||||
return false;
|
||||
args.rval() = v;
|
||||
return true;
|
||||
|
@ -190,13 +190,13 @@ class Debugger {
|
||||
* Allocate and initialize a Debugger.Script instance whose referent is
|
||||
* |script|.
|
||||
*/
|
||||
JSObject *newDebuggerScript(JSContext *cx, Handle<JSScript*> script);
|
||||
JSObject *newDebuggerScript(JSContext *cx, HandleScript script);
|
||||
|
||||
/*
|
||||
* Receive a "new script" event from the engine. A new script was compiled
|
||||
* or deserialized.
|
||||
*/
|
||||
void fireNewScript(JSContext *cx, Handle<JSScript*> script);
|
||||
void fireNewScript(JSContext *cx, HandleScript script);
|
||||
|
||||
static inline Debugger *fromLinks(JSCList *links);
|
||||
inline Breakpoint *firstBreakpoint() const;
|
||||
@ -337,7 +337,7 @@ class Debugger {
|
||||
* needed. The context |cx| must be in the debugger compartment; |script|
|
||||
* must be a script in a debuggee compartment.
|
||||
*/
|
||||
JSObject *wrapScript(JSContext *cx, Handle<JSScript*> script);
|
||||
JSObject *wrapScript(JSContext *cx, HandleScript script);
|
||||
|
||||
private:
|
||||
Debugger(const Debugger &) MOZ_DELETE;
|
||||
|
@ -53,20 +53,20 @@ class PrimitiveBehavior<JSString *> {
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
inline JSObject *
|
||||
NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok)
|
||||
inline bool
|
||||
NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, JSObject **thisObj)
|
||||
{
|
||||
const Value &thisv = args.thisv();
|
||||
if (thisv.isObject()) {
|
||||
JSObject &obj = thisv.toObject();
|
||||
if (obj.getClass() == clasp) {
|
||||
*ok = true; /* quell gcc overwarning */
|
||||
return &obj;
|
||||
*thisObj = &obj;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*ok = HandleNonGenericMethodClassMismatch(cx, args, native, clasp);
|
||||
return NULL;
|
||||
*thisObj = NULL;
|
||||
return HandleNonGenericMethodClassMismatch(cx, args, native, clasp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -81,10 +81,11 @@ BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, boo
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!NonGenericMethodGuard(cx, args, native, Behavior::getClass(), ok))
|
||||
JSObject *thisObj;
|
||||
*ok = NonGenericMethodGuard(cx, args, native, Behavior::getClass(), &thisObj);
|
||||
if (!*ok || !thisObj)
|
||||
return false;
|
||||
|
||||
*v = Behavior::extract(thisv.toObject());
|
||||
*v = Behavior::extract(*thisObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -32,31 +32,36 @@ ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp);
|
||||
* NonGenericMethodGuard performs this checking. Canonical usage is:
|
||||
*
|
||||
* CallArgs args = ...
|
||||
* bool ok;
|
||||
* JSObject *thisObj = NonGenericMethodGuard(cx, args, clasp, &ok);
|
||||
* JSObject *thisObj;
|
||||
* if (!NonGenericMethodGuard(cx, args, clasp, &thisObj))
|
||||
* return false;
|
||||
* if (!thisObj)
|
||||
* return ok;
|
||||
* return true;
|
||||
*
|
||||
* Specifically: if obj is a proxy, NonGenericMethodGuard will call the
|
||||
* object's ProxyHandler's nativeCall hook (which may recursively call
|
||||
* args.callee in args.thisv's compartment). Thus, there are three possible
|
||||
* post-conditions:
|
||||
* Specifically: if args.thisv is a proxy, NonGenericMethodGuard will call its
|
||||
* ProxyHandler's nativeCall hook (which may recursively call args.callee in
|
||||
* args.thisv's compartment). These are the possible post-conditions:
|
||||
*
|
||||
* 1. thisv is an object of the given clasp: the caller may proceed;
|
||||
* 1. NonGenericMethodGuard returned false because it encountered an error:
|
||||
* args.thisv wasn't an object, was an object of the wrong class, was a
|
||||
* proxy to an object of the wrong class, or was a proxy to an object of
|
||||
* the right class but the recursive call to args.callee failed. This case
|
||||
* should be handled like any other failure: propagate it, or catch it and
|
||||
* continue.
|
||||
* 2. NonGenericMethodGuard returned true, and thisObj was nulled out. In
|
||||
* this case args.thisv was a proxy to an object with the desired class,
|
||||
* and recursive invocation of args.callee succeeded. This completes the
|
||||
* invocation of args.callee, so return true.
|
||||
* 3. NonGenericMethodGuard returned true, and thisObj was set to a non-null
|
||||
* pointer. In this case args.thisv was exactly an object of the desired
|
||||
* class, and not a proxy to one. Finish up the call using thisObj as the
|
||||
* this object provided to the call, which will have clasp as its class.
|
||||
*
|
||||
* 2. there was an error: the caller must return 'false';
|
||||
*
|
||||
* 3. thisv wrapped an object of the given clasp and the native was reentered
|
||||
* and completed succesfully: the caller must return 'true'.
|
||||
*
|
||||
* Case 1 is indicated by a non-NULL return value; case 2 by a NULL return
|
||||
* value with *ok == false; and case 3 by a NULL return value with *ok == true.
|
||||
*
|
||||
* NB: since this guard may reenter the native, the guard must be placed before
|
||||
* any effectful operations are performed.
|
||||
* Be careful! This guard may reenter the native, so the guard must be placed
|
||||
* before any effectful operations are performed.
|
||||
*/
|
||||
inline JSObject *
|
||||
NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok);
|
||||
inline bool
|
||||
NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, JSObject **thisObj);
|
||||
|
||||
/*
|
||||
* NonGenericMethodGuard tests args.thisv's class using 'clasp'. If more than
|
||||
|
@ -332,12 +332,6 @@ WithObject::create(JSContext *cx, HandleObject proto, HandleObject enclosing, ui
|
||||
static JSBool
|
||||
with_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp, JSProperty **propp)
|
||||
{
|
||||
/* Fixes bug 463997 */
|
||||
unsigned flags = cx->resolveFlags;
|
||||
if (flags == RESOLVE_INFER)
|
||||
flags = js_InferFlags(cx, flags);
|
||||
flags |= JSRESOLVE_WITH;
|
||||
JSAutoResolveFlags rf(cx, flags);
|
||||
return obj->asWith().object().lookupGeneric(cx, id, objp, propp);
|
||||
}
|
||||
|
||||
@ -1375,7 +1369,7 @@ int DebugScopeProxy::family = 0;
|
||||
DebugScopeProxy DebugScopeProxy::singleton;
|
||||
|
||||
/* static */ DebugScopeObject *
|
||||
DebugScopeObject::create(JSContext *cx, ScopeObject &scope, JSObject &enclosing)
|
||||
DebugScopeObject::create(JSContext *cx, ScopeObject &scope, HandleObject enclosing)
|
||||
{
|
||||
JSObject *obj = NewProxyObject(cx, &DebugScopeProxy::singleton, ObjectValue(scope),
|
||||
NULL /* proto */, &scope.global(),
|
||||
@ -1383,8 +1377,8 @@ DebugScopeObject::create(JSContext *cx, ScopeObject &scope, JSObject &enclosing)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(!enclosing.isScope());
|
||||
SetProxyExtra(obj, ENCLOSING_EXTRA, ObjectValue(enclosing));
|
||||
JS_ASSERT(!enclosing->isScope());
|
||||
SetProxyExtra(obj, ENCLOSING_EXTRA, ObjectValue(*enclosing.value()));
|
||||
|
||||
return &obj->asDebugScope();
|
||||
}
|
||||
@ -1735,19 +1729,19 @@ GetDebugScopeForScope(JSContext *cx, ScopeObject &scope, ScopeIter enclosing)
|
||||
if (DebugScopeObject *debugScope = debugScopes.hasDebugScope(cx, scope))
|
||||
return debugScope;
|
||||
|
||||
JSObject *enclosingDebug = GetDebugScope(cx, enclosing);
|
||||
RootedObject enclosingDebug(cx, GetDebugScope(cx, enclosing));
|
||||
if (!enclosingDebug)
|
||||
return NULL;
|
||||
|
||||
JSObject &maybeDecl = scope.enclosingScope();
|
||||
if (maybeDecl.isDeclEnv()) {
|
||||
JS_ASSERT(CallObjectLambdaName(scope.asCall().getCalleeFunction()));
|
||||
enclosingDebug = DebugScopeObject::create(cx, maybeDecl.asDeclEnv(), *enclosingDebug);
|
||||
enclosingDebug = DebugScopeObject::create(cx, maybeDecl.asDeclEnv(), enclosingDebug);
|
||||
if (!enclosingDebug)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DebugScopeObject *debugScope = DebugScopeObject::create(cx, scope, *enclosingDebug);
|
||||
DebugScopeObject *debugScope = DebugScopeObject::create(cx, scope, enclosingDebug);
|
||||
if (!debugScope)
|
||||
return NULL;
|
||||
|
||||
@ -1760,11 +1754,13 @@ GetDebugScopeForScope(JSContext *cx, ScopeObject &scope, ScopeIter enclosing)
|
||||
static DebugScopeObject *
|
||||
GetDebugScopeForMissing(JSContext *cx, ScopeIter si)
|
||||
{
|
||||
SkipRoot si_(cx, &si);
|
||||
|
||||
DebugScopes &debugScopes = *cx->runtime->debugScopes;
|
||||
if (DebugScopeObject *debugScope = debugScopes.hasDebugScope(cx, si))
|
||||
return debugScope;
|
||||
|
||||
JSObject *enclosingDebug = GetDebugScope(cx, si.enclosing());
|
||||
RootedObject enclosingDebug(cx, GetDebugScope(cx, si.enclosing()));
|
||||
if (!enclosingDebug)
|
||||
return NULL;
|
||||
|
||||
@ -1784,12 +1780,12 @@ GetDebugScopeForMissing(JSContext *cx, ScopeIter si)
|
||||
if (callobj->enclosingScope().isDeclEnv()) {
|
||||
JS_ASSERT(CallObjectLambdaName(callobj->getCalleeFunction()));
|
||||
DeclEnvObject &declenv = callobj->enclosingScope().asDeclEnv();
|
||||
enclosingDebug = DebugScopeObject::create(cx, declenv, *enclosingDebug);
|
||||
enclosingDebug = DebugScopeObject::create(cx, declenv, enclosingDebug);
|
||||
if (!enclosingDebug)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
debugScope = DebugScopeObject::create(cx, *callobj, *enclosingDebug);
|
||||
debugScope = DebugScopeObject::create(cx, *callobj, enclosingDebug);
|
||||
break;
|
||||
}
|
||||
case ScopeIter::Block: {
|
||||
@ -1798,7 +1794,7 @@ GetDebugScopeForMissing(JSContext *cx, ScopeIter si)
|
||||
if (!block)
|
||||
return NULL;
|
||||
|
||||
debugScope = DebugScopeObject::create(cx, *block, *enclosingDebug);
|
||||
debugScope = DebugScopeObject::create(cx, *block, enclosingDebug);
|
||||
break;
|
||||
}
|
||||
case ScopeIter::With:
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "jsobj.h"
|
||||
#include "jsweakmap.h"
|
||||
|
||||
#include "gc/Barrier.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -402,7 +404,7 @@ class DebugScopeObject : public JSObject
|
||||
static const unsigned ENCLOSING_EXTRA = 0;
|
||||
|
||||
public:
|
||||
static DebugScopeObject *create(JSContext *cx, ScopeObject &scope, JSObject &enclosing);
|
||||
static DebugScopeObject *create(JSContext *cx, ScopeObject &scope, HandleObject enclosing);
|
||||
|
||||
ScopeObject &scope() const;
|
||||
JSObject &enclosingScope() const;
|
||||
|
@ -36,10 +36,11 @@ class ScriptFrameIter;
|
||||
class AllFramesIter;
|
||||
|
||||
class ArgumentsObject;
|
||||
class ScopeCoordinate;
|
||||
class ScopeObject;
|
||||
class StaticBlockObject;
|
||||
|
||||
struct ScopeCoordinate;
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
namespace mjit {
|
||||
class CallCompiler;
|
||||
@ -415,7 +416,7 @@ class StackFrame
|
||||
#ifdef JS_METHODJIT
|
||||
friend class mjit::CallCompiler;
|
||||
friend class mjit::GetPropCompiler;
|
||||
friend class mjit::ic::GetElementIC;
|
||||
friend struct mjit::ic::GetElementIC;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -357,15 +357,6 @@ TraceJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number,
|
||||
return JS_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
TraceExpandos(XPCWrappedNative *wn, JSObject *&expando, void *aClosure)
|
||||
{
|
||||
if (wn->IsWrapperExpired())
|
||||
return PL_DHASH_REMOVE;
|
||||
JS_CALL_OBJECT_TRACER(static_cast<JSTracer *>(aClosure), expando, "expando object");
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
TraceDOMExpandos(nsPtrHashKey<JSObject> *expando, void *aClosure)
|
||||
{
|
||||
@ -400,8 +391,6 @@ void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc)
|
||||
XPCCompartmentSet &set = GetCompartmentSet();
|
||||
for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
|
||||
CompartmentPrivate *priv = GetCompartmentPrivate(r.front());
|
||||
if (priv->expandoMap)
|
||||
priv->expandoMap->Enumerate(TraceExpandos, trc);
|
||||
if (priv->domExpandoMap)
|
||||
priv->domExpandoMap->EnumerateEntries(TraceDOMExpandos, trc);
|
||||
}
|
||||
@ -464,15 +453,6 @@ XPCJSRuntime::SuspectWrappedNative(XPCWrappedNative *wrapper,
|
||||
cb.NoteJSRoot(obj);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
SuspectExpandos(XPCWrappedNative *wrapper, JSObject *expando, void *arg)
|
||||
{
|
||||
Closure* closure = static_cast<Closure*>(arg);
|
||||
XPCJSRuntime::SuspectWrappedNative(wrapper, *closure->cb);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
SuspectDOMExpandos(nsPtrHashKey<JSObject> *key, void *arg)
|
||||
{
|
||||
@ -546,12 +526,10 @@ XPCJSRuntime::AddXPConnectRoots(nsCycleCollectionTraversalCallback &cb)
|
||||
JS_DHashTableEnumerate(&mJSHolders, NoteJSHolder, &closure);
|
||||
}
|
||||
|
||||
// Suspect wrapped natives with expando objects.
|
||||
// Suspect objects with expando objects.
|
||||
XPCCompartmentSet &set = GetCompartmentSet();
|
||||
for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
|
||||
CompartmentPrivate *priv = GetCompartmentPrivate(r.front());
|
||||
if (priv->expandoMap)
|
||||
priv->expandoMap->EnumerateRead(SuspectExpandos, &closure);
|
||||
if (priv->domExpandoMap)
|
||||
priv->domExpandoMap->EnumerateEntries(SuspectDOMExpandos, &closure);
|
||||
}
|
||||
@ -599,14 +577,6 @@ DoDeferredRelease(nsTArray<T> &array)
|
||||
}
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
SweepExpandos(XPCWrappedNative *wn, JSObject *&expando, void *arg)
|
||||
{
|
||||
return JS_IsAboutToBeFinalized(wn->GetFlatJSObjectPreserveColor())
|
||||
? PL_DHASH_REMOVE
|
||||
: PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::GCCallback(JSRuntime *rt, JSGCStatus status)
|
||||
{
|
||||
@ -688,8 +658,6 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status, JSBool is
|
||||
CompartmentPrivate *priv = GetCompartmentPrivate(r.front());
|
||||
if (priv->waiverWrapperMap)
|
||||
priv->waiverWrapperMap->Sweep();
|
||||
if (priv->expandoMap)
|
||||
priv->expandoMap->Enumerate(SweepExpandos, NULL);
|
||||
}
|
||||
|
||||
self->mDoingFinalization = true;
|
||||
|
@ -129,7 +129,11 @@ Native2WrappedNativeMap::newMap(int size)
|
||||
Native2WrappedNativeMap* map = new Native2WrappedNativeMap(size);
|
||||
if (map && map->mTable)
|
||||
return map;
|
||||
delete map;
|
||||
// Allocation of the map or the creation of its hash table has
|
||||
// failed. This will cause a NULL deref later when we attempt to
|
||||
// use the map, so we abort immediately to provide a more useful
|
||||
// crash stack.
|
||||
NS_RUNTIMEABORT("Ran out of memory.");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
@ -297,7 +301,11 @@ ClassInfo2WrappedNativeProtoMap::newMap(int size)
|
||||
ClassInfo2WrappedNativeProtoMap* map = new ClassInfo2WrappedNativeProtoMap(size);
|
||||
if (map && map->mTable)
|
||||
return map;
|
||||
delete map;
|
||||
// Allocation of the map or the creation of its hash table has
|
||||
// failed. This will cause a NULL deref later when we attempt to
|
||||
// use the map, so we abort immediately to provide a more useful
|
||||
// crash stack.
|
||||
NS_RUNTIMEABORT("Ran out of memory.");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "jsproxy.h"
|
||||
#include "AccessCheck.h"
|
||||
#include "WrapperFactory.h"
|
||||
#include "XrayWrapper.h"
|
||||
#include "dombindings.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
@ -90,16 +91,6 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p,
|
||||
cb.NoteJSChild(obj);
|
||||
}
|
||||
|
||||
if (tmp->MightHaveExpandoObject()) {
|
||||
XPCJSRuntime *rt = tmp->GetRuntime();
|
||||
XPCCompartmentSet &set = rt->GetCompartmentSet();
|
||||
for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
|
||||
CompartmentPrivate *priv = GetCompartmentPrivate(r.front());
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "XPCWrappedNative expando object");
|
||||
cb.NoteJSChild(priv->LookupExpandoObjectPreserveColor(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
// XPCWrappedNative keeps its native object alive.
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mIdentity");
|
||||
cb.NoteXPCOMChild(tmp->GetIdentityObject());
|
||||
@ -1192,10 +1183,11 @@ XPCWrappedNative::Init(XPCCallContext& ccx, JSObject* parent,
|
||||
JSBool
|
||||
XPCWrappedNative::Init(XPCCallContext &ccx, JSObject *existingJSObject)
|
||||
{
|
||||
// Set up the private to point to the WN.
|
||||
JS_SetPrivate(existingJSObject, this);
|
||||
|
||||
// Morph the existing object.
|
||||
JS_SetReservedSlot(existingJSObject, 0, JSVAL_VOID);
|
||||
// Officially mark us as non-slim.
|
||||
MorphMultiSlot(existingJSObject);
|
||||
|
||||
mScriptableInfo = GetProto()->GetScriptableInfo();
|
||||
mFlatJSObject = existingJSObject;
|
||||
@ -1210,6 +1202,11 @@ XPCWrappedNative::Init(XPCCallContext &ccx, JSObject *existingJSObject)
|
||||
JSBool
|
||||
XPCWrappedNative::FinishInit(XPCCallContext &ccx)
|
||||
{
|
||||
// For all WNs, we want to make sure that the multislot starts out as null.
|
||||
// This happens explicitly when morphing a slim wrapper, but we need to
|
||||
// make sure it happens in the other cases too.
|
||||
JS_SetReservedSlot(mFlatJSObject, WRAPPER_MULTISLOT, JSVAL_NULL);
|
||||
|
||||
// This reference will be released when mFlatJSObject is finalized.
|
||||
// Since this reference will push the refcount to 2 it will also root
|
||||
// mFlatJSObject;
|
||||
@ -1614,6 +1611,12 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
||||
if (!propertyHolder || !JS_CopyPropertiesFrom(ccx, propertyHolder, flat))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Expandos from other compartments are attached to the target JS object.
|
||||
// Copy them over, and let the old ones die a natural death.
|
||||
SetExpandoChain(newobj, nsnull);
|
||||
if (!XrayUtils::CloneExpandoChain(ccx, newobj, flat))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Before proceeding, eagerly create any same-compartment security wrappers
|
||||
// that the object might have. This forces us to take the 'WithWrapper' path
|
||||
// while transplanting that handles this stuff correctly.
|
||||
@ -1652,40 +1655,13 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
||||
}
|
||||
|
||||
// Ok, now we do the special object-plus-wrapper transplant.
|
||||
//
|
||||
// This is some pretty serious brain surgery.
|
||||
//
|
||||
// In the case where we wrap a Location object from a same-
|
||||
// origin compartment, we actually want our cross-compartment
|
||||
// wrapper to point to the same-compartment wrapper in the
|
||||
// other compartment. This double-wrapping allows expandos to
|
||||
// be shared. So our wrapping callback (in WrapperFactory.cpp)
|
||||
// calls XPCWrappedNative::GetSameCompartmentSecurityWrapper
|
||||
// before wrapping same-origin Location objects.
|
||||
//
|
||||
// This normally works fine, but gets tricky here.
|
||||
// js_TransplantObjectWithWrapper needs to update the old
|
||||
// same-compartment security wrapper to be a cross-compartment
|
||||
// wrapper to the newly transplanted object. So it needs to go
|
||||
// through the aforementioned double-wrapping mechanism.
|
||||
// But during the call, things aren't really in a consistent
|
||||
// state, because mFlatJSObject hasn't yet been updated to
|
||||
// point to the object in the new compartment.
|
||||
//
|
||||
// So we need to cache the new same-compartment security
|
||||
// wrapper on the XPCWN before the call, so that
|
||||
// GetSameCompartmentSecurityWrapper can return early before
|
||||
// getting confused. Hold your breath.
|
||||
JSObject *wwsaved = ww;
|
||||
wrapper->SetWrapper(newwrapper);
|
||||
ww = js_TransplantObjectWithWrapper(ccx, flat, ww, newobj,
|
||||
newwrapper);
|
||||
if (!ww) {
|
||||
wrapper->SetWrapper(wwsaved);
|
||||
if (!ww)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
flat = newobj;
|
||||
wrapper->SetWrapper(ww);
|
||||
} else {
|
||||
flat = JS_TransplantObject(ccx, flat, newobj);
|
||||
if (!flat)
|
||||
@ -1698,11 +1674,10 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
||||
if (!JS_CopyPropertiesFrom(ccx, flat, propertyHolder))
|
||||
return NS_ERROR_FAILURE;
|
||||
} else {
|
||||
JS_SetReservedSlot(flat, 0,
|
||||
PRIVATE_TO_JSVAL(newProto.get()));
|
||||
SetSlimWrapperProto(flat, newProto.get());
|
||||
if (!JS_SetPrototype(ccx, flat, newProto->GetJSProtoObject())) {
|
||||
// this is bad, very bad
|
||||
JS_SetReservedSlot(flat, 0, JSVAL_NULL);
|
||||
SetSlimWrapperProto(flat, nsnull);
|
||||
NS_ERROR("JS_SetPrototype failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2232,10 +2207,6 @@ XPCWrappedNative::GetSameCompartmentSecurityWrapper(JSContext *cx)
|
||||
JSObject *wrapper = GetWrapper();
|
||||
|
||||
// If we already have a wrapper, it must be what we want.
|
||||
//
|
||||
// NB: This must come before anything below because of some trickiness
|
||||
// with brain transplants. See the "pretty serious brain surgery" comment
|
||||
// in ReparentWrapperIfFound.
|
||||
if (wrapper)
|
||||
return wrapper;
|
||||
|
||||
@ -3936,7 +3907,7 @@ ConstructSlimWrapper(XPCCallContext &ccx,
|
||||
return false;
|
||||
|
||||
JS_SetPrivate(wrapper, identityObj);
|
||||
JS_SetReservedSlot(wrapper, 0, PRIVATE_TO_JSVAL(xpcproto.get()));
|
||||
SetSlimWrapperProto(wrapper, xpcproto.get());
|
||||
|
||||
// Transfer ownership to the wrapper's private.
|
||||
aHelper.forgetCanonical();
|
||||
|
@ -301,8 +301,44 @@ typedef XPCCompartmentSet::Range XPCCompartmentRange;
|
||||
#define WRAPPER_SLOTS (JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | \
|
||||
JSCLASS_HAS_RESERVED_SLOTS(1))
|
||||
|
||||
// WRAPPER_MULTISLOT is defined in xpcpublic.h
|
||||
|
||||
#define INVALID_OBJECT ((JSObject *)1)
|
||||
|
||||
inline void SetSlimWrapperProto(JSObject *obj, XPCWrappedNativeProto *proto)
|
||||
{
|
||||
JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, PRIVATE_TO_JSVAL(proto));
|
||||
}
|
||||
|
||||
inline XPCWrappedNativeProto* GetSlimWrapperProto(JSObject *obj)
|
||||
{
|
||||
MOZ_ASSERT(IS_SLIM_WRAPPER(obj));
|
||||
const JS::Value &v = js::GetReservedSlot(obj, WRAPPER_MULTISLOT);
|
||||
return static_cast<XPCWrappedNativeProto*>(v.toPrivate());
|
||||
}
|
||||
|
||||
// A slim wrapper is identified by having a native pointer in its reserved slot.
|
||||
// This function, therefore, does the official transition from a slim wrapper to
|
||||
// a non-slim wrapper.
|
||||
inline void MorphMultiSlot(JSObject *obj)
|
||||
{
|
||||
MOZ_ASSERT(IS_SLIM_WRAPPER(obj));
|
||||
JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, JSVAL_NULL);
|
||||
MOZ_ASSERT(!IS_SLIM_WRAPPER(obj));
|
||||
}
|
||||
|
||||
inline void SetExpandoChain(JSObject *obj, JSObject *chain)
|
||||
{
|
||||
MOZ_ASSERT(IS_WN_WRAPPER(obj));
|
||||
JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, JS::ObjectOrNullValue(chain));
|
||||
}
|
||||
|
||||
inline JSObject* GetExpandoChain(JSObject *obj)
|
||||
{
|
||||
MOZ_ASSERT(IS_WN_WRAPPER(obj));
|
||||
return JS_GetReservedSlot(obj, WRAPPER_MULTISLOT).toObjectOrNull();
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
// Auto locking support class...
|
||||
|
||||
@ -2426,14 +2462,6 @@ extern JSBool ConstructSlimWrapper(XPCCallContext &ccx,
|
||||
jsval *rval);
|
||||
extern JSBool MorphSlimWrapper(JSContext *cx, JSObject *obj);
|
||||
|
||||
static inline XPCWrappedNativeProto*
|
||||
GetSlimWrapperProto(JSObject *obj)
|
||||
{
|
||||
const js::Value &v = js::GetReservedSlot(obj, 0);
|
||||
return static_cast<XPCWrappedNativeProto*>(v.toPrivate());
|
||||
}
|
||||
|
||||
|
||||
/***********************************************/
|
||||
// XPCWrappedNativeTearOff represents the info needed to make calls to one
|
||||
// interface on the underlying native object of a XPCWrappedNative.
|
||||
@ -2807,8 +2835,6 @@ public:
|
||||
void SetNeedsSOW() { mWrapperWord |= NEEDS_SOW; }
|
||||
JSBool NeedsCOW() { return !!(mWrapperWord & NEEDS_COW); }
|
||||
void SetNeedsCOW() { mWrapperWord |= NEEDS_COW; }
|
||||
JSBool MightHaveExpandoObject() { return !!(mWrapperWord & MIGHT_HAVE_EXPANDO); }
|
||||
void SetHasExpandoObject() { mWrapperWord |= MIGHT_HAVE_EXPANDO; }
|
||||
|
||||
JSObject* GetWrapperPreserveColor() const
|
||||
{return (JSObject*)(mWrapperWord & (size_t)~(size_t)FLAG_MASK);}
|
||||
@ -2875,7 +2901,6 @@ private:
|
||||
enum {
|
||||
NEEDS_SOW = JS_BIT(0),
|
||||
NEEDS_COW = JS_BIT(1),
|
||||
MIGHT_HAVE_EXPANDO = JS_BIT(2),
|
||||
FLAG_MASK = JS_BITMASK(3)
|
||||
};
|
||||
|
||||
@ -4354,7 +4379,6 @@ namespace xpc {
|
||||
class CompartmentPrivate
|
||||
{
|
||||
public:
|
||||
typedef nsDataHashtable<nsPtrHashKey<XPCWrappedNative>, JSObject *> ExpandoMap;
|
||||
typedef nsTHashtable<nsPtrHashKey<JSObject> > DOMExpandoMap;
|
||||
|
||||
CompartmentPrivate(bool wantXrays)
|
||||
@ -4367,40 +4391,8 @@ public:
|
||||
|
||||
bool wantXrays;
|
||||
nsAutoPtr<JSObject2JSObjectMap> waiverWrapperMap;
|
||||
// NB: we don't want this map to hold a strong reference to the wrapper.
|
||||
nsAutoPtr<ExpandoMap> expandoMap;
|
||||
nsAutoPtr<DOMExpandoMap> domExpandoMap;
|
||||
|
||||
bool RegisterExpandoObject(XPCWrappedNative *wn, JSObject *expando) {
|
||||
if (!expandoMap) {
|
||||
expandoMap = new ExpandoMap();
|
||||
expandoMap->Init(8);
|
||||
}
|
||||
wn->SetHasExpandoObject();
|
||||
return expandoMap->Put(wn, expando, mozilla::fallible_t());
|
||||
}
|
||||
|
||||
/**
|
||||
* This lookup does not change the color of the JSObject meaning that the
|
||||
* object returned is not guaranteed to be kept alive past the next CC.
|
||||
*
|
||||
* This should only be called if you are certain that the return value won't
|
||||
* be passed into a JS API function and that it won't be stored without
|
||||
* being rooted (or otherwise signaling the stored value to the CC).
|
||||
*/
|
||||
JSObject *LookupExpandoObjectPreserveColor(XPCWrappedNative *wn) {
|
||||
return expandoMap ? expandoMap->Get(wn) : nsnull;
|
||||
}
|
||||
|
||||
/**
|
||||
* This lookup clears the gray bit before handing out the JSObject which
|
||||
* means that the object is guaranteed to be kept alive past the next CC.
|
||||
*/
|
||||
JSObject *LookupExpandoObject(XPCWrappedNative *wn) {
|
||||
JSObject *obj = LookupExpandoObjectPreserveColor(wn);
|
||||
return xpc_UnmarkGrayObject(obj);
|
||||
}
|
||||
|
||||
bool RegisterDOMExpandoObject(JSObject *expando) {
|
||||
if (!domExpandoMap) {
|
||||
domExpandoMap = new DOMExpandoMap();
|
||||
|
@ -74,13 +74,21 @@ DebugCheckWrapperClass(JSObject* obj)
|
||||
// a slim wrapper, holding a native in its private slot, or a wrappednative
|
||||
// wrapper, holding the XPCWrappedNative in its private slot. A slim wrapper
|
||||
// also holds a pointer to its XPCWrappedNativeProto in a reserved slot, we can
|
||||
// check that slot for a non-void value to distinguish between the two.
|
||||
// check that slot for a private value (i.e. a double) to distinguish between
|
||||
// the two. This allows us to store a JSObject in that slot for non-slim wrappers
|
||||
// while still being able to distinguish the two cases.
|
||||
|
||||
// NB: This slot isn't actually reserved for us on globals, because SpiderMonkey
|
||||
// uses the first N slots on globals internally. The fact that we use it for
|
||||
// wrapped global objects is totally broken. But due to a happy coincidence, the
|
||||
// JS engine never uses that slot. This still needs fixing though. See bug 760095.
|
||||
#define WRAPPER_MULTISLOT 0
|
||||
|
||||
// Only use these macros if IS_WRAPPER_CLASS(GetObjectClass(obj)) is true.
|
||||
#define IS_WN_WRAPPER_OBJECT(obj) \
|
||||
(DebugCheckWrapperClass(obj) && js::GetReservedSlot(obj, 0).isUndefined())
|
||||
(DebugCheckWrapperClass(obj) && !js::GetReservedSlot(obj, WRAPPER_MULTISLOT).isDouble())
|
||||
#define IS_SLIM_WRAPPER_OBJECT(obj) \
|
||||
(DebugCheckWrapperClass(obj) && !js::GetReservedSlot(obj, 0).isUndefined())
|
||||
(DebugCheckWrapperClass(obj) && js::GetReservedSlot(obj, WRAPPER_MULTISLOT).isDouble())
|
||||
|
||||
// Use these macros if IS_WRAPPER_CLASS(GetObjectClass(obj)) might be false.
|
||||
// Avoid calling them if IS_WRAPPER_CLASS(GetObjectClass(obj)) can only be
|
||||
|
@ -47,6 +47,8 @@ _CHROME_FILES = \
|
||||
test_exnstack.xul \
|
||||
test_weakref.xul \
|
||||
test_bug726949.xul \
|
||||
test_expandosharing.xul \
|
||||
file_expandosharing.jsm \
|
||||
test_bug758563.xul \
|
||||
test_bug760076.xul \
|
||||
$(NULL)
|
||||
|
10
js/xpconnect/tests/chrome/file_expandosharing.jsm
Normal file
10
js/xpconnect/tests/chrome/file_expandosharing.jsm
Normal file
@ -0,0 +1,10 @@
|
||||
var EXPORTED_SYMBOLS = ['checkFromJSM'];
|
||||
|
||||
function checkFromJSM(target, is_op) {
|
||||
is_op(target.numProp, 42, "Number expando works");
|
||||
is_op(target.strProp, "foo", "String expando works");
|
||||
// If is_op is todo_is, target.objProp will be undefined.
|
||||
try {
|
||||
is_op(target.objProp.bar, "baz", "Object expando works");
|
||||
} catch(e) { is_op(0, 1, "No object expando"); }
|
||||
}
|
141
js/xpconnect/tests/chrome/test_expandosharing.xul
Normal file
141
js/xpconnect/tests/chrome/test_expandosharing.xul
Normal file
@ -0,0 +1,141 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=758415
|
||||
-->
|
||||
<window title="Mozilla Bug 758415"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=758415"
|
||||
target="_blank">Mozilla Bug 758415</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
/** Test for Cross-Origin Xray Expando Sharing. **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
const Cu = Components.utils;
|
||||
|
||||
// Import our test JSM. We first strip the filename off
|
||||
// the chrome url, then append the jsm filename.
|
||||
var base = /.*\//.exec(window.location.href)[0];
|
||||
Cu.import(base + "file_expandosharing.jsm");
|
||||
|
||||
// Wait for all child frames to load.
|
||||
var gLoadCount = 0;
|
||||
function frameLoaded() {
|
||||
if (++gLoadCount == 4)
|
||||
go();
|
||||
}
|
||||
|
||||
function go() {
|
||||
|
||||
// Empower the content windows with some functions.
|
||||
var wins = document.getElementsByTagName('iframe');
|
||||
for (var i = 0; i < wins.length; ++i) {
|
||||
var win = wins[i].contentWindow.wrappedJSObject;
|
||||
win.ok = ok;
|
||||
win.is = is;
|
||||
}
|
||||
|
||||
// Grab references to the content windows. We abbreviate the origins as follows:
|
||||
// A: test1.example.org
|
||||
// B: test2.example.org
|
||||
// C: sub1.test1.example.org
|
||||
window.gWinA1 = document.getElementById('frameA1').contentWindow;
|
||||
window.gWinA2 = document.getElementById('frameA2').contentWindow;
|
||||
window.gWinB = document.getElementById('frameB').contentWindow;
|
||||
window.gWinC = document.getElementById('frameC').contentWindow;
|
||||
|
||||
// Test expando sharing with a JSM for different types of Xrays.
|
||||
// Note that we don't yet support it for nodelists and new bindings.
|
||||
testJSM(XPCNativeWrapper(gWinC.wrappedJSObject.targetWN), is);
|
||||
testJSM(XPCNativeWrapper(gWinC.wrappedJSObject.targetNodeList), todo_is);
|
||||
testJSM(XPCNativeWrapper(gWinC.wrappedJSObject.targetXHR), todo_is);
|
||||
|
||||
// Make sure sandboxes never share expandos with anyone else.
|
||||
testSandbox(XPCNativeWrapper(gWinB.wrappedJSObject.targetWN));
|
||||
testSandbox(XPCNativeWrapper(gWinB.wrappedJSObject.targetNodeList));
|
||||
testSandbox(XPCNativeWrapper(gWinB.wrappedJSObject.targetXHR));
|
||||
|
||||
// Test XOWs using Location objects.
|
||||
testLocation();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// Make sure that expandos are shared between us and a JSM.
|
||||
function testJSM(target, is_op) {
|
||||
target.numProp = 42;
|
||||
target.strProp = "foo";
|
||||
target.objProp = { bar: "baz" };
|
||||
checkFromJSM(target, is_op);
|
||||
}
|
||||
|
||||
function testSandbox(target) {
|
||||
|
||||
// This gets both run in this scope and the sandbox scope.
|
||||
var name = "harness";
|
||||
function placeExpando() {
|
||||
target.prop = name;
|
||||
}
|
||||
|
||||
// Set up the sandboxes.
|
||||
sb1 = Cu.Sandbox(window);
|
||||
sb2 = Cu.Sandbox(window);
|
||||
sb1.target = target;
|
||||
sb2.target = target;
|
||||
sb1.name = "sandbox1";
|
||||
sb2.name = "sandbox2";
|
||||
placeExpando();
|
||||
Cu.evalInSandbox(placeExpando.toSource() + "placeExpando();", sb1);
|
||||
Cu.evalInSandbox(placeExpando.toSource() + "placeExpando();", sb2);
|
||||
|
||||
// Make sure everyone sees a different value.
|
||||
is(target.prop, "harness", "Harness sees its own value");
|
||||
is(Cu.evalInSandbox("target.prop", sb1), "sandbox1", "Sandbox 1 sees its own value");
|
||||
is(Cu.evalInSandbox("target.prop", sb2), "sandbox2", "Sandbox 2 sees its own value");
|
||||
}
|
||||
|
||||
// Location is special in that same-origin access for content still involves
|
||||
// an Xray wrapper. This gives us a good opportunity to test that we don't
|
||||
// mix up chrome and content expandos.
|
||||
function testLocation() {
|
||||
|
||||
// Each scope has an Xray wrapper to Location. make sure the sharing happens.
|
||||
gWinA1.wrappedJSObject.placeExpando('A1_expando', 11, gWinA2.location);
|
||||
gWinA2.wrappedJSObject.placeExpando('A2_expando', 22, gWinA2.location);
|
||||
gWinA2.location.Chrome_expando = 33;
|
||||
|
||||
is(gWinA2.location.Chrome_expando, 33, "Read chrome expando properly");
|
||||
is(typeof gWinA2.location.A1_expando, 'undefined', "Chrome doesn't see content expandos");
|
||||
is(typeof gWinA2.location.A2_expando, 'undefined', "Chrome doesn't see content expandos");
|
||||
gWinA1.wrappedJSObject.checkExpando('A1_expando', 11, gWinA2.location, "Content sees proper expandos");
|
||||
gWinA2.wrappedJSObject.checkExpando('A1_expando', 11, gWinA2.location, "Content sees proper expandos");
|
||||
gWinA1.wrappedJSObject.checkExpando('A2_expando', 22, gWinA2.location, "Content sees proper expandos");
|
||||
gWinA2.wrappedJSObject.checkExpando('A2_expando', 22, gWinA2.location, "Content sees proper expandos");
|
||||
gWinA1.wrappedJSObject.checkExpando('Chrome_expando', null, gWinA2.location, "Content doesn't see chrome expandos");
|
||||
gWinA2.wrappedJSObject.checkExpando('Chrome_expando', null, gWinA2.location, "Content doesn't see chrome expandos");
|
||||
|
||||
// We very explicitly do not support expando sharing via document.domain.
|
||||
// A comment in the implementation explains why.
|
||||
gWinA1.document.domain = 'test1.example.org';
|
||||
gWinA2.document.domain = 'test1.example.org';
|
||||
gWinC.document.domain = 'test1.example.org';
|
||||
gWinC.wrappedJSObject.checkExpando('A1_expando', null, gWinA2.location, "document.domain should have no effect here");
|
||||
gWinC.wrappedJSObject.checkExpando('A2_expando', null, gWinA2.location, "document.domain should have no effect here");
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
<iframe id="frameA1" onload="frameLoaded();" type="content" src="http://test1.example.org/tests/js/xpconnect/tests/mochitest/file_expandosharing.html" />
|
||||
<iframe id="frameA2" onload="frameLoaded();" type="content" src="http://test1.example.org/tests/js/xpconnect/tests/mochitest/file_expandosharing.html" />
|
||||
<iframe id="frameB" onload="frameLoaded();" type="content" src="http://test2.example.org/tests/js/xpconnect/tests/mochitest/file_expandosharing.html" />
|
||||
<iframe id="frameC" onload="frameLoaded();" type="content" src="http://sub1.test1.example.org/tests/js/xpconnect/tests/mochitest/file_expandosharing.html" />
|
||||
</window>
|
@ -67,6 +67,7 @@ _TEST_FILES = bug500931_helper.html \
|
||||
file_nodelists.html \
|
||||
file_bug706301.html \
|
||||
file_exnstack.html \
|
||||
file_expandosharing.html \
|
||||
$(NULL)
|
||||
|
||||
_CHROME_FILES = \
|
||||
|
34
js/xpconnect/tests/mochitest/file_expandosharing.html
Normal file
34
js/xpconnect/tests/mochitest/file_expandosharing.html
Normal file
@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript">
|
||||
function setup() {
|
||||
// Set up different target objects for expandos, one for each binding type.
|
||||
window.targetWN = document.body.firstChild;
|
||||
window.targetNodeList = document.getElementsByTagName('span');
|
||||
window.targetXHR = new XMLHttpRequest();
|
||||
}
|
||||
|
||||
function placeExpando(name, val, target) {
|
||||
target[name] = val;
|
||||
}
|
||||
|
||||
// If val === null, then we shouldn't have access.
|
||||
function checkExpando(name, val, target, msg) {
|
||||
if (val !== null) {
|
||||
ok(name in target, msg);
|
||||
try {
|
||||
is(target[name], val, "Got the right expando value");
|
||||
} catch(e) { ok(false, "Threw when accessing same-origin expando"); }
|
||||
}
|
||||
else {
|
||||
ok(!(name in target), msg);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="setup();">
|
||||
<span>Salut, Ma Cherise. ;-)</span>
|
||||
</body>
|
||||
</html>
|
@ -379,47 +379,26 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
|
||||
// For the same-origin case we use a transparent wrapper, unless one
|
||||
// of the following is true:
|
||||
// * The object is flagged as needing a SOW.
|
||||
// * The object is a location object.
|
||||
// * The object is a Location object.
|
||||
// * The object is a Components object.
|
||||
// * The context compartment specifically requested Xray vision into
|
||||
// same-origin compartments.
|
||||
//
|
||||
// The first two cases always require a security wrapper for non-chrome
|
||||
// access, regardless of the origin of the object.
|
||||
//
|
||||
// The Location case is a bit tricky. Because the security characteristics
|
||||
// depend on the current outer window, we always have a security wrapper
|
||||
// around locations, same-compartment or cross-compartment. We would
|
||||
// normally just use an identical security policy and just switch between
|
||||
// Wrapper and CrossCompartmentWrapper to differentiate the cases (LW/XLW).
|
||||
// However, there's an added wrinkle that same-origin-but-cross-compartment
|
||||
// scripts expect to be able to see expandos on each others' location
|
||||
// objects. So if all cross-compartment access used XLWs, then the expandos
|
||||
// would live on the per-compartment XrayWrapper expando object, and would
|
||||
// not be shared. So to make sure that expandos work correctly in the
|
||||
// same-origin case, we need to use a transparent CrossCompartmentWrapper
|
||||
// to the LW in the host compartment, rather than an XLW directly to the
|
||||
// Location object. This still doesn't share expandos in the
|
||||
// document.domain case, but that's probably fine. Double-wrapping sucks,
|
||||
// but it's kind of unavoidable here.
|
||||
XrayType type;
|
||||
if (AccessCheck::needsSystemOnlyWrapper(obj)) {
|
||||
wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
|
||||
OnlyIfSubjectIsSystem>::singleton;
|
||||
} else if (IsLocationObject(obj)) {
|
||||
typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray;
|
||||
usingXray = true;
|
||||
wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton;
|
||||
} else if (IsComponentsObject(obj)) {
|
||||
wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
|
||||
ComponentsObjectPolicy>::singleton;
|
||||
} else if (!targetdata || !targetdata->wantXrays ||
|
||||
(type = GetXrayType(obj)) == NotXray) {
|
||||
// Do the double-wrapping if need be.
|
||||
if (IsLocationObject(obj)) {
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, obj))
|
||||
return nsnull;
|
||||
XPCWrappedNative *wn = GetWrappedNative(cx, obj);
|
||||
if (!wn)
|
||||
return nsnull;
|
||||
obj = wn->GetSameCompartmentSecurityWrapper(cx);
|
||||
}
|
||||
wrapper = &CrossCompartmentWrapper::singleton;
|
||||
} else if (type == XrayForDOMObject) {
|
||||
wrapper = &XrayDOM::singleton;
|
||||
|
@ -29,7 +29,6 @@ using namespace js;
|
||||
|
||||
static const uint32_t JSSLOT_WN = 0;
|
||||
static const uint32_t JSSLOT_RESOLVING = 1;
|
||||
static const uint32_t JSSLOT_EXPANDO = 2;
|
||||
|
||||
static XPCWrappedNative *GetWrappedNative(JSObject *obj);
|
||||
|
||||
@ -37,11 +36,194 @@ namespace XrayUtils {
|
||||
|
||||
JSClass HolderClass = {
|
||||
"NativePropertyHolder",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(3),
|
||||
JSCLASS_HAS_RESERVED_SLOTS(2),
|
||||
JS_PropertyStub, JS_PropertyStub, holder_get, holder_set,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
|
||||
};
|
||||
|
||||
/*
|
||||
* Xray expando handling.
|
||||
*
|
||||
* We hang expandos for Xray wrappers off a reserved slot on the target object
|
||||
* so that same-origin compartments can share expandos for a given object. We
|
||||
* have a linked list of expando objects, one per origin. The properties on these
|
||||
* objects are generally wrappers pointing back to the compartment that applied
|
||||
* them.
|
||||
*
|
||||
* The expando objects should _never_ be exposed to script. The fact that they
|
||||
* live in the target compartment is a detail of the implementation, and does
|
||||
* not imply that code in the target compartment should be allowed to inspect
|
||||
* them. They are private to the origin that placed them.
|
||||
*/
|
||||
|
||||
enum ExpandoSlots {
|
||||
JSSLOT_EXPANDO_NEXT = 0,
|
||||
JSSLOT_EXPANDO_ORIGIN,
|
||||
JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL,
|
||||
JSSLOT_EXPANDO_COUNT
|
||||
};
|
||||
|
||||
static nsIPrincipal*
|
||||
ObjectPrincipal(JSObject *obj)
|
||||
{
|
||||
return GetCompartmentPrincipal(js::GetObjectCompartment(obj));
|
||||
}
|
||||
|
||||
static nsIPrincipal*
|
||||
GetExpandoObjectPrincipal(JSObject *expandoObject)
|
||||
{
|
||||
JS::Value v = JS_GetReservedSlot(expandoObject, JSSLOT_EXPANDO_ORIGIN);
|
||||
return static_cast<nsIPrincipal*>(v.toPrivate());
|
||||
}
|
||||
|
||||
static void
|
||||
ExpandoObjectFinalize(JSFreeOp *fop, JSObject *obj)
|
||||
{
|
||||
// Release the principal.
|
||||
nsIPrincipal *principal = GetExpandoObjectPrincipal(obj);
|
||||
NS_RELEASE(principal);
|
||||
}
|
||||
|
||||
JSClass ExpandoObjectClass = {
|
||||
"XrayExpandoObject",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_EXPANDO_COUNT),
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ExpandoObjectFinalize
|
||||
};
|
||||
|
||||
bool
|
||||
ExpandoObjectMatchesConsumer(JSObject *expandoObject,
|
||||
nsIPrincipal *consumerOrigin,
|
||||
JSObject *exclusiveGlobal)
|
||||
{
|
||||
// First, compare the principals.
|
||||
nsIPrincipal *o = GetExpandoObjectPrincipal(expandoObject);
|
||||
bool equal;
|
||||
// Note that it's very important here to ignore document.domain. We
|
||||
// pull the principal for the expando object off of the first consumer
|
||||
// for a given origin, and freely share the expandos amongst multiple
|
||||
// same-origin consumers afterwards. However, this means that we have
|
||||
// no way to know whether _all_ consumers have opted in to collaboration
|
||||
// by explicitly setting document.domain. So we just mandate that expando
|
||||
// sharing is unaffected by it.
|
||||
nsresult rv = consumerOrigin->EqualsIgnoringDomain(o, &equal);
|
||||
if (NS_FAILED(rv) || !equal)
|
||||
return false;
|
||||
|
||||
// Sandboxes want exclusive expando objects.
|
||||
JSObject *owner = JS_GetReservedSlot(expandoObject,
|
||||
JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL)
|
||||
.toObjectOrNull();
|
||||
if (!owner && !exclusiveGlobal)
|
||||
return true;
|
||||
return owner == exclusiveGlobal;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
LookupExpandoObject(JSObject *target, nsIPrincipal *origin,
|
||||
JSObject *exclusiveGlobal)
|
||||
{
|
||||
// Iterate through the chain, looking for a same-origin object.
|
||||
JSObject *head = GetExpandoChain(target);
|
||||
while (head) {
|
||||
if (ExpandoObjectMatchesConsumer(head, origin, exclusiveGlobal))
|
||||
return head;
|
||||
head = JS_GetReservedSlot(head, JSSLOT_EXPANDO_NEXT).toObjectOrNull();
|
||||
}
|
||||
|
||||
// Not found.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Convenience method for the above.
|
||||
JSObject *
|
||||
LookupExpandoObject(JSObject *target, JSObject *consumer)
|
||||
{
|
||||
JSObject *consumerGlobal = js::GetGlobalForObjectCrossCompartment(consumer);
|
||||
bool isSandbox = !strcmp(js::GetObjectJSClass(consumerGlobal)->name, "Sandbox");
|
||||
return LookupExpandoObject(target, ObjectPrincipal(consumer),
|
||||
isSandbox ? consumerGlobal : nsnull);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
AttachExpandoObject(JSContext *cx, JSObject *target, nsIPrincipal *origin,
|
||||
JSObject *exclusiveGlobal)
|
||||
{
|
||||
// We should only be used for WNs.
|
||||
MOZ_ASSERT(IS_WN_WRAPPER(target));
|
||||
|
||||
// No duplicates allowed.
|
||||
MOZ_ASSERT(!LookupExpandoObject(target, origin, exclusiveGlobal));
|
||||
|
||||
// Create the expando object. We parent it directly to the target object.
|
||||
JSObject *expandoObject = JS_NewObjectWithGivenProto(cx, &ExpandoObjectClass,
|
||||
nsnull, target);
|
||||
if (!expandoObject)
|
||||
return nsnull;
|
||||
|
||||
// AddRef and store the principal.
|
||||
NS_ADDREF(origin);
|
||||
JS_SetReservedSlot(expandoObject, JSSLOT_EXPANDO_ORIGIN, PRIVATE_TO_JSVAL(origin));
|
||||
|
||||
// Note the exclusive global, if any.
|
||||
JS_SetReservedSlot(expandoObject, JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL,
|
||||
OBJECT_TO_JSVAL(exclusiveGlobal));
|
||||
|
||||
// If this is our first expando object, take the opportunity to preserve
|
||||
// the wrapper. This keeps our expandos alive even if the Xray wrapper gets
|
||||
// collected.
|
||||
JSObject *chain = GetExpandoChain(target);
|
||||
if (!chain) {
|
||||
XPCWrappedNative *wn =
|
||||
static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(target));
|
||||
nsRefPtr<nsXPCClassInfo> ci;
|
||||
CallQueryInterface(wn->Native(), getter_AddRefs(ci));
|
||||
if (ci)
|
||||
ci->PreserveWrapper(wn->Native());
|
||||
}
|
||||
|
||||
// Insert it at the front of the chain.
|
||||
JS_SetReservedSlot(expandoObject, JSSLOT_EXPANDO_NEXT, OBJECT_TO_JSVAL(chain));
|
||||
SetExpandoChain(target, expandoObject);
|
||||
|
||||
return expandoObject;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
EnsureExpandoObject(JSContext *cx, JSObject *wrapper, JSObject *target)
|
||||
{
|
||||
JSObject *expandoObject = LookupExpandoObject(target, wrapper);
|
||||
if (!expandoObject) {
|
||||
// If the object is a sandbox, we don't want it to share expandos with
|
||||
// anyone else, so we tag it with the sandbox global.
|
||||
JSObject *consumerGlobal = js::GetGlobalForObjectCrossCompartment(wrapper);
|
||||
bool isSandbox = !strcmp(js::GetObjectJSClass(consumerGlobal)->name, "Sandbox");
|
||||
expandoObject = AttachExpandoObject(cx, target, ObjectPrincipal(wrapper),
|
||||
isSandbox ? consumerGlobal : nsnull);
|
||||
}
|
||||
return expandoObject;
|
||||
}
|
||||
|
||||
bool
|
||||
CloneExpandoChain(JSContext *cx, JSObject *dst, JSObject *src)
|
||||
{
|
||||
MOZ_ASSERT(js::IsObjectInContextCompartment(dst, cx));
|
||||
MOZ_ASSERT(GetExpandoChain(dst) == nsnull);
|
||||
|
||||
JSObject *oldHead = GetExpandoChain(src);
|
||||
while (oldHead) {
|
||||
JSObject *exclusive = JS_GetReservedSlot(oldHead,
|
||||
JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL)
|
||||
.toObjectOrNull();
|
||||
JSObject *newHead =
|
||||
AttachExpandoObject(cx, dst, GetExpandoObjectPrincipal(oldHead), exclusive);
|
||||
if (!JS_CopyPropertiesFrom(cx, newHead, oldHead))
|
||||
return false;
|
||||
oldHead = JS_GetReservedSlot(oldHead, JSSLOT_EXPANDO_NEXT).toObjectOrNull();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
createHolder(JSContext *cx, JSObject *wrappedNative, JSObject *parent)
|
||||
{
|
||||
@ -49,10 +231,8 @@ createHolder(JSContext *cx, JSObject *wrappedNative, JSObject *parent)
|
||||
if (!holder)
|
||||
return nsnull;
|
||||
|
||||
CompartmentPrivate *priv = GetCompartmentPrivate(holder);
|
||||
JSObject *inner = JS_ObjectToInnerObject(cx, wrappedNative);
|
||||
XPCWrappedNative *wn = GetWrappedNative(inner);
|
||||
Value expando = ObjectOrNullValue(priv->LookupExpandoObject(wn));
|
||||
|
||||
// A note about ownership: the holder has a direct pointer to the wrapped
|
||||
// native that we're wrapping. Normally, we'd have to AddRef the pointer
|
||||
@ -66,7 +246,6 @@ createHolder(JSContext *cx, JSObject *wrappedNative, JSObject *parent)
|
||||
js::GetObjectClass(wrappedNative)->ext.innerObject);
|
||||
js::SetReservedSlot(holder, JSSLOT_WN, PrivateValue(wn));
|
||||
js::SetReservedSlot(holder, JSSLOT_RESOLVING, PrivateValue(NULL));
|
||||
js::SetReservedSlot(holder, JSSLOT_EXPANDO, expando);
|
||||
return holder;
|
||||
}
|
||||
|
||||
@ -243,43 +422,6 @@ GetWrappedNativeObjectFromHolder(JSObject *holder)
|
||||
return GetWrappedNativeFromHolder(holder)->GetFlatJSObject();
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
GetExpandoObject(JSObject *holder)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectJSClass(holder) == &HolderClass);
|
||||
return js::GetReservedSlot(holder, JSSLOT_EXPANDO).toObjectOrNull();
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
EnsureExpandoObject(JSContext *cx, JSObject *holder)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectJSClass(holder) == &HolderClass);
|
||||
JSObject *expando = GetExpandoObject(holder);
|
||||
if (expando)
|
||||
return expando;
|
||||
CompartmentPrivate *priv = GetCompartmentPrivate(holder);
|
||||
XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
|
||||
expando = priv->LookupExpandoObject(wn);
|
||||
if (!expando) {
|
||||
expando = JS_NewObjectWithGivenProto(cx, nsnull, nsnull,
|
||||
js::GetObjectParent(holder));
|
||||
if (!expando)
|
||||
return NULL;
|
||||
// Add the expando object to the expando map to keep it alive.
|
||||
if (!priv->RegisterExpandoObject(wn, expando)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
// Make sure the wn stays alive so it keeps the expando object alive.
|
||||
nsRefPtr<nsXPCClassInfo> ci;
|
||||
CallQueryInterface(wn->Native(), getter_AddRefs(ci));
|
||||
if (ci)
|
||||
ci->PreserveWrapper(wn->Native());
|
||||
}
|
||||
js::SetReservedSlot(holder, JSSLOT_EXPANDO, ObjectValue(*expando));
|
||||
return expando;
|
||||
}
|
||||
|
||||
static inline JSObject *
|
||||
FindWrapper(JSObject *wrapper)
|
||||
{
|
||||
@ -654,13 +796,22 @@ XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, js::Wrapper &jsWra
|
||||
desc->obj = NULL;
|
||||
|
||||
unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED;
|
||||
JSObject *expando = GetExpandoObject(holder);
|
||||
JSObject *target = GetWrappedNativeObjectFromHolder(holder);
|
||||
JSObject *expando = LookupExpandoObject(target, wrapper);
|
||||
|
||||
// Check for expando properties first.
|
||||
if (expando && !JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) {
|
||||
return false;
|
||||
// Check for expando properties first. Note that the expando object lives
|
||||
// in the target compartment.
|
||||
if (expando) {
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, expando) ||
|
||||
!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (desc->obj) {
|
||||
if (!JS_WrapPropertyDescriptor(cx, desc))
|
||||
return false;
|
||||
// Pretend the property lives on the wrapper.
|
||||
desc->obj = wrapper;
|
||||
return true;
|
||||
@ -718,24 +869,42 @@ XPCWrappedNativeXrayTraits::defineProperty(JSContext *cx, JSObject *wrapper, jsi
|
||||
desc->attrs);
|
||||
}
|
||||
|
||||
JSObject *expando = EnsureExpandoObject(cx, holder);
|
||||
if (!expando)
|
||||
// We're placing an expando. The expando objects live in the target
|
||||
// compartment, so we need to enter it.
|
||||
JSObject *target = GetWrappedNativeObjectFromHolder(holder);
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, target))
|
||||
return false;
|
||||
|
||||
return JS_DefinePropertyById(cx, expando, id, desc->value, desc->getter, desc->setter,
|
||||
desc->attrs);
|
||||
// Grab the relevant expando object.
|
||||
JSObject *expandoObject = EnsureExpandoObject(cx, wrapper, target);
|
||||
if (!expandoObject)
|
||||
return false;
|
||||
|
||||
// Wrap the property descriptor for the target compartment.
|
||||
PropertyDescriptor wrappedDesc = *desc;
|
||||
if (!JS_WrapPropertyDescriptor(cx, &wrappedDesc))
|
||||
return false;
|
||||
|
||||
return JS_DefinePropertyById(cx, expandoObject, id, wrappedDesc.value,
|
||||
wrappedDesc.getter, wrappedDesc.setter,
|
||||
wrappedDesc.attrs);
|
||||
}
|
||||
|
||||
bool
|
||||
XPCWrappedNativeXrayTraits::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
{
|
||||
JSObject *holder = getHolderObject(wrapper);
|
||||
JSObject *expando = GetExpandoObject(holder);
|
||||
JSObject *target = GetWrappedNativeObjectFromHolder(holder);
|
||||
JSObject *expando = LookupExpandoObject(target, wrapper);
|
||||
JSAutoEnterCompartment ac;
|
||||
JSBool b = true;
|
||||
jsval v;
|
||||
if (expando &&
|
||||
(!JS_DeletePropertyById2(cx, expando, id, &v) ||
|
||||
!JS_ValueToBoolean(cx, v, &b))) {
|
||||
(!ac.enter(cx, expando) ||
|
||||
!JS_DeletePropertyById2(cx, expando, id, &v) ||
|
||||
!JS_ValueToBoolean(cx, v, &b)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -749,9 +918,19 @@ XPCWrappedNativeXrayTraits::enumerateNames(JSContext *cx, JSObject *wrapper, uns
|
||||
{
|
||||
JSObject *holder = getHolderObject(wrapper);
|
||||
|
||||
// Enumerate expando properties first.
|
||||
JSObject *expando = GetExpandoObject(holder);
|
||||
if (expando && !js::GetPropertyNames(cx, expando, flags, &props))
|
||||
// Enumerate expando properties first. Note that the expando object lives
|
||||
// in the target compartment.
|
||||
JSObject *target = GetWrappedNativeObjectFromHolder(holder);
|
||||
JSObject *expando = LookupExpandoObject(target, wrapper);
|
||||
if (expando) {
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, expando) ||
|
||||
!js::GetPropertyNames(cx, expando, flags, &props))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!JS_WrapAutoIdVector(cx, props))
|
||||
return false;
|
||||
|
||||
// Force all native properties to be materialized onto the wrapped native.
|
||||
|
@ -27,6 +27,8 @@ namespace XrayUtils {
|
||||
|
||||
extern JSClass HolderClass;
|
||||
|
||||
bool CloneExpandoChain(JSContext *cx, JSObject *src, JSObject *dst);
|
||||
|
||||
JSObject *createHolder(JSContext *cx, JSObject *wrappedNative, JSObject *parent);
|
||||
|
||||
bool
|
||||
|
@ -414,16 +414,14 @@ nsPresArena::~nsPresArena()
|
||||
void*
|
||||
nsPresArena::AllocateBySize(size_t aSize)
|
||||
{
|
||||
return mState->Allocate(PRUint32(aSize) |
|
||||
PRUint32(nsQueryFrame::NON_FRAME_MARKER),
|
||||
return mState->Allocate(PRUint32(aSize) | PRUint32(NON_OBJECT_MARKER),
|
||||
aSize);
|
||||
}
|
||||
|
||||
void
|
||||
nsPresArena::FreeBySize(size_t aSize, void* aPtr)
|
||||
{
|
||||
mState->Free(PRUint32(aSize) |
|
||||
PRUint32(nsQueryFrame::NON_FRAME_MARKER), aPtr);
|
||||
mState->Free(PRUint32(aSize) | PRUint32(NON_OBJECT_MARKER), aPtr);
|
||||
}
|
||||
|
||||
void*
|
||||
|
@ -69,7 +69,6 @@ protected:
|
||||
|
||||
virtual bool IsInput() { return true; }
|
||||
private:
|
||||
nsSize mSuggestedSize;
|
||||
nsCOMPtr<nsIContent> mTextContent;
|
||||
};
|
||||
|
||||
|
@ -669,6 +669,27 @@ nsBlockFrame::MarkIntrinsicWidthsDirty()
|
||||
nsBlockFrameSuper::MarkIntrinsicWidthsDirty();
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockFrame::CheckIntrinsicCacheAgainstShrinkWrapState()
|
||||
{
|
||||
nsPresContext *presContext = PresContext();
|
||||
if (!nsLayoutUtils::FontSizeInflationEnabled(presContext)) {
|
||||
return;
|
||||
}
|
||||
bool inflationEnabled =
|
||||
!presContext->mInflationDisabledForShrinkWrap;
|
||||
if (inflationEnabled !=
|
||||
!!(GetStateBits() & NS_BLOCK_FRAME_INTRINSICS_INFLATED)) {
|
||||
mMinWidth = NS_INTRINSIC_WIDTH_UNKNOWN;
|
||||
mPrefWidth = NS_INTRINSIC_WIDTH_UNKNOWN;
|
||||
if (inflationEnabled) {
|
||||
AddStateBits(NS_BLOCK_FRAME_INTRINSICS_INFLATED);
|
||||
} else {
|
||||
RemoveStateBits(NS_BLOCK_FRAME_INTRINSICS_INFLATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ nscoord
|
||||
nsBlockFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
|
||||
{
|
||||
@ -677,6 +698,9 @@ nsBlockFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
|
||||
return firstInFlow->GetMinWidth(aRenderingContext);
|
||||
|
||||
DISPLAY_MIN_WIDTH(this, mMinWidth);
|
||||
|
||||
CheckIntrinsicCacheAgainstShrinkWrapState();
|
||||
|
||||
if (mMinWidth != NS_INTRINSIC_WIDTH_UNKNOWN)
|
||||
return mMinWidth;
|
||||
|
||||
@ -755,6 +779,8 @@ nsBlockFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
|
||||
|
||||
DISPLAY_PREF_WIDTH(this, mPrefWidth);
|
||||
|
||||
CheckIntrinsicCacheAgainstShrinkWrapState();
|
||||
|
||||
if (mPrefWidth != NS_INTRINSIC_WIDTH_UNKNOWN)
|
||||
return mPrefWidth;
|
||||
|
||||
|
@ -91,6 +91,16 @@ class nsIntervalSet;
|
||||
// (including <BR CLEAR="..."> frames)
|
||||
#define NS_BLOCK_HAS_CLEAR_CHILDREN NS_FRAME_STATE_BIT(27)
|
||||
|
||||
// Are our cached intrinsic widths intrinsic widths for font size
|
||||
// inflation? i.e., what was the current state of
|
||||
// GetPresContext()->mInflationDisabledForShrinkWrap at the time they
|
||||
// were computed?
|
||||
// nsBlockFrame is the only thing that caches intrinsic widths that
|
||||
// needs to track this because it's the only thing that caches intrinsic
|
||||
// widths that lives inside of things (form controls) that do intrinsic
|
||||
// sizing with font inflation enabled.
|
||||
#define NS_BLOCK_FRAME_INTRINSICS_INFLATED NS_FRAME_STATE_BIT(62)
|
||||
|
||||
#define nsBlockFrameSuper nsContainerFrame
|
||||
|
||||
/*
|
||||
@ -241,6 +251,9 @@ public:
|
||||
}
|
||||
|
||||
virtual void MarkIntrinsicWidthsDirty();
|
||||
private:
|
||||
void CheckIntrinsicCacheAgainstShrinkWrapState();
|
||||
public:
|
||||
virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
|
||||
virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
|
||||
|
||||
|
@ -131,6 +131,11 @@ ComputeDescendantWidth(const nsHTMLReflowState& aAncestorReflowState,
|
||||
frames.AppendElement(f);
|
||||
}
|
||||
|
||||
// This ignores the width contributions made by scrollbars, though in
|
||||
// reality we don't have any scrollbars on the sorts of devices on
|
||||
// which we use font inflation, so it's not a problem. But it may
|
||||
// occasionally cause problems when writing tests on desktop.
|
||||
|
||||
PRUint32 len = frames.Length();
|
||||
nsHTMLReflowState *reflowStates = static_cast<nsHTMLReflowState*>
|
||||
(moz_xmalloc(sizeof(nsHTMLReflowState) * len));
|
||||
|
@ -6696,6 +6696,12 @@ nsTextFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext,
|
||||
float inflation = nsLayoutUtils::FontSizeInflationFor(this);
|
||||
TextRunType trtype = (inflation == 1.0f) ? eNotInflated : eInflated;
|
||||
|
||||
if (trtype == eInflated && inflation != GetFontSizeInflation()) {
|
||||
// FIXME: Ideally, if we already have a text run, we'd move it to be
|
||||
// the uninflated text run.
|
||||
ClearTextRun(nsnull, nsTextFrame::eInflated);
|
||||
}
|
||||
|
||||
nsTextFrame* f;
|
||||
gfxTextRun* lastTextRun = nsnull;
|
||||
// nsContinuingTextFrame does nothing for AddInlineMinWidth; all text frames
|
||||
@ -6826,6 +6832,12 @@ nsTextFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext,
|
||||
float inflation = nsLayoutUtils::FontSizeInflationFor(this);
|
||||
TextRunType trtype = (inflation == 1.0f) ? eNotInflated : eInflated;
|
||||
|
||||
if (trtype == eInflated && inflation != GetFontSizeInflation()) {
|
||||
// FIXME: Ideally, if we already have a text run, we'd move it to be
|
||||
// the uninflated text run.
|
||||
ClearTextRun(nsnull, nsTextFrame::eInflated);
|
||||
}
|
||||
|
||||
nsTextFrame* f;
|
||||
gfxTextRun* lastTextRun = nsnull;
|
||||
// nsContinuingTextFrame does nothing for AddInlineMinWidth; all text frames
|
||||
|
23
layout/reftests/font-inflation/min-width-passes-1-ref.html
Normal file
23
layout/reftests/font-inflation/min-width-passes-1-ref.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug Reproduction</title>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
/*
|
||||
* Work around bug 759755 / bug 757179. Setting overflow hidden
|
||||
* avoids these bugs being triggered due to the hypothetical scrollbar
|
||||
* reflows.
|
||||
*/
|
||||
overflow: hidden;
|
||||
}
|
||||
table { width: 100% }
|
||||
body, table, tbody, tr, td {
|
||||
margin: 0; border: none; padding: 0; border-spacing: 0;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1 id="welcome">Welcome to Bugzilla</h1>
|
||||
<input type="button" id="find" value="Quick Search"></input>
|
||||
</body>
|
||||
</html>
|
25
layout/reftests/font-inflation/min-width-passes-1.html
Normal file
25
layout/reftests/font-inflation/min-width-passes-1.html
Normal file
@ -0,0 +1,25 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug Reproduction</title>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
/*
|
||||
* Work around bug 759755 / bug 757179. Setting overflow hidden
|
||||
* avoids these bugs being triggered due to the hypothetical scrollbar
|
||||
* reflows.
|
||||
*/
|
||||
overflow: hidden;
|
||||
}
|
||||
table { width: 100% }
|
||||
body, table, tbody, tr, td {
|
||||
margin: 0; border: none; padding: 0; border-spacing: 0;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<table><tr><td>
|
||||
<h1 id="welcome">Welcome to Bugzilla</h1>
|
||||
<input type="button" id="find" value="Quick Search"></input>
|
||||
</td></tr></table>
|
||||
</body>
|
||||
</html>
|
@ -95,3 +95,5 @@ fuzzy-if(gtk2Widget,1,8) test-pref(font.size.inflation.emPerLine,15) test-pref(f
|
||||
|
||||
test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) == relevant-width-1.html relevant-width-1-ref.html
|
||||
test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) == relevant-width-overflow-1.html relevant-width-overflow-1-ref.html
|
||||
|
||||
pref(font.size.inflation.emPerLine,15) pref(font.size.inflation.lineThreshold,0) == min-width-passes-1.html min-width-passes-1-ref.html
|
||||
|
@ -58,6 +58,9 @@ To upgrade to a new revision of libjpeg-turbo, do the following:
|
||||
|
||||
$ hg addremove
|
||||
|
||||
== June 5, 2012 (libjpeg-turbo v1.2.x branch, r831 2012-05-30) ==
|
||||
|
||||
* Updated to latest version on v1.2.x branch (bug 759891).
|
||||
|
||||
== February 10, 2012 (libjpeg-turbo v1.2.0 r807 2012-02-10) ==
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* jccolext.c
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Copyright (C) 2009-2011, D. R. Commander.
|
||||
* Copyright (C) 2009-2012, D. R. Commander.
|
||||
* This file is part of the Independent JPEG Group's software.
|
||||
* For conditions of distribution and use, see the accompanying README file.
|
||||
*
|
||||
@ -112,3 +112,35 @@ rgb_gray_convert_internal (j_compress_ptr cinfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert some rows of samples to the JPEG colorspace.
|
||||
* This version handles extended RGB->plain RGB conversion
|
||||
*/
|
||||
|
||||
INLINE
|
||||
LOCAL(void)
|
||||
rgb_rgb_convert_internal (j_compress_ptr cinfo,
|
||||
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
|
||||
JDIMENSION output_row, int num_rows)
|
||||
{
|
||||
register JSAMPROW inptr;
|
||||
register JSAMPROW outptr0, outptr1, outptr2;
|
||||
register JDIMENSION col;
|
||||
JDIMENSION num_cols = cinfo->image_width;
|
||||
|
||||
while (--num_rows >= 0) {
|
||||
inptr = *input_buf++;
|
||||
outptr0 = output_buf[0][output_row];
|
||||
outptr1 = output_buf[1][output_row];
|
||||
outptr2 = output_buf[2][output_row];
|
||||
output_row++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
outptr0[col] = GETJSAMPLE(inptr[RGB_RED]);
|
||||
outptr1[col] = GETJSAMPLE(inptr[RGB_GREEN]);
|
||||
outptr2[col] = GETJSAMPLE(inptr[RGB_BLUE]);
|
||||
inptr += RGB_PIXELSIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1991-1996, Thomas G. Lane.
|
||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
* Copyright (C) 2009-2011, D. R. Commander.
|
||||
* Copyright (C) 2009-2012, D. R. Commander.
|
||||
* This file is part of the Independent JPEG Group's software.
|
||||
* For conditions of distribution and use, see the accompanying README file.
|
||||
*
|
||||
@ -96,6 +96,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_RGB_PIXELSIZE
|
||||
#define rgb_ycc_convert_internal extrgb_ycc_convert_internal
|
||||
#define rgb_gray_convert_internal extrgb_gray_convert_internal
|
||||
#define rgb_rgb_convert_internal extrgb_rgb_convert_internal
|
||||
#include "jccolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -103,6 +104,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef rgb_ycc_convert_internal
|
||||
#undef rgb_gray_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_RGBX_RED
|
||||
#define RGB_GREEN EXT_RGBX_GREEN
|
||||
@ -110,6 +112,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_RGBX_PIXELSIZE
|
||||
#define rgb_ycc_convert_internal extrgbx_ycc_convert_internal
|
||||
#define rgb_gray_convert_internal extrgbx_gray_convert_internal
|
||||
#define rgb_rgb_convert_internal extrgbx_rgb_convert_internal
|
||||
#include "jccolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -117,6 +120,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef rgb_ycc_convert_internal
|
||||
#undef rgb_gray_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_BGR_RED
|
||||
#define RGB_GREEN EXT_BGR_GREEN
|
||||
@ -124,6 +128,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_BGR_PIXELSIZE
|
||||
#define rgb_ycc_convert_internal extbgr_ycc_convert_internal
|
||||
#define rgb_gray_convert_internal extbgr_gray_convert_internal
|
||||
#define rgb_rgb_convert_internal extbgr_rgb_convert_internal
|
||||
#include "jccolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -131,6 +136,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef rgb_ycc_convert_internal
|
||||
#undef rgb_gray_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_BGRX_RED
|
||||
#define RGB_GREEN EXT_BGRX_GREEN
|
||||
@ -138,6 +144,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_BGRX_PIXELSIZE
|
||||
#define rgb_ycc_convert_internal extbgrx_ycc_convert_internal
|
||||
#define rgb_gray_convert_internal extbgrx_gray_convert_internal
|
||||
#define rgb_rgb_convert_internal extbgrx_rgb_convert_internal
|
||||
#include "jccolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -145,6 +152,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef rgb_ycc_convert_internal
|
||||
#undef rgb_gray_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_XBGR_RED
|
||||
#define RGB_GREEN EXT_XBGR_GREEN
|
||||
@ -152,6 +160,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_XBGR_PIXELSIZE
|
||||
#define rgb_ycc_convert_internal extxbgr_ycc_convert_internal
|
||||
#define rgb_gray_convert_internal extxbgr_gray_convert_internal
|
||||
#define rgb_rgb_convert_internal extxbgr_rgb_convert_internal
|
||||
#include "jccolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -159,6 +168,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef rgb_ycc_convert_internal
|
||||
#undef rgb_gray_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_XRGB_RED
|
||||
#define RGB_GREEN EXT_XRGB_GREEN
|
||||
@ -166,6 +176,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_XRGB_PIXELSIZE
|
||||
#define rgb_ycc_convert_internal extxrgb_ycc_convert_internal
|
||||
#define rgb_gray_convert_internal extxrgb_gray_convert_internal
|
||||
#define rgb_rgb_convert_internal extxrgb_rgb_convert_internal
|
||||
#include "jccolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -173,6 +184,7 @@ typedef my_color_converter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef rgb_ycc_convert_internal
|
||||
#undef rgb_gray_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
|
||||
/*
|
||||
@ -306,6 +318,52 @@ rgb_gray_convert (j_compress_ptr cinfo,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Extended RGB to plain RGB conversion
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
rgb_rgb_convert (j_compress_ptr cinfo,
|
||||
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
|
||||
JDIMENSION output_row, int num_rows)
|
||||
{
|
||||
switch (cinfo->in_color_space) {
|
||||
case JCS_EXT_RGB:
|
||||
extrgb_rgb_convert_internal(cinfo, input_buf, output_buf, output_row,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_RGBX:
|
||||
case JCS_EXT_RGBA:
|
||||
extrgbx_rgb_convert_internal(cinfo, input_buf, output_buf, output_row,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_BGR:
|
||||
extbgr_rgb_convert_internal(cinfo, input_buf, output_buf, output_row,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_BGRX:
|
||||
case JCS_EXT_BGRA:
|
||||
extbgrx_rgb_convert_internal(cinfo, input_buf, output_buf, output_row,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_XBGR:
|
||||
case JCS_EXT_ABGR:
|
||||
extxbgr_rgb_convert_internal(cinfo, input_buf, output_buf, output_row,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_XRGB:
|
||||
case JCS_EXT_ARGB:
|
||||
extxrgb_rgb_convert_internal(cinfo, input_buf, output_buf, output_row,
|
||||
num_rows);
|
||||
break;
|
||||
default:
|
||||
rgb_rgb_convert_internal(cinfo, input_buf, output_buf, output_row,
|
||||
num_rows);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert some rows of samples to the JPEG colorspace.
|
||||
* This version handles Adobe-style CMYK->YCCK conversion,
|
||||
@ -523,21 +581,25 @@ jinit_color_converter (j_compress_ptr cinfo)
|
||||
break;
|
||||
|
||||
case JCS_RGB:
|
||||
case JCS_EXT_RGB:
|
||||
case JCS_EXT_RGBX:
|
||||
case JCS_EXT_BGR:
|
||||
case JCS_EXT_BGRX:
|
||||
case JCS_EXT_XBGR:
|
||||
case JCS_EXT_XRGB:
|
||||
case JCS_EXT_RGBA:
|
||||
case JCS_EXT_BGRA:
|
||||
case JCS_EXT_ABGR:
|
||||
case JCS_EXT_ARGB:
|
||||
if (cinfo->num_components != 3)
|
||||
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
|
||||
if (cinfo->in_color_space == cinfo->jpeg_color_space &&
|
||||
rgb_pixelsize[cinfo->in_color_space] == 3)
|
||||
if (rgb_red[cinfo->in_color_space] == 0 &&
|
||||
rgb_green[cinfo->in_color_space] == 1 &&
|
||||
rgb_blue[cinfo->in_color_space] == 2 &&
|
||||
rgb_pixelsize[cinfo->in_color_space] == 3)
|
||||
cconvert->pub.color_convert = null_convert;
|
||||
else if (cinfo->in_color_space == JCS_RGB ||
|
||||
cinfo->in_color_space == JCS_EXT_RGB ||
|
||||
cinfo->in_color_space == JCS_EXT_RGBX ||
|
||||
cinfo->in_color_space == JCS_EXT_BGR ||
|
||||
cinfo->in_color_space == JCS_EXT_BGRX ||
|
||||
cinfo->in_color_space == JCS_EXT_XBGR ||
|
||||
cinfo->in_color_space == JCS_EXT_XRGB ||
|
||||
cinfo->in_color_space == JCS_EXT_RGBA ||
|
||||
cinfo->in_color_space == JCS_EXT_BGRA ||
|
||||
cinfo->in_color_space == JCS_EXT_ABGR ||
|
||||
cinfo->in_color_space == JCS_EXT_ARGB)
|
||||
cconvert->pub.color_convert = rgb_rgb_convert;
|
||||
else
|
||||
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
|
||||
break;
|
||||
|
@ -102,3 +102,40 @@ gray_rgb_convert_internal (j_decompress_ptr cinfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert RGB to extended RGB: just swap the order of source pixels
|
||||
*/
|
||||
|
||||
INLINE
|
||||
LOCAL(void)
|
||||
rgb_rgb_convert_internal (j_decompress_ptr cinfo,
|
||||
JSAMPIMAGE input_buf, JDIMENSION input_row,
|
||||
JSAMPARRAY output_buf, int num_rows)
|
||||
{
|
||||
register JSAMPROW inptr0, inptr1, inptr2;
|
||||
register JSAMPROW outptr;
|
||||
register JDIMENSION col;
|
||||
JDIMENSION num_cols = cinfo->output_width;
|
||||
|
||||
while (--num_rows >= 0) {
|
||||
inptr0 = input_buf[0][input_row];
|
||||
inptr1 = input_buf[1][input_row];
|
||||
inptr2 = input_buf[2][input_row];
|
||||
input_row++;
|
||||
outptr = *output_buf++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
/* We can dispense with GETJSAMPLE() here */
|
||||
outptr[RGB_RED] = inptr0[col];
|
||||
outptr[RGB_GREEN] = inptr1[col];
|
||||
outptr[RGB_BLUE] = inptr2[col];
|
||||
/* Set unused byte to 0xFF so it can be interpreted as an opaque */
|
||||
/* alpha channel value */
|
||||
#ifdef RGB_ALPHA
|
||||
outptr[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr += RGB_PIXELSIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
* Copyright (C) 2009, 2011, D. R. Commander.
|
||||
* Copyright (C) 2009, 2011-2012, D. R. Commander.
|
||||
* This file is part of the Independent JPEG Group's software.
|
||||
* For conditions of distribution and use, see the accompanying README file.
|
||||
*
|
||||
@ -80,6 +80,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_RGB_PIXELSIZE
|
||||
#define ycc_rgb_convert_internal ycc_extrgb_convert_internal
|
||||
#define gray_rgb_convert_internal gray_extrgb_convert_internal
|
||||
#define rgb_rgb_convert_internal rgb_extrgb_convert_internal
|
||||
#include "jdcolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -87,6 +88,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef ycc_rgb_convert_internal
|
||||
#undef gray_rgb_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_RGBX_RED
|
||||
#define RGB_GREEN EXT_RGBX_GREEN
|
||||
@ -95,6 +97,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_RGBX_PIXELSIZE
|
||||
#define ycc_rgb_convert_internal ycc_extrgbx_convert_internal
|
||||
#define gray_rgb_convert_internal gray_extrgbx_convert_internal
|
||||
#define rgb_rgb_convert_internal rgb_extrgbx_convert_internal
|
||||
#include "jdcolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -103,6 +106,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef ycc_rgb_convert_internal
|
||||
#undef gray_rgb_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_BGR_RED
|
||||
#define RGB_GREEN EXT_BGR_GREEN
|
||||
@ -110,6 +114,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_BGR_PIXELSIZE
|
||||
#define ycc_rgb_convert_internal ycc_extbgr_convert_internal
|
||||
#define gray_rgb_convert_internal gray_extbgr_convert_internal
|
||||
#define rgb_rgb_convert_internal rgb_extbgr_convert_internal
|
||||
#include "jdcolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -117,6 +122,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef ycc_rgb_convert_internal
|
||||
#undef gray_rgb_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_BGRX_RED
|
||||
#define RGB_GREEN EXT_BGRX_GREEN
|
||||
@ -125,6 +131,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_BGRX_PIXELSIZE
|
||||
#define ycc_rgb_convert_internal ycc_extbgrx_convert_internal
|
||||
#define gray_rgb_convert_internal gray_extbgrx_convert_internal
|
||||
#define rgb_rgb_convert_internal rgb_extbgrx_convert_internal
|
||||
#include "jdcolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -133,6 +140,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef ycc_rgb_convert_internal
|
||||
#undef gray_rgb_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_XBGR_RED
|
||||
#define RGB_GREEN EXT_XBGR_GREEN
|
||||
@ -141,6 +149,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_XBGR_PIXELSIZE
|
||||
#define ycc_rgb_convert_internal ycc_extxbgr_convert_internal
|
||||
#define gray_rgb_convert_internal gray_extxbgr_convert_internal
|
||||
#define rgb_rgb_convert_internal rgb_extxbgr_convert_internal
|
||||
#include "jdcolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -149,6 +158,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef ycc_rgb_convert_internal
|
||||
#undef gray_rgb_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
#define RGB_RED EXT_XRGB_RED
|
||||
#define RGB_GREEN EXT_XRGB_GREEN
|
||||
@ -157,6 +167,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#define RGB_PIXELSIZE EXT_XRGB_PIXELSIZE
|
||||
#define ycc_rgb_convert_internal ycc_extxrgb_convert_internal
|
||||
#define gray_rgb_convert_internal gray_extxrgb_convert_internal
|
||||
#define rgb_rgb_convert_internal rgb_extxrgb_convert_internal
|
||||
#include "jdcolext.c"
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
@ -165,6 +176,7 @@ typedef my_color_deconverter * my_cconvert_ptr;
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef ycc_rgb_convert_internal
|
||||
#undef gray_rgb_convert_internal
|
||||
#undef rgb_rgb_convert_internal
|
||||
|
||||
|
||||
/*
|
||||
@ -352,6 +364,51 @@ gray_rgb_convert (j_decompress_ptr cinfo,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert plain RGB to extended RGB
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
rgb_rgb_convert (j_decompress_ptr cinfo,
|
||||
JSAMPIMAGE input_buf, JDIMENSION input_row,
|
||||
JSAMPARRAY output_buf, int num_rows)
|
||||
{
|
||||
switch (cinfo->out_color_space) {
|
||||
case JCS_EXT_RGB:
|
||||
rgb_extrgb_convert_internal(cinfo, input_buf, input_row, output_buf,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_RGBX:
|
||||
case JCS_EXT_RGBA:
|
||||
rgb_extrgbx_convert_internal(cinfo, input_buf, input_row, output_buf,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_BGR:
|
||||
rgb_extbgr_convert_internal(cinfo, input_buf, input_row, output_buf,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_BGRX:
|
||||
case JCS_EXT_BGRA:
|
||||
rgb_extbgrx_convert_internal(cinfo, input_buf, input_row, output_buf,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_XBGR:
|
||||
case JCS_EXT_ABGR:
|
||||
rgb_extxbgr_convert_internal(cinfo, input_buf, input_row, output_buf,
|
||||
num_rows);
|
||||
break;
|
||||
case JCS_EXT_XRGB:
|
||||
case JCS_EXT_ARGB:
|
||||
rgb_extxrgb_convert_internal(cinfo, input_buf, input_row, output_buf,
|
||||
num_rows);
|
||||
break;
|
||||
default:
|
||||
rgb_rgb_convert_internal(cinfo, input_buf, input_row, output_buf,
|
||||
num_rows);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adobe-style YCCK->CMYK conversion.
|
||||
* We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same
|
||||
@ -494,9 +551,14 @@ jinit_color_deconverter (j_decompress_ptr cinfo)
|
||||
}
|
||||
} else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
|
||||
cconvert->pub.color_convert = gray_rgb_convert;
|
||||
} else if (cinfo->jpeg_color_space == cinfo->out_color_space &&
|
||||
rgb_pixelsize[cinfo->out_color_space] == 3) {
|
||||
cconvert->pub.color_convert = null_convert;
|
||||
} else if (cinfo->jpeg_color_space == JCS_RGB) {
|
||||
if (rgb_red[cinfo->out_color_space] == 0 &&
|
||||
rgb_green[cinfo->out_color_space] == 1 &&
|
||||
rgb_blue[cinfo->out_color_space] == 2 &&
|
||||
rgb_pixelsize[cinfo->out_color_space] == 3)
|
||||
cconvert->pub.color_convert = null_convert;
|
||||
else
|
||||
cconvert->pub.color_convert = rgb_rgb_convert;
|
||||
} else
|
||||
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
|
||||
break;
|
||||
|
@ -323,14 +323,15 @@ get_sos (j_decompress_ptr cinfo)
|
||||
|
||||
/* Collect the component-spec parameters */
|
||||
|
||||
for (i = 0; i < cinfo->num_components; i++)
|
||||
for (i = 0; i < MAX_COMPS_IN_SCAN; i++)
|
||||
cinfo->cur_comp_info[i] = NULL;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
INPUT_BYTE(cinfo, cc, return FALSE);
|
||||
INPUT_BYTE(cinfo, c, return FALSE);
|
||||
|
||||
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
||||
for (ci = 0, compptr = cinfo->comp_info;
|
||||
ci < cinfo->num_components && ci < MAX_COMPS_IN_SCAN;
|
||||
ci++, compptr++) {
|
||||
if (cc == compptr->component_id && !cinfo->cur_comp_info[ci])
|
||||
goto id_found;
|
||||
|
@ -103,6 +103,7 @@ typedef my_upsampler * my_upsample_ptr;
|
||||
#define RGB_RED EXT_RGBX_RED
|
||||
#define RGB_GREEN EXT_RGBX_GREEN
|
||||
#define RGB_BLUE EXT_RGBX_BLUE
|
||||
#define RGB_ALPHA 3
|
||||
#define RGB_PIXELSIZE EXT_RGBX_PIXELSIZE
|
||||
#define h2v1_merged_upsample_internal extrgbx_h2v1_merged_upsample_internal
|
||||
#define h2v2_merged_upsample_internal extrgbx_h2v2_merged_upsample_internal
|
||||
@ -110,6 +111,7 @@ typedef my_upsampler * my_upsample_ptr;
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
#undef RGB_BLUE
|
||||
#undef RGB_ALPHA
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef h2v1_merged_upsample_internal
|
||||
#undef h2v2_merged_upsample_internal
|
||||
@ -131,6 +133,7 @@ typedef my_upsampler * my_upsample_ptr;
|
||||
#define RGB_RED EXT_BGRX_RED
|
||||
#define RGB_GREEN EXT_BGRX_GREEN
|
||||
#define RGB_BLUE EXT_BGRX_BLUE
|
||||
#define RGB_ALPHA 3
|
||||
#define RGB_PIXELSIZE EXT_BGRX_PIXELSIZE
|
||||
#define h2v1_merged_upsample_internal extbgrx_h2v1_merged_upsample_internal
|
||||
#define h2v2_merged_upsample_internal extbgrx_h2v2_merged_upsample_internal
|
||||
@ -138,6 +141,7 @@ typedef my_upsampler * my_upsample_ptr;
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
#undef RGB_BLUE
|
||||
#undef RGB_ALPHA
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef h2v1_merged_upsample_internal
|
||||
#undef h2v2_merged_upsample_internal
|
||||
@ -145,6 +149,7 @@ typedef my_upsampler * my_upsample_ptr;
|
||||
#define RGB_RED EXT_XBGR_RED
|
||||
#define RGB_GREEN EXT_XBGR_GREEN
|
||||
#define RGB_BLUE EXT_XBGR_BLUE
|
||||
#define RGB_ALPHA 0
|
||||
#define RGB_PIXELSIZE EXT_XBGR_PIXELSIZE
|
||||
#define h2v1_merged_upsample_internal extxbgr_h2v1_merged_upsample_internal
|
||||
#define h2v2_merged_upsample_internal extxbgr_h2v2_merged_upsample_internal
|
||||
@ -152,6 +157,7 @@ typedef my_upsampler * my_upsample_ptr;
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
#undef RGB_BLUE
|
||||
#undef RGB_ALPHA
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef h2v1_merged_upsample_internal
|
||||
#undef h2v2_merged_upsample_internal
|
||||
@ -159,6 +165,7 @@ typedef my_upsampler * my_upsample_ptr;
|
||||
#define RGB_RED EXT_XRGB_RED
|
||||
#define RGB_GREEN EXT_XRGB_GREEN
|
||||
#define RGB_BLUE EXT_XRGB_BLUE
|
||||
#define RGB_ALPHA 0
|
||||
#define RGB_PIXELSIZE EXT_XRGB_PIXELSIZE
|
||||
#define h2v1_merged_upsample_internal extxrgb_h2v1_merged_upsample_internal
|
||||
#define h2v2_merged_upsample_internal extxrgb_h2v2_merged_upsample_internal
|
||||
@ -166,6 +173,7 @@ typedef my_upsampler * my_upsample_ptr;
|
||||
#undef RGB_RED
|
||||
#undef RGB_GREEN
|
||||
#undef RGB_BLUE
|
||||
#undef RGB_ALPHA
|
||||
#undef RGB_PIXELSIZE
|
||||
#undef h2v1_merged_upsample_internal
|
||||
#undef h2v2_merged_upsample_internal
|
||||
|
@ -2,6 +2,7 @@
|
||||
* jdmrgext.c
|
||||
*
|
||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||
* Copyright (C) 2011, D. R. Commander.
|
||||
* This file is part of the Independent JPEG Group's software.
|
||||
* For conditions of distribution and use, see the accompanying README file.
|
||||
*
|
||||
@ -54,11 +55,17 @@ h2v1_merged_upsample_internal (j_decompress_ptr cinfo,
|
||||
outptr[RGB_RED] = range_limit[y + cred];
|
||||
outptr[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr += RGB_PIXELSIZE;
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
outptr[RGB_RED] = range_limit[y + cred];
|
||||
outptr[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr += RGB_PIXELSIZE;
|
||||
}
|
||||
/* If image width is odd, do the last output column separately */
|
||||
@ -72,6 +79,9 @@ h2v1_merged_upsample_internal (j_decompress_ptr cinfo,
|
||||
outptr[RGB_RED] = range_limit[y + cred];
|
||||
outptr[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,21 +130,33 @@ h2v2_merged_upsample_internal (j_decompress_ptr cinfo,
|
||||
outptr0[RGB_RED] = range_limit[y + cred];
|
||||
outptr0[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr0[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr0[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr0 += RGB_PIXELSIZE;
|
||||
y = GETJSAMPLE(*inptr00++);
|
||||
outptr0[RGB_RED] = range_limit[y + cred];
|
||||
outptr0[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr0[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr0[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr0 += RGB_PIXELSIZE;
|
||||
y = GETJSAMPLE(*inptr01++);
|
||||
outptr1[RGB_RED] = range_limit[y + cred];
|
||||
outptr1[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr1[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr1[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr1 += RGB_PIXELSIZE;
|
||||
y = GETJSAMPLE(*inptr01++);
|
||||
outptr1[RGB_RED] = range_limit[y + cred];
|
||||
outptr1[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr1[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr1[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr1 += RGB_PIXELSIZE;
|
||||
}
|
||||
/* If image width is odd, do the last output column separately */
|
||||
@ -148,9 +170,15 @@ h2v2_merged_upsample_internal (j_decompress_ptr cinfo,
|
||||
outptr0[RGB_RED] = range_limit[y + cred];
|
||||
outptr0[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr0[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr0[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
y = GETJSAMPLE(*inptr01);
|
||||
outptr1[RGB_RED] = range_limit[y + cred];
|
||||
outptr1[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr1[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr1[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -322,15 +322,15 @@ const_base:
|
||||
push rsi
|
||||
push rdi
|
||||
sub rsp, SIZEOF_XMMWORD
|
||||
movlpd XMMWORD [rsp], xmm6
|
||||
movaps XMMWORD [rsp], xmm6
|
||||
sub rsp, SIZEOF_XMMWORD
|
||||
movlpd XMMWORD [rsp], xmm7
|
||||
movaps XMMWORD [rsp], xmm7
|
||||
%endmacro
|
||||
|
||||
%imacro uncollect_args 0
|
||||
movlpd xmm7, XMMWORD [rsp]
|
||||
movaps xmm7, XMMWORD [rsp]
|
||||
add rsp, SIZEOF_XMMWORD
|
||||
movlpd xmm6, XMMWORD [rsp]
|
||||
movaps xmm6, XMMWORD [rsp]
|
||||
add rsp, SIZEOF_XMMWORD
|
||||
pop rdi
|
||||
pop rsi
|
||||
|
@ -1,7 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -52,7 +52,8 @@ namespace mozilla {
|
||||
*/
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
class BloomFilter {
|
||||
class BloomFilter
|
||||
{
|
||||
/*
|
||||
* A counting Bloom filter with 8-bit counters. For now we assume
|
||||
* that having two hash functions is enough, but we may revisit that
|
||||
@ -101,7 +102,7 @@ class BloomFilter {
|
||||
* positive rate for N == 100 and to quite bad false positive
|
||||
* rates for larger N.
|
||||
*/
|
||||
public:
|
||||
public:
|
||||
BloomFilter() {
|
||||
MOZ_STATIC_ASSERT(KeySize <= keyShift, "KeySize too big");
|
||||
|
||||
@ -142,7 +143,7 @@ public:
|
||||
void remove(uint32_t hash);
|
||||
bool mightContain(uint32_t hash) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
static const size_t arraySize = (1 << KeySize);
|
||||
static const uint32_t keyMask = (1 << KeySize) - 1;
|
||||
static const uint32_t keyShift = 16;
|
||||
@ -164,67 +165,67 @@ template<unsigned KeySize, class T>
|
||||
inline void
|
||||
BloomFilter<KeySize, T>::clear()
|
||||
{
|
||||
memset(counters, 0, arraySize);
|
||||
memset(counters, 0, arraySize);
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
inline void
|
||||
BloomFilter<KeySize, T>::add(uint32_t hash)
|
||||
{
|
||||
uint8_t& slot1 = firstSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot1)))
|
||||
++slot1;
|
||||
uint8_t& slot1 = firstSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot1)))
|
||||
++slot1;
|
||||
|
||||
uint8_t& slot2 = secondSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot2)))
|
||||
++slot2;
|
||||
uint8_t& slot2 = secondSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot2)))
|
||||
++slot2;
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
MOZ_ALWAYS_INLINE void
|
||||
BloomFilter<KeySize, T>::add(const T* t)
|
||||
{
|
||||
uint32_t hash = t->hash();
|
||||
return add(hash);
|
||||
uint32_t hash = t->hash();
|
||||
return add(hash);
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
inline void
|
||||
BloomFilter<KeySize, T>::remove(uint32_t hash)
|
||||
{
|
||||
// If the slots are full, we don't know whether we bumped them to be
|
||||
// there when we added or not, so just leave them full.
|
||||
uint8_t& slot1 = firstSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot1)))
|
||||
--slot1;
|
||||
// If the slots are full, we don't know whether we bumped them to be
|
||||
// there when we added or not, so just leave them full.
|
||||
uint8_t& slot1 = firstSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot1)))
|
||||
--slot1;
|
||||
|
||||
uint8_t& slot2 = secondSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot2)))
|
||||
--slot2;
|
||||
uint8_t& slot2 = secondSlot(hash);
|
||||
if (MOZ_LIKELY(!full(slot2)))
|
||||
--slot2;
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
MOZ_ALWAYS_INLINE void
|
||||
BloomFilter<KeySize, T>::remove(const T* t)
|
||||
{
|
||||
uint32_t hash = t->hash();
|
||||
remove(hash);
|
||||
uint32_t hash = t->hash();
|
||||
remove(hash);
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
BloomFilter<KeySize, T>::mightContain(uint32_t hash) const
|
||||
{
|
||||
// Check that all the slots for this hash contain something
|
||||
return firstSlot(hash) && secondSlot(hash);
|
||||
// Check that all the slots for this hash contain something
|
||||
return firstSlot(hash) && secondSlot(hash);
|
||||
}
|
||||
|
||||
template<unsigned KeySize, class T>
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
BloomFilter<KeySize, T>::mightContain(const T* t) const
|
||||
{
|
||||
uint32_t hash = t->hash();
|
||||
return mightContain(hash);
|
||||
uint32_t hash = t->hash();
|
||||
return mightContain(hash);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -226,16 +226,6 @@ MOZ_DOUBLE_MIN_VALUE()
|
||||
return pun.d;
|
||||
}
|
||||
|
||||
/** Computes a 32-bit hash of the given double. */
|
||||
static MOZ_ALWAYS_INLINE uint32_t
|
||||
MOZ_HASH_DOUBLE(double d)
|
||||
{
|
||||
union MozDoublePun pun;
|
||||
pun.d = d;
|
||||
|
||||
return ((uint32_t)(pun.u >> 32)) ^ ((uint32_t)(pun.u));
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE int
|
||||
MOZ_DOUBLE_IS_INT32(double d, int32_t* i)
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sw=4 et tw=99 ft=cpp: */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -18,6 +17,7 @@
|
||||
|
||||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
/*
|
||||
* The following classes are designed to cause assertions to detect
|
||||
* inadvertent use of guard objects as temporaries. In other words,
|
||||
@ -25,11 +25,11 @@ namespace detail {
|
||||
* destructor (and is never otherwise referenced), the intended use
|
||||
* might be:
|
||||
*
|
||||
* AutoRestore savePainting(mIsPainting);
|
||||
* AutoRestore savePainting(mIsPainting);
|
||||
*
|
||||
* but is is easy to accidentally write:
|
||||
*
|
||||
* AutoRestore(mIsPainting);
|
||||
* AutoRestore(mIsPainting);
|
||||
*
|
||||
* which compiles just fine, but runs the destructor well before the
|
||||
* intended time.
|
||||
@ -72,14 +72,14 @@ class MOZ_EXPORT_API(GuardObjectNotifier)
|
||||
bool* statementDone;
|
||||
|
||||
public:
|
||||
GuardObjectNotifier() : statementDone(NULL) {}
|
||||
GuardObjectNotifier() : statementDone(NULL) { }
|
||||
|
||||
~GuardObjectNotifier() {
|
||||
*statementDone = true;
|
||||
*statementDone = true;
|
||||
}
|
||||
|
||||
void setStatementDone(bool* statementIsDone) {
|
||||
statementDone = statementIsDone;
|
||||
statementDone = statementIsDone;
|
||||
}
|
||||
};
|
||||
|
||||
@ -89,25 +89,24 @@ class MOZ_EXPORT_API(GuardObjectNotificationReceiver)
|
||||
bool statementDone;
|
||||
|
||||
public:
|
||||
GuardObjectNotificationReceiver() : statementDone(false) {}
|
||||
GuardObjectNotificationReceiver() : statementDone(false) { }
|
||||
|
||||
~GuardObjectNotificationReceiver() {
|
||||
/*
|
||||
* Assert that the guard object was not used as a temporary.
|
||||
* (Note that this assert might also fire if init is not called
|
||||
* because the guard object's implementation is not using the
|
||||
* above macros correctly.)
|
||||
*/
|
||||
MOZ_ASSERT(statementDone);
|
||||
/*
|
||||
* Assert that the guard object was not used as a temporary. (Note that
|
||||
* this assert might also fire if init is not called because the guard
|
||||
* object's implementation is not using the above macros correctly.)
|
||||
*/
|
||||
MOZ_ASSERT(statementDone);
|
||||
}
|
||||
|
||||
void init(const GuardObjectNotifier& constNotifier) {
|
||||
/*
|
||||
* constNotifier is passed as a const reference so that we can pass a
|
||||
* temporary, but we really intend it as non-const.
|
||||
*/
|
||||
GuardObjectNotifier& notifier = const_cast<GuardObjectNotifier&>(constNotifier);
|
||||
notifier.setStatementDone(&statementDone);
|
||||
/*
|
||||
* constNotifier is passed as a const reference so that we can pass a
|
||||
* temporary, but we really intend it as non-const.
|
||||
*/
|
||||
GuardObjectNotifier& notifier = const_cast<GuardObjectNotifier&>(constNotifier);
|
||||
notifier.setStatementDone(&statementDone);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Implementations of hash functions */
|
||||
/* Implementations of hash functions. */
|
||||
|
||||
#include "mozilla/HashFunctions.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace mozilla {
|
||||
@ -29,9 +28,8 @@ HashBytes(const void* bytes, size_t length)
|
||||
}
|
||||
|
||||
/* Get the remaining bytes. */
|
||||
for (; i < length; i++) {
|
||||
for (; i < length; i++)
|
||||
hash = AddToHash(hash, b[i]);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Utilities for hashing */
|
||||
/* Utilities for hashing. */
|
||||
|
||||
/*
|
||||
* This file exports functions for hashing data down to a 32-bit value,
|
||||
@ -26,16 +24,18 @@
|
||||
*
|
||||
* You can chain these functions together to hash complex objects. For example:
|
||||
*
|
||||
* class ComplexObject {
|
||||
* char* str;
|
||||
* uint32_t uint1, uint2;
|
||||
* void (*callbackFn)();
|
||||
* class ComplexObject
|
||||
* {
|
||||
* char* str;
|
||||
* uint32_t uint1, uint2;
|
||||
* void (*callbackFn)();
|
||||
*
|
||||
* uint32_t Hash() {
|
||||
* uint32_t hash = HashString(str);
|
||||
* hash = AddToHash(hash, uint1, uint2);
|
||||
* return AddToHash(hash, callbackFn);
|
||||
* }
|
||||
* public:
|
||||
* uint32_t hash() {
|
||||
* uint32_t hash = HashString(str);
|
||||
* hash = AddToHash(hash, uint1, uint2);
|
||||
* return AddToHash(hash, callbackFn);
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* If you want to hash an nsAString or nsACString, use the HashString functions
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user