Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-06-06 09:20:35 +01:00
commit 31ad3140c9
152 changed files with 4852 additions and 2497 deletions

View File

@ -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"));
}
};

View File

@ -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!");
}

View File

@ -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;
}

View File

@ -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";
}
}
}

View File

@ -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()

View File

@ -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
*/

View File

@ -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);

View File

@ -660,6 +660,8 @@ protected:
nsRefPtr<nsDocShell> mDocShell;
};
bool JustStartedNetworkLoad();
// hash of session storages, keyed by domain
nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorage> mStorages;

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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()
{
}

View File

@ -26,7 +26,6 @@ XPIDLSRCS = \
nsIPluginHost.idl \
nsIPluginInputStream.idl \
nsIPluginInstanceOwner.idl \
nsIPluginStreamInfo.idl \
nsIPluginTag.idl \
nsIPluginTagInfo.idl \
nspluginroot.idl \

View File

@ -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;
};

View File

@ -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;

View File

@ -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.

View File

@ -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_

View File

@ -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"

View File

@ -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);
}

View File

@ -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_

View File

@ -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,

View File

@ -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++) {

View File

@ -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;
})();

View File

@ -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

View File

@ -1,3 +0,0 @@
This folder contains sample applications developed using the Gecko embedding
APIs.

View File

@ -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())) {

View File

@ -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;

View 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);

View File

@ -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 = \

View 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)

View File

@ -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 {

View File

@ -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

View File

@ -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[] = {

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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]);

View File

@ -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;

View File

@ -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();

View File

@ -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;
/*

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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 */ \

View File

@ -12,8 +12,6 @@
* Implementation details for js::Value in jsapi.h.
*/
#include "mozilla/FloatingPoint.h"
#include "js/Utility.h"
JS_BEGIN_EXTERN_C

View File

@ -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))

View File

@ -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();

View File

@ -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 {

View File

@ -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;
}

View File

@ -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');
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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;

View File

@ -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
/*

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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)

View 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"); }
}

View 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>

View File

@ -67,6 +67,7 @@ _TEST_FILES = bug500931_helper.html \
file_nodelists.html \
file_bug706301.html \
file_exnstack.html \
file_expandosharing.html \
$(NULL)
_CHROME_FILES = \

View 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>

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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*

View File

@ -69,7 +69,6 @@ protected:
virtual bool IsInput() { return true; }
private:
nsSize mSuggestedSize;
nsCOMPtr<nsIContent> mTextContent;
};

View File

@ -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;

View File

@ -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);

View File

@ -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));

View File

@ -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

View 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>

View 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>

View File

@ -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

View File

@ -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) ==

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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
}
}

View File

@ -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

View File

@ -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/. */

View File

@ -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/. */

View File

@ -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/. */

View File

@ -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

View File

@ -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)
{

View File

@ -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);
}
};

View File

@ -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;
}

View File

@ -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