Merge inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-09-22 08:28:28 -04:00
commit 4cc66c38b4
97 changed files with 3428 additions and 1765 deletions

4
.gitignore vendored
View File

@ -47,6 +47,6 @@ parser/html/java/javaparser/
.settings/
# Python virtualenv artifacts.
python/psutil/.*.so
python/psutil/.*.pyd
python/psutil/*.so
python/psutil/*.pyd
python/psutil/build/

View File

@ -101,7 +101,7 @@
var gQueue = null;
//gA11yEventDumpID = "eventdump"; // debug stuff
//gA11yEventDumpToConsole = true;
gA11yEventDumpToConsole = true;
function doTests()
{

View File

@ -21,6 +21,8 @@
src="../events.js"></script>
<script type="application/javascript">
gA11yEventDumpToConsole = true; // debug stuff
function doTest()
{
// a@href and its text node

View File

@ -179,6 +179,7 @@ var shell = {
});
this.contentBrowser.src = homeURL;
this.isHomeLoaded = false;
ppmm.addMessageListener("content-handler", this);
},
@ -304,6 +305,18 @@ var shell = {
DOMApplicationRegistry.allAppsLaunchable = true;
this.sendEvent(window, 'ContentStart');
let content = this.contentBrowser.contentWindow;
content.addEventListener('load', function shell_homeLoaded() {
content.removeEventListener('load', shell_homeLoaded);
shell.isHomeLoaded = true;
if ('pendingChromeEvents' in shell) {
shell.pendingChromeEvents.forEach((shell.sendChromeEvent).bind(shell));
}
delete shell.pendingChromeEvents;
});
break;
case 'MozApplicationManifest':
try {
@ -349,6 +362,15 @@ var shell = {
},
sendChromeEvent: function shell_sendChromeEvent(details) {
if (!this.isHomeLoaded) {
if (!('pendingChromeEvents' in this)) {
this.pendingChromeEvents = [];
}
this.pendingChromeEvents.push(details);
return;
}
this.sendEvent(getContentWindow(), "mozChromeEvent",
ObjectWrapper.wrap(details, getContentWindow()));
},

View File

@ -2076,21 +2076,28 @@ function BrowserOpenFileWindow()
{
// Get filepicker component.
try {
const nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(window, gNavigatorBundle.getString("openFile"), nsIFilePicker.modeOpen);
fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText | nsIFilePicker.filterImages |
nsIFilePicker.filterXML | nsIFilePicker.filterHTML);
fp.displayDirectory = gLastOpenDirectory.path;
if (fp.show() == nsIFilePicker.returnOK) {
try {
if (fp.file)
gLastOpenDirectory.path = fp.file.parent.QueryInterface(Ci.nsILocalFile);
} catch(e) {
const nsIFilePicker = Ci.nsIFilePicker;
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult == nsIFilePicker.returnOK) {
try {
if (fp.file) {
gLastOpenDirectory.path =
fp.file.parent.QueryInterface(Ci.nsILocalFile);
}
} catch (ex) {
}
openUILinkIn(fp.fileURL.spec, "current");
}
openUILinkIn(fp.fileURL.spec, "current");
}
};
fp.init(window, gNavigatorBundle.getString("openFile"),
nsIFilePicker.modeOpen);
fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText |
nsIFilePicker.filterImages | nsIFilePicker.filterXML |
nsIFilePicker.filterHTML);
fp.displayDirectory = gLastOpenDirectory.path;
fp.open(fpCallback);
} catch (ex) {
}
}

View File

@ -112,15 +112,22 @@ const nsIFilePicker = Components.interfaces.nsIFilePicker;
function onChooseFile()
{
try {
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(window, dialog.bundle.getString("chooseFileDialogTitle"), nsIFilePicker.modeOpen);
fp.appendFilters(nsIFilePicker.filterHTML | nsIFilePicker.filterText |
nsIFilePicker.filterAll | nsIFilePicker.filterImages | nsIFilePicker.filterXML);
let fp = Components.classes["@mozilla.org/filepicker;1"].
createInstance(nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult == nsIFilePicker.returnOK && fp.fileURL.spec &&
fp.fileURL.spec.length > 0) {
dialog.input.value = fp.fileURL.spec;
}
doEnabling();
};
if (fp.show() == nsIFilePicker.returnOK && fp.fileURL.spec && fp.fileURL.spec.length > 0)
dialog.input.value = fp.fileURL.spec;
fp.init(window, dialog.bundle.getString("chooseFileDialogTitle"),
nsIFilePicker.modeOpen);
fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText |
nsIFilePicker.filterImages | nsIFilePicker.filterXML |
nsIFilePicker.filterHTML);
fp.open(fpCallback);
} catch (ex) {
}
catch(ex) {
}
doEnabling();
}

View File

@ -761,31 +761,33 @@ function getSelectedRow(tree)
return (rows.length == 1) ? rows[0] : -1;
}
function selectSaveFolder()
function selectSaveFolder(aCallback)
{
const nsILocalFile = Components.interfaces.nsILocalFile;
const nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["@mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
let titleText = gBundle.getString("mediaSelectFolder");
let fp = Components.classes["@mozilla.org/filepicker;1"].
createInstance(nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult == nsIFilePicker.returnOK) {
aCallback(fp.file.QueryInterface(nsILocalFile));
} else {
aCallback(null);
}
};
var titleText = gBundle.getString("mediaSelectFolder");
fp.init(window, titleText, nsIFilePicker.modeGetFolder);
try {
var prefs = Components.classes[PREFERENCES_CONTRACTID]
.getService(Components.interfaces.nsIPrefBranch);
var initialDir = prefs.getComplexValue("browser.download.dir", nsILocalFile);
if (initialDir)
fp.displayDirectory = initialDir;
}
catch (ex) { }
fp.appendFilters(nsIFilePicker.filterAll);
var ret = fp.show();
if (ret == nsIFilePicker.returnOK)
return fp.file.QueryInterface(nsILocalFile);
return null;
try {
let prefs = Components.classes[PREFERENCES_CONTRACTID].
getService(Components.interfaces.nsIPrefBranch);
let initialDir = prefs.getComplexValue("browser.download.dir", nsILocalFile);
if (initialDir) {
fp.displayDirectory = initialDir;
}
} catch (ex) {
}
fp.open(fpCallback);
}
function saveMedia()
@ -807,37 +809,39 @@ function saveMedia()
saveURL(url, null, titleKey, false, false, makeURI(item.baseURI));
}
}
else {
var odir = selectSaveFolder();
var saveAnImage = function(aURIString, aChosenData, aBaseURI) {
internalSave(aURIString, null, null, null, null, false, "SaveImageTitle",
aChosenData, aBaseURI);
}
for (var i = 0; i < rowArray.length; i++) {
var v = rowArray[i];
var dir = odir.clone();
var item = gImageView.data[v][COL_IMAGE_NODE];
var uriString = gImageView.data[v][COL_IMAGE_ADDRESS];
var uri = makeURI(uriString);
try {
uri.QueryInterface(Components.interfaces.nsIURL);
dir.append(decodeURIComponent(uri.fileName));
} else {
selectSaveFolder(function(aDirectory) {
if (aDirectory) {
var saveAnImage = function(aURIString, aChosenData, aBaseURI) {
internalSave(aURIString, null, null, null, null, false, "SaveImageTitle",
aChosenData, aBaseURI);
};
for (var i = 0; i < rowArray.length; i++) {
var v = rowArray[i];
var dir = aDirectory.clone();
var item = gImageView.data[v][COL_IMAGE_NODE];
var uriString = gImageView.data[v][COL_IMAGE_ADDRESS];
var uri = makeURI(uriString);
try {
uri.QueryInterface(Components.interfaces.nsIURL);
dir.append(decodeURIComponent(uri.fileName));
} catch(ex) {
/* data: uris */
}
if (i == 0) {
saveAnImage(uriString, new AutoChosen(dir, uri), makeURI(item.baseURI));
} else {
// This delay is a hack which prevents the download manager
// from opening many times. See bug 377339.
setTimeout(saveAnImage, 200, uriString, new AutoChosen(dir, uri),
makeURI(item.baseURI));
}
}
}
catch(ex) { /* data: uris */ }
if (i == 0)
saveAnImage(uriString, new AutoChosen(dir, uri), makeURI(item.baseURI));
else {
// This delay is a hack which prevents the download manager
// from opening many times. See bug 377339.
setTimeout(saveAnImage, 200, uriString, new AutoChosen(dir, uri),
makeURI(item.baseURI));
}
}
});
}
}

View File

@ -151,26 +151,28 @@ let gSyncUtils = {
let dialogTitle = this.bundle.GetStringFromName("save.recoverykey.title");
let defaultSaveName = this.bundle.GetStringFromName("save.recoverykey.defaultfilename");
this._preparePPiframe(elid, function(iframe) {
let filepicker = Cc["@mozilla.org/filepicker;1"]
.createInstance(Ci.nsIFilePicker);
filepicker.init(window, dialogTitle, Ci.nsIFilePicker.modeSave);
filepicker.appendFilters(Ci.nsIFilePicker.filterHTML);
filepicker.defaultString = defaultSaveName;
let rv = filepicker.show();
if (rv == Ci.nsIFilePicker.returnOK
|| rv == Ci.nsIFilePicker.returnReplace) {
let stream = Cc["@mozilla.org/network/file-output-stream;1"]
.createInstance(Ci.nsIFileOutputStream);
stream.init(filepicker.file, -1, 0600, 0);
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult == Ci.nsIFilePicker.returnOK ||
aResult == Ci.nsIFilePicker.returnReplace) {
let stream = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
stream.init(fp.file, -1, 0600, 0);
let serializer = new XMLSerializer();
let output = serializer.serializeToString(iframe.contentDocument);
output = output.replace(/<!DOCTYPE (.|\n)*?]>/,
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' +
'"DTD/xhtml1-strict.dtd">');
output = Weave.Utils.encodeUTF8(output);
stream.write(output, output.length);
}
let serializer = new XMLSerializer();
let output = serializer.serializeToString(iframe.contentDocument);
output = output.replace(/<!DOCTYPE (.|\n)*?]>/,
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' +
'"DTD/xhtml1-strict.dtd">');
output = Weave.Utils.encodeUTF8(output);
stream.write(output, output.length);
}
};
fp.init(window, dialogTitle, Ci.nsIFilePicker.modeSave);
fp.appendFilters(Ci.nsIFilePicker.filterHTML);
fp.defaultString = defaultSaveName;
fp.open(fpCallback);
return false;
});
},

View File

@ -836,6 +836,9 @@
if (this.mCurrentBrowser == newBrowser && !aForceUpdate)
return;
if (!aForceUpdate)
TelemetryStopwatch.start("FX_TAB_SWITCH_UPDATE_MS");
var oldTab = this.mCurrentTab;
// Preview mode should not reset the owner
@ -1015,6 +1018,9 @@
fm.setFocus(newBrowser, focusFlags);
} while (false);
}
if (!aForceUpdate)
TelemetryStopwatch.finish("FX_TAB_SWITCH_UPDATE_MS");
]]>
</body>
</method>

View File

@ -182,12 +182,16 @@
if (domain[0] != "[") {
try {
baseDomain = Services.eTLD.getBaseDomainFromHost(domain);
if (!domain.contains(baseDomain)) {
// getBaseDomainFromHost converts its resultant to ACE.
let IDNService = Cc["@mozilla.org/network/idn-service;1"]
.getService(Ci.nsIIDNService);
baseDomain = IDNService.convertACEtoUTF8(baseDomain);
}
} catch (e) {}
}
if (baseDomain != domain) {
let segments = function (s) s.replace(/[^.]*/g, "").length + 1;
let subSegments = segments(domain) - segments(baseDomain);
subDomain = domain.match(new RegExp("(?:[^.]*\.){" + subSegments + "}"))[0];
subDomain = domain.slice(0, -baseDomain.length);
}
let rangeLength = preDomain.length + subDomain.length;

View File

@ -708,46 +708,53 @@ FeedWriter.prototype = {
/**
* Displays a prompt from which the user may choose a (client) feed reader.
* @return - true if a feed reader was selected, false otherwise.
* @param aCallback the callback method, passes in true if a feed reader was
* selected, false otherwise.
*/
_chooseClientApp: function FW__chooseClientApp() {
_chooseClientApp: function FW__chooseClientApp(aCallback) {
try {
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(this._window,
this._getString("chooseApplicationDialogTitle"),
Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterApps);
if (fp.show() == Ci.nsIFilePicker.returnOK) {
this._selectedApp = fp.file;
if (this._selectedApp) {
// XXXben - we need to compare this with the running instance executable
// just don't know how to do that via script...
// XXXmano TBD: can probably add this to nsIShellService
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult == Ci.nsIFilePicker.returnOK) {
this._selectedApp = fp.file;
if (this._selectedApp) {
// XXXben - we need to compare this with the running instance
// executable just don't know how to do that via script
// XXXmano TBD: can probably add this to nsIShellService
#ifdef XP_WIN
#expand if (fp.file.leafName != "__MOZ_APP_NAME__.exe") {
#expand if (fp.file.leafName != "__MOZ_APP_NAME__.exe") {
#else
#ifdef XP_MACOSX
#expand if (fp.file.leafName != "__MOZ_MACBUNDLE_NAME__") {
#expand if (fp.file.leafName != "__MOZ_MACBUNDLE_NAME__") {
#else
#expand if (fp.file.leafName != "__MOZ_APP_NAME__-bin") {
#expand if (fp.file.leafName != "__MOZ_APP_NAME__-bin") {
#endif
#endif
this._initMenuItemWithFile(this._contentSandbox.selectedAppMenuItem,
this._selectedApp);
this._initMenuItemWithFile(this._contentSandbox.selectedAppMenuItem,
this._selectedApp);
// Show and select the selected application menuitem
var codeStr = "selectedAppMenuItem.hidden = false;" +
"selectedAppMenuItem.doCommand();"
Cu.evalInSandbox(codeStr, this._contentSandbox);
return true;
// Show and select the selected application menuitem
let codeStr = "selectedAppMenuItem.hidden = false;" +
"selectedAppMenuItem.doCommand();"
Cu.evalInSandbox(codeStr, this._contentSandbox);
if (aCallback) {
aCallback(true);
return;
}
}
}
}
}
}
catch(ex) { }
if (aCallback) {
aCallback(false);
}
}.bind(this);
return false;
fp.init(this._window, this._getString("chooseApplicationDialogTitle"),
Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterApps);
fp.open(fpCallback);
} catch(ex) {
}
},
_setAlwaysUseCheckedState: function FW__setAlwaysUseCheckedState(feedType) {
@ -833,10 +840,14 @@ FeedWriter.prototype = {
*/
var popupbox = this._handlersMenuList.firstChild.boxObject;
popupbox.QueryInterface(Components.interfaces.nsIPopupBoxObject);
if (popupbox.popupState == "hiding" && !this._chooseClientApp()) {
// Select the (per-prefs) selected handler if no application was
// selected
this._setSelectedHandler(this._getFeedType());
if (popupbox.popupState == "hiding") {
this._chooseClientApp(function(aResult) {
if (!aResult) {
// Select the (per-prefs) selected handler if no application
// was selected
this._setSelectedHandler(this._getFeedType());
}
}.bind(this));
}
break;
default:
@ -1210,70 +1221,77 @@ FeedWriter.prototype = {
var useAsDefault = this._getUIElement("alwaysUse").getAttribute("checked");
var selectedItem = this._getSelectedItemFromMenulist(this._handlersMenuList);
let subscribeCallback = function() {
if (selectedItem.hasAttribute("webhandlerurl")) {
var webURI = selectedItem.getAttribute("webhandlerurl");
prefs.setCharPref(getPrefReaderForType(feedType), "web");
var supportsString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
supportsString.data = webURI;
prefs.setComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString,
supportsString);
var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentConverterService);
var handler = wccr.getWebContentHandlerByURI(this._getMimeTypeForFeedType(feedType), webURI);
if (handler) {
if (useAsDefault) {
wccr.setAutoHandler(this._getMimeTypeForFeedType(feedType), handler);
}
this._window.location.href = handler.getHandlerURI(this._window.location.href);
}
} else {
switch (selectedItem.getAttribute("anonid")) {
case "selectedAppMenuItem":
prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile,
this._selectedApp);
prefs.setCharPref(getPrefReaderForType(feedType), "client");
break;
case "defaultHandlerMenuItem":
prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile,
this._defaultSystemReader);
prefs.setCharPref(getPrefReaderForType(feedType), "client");
break;
case "liveBookmarksMenuItem":
defaultHandler = "bookmarks";
prefs.setCharPref(getPrefReaderForType(feedType), "bookmarks");
break;
}
var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
getService(Ci.nsIFeedResultService);
// Pull the title and subtitle out of the document
var feedTitle = this._document.getElementById(TITLE_ID).textContent;
var feedSubtitle = this._document.getElementById(SUBTITLE_ID).textContent;
feedService.addToClientReader(this._window.location.href, feedTitle, feedSubtitle, feedType);
}
// If "Always use..." is checked, we should set PREF_*SELECTED_ACTION
// to either "reader" (If a web reader or if an application is selected),
// or to "bookmarks" (if the live bookmarks option is selected).
// Otherwise, we should set it to "ask"
if (useAsDefault) {
prefs.setCharPref(getPrefActionForType(feedType), defaultHandler);
} else {
prefs.setCharPref(getPrefActionForType(feedType), "ask");
}
}.bind(this);
// Show the file picker before subscribing if the
// choose application menuitem was chosen using the keyboard
if (selectedItem.getAttribute("anonid") == "chooseApplicationMenuItem") {
if (!this._chooseClientApp())
return;
selectedItem = this._getSelectedItemFromMenulist(this._handlersMenuList);
this._chooseClientApp(function(aResult) {
if (aResult) {
selectedItem =
this._getSelectedItemFromMenulist(this._handlersMenuList);
subscribeCallback();
}
}.bind(this));
} else {
subscribeCallback();
}
if (selectedItem.hasAttribute("webhandlerurl")) {
var webURI = selectedItem.getAttribute("webhandlerurl");
prefs.setCharPref(getPrefReaderForType(feedType), "web");
var supportsString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
supportsString.data = webURI;
prefs.setComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString,
supportsString);
var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentConverterService);
var handler = wccr.getWebContentHandlerByURI(this._getMimeTypeForFeedType(feedType), webURI);
if (handler) {
if (useAsDefault)
wccr.setAutoHandler(this._getMimeTypeForFeedType(feedType), handler);
this._window.location.href = handler.getHandlerURI(this._window.location.href);
}
}
else {
switch (selectedItem.getAttribute("anonid")) {
case "selectedAppMenuItem":
prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile,
this._selectedApp);
prefs.setCharPref(getPrefReaderForType(feedType), "client");
break;
case "defaultHandlerMenuItem":
prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile,
this._defaultSystemReader);
prefs.setCharPref(getPrefReaderForType(feedType), "client");
break;
case "liveBookmarksMenuItem":
defaultHandler = "bookmarks";
prefs.setCharPref(getPrefReaderForType(feedType), "bookmarks");
break;
}
var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
getService(Ci.nsIFeedResultService);
// Pull the title and subtitle out of the document
var feedTitle = this._document.getElementById(TITLE_ID).textContent;
var feedSubtitle = this._document.getElementById(SUBTITLE_ID).textContent;
feedService.addToClientReader(this._window.location.href, feedTitle, feedSubtitle, feedType);
}
// If "Always use..." is checked, we should set PREF_*SELECTED_ACTION
// to either "reader" (If a web reader or if an application is selected),
// or to "bookmarks" (if the live bookmarks option is selected).
// Otherwise, we should set it to "ask"
if (useAsDefault)
prefs.setCharPref(getPrefActionForType(feedType), defaultHandler);
else
prefs.setCharPref(getPrefActionForType(feedType), "ask");
},
// nsIObserver

View File

@ -354,34 +354,39 @@ var PlacesOrganizer = {
* Open a file-picker and import the selected file into the bookmarks store
*/
importFromFile: function PO_importFromFile() {
var fp = Cc["@mozilla.org/filepicker;1"].
createInstance(Ci.nsIFilePicker);
fp.init(window, PlacesUIUtils.getString("SelectImport"),
Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterHTML);
if (fp.show() != Ci.nsIFilePicker.returnCancel) {
if (fp.fileURL) {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult != Ci.nsIFilePicker.returnCancel && fp.fileURL) {
Components.utils.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
BookmarkHTMLUtils.importFromURL(fp.fileURL.spec, false);
}
}
};
fp.init(window, PlacesUIUtils.getString("SelectImport"),
Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterHTML);
fp.open(fpCallback);
},
/**
* Allows simple exporting of bookmarks.
*/
exportBookmarks: function PO_exportBookmarks() {
var fp = Cc["@mozilla.org/filepicker;1"].
createInstance(Ci.nsIFilePicker);
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult != Ci.nsIFilePicker.returnCancel) {
let exporter =
Cc["@mozilla.org/browser/places/import-export-service;1"].
getService(Ci.nsIPlacesImportExportService);
exporter.exportHTMLToFile(fp.file);
}
};
fp.init(window, PlacesUIUtils.getString("EnterExport"),
Ci.nsIFilePicker.modeSave);
fp.appendFilters(Ci.nsIFilePicker.filterHTML);
fp.defaultString = "bookmarks.html";
if (fp.show() != Ci.nsIFilePicker.returnCancel) {
var exporter = Cc["@mozilla.org/browser/places/import-export-service;1"].
getService(Ci.nsIPlacesImportExportService);
exporter.exportHTMLToFile(fp.file);
}
fp.open(fpCallback);
},
/**
@ -441,20 +446,23 @@ var PlacesOrganizer = {
* Prompts for a file and restores bookmarks to those in the file.
*/
onRestoreBookmarksFromFile: function PO_onRestoreBookmarksFromFile() {
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
let backupsDir = dirSvc.get("Desk", Ci.nsILocalFile);
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult != Ci.nsIFilePicker.returnCancel) {
this.restoreBookmarksFromFile(fp.file);
}
}.bind(this);
fp.init(window, PlacesUIUtils.getString("bookmarksRestoreTitle"),
Ci.nsIFilePicker.modeOpen);
fp.appendFilter(PlacesUIUtils.getString("bookmarksRestoreFilterName"),
PlacesUIUtils.getString("bookmarksRestoreFilterExtension"));
fp.appendFilters(Ci.nsIFilePicker.filterAll);
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
var backupsDir = dirSvc.get("Desk", Ci.nsILocalFile);
fp.displayDirectory = backupsDir;
if (fp.show() != Ci.nsIFilePicker.returnCancel)
this.restoreBookmarksFromFile(fp.file);
fp.open(fpCallback);
},
/**
@ -498,21 +506,23 @@ var PlacesOrganizer = {
* of those items.
*/
backupBookmarks: function PO_backupBookmarks() {
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
let backupsDir = dirSvc.get("Desk", Ci.nsILocalFile);
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult != Ci.nsIFilePicker.returnCancel) {
PlacesUtils.backups.saveBookmarksToJSONFile(fp.file);
}
};
fp.init(window, PlacesUIUtils.getString("bookmarksBackupTitle"),
Ci.nsIFilePicker.modeSave);
fp.appendFilter(PlacesUIUtils.getString("bookmarksRestoreFilterName"),
PlacesUIUtils.getString("bookmarksRestoreFilterExtension"));
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
var backupsDir = dirSvc.get("Desk", Ci.nsILocalFile);
fp.displayDirectory = backupsDir;
fp.defaultString = PlacesUtils.backups.getFilenameForDate();
if (fp.show() != Ci.nsIFilePicker.returnCancel)
PlacesUtils.backups.saveBookmarksToJSONFile(fp.file);
fp.displayDirectory = backupsDir;
fp.open(fpCallback);
},
_paneDisabled: false,

View File

@ -1715,6 +1715,28 @@ var gApplicationsPane = {
aEvent.stopPropagation();
var handlerApp;
let chooseAppCallback = function(aHandlerApp) {
// Rebuild the actions menu whether the user picked an app or canceled.
// If they picked an app, we want to add the app to the menu and select it.
// If they canceled, we want to go back to their previous selection.
this.rebuildActionsMenu();
// If the user picked a new app from the menu, select it.
if (aHandlerApp) {
let typeItem = this._list.selectedItem;
let actionsMenu =
document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
let menuItems = actionsMenu.menupopup.childNodes;
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i];
if (menuItem.handlerApp && menuItem.handlerApp.equals(aHandlerApp)) {
actionsMenu.selectedIndex = i;
this.onSelectAction(menuItem);
break;
}
}
}
}.bind(this);
#ifdef XP_WIN
var params = {};
@ -1743,47 +1765,33 @@ var gApplicationsPane = {
// Add the app to the type's list of possible handlers.
handlerInfo.addPossibleApplicationHandler(handlerApp);
}
chooseAppCallback(handlerApp);
#else
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
var winTitle = this._prefsBundle.getString("fpTitleChooseApp");
fp.init(window, winTitle, Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterApps);
let winTitle = this._prefsBundle.getString("fpTitleChooseApp");
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult == Ci.nsIFilePicker.returnOK && fp.file &&
this._isValidHandlerExecutable(fp.file)) {
handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
createInstance(Ci.nsILocalHandlerApp);
handlerApp.name = getFileDisplayName(fp.file);
handlerApp.executable = fp.file;
// Add the app to the type's list of possible handlers.
let handlerInfo = this._handledTypes[this._list.selectedItem.type];
handlerInfo.addPossibleApplicationHandler(handlerApp);
chooseAppCallback(handlerApp);
}
}.bind(this);
// Prompt the user to pick an app. If they pick one, and it's a valid
// selection, then add it to the list of possible handlers.
if (fp.show() == Ci.nsIFilePicker.returnOK && fp.file &&
this._isValidHandlerExecutable(fp.file)) {
handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
createInstance(Ci.nsILocalHandlerApp);
handlerApp.name = getFileDisplayName(fp.file);
handlerApp.executable = fp.file;
// Add the app to the type's list of possible handlers.
let handlerInfo = this._handledTypes[this._list.selectedItem.type];
handlerInfo.addPossibleApplicationHandler(handlerApp);
}
fp.init(window, winTitle, Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterApps);
fp.open(fpCallback);
#endif
// Rebuild the actions menu whether the user picked an app or canceled.
// If they picked an app, we want to add the app to the menu and select it.
// If they canceled, we want to go back to their previous selection.
this.rebuildActionsMenu();
// If the user picked a new app from the menu, select it.
if (handlerApp) {
let typeItem = this._list.selectedItem;
let actionsMenu =
document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
let menuItems = actionsMenu.menupopup.childNodes;
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i];
if (menuItem.handlerApp && menuItem.handlerApp.equals(handlerApp)) {
actionsMenu.selectedIndex = i;
this.onSelectAction(menuItem);
break;
}
}
}
},
// Mark which item in the list was last selected so we can reselect it

View File

@ -1702,6 +1702,28 @@ var gApplicationsPane = {
aEvent.stopPropagation();
var handlerApp;
let chooseAppCallback = function(aHandlerApp) {
// Rebuild the actions menu whether the user picked an app or canceled.
// If they picked an app, we want to add the app to the menu and select it.
// If they canceled, we want to go back to their previous selection.
this.rebuildActionsMenu();
// If the user picked a new app from the menu, select it.
if (aHandlerApp) {
let typeItem = this._list.selectedItem;
let actionsMenu =
document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
let menuItems = actionsMenu.menupopup.childNodes;
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i];
if (menuItem.handlerApp && menuItem.handlerApp.equals(aHandlerApp)) {
actionsMenu.selectedIndex = i;
this.onSelectAction(menuItem);
break;
}
}
}
}.bind(this);
#ifdef XP_WIN
var params = {};
@ -1730,47 +1752,33 @@ var gApplicationsPane = {
// Add the app to the type's list of possible handlers.
handlerInfo.addPossibleApplicationHandler(handlerApp);
}
chooseAppCallback(handlerApp);
#else
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
var winTitle = this._prefsBundle.getString("fpTitleChooseApp");
fp.init(window, winTitle, Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterApps);
let winTitle = this._prefsBundle.getString("fpTitleChooseApp");
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult == Ci.nsIFilePicker.returnOK && fp.file &&
this._isValidHandlerExecutable(fp.file)) {
handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
createInstance(Ci.nsILocalHandlerApp);
handlerApp.name = getFileDisplayName(fp.file);
handlerApp.executable = fp.file;
// Add the app to the type's list of possible handlers.
let handlerInfo = this._handledTypes[this._list.selectedItem.type];
handlerInfo.addPossibleApplicationHandler(handlerApp);
chooseAppCallback(handlerApp);
}
}.bind(this);
// Prompt the user to pick an app. If they pick one, and it's a valid
// selection, then add it to the list of possible handlers.
if (fp.show() == Ci.nsIFilePicker.returnOK && fp.file &&
this._isValidHandlerExecutable(fp.file)) {
handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
createInstance(Ci.nsILocalHandlerApp);
handlerApp.name = getFileDisplayName(fp.file);
handlerApp.executable = fp.file;
// Add the app to the type's list of possible handlers.
let handlerInfo = this._handledTypes[this._list.selectedItem.type];
handlerInfo.addPossibleApplicationHandler(handlerApp);
}
fp.init(window, winTitle, Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterApps);
fp.open(fpCallback);
#endif
// Rebuild the actions menu whether the user picked an app or canceled.
// If they picked an app, we want to add the app to the menu and select it.
// If they canceled, we want to go back to their previous selection.
this.rebuildActionsMenu();
// If the user picked a new app from the menu, select it.
if (handlerApp) {
let typeItem = this._list.selectedItem;
let actionsMenu =
document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
let menuItems = actionsMenu.menupopup.childNodes;
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i];
if (menuItem.handlerApp && menuItem.handlerApp.equals(handlerApp)) {
actionsMenu.selectedIndex = i;
this.onSelectAction(menuItem);
break;
}
}
}
},
// Mark which item in the list was last selected so we can reselect it

View File

@ -258,17 +258,29 @@ var gMainPane = {
const nsIFilePicker = Components.interfaces.nsIFilePicker;
const nsILocalFile = Components.interfaces.nsILocalFile;
var fp = Components.classes["@mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
var bundlePreferences = document.getElementById("bundlePreferences");
var title = bundlePreferences.getString("chooseDownloadFolderTitle");
let bundlePreferences = document.getElementById("bundlePreferences");
let title = bundlePreferences.getString("chooseDownloadFolderTitle");
let folderListPref = document.getElementById("browser.download.folderList");
let currentDirPref = this._indexToFolder(folderListPref.value); // file
let defDownloads = this._indexToFolder(1); // file
let fp = Components.classes["@mozilla.org/filepicker;1"].
createInstance(nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult == nsIFilePicker.returnOK) {
let file = fp.file.QueryInterface(nsILocalFile);
let downloadDirPref = document.getElementById("browser.download.dir");
downloadDirPref.value = file;
folderListPref.value = this._folderToIndex(file);
// Note, the real prefs will not be updated yet, so dnld manager's
// userDownloadsDirectory may not return the right folder after
// this code executes. displayDownloadDirPref will be called on
// the assignment above to update the UI.
}
}.bind(this);
fp.init(window, title, nsIFilePicker.modeGetFolder);
fp.appendFilters(nsIFilePicker.filterAll);
var folderListPref = document.getElementById("browser.download.folderList");
var currentDirPref = this._indexToFolder(folderListPref.value); // file
var defDownloads = this._indexToFolder(1); // file
// First try to open what's currently configured
if (currentDirPref && currentDirPref.exists()) {
fp.displayDirectory = currentDirPref;
@ -279,18 +291,7 @@ var gMainPane = {
else {
fp.displayDirectory = this._indexToFolder(0);
}
if (fp.show() == nsIFilePicker.returnOK) {
var file = fp.file.QueryInterface(nsILocalFile);
var currentDirPref = document.getElementById("browser.download.dir");
currentDirPref.value = file;
var folderListPref = document.getElementById("browser.download.folderList");
folderListPref.value = this._folderToIndex(file);
// Note, the real prefs will not be updated yet, so dnld manager's
// userDownloadsDirectory may not return the right folder after
// this code executes. displayDownloadDirPref will be called on
// the assignment above to update the UI.
}
fp.open(fpCallback);
},
/**

View File

@ -255,17 +255,29 @@ var gMainPane = {
const nsIFilePicker = Components.interfaces.nsIFilePicker;
const nsILocalFile = Components.interfaces.nsILocalFile;
var fp = Components.classes["@mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
var bundlePreferences = document.getElementById("bundlePreferences");
var title = bundlePreferences.getString("chooseDownloadFolderTitle");
let bundlePreferences = document.getElementById("bundlePreferences");
let title = bundlePreferences.getString("chooseDownloadFolderTitle");
let folderListPref = document.getElementById("browser.download.folderList");
let currentDirPref = this._indexToFolder(folderListPref.value); // file
let defDownloads = this._indexToFolder(1); // file
let fp = Components.classes["@mozilla.org/filepicker;1"].
createInstance(nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult == nsIFilePicker.returnOK) {
let file = fp.file.QueryInterface(nsILocalFile);
let downloadDirPref = document.getElementById("browser.download.dir");
downloadDirPref.value = file;
folderListPref.value = this._folderToIndex(file);
// Note, the real prefs will not be updated yet, so dnld manager's
// userDownloadsDirectory may not return the right folder after
// this code executes. displayDownloadDirPref will be called on
// the assignment above to update the UI.
}
}.bind(this);
fp.init(window, title, nsIFilePicker.modeGetFolder);
fp.appendFilters(nsIFilePicker.filterAll);
var folderListPref = document.getElementById("browser.download.folderList");
var currentDirPref = this._indexToFolder(folderListPref.value); // file
var defDownloads = this._indexToFolder(1); // file
// First try to open what's currently configured
if (currentDirPref && currentDirPref.exists()) {
fp.displayDirectory = currentDirPref;
@ -276,18 +288,7 @@ var gMainPane = {
else {
fp.displayDirectory = this._indexToFolder(0);
}
if (fp.show() == nsIFilePicker.returnOK) {
var file = fp.file.QueryInterface(nsILocalFile);
var currentDirPref = document.getElementById("browser.download.dir");
currentDirPref.value = file;
var folderListPref = document.getElementById("browser.download.folderList");
folderListPref.value = this._folderToIndex(file);
// Note, the real prefs will not be updated yet, so dnld manager's
// userDownloadsDirectory may not return the right folder after
// this code executes. displayDownloadDirPref will be called on
// the assignment above to update the UI.
}
fp.open(fpCallback);
},
/**

View File

@ -668,15 +668,7 @@ var Scratchpad = {
*/
openFile: function SP_openFile(aIndex)
{
let fp;
if (!aIndex && aIndex !== 0) {
fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, this.strings.GetStringFromName("openFile.title"),
Ci.nsIFilePicker.modeOpen);
fp.defaultString = "";
}
if (aIndex > -1 || fp.show() != Ci.nsIFilePicker.returnCancel) {
let promptCallback = function(aFile) {
this.promptSave(function(aCloseFile, aSaved, aStatus) {
let shouldOpen = aCloseFile;
if (aSaved && !Components.isSuccessCode(aStatus)) {
@ -687,8 +679,8 @@ var Scratchpad = {
this._skipClosePrompt = true;
let file;
if (fp) {
file = fp.file;
if (aFile) {
file = aFile;
} else {
file = Components.classes["@mozilla.org/file/local;1"].
createInstance(Components.interfaces.nsILocalFile);
@ -701,6 +693,22 @@ var Scratchpad = {
this.setRecentFile(file);
}
}.bind(this));
}.bind(this);
if (aIndex > -1) {
promptCallback();
} else {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult != Ci.nsIFilePicker.returnCancel) {
promptCallback(fp.file);
}
};
fp.init(window, this.strings.GetStringFromName("openFile.title"),
Ci.nsIFilePicker.modeOpen);
fp.defaultString = "";
fp.open(fpCallback);
}
},
@ -894,22 +902,25 @@ var Scratchpad = {
saveFileAs: function SP_saveFileAs(aCallback)
{
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let fpCallback = function fpCallback_done(aResult) {
if (aResult != Ci.nsIFilePicker.returnCancel) {
this.setFilename(fp.file.path);
this.exportToFile(fp.file, true, false, function(aStatus) {
if (Components.isSuccessCode(aStatus)) {
this.editor.dirty = false;
this.setRecentFile(fp.file);
}
if (aCallback) {
aCallback(aStatus);
}
});
}
}.bind(this);
fp.init(window, this.strings.GetStringFromName("saveFileAs"),
Ci.nsIFilePicker.modeSave);
fp.defaultString = "scratchpad.js";
if (fp.show() != Ci.nsIFilePicker.returnCancel) {
this.setFilename(fp.file.path);
this.exportToFile(fp.file, true, false, function(aStatus) {
if (Components.isSuccessCode(aStatus)) {
this.editor.dirty = false;
this.setRecentFile(fp.file);
}
if (aCallback) {
aCallback(aStatus);
}
});
}
fp.open(fpCallback);
},
/**

View File

@ -288,22 +288,24 @@ StyleEditor.prototype = {
*/
importFromFile: function SE_importFromFile(aFile, aParentWindow)
{
aFile = this._showFilePicker(aFile, false, aParentWindow);
if (!aFile) {
return;
}
this._savedFile = aFile; // remember filename for next save if any
let callback = function(aFile) {
if (aFile) {
this._savedFile = aFile; // remember filename for next save if any
NetUtil.asyncFetch(aFile, function onAsyncFetch(aStream, aStatus) {
if (!Components.isSuccessCode(aStatus)) {
return this._signalError(LOAD_ERROR);
NetUtil.asyncFetch(aFile, function onAsyncFetch(aStream, aStatus) {
if (!Components.isSuccessCode(aStatus)) {
return this._signalError(LOAD_ERROR);
}
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
aStream.close();
this._appendNewStyleSheet(source);
this.clearFlag(StyleEditorFlags.ERROR);
}.bind(this));
}
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
aStream.close();
}.bind(this);
this._appendNewStyleSheet(source);
this.clearFlag(StyleEditorFlags.ERROR);
}.bind(this));
this._showFilePicker(aFile, false, aParentWindow, callback);
},
/**
@ -553,46 +555,48 @@ StyleEditor.prototype = {
*/
saveToFile: function SE_saveToFile(aFile, aCallback)
{
aFile = this._showFilePicker(aFile || this._styleSheetFilePath, true);
if (!aFile) {
if (aCallback) {
aCallback(null);
}
return;
}
if (this._sourceEditor) {
this._state.text = this._sourceEditor.getText();
}
let ostream = FileUtils.openSafeFileOutputStream(aFile);
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let istream = converter.convertToInputStream(this._state.text);
NetUtil.asyncCopy(istream, ostream, function SE_onStreamCopied(status) {
if (!Components.isSuccessCode(status)) {
let callback = function(aReturnFile) {
if (!aReturnFile) {
if (aCallback) {
aCallback(null);
}
this._signalError(SAVE_ERROR);
return;
}
FileUtils.closeSafeFileOutputStream(ostream);
// remember filename for next save if any
this._friendlyName = null;
this._savedFile = aFile;
this._persistExpando();
if (aCallback) {
aCallback(aFile);
if (this._sourceEditor) {
this._state.text = this._sourceEditor.getText();
}
this.clearFlag(StyleEditorFlags.UNSAVED);
this.clearFlag(StyleEditorFlags.ERROR);
}.bind(this));
let ostream = FileUtils.openSafeFileOutputStream(aReturnFile);
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let istream = converter.convertToInputStream(this._state.text);
NetUtil.asyncCopy(istream, ostream, function SE_onStreamCopied(status) {
if (!Components.isSuccessCode(status)) {
if (aCallback) {
aCallback(null);
}
this._signalError(SAVE_ERROR);
return;
}
FileUtils.closeSafeFileOutputStream(ostream);
// remember filename for next save if any
this._friendlyName = null;
this._savedFile = aReturnFile;
this._persistExpando();
if (aCallback) {
aCallback(aReturnFile);
}
this.clearFlag(StyleEditorFlags.UNSAVED);
this.clearFlag(StyleEditorFlags.ERROR);
}.bind(this));
}.bind(this);
this._showFilePicker(aFile || this._styleSheetFilePath, true, null, callback);
},
/**
@ -690,31 +694,36 @@ StyleEditor.prototype = {
* @param nsIWindow aParentWindow
* Optional parent window. If null the parent window of the file picker
* will be the window of the attached input element.
* @return nsIFile
* The selected file or null if the user did not pick one.
* @param aCallback
* The callback method, which will be called passing in the selected
* file or null if the user did not pick one.
*/
_showFilePicker: function SE__showFilePicker(aFile, aSave, aParentWindow)
_showFilePicker: function SE__showFilePicker(aFile, aSave, aParentWindow, aCallback)
{
if (typeof(aFile) == "string") {
try {
if (Services.io.extractScheme(aFile) == "file") {
let uri = Services.io.newURI(aFile, null, null);
let file = uri.QueryInterface(Ci.nsIFileURL).file;
return file;
aCallback(file);
return;
}
} catch (ex) {
}
try {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(aFile);
return file;
aCallback(file);
return;
} catch (ex) {
this._signalError(aSave ? SAVE_ERROR : LOAD_ERROR);
return null;
aCallback(null);
return;
}
}
if (aFile) {
return aFile;
aCallback(aFile);
return;
}
let window = aParentWindow
@ -723,13 +732,19 @@ StyleEditor.prototype = {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let mode = aSave ? fp.modeSave : fp.modeOpen;
let key = aSave ? "saveStyleSheet" : "importStyleSheet";
let fpCallback = function fpCallback_done(aResult) {
if (aResult == Ci.nsIFilePicker.returnCancel) {
aCallback(null);
} else {
aCallback(fp.file);
}
};
fp.init(window, _(key + ".title"), mode);
fp.appendFilters(_(key + ".filter"), "*.css");
fp.appendFilters(fp.filterAll);
let rv = fp.show();
return (rv == fp.returnCancel) ? null : fp.file;
fp.open(fpCallback);
return;
},
/**

View File

@ -1537,10 +1537,22 @@ public:
* which places the viewport information in the document header instead
* of returning it directly.
*
* @param aDisplayWidth width of the on-screen display area for this
* document, in device pixels.
* @param aDisplayHeight height of the on-screen display area for this
* document, in device pixels.
*
* NOTE: If the site is optimized for mobile (via the doctype), this
* will return viewport information that specifies default information.
*/
static ViewportInfo GetViewportInfo(nsIDocument* aDocument);
static ViewportInfo GetViewportInfo(nsIDocument* aDocument,
uint32_t aDisplayWidth,
uint32_t aDisplayHeight);
/**
* The device-pixel-to-CSS-px ratio used to adjust meta viewport values.
*/
static double GetDevicePixelsPerMetaViewportPixel(nsIWidget* aWidget);
// Call EnterMicroTask when you're entering JS execution.
// Usually the best way to do this is to use nsAutoMicroTask.

View File

@ -388,6 +388,7 @@ interface nsIXMLHttpRequest : nsISupports
[scriptable, uuid(840d0d00-e83e-4a29-b3c7-67e96e90a499)]
interface nsIXHRSendable : nsISupports {
void getSendInfo(out nsIInputStream body,
out uint64_t contentLength,
out ACString contentType,
out ACString charset);
};

View File

@ -12,6 +12,8 @@
#include "jsdbgapi.h"
#include "jsfriendapi.h"
#include <math.h>
#include "Layers.h"
#include "nsJSUtils.h"
#include "nsCOMPtr.h"
@ -5083,7 +5085,9 @@ static void ProcessViewportToken(nsIDocument *aDocument,
/* static */
ViewportInfo
nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
nsContentUtils::GetViewportInfo(nsIDocument *aDocument,
uint32_t aDisplayWidth,
uint32_t aDisplayHeight)
{
ViewportInfo ret;
ret.defaultZoom = 1.0;
@ -5172,37 +5176,44 @@ nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
autoSize = true;
}
// XXXjwir3:
// See bug 706918, comment 23 for more information on this particular section
// of the code. We're using "screen size" in place of the size of the content
// area, because on mobile, these are close or equal. This will work for our
// purposes (bug 706198), but it will need to be changed in the future to be
// more correct when we bring the rest of the viewport code into platform.
// We actually want the size of the content area, in the event that we don't
// have any metadata about the width and/or height. On mobile, the screen size
// and the size of the content area are very close, or the same value.
// In XUL fennec, the content area is the size of the <browser> widget, but
// in native fennec, the content area is the size of the Gecko LayerView
// object.
// Now convert the scale into device pixels per CSS pixel.
nsIWidget *widget = WidgetForDocument(aDocument);
double pixelRatio = widget ? GetDevicePixelsPerMetaViewportPixel(widget) : 1.0;
scaleFloat *= pixelRatio;
scaleMinFloat *= pixelRatio;
scaleMaxFloat *= pixelRatio;
// TODO:
// Once bug 716575 has been resolved, this code should be changed so that it
// does the right thing on all platforms.
nsresult result;
int32_t screenLeft, screenTop, screenWidth, screenHeight;
nsCOMPtr<nsIScreenManager> screenMgr =
do_GetService("@mozilla.org/gfx/screenmanager;1", &result);
uint32_t width, height;
if (autoSize) {
// aDisplayWidth and aDisplayHeight are in device pixels; convert them to
// CSS pixels for the viewport size.
width = aDisplayWidth / pixelRatio;
height = aDisplayHeight / pixelRatio;
} else {
nsresult widthErrorCode, heightErrorCode;
width = widthStr.ToInteger(&widthErrorCode);
height = heightStr.ToInteger(&heightErrorCode);
nsCOMPtr<nsIScreen> screen;
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
// If width or height has not been set to a valid number by this point,
// fall back to a default value.
bool validWidth = (!widthStr.IsEmpty() && NS_SUCCEEDED(widthErrorCode) && width > 0);
bool validHeight = (!heightStr.IsEmpty() && NS_SUCCEEDED(heightErrorCode) && height > 0);
uint32_t width = widthStr.ToInteger(&errorCode);
if (NS_FAILED(errorCode)) {
if (autoSize) {
width = screenWidth;
} else {
width = Preferences::GetInt("browser.viewport.desktopWidth", 0);
if (!validWidth) {
if (validHeight && aDisplayWidth > 0 && aDisplayHeight > 0) {
width = uint32_t((height * aDisplayWidth) / aDisplayHeight);
} else {
width = Preferences::GetInt("browser.viewport.desktopWidth",
kViewportDefaultScreenWidth);
}
}
if (!validHeight) {
if (aDisplayWidth > 0 && aDisplayHeight > 0) {
height = uint32_t((width * aDisplayHeight) / aDisplayWidth);
} else {
height = width;
}
}
}
@ -5212,19 +5223,7 @@ nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
// Also recalculate the default zoom, if it wasn't specified in the metadata,
// and the width is specified.
if (scaleStr.IsEmpty() && !widthStr.IsEmpty()) {
scaleFloat = NS_MAX(scaleFloat, (float)(screenWidth/width));
}
uint32_t height = heightStr.ToInteger(&errorCode);
if (NS_FAILED(errorCode)) {
height = width * ((float)screenHeight / screenWidth);
}
// If height was provided by the user, but width wasn't, then we should
// calculate the width.
if (widthStr.IsEmpty() && !heightStr.IsEmpty()) {
width = (uint32_t) ((height * screenWidth) / screenHeight);
scaleFloat = NS_MAX(scaleFloat, float(aDisplayWidth) / float(width));
}
height = NS_MIN(height, kViewportMaxHeight);
@ -5233,11 +5232,11 @@ nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
// We need to perform a conversion, but only if the initial or maximum
// scale were set explicitly by the user.
if (!scaleStr.IsEmpty() && NS_SUCCEEDED(scaleErrorCode)) {
width = NS_MAX(width, (uint32_t)(screenWidth / scaleFloat));
height = NS_MAX(height, (uint32_t)(screenHeight / scaleFloat));
width = NS_MAX(width, (uint32_t)(aDisplayWidth / scaleFloat));
height = NS_MAX(height, (uint32_t)(aDisplayHeight / scaleFloat));
} else if (!maxScaleStr.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode)) {
width = NS_MAX(width, (uint32_t)(screenWidth / scaleMaxFloat));
height = NS_MAX(height, (uint32_t)(screenHeight / scaleMaxFloat));
width = NS_MAX(width, (uint32_t)(aDisplayWidth / scaleMaxFloat));
height = NS_MAX(height, (uint32_t)(aDisplayHeight / scaleMaxFloat));
}
bool allowZoom = true;
@ -5260,6 +5259,28 @@ nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
return ret;
}
/* static */
double
nsContentUtils::GetDevicePixelsPerMetaViewportPixel(nsIWidget* aWidget)
{
int32_t prefValue = Preferences::GetInt("browser.viewport.scaleRatio", 0);
if (prefValue > 0) {
return double(prefValue) / 100.0;
}
float dpi = aWidget->GetDPI();
if (dpi < 200.0) {
// Includes desktop displays, LDPI and MDPI Android devices
return 1.0;
}
if (dpi < 300.0) {
// Includes Nokia N900, and HDPI Android devices
return 1.5;
}
// For very high-density displays like the iPhone 4, use an integer ratio.
return floor(dpi / 150.0);
}
/* static */
nsresult
nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,

View File

@ -374,6 +374,7 @@ nsDOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
NS_IMETHODIMP
nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
uint64_t* aContentLength,
nsACString& aContentType,
nsACString& aCharset)
{
@ -383,6 +384,9 @@ nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
rv = this->GetInternalStream(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
rv = this->GetSize(aContentLength);
NS_ENSURE_SUCCESS(rv, rv);
nsString contentType;
rv = this->GetType(contentType);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -103,8 +103,8 @@ nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
// nsIXHRSendable
NS_IMETHODIMP
nsFormData::GetSendInfo(nsIInputStream** aBody, nsACString& aContentType,
nsACString& aCharset)
nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
@ -119,7 +119,8 @@ nsFormData::GetSendInfo(nsIInputStream** aBody, nsACString& aContentType,
fs.GetContentType(aContentType);
aCharset.Truncate();
NS_ADDREF(*aBody = fs.GetSubmissionBody());
*aContentLength = 0;
NS_ADDREF(*aBody = fs.GetSubmissionBody(aContentLength));
return NS_OK;
}

View File

@ -2421,7 +2421,7 @@ nsXMLHttpRequest::SendAsBinary(const nsAString &aBody,
}
static nsresult
GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult, uint64* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
aContentType.AssignLiteral("application/xml");
@ -2455,46 +2455,57 @@ GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
output->Close();
uint32_t length;
rv = storStream->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
*aContentLength = length;
return storStream->NewInputStream(0, aResult);
}
static nsresult
GetRequestBody(const nsAString& aString, nsIInputStream** aResult,
GetRequestBody(const nsAString& aString, nsIInputStream** aResult, uint64* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
aContentType.AssignLiteral("text/plain");
aCharset.AssignLiteral("UTF-8");
return NS_NewCStringInputStream(aResult, NS_ConvertUTF16toUTF8(aString));
nsCString converted = NS_ConvertUTF16toUTF8(aString);
*aContentLength = converted.Length();
return NS_NewCStringInputStream(aResult, converted);
}
static nsresult
GetRequestBody(nsIInputStream* aStream, nsIInputStream** aResult,
GetRequestBody(nsIInputStream* aStream, nsIInputStream** aResult, uint64* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
aContentType.AssignLiteral("text/plain");
aCharset.Truncate();
nsresult rv = aStream->Available(aContentLength);
NS_ENSURE_SUCCESS(rv, rv);
NS_ADDREF(*aResult = aStream);
return NS_OK;
}
static nsresult
GetRequestBody(nsIXHRSendable* aSendable, nsIInputStream** aResult,
GetRequestBody(nsIXHRSendable* aSendable, nsIInputStream** aResult, uint64_t* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
return aSendable->GetSendInfo(aResult, aContentType, aCharset);
return aSendable->GetSendInfo(aResult, aContentLength, aContentType, aCharset);
}
static nsresult
GetRequestBody(ArrayBuffer* aArrayBuffer, nsIInputStream** aResult,
GetRequestBody(ArrayBuffer* aArrayBuffer, nsIInputStream** aResult, uint64_t* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
aContentType.SetIsVoid(true);
aCharset.Truncate();
int32_t length = aArrayBuffer->Length();
*aContentLength = length;
char* data = reinterpret_cast<char*>(aArrayBuffer->Data());
nsCOMPtr<nsIInputStream> stream;
@ -2508,7 +2519,7 @@ GetRequestBody(ArrayBuffer* aArrayBuffer, nsIInputStream** aResult,
}
static nsresult
GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult, uint64_t* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
*aResult = nullptr;
@ -2529,7 +2540,7 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
// document?
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(supports);
if (doc) {
return GetRequestBody(doc, aResult, aContentType, aCharset);
return GetRequestBody(doc, aResult, aContentLength, aContentType, aCharset);
}
// nsISupportsString?
@ -2538,19 +2549,19 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
nsAutoString string;
wstr->GetData(string);
return GetRequestBody(string, aResult, aContentType, aCharset);
return GetRequestBody(string, aResult, aContentLength, aContentType, aCharset);
}
// nsIInputStream?
nsCOMPtr<nsIInputStream> stream = do_QueryInterface(supports);
if (stream) {
return GetRequestBody(stream, aResult, aContentType, aCharset);
return GetRequestBody(stream, aResult, aContentLength, aContentType, aCharset);
}
// nsIXHRSendable?
nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
if (sendable) {
return GetRequestBody(sendable, aResult, aContentType, aCharset);
return GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
}
// ArrayBuffer?
@ -2575,7 +2586,7 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
ac.construct(cx, obj);
if (JS_IsArrayBufferObject(obj, cx)) {
ArrayBuffer buf(cx, obj);
return GetRequestBody(&buf, aResult, aContentType, aCharset);
return GetRequestBody(&buf, aResult, aContentLength, aContentType, aCharset);
}
}
}
@ -2584,6 +2595,7 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
// Makes us act as if !aBody, don't upload anything
aContentType.AssignLiteral("text/plain");
aCharset.AssignLiteral("UTF-8");
*aContentLength = 0;
return NS_OK;
}
@ -2596,18 +2608,18 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
nsString string;
string.Adopt(data, len);
return GetRequestBody(string, aResult, aContentType, aCharset);
return GetRequestBody(string, aResult, aContentLength, aContentType, aCharset);
}
/* static */
nsresult
nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
const Nullable<RequestBody>& aBody,
nsIInputStream** aResult,
nsIInputStream** aResult, uint64* aContentLength,
nsACString& aContentType, nsACString& aCharset)
{
if (aVariant) {
return ::GetRequestBody(aVariant, aResult, aContentType, aCharset);
return ::GetRequestBody(aVariant, aResult, aContentLength, aContentType, aCharset);
}
const RequestBody& body = aBody.Value();
@ -2615,7 +2627,8 @@ nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
switch (body.GetType()) {
case nsXMLHttpRequest::RequestBody::ArrayBuffer:
{
return ::GetRequestBody(value.mArrayBuffer, aResult, aContentType, aCharset);
return ::GetRequestBody(value.mArrayBuffer, aResult, aContentLength,
aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::Blob:
{
@ -2623,16 +2636,17 @@ nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(value.mBlob, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return ::GetRequestBody(sendable, aResult, aContentType, aCharset);
return ::GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::Document:
{
nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(value.mDocument);
return ::GetRequestBody(document, aResult, aContentType, aCharset);
return ::GetRequestBody(document, aResult, aContentLength, aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::DOMString:
{
return ::GetRequestBody(*value.mString, aResult, aContentType, aCharset);
return ::GetRequestBody(*value.mString, aResult, aContentLength,
aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::FormData:
{
@ -2640,11 +2654,12 @@ nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(value.mFormData, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return ::GetRequestBody(sendable, aResult, aContentType, aCharset);
return ::GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::InputStream:
{
return ::GetRequestBody(value.mStream, aResult, aContentType, aCharset);
return ::GetRequestBody(value.mStream, aResult, aContentLength,
aContentType, aCharset);
}
default:
{
@ -2788,7 +2803,7 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
nsCOMPtr<nsIInputStream> postDataStream;
rv = GetRequestBody(aVariant, aBody, getter_AddRefs(postDataStream),
defaultContentType, charset);
&mUploadTotal, defaultContentType, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (postDataStream) {
@ -2851,9 +2866,6 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
}
mUploadComplete = false;
uint64_t uploadTotal = 0;
postDataStream->Available(&uploadTotal);
mUploadTotal = uploadTotal;
// We want to use a newer version of the upload channel that won't
// ignore the necessary headers for an empty Content-Type.
@ -2862,7 +2874,7 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel2");
if (uploadChannel2) {
uploadChannel2->ExplicitSetUploadStream(postDataStream, contentType,
-1, method, false);
mUploadTotal, method, false);
}
else {
// http channel doesn't support the new nsIUploadChannel2. Emulate
@ -2872,7 +2884,7 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
}
nsCOMPtr<nsIUploadChannel> uploadChannel =
do_QueryInterface(httpChannel);
uploadChannel->SetUploadStream(postDataStream, contentType, -1);
uploadChannel->SetUploadStream(postDataStream, contentType, mUploadTotal);
// Reset the method to its original value
httpChannel->SetRequestMethod(method);
}

View File

@ -345,6 +345,7 @@ private:
static nsresult GetRequestBody(nsIVariant* aVariant,
const Nullable<RequestBody>& aBody,
nsIInputStream** aResult,
uint64_t* aContentLength,
nsACString& aContentType,
nsACString& aCharset);

View File

@ -250,6 +250,13 @@ MOCHITEST_FILES_A = \
file_XHRDocURI.text \
file_XHRDocURI.text^headers^ \
test_DOMException.html \
test_meta_viewport0.html \
test_meta_viewport1.html \
test_meta_viewport2.html \
test_meta_viewport3.html \
test_meta_viewport4.html \
test_meta_viewport5.html \
test_meta_viewport6.html \
test_mutationobservers.html \
mutationobserver_dialog.html \
test_bug744830.html \

View File

@ -0,0 +1,76 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>meta viewport test</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p>No &lt;meta name="viewport"&gt; tag</p>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
let tests = [];
tests.push(function test1() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 100]]},
function() {
let info = getViewportInfo(800, 480);
is(info.defaultZoom, 0, "initial scale is unspecified");
is(info.minZoom, 0, "minumum scale defaults to the absolute minumum");
is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
is(info.width, 980, "width is the default width");
is(info.height, 588, "height is proportional to displayHeight");
is(info.autoSize, false, "autoSize is disabled by default");
is(info.allowZoom, true, "zooming is enabled by default");
info = getViewportInfo(490, 600);
is(info.width, 980, "width is still the default width");
is(info.height, 1200, "height is proportional to the new displayHeight");
nextTest();
});
});
tests.push(function test2() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 150]]},
function() {
let info = getViewportInfo(800, 480);
is(info.width, 980, "width is still the default width");
is(info.height, 588, "height is still proportional to displayHeight");
nextTest();
});
});
function getViewportInfo(aDisplayWidth, aDisplayHeight) {
let defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom = {},
width = {}, height = {}, autoSize = {};
let cwu = SpecialPowers.getDOMWindowUtils(window);
cwu.getViewportInfo(aDisplayWidth, aDisplayHeight, defaultZoom, allowZoom,
minZoom, maxZoom, width, height, autoSize);
return {
defaultZoom: defaultZoom.value,
minZoom: minZoom.value,
maxZoom: maxZoom.value,
width: width.value,
height: height.value,
autoSize: autoSize.value,
allowZoom: allowZoom.value
};
}
function nextTest() {
if (tests.length)
(tests.shift())();
else
SimpleTest.finish();
}
addEventListener("load", nextTest);
</script>
</body>
</html>

View File

@ -0,0 +1,76 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>meta viewport test</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>width=device-width, initial-scale=1</p>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
let tests = [];
tests.push(function test1() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 100]]},
function() {
let info = getViewportInfo(800, 480);
is(info.defaultZoom, 1, "initial zoom is 100%");
is(info.width, 800, "width is the same as the displayWidth");
is(info.height, 480, "height is the same as the displayHeight");
is(info.autoSize, true, "width=device-width enables autoSize");
is(info.allowZoom, true, "zooming is enabled by default");
info = getViewportInfo(900, 600);
is(info.width, 900, "changing the displayWidth changes the width");
is(info.height, 600, "changing the displayHeight changes the height");
nextTest();
});
});
tests.push(function test2() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 150]]},
function() {
let info = getViewportInfo(900, 600);
is(info.defaultZoom, 1.5, "initial zoom is 150%");
is(info.width, 600, "width equals displayWidth/1.5");
is(info.height, 400, "height equals displayHeight/1.5");
nextTest();
});
});
function getViewportInfo(aDisplayWidth, aDisplayHeight) {
let defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom = {},
width = {}, height = {}, autoSize = {};
let cwu = SpecialPowers.getDOMWindowUtils(window);
cwu.getViewportInfo(aDisplayWidth, aDisplayHeight, defaultZoom, allowZoom,
minZoom, maxZoom, width, height, autoSize);
return {
defaultZoom: defaultZoom.value,
minZoom: minZoom.value,
maxZoom: maxZoom.value,
width: width.value,
height: height.value,
autoSize: autoSize.value,
allowZoom: allowZoom.value
};
}
function nextTest() {
if (tests.length)
(tests.shift())();
else
SimpleTest.finish();
}
addEventListener("load", nextTest);
</script>
</body>
</html>

View File

@ -0,0 +1,76 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>meta viewport test</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta name="viewport" content="width=device-width">
</head>
<body>
<p>width=device-width</p>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
let tests = [];
tests.push(function test1() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 100]]},
function() {
let info = getViewportInfo(800, 480);
is(info.defaultZoom, 1, "initial zoom is 100%");
is(info.width, 800, "width is the same as the displayWidth");
is(info.height, 480, "height is the same as the displayHeight");
is(info.autoSize, true, "width=device-width enables autoSize");
is(info.allowZoom, true, "zooming is enabled by default");
info = getViewportInfo(900, 600);
is(info.width, 900, "changing the displayWidth changes the width");
is(info.height, 600, "changing the displayHeight changes the height");
nextTest();
});
});
tests.push(function test2() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 150]]},
function() {
let info = getViewportInfo(900, 600);
is(info.defaultZoom, 1.5, "initial zoom is 150%");
is(info.width, 600, "width equals displayWidth/1.5");
is(info.height, 400, "height equals displayHeight/1.5");
nextTest();
});
});
function getViewportInfo(aDisplayWidth, aDisplayHeight) {
let defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom = {},
width = {}, height = {}, autoSize = {};
let cwu = SpecialPowers.getDOMWindowUtils(window);
cwu.getViewportInfo(aDisplayWidth, aDisplayHeight, defaultZoom, allowZoom,
minZoom, maxZoom, width, height, autoSize);
return {
defaultZoom: defaultZoom.value,
minZoom: minZoom.value,
maxZoom: maxZoom.value,
width: width.value,
height: height.value,
autoSize: autoSize.value,
allowZoom: allowZoom.value
};
}
function nextTest() {
if (tests.length)
(tests.shift())();
else
SimpleTest.finish();
}
addEventListener("load", nextTest);
</script>
</body>
</html>

View File

@ -0,0 +1,78 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>meta viewport test</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta name="viewport" content="width=320">
</head>
<body>
<p>width=320</p>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
let tests = [];
tests.push(function test1() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 100]]},
function() {
let info = getViewportInfo(800, 480);
is(info.defaultZoom, 2.5, "initial zoom fits the displayWidth");
is(info.width, 320, "width is set explicitly");
is(info.height, 223, "height is at the absolute minimum");
is(info.autoSize, false, "width=device-width enables autoSize");
is(info.allowZoom, true, "zooming is enabled by default");
info = getViewportInfo(480, 800);
is(info.defaultZoom, 1.5, "initial zoom fits the new displayWidth");
is(info.width, 320, "explicit width is unchanged");
is(info.height, 533, "height changes proportional to displayHeight");
nextTest();
});
});
tests.push(function test2() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 150]]},
function() {
// With an explicit width in CSS px, the scaleRatio has no effect.
let info = getViewportInfo(800, 480);
is(info.defaultZoom, 2.5, "initial zoom still fits the displayWidth");
is(info.width, 320, "width is still set explicitly");
is(info.height, 223, "height is still minimum height");
nextTest();
});
});
function getViewportInfo(aDisplayWidth, aDisplayHeight) {
let defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom = {},
width = {}, height = {}, autoSize = {};
let cwu = SpecialPowers.getDOMWindowUtils(window);
cwu.getViewportInfo(aDisplayWidth, aDisplayHeight, defaultZoom, allowZoom,
minZoom, maxZoom, width, height, autoSize);
return {
defaultZoom: defaultZoom.value,
minZoom: minZoom.value,
maxZoom: maxZoom.value,
width: width.value,
height: height.value,
autoSize: autoSize.value,
allowZoom: allowZoom.value
};
}
function nextTest() {
if (tests.length)
(tests.shift())();
else
SimpleTest.finish();
}
addEventListener("load", nextTest);
</script>
</body>
</html>

View File

@ -0,0 +1,77 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>meta viewport test</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
</head>
<body>
<p>initial-scale=1.0, user-scalable=no</p>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
let tests = [];
tests.push(function test1() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 100]]},
function() {
let info = getViewportInfo(800, 480);
is(info.defaultZoom, 1, "initial zoom is set explicitly");
is(info.width, 800, "width fits the initial zoom level");
is(info.height, 480, "height fits the initial zoom level");
is(info.autoSize, true, "initial-scale=1 enables autoSize");
is(info.allowZoom, false, "zooming is explicitly disabled");
info = getViewportInfo(480, 800);
is(info.defaultZoom, 1, "initial zoom is still set explicitly");
is(info.width, 480, "width changes to match the displayWidth");
is(info.height, 800, "height changes to match the displayHeight");
nextTest();
});
});
tests.push(function test2() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 150]]},
function() {
let info = getViewportInfo(800, 480);
is(info.defaultZoom, 1.5, "initial zoom is adjusted for device pixel ratio");
is(info.width, 533, "width fits the initial zoom");
is(info.height, 320, "height fits the initial zoom");
nextTest();
});
});
function getViewportInfo(aDisplayWidth, aDisplayHeight) {
let defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom = {},
width = {}, height = {}, autoSize = {};
let cwu = SpecialPowers.getDOMWindowUtils(window);
cwu.getViewportInfo(aDisplayWidth, aDisplayHeight, defaultZoom, allowZoom,
minZoom, maxZoom, width, height, autoSize);
return {
defaultZoom: defaultZoom.value,
minZoom: minZoom.value,
maxZoom: maxZoom.value,
width: width.value,
height: height.value,
autoSize: autoSize.value,
allowZoom: allowZoom.value
};
}
function nextTest() {
if (tests.length)
(tests.shift())();
else
SimpleTest.finish();
}
addEventListener("load", nextTest);
</script>
</body>
</html>

View File

@ -0,0 +1,53 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>meta viewport test</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta name="viewport" content="user-scalable=NO">
</head>
<body>
<p>user-scalable=NO</p>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
let tests = [];
tests.push(function test1() {
let info = getViewportInfo(800, 480);
is(info.allowZoom, true, "user-scalable values are case-sensitive; 'NO' is not valid");
nextTest();
});
function getViewportInfo(aDisplayWidth, aDisplayHeight) {
let defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom = {},
width = {}, height = {}, autoSize = {};
let cwu = SpecialPowers.getDOMWindowUtils(window);
cwu.getViewportInfo(aDisplayWidth, aDisplayHeight, defaultZoom, allowZoom,
minZoom, maxZoom, width, height, autoSize);
return {
defaultZoom: defaultZoom.value,
minZoom: minZoom.value,
maxZoom: maxZoom.value,
width: width.value,
height: height.value,
autoSize: autoSize.value,
allowZoom: allowZoom.value
};
}
function nextTest() {
if (tests.length)
(tests.shift())();
else
SimpleTest.finish();
}
addEventListener("load", nextTest);
</script>
</body>
</html>

View File

@ -0,0 +1,82 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>meta viewport test</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta name="viewport" content="width=2000, minimum-scale=0.75">
</head>
<body>
<p>width=2000, minimum-scale=0.75</p>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
let tests = [];
tests.push(function test1() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 100]]},
function() {
let info = getViewportInfo(800, 480);
is(info.minZoom, 0.75, "minumum scale is set explicitly");
is(info.defaultZoom, 0.75, "initial scale is bounded by the minimum scale");
is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
is(info.width, 2000, "width is set explicitly");
is(info.height, 1200, "height is proportional to displayHeight");
is(info.autoSize, false, "autoSize is disabled by default");
is(info.allowZoom, true, "zooming is enabled by default");
info = getViewportInfo(2000, 1000);
is(info.minZoom, 0.75, "minumum scale is still set explicitly");
is(info.defaultZoom, 1, "initial scale fits the width");
is(info.width, 2000, "width is set explicitly");
is(info.height, 1000, "height is proportional to the new displayHeight");
nextTest();
});
});
tests.push(function test2() {
SpecialPowers.pushPrefEnv({"set": [["browser.viewport.scaleRatio", 150]]},
function() {
let info = getViewportInfo(800, 480);
is(info.minZoom, 1.125, "minumum scale is converted to device pixel scale");
is(info.defaultZoom, 1.125, "initial scale is bounded by the minimum scale");
is(info.maxZoom, 15, "maximum scale defaults to the absolute maximum");
is(info.width, 2000, "width is still set explicitly");
is(info.height, 1200, "height is still proportional to displayHeight");
nextTest();
});
});
function getViewportInfo(aDisplayWidth, aDisplayHeight) {
let defaultZoom = {}, allowZoom = {}, minZoom = {}, maxZoom = {},
width = {}, height = {}, autoSize = {};
let cwu = SpecialPowers.getDOMWindowUtils(window);
cwu.getViewportInfo(aDisplayWidth, aDisplayHeight, defaultZoom, allowZoom,
minZoom, maxZoom, width, height, autoSize);
return {
defaultZoom: defaultZoom.value,
minZoom: minZoom.value,
maxZoom: maxZoom.value,
width: width.value,
height: height.value,
autoSize: autoSize.value,
allowZoom: allowZoom.value
};
}
function nextTest() {
if (tests.length)
(tests.shift())();
else
SimpleTest.finish();
}
addEventListener("load", nextTest);
</script>
</body>
</html>

View File

@ -169,7 +169,7 @@ public:
NS_LITERAL_CSTRING("multipart/form-data; boundary=") + mBoundary;
}
nsIInputStream* GetSubmissionBody();
nsIInputStream* GetSubmissionBody(uint64_t* aContentLength);
protected:
@ -201,6 +201,11 @@ private:
* submission.
*/
nsCString mBoundary;
/**
* The total length in bytes of the streams that make up mPostDataStream
*/
uint64_t mTotalLength;
};
/**

View File

@ -378,6 +378,7 @@ nsFSMultipartFormData::nsFSMultipartFormData(const nsACString& aCharset,
{
mPostDataStream =
do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
mTotalLength = 0;
mBoundary.AssignLiteral("---------------------------");
mBoundary.AppendInt(rand());
@ -391,7 +392,7 @@ nsFSMultipartFormData::~nsFSMultipartFormData()
}
nsIInputStream*
nsFSMultipartFormData::GetSubmissionBody()
nsFSMultipartFormData::GetSubmissionBody(uint64_t* aContentLength)
{
// Finish data
mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
@ -400,6 +401,7 @@ nsFSMultipartFormData::GetSubmissionBody()
// Add final data input stream
AddPostDataStream();
*aContentLength = mTotalLength;
return mPostDataStream;
}
@ -513,6 +515,11 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
AddPostDataStream();
mPostDataStream->AppendStream(fileStream);
uint64_t size;
nsresult rv = aBlob->GetSize(&size);
NS_ENSURE_SUCCESS(rv, rv);
mTotalLength += size;
}
// CRLF after file
@ -536,7 +543,8 @@ nsFSMultipartFormData::GetEncodedSubmission(nsIURI* aURI,
GetContentType(contentType);
mimeStream->AddHeader("Content-Type", contentType.get());
mimeStream->SetAddContentLength(true);
mimeStream->SetData(GetSubmissionBody());
uint64_t unused;
mimeStream->SetData(GetSubmissionBody(&unused));
*aPostDataStream = mimeStream.forget().get();
@ -554,6 +562,7 @@ nsFSMultipartFormData::AddPostDataStream()
NS_ASSERTION(postDataChunkStream, "Could not open a stream for POST!");
if (postDataChunkStream) {
mPostDataStream->AppendStream(postDataChunkStream);
mTotalLength += mPostDataChunk.Length();
}
mPostDataChunk.Truncate();

View File

@ -1490,7 +1490,9 @@ void nsBuiltinDecoderStateMachine::Seek(double aTime)
mSeekTime = NS_MAX(mStartTime, mSeekTime);
LOG(PR_LOG_DEBUG, ("%p Changed state to SEEKING (to %f)", mDecoder.get(), aTime));
mState = DECODER_STATE_SEEKING;
mDecoder->RecreateDecodedStream(mSeekTime - mStartTime);
if (mDecoder->GetDecodedStream()) {
mDecoder->RecreateDecodedStream(mSeekTime - mStartTime);
}
ScheduleStateMachine();
}
@ -2045,7 +2047,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
if ((isLiveStream || !mDecoder->CanPlayThrough()) &&
elapsed < TimeDuration::FromSeconds(mBufferingWait) &&
(mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS)
: (GetUndecodedData() < mBufferingWait * USECS_PER_S / 1000)) &&
: (GetUndecodedData() < mBufferingWait * USECS_PER_S)) &&
!resource->IsDataCachedToEndOfResource(mDecoder->mDecoderPosition) &&
!resource->IsSuspended())
{
@ -2217,12 +2219,21 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame()
int64_t remainingTime = AUDIO_DURATION_USECS;
NS_ASSERTION(clock_time >= mStartTime, "Should have positive clock time.");
nsAutoPtr<VideoData> currentFrame;
#ifdef PR_LOGGING
int32_t droppedFrames = 0;
#endif
if (mReader->VideoQueue().GetSize() > 0) {
VideoData* frame = mReader->VideoQueue().PeekFront();
while (mRealTime || clock_time >= frame->mTime) {
mVideoFrameEndTime = frame->mEndTime;
currentFrame = frame;
LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld", mDecoder.get(), frame->mTime));
#ifdef PR_LOGGING
if (droppedFrames++) {
LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld (%d so far)",
mDecoder.get(), frame->mTime, droppedFrames - 1));
}
#endif
mReader->VideoQueue().PopFront();
// Notify the decode thread that the video queue's buffers may have
// free'd up space for more frames.
@ -2388,7 +2399,7 @@ bool nsBuiltinDecoderStateMachine::JustExitedQuickBuffering()
{
return !mDecodeStartTime.IsNull() &&
mQuickBuffering &&
(TimeStamp::Now() - mDecodeStartTime) < TimeDuration::FromSeconds(QUICK_BUFFER_THRESHOLD_USECS);
(TimeStamp::Now() - mDecodeStartTime) < TimeDuration::FromMicroseconds(QUICK_BUFFER_THRESHOLD_USECS);
}
void nsBuiltinDecoderStateMachine::StartBuffering()

View File

@ -152,7 +152,11 @@ let DOMApplicationRegistry = {
#ifdef MOZ_WIDGET_GONK
// if first run, merge the system apps.
if (runUpdate) {
let file = FileUtils.getFile("coreAppsDir", ["webapps", "webapps.json"], false);
let file;
try {
file = FileUtils.getFile("coreAppsDir", ["webapps", "webapps.json"], false);
} catch(e) { }
if (file && file.exists) {
// 2.a
this._loadJSONAsync(file, (function loadCoreRegistry(aData) {
@ -194,6 +198,8 @@ let DOMApplicationRegistry = {
}
this.registerAppsHandlers();
}).bind(this));
} else {
this.registerAppsHandlers();
}
} else {
this.registerAppsHandlers();
@ -381,7 +387,8 @@ let DOMApplicationRegistry = {
if (aCallback)
aCallback(data);
} catch (ex) {
Cu.reportError("DOMApplicationRegistry: Could not parse JSON: " + ex);
Cu.reportError("DOMApplicationRegistry: Could not parse JSON: " +
aFile.path + " " + ex);
if (aCallback)
aCallback(null);
}

View File

@ -177,7 +177,7 @@ nsDOMWindowUtils::GetDocCharsetIsForced(bool *aIsForced)
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
if (window) {
nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
*aIsForced = doc &&
doc->GetDocumentCharacterSetSource() >= kCharsetFromParentForced;
}
@ -263,6 +263,31 @@ nsDOMWindowUtils::SetCSSViewport(float aWidthPx, float aHeightPx)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetViewportInfo(uint32_t aDisplayWidth,
uint32_t aDisplayHeight,
double *aDefaultZoom, bool *aAllowZoom,
double *aMinZoom, double *aMaxZoom,
uint32_t *aWidth, uint32_t *aHeight,
bool *aAutoSize)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
NS_ENSURE_STATE(doc);
ViewportInfo info = nsContentUtils::GetViewportInfo(doc, aDisplayWidth, aDisplayHeight);
*aDefaultZoom = info.defaultZoom;
*aAllowZoom = info.allowZoom;
*aMinZoom = info.minZoom;
*aMaxZoom = info.maxZoom;
*aWidth = info.width;
*aHeight = info.height;
*aAutoSize = info.autoSize;
return NS_OK;
}
static void DestroyNsRect(void* aObject, nsIAtom* aPropertyName,
void* aPropertyValue, void* aData)
{

View File

@ -40,7 +40,7 @@ interface nsIDOMTouch;
interface nsIDOMClientRect;
interface nsIURI;
[scriptable, uuid(6cf3e8f0-fb82-11e1-a21f-0800200c9a66)]
[scriptable, uuid(90d8e97b-2c61-4c05-9f1c-e568d22f5bdc)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -103,6 +103,16 @@ interface nsIDOMWindowUtils : nsISupports {
*/
void setCSSViewport(in float aWidthPx, in float aHeightPx);
/**
* Information retrieved from the <meta name="viewport"> tag.
* See nsContentUtils::GetViewportInfo for more information.
*/
void getViewportInfo(in uint32_t aDisplayWidth, in uint32_t aDisplayHeight,
out double aDefaultZoom, out boolean aAllowZoom,
out double aMinZoom, out double aMaxZoom,
out uint32_t aWidth, out uint32_t aHeight,
out boolean aAutoSize);
/**
* For any scrollable element, this allows you to override the
* visible region and draw more than what is visible, which is

View File

@ -31,23 +31,50 @@ using namespace mozilla::ipc;
namespace {
class RemoteInputStream : public nsIInputStream,
public nsISeekableStream
public nsISeekableStream,
public nsIIPCSerializableInputStream
{
mozilla::Monitor mMonitor;
nsCOMPtr<nsIDOMBlob> mSourceBlob;
nsCOMPtr<nsIInputStream> mStream;
nsCOMPtr<nsISeekableStream> mSeekableStream;
ActorFlavorEnum mOrigin;
public:
NS_DECL_ISUPPORTS
RemoteInputStream(nsIDOMBlob* aSourceBlob)
: mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob)
RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorFlavorEnum aOrigin)
: mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob),
mOrigin(aOrigin)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSourceBlob);
}
void
Serialize(InputStreamParams& aParams)
{
nsCOMPtr<nsIRemoteBlob> remote = do_QueryInterface(mSourceBlob);
MOZ_ASSERT(remote);
if (mOrigin == Parent) {
aParams = RemoteInputStreamParams(
static_cast<PBlobParent*>(remote->GetPBlob()), nullptr);
} else {
aParams = RemoteInputStreamParams(
nullptr, static_cast<PBlobChild*>(remote->GetPBlob()));
}
}
bool
Deserialize(const InputStreamParams& aParams)
{
// See InputStreamUtils.cpp to see how deserialization of a
// RemoteInputStream is special-cased.
MOZ_NOT_REACHED("RemoteInputStream should never be deserialized");
return false;
}
void
SetStream(nsIInputStream* aStream)
{
@ -234,6 +261,7 @@ NS_IMPL_THREADSAFE_RELEASE(RemoteInputStream)
NS_INTERFACE_MAP_BEGIN(RemoteInputStream)
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
NS_INTERFACE_MAP_END
@ -421,7 +449,8 @@ private:
MOZ_ASSERT(!mInputStream);
MOZ_ASSERT(!mDone);
nsRefPtr<RemoteInputStream> stream = new RemoteInputStream(mSourceBlob);
nsRefPtr<RemoteInputStream> stream = new RemoteInputStream(mSourceBlob,
ActorFlavor);
StreamActorType* streamActor = new StreamActorType(stream);
if (mActor->SendPBlobStreamConstructor(streamActor)) {

View File

@ -189,6 +189,9 @@ function RadioInterfaceLayer() {
let lock = gSettingsService.createLock();
lock.get("ril.radio.disabled", this);
// Read preferred network type from the setting DB.
lock.get("ril.radio.preferredNetworkType", this);
// Read the APN data form the setting DB.
lock.get("ril.data.apn", this);
lock.get("ril.data.user", this);
@ -470,6 +473,9 @@ RadioInterfaceLayer.prototype = {
case "stksessionend":
ppmm.broadcastAsyncMessage("RIL:StkSessionEnd", null);
break;
case "setPreferredNetworkType":
this.handleSetPreferredNetworkType(message);
break;
default:
throw new Error("Don't know about this message type: " +
message.rilMessageType);
@ -643,6 +649,39 @@ RadioInterfaceLayer.prototype = {
this.updateRILNetworkInterface();
},
_preferredNetworkType: null,
setPreferredNetworkType: function setPreferredNetworkType(value) {
let networkType = RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO.indexOf(value);
if (networkType < 0) {
gSettingsService.createLock().set("ril.radio.preferredNetworkType",
this._preferredNetworkType || RIL.GECKO_PREFERRED_NETWORK_TYPE_DEFAULT,
false);
return;
}
if (networkType == this._preferredNetworkType) {
return;
}
this.worker.postMessage({rilMessageType: "setPreferredNetworkType",
networkType: networkType});
this._ensureRadioState();
},
handleSetPreferredNetworkType: function handleSetPreferredNetworkType(message) {
if ((this._preferredNetworkType != null) && !message.success) {
gSettingsService.createLock().set("ril.radio.preferredNetworkType",
this._preferredNetworkType,
false);
return;
}
this._preferredNetworkType = message.networkType;
debug("_preferredNetworkType is now " +
RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[this._preferredNetworkType]);
},
handleSignalStrengthChange: function handleSignalStrengthChange(message) {
let voiceInfo = this.rilContext.voice;
// TODO CDMA, EVDO, LTE, etc. (see bug 726098)
@ -704,6 +743,11 @@ RadioInterfaceLayer.prototype = {
// Wait for that.
return;
}
if (this._preferredNetworkType == null) {
// We haven't read the initial value from the settings DB yet.
// Wait for that.
return;
}
if (!this._sysMsgListenerReady) {
// The UI's system app isn't ready yet for us to receive any
// events (e.g. incoming SMS, etc.). Wait for that.
@ -1203,6 +1247,10 @@ RadioInterfaceLayer.prototype = {
this._radioEnabled = !aResult;
this._ensureRadioState();
break;
case "ril.radio.preferredNetworkType":
debug("'ril.radio.preferredNetworkType' is now " + aResult);
this.setPreferredNetworkType(aResult);
break;
case "ril.data.enabled":
this._oldRilDataEnabledState = this.dataCallSettings["enabled"];
// Fall through!

View File

@ -335,18 +335,15 @@ const NETWORK_INFO_MESSAGE_TYPES = [
NETWORK_INFO_NETWORK_SELECTION_MODE
];
const PREFERRED_NETWORK_TYPE_GSM_WCDMA = 0;
const PREFERRED_NETWORK_TYPE_GSM_ONLY = 1;
const PREFERRED_NETWORK_TYPE_WCDMA = 2;
const PREFERRED_NETWORK_TYPE_GSM_WCDMA_AUTO = 3;
const PREFERRED_NETWORK_TYPE_CDMA_EVDO_AUTO = 4;
const PREFERRED_NETWORK_TYPE_CDMA_ONLY = 5;
const PREFERRED_NETWORK_TYPE_EVDO_ONLY = 6;
const PREFERRED_NETWORK_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7;
const PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO = 8;
const PREFERRED_NETWORK_TYPE_LTE_GSM_WCDMA = 9;
const PREFERRED_NETWORK_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10;
const PREFERRED_NETWORK_TYPE_LTE_ONLY = 11;
const GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM = "wcdma/gsm";
const GECKO_PREFERRED_NETWORK_TYPE_GSM_ONLY = "gsm";
const GECKO_PREFERRED_NETWORK_TYPE_WCDMA_ONLY = "wcdma";
const GECKO_PREFERRED_NETWORK_TYPE_DEFAULT = GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM;
const RIL_PREFERRED_NETWORK_TYPE_TO_GECKO = [
GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM,
GECKO_PREFERRED_NETWORK_TYPE_GSM_ONLY,
GECKO_PREFERRED_NETWORK_TYPE_WCDMA_ONLY
];
// Network registration states. See TS 27.007 7.2
const NETWORK_CREG_STATE_NOT_SEARCHING = 0;

View File

@ -604,6 +604,12 @@ let RIL = {
*/
_pendingSentSmsMap: {},
/**
* Index of the RIL_PREFERRED_NETWORK_TYPE_TO_GECKO. Its value should be
* preserved over rild reset.
*/
preferredNetworkType: null,
initRILState: function initRILState() {
/**
* One of the RADIO_STATE_* constants.
@ -1681,15 +1687,32 @@ let RIL = {
/**
* Set the preferred network type.
*
* @param network_type
* The network type. One of the PREFERRED_NETWORK_TYPE_* constants.
* @param options An object contains a valid index of
* RIL_PREFERRED_NETWORK_TYPE_TO_GECKO as its `networkType`
* attribute, or undefined to set current preferred network
* type.
*/
setPreferredNetworkType: function setPreferredNetworkType(network_type) {
Buf.newParcel(REQUEST_SET_PREFERRED_NETWORK_TYPE);
Buf.writeUint32(network_type);
setPreferredNetworkType: function setPreferredNetworkType(options) {
if (options) {
this.preferredNetworkType = options.networkType;
}
if (this.preferredNetworkType == null) {
return;
}
Buf.newParcel(REQUEST_SET_PREFERRED_NETWORK_TYPE, options);
Buf.writeUint32(1);
Buf.writeUint32(this.preferredNetworkType);
Buf.sendParcel();
},
/**
* Get the preferred network type.
*/
getPreferredNetworkType: function getPreferredNetworkType() {
Buf.simpleRequest(REQUEST_GET_PREFERRED_NETWORK_TYPE);
},
/**
* Request various states about the network.
*/
@ -3999,8 +4022,33 @@ RIL[REQUEST_STK_SEND_ENVELOPE_COMMAND] = null;
RIL[REQUEST_STK_SEND_TERMINAL_RESPONSE] = null;
RIL[REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM] = null;
RIL[REQUEST_EXPLICIT_CALL_TRANSFER] = null;
RIL[REQUEST_SET_PREFERRED_NETWORK_TYPE] = null;
RIL[REQUEST_GET_PREFERRED_NETWORK_TYPE] = null;
RIL[REQUEST_SET_PREFERRED_NETWORK_TYPE] = function REQUEST_SET_PREFERRED_NETWORK_TYPE(length, options) {
if (options.networkType == null) {
// The request was made by ril_worker itself automatically. Don't report.
return;
}
this.sendDOMMessage({
rilMessageType: "setPreferredNetworkType",
networkType: options.networkType,
success: options.rilRequestError == ERROR_SUCCESS
});
};
RIL[REQUEST_GET_PREFERRED_NETWORK_TYPE] = function REQUEST_GET_PREFERRED_NETWORK_TYPE(length, options) {
let networkType;
if (!options.rilRequestError) {
networkType = RIL_PREFERRED_NETWORK_TYPE_TO_GECKO.indexOf(GECKO_PREFERRED_NETWORK_TYPE_DEFAULT);
if (Buf.readUint32()) {
this.preferredNetworkType = networkType = Buf.readUint32();
}
}
this.sendDOMMessage({
rilMessageType: "getPreferredNetworkType",
networkType: networkType,
success: options.rilRequestError == ERROR_SUCCESS
});
};
RIL[REQUEST_GET_NEIGHBORING_CELL_IDS] = null;
RIL[REQUEST_SET_LOCATION_UPDATES] = null;
RIL[REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE] = null;
@ -4233,6 +4281,8 @@ RIL[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length) {
}
this.initRILState();
this.setPreferredNetworkType();
};
/**

View File

@ -83,7 +83,7 @@ CPPSRCS += \
$(NULL)
else ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += \
FallbackBattery.cpp \
CocoaBattery.cpp \
FallbackVibration.cpp \
FallbackPower.cpp \
FallbackScreenConfiguration.cpp \

291
hal/cocoa/CocoaBattery.cpp Normal file
View File

@ -0,0 +1,291 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : */
/* 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/. */
#import <CoreFoundation/CoreFoundation.h>
#import <IOKit/ps/IOPowerSources.h>
#import <IOKit/ps/IOPSKeys.h>
#include <mozilla/Hal.h>
#include <mozilla/dom/battery/Constants.h>
#include <mozilla/Services.h>
#include <nsObserverService.h>
#include <dlfcn.h>
#define IOKIT_FRAMEWORK_PATH "/System/Library/Frameworks/IOKit.framework/IOKit"
#ifndef kIOPSTimeRemainingUnknown
#define kIOPSTimeRemainingUnknown ((CFTimeInterval)-1.0)
#endif
#ifndef kIOPSTimeRemainingUnlimited
#define kIOPSTimeRemainingUnlimited ((CFTimeInterval)-2.0)
#endif
using namespace mozilla::dom::battery;
namespace mozilla {
namespace hal_impl {
typedef CFTimeInterval (*IOPSGetTimeRemainingEstimateFunc)(void);
class MacPowerInformationService
{
public:
static MacPowerInformationService* GetInstance();
static void Shutdown();
void BeginListening();
void StopListening();
static void HandleChange(void *aContext);
~MacPowerInformationService();
private:
MacPowerInformationService();
// The reference to the runloop that is notified of power changes.
CFRunLoopSourceRef mRunLoopSource;
double mLevel;
bool mCharging;
double mRemainingTime;
bool mShouldNotify;
friend void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
static MacPowerInformationService* sInstance;
static void* sIOKitFramework;
static IOPSGetTimeRemainingEstimateFunc sIOPSGetTimeRemainingEstimate;
};
void* MacPowerInformationService::sIOKitFramework;
IOPSGetTimeRemainingEstimateFunc MacPowerInformationService::sIOPSGetTimeRemainingEstimate;
/*
* Implementation of mozilla::hal_impl::EnableBatteryNotifications,
* mozilla::hal_impl::DisableBatteryNotifications,
* and mozilla::hal_impl::GetCurrentBatteryInformation.
*/
void
EnableBatteryNotifications()
{
MacPowerInformationService::GetInstance()->BeginListening();
}
void
DisableBatteryNotifications()
{
MacPowerInformationService::GetInstance()->StopListening();
}
void
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
{
MacPowerInformationService* powerService = MacPowerInformationService::GetInstance();
aBatteryInfo->level() = powerService->mLevel;
aBatteryInfo->charging() = powerService->mCharging;
aBatteryInfo->remainingTime() = powerService->mRemainingTime;
}
/*
* Following is the implementation of MacPowerInformationService.
*/
MacPowerInformationService* MacPowerInformationService::sInstance = nullptr;
namespace {
struct SingletonDestroyer MOZ_FINAL : public nsIObserver
{
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
};
NS_IMPL_ISUPPORTS1(SingletonDestroyer, nsIObserver)
NS_IMETHODIMP
SingletonDestroyer::Observe(nsISupports*, const char* aTopic, const PRUnichar*)
{
MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
MacPowerInformationService::Shutdown();
return NS_OK;
}
} // anonymous namespace
/* static */ MacPowerInformationService*
MacPowerInformationService::GetInstance()
{
if (sInstance) {
return sInstance;
}
sInstance = new MacPowerInformationService();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(new SingletonDestroyer(), "xpcom-shutdown", false);
}
return sInstance;
}
void
MacPowerInformationService::Shutdown()
{
delete sInstance;
sInstance = nullptr;
}
MacPowerInformationService::MacPowerInformationService()
: mRunLoopSource(nullptr)
, mLevel(kDefaultLevel)
, mCharging(kDefaultCharging)
, mRemainingTime(kDefaultRemainingTime)
, mShouldNotify(false)
{
// IOPSGetTimeRemainingEstimate (and the related constants) are only available
// on 10.7, so we test for their presence at runtime.
sIOKitFramework = dlopen(IOKIT_FRAMEWORK_PATH, RTLD_LAZY | RTLD_LOCAL);
if (sIOKitFramework) {
sIOPSGetTimeRemainingEstimate =
(IOPSGetTimeRemainingEstimateFunc)dlsym(sIOKitFramework, "IOPSGetTimeRemainingEstimate");
} else {
sIOPSGetTimeRemainingEstimate = nullptr;
}
}
MacPowerInformationService::~MacPowerInformationService()
{
MOZ_ASSERT(!mRunLoopSource,
"The observers have not been correctly removed! "
"(StopListening should have been called)");
if (sIOKitFramework) {
dlclose(sIOKitFramework);
}
}
void
MacPowerInformationService::BeginListening()
{
// Set ourselves up to be notified about changes.
MOZ_ASSERT(!mRunLoopSource, "IOPS Notification Loop Source already set up. "
"(StopListening should have been called)");
mRunLoopSource = ::IOPSNotificationCreateRunLoopSource(HandleChange, this);
if (mRunLoopSource) {
::CFRunLoopAddSource(::CFRunLoopGetCurrent(), mRunLoopSource,
kCFRunLoopDefaultMode);
// Invoke our callback now so we have data if GetCurrentBatteryInformation is
// called before a change happens.
HandleChange(this);
mShouldNotify = true;
}
}
void
MacPowerInformationService::StopListening()
{
MOZ_ASSERT(mRunLoopSource, "IOPS Notification Loop Source not set up. "
"(StopListening without BeginListening)");
::CFRunLoopRemoveSource(::CFRunLoopGetCurrent(), mRunLoopSource,
kCFRunLoopDefaultMode);
mRunLoopSource = nullptr;
}
void
MacPowerInformationService::HandleChange(void* aContext) {
MacPowerInformationService* power =
static_cast<MacPowerInformationService*>(aContext);
CFTypeRef data = ::IOPSCopyPowerSourcesInfo();
if (!data) {
::CFRelease(data);
return;
}
// Get the list of power sources.
CFArrayRef list = ::IOPSCopyPowerSourcesList(data);
if (!list) {
::CFRelease(list);
return;
}
// Default values. These will be used if there are 0 sources or we can't find
// better information.
double level = kDefaultLevel;
double charging = kDefaultCharging;
double remainingTime = kDefaultRemainingTime;
// Look for the first battery power source to give us the information we need.
// Usually there's only 1 available, depending on current power source.
for (CFIndex i = 0; i < ::CFArrayGetCount(list); ++i) {
CFTypeRef source = ::CFArrayGetValueAtIndex(list, i);
CFDictionaryRef currPowerSourceDesc = ::IOPSGetPowerSourceDescription(data, source);
if (!currPowerSourceDesc) {
continue;
}
if (sIOPSGetTimeRemainingEstimate) {
// See if we can get a time estimate.
CFTimeInterval estimate = sIOPSGetTimeRemainingEstimate();
if (estimate == kIOPSTimeRemainingUnlimited || estimate == kIOPSTimeRemainingUnknown) {
remainingTime = kUnknownRemainingTime;
} else {
remainingTime = estimate;
}
}
// Get a battery level estimate. This key is required.
int currentCapacity = 0;
const void* cfRef = ::CFDictionaryGetValue(currPowerSourceDesc, CFSTR(kIOPSCurrentCapacityKey));
::CFNumberGetValue((CFNumberRef)cfRef, kCFNumberSInt32Type, &currentCapacity);
// This key is also required.
int maxCapacity = 0;
cfRef = ::CFDictionaryGetValue(currPowerSourceDesc, CFSTR(kIOPSMaxCapacityKey));
::CFNumberGetValue((CFNumberRef)cfRef, kCFNumberSInt32Type, &maxCapacity);
if (maxCapacity > 0) {
level = static_cast<double>(currentCapacity)/static_cast<double>(maxCapacity);
}
// Find out if we're charging.
// This key is optional, we fallback to kDefaultCharging if the current power
// source doesn't have that info.
if(::CFDictionaryGetValueIfPresent(currPowerSourceDesc, CFSTR(kIOPSIsChargingKey), &cfRef)) {
charging = ::CFBooleanGetValue((CFBooleanRef)cfRef);
}
break;
}
bool isNewData = level != power->mLevel || charging != power->mCharging ||
remainingTime != power->mRemainingTime;
power->mRemainingTime = remainingTime;
power->mCharging = charging;
power->mLevel = level;
// Notify the observers if stuff changed.
if (power->mShouldNotify && isNewData) {
hal::NotifyBatteryChange(hal::BatteryInformation(power->mLevel,
power->mCharging,
power->mRemainingTime));
}
::CFRelease(data);
::CFRelease(list);
}
} // namespace hal_impl
} // namespace mozilla

View File

@ -78,6 +78,7 @@ nsGIFDecoder2::nsGIFDecoder2(RasterImage &aImage, imgIDecoderObserver* aObserver
, mCurrentRow(-1)
, mLastFlushedRow(-1)
, mImageData(nullptr)
, mColormap(nullptr)
, mOldColor(0)
, mCurrentFrame(-1)
, mCurrentPass(0)
@ -187,6 +188,14 @@ nsresult nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
mGIFStruct.width, mGIFStruct.height,
format, aDepth, &mImageData, &imageDataLength,
&mColormap, &mColormapSize);
// While EnsureFrame can reuse frames, we unconditionally increment
// mGIFStruct.images_decoded when we're done with a frame, so we both can
// and need to zero out the colormap and image data after every call to
// EnsureFrame.
if (NS_SUCCEEDED(rv) && mColormap) {
memset(mColormap, 0, mColormapSize);
}
} else {
// Regardless of depth of input, image is decoded into 24bit RGB
rv = mImage.EnsureFrame(mGIFStruct.images_decoded,
@ -198,6 +207,8 @@ nsresult nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
if (NS_FAILED(rv))
return rv;
memset(mImageData, 0, imageDataLength);
mImage.SetFrameDisposalMethod(mGIFStruct.images_decoded,
mGIFStruct.disposal_method);
@ -762,21 +773,45 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, uint32_t aCount)
break;
case gif_extension:
// Comment taken directly from WebKit's GIFImageReader.cpp.
//
// The GIF spec mandates lengths for three of the extensions below.
// However, it's possible for GIFs in the wild to deviate. For example,
// some GIFs that embed ICC color profiles using gif_application_extension
// violate the spec and treat this extension block like a sort of
// "extension + data" block, giving a size greater than 11 and filling the
// remaining bytes with data (then following with more data blocks as
// needed), instead of placing a true data block just after the 11 byte
// extension block.
//
// Accordingly, if the specified length is larger than the required value,
// we use it. If it's smaller, then we enforce the spec value, because the
// parsers for these extensions expect to have the specified number of
// bytes available, and if we don't ensure that, they could read off the
// end of the heap buffer. (In this case, it's likely the GIF is corrupt
// and we'll soon fail to decode anyway.)
mGIFStruct.bytes_to_consume = q[1];
if (mGIFStruct.bytes_to_consume) {
switch (*q) {
case GIF_GRAPHIC_CONTROL_LABEL:
mGIFStruct.state = gif_control_extension;
mGIFStruct.bytes_to_consume = NS_MAX(mGIFStruct.bytes_to_consume, 4u);
break;
case GIF_APPLICATION_EXTENSION_LABEL:
mGIFStruct.state = gif_application_extension;
mGIFStruct.bytes_to_consume = NS_MAX(mGIFStruct.bytes_to_consume, 11u);
break;
case GIF_PLAIN_TEXT_LABEL:
mGIFStruct.state = gif_skip_block;
mGIFStruct.bytes_to_consume = NS_MAX(mGIFStruct.bytes_to_consume, 12u);
break;
case GIF_COMMENT_LABEL:
mGIFStruct.state = gif_consume_comment;
break;
default:
mGIFStruct.state = gif_skip_block;
}

View File

@ -1593,7 +1593,7 @@ RasterImage::SourceDataComplete()
}
nsresult
RasterImage::NewSourceData(const char* aMimeType)
RasterImage::NewSourceData()
{
nsresult rv;
@ -1628,8 +1628,6 @@ RasterImage::NewSourceData(const char* aMimeType)
mDecoded = false;
mHasSourceData = false;
mSourceDataMimeType.Assign(aMimeType);
// We're decode-on-load here. Open up a new decoder just like what happens when
// we call Init() for decode-on-load images.
rv = InitDecoder(/* aDoSizeDecode = */ false);

View File

@ -269,7 +269,7 @@ public:
nsresult SourceDataComplete();
/* Called for multipart images when there's a new source image to add. */
nsresult NewSourceData(const char *aMimeType);
nsresult NewSourceData();
/**
* A hint of the number of bytes of source data that the image contains. If

View File

@ -79,11 +79,18 @@ NS_IMPL_ISUPPORTS8(imgRequest,
nsIInterfaceRequestor,
nsIAsyncVerifyRedirectCallback)
imgRequest::imgRequest(imgLoader* aLoader) :
mLoader(aLoader), mValidator(nullptr), mImageSniffers("image-sniffing-services"),
mInnerWindowId(0), mCORSMode(imgIRequest::CORS_NONE),
mDecodeRequested(false), mIsMultiPartChannel(false), mGotData(false),
mIsInCache(false), mBlockingOnload(false)
imgRequest::imgRequest(imgLoader* aLoader)
: mLoader(aLoader)
, mValidator(nullptr)
, mImageSniffers("image-sniffing-services")
, mInnerWindowId(0)
, mCORSMode(imgIRequest::CORS_NONE)
, mDecodeRequested(false)
, mIsMultiPartChannel(false)
, mGotData(false)
, mIsInCache(false)
, mBlockingOnload(false)
, mResniffMimeType(false)
{
// Register our pref observers if we haven't yet.
if (NS_UNLIKELY(!gInitializedPrefCaches)) {
@ -787,22 +794,18 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
NS_ABORT_IF_FALSE(mIsMultiPartChannel || !mImage,
"Already have an image for non-multipart request");
// If we're multipart, and our image is initialized, fix things up for another round
// If we're multipart and about to load another image, signal so we can
// detect the mime type in OnDataAvailable.
if (mIsMultiPartChannel && mImage) {
// Update the content type for this new part
nsCOMPtr<nsIChannel> partChan(do_QueryInterface(aRequest));
partChan->GetContentType(mContentType);
if (mContentType.EqualsLiteral(SVG_MIMETYPE) ||
mImage->GetType() == imgIContainer::TYPE_VECTOR) {
// mImage won't be reusable due to format change or a new SVG part
// Reset the tracker and forget that we have data for OnDataAvailable to
// treat its next call as a fresh image.
mStatusTracker = new imgStatusTracker(nullptr);
mGotData = false;
} else if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
// Inform the RasterImage that we have new source data
static_cast<RasterImage*>(mImage.get())->NewSourceData(mContentType.get());
}
mResniffMimeType = true;
if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
// Tell the RasterImage to reinitialize itself. We have to do this in
// OnStartRequest so that its state machine is always in a consistent
// state.
// Note that if our MIME type changes, mImage will be replaced with a
// new object.
static_cast<RasterImage*>(mImage.get())->NewSourceData();
}
}
/*
@ -935,6 +938,12 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt,
return NS_OK;
}
struct mimetype_closure
{
imgRequest* request;
nsACString* newType;
};
/* prototype for these defined below */
static NS_METHOD sniff_mimetype_callback(nsIInputStream* in, void* closure, const char* fromRawSegment,
uint32_t toOffset, uint32_t count, uint32_t *writeCount);
@ -953,31 +962,33 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
nsresult rv;
uint16_t imageType;
if (mGotData) {
imageType = mImage->GetType();
} else {
if (!mGotData || mResniffMimeType) {
LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable |First time through... finding mimetype|");
mGotData = true;
mimetype_closure closure;
nsAutoCString newType;
closure.request = this;
closure.newType = &newType;
/* look at the first few bytes and see if we can tell what the data is from that
* since servers tend to lie. :(
*/
uint32_t out;
inStr->ReadSegments(sniff_mimetype_callback, this, count, &out);
inStr->ReadSegments(sniff_mimetype_callback, &closure, count, &out);
#ifdef DEBUG
/* NS_WARNING if the content type from the channel isn't the same if the sniffing */
#endif
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
if (mContentType.IsEmpty()) {
if (newType.IsEmpty()) {
LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable |sniffing of mimetype failed|");
rv = NS_ERROR_FAILURE;
if (chan) {
rv = chan->GetContentType(mContentType);
rv = chan->GetContentType(newType);
}
if (NS_FAILED(rv)) {
@ -993,140 +1004,162 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
LOG_MSG(gImgLog, "imgRequest::OnDataAvailable", "Got content type from the channel");
}
/* now we have mimetype, so we can infer the image type that we want */
if (mContentType.EqualsLiteral(SVG_MIMETYPE)) {
mImage = new VectorImage(mStatusTracker.forget());
} else {
mImage = new RasterImage(mStatusTracker.forget());
}
mImage->SetInnerWindowID(mInnerWindowId);
imageType = mImage->GetType();
// If we're a regular image and this is the first call to OnDataAvailable,
// this will always be true. If we've resniffed our MIME type (i.e. we're a
// multipart/x-mixed-replace image), we have to be able to switch our image
// type and decoder.
// We always reinitialize for SVGs, because they have no way of
// reinitializing themselves.
if (mContentType != newType || newType.EqualsLiteral(SVG_MIMETYPE)) {
mContentType = newType;
// Notify any imgRequestProxys that are observing us that we have an Image.
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
iter.GetNext()->SetImage(mImage);
}
/* set our mimetype as a property */
nsCOMPtr<nsISupportsCString> contentType(do_CreateInstance("@mozilla.org/supports-cstring;1"));
if (contentType) {
contentType->SetData(mContentType);
mProperties->Set("type", contentType);
}
/* set our content disposition as a property */
nsAutoCString disposition;
if (chan) {
chan->GetContentDispositionHeader(disposition);
}
if (!disposition.IsEmpty()) {
nsCOMPtr<nsISupportsCString> contentDisposition(do_CreateInstance("@mozilla.org/supports-cstring;1"));
if (contentDisposition) {
contentDisposition->SetData(disposition);
mProperties->Set("content-disposition", contentDisposition);
// If we've resniffed our MIME type and it changed, we need to create a
// new status tracker to give to the image, because we don't have one of
// our own any more.
if (mResniffMimeType) {
NS_ABORT_IF_FALSE(mIsMultiPartChannel, "Resniffing a non-multipart image");
mStatusTracker = new imgStatusTracker(nullptr);
}
}
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnDataAvailable", "content type", mContentType.get());
mResniffMimeType = false;
//
// Figure out our Image initialization flags
//
/* now we have mimetype, so we can infer the image type that we want */
if (mContentType.EqualsLiteral(SVG_MIMETYPE)) {
mImage = new VectorImage(mStatusTracker.forget());
} else {
mImage = new RasterImage(mStatusTracker.forget());
}
mImage->SetInnerWindowID(mInnerWindowId);
// We default to the static globals
bool isDiscardable = gDiscardable;
bool doDecodeOnDraw = gDecodeOnDraw;
// Notify any imgRequestProxys that are observing us that we have an Image.
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
iter.GetNext()->SetImage(mImage);
}
// We want UI to be as snappy as possible and not to flicker. Disable discarding
// and decode-on-draw for chrome URLS
bool isChrome = false;
rv = mURI->SchemeIs("chrome", &isChrome);
if (NS_SUCCEEDED(rv) && isChrome)
isDiscardable = doDecodeOnDraw = false;
/* set our mimetype as a property */
nsCOMPtr<nsISupportsCString> contentType(do_CreateInstance("@mozilla.org/supports-cstring;1"));
if (contentType) {
contentType->SetData(mContentType);
mProperties->Set("type", contentType);
}
// We don't want resources like the "loading" icon to be discardable or
// decode-on-draw either.
bool isResource = false;
rv = mURI->SchemeIs("resource", &isResource);
if (NS_SUCCEEDED(rv) && isResource)
isDiscardable = doDecodeOnDraw = false;
/* set our content disposition as a property */
nsAutoCString disposition;
if (chan) {
chan->GetContentDispositionHeader(disposition);
}
if (!disposition.IsEmpty()) {
nsCOMPtr<nsISupportsCString> contentDisposition(do_CreateInstance("@mozilla.org/supports-cstring;1"));
if (contentDisposition) {
contentDisposition->SetData(disposition);
mProperties->Set("content-disposition", contentDisposition);
}
}
// For multipart/x-mixed-replace, we basically want a direct channel to the
// decoder. Disable both for this case as well.
if (mIsMultiPartChannel)
isDiscardable = doDecodeOnDraw = false;
LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnDataAvailable", "content type", mContentType.get());
// We have all the information we need
uint32_t imageFlags = Image::INIT_FLAG_NONE;
if (isDiscardable)
imageFlags |= Image::INIT_FLAG_DISCARDABLE;
if (doDecodeOnDraw)
imageFlags |= Image::INIT_FLAG_DECODE_ON_DRAW;
if (mIsMultiPartChannel)
imageFlags |= Image::INIT_FLAG_MULTIPART;
//
// Figure out our Image initialization flags
//
// Get our URI string
nsAutoCString uriString;
rv = mURI->GetSpec(uriString);
if (NS_FAILED(rv))
uriString.Assign("<unknown image URI>");
// We default to the static globals
bool isDiscardable = gDiscardable;
bool doDecodeOnDraw = gDecodeOnDraw;
// Initialize the image that we created above. For RasterImages, this
// instantiates a decoder behind the scenes, so if we don't have a decoder
// for this mimetype we'll find out about it here.
rv = mImage->Init(this, mContentType.get(), uriString.get(), imageFlags);
if (NS_FAILED(rv)) { // Probably bad mimetype
// We want UI to be as snappy as possible and not to flicker. Disable discarding
// and decode-on-draw for chrome URLS
bool isChrome = false;
rv = mURI->SchemeIs("chrome", &isChrome);
if (NS_SUCCEEDED(rv) && isChrome)
isDiscardable = doDecodeOnDraw = false;
this->Cancel(rv);
return NS_BINDING_ABORTED;
}
// We don't want resources like the "loading" icon to be discardable or
// decode-on-draw either.
bool isResource = false;
rv = mURI->SchemeIs("resource", &isResource);
if (NS_SUCCEEDED(rv) && isResource)
isDiscardable = doDecodeOnDraw = false;
if (imageType == imgIContainer::TYPE_RASTER) {
/* Use content-length as a size hint for http channels. */
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
if (httpChannel) {
nsAutoCString contentLength;
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-length"),
contentLength);
if (NS_SUCCEEDED(rv)) {
int32_t len = contentLength.ToInteger(&rv);
// For multipart/x-mixed-replace, we basically want a direct channel to the
// decoder. Disable both for this case as well.
if (mIsMultiPartChannel)
isDiscardable = doDecodeOnDraw = false;
// Pass anything usable on so that the RasterImage can preallocate
// its source buffer
if (len > 0) {
uint32_t sizeHint = (uint32_t) len;
sizeHint = NS_MIN<uint32_t>(sizeHint, 20000000); /* Bound by something reasonable */
RasterImage* rasterImage = static_cast<RasterImage*>(mImage.get());
rv = rasterImage->SetSourceSizeHint(sizeHint);
if (NS_FAILED(rv)) {
// Flush memory, try to get some back, and try again
rv = nsMemory::HeapMinimize(true);
nsresult rv2 = rasterImage->SetSourceSizeHint(sizeHint);
// If we've still failed at this point, things are going downhill
if (NS_FAILED(rv) || NS_FAILED(rv2)) {
NS_WARNING("About to hit OOM in imagelib!");
// We have all the information we need
uint32_t imageFlags = Image::INIT_FLAG_NONE;
if (isDiscardable)
imageFlags |= Image::INIT_FLAG_DISCARDABLE;
if (doDecodeOnDraw)
imageFlags |= Image::INIT_FLAG_DECODE_ON_DRAW;
if (mIsMultiPartChannel)
imageFlags |= Image::INIT_FLAG_MULTIPART;
// Get our URI string
nsAutoCString uriString;
rv = mURI->GetSpec(uriString);
if (NS_FAILED(rv))
uriString.Assign("<unknown image URI>");
// Initialize the image that we created above. For RasterImages, this
// instantiates a decoder behind the scenes, so if we don't have a decoder
// for this mimetype we'll find out about it here.
rv = mImage->Init(this, mContentType.get(), uriString.get(), imageFlags);
// We allow multipart images to fail to initialize without cancelling the
// load because subsequent images might be fine.
if (NS_FAILED(rv) && !mIsMultiPartChannel) { // Probably bad mimetype
this->Cancel(rv);
return NS_BINDING_ABORTED;
}
if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
/* Use content-length as a size hint for http channels. */
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
if (httpChannel) {
nsAutoCString contentLength;
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-length"),
contentLength);
if (NS_SUCCEEDED(rv)) {
int32_t len = contentLength.ToInteger(&rv);
// Pass anything usable on so that the RasterImage can preallocate
// its source buffer
if (len > 0) {
uint32_t sizeHint = (uint32_t) len;
sizeHint = NS_MIN<uint32_t>(sizeHint, 20000000); /* Bound by something reasonable */
RasterImage* rasterImage = static_cast<RasterImage*>(mImage.get());
rv = rasterImage->SetSourceSizeHint(sizeHint);
if (NS_FAILED(rv)) {
// Flush memory, try to get some back, and try again
rv = nsMemory::HeapMinimize(true);
nsresult rv2 = rasterImage->SetSourceSizeHint(sizeHint);
// If we've still failed at this point, things are going downhill
if (NS_FAILED(rv) || NS_FAILED(rv2)) {
NS_WARNING("About to hit OOM in imagelib!");
}
}
}
}
}
}
}
if (imageType == imgIContainer::TYPE_RASTER) {
// If we were waiting on the image to do something, now's our chance.
if (mDecodeRequested) {
mImage->RequestDecode();
if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
// If we were waiting on the image to do something, now's our chance.
if (mDecodeRequested) {
mImage->RequestDecode();
}
} else { // mImage->GetType() == imgIContainer::TYPE_VECTOR
nsCOMPtr<nsIStreamListener> imageAsStream = do_QueryInterface(mImage);
NS_ABORT_IF_FALSE(imageAsStream,
"SVG-typed Image failed QI to nsIStreamListener");
imageAsStream->OnStartRequest(aRequest, nullptr);
}
} else { // imageType == imgIContainer::TYPE_VECTOR
nsCOMPtr<nsIStreamListener> imageAsStream = do_QueryInterface(mImage);
NS_ABORT_IF_FALSE(imageAsStream,
"SVG-typed Image failed QI to nsIStreamListener");
imageAsStream->OnStartRequest(aRequest, nullptr);
}
}
if (imageType == imgIContainer::TYPE_RASTER) {
if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
// WriteToRasterImage always consumes everything it gets
// if it doesn't run out of memory
uint32_t bytesRead;
@ -1135,7 +1168,7 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
count, &bytesRead);
NS_ABORT_IF_FALSE(bytesRead == count || mImage->HasError(),
"WriteToRasterImage should consume everything or the image must be in error!");
} else { // imageType == imgIContainer::TYPE_VECTOR
} else { // mImage->GetType() == imgIContainer::TYPE_VECTOR
nsCOMPtr<nsIStreamListener> imageAsStream = do_QueryInterface(mImage);
rv = imageAsStream->OnDataAvailable(aRequest, ctxt, inStr,
sourceOffset, count);
@ -1152,31 +1185,31 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
}
static NS_METHOD sniff_mimetype_callback(nsIInputStream* in,
void* closure,
void* data,
const char* fromRawSegment,
uint32_t toOffset,
uint32_t count,
uint32_t *writeCount)
{
imgRequest *request = static_cast<imgRequest*>(closure);
mimetype_closure* closure = static_cast<mimetype_closure*>(data);
NS_ASSERTION(request, "request is null!");
NS_ASSERTION(closure, "closure is null!");
if (count > 0)
request->SniffMimeType(fromRawSegment, count);
closure->request->SniffMimeType(fromRawSegment, count, *closure->newType);
*writeCount = 0;
return NS_ERROR_FAILURE;
}
void
imgRequest::SniffMimeType(const char *buf, uint32_t len)
imgRequest::SniffMimeType(const char *buf, uint32_t len, nsACString& newType)
{
imgLoader::GetMimeTypeFromContent(buf, len, mContentType);
imgLoader::GetMimeTypeFromContent(buf, len, newType);
// The vast majority of the time, imgLoader will find a gif/jpeg/png image
// and fill mContentType with the sniffed MIME type.
if (!mContentType.IsEmpty())
// and fill newType with the sniffed MIME type.
if (!newType.IsEmpty())
return;
// When our sniffing fails, we want to query registered image decoders
@ -1186,8 +1219,8 @@ imgRequest::SniffMimeType(const char *buf, uint32_t len)
uint32_t length = sniffers.Count();
for (uint32_t i = 0; i < length; ++i) {
nsresult rv =
sniffers[i]->GetMIMETypeFromContent(nullptr, (const uint8_t *) buf, len, mContentType);
if (NS_SUCCEEDED(rv) && !mContentType.IsEmpty()) {
sniffers[i]->GetMIMETypeFromContent(nullptr, (const uint8_t *) buf, len, newType);
if (NS_SUCCEEDED(rv) && !newType.IsEmpty()) {
return;
}
}

View File

@ -71,7 +71,7 @@ public:
// aNotify==false still sends OnStopRequest.
nsresult RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, bool aNotify);
void SniffMimeType(const char *buf, uint32_t len);
void SniffMimeType(const char *buf, uint32_t len, nsACString& newType);
// Cancel, but also ensure that all work done in Init() is undone. Call this
// only when the channel has failed to open, and so calling Cancel() on it
@ -234,6 +234,7 @@ private:
bool mGotData : 1;
bool mIsInCache : 1;
bool mBlockingOnload : 1;
bool mResniffMimeType : 1;
};
#endif

View File

@ -55,10 +55,12 @@ MOCHITEST_FILES = imgutils.js \
bug671906.sjs \
test_bug671906.html \
test_bug733553.html \
bug733553-iframe.html \
bug733553.sjs \
bug733553-informant.sjs \
animated-gif2.gif \
invalid.jpg \
bad.jpg \
rillybad.jpg \
test_bug767779.html \
bug767779.sjs \
animated-gif_trailing-garbage.gif \

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,7 +0,0 @@
<html>
<head>
<title>Bug 733553 iframe</title>
<body>
<img src="bug733553.sjs" id="image1" />
</body>
</html>

View File

@ -2,15 +2,24 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var bodyPartIndex = 0;
var bodyPartIndex = -1;
var bodyParts = [
["red.png", "image/png"],
["animated-gif2.gif", "image/gif"],
["red.png", "image/png"],
["lime100x100.svg", "image/svg+xml"],
["lime100x100.svg", "image/svg+xml"],
["animated-gif2.gif", "image/gif"],
["red.png", "image/png"],
["lime100x100.svg", "image/svg+xml"]
["damon.jpg", "image/jpeg"],
["damon.jpg", "application/octet-stream"],
["damon.jpg", "image/jpeg"],
["rillybad.jpg", "application/x-unknown-content-type"],
["damon.jpg", "image/jpeg"],
["bad.jpg", "image/jpeg"],
["red.png", "image/png"],
["invalid.jpg", "image/jpeg"],
["animated-gif2.gif", "image/gif"]
];
var timer = Components.classes["@mozilla.org/timer;1"];
var partTimer = timer.createInstance(Components.interfaces.nsITimer);
@ -34,6 +43,7 @@ function getFileAsInputStream(aFilename) {
function handleRequest(request, response)
{
setSharedState("next-part", "-1");
response.setHeader("Content-Type",
"multipart/x-mixed-replace;boundary=BOUNDARYOMG", false);
response.setHeader("Cache-Control", "no-cache", false);
@ -47,13 +57,11 @@ function handleRequest(request, response)
function sendParts(response) {
let wait = false;
let nextPart = parseInt(getSharedState("next-part"), 10);
if (nextPart) {
if (nextPart == bodyPartIndex) {
// Haven't been signaled yet, remain in holding pattern
wait = true;
} else {
bodyPartIndex = nextPart;
}
if (nextPart == bodyPartIndex) {
// Haven't been signaled yet, remain in holding pattern
wait = true;
} else {
bodyPartIndex = nextPart;
}
if (bodyParts.length > bodyPartIndex) {
let callback;

Binary file not shown.

View File

@ -9,7 +9,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=733553
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<body onload="initializeOnload()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=733553">Mozilla Bug 733553</a>
<p id="display"></p>
<pre id="test">
@ -17,53 +17,66 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=733553
SimpleTest.waitForExplicitFinish();
var testIndex = 0;
var testIndex = -1;
var testParts = [
[1, "red.png"],
[40, "animated-gif2.gif"],
[1, "red.png"],
[100, "lime100x100.svg"],
[100, "lime100x100.svg"],
[40, "animated-gif2.gif"],
[1, "red.png"]
[1, "red.png"],
[80, "damon.jpg"],
[80, "damon.jpg"],
[80, "damon.jpg"],
// An invalid image (from bug 787899) that is further delivered with a
// "special" bad MIME type that indicates that the necko
// multipart/x-mixed-replace parser wasn't able to parse it.
[0, "rillybad.jpg"],
// Bad.jpg is bad such that it sniffs as a JPEG, and therefore doesn't change
// what's been decoded (since the RasterImage isn't deleted), so its width
// needs to be the same as the previous image.
[80, "damon.jpg"],
[80, "bad.jpg"],
[1, "red.png"],
[0, "invalid.jpg"],
[40, "animated-gif2.gif"]
];
// We'll append the part number to this, and tell the informant
const BASE_URL = "bug733553-informant.sjs?";
function initializeOnload() {
var iframeelem = document.getElementById('test-iframe');
var firstimg = iframeelem.contentDocument.getElementById('image1');
var firstimg = document.createElement('img');
firstimg.addEventListener("load", imageLoad, false);
firstimg.addEventListener("error", imageLoad, false);
firstimg.src = "bug733553.sjs";
document.getElementById('content').appendChild(firstimg);
// Really ready for first, but who's counting
readyForNext();
}
function readyForNext() {
var loader = document.getElementById("loader");
if (loader) {
testIndex++;
loader.src = BASE_URL + testIndex;
}
loader.src = BASE_URL + ++testIndex;
}
function imageLoad(aEvent) {
if (testParts.length > testIndex) {
var [width, fileName] = testParts[testIndex];
if (aEvent.target.width == width) {
is(aEvent.target.width, width,
"Test " + testIndex + " " + fileName + " width correct");
readyForNext();
}
} else {
aEvent.target.removeEventListener("load", imageLoad, false);
var loader = document.getElementById("loader");
readyForNext();
var [width, fileName] = testParts[testIndex];
is(aEvent.target.width, width,
"Test " + testIndex + " " + fileName + " width correct");
if ((testParts.length - 1) == testIndex) {
SimpleTest.finish();
} else {
readyForNext();
}
}
</script>
</pre>
<div id="content"> <!-- style="display: none" -->
<iframe id="test-iframe" src="http://mochi.test:8888/tests/image/test/mochitest/bug733553-iframe.html" onload="initializeOnload()"></iframe>
<iframe id="loader"></iframe>
</div>
</body>

View File

@ -5,6 +5,7 @@
include "ipc/IPCMessageUtils.h";
using mozilla::void_t;
include protocol PBlob;
namespace mozilla {
namespace ipc {
@ -36,6 +37,11 @@ struct MultiplexInputStreamParams
bool startedReadingCurrent;
};
struct RemoteInputStreamParams
{
PBlob remoteBlob;
};
union InputStreamParams
{
StringInputStreamParams;
@ -44,6 +50,7 @@ union InputStreamParams
BufferedInputStreamParams;
MIMEInputStreamParams;
MultiplexInputStreamParams;
RemoteInputStreamParams;
};
union OptionalInputStreamParams

View File

@ -7,16 +7,22 @@
#include "nsIIPCSerializableInputStream.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/ipc/Blob.h"
#include "nsComponentManagerUtils.h"
#include "nsDebug.h"
#include "nsID.h"
#include "nsIDOMFile.h"
#include "nsIXULRuntime.h"
#include "nsMIMEInputStream.h"
#include "nsMultiplexInputStream.h"
#include "nsNetCID.h"
#include "nsStringStream.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
using namespace mozilla::ipc;
using mozilla::dom::BlobChild;
using mozilla::dom::BlobParent;
namespace {
@ -100,6 +106,29 @@ DeserializeInputStream(const InputStreamParams& aParams)
serializable = do_CreateInstance(kMultiplexInputStreamCID);
break;
// When the input stream already exists in this process, all we need to do
// is retrieve the original instead of sending any data over the wire.
case InputStreamParams::TRemoteInputStreamParams: {
nsCOMPtr<nsIDOMBlob> domBlob;
const RemoteInputStreamParams& params =
aParams.get_RemoteInputStreamParams();
domBlob = params.remoteBlobParent() ?
static_cast<BlobParent*>(params.remoteBlobParent())->GetBlob() :
static_cast<BlobChild*>(params.remoteBlobChild())->GetBlob();
MOZ_ASSERT(domBlob, "Invalid blob contents");
// If fetching the internal stream fails, we ignore it and return a
// null stream.
nsCOMPtr<nsIInputStream> stream;
nsresult rv = domBlob->GetInternalStream(getter_AddRefs(stream));
if (NS_FAILED(rv) || !stream) {
NS_WARNING("Couldn't obtain a valid stream from the blob");
}
return stream.forget();
}
default:
MOZ_ASSERT(false, "Unknown params!");
return nullptr;

View File

@ -131,6 +131,7 @@ CPPSRCS = \
SPSProfiler.cpp \
TokenStream.cpp \
TestingFunctions.cpp \
Profilers.cpp \
LifoAlloc.cpp \
Eval.cpp \
MapObject.cpp \

View File

@ -226,6 +226,13 @@ ArrayLikeToIndexVector(JSContext *cx, HandleObject obj, IndexVector &indices)
return true;
}
static inline bool
IdIsInBoundsIndex(JSContext *cx, HandleObject obj, HandleId id)
{
uint32_t i;
return js_IdIsIndex(id, &i) && i < ParallelArrayObject::as(obj)->outermostDimension();
}
template <bool impl(JSContext *, CallArgs)>
static inline
JSBool NonGenericMethod(JSContext *cx, unsigned argc, Value *vp)
@ -820,7 +827,7 @@ Class ParallelArrayObject::class_ = {
getGeneric,
getProperty,
getElement,
NULL, // getElementIfPresent
getElementIfPresent,
getSpecial,
setGeneric,
setProperty,
@ -1034,6 +1041,15 @@ ParallelArrayObject::create(JSContext *cx, HandleObject buffer, uint32_t offset,
result->setSlot(SLOT_BUFFER, ObjectValue(*buffer));
result->setSlot(SLOT_BUFFER_OFFSET, Int32Value(static_cast<int32_t>(offset)));
// ParallelArray objects are frozen, so mark it as non-extensible here.
Shape *empty = EmptyShape::getInitialShape(cx, &class_,
result->getProto(), result->getParent(),
result->getAllocKind(),
BaseShape::NOT_EXTENSIBLE);
if (!empty)
return false;
result->setLastPropertyInfallible(empty);
// This is usually args.rval() from build or construct.
vp.setObject(*result);
@ -1430,7 +1446,14 @@ ParallelArrayObject::get(JSContext *cx, CallArgs args)
bool
ParallelArrayObject::dimensionsGetter(JSContext *cx, CallArgs args)
{
args.rval().setObject(*(as(&args.thisv().toObject())->dimensionArray()));
RootedObject dimArray(cx, as(&args.thisv().toObject())->dimensionArray());
RootedObject copy(cx, NewDenseCopiedArray(cx, dimArray->getDenseArrayInitializedLength(),
dimArray->getDenseArrayElements()));
if (!copy)
return false;
// Reuse the existing dimension array's type.
copy->setType(dimArray->type());
args.rval().setObject(*copy);
return true;
}
@ -1507,7 +1530,7 @@ ParallelArrayObject::toStringBufferImpl(JSContext *cx, IndexInfo &iv, bool useLo
if (!elem->isNullOrUndefined()) {
if (useLocale) {
tmp = *elem;
JSObject *robj = ToObject(cx, tmp);
RootedObject robj(cx, ToObject(cx, tmp));
if (!robj)
return false;
@ -1589,12 +1612,6 @@ ParallelArrayObject::lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
if (js_IdIsIndex(id, &i))
return lookupElement(cx, obj, i, objp, propp);
if (JSID_IS_ATOM(id, cx->names().length)) {
MarkNonNativePropertyFound(obj, propp);
objp.set(obj);
return true;
}
RootedObject proto(cx, obj->getProto());
if (proto)
return JSObject::lookupGeneric(cx, proto, id, objp, propp);
@ -1637,11 +1654,27 @@ ParallelArrayObject::lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecia
}
JSBool
ParallelArrayObject::defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue Value,
ParallelArrayObject::defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
uint32_t i;
if (js_IdIsIndex(id, &i) && i < as(obj)->outermostDimension()) {
RootedValue existingValue(cx);
if (!as(obj)->getParallelArrayElement(cx, i, &existingValue))
return false;
bool same;
if (!SameValue(cx, value, existingValue, &same))
return false;
if (!same)
return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
} else {
RootedValue tmp(cx, value);
if (!setGeneric(cx, obj, id, &tmp, true))
return false;
}
return setGenericAttributes(cx, obj, id, &attrs);
}
JSBool
@ -1649,8 +1682,8 @@ ParallelArrayObject::defineProperty(JSContext *cx, HandleObject obj,
HandlePropertyName name, HandleValue value,
JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx, NameToId(name));
return defineGeneric(cx, obj, id, value, getter, setter, attrs);
}
JSBool
@ -1658,8 +1691,10 @@ ParallelArrayObject::defineElement(JSContext *cx, HandleObject obj,
uint32_t index, HandleValue value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx);
if (!IndexToId(cx, index, id.address()))
return false;
return defineGeneric(cx, obj, id, value, getter, setter, attrs);
}
JSBool
@ -1667,20 +1702,24 @@ ParallelArrayObject::defineSpecial(JSContext *cx, HandleObject obj,
HandleSpecialId sid, HandleValue value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx, SPECIALID_TO_JSID(sid));
return defineGeneric(cx, obj, id, value, getter, setter, attrs);
}
JSBool
ParallelArrayObject::getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
Value idval = IdToValue(id);
RootedValue idval(cx, IdToValue(id));
uint32_t index;
if (IsDefinitelyIndex(idval, &index))
return getElement(cx, obj, receiver, index, vp);
Rooted<SpecialId> sid(cx);
if (ValueIsSpecial(obj, &idval, sid.address(), cx))
return getSpecial(cx, obj, receiver, sid, vp);
JSAtom *atom = ToAtom(cx, idval);
if (!atom)
return false;
@ -1696,11 +1735,6 @@ JSBool
ParallelArrayObject::getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
HandlePropertyName name, MutableHandleValue vp)
{
if (name == cx->names().length) {
vp.setNumber(as(obj)->outermostDimension());
return true;
}
RootedObject proto(cx, obj->getProto());
if (proto)
return JSObject::getProperty(cx, proto, receiver, name, vp);
@ -1718,6 +1752,23 @@ ParallelArrayObject::getElement(JSContext *cx, HandleObject obj, HandleObject re
return as(obj)->getParallelArrayElement(cx, index, vp);
}
JSBool
ParallelArrayObject::getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool *present)
{
RootedParallelArrayObject source(cx, as(obj));
if (index < source->outermostDimension()) {
if (!source->getParallelArrayElement(cx, index, vp))
return false;
*present = true;
return true;
}
*present = false;
vp.setUndefined();
return true;
}
JSBool
ParallelArrayObject::getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleSpecialId sid, MutableHandleValue vp)
@ -1735,43 +1786,57 @@ JSBool
ParallelArrayObject::setGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, JSBool strict)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
JS_ASSERT(!obj->isExtensible());
if (IdIsInBoundsIndex(cx, obj, id)) {
if (strict)
return JSObject::reportReadOnly(cx, id);
if (cx->hasStrictOption())
return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
} else {
if (strict)
return obj->reportNotExtensible(cx);
if (cx->hasStrictOption())
return obj->reportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
}
return true;
}
JSBool
ParallelArrayObject::setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
MutableHandleValue vp, JSBool strict)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx, NameToId(name));
return setGeneric(cx, obj, id, vp, strict);
}
JSBool
ParallelArrayObject::setElement(JSContext *cx, HandleObject obj, uint32_t index,
MutableHandleValue vp, JSBool strict)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx);
if (!IndexToId(cx, index, id.address()))
return false;
return setGeneric(cx, obj, id, vp, strict);
}
JSBool
ParallelArrayObject::setSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
MutableHandleValue vp, JSBool strict)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx, SPECIALID_TO_JSID(sid));
return setGeneric(cx, obj, id, vp, strict);
}
JSBool
ParallelArrayObject::getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id,
unsigned *attrsp)
{
if (JSID_IS_ATOM(id, cx->names().length))
*attrsp = JSPROP_PERMANENT | JSPROP_READONLY;
else
*attrsp = JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_ENUMERATE;
*attrsp = JSPROP_PERMANENT | JSPROP_READONLY;
uint32_t i;
if (js_IdIsIndex(id, &i))
*attrsp |= JSPROP_ENUMERATE;
return true;
}
@ -1779,8 +1844,7 @@ JSBool
ParallelArrayObject::getPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name,
unsigned *attrsp)
{
if (name == cx->names().length)
*attrsp = JSPROP_PERMANENT | JSPROP_READONLY;
*attrsp = JSPROP_PERMANENT | JSPROP_READONLY;
return true;
}
@ -1804,64 +1868,87 @@ JSBool
ParallelArrayObject::setGenericAttributes(JSContext *cx, HandleObject obj, HandleId id,
unsigned *attrsp)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
if (IdIsInBoundsIndex(cx, obj, id)) {
unsigned attrs;
if (!getGenericAttributes(cx, obj, id, &attrs))
return false;
if (*attrsp != attrs)
return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
}
return obj->reportNotExtensible(cx);
}
JSBool
ParallelArrayObject::setPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name,
unsigned *attrsp)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx, NameToId(name));
return setGenericAttributes(cx, obj, id, attrsp);
}
JSBool
ParallelArrayObject::setElementAttributes(JSContext *cx, HandleObject obj, uint32_t index,
unsigned *attrsp)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx);
if (!IndexToId(cx, index, id.address()))
return false;
return setGenericAttributes(cx, obj, id, attrsp);
}
JSBool
ParallelArrayObject::setSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid,
unsigned *attrsp)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx, SPECIALID_TO_JSID(sid));
return setGenericAttributes(cx, obj, id, attrsp);
}
JSBool
ParallelArrayObject::deleteGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue rval, JSBool strict)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
if (IdIsInBoundsIndex(cx, obj, id)) {
if (strict)
return obj->reportNotConfigurable(cx, id);
if (cx->hasStrictOption()) {
if (!obj->reportNotConfigurable(cx, id, JSREPORT_STRICT | JSREPORT_WARNING))
return false;
}
rval.setBoolean(false);
return true;
}
rval.setBoolean(true);
return true;
}
JSBool
ParallelArrayObject::deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
MutableHandleValue rval, JSBool strict)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx, NameToId(name));
return deleteGeneric(cx, obj, id, rval, strict);
}
JSBool
ParallelArrayObject::deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
MutableHandleValue rval, JSBool strict)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx);
if (!IndexToId(cx, index, id.address()))
return false;
return deleteGeneric(cx, obj, id, rval, strict);
}
JSBool
ParallelArrayObject::deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
MutableHandleValue rval, JSBool strict)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PAR_ARRAY_IMMUTABLE);
return false;
RootedId id(cx, SPECIALID_TO_JSID(sid));
return deleteGeneric(cx, obj, id, rval, strict);
}
bool
@ -1870,13 +1957,12 @@ ParallelArrayObject::enumerate(JSContext *cx, HandleObject obj, unsigned flags,
{
RootedParallelArrayObject source(cx, as(obj));
if (flags & JSITER_HIDDEN && !props->append(NameToId(cx->names().length)))
return false;
// ParallelArray objects have no holes.
if (source->outermostDimension() > 0) {
for (uint32_t i = 0; i < source->outermostDimension(); i++)
props->append(INT_TO_JSID(i));
for (uint32_t i = 0; i < source->outermostDimension(); i++) {
if (!props->append(INT_TO_JSID(i)))
return false;
}
}
if (flags & JSITER_OWNONLY)

View File

@ -379,6 +379,8 @@ class ParallelArrayObject : public JSObject {
MutableHandleValue vp, JSBool strict);
static JSBool setElement(JSContext *cx, HandleObject obj, uint32_t index,
MutableHandleValue vp, JSBool strict);
static JSBool getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool *present);
static JSBool setSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
MutableHandleValue vp, JSBool strict);
static JSBool getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id,

View File

@ -0,0 +1,502 @@
/* -*- Mode: C++; tab-width: 8; 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/. */
/* Profiling-related API */
#include <stdarg.h>
#include "Profilers.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsprobes.h"
#include "jscntxtinlines.h"
#include "vm/Stack-inl.h"
#ifdef MOZ_CALLGRIND
#include <valgrind/callgrind.h>
#endif
#ifdef __APPLE__
#include "devtools/sharkctl.h"
#endif
using namespace js;
/* Thread-unsafe error management */
static char gLastError[2000];
static void
#ifdef __GNUC__
__attribute__((unused,format(printf,1,2)))
#endif
UnsafeError(const char *format, ...)
{
va_list args;
va_start(args, format);
(void) vsnprintf(gLastError, sizeof(gLastError), format, args);
va_end(args);
gLastError[sizeof(gLastError) - 1] = '\0';
}
JS_PUBLIC_API(const char *)
JS_UnsafeGetLastProfilingError()
{
return gLastError;
}
JS_PUBLIC_API(JSBool)
JS_StartProfiling(const char *profileName)
{
JSBool ok = JS_TRUE;
#if defined(MOZ_SHARK) && defined(__APPLE__)
if (!Shark::Start()) {
UnsafeError("Failed to start Shark for %s", profileName);
ok = JS_FALSE;
}
#endif
#ifdef __linux__
if (!js_StartPerf())
ok = JS_FALSE;
#endif
return ok;
}
JS_PUBLIC_API(JSBool)
JS_StopProfiling(const char *profileName)
{
JSBool ok = JS_TRUE;
#if defined(MOZ_SHARK) && defined(__APPLE__)
Shark::Stop();
#endif
#ifdef __linux__
if (!js_StopPerf())
ok = JS_FALSE;
#endif
return ok;
}
/*
* Start or stop whatever platform- and configuration-specific profiling
* backends are available.
*/
static JSBool
ControlProfilers(bool toState)
{
JSBool ok = JS_TRUE;
if (! Probes::ProfilingActive && toState) {
#if defined(MOZ_SHARK) && defined(__APPLE__)
if (!Shark::Start()) {
UnsafeError("Failed to start Shark");
ok = JS_FALSE;
}
#endif
#ifdef MOZ_CALLGRIND
if (! js_StartCallgrind()) {
UnsafeError("Failed to start Callgrind");
ok = JS_FALSE;
}
#endif
} else if (Probes::ProfilingActive && ! toState) {
#if defined(MOZ_SHARK) && defined(__APPLE__)
Shark::Stop();
#endif
#ifdef MOZ_CALLGRIND
if (! js_StopCallgrind()) {
UnsafeError("failed to stop Callgrind");
ok = JS_FALSE;
}
#endif
}
Probes::ProfilingActive = toState;
return ok;
}
/*
* Pause/resume whatever profiling mechanism is currently compiled
* in, if applicable. This will not affect things like dtrace.
*
* Do not mix calls to these APIs with calls to the individual
* profilers' pause/resume functions, because only overall state is
* tracked, not the state of each profiler.
*/
JS_PUBLIC_API(JSBool)
JS_PauseProfilers(const char *profileName)
{
return ControlProfilers(false);
}
JS_PUBLIC_API(JSBool)
JS_ResumeProfilers(const char *profileName)
{
return ControlProfilers(true);
}
JS_PUBLIC_API(JSBool)
JS_DumpProfile(const char *outfile, const char *profileName)
{
JSBool ok = JS_TRUE;
#ifdef MOZ_CALLGRIND
js_DumpCallgrind(outfile);
#endif
return ok;
}
#ifdef MOZ_PROFILING
struct RequiredStringArg {
JSContext *mCx;
char *mBytes;
RequiredStringArg(JSContext *cx, unsigned argc, jsval *vp, size_t argi, const char *caller)
: mCx(cx), mBytes(NULL)
{
if (argc <= argi) {
JS_ReportError(cx, "%s: not enough arguments", caller);
} else if (!JSVAL_IS_STRING(JS_ARGV(cx, vp)[argi])) {
JS_ReportError(cx, "%s: invalid arguments (string expected)", caller);
} else {
mBytes = JS_EncodeString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[argi]));
}
}
operator void*() {
return (void*) mBytes;
}
~RequiredStringArg() {
if (mBytes)
js_free(mBytes);
}
};
static JSBool
StartProfiling(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "startProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
StopProfiling(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "stopProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
PauseProfilers(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "pauseProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
ResumeProfilers(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "resumeProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(profileName.mBytes)));
return JS_TRUE;
}
/* Usage: DumpProfile([filename[, profileName]]) */
static JSBool
DumpProfile(JSContext *cx, unsigned argc, jsval *vp)
{
bool ret;
if (argc == 0) {
ret = JS_DumpProfile(NULL, NULL);
} else {
RequiredStringArg filename(cx, argc, vp, 0, "dumpProfile");
if (!filename)
return JS_FALSE;
if (argc == 1) {
ret = JS_DumpProfile(filename.mBytes, NULL);
} else {
RequiredStringArg profileName(cx, argc, vp, 1, "dumpProfile");
if (!profileName)
return JS_FALSE;
ret = JS_DumpProfile(filename.mBytes, profileName.mBytes);
}
}
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(ret));
return true;
}
#ifdef MOZ_SHARK
static JSBool
IgnoreAndReturnTrue(JSContext *cx, unsigned argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, JSVAL_TRUE);
return true;
}
#endif
#ifdef MOZ_CALLGRIND
static JSBool
StartCallgrind(JSContext *cx, unsigned argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartCallgrind()));
return JS_TRUE;
}
static JSBool
StopCallgrind(JSContext *cx, unsigned argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopCallgrind()));
return JS_TRUE;
}
static JSBool
DumpCallgrind(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(NULL)));
return JS_TRUE;
}
RequiredStringArg outFile(cx, argc, vp, 0, "dumpCallgrind");
if (!outFile)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(outFile.mBytes)));
return JS_TRUE;
}
#endif
static JSFunctionSpec profiling_functions[] = {
JS_FN("startProfiling", StartProfiling, 1,0),
JS_FN("stopProfiling", StopProfiling, 1,0),
JS_FN("pauseProfilers", PauseProfilers, 1,0),
JS_FN("resumeProfilers", ResumeProfilers, 1,0),
JS_FN("dumpProfile", DumpProfile, 2,0),
#ifdef MOZ_SHARK
/* Keep users of the old shark API happy. */
JS_FN("connectShark", IgnoreAndReturnTrue, 0,0),
JS_FN("disconnectShark", IgnoreAndReturnTrue, 0,0),
JS_FN("startShark", StartProfiling, 0,0),
JS_FN("stopShark", StopProfiling, 0,0),
#endif
#ifdef MOZ_CALLGRIND
JS_FN("startCallgrind", StartCallgrind, 0,0),
JS_FN("stopCallgrind", StopCallgrind, 0,0),
JS_FN("dumpCallgrind", DumpCallgrind, 1,0),
#endif
JS_FS_END
};
#endif
JS_PUBLIC_API(JSBool)
JS_DefineProfilingFunctions(JSContext *cx, JSObject *objArg)
{
RootedObject obj(cx, objArg);
assertSameCompartment(cx, obj);
#ifdef MOZ_PROFILING
return JS_DefineFunctions(cx, obj, profiling_functions);
#else
return true;
#endif
}
#ifdef MOZ_CALLGRIND
JS_FRIEND_API(JSBool)
js_StartCallgrind()
{
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_START_INSTRUMENTATION);
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_ZERO_STATS);
return true;
}
JS_FRIEND_API(JSBool)
js_StopCallgrind()
{
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_STOP_INSTRUMENTATION);
return true;
}
JS_FRIEND_API(JSBool)
js_DumpCallgrind(const char *outfile)
{
if (outfile) {
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS_AT(outfile));
} else {
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS);
}
return true;
}
#endif /* MOZ_CALLGRIND */
#ifdef __linux__
/*
* Code for starting and stopping |perf|, the Linux profiler.
*
* Output from profiling is written to mozperf.data in your cwd.
*
* To enable, set MOZ_PROFILE_WITH_PERF=1 in your environment.
*
* To pass additional parameters to |perf record|, provide them in the
* MOZ_PROFILE_PERF_FLAGS environment variable. If this variable does not
* exist, we default it to "--call-graph". (If you don't want --call-graph but
* don't want to pass any other args, define MOZ_PROFILE_PERF_FLAGS to the empty
* string.)
*
* If you include --pid or --output in MOZ_PROFILE_PERF_FLAGS, you're just
* asking for trouble.
*
* Our split-on-spaces logic is lame, so don't expect MOZ_PROFILE_PERF_FLAGS to
* work if you pass an argument which includes a space (e.g.
* MOZ_PROFILE_PERF_FLAGS="-e 'foo bar'").
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
static bool perfInitialized = false;
static pid_t perfPid = 0;
JSBool js_StartPerf()
{
const char *outfile = "mozperf.data";
if (perfPid != 0) {
UnsafeError("js_StartPerf: called while perf was already running!\n");
return false;
}
// Bail if MOZ_PROFILE_WITH_PERF is empty or undefined.
if (!getenv("MOZ_PROFILE_WITH_PERF") ||
!strlen(getenv("MOZ_PROFILE_WITH_PERF"))) {
return true;
}
/*
* Delete mozperf.data the first time through -- we're going to append to it
* later on, so we want it to be clean when we start out.
*/
if (!perfInitialized) {
perfInitialized = true;
unlink(outfile);
char cwd[4096];
printf("Writing perf profiling data to %s/%s\n",
getcwd(cwd, sizeof(cwd)), outfile);
}
pid_t mainPid = getpid();
pid_t childPid = fork();
if (childPid == 0) {
/* perf record --append --pid $mainPID --output=$outfile $MOZ_PROFILE_PERF_FLAGS */
char mainPidStr[16];
snprintf(mainPidStr, sizeof(mainPidStr), "%d", mainPid);
const char *defaultArgs[] = {"perf", "record", "--append",
"--pid", mainPidStr, "--output", outfile};
Vector<const char*, 0, SystemAllocPolicy> args;
args.append(defaultArgs, ArrayLength(defaultArgs));
const char *flags = getenv("MOZ_PROFILE_PERF_FLAGS");
if (!flags) {
flags = "--call-graph";
}
// Split |flags| on spaces. (Don't bother to free it -- we're going to
// exec anyway.)
char *toksave;
char *tok = strtok_r(strdup(flags), " ", &toksave);
while (tok) {
args.append(tok);
tok = strtok_r(NULL, " ", &toksave);
}
args.append((char*) NULL);
execvp("perf", const_cast<char**>(args.begin()));
/* Reached only if execlp fails. */
fprintf(stderr, "Unable to start perf.\n");
exit(1);
}
else if (childPid > 0) {
perfPid = childPid;
/* Give perf a chance to warm up. */
usleep(500 * 1000);
return true;
}
else {
UnsafeError("js_StartPerf: fork() failed\n");
return false;
}
}
JSBool js_StopPerf()
{
if (perfPid == 0) {
UnsafeError("js_StopPerf: perf is not running.\n");
return true;
}
if (kill(perfPid, SIGINT)) {
UnsafeError("js_StopPerf: kill failed\n");
// Try to reap the process anyway.
waitpid(perfPid, NULL, WNOHANG);
}
else {
waitpid(perfPid, NULL, 0);
}
perfPid = 0;
return true;
}
#endif /* __linux__ */

View File

@ -0,0 +1,90 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*
* 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/. */
/*
* Functions for controlling profilers from within JS: Valgrind, Perf,
* Shark, etc.
*/
#ifndef Profilers_h___
#define Profilers_h___
#include "jsapi.h"
/**
* Start any profilers that are available and have been configured on for this
* platform. This is NOT thread safe.
*
* The profileName is used by some profilers to describe the current profiling
* run. It may be used for part of the filename of the output, but the
* specifics depend on the profiler. Many profilers will ignore it. Passing in
* NULL is legal; some profilers may use it to output to stdout or similar.
*
* Returns true if no profilers fail to start.
*/
extern JS_PUBLIC_API(JSBool)
JS_StartProfiling(const char *profileName);
/**
* Stop any profilers that were previously started with JS_StartProfiling.
* Returns true if no profilers fail to stop.
*/
extern JS_PUBLIC_API(JSBool)
JS_StopProfiling(const char *profileName);
/**
* Write the current profile data to the given file, if applicable to whatever
* profiler is being used.
*/
extern JS_PUBLIC_API(JSBool)
JS_DumpProfile(const char *outfile, const char *profileName);
/**
* Pause currently active profilers (only supported by some profilers). Returns
* whether any profilers failed to pause. (Profilers that do not support
* pause/resume do not count.)
*/
extern JS_PUBLIC_API(JSBool)
JS_PauseProfilers(const char *profileName);
/**
* Resume suspended profilers
*/
extern JS_PUBLIC_API(JSBool)
JS_ResumeProfilers(const char *profileName);
/**
* The profiling API calls are not able to report errors, so they use a
* thread-unsafe global memory buffer to hold the last error encountered. This
* should only be called after something returns false.
*/
JS_PUBLIC_API(const char *)
JS_UnsafeGetLastProfilingError();
#ifdef MOZ_CALLGRIND
extern JS_FRIEND_API(JSBool)
js_StopCallgrind();
extern JS_FRIEND_API(JSBool)
js_StartCallgrind();
extern JS_FRIEND_API(JSBool)
js_DumpCallgrind(const char *outfile);
#endif /* MOZ_CALLGRIND */
#ifdef __linux__
extern JS_FRIEND_API(JSBool)
js_StartPerf();
extern JS_FRIEND_API(JSBool)
js_StopPerf();
#endif /* __linux__ */
#endif /* Profilers_h___ */

View File

@ -1047,7 +1047,7 @@ TestIonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osr
{
if (!IonCompile<TestCompiler>(cx, script, fun, osrPc, constructing)) {
if (!cx->isExceptionPending())
ForbidCompilation(script);
ForbidCompilation(cx, script);
return false;
}
return true;
@ -1202,7 +1202,7 @@ ion::CanEnterAtBranch(JSContext *cx, HandleScript script, StackFrame *fp, jsbyte
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(fp)) {
ForbidCompilation(script);
ForbidCompilation(cx, script);
return Method_CantCompile;
}
@ -1211,7 +1211,7 @@ ion::CanEnterAtBranch(JSContext *cx, HandleScript script, StackFrame *fp, jsbyte
MethodStatus status = Compile<TestCompiler>(cx, script, fun, pc, false);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(script);
ForbidCompilation(cx, script);
return status;
}
@ -1258,7 +1258,7 @@ ion::CanEnter(JSContext *cx, HandleScript script, StackFrame *fp, bool newType)
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(fp)) {
ForbidCompilation(script);
ForbidCompilation(cx, script);
return Method_CantCompile;
}
@ -1267,7 +1267,7 @@ ion::CanEnter(JSContext *cx, HandleScript script, StackFrame *fp, bool newType)
MethodStatus status = Compile<TestCompiler>(cx, script, fun, NULL, fp->isConstructing());
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(script);
ForbidCompilation(cx, script);
return status;
}
@ -1634,7 +1634,9 @@ ion::Invalidate(JSContext *cx, JSScript *script, bool resetUses)
JS_ASSERT(script->hasIonScript());
Vector<types::RecompileInfo> scripts(cx);
scripts.append(script->ionScript()->recompileInfo());
if (!scripts.append(script->ionScript()->recompileInfo()))
return false;
Invalidate(cx, scripts, resetUses);
return true;
}
@ -1667,17 +1669,19 @@ ion::MarkFromIon(JSCompartment *comp, Value *vp)
}
void
ion::ForbidCompilation(JSScript *script)
ion::ForbidCompilation(JSContext *cx, JSScript *script)
{
IonSpew(IonSpew_Abort, "Disabling Ion compilation of script %s:%d",
script->filename, script->lineno);
if (script->hasIonScript() && script->compartment()->needsBarrier()) {
// We're about to remove edges from the JSScript to gcthings
// embedded in the IonScript. Perform one final trace of the
// IonScript for the incremental GC, as it must know about
// those edges.
IonScript::Trace(script->compartment()->barrierTracer(), script->ion);
if (script->hasIonScript()) {
// It is only safe to modify script->ion if the script is not currently
// running, because IonFrameIterator needs to tell what ionScript to
// use (either the one on the JSScript, or the one hidden in the
// breadcrumbs Invalidation() leaves). Therefore, if invalidation
// fails, we cannot disable the script.
if (!Invalidate(cx, script, false))
return;
}
script->ion = ION_DISABLED_SCRIPT;

View File

@ -252,7 +252,7 @@ static inline bool IsEnabled(JSContext *cx)
return cx->hasRunOption(JSOPTION_ION) && cx->typeInferenceEnabled();
}
void ForbidCompilation(JSScript *script);
void ForbidCompilation(JSContext *cx, JSScript *script);
uint32_t UsesBeforeIonRecompile(JSScript *script, jsbytecode *pc);
} // namespace ion

View File

@ -39,14 +39,13 @@ InvokeFunction(JSContext *cx, JSFunction *fun, uint32 argc, Value *argv, Value *
JSScript *script = GetTopIonJSScript(cx);
if (script->hasIonScript() && ++script->ion->slowCallCount >= js_IonOptions.slowCallLimit) {
AutoFlushCache afc("InvokeFunction");
Invalidate(cx, script, false);
// Finally, poison the script so we don't try to run it again
ForbidCompilation(script);
// Poison the script so we don't try to run it again. This will
// trigger invalidation.
ForbidCompilation(cx, script);
}
}
// TI will return false for monitorReturnTypes, meaning there is no
// TypeBarrier or Monitor instruction following this. However, we need to
// explicitly monitor if the callee has not been analyzed yet. We special

View File

@ -0,0 +1,11 @@
// Bug 791157: the shell 'evaluate' function should properly restore the
// context's options.
try {
evaluate('%', {noScriptRval: true});
} catch(e) {}
new Function("");
try {
evaluate('new Function("");', {noScriptRval: true});
} catch (e) {}

View File

@ -1,11 +1,9 @@
function testLength() {
// Test length attributes
// Test length immutability.
var p = new ParallelArray([1,2,3,4]);
var desc = Object.getOwnPropertyDescriptor(p, "length");
assertEq(desc.enumerable, false);
assertEq(desc.configurable, false);
assertEq(desc.writable, false);
assertEq(desc.value, 4);
p.length = 0;
assertEq(p[0], 1);
assertEq(p.length, 4);
}
testLength();

View File

@ -7,9 +7,8 @@ function testShape() {
shape.push(i+1);
var p = new ParallelArray(shape, function () { return 0; });
// Test shape identity and shape
assertEq(p.shape, p.shape);
assertEq(p.shape !== shape, true);
assertEqArray(p.shape, shape);
assertEq(p.shape !== shape, true);
}
}

View File

@ -0,0 +1,12 @@
load(libdir + "eqArrayHelper.js");
function testShape() {
// Test shape immutability.
var p = new ParallelArray([1,2,3,4]);
p.shape[0] = 0;
p.shape[1] = 42;
assertEq(p[0], 1);
assertEqArray(p.shape, [4]);
}
testShape();

View File

@ -1,3 +1,5 @@
load(libdir + "eqArrayHelper.js");
// ParallelArray surfaces
var desc = Object.getOwnPropertyDescriptor(this, "ParallelArray");
@ -35,3 +37,14 @@ checkMethod("filter", 1);
checkMethod("flatten", 0);
checkMethod("partition", 1);
checkMethod("get", 1);
function checkAccessor(name) {
var desc = Object.getOwnPropertyDescriptor(ParallelArray.prototype, name);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, false);
assertEq(typeof desc.get, 'function');
assertEq(desc.set, undefined);
}
checkAccessor("length");
checkAccessor("shape");

View File

@ -0,0 +1,3 @@
// ParallelArray objects are frozen.
assertEq(Object.isFrozen(new ParallelArray), true);

View File

@ -354,25 +354,24 @@ MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "paramet
MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 301, 0, JSEXN_SYNTAXERR, "yield in default expression")
MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED, 302, 1, JSEXN_REFERENCEERR, "no intrinsic function {0}")
MSG_DEF(JSMSG_ALREADY_HAS_SOURCEMAP, 303, 1, JSEXN_ERR, "{0} is being assigned a source map, yet already has one")
MSG_DEF(JSMSG_PAR_ARRAY_IMMUTABLE, 304, 0, JSEXN_TYPEERR, "ParallelArray objects are immutable")
MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG, 305, 1, JSEXN_TYPEERR, "invalid ParallelArray{0} argument")
MSG_DEF(JSMSG_PAR_ARRAY_BAD_PARTITION, 306, 0, JSEXN_ERR, "argument must be divisible by outermost dimension")
MSG_DEF(JSMSG_PAR_ARRAY_REDUCE_EMPTY, 307, 0, JSEXN_ERR, "cannot reduce empty ParallelArray object")
MSG_DEF(JSMSG_PAR_ARRAY_ALREADY_FLAT, 308, 0, JSEXN_ERR, "cannot flatten 1-dimensional ParallelArray object")
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 309, 0, JSEXN_ERR, "no conflict resolution function provided")
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS, 310, 0, JSEXN_ERR, "index in scatter vector out of bounds")
MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 311, 0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent")
MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 312, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object")
MSG_DEF(JSMSG_CANT_REPORT_NEW, 313, 0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object")
MSG_DEF(JSMSG_CANT_REPORT_INVALID, 314, 0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor")
MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 315, 0, JSEXN_TYPEERR, "proxy can't report a non-existent property as non-configurable")
MSG_DEF(JSMSG_CANT_DEFINE_NEW, 316, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object")
MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 317, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor")
MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 318, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable")
MSG_DEF(JSMSG_INVALID_TRAP_RESULT, 319, 2, JSEXN_TYPEERR, "trap {1} for {0} returned an invalid result")
MSG_DEF(JSMSG_CANT_SKIP_NC, 320, 0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property")
MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 321, 0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property")
MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 322, 0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter")
MSG_DEF(JSMSG_CANT_SET_NW_NC, 323, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 324, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 325, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG, 304, 1, JSEXN_TYPEERR, "invalid ParallelArray{0} argument")
MSG_DEF(JSMSG_PAR_ARRAY_BAD_PARTITION, 305, 0, JSEXN_ERR, "argument must be divisible by outermost dimension")
MSG_DEF(JSMSG_PAR_ARRAY_REDUCE_EMPTY, 306, 0, JSEXN_ERR, "cannot reduce empty ParallelArray object")
MSG_DEF(JSMSG_PAR_ARRAY_ALREADY_FLAT, 307, 0, JSEXN_ERR, "cannot flatten 1-dimensional ParallelArray object")
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 308, 0, JSEXN_ERR, "no conflict resolution function provided")
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS, 309, 0, JSEXN_ERR, "index in scatter vector out of bounds")
MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 310, 0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent")
MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 311, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object")
MSG_DEF(JSMSG_CANT_REPORT_NEW, 312, 0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object")
MSG_DEF(JSMSG_CANT_REPORT_INVALID, 313, 0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor")
MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 314, 0, JSEXN_TYPEERR, "proxy can't report a non-existent property as non-configurable")
MSG_DEF(JSMSG_CANT_DEFINE_NEW, 315, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object")
MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 316, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor")
MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 317, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable")
MSG_DEF(JSMSG_INVALID_TRAP_RESULT, 318, 2, JSEXN_TYPEERR, "trap {1} for {0} returned an invalid result")
MSG_DEF(JSMSG_CANT_SKIP_NC, 319, 0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property")
MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 320, 0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property")
MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 321, 0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter")
MSG_DEF(JSMSG_CANT_SET_NW_NC, 322, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 323, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 324, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")

View File

@ -449,13 +449,11 @@ JSStructuredCloneWriter::writeArrayBuffer(JSHandleObject obj)
}
bool
JSStructuredCloneWriter::startObject(JSHandleObject obj)
JSStructuredCloneWriter::startObject(JSHandleObject obj, bool *backref)
{
JS_ASSERT(obj->isArray() || obj->isObject());
/* Handle cycles in the object graph. */
CloneMemory::AddPtr p = memory.lookupForAdd(obj);
if (p)
if ((*backref = p))
return out.writePair(SCTAG_BACK_REFERENCE_OBJECT, p->value);
if (!memory.add(p, obj, memory.count()))
return false;
@ -466,6 +464,12 @@ JSStructuredCloneWriter::startObject(JSHandleObject obj)
return false;
}
return true;
}
bool
JSStructuredCloneWriter::traverseObject(JSHandleObject obj)
{
/*
* Get enumerable property ids and put them in reverse order so that they
* will come off the stack in forward order.
@ -511,6 +515,13 @@ JSStructuredCloneWriter::startWrite(const Value &v)
return false;
AutoCompartment ac(context(), obj);
bool backref;
if (!startObject(obj, &backref))
return false;
if (backref)
return true;
if (obj->isRegExp()) {
RegExpObject &reobj = obj->asRegExp();
return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) &&
@ -518,12 +529,12 @@ JSStructuredCloneWriter::startWrite(const Value &v)
} else if (obj->isDate()) {
double d = js_DateGetMsecSinceEpoch(context(), obj);
return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d);
} else if (obj->isObject() || obj->isArray()) {
return startObject(obj);
} else if (obj->isTypedArray()) {
return writeTypedArray(obj);
} else if (obj->isArrayBuffer() && obj->asArrayBuffer().hasData()) {
return writeArrayBuffer(obj);
} else if (obj->isObject() || obj->isArray()) {
return traverseObject(obj);
} else if (obj->isBoolean()) {
return out.writePair(SCTAG_BOOLEAN_OBJECT, obj->asBoolean().unbox());
} else if (obj->isNumber()) {
@ -821,8 +832,7 @@ JSStructuredCloneReader::startRead(Value *vp)
JSObject *obj = (tag == SCTAG_ARRAY_OBJECT)
? NewDenseEmptyArray(context())
: NewBuiltinClassInstance(context(), &ObjectClass);
if (!obj || !objs.append(ObjectValue(*obj)) ||
!allObjs.append(ObjectValue(*obj)))
if (!obj || !objs.append(ObjectValue(*obj)))
return false;
vp->setObject(*obj);
break;
@ -832,14 +842,17 @@ JSStructuredCloneReader::startRead(Value *vp)
if (data >= allObjs.length()) {
JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL,
JSMSG_SC_BAD_SERIALIZED_DATA,
"invalid input");
"invalid back reference in input");
return false;
}
*vp = allObjs[data];
break;
return true;
}
case SCTAG_ARRAY_BUFFER_OBJECT:
return readArrayBuffer(data, vp);
if (!readArrayBuffer(data, vp))
return false;
break;
default: {
if (tag <= SCTAG_FLOAT_MAX) {
@ -850,8 +863,11 @@ JSStructuredCloneReader::startRead(Value *vp)
break;
}
if (SCTAG_TYPED_ARRAY_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_MAX)
return readTypedArray(tag, data, vp);
if (SCTAG_TYPED_ARRAY_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_MAX) {
if (!readTypedArray(tag, data, vp))
return false;
break;
}
if (!callbacks || !callbacks->read) {
JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA,
@ -864,6 +880,10 @@ JSStructuredCloneReader::startRead(Value *vp)
vp->setObject(*obj);
}
}
if (vp->isObject() && !allObjs.append(*vp))
return false;
return true;
}

View File

@ -134,8 +134,9 @@ struct JSStructuredCloneWriter {
bool writeId(jsid id);
bool writeArrayBuffer(JSHandleObject obj);
bool writeTypedArray(JSHandleObject obj);
bool startObject(JSHandleObject obj);
bool startObject(JSHandleObject obj, bool *backref);
bool startWrite(const js::Value &v);
bool traverseObject(JSHandleObject obj);
inline void checkStack();

View File

@ -9,7 +9,6 @@
* JS debugging API.
*/
#include <string.h>
#include <stdarg.h>
#include "jsprvtd.h"
#include "jstypes.h"
#include "jsutil.h"
@ -48,10 +47,6 @@
#include "jsautooplen.h"
#include "mozilla/Util.h"
#ifdef __APPLE__
#include "devtools/sharkctl.h"
#endif
using namespace js;
using namespace js::gc;
using namespace mozilla;
@ -1064,652 +1059,6 @@ JS_GetGlobalDebugHooks(JSRuntime *rt)
/************************************************************************/
/* Profiling-related API */
/* Thread-unsafe error management */
static char gLastError[2000];
static void
#ifdef __GNUC__
__attribute__((unused,format(printf,1,2)))
#endif
UnsafeError(const char *format, ...)
{
va_list args;
va_start(args, format);
(void) vsnprintf(gLastError, sizeof(gLastError), format, args);
va_end(args);
gLastError[sizeof(gLastError) - 1] = '\0';
}
JS_PUBLIC_API(const char *)
JS_UnsafeGetLastProfilingError()
{
return gLastError;
}
JS_PUBLIC_API(JSBool)
JS_StartProfiling(const char *profileName)
{
JSBool ok = JS_TRUE;
#if defined(MOZ_SHARK) && defined(__APPLE__)
if (!Shark::Start()) {
UnsafeError("Failed to start Shark for %s", profileName);
ok = JS_FALSE;
}
#endif
#if 0 //def MOZ_VTUNE
if (!js_StartVtune(profileName))
ok = JS_FALSE;
#endif
#ifdef __linux__
if (!js_StartPerf())
ok = JS_FALSE;
#endif
return ok;
}
JS_PUBLIC_API(JSBool)
JS_StopProfiling(const char *profileName)
{
JSBool ok = JS_TRUE;
#if defined(MOZ_SHARK) && defined(__APPLE__)
Shark::Stop();
#endif
#if 0 //def MOZ_VTUNE
if (!js_StopVtune())
ok = JS_FALSE;
#endif
#ifdef __linux__
if (!js_StopPerf())
ok = JS_FALSE;
#endif
return ok;
}
/*
* Start or stop whatever platform- and configuration-specific profiling
* backends are available.
*/
static JSBool
ControlProfilers(bool toState)
{
JSBool ok = JS_TRUE;
if (! Probes::ProfilingActive && toState) {
#if defined(MOZ_SHARK) && defined(__APPLE__)
if (!Shark::Start()) {
UnsafeError("Failed to start Shark");
ok = JS_FALSE;
}
#endif
#ifdef MOZ_CALLGRIND
if (! js_StartCallgrind()) {
UnsafeError("Failed to start Callgrind");
ok = JS_FALSE;
}
#endif
#if 0 //def MOZ_VTUNE
if (! js_ResumeVtune())
ok = JS_FALSE;
#endif
} else if (Probes::ProfilingActive && ! toState) {
#if defined(MOZ_SHARK) && defined(__APPLE__)
Shark::Stop();
#endif
#ifdef MOZ_CALLGRIND
if (! js_StopCallgrind()) {
UnsafeError("failed to stop Callgrind");
ok = JS_FALSE;
}
#endif
#if 0 //def MOZ_VTUNE
if (! js_PauseVtune())
ok = JS_FALSE;
#endif
}
Probes::ProfilingActive = toState;
return ok;
}
/*
* Pause/resume whatever profiling mechanism is currently compiled
* in, if applicable. This will not affect things like dtrace.
*
* Do not mix calls to these APIs with calls to the individual
* profilers' pause/resume functions, because only overall state is
* tracked, not the state of each profiler.
*/
JS_PUBLIC_API(JSBool)
JS_PauseProfilers(const char *profileName)
{
return ControlProfilers(false);
}
JS_PUBLIC_API(JSBool)
JS_ResumeProfilers(const char *profileName)
{
return ControlProfilers(true);
}
JS_PUBLIC_API(JSBool)
JS_DumpProfile(const char *outfile, const char *profileName)
{
JSBool ok = JS_TRUE;
#ifdef MOZ_CALLGRIND
js_DumpCallgrind(outfile);
#endif
return ok;
}
#ifdef MOZ_PROFILING
struct RequiredStringArg {
JSContext *mCx;
char *mBytes;
RequiredStringArg(JSContext *cx, unsigned argc, jsval *vp, size_t argi, const char *caller)
: mCx(cx), mBytes(NULL)
{
if (argc <= argi) {
JS_ReportError(cx, "%s: not enough arguments", caller);
} else if (!JSVAL_IS_STRING(JS_ARGV(cx, vp)[argi])) {
JS_ReportError(cx, "%s: invalid arguments (string expected)", caller);
} else {
mBytes = JS_EncodeString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[argi]));
}
}
operator void*() {
return (void*) mBytes;
}
~RequiredStringArg() {
if (mBytes)
js_free(mBytes);
}
};
static JSBool
StartProfiling(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "startProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
StopProfiling(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "stopProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
PauseProfilers(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "pauseProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
ResumeProfilers(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "resumeProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(profileName.mBytes)));
return JS_TRUE;
}
/* Usage: DumpProfile([filename[, profileName]]) */
static JSBool
DumpProfile(JSContext *cx, unsigned argc, jsval *vp)
{
bool ret;
if (argc == 0) {
ret = JS_DumpProfile(NULL, NULL);
} else {
RequiredStringArg filename(cx, argc, vp, 0, "dumpProfile");
if (!filename)
return JS_FALSE;
if (argc == 1) {
ret = JS_DumpProfile(filename.mBytes, NULL);
} else {
RequiredStringArg profileName(cx, argc, vp, 1, "dumpProfile");
if (!profileName)
return JS_FALSE;
ret = JS_DumpProfile(filename.mBytes, profileName.mBytes);
}
}
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(ret));
return true;
}
#ifdef MOZ_SHARK
static JSBool
IgnoreAndReturnTrue(JSContext *cx, unsigned argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, JSVAL_TRUE);
return true;
}
#endif
#ifdef MOZ_CALLGRIND
static JSBool
StartCallgrind(JSContext *cx, unsigned argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartCallgrind()));
return JS_TRUE;
}
static JSBool
StopCallgrind(JSContext *cx, unsigned argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopCallgrind()));
return JS_TRUE;
}
static JSBool
DumpCallgrind(JSContext *cx, unsigned argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(NULL)));
return JS_TRUE;
}
RequiredStringArg outFile(cx, argc, vp, 0, "dumpCallgrind");
if (!outFile)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(outFile.mBytes)));
return JS_TRUE;
}
#endif
#ifdef MOZ_VTUNE
static JSBool
StartVtune(JSContext *cx, unsigned argc, jsval *vp)
{
RequiredStringArg profileName(cx, argc, vp, 0, "startVtune");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartVtune(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
StopVtune(JSContext *cx, unsigned argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopVtune()));
return JS_TRUE;
}
static JSBool
PauseVtune(JSContext *cx, unsigned argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_PauseVtune()));
return JS_TRUE;
}
static JSBool
ResumeVtune(JSContext *cx, unsigned argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_ResumeVtune()));
return JS_TRUE;
}
#endif
static JSFunctionSpec profiling_functions[] = {
JS_FN("startProfiling", StartProfiling, 1,0),
JS_FN("stopProfiling", StopProfiling, 1,0),
JS_FN("pauseProfilers", PauseProfilers, 1,0),
JS_FN("resumeProfilers", ResumeProfilers, 1,0),
JS_FN("dumpProfile", DumpProfile, 2,0),
#ifdef MOZ_SHARK
/* Keep users of the old shark API happy. */
JS_FN("connectShark", IgnoreAndReturnTrue, 0,0),
JS_FN("disconnectShark", IgnoreAndReturnTrue, 0,0),
JS_FN("startShark", StartProfiling, 0,0),
JS_FN("stopShark", StopProfiling, 0,0),
#endif
#ifdef MOZ_CALLGRIND
JS_FN("startCallgrind", StartCallgrind, 0,0),
JS_FN("stopCallgrind", StopCallgrind, 0,0),
JS_FN("dumpCallgrind", DumpCallgrind, 1,0),
#endif
#if 0 //ef MOZ_VTUNE
JS_FN("startVtune", js_StartVtune, 1,0),
JS_FN("stopVtune", js_StopVtune, 0,0),
JS_FN("pauseVtune", js_PauseVtune, 0,0),
JS_FN("resumeVtune", js_ResumeVtune, 0,0),
#endif
JS_FS_END
};
#endif
JS_PUBLIC_API(JSBool)
JS_DefineProfilingFunctions(JSContext *cx, JSObject *objArg)
{
RootedObject obj(cx, objArg);
assertSameCompartment(cx, obj);
#ifdef MOZ_PROFILING
return JS_DefineFunctions(cx, obj, profiling_functions);
#else
return true;
#endif
}
#ifdef MOZ_CALLGRIND
#include <valgrind/callgrind.h>
JS_FRIEND_API(JSBool)
js_StartCallgrind()
{
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_START_INSTRUMENTATION);
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_ZERO_STATS);
return true;
}
JS_FRIEND_API(JSBool)
js_StopCallgrind()
{
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_STOP_INSTRUMENTATION);
return true;
}
JS_FRIEND_API(JSBool)
js_DumpCallgrind(const char *outfile)
{
if (outfile) {
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS_AT(outfile));
} else {
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS);
}
return true;
}
#endif /* MOZ_CALLGRIND */
#if 0 //def MOZ_VTUNE
#include <VTuneApi.h>
static const char *vtuneErrorMessages[] = {
"unknown, error #0",
"invalid 'max samples' field",
"invalid 'samples per buffer' field",
"invalid 'sample interval' field",
"invalid path",
"sample file in use",
"invalid 'number of events' field",
"unknown, error #7",
"internal error",
"bad event name",
"VTStopSampling called without calling VTStartSampling",
"no events selected for event-based sampling",
"events selected cannot be run together",
"no sampling parameters",
"sample database already exists",
"sampling already started",
"time-based sampling not supported",
"invalid 'sampling parameters size' field",
"invalid 'event size' field",
"sampling file already bound",
"invalid event path",
"invalid license",
"invalid 'global options' field",
};
bool
js_StartVtune(const char *profileName)
{
VTUNE_EVENT events[] = {
{ 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
{ 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
};
U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT);
char *default_filename = "mozilla-vtune.tb5";
JSString *str;
U32 status;
VTUNE_SAMPLING_PARAMS params = {
sizeof(VTUNE_SAMPLING_PARAMS),
sizeof(VTUNE_EVENT),
0, 0, /* Reserved fields */
1, /* Initialize in "paused" state */
0, /* Max samples, or 0 for "continuous" */
4096, /* Samples per buffer */
0.1, /* Sampling interval in ms */
1, /* 1 for event-based sampling, 0 for time-based */
n_events,
events,
default_filename,
};
if (profileName) {
char filename[strlen(profileName) + strlen("-vtune.tb5") + 1];
snprintf(filename, sizeof(filename), "%s-vtune.tb5", profileName);
params.tb5Filename = filename;
}
status = VTStartSampling(&params);
if (params.tb5Filename != default_filename)
js_free(params.tb5Filename);
if (status != 0) {
if (status == VTAPI_MULTIPLE_RUNS)
VTStopSampling(0);
if (status < sizeof(vtuneErrorMessages))
UnsafeError("Vtune setup error: %s", vtuneErrorMessages[status]);
else
UnsafeError("Vtune setup error: %d", status);
return false;
}
return true;
}
bool
js_StopVtune()
{
U32 status = VTStopSampling(1);
if (status) {
if (status < sizeof(vtuneErrorMessages))
UnsafeError("Vtune shutdown error: %s", vtuneErrorMessages[status]);
else
UnsafeError("Vtune shutdown error: %d", status);
return false;
}
return true;
}
bool
js_PauseVtune()
{
VTPause();
return true;
}
bool
js_ResumeVtune()
{
VTResume();
return true;
}
#endif /* MOZ_VTUNE */
#ifdef __linux__
/*
* Code for starting and stopping |perf|, the Linux profiler.
*
* Output from profiling is written to mozperf.data in your cwd.
*
* To enable, set MOZ_PROFILE_WITH_PERF=1 in your environment.
*
* To pass additional parameters to |perf record|, provide them in the
* MOZ_PROFILE_PERF_FLAGS environment variable. If this variable does not
* exist, we default it to "--call-graph". (If you don't want --call-graph but
* don't want to pass any other args, define MOZ_PROFILE_PERF_FLAGS to the empty
* string.)
*
* If you include --pid or --output in MOZ_PROFILE_PERF_FLAGS, you're just
* asking for trouble.
*
* Our split-on-spaces logic is lame, so don't expect MOZ_PROFILE_PERF_FLAGS to
* work if you pass an argument which includes a space (e.g.
* MOZ_PROFILE_PERF_FLAGS="-e 'foo bar'").
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
static bool perfInitialized = false;
static pid_t perfPid = 0;
JSBool js_StartPerf()
{
const char *outfile = "mozperf.data";
if (perfPid != 0) {
UnsafeError("js_StartPerf: called while perf was already running!\n");
return false;
}
// Bail if MOZ_PROFILE_WITH_PERF is empty or undefined.
if (!getenv("MOZ_PROFILE_WITH_PERF") ||
!strlen(getenv("MOZ_PROFILE_WITH_PERF"))) {
return true;
}
/*
* Delete mozperf.data the first time through -- we're going to append to it
* later on, so we want it to be clean when we start out.
*/
if (!perfInitialized) {
perfInitialized = true;
unlink(outfile);
char cwd[4096];
printf("Writing perf profiling data to %s/%s\n",
getcwd(cwd, sizeof(cwd)), outfile);
}
pid_t mainPid = getpid();
pid_t childPid = fork();
if (childPid == 0) {
/* perf record --append --pid $mainPID --output=$outfile $MOZ_PROFILE_PERF_FLAGS */
char mainPidStr[16];
snprintf(mainPidStr, sizeof(mainPidStr), "%d", mainPid);
const char *defaultArgs[] = {"perf", "record", "--append",
"--pid", mainPidStr, "--output", outfile};
Vector<const char*, 0, SystemAllocPolicy> args;
args.append(defaultArgs, ArrayLength(defaultArgs));
const char *flags = getenv("MOZ_PROFILE_PERF_FLAGS");
if (!flags) {
flags = "--call-graph";
}
// Split |flags| on spaces. (Don't bother to free it -- we're going to
// exec anyway.)
char *toksave;
char *tok = strtok_r(strdup(flags), " ", &toksave);
while (tok) {
args.append(tok);
tok = strtok_r(NULL, " ", &toksave);
}
args.append((char*) NULL);
execvp("perf", const_cast<char**>(args.begin()));
/* Reached only if execlp fails. */
fprintf(stderr, "Unable to start perf.\n");
exit(1);
}
else if (childPid > 0) {
perfPid = childPid;
/* Give perf a chance to warm up. */
usleep(500 * 1000);
return true;
}
else {
UnsafeError("js_StartPerf: fork() failed\n");
return false;
}
}
JSBool js_StopPerf()
{
if (perfPid == 0) {
UnsafeError("js_StopPerf: perf is not running.\n");
return true;
}
if (kill(perfPid, SIGINT)) {
UnsafeError("js_StopPerf: kill failed\n");
// Try to reap the process anyway.
waitpid(perfPid, NULL, WNOHANG);
}
else {
waitpid(perfPid, NULL, 0);
}
perfPid = 0;
return true;
}
#endif /* __linux__ */
JS_PUBLIC_API(void)
JS_DumpBytecode(JSContext *cx, JSScript *scriptArg)
{

View File

@ -394,48 +394,6 @@ js_RevertVersion(JSContext *cx);
extern JS_PUBLIC_API(const JSDebugHooks *)
JS_GetGlobalDebugHooks(JSRuntime *rt);
/**
* Start any profilers that are available and have been configured on for this
* platform. This is NOT thread safe.
*
* The profileName is used by some profilers to describe the current profiling
* run. It may be used for part of the filename of the output, but the
* specifics depend on the profiler. Many profilers will ignore it. Passing in
* NULL is legal; some profilers may use it to output to stdout or similar.
*
* Returns true if no profilers fail to start.
*/
extern JS_PUBLIC_API(JSBool)
JS_StartProfiling(const char *profileName);
/**
* Stop any profilers that were previously started with JS_StartProfiling.
* Returns true if no profilers fail to stop.
*/
extern JS_PUBLIC_API(JSBool)
JS_StopProfiling(const char *profileName);
/**
* Write the current profile data to the given file, if applicable to whatever
* profiler is being used.
*/
extern JS_PUBLIC_API(JSBool)
JS_DumpProfile(const char *outfile, const char *profileName);
/**
* Pause currently active profilers (only supported by some profilers). Returns
* whether any profilers failed to pause. (Profilers that do not support
* pause/resume do not count.)
*/
extern JS_PUBLIC_API(JSBool)
JS_PauseProfilers(const char *profileName);
/**
* Resume suspended profilers
*/
extern JS_PUBLIC_API(JSBool)
JS_ResumeProfilers(const char *profileName);
/**
* Add various profiling-related functions as properties of the given object.
*/
@ -446,53 +404,6 @@ JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj);
extern JS_PUBLIC_API(JSBool)
JS_DefineDebuggerObject(JSContext *cx, JSObject *obj);
/**
* The profiling API calls are not able to report errors, so they use a
* thread-unsafe global memory buffer to hold the last error encountered. This
* should only be called after something returns false.
*/
JS_PUBLIC_API(const char *)
JS_UnsafeGetLastProfilingError();
#ifdef MOZ_CALLGRIND
extern JS_FRIEND_API(JSBool)
js_StopCallgrind();
extern JS_FRIEND_API(JSBool)
js_StartCallgrind();
extern JS_FRIEND_API(JSBool)
js_DumpCallgrind(const char *outfile);
#endif /* MOZ_CALLGRIND */
#ifdef MOZ_VTUNE
extern JS_FRIEND_API(bool)
js_StartVtune(const char *profileName);
extern JS_FRIEND_API(bool)
js_StopVtune();
extern JS_FRIEND_API(bool)
js_PauseVtune();
extern JS_FRIEND_API(bool)
js_ResumeVtune();
#endif /* MOZ_VTUNE */
#ifdef __linux__
extern JS_FRIEND_API(JSBool)
js_StartPerf();
extern JS_FRIEND_API(JSBool)
js_StopPerf();
#endif /* __linux__ */
extern JS_PUBLIC_API(void)
JS_DumpBytecode(JSContext *cx, JSScript *script);

View File

@ -131,7 +131,7 @@ fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValu
// detecting its use early.
JSScript *script = iter.script();
if (!script->hasIonScript())
ion::ForbidCompilation(script);
ion::ForbidCompilation(cx, script);
#endif
vp.setObject(*argsobj);

View File

@ -902,16 +902,17 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp)
options |= JSOPTION_COMPILE_N_GO;
if (noScriptRval)
options |= JSOPTION_NO_SCRIPT_RVAL;
JS_SetOptions(cx, options);
JS_SetOptions(cx, options);
JSScript *script = JS_CompileUCScript(cx, global, codeChars, codeLength, fileName, lineNumber);
JS_SetOptions(cx, saved);
if (!script)
return false;
if (sourceMapURL && !script->scriptSource()->hasSourceMap()) {
if (!script->scriptSource()->setSourceMap(cx, sourceMapURL, script->filename))
return false;
}
JS_SetOptions(cx, saved);
if (!JS_ExecuteScript(cx, global, script, vp))
return false;
}

View File

@ -3,54 +3,144 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Set of properties on a cloned object that are legitimately non-enumerable,
// grouped by object type.
var non_enumerable = { 'Array': [ 'length' ],
'String': [ 'length' ] };
// Set of properties on a cloned object that are legitimately non-configurable,
// grouped by object type. The property name '0' stands in for any indexed
// property.
var non_configurable = { 'String': [ 0 ],
'(typed array)': [ 0 ] };
// Set of properties on a cloned object that are legitimately non-writable,
// grouped by object type. The property name '0' stands in for any indexed
// property.
var non_writable = { 'String': [ 0 ] };
function classOf(obj) {
var classString = Object.prototype.toString.call(obj);
var [ all, classname ] = classString.match(/\[object (\w+)/);
return classname;
}
function isIndex(p) {
var u = p >>> 0;
return ("" + u == p && u != 0xffffffff);
}
function notIndex(p) {
return !isIndex(p);
}
function tableContains(table, cls, prop) {
if (isIndex(prop))
prop = 0;
if (cls.match(/\wArray$/))
cls = "(typed array)";
var exceptionalProps = table[cls] || [];
return exceptionalProps.indexOf(prop) != -1;
}
function shouldBeConfigurable(cls, prop) {
return !tableContains(non_configurable, cls, prop);
}
function shouldBeWritable(cls, prop) {
return !tableContains(non_writable, cls, prop);
}
function ownProperties(obj) {
return Object.getOwnPropertyNames(obj).
map(function (p) { return [p, Object.getOwnPropertyDescriptor(obj, p)]; });
}
function isCloneable(pair) {
return typeof pair[0] === 'string' && pair[1].enumerable;
}
function compareProperties(a, b, stack, path) {
var ca = classOf(a);
// 'b', the original object, may have non-enumerable or XMLName properties;
// ignore them. 'a', the clone, should not have any non-enumerable
// properties (except .length, if it's an Array or String) or XMLName
// properties.
var pb = ownProperties(b).filter(isCloneable);
var pa = ownProperties(a);
for (var i = 0; i < pa.length; i++) {
var propname = pa[i][0];
assertEq(typeof propname, "string", "clone should not have E4X properties " + path);
if (!pa[i][1].enumerable) {
if (tableContains(non_enumerable, ca, propname)) {
// remove it so that the comparisons below will work
pa.splice(i, 1);
i--;
} else {
throw new Error("non-enumerable clone property " + uneval(pa[i][0]) + " " + path);
}
}
}
// Check that, apart from properties whose names are array indexes,
// the enumerable properties appear in the same order.
var aNames = pa.map(function (pair) { return pair[1]; }).filter(notIndex);
var bNames = pa.map(function (pair) { return pair[1]; }).filter(notIndex);
assertEq(aNames.join(","), bNames.join(","), path);
// Check that the lists are the same when including array indexes.
function byName(a, b) { a = a[0]; b = b[0]; return a < b ? -1 : a === b ? 0 : 1; }
pa.sort(byName);
pb.sort(byName);
assertEq(pa.length, pb.length, "should see the same number of properties " + path);
for (var i = 0; i < pa.length; i++) {
var aName = pa[i][0];
var bName = pb[i][0];
assertEq(aName, bName, path);
var path2 = isIndex(aName) ? path + "[" + aName + "]" : path + "." + aName;
var da = pa[i][1];
var db = pb[i][1];
assertEq(da.configurable, shouldBeConfigurable(ca, aName), path2);
assertEq(da.writable, shouldBeWritable(ca, aName), path2);
assertEq("value" in da, true, path2);
var va = da.value;
var vb = b[pb[i][0]];
stack.push([va, vb, path2]);
}
}
function isClone(a, b) {
var stack = [[a, b]];
var stack = [[a, b, 'obj']];
var memory = new WeakMap();
var rmemory = new WeakMap();
while (stack.length > 0) {
var pair = stack.pop();
var x = pair[0], y = pair[1];
var x = pair[0], y = pair[1], path = pair[2];
if (typeof x !== "object" || x === null) {
// x is primitive.
if (x !== y)
return false;
assertEq(x, y, "equal primitives");
} else if (x instanceof Date) {
if (x.getTime() !== y.getTime())
return false;
assertEq(x.getTime(), y.getTime(), "equal times for cloned Dates");
} else if (memory.has(x)) {
// x is an object we have seen before in a.
if (y !== memory.get(x))
return false;
assertEq(rmemory.get(y), x);
assertEq(y, memory.get(x), "repeated object the same");
assertEq(rmemory.get(y), x, "repeated object's clone already seen");
} else {
// x is an object we have not seen before.
// Check that we have not seen y before either.
if (rmemory.has(y))
return false;
// Check that we have not seen y before either.
assertEq(rmemory.has(y), false);
// x and y must be of the same [[Class]].
var xcls = Object.prototype.toString.call(x);
var ycls = Object.prototype.toString.call(y);
if (xcls !== ycls)
return false;
var xcls = classOf(x);
var ycls = classOf(y);
assertEq(xcls, ycls, "same [[Class]]");
// This function is only designed to check Objects and Arrays.
assertEq(xcls === "[object Object]" || xcls === "[object Array]",
true);
// clone objects should have the default prototype of the class
assertEq(Object.getPrototypeOf(x), this[xcls].prototype);
// Compare objects.
var xk = Object.keys(x), yk = Object.keys(y);
if (xk.length !== yk.length)
return false;
for (var i = 0; i < xk.length; i++) {
// We must see the same property names in the same order.
if (xk[i] !== yk[i])
return false;
// Put the property values on the stack to compare later.
stack.push([x[xk[i]], y[yk[i]]]);
}
compareProperties(x, y, stack, path);
// Record that we have seen this pair of objects.
memory.set(x, y);
@ -60,13 +150,14 @@ function isClone(a, b) {
return true;
}
function check(a) {
assertEq(isClone(a, deserialize(serialize(a))), true);
function check(val) {
var clone = deserialize(serialize(val));
assertEq(isClone(val, clone), true);
return clone;
}
// Various recursive objects, i.e. those which the structured cloning
// algorithm wants us to reject due to "memory".
//
// Various recursive objects
// Recursive array.
var a = [];
a[0] = a;
@ -103,4 +194,120 @@ b[0] = {owner: a};
b[1] = [];
check(a);
// Date objects should not be identical even if representing the same date
var ar = [ new Date(1000), new Date(1000) ];
var clone = check(ar);
assertEq(clone[0] === clone[1], false);
// Identity preservation for various types of objects
function checkSimpleIdentity(v)
{
a = check([ v, v ]);
assertEq(a[0] === a[1], true);
return a;
}
var v = new Boolean(true);
checkSimpleIdentity(v);
v = new Number(17);
checkSimpleIdentity(v);
v = new String("yo");
checkSimpleIdentity(v);
v = "fish";
checkSimpleIdentity(v);
v = new Int8Array([ 10, 20 ]);
checkSimpleIdentity(v);
v = new ArrayBuffer(7);
checkSimpleIdentity(v);
v = new Date(1000);
b = [ v, v, { 'date': v } ];
clone = check(b);
assertEq(clone[0] === clone[1], true);
assertEq(clone[0], clone[2]['date']);
assertEq(clone[0] === v, false);
// Reduced and modified from postMessage_structured_clone test
let foo = { };
let baz = { };
let obj = { 'foo': foo,
'bar': { 'foo': foo },
'expando': { 'expando': baz },
'baz': baz };
check(obj);
for (var obj of new getTestContent)
check(obj);
// Stolen wholesale from postMessage_structured_clone_helper.js
function getTestContent()
{
yield "hello";
yield 2+3;
yield 12;
yield null;
yield "complex" + "string";
yield new Object();
yield new Date(1306113544);
yield [1, 2, 3, 4, 5];
let obj = new Object();
obj.foo = 3;
obj.bar = "hi";
obj.baz = new Date(1306113544);
obj.boo = obj;
yield obj;
let recursiveobj = new Object();
recursiveobj.a = recursiveobj;
recursiveobj.foo = new Object();
recursiveobj.foo.bar = "bar";
recursiveobj.foo.backref = recursiveobj;
recursiveobj.foo.baz = 84;
recursiveobj.foo.backref2 = recursiveobj;
recursiveobj.bar = new Object();
recursiveobj.bar.foo = "foo";
recursiveobj.bar.backref = recursiveobj;
recursiveobj.bar.baz = new Date(1306113544);
recursiveobj.bar.backref2 = recursiveobj;
recursiveobj.expando = recursiveobj;
yield recursiveobj;
let obj = new Object();
obj.expando1 = 1;
obj.foo = new Object();
obj.foo.bar = 2;
obj.bar = new Object();
obj.bar.foo = obj.foo;
obj.expando = new Object();
obj.expando.expando = new Object();
obj.expando.expando.obj = obj;
obj.expando2 = 4;
obj.baz = obj.expando.expando;
obj.blah = obj.bar;
obj.foo.baz = obj.blah;
obj.foo.blah = obj.blah;
yield obj;
let diamond = new Object();
let obj = new Object();
obj.foo = "foo";
obj.bar = 92;
obj.backref = diamond;
diamond.ref1 = obj;
diamond.ref2 = obj;
yield diamond;
let doubleref = new Object();
let obj = new Object();
doubleref.ref1 = obj;
doubleref.ref2 = obj;
yield doubleref;
}
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,10 @@
import re
from subprocess import list2cmdline
from progressbar import NullProgressBar, ProgressBar
import pipes
# subprocess.list2cmdline does not properly escape for sh-like shells
def escape_cmdline(args):
return ' '.join([ pipes.quote(a) for a in args ])
class TestOutput:
"""Output from a test run."""
@ -107,7 +111,7 @@ class ResultsSink:
self.n += 1
else:
if self.options.show_cmd:
print >> self.fp, list2cmdline(output.cmd)
print >> self.fp, escape_cmdline(output.cmd)
if self.options.show_output:
print >> self.fp, ' rc = %d, run time = %f' % (output.rc, output.dt)

View File

@ -5066,11 +5066,40 @@ nsLayoutUtils::FontSizeInflationEnabled(nsPresContext *aPresContext)
return false;
}
ViewportInfo vInf =
nsContentUtils::GetViewportInfo(aPresContext->PresShell()->GetDocument());
// XXXjwir3:
// See bug 706918, comment 23 for more information on this particular section
// of the code. We're using "screen size" in place of the size of the content
// area, because on mobile, these are close or equal. This will work for our
// purposes (bug 706198), but it will need to be changed in the future to be
// more correct when we bring the rest of the viewport code into platform.
// We actually want the size of the content area, in the event that we don't
// have any metadata about the width and/or height. On mobile, the screen size
// and the size of the content area are very close, or the same value.
// In XUL fennec, the content area is the size of the <browser> widget, but
// in native fennec, the content area is the size of the Gecko LayerView
// object.
if (vInf.defaultZoom >= 1.0 || vInf.autoSize) {
return false;
// TODO:
// Once bug 716575 has been resolved, this code should be changed so that it
// does the right thing on all platforms.
nsresult rv;
nsCOMPtr<nsIScreenManager> screenMgr =
do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIScreen> screen;
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
if (screen) {
int32_t screenLeft, screenTop, screenWidth, screenHeight;
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
ViewportInfo vInf =
nsContentUtils::GetViewportInfo(aPresContext->PresShell()->GetDocument(),
screenWidth, screenHeight);
if (vInf.defaultZoom >= 1.0 || vInf.autoSize) {
return false;
}
}
return true;

View File

@ -24,8 +24,6 @@
using namespace MPAPI;
const int OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka = 0x7FA30C01;
namespace android {
// MediaStreamSource is a DataSource that reads from a MPAPI media stream.

View File

@ -9,6 +9,8 @@ include protocol PNecko;
include InputStreamParams;
include URIParams;
include protocol PBlob; //FIXME: bug #792908
include "SerializedLoadContext.h";
using IPC::SerializedLoadContext;

View File

@ -9,6 +9,8 @@ include protocol PNecko;
include InputStreamParams;
include URIParams;
include protocol PBlob; //FIXME: bug #792908
include "mozilla/net/PHttpChannelParams.h";
include "mozilla/net/NeckoMessageUtils.h";
include "prio.h";

View File

@ -10,6 +10,8 @@ include protocol PBrowser;
include InputStreamParams;
include URIParams;
include protocol PBlob; //FIXME: bug #792908
include "SerializedLoadContext.h";
using IPC::SerializedLoadContext;

View File

@ -190,6 +190,58 @@ AbstractFile.normalizeToPointer = function normalizeToPointer(candidate, bytes,
return {ptr: ptr, bytes: bytes};
};
/**
* Code shared by iterators.
*/
AbstractFile.AbstractIterator = function AbstractIterator() {
};
AbstractFile.AbstractIterator.prototype = {
/**
* Allow iterating with |for|
*/
__iterator__: function __iterator__() {
return this;
},
/**
* Apply a function to all elements of the directory sequentially.
*
* @param {Function} cb This function will be applied to all entries
* of the directory. It receives as arguments
* - the OS.File.Entry corresponding to the entry;
* - the index of the entry in the enumeration;
* - the iterator itself - calling |close| on the iterator stops
* the loop.
*/
forEach: function forEach(cb) {
let index = 0;
for (let entry in this) {
cb(entry, index++, this);
}
},
/**
* Return several entries at once.
*
* Entries are returned in the same order as a walk with |forEach| or
* |for(...)|.
*
* @param {number=} length If specified, the number of entries
* to return. If unspecified, return all remaining entries.
* @return {Array} An array containing the next |length| entries, or
* less if the iteration contains less than |length| entries left.
*/
nextBatch: function nextBatch(length) {
let array = [];
let i = 0;
for (let entry in this) {
array.push(entry);
if (++i >= length) {
return array;
}
}
return array;
}
};
/**
* Utility function shared by implementations of |OS.File.open|:
* extract read/write/trunc/create/existing flags from a |mode|

View File

@ -583,53 +583,51 @@
* @constructor
*/
File.DirectoryIterator = function DirectoryIterator(path, options) {
exports.OS.Shared.AbstractFile.AbstractIterator.call(this);
let dir = throw_on_null("DirectoryIterator", UnixFile.opendir(path));
this._dir = dir;
this._path = path;
};
File.DirectoryIterator.prototype = {
__iterator__: function __iterator__() {
return this;
},
/**
* Return the next entry in the directory, if any such entry is
* available.
*
* Skip special directories "." and "..".
*
* @return {File.Entry} The next entry in the directory.
* @throws {StopIteration} Once all files in the directory have been
* encountered.
*/
next: function next() {
if (!this._dir) {
throw StopIteration;
}
for (let entry = UnixFile.readdir(this._dir);
entry != null && !entry.isNull();
entry = UnixFile.readdir(this._dir)) {
let contents = entry.contents;
if (contents.d_type == OS.Constants.libc.DT_DIR) {
let name = contents.d_name.readString();
if (name == "." || name == "..") {
continue;
}
}
return new File.DirectoryIterator.Entry(contents, this._path);
}
this.close();
throw StopIteration;
},
File.DirectoryIterator.prototype = Object.create(exports.OS.Shared.AbstractFile.AbstractIterator.prototype);
/**
* Close the iterator and recover all resources.
* You should call this once you have finished iterating on a directory.
*/
close: function close() {
if (!this._dir) return;
UnixFile.closedir(this._dir);
this._dir = null;
/**
* Return the next entry in the directory, if any such entry is
* available.
*
* Skip special directories "." and "..".
*
* @return {File.Entry} The next entry in the directory.
* @throws {StopIteration} Once all files in the directory have been
* encountered.
*/
File.DirectoryIterator.prototype.next = function next() {
if (!this._dir) {
throw StopIteration;
}
for (let entry = UnixFile.readdir(this._dir);
entry != null && !entry.isNull();
entry = UnixFile.readdir(this._dir)) {
let contents = entry.contents;
if (contents.d_type == OS.Constants.libc.DT_DIR) {
let name = contents.d_name.readString();
if (name == "." || name == "..") {
continue;
}
}
return new File.DirectoryIterator.Entry(contents, this._path);
}
this.close();
throw StopIteration;
};
/**
* Close the iterator and recover all resources.
* You should call this once you have finished iterating on a directory.
*/
File.DirectoryIterator.prototype.close = function close() {
if (!this._dir) return;
UnixFile.closedir(this._dir);
this._dir = null;
};
/**

View File

@ -480,6 +480,7 @@
* @constructor
*/
File.DirectoryIterator = function DirectoryIterator(path, options) {
exports.OS.Shared.AbstractFile.AbstractIterator.call(this);
if (options && options.winPattern) {
this._pattern = path + "\\" + options.winPattern;
} else {
@ -488,18 +489,22 @@
this._handle = null;
this._path = path;
this._started = false;
this._closed = false;
};
File.DirectoryIterator.prototype = {
__iterator__: function __iterator__() {
return this;
},
File.DirectoryIterator.prototype = Object.create(exports.OS.Shared.AbstractFile.AbstractIterator.prototype);
/**
* Fetch the next entry in the directory.
*
* @return null If we have reached the end of the directory.
*/
_next: function _next() {
File.DirectoryIterator.prototype._next = function _next() {
// Bailout if the iterator is closed. Note that this may
// happen even before it is fully initialized.
if (this._closed) {
return null;
}
// Iterator is not fully initialized yet. Finish
// initialization.
if (!this._started) {
@ -517,11 +522,6 @@
return gFindData;
}
// We have closed this iterator already.
if (!this._handle) {
return null;
}
if (WinFile.FindNextFile(this._handle, gFindDataPtr)) {
return gFindData;
} else {
@ -544,7 +544,7 @@
* @throws {StopIteration} Once all files in the directory have been
* encountered.
*/
next: function next() {
File.DirectoryIterator.prototype.next = function next() {
// FIXME: If we start supporting "\\?\"-prefixed paths, do not forget
// that "." and ".." are absolutely normal file names if _path starts
// with such prefix
@ -556,15 +556,22 @@
return new File.DirectoryIterator.Entry(entry, this._path);
}
throw StopIteration;
},
close: function close() {
if (!this._handle) {
return;
}
WinFile.FindClose(this._handle);
};
File.DirectoryIterator.prototype.close = function close() {
if (this._closed) {
return;
}
this._closed = true;
if (this._handle) {
// We might not have a handle if the iterator is closed
// before being used.
throw_on_zero("FindClose",
WinFile.FindClose(this._handle));
this._handle = null;
}
};
File.DirectoryIterator.Entry = function Entry(win_entry, parent) {
// Copy the relevant part of |win_entry| to ensure that
// our data is not overwritten prematurely.

View File

@ -449,6 +449,63 @@ function test_iter_dir()
ok(true, "test_iter_dir: Cleaning up");
iterator.close();
// Testing nextBatch()
iterator = new OS.File.DirectoryIterator(parent);
let allentries = [x for(x in iterator)];
iterator.close();
ok(allentries.length >= 14, "test_iter_dir: Meta-check: the test directory should contain at least 14 items");
iterator = new OS.File.DirectoryIterator(parent);
let firstten = iterator.nextBatch(10);
is(firstten.length, 10, "test_iter_dir: nextBatch(10) returns 10 items");
for (let i = 0; i < firstten.length; ++i) {
is(allentries[i].path, firstten[i].path, "test_iter_dir: Checking that batch returns the correct entries");
}
let nextthree = iterator.nextBatch(3);
is(nextthree.length, 3, "test_iter_dir: nextBatch(3) returns 3 items");
for (let i = 0; i < nextthree.length; ++i) {
is(allentries[i + firstten.length].path, nextthree[i].path, "test_iter_dir: Checking that batch 2 returns the correct entries");
}
let everythingelse = iterator.nextBatch();
ok(everythingelse.length >= 1, "test_iter_dir: nextBatch() returns at least one item");
for (let i = 0; i < everythingelse.length; ++i) {
is(allentries[i + firstten.length + nextthree.length].path, everythingelse[i].path, "test_iter_dir: Checking that batch 3 returns the correct entries");
}
is(iterator.nextBatch().length, 0, "test_iter_dir: Once there is nothing left, nextBatch returns an empty array");
iterator.close();
iterator = new OS.File.DirectoryIterator(parent);
iterator.close();
is(iterator.nextBatch().length, 0, "test_iter_dir: nextBatch on closed iterator returns an empty array");
iterator = new OS.File.DirectoryIterator(parent);
let allentries2 = iterator.nextBatch();
is(allentries.length, allentries2.length, "test_iter_dir: Checking that getBatch(null) returns the right number of entries");
for (let i = 0; i < allentries.length; ++i) {
is(allentries[i].path, allentries2[i].path, "test_iter_dir: Checking that getBatch(null) returns everything in the right order");
}
iterator.close();
// Test forEach
iterator = new OS.File.DirectoryIterator(parent);
let index = 0;
iterator.forEach(
function cb(entry, aIndex, aIterator) {
is(index, aIndex, "test_iter_dir: Checking that forEach index is correct");
ok(iterator == aIterator, "test_iter_dir: Checking that right iterator is passed");
if (index < 10) {
is(allentries[index].path, entry.path, "test_iter_dir: Checking that forEach entry is correct");
} else if (index == 10) {
iterator.close();
} else {
ok(false, "test_iter_dir: Checking that forEach can be stopped early");
}
++index;
});
iterator.close();
ok(true, "test_iter_dir: Complete");
}

View File

@ -1921,6 +1921,12 @@
"n_buckets": 10,
"description": "Firefox: Time taken by the tab closing animation in milliseconds"
},
"FX_TAB_SWITCH_UPDATE_MS": {
"kind": "exponential",
"high": "1000",
"n_buckets": 20,
"description": "Firefox: Time in ms spent updating UI in response to a tab switch"
},
"FX_KEYWORD_URL_USERSET": {
"kind": "boolean",
"description": "Firefox: keyword.URL has a user-set value"

View File

@ -35,6 +35,7 @@ const PREFS_WHITELIST = [
"browser.sessionstore.",
"browser.startup.homepage",
"browser.tabs.",
"browser.urlbar.",
"browser.zoom.",
"dom.",
"extensions.checkCompatibility",

View File

@ -31,8 +31,13 @@ let tests = [
function snapshotSchema(done) {
Troubleshoot.snapshot(function (snapshot) {
validateObject(snapshot, SNAPSHOT_SCHEMA);
ok(true, "The snapshot should conform to the schema.");
try {
validateObject(snapshot, SNAPSHOT_SCHEMA);
ok(true, "The snapshot should conform to the schema.");
}
catch (err) {
ok(false, err);
}
done();
});
},

View File

@ -92,12 +92,9 @@
onset="if (val) this.setAttribute('clickSelectsAll', 'true');
else this.removeAttribute('clickSelectsAll'); return val;" />
<property name="editor" readonly="true">
<getter><![CDATA[
const nsIDOMNSEditableElement = Components.interfaces.nsIDOMNSEditableElement;
return this.inputField.QueryInterface(nsIDOMNSEditableElement).editor;
]]></getter>
</property>
<field name="editor" readonly="true">
this.inputField.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
</field>
<method name="reset">
<body><![CDATA[
@ -217,7 +214,7 @@
<handler event="blur" phase="capturing">
<![CDATA[
this.removeAttribute('focused');
this.removeAttribute("focused");
// don't trigger clickSelectsAll when switching application windows
if (window == window.top &&

View File

@ -11,7 +11,7 @@ interface nsIURI;
interface nsIDOMWindow;
interface nsISimpleEnumerator;
[scriptable, uuid(0d79adad-b244-49A5-9997-2a8cad93fc44)]
[scriptable, function, uuid(0d79adad-b244-49A5-9997-2a8cad93fc44)]
interface nsIFilePickerShownCallback : nsISupports
{
/**

View File

@ -731,33 +731,56 @@ const nsTArray<GfxDriverInfo>&
GfxInfo::GetGfxDriverInfo()
{
if (!mDriverInfo->Length()) {
/*
* It should be noted here that more specialized rules on certain features
* should be inserted -before- more generalized restriction. As the first
* match for feature/OS/device found in the list will be used for the final
* blacklisting call.
*/
/*
* NVIDIA entries
*/
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_XP,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices,
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(6,14,12,5721), "257.21" );
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_VISTA,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices,
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" );
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_7,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices,
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" );
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_XP,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices,
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(6,14,11,8265), "182.65" );
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_VISTA,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices,
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(8,17,11,8265), "182.65" );
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_7,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), GfxDriverInfo::allDevices,
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(8,17,11,8265), "182.65" );
/*
* AMD/ATI entries
*/
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices,
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(8,741,0,0), "10.6" );
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAMD), GfxDriverInfo::allDevices,
nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(8,741,0,0), "10.6" );
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices,
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(8,62,0,0), "9.6" );
APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAMD), GfxDriverInfo::allDevices,
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN, V(8,741,0,0), "10.6" );
DRIVER_LESS_THAN, V(8,62,0,0), "9.6" );
/*
* Bug 783517 - crashes in AMD driver on Windows 8
@ -807,27 +830,46 @@ GfxInfo::GetGfxDriverInfo()
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(devFamily), \
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, \
DRIVER_LESS_THAN, driverVer )
#define IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(winVer, devFamily, driverVer) \
APPEND_TO_DRIVER_BLOCKLIST2( winVer, \
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(devFamily), \
nsIGfxInfo::FEATURE_DIRECT2D, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, \
DRIVER_LESS_THAN, driverVer )
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA500, V(6,14,11,1018));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMA500, V(7,14,10,1006));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMA900, GfxDriverInfo::allDriverVersions);
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMA950, V(7,14,10,1504));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMA3150, V(7,14,10,2124));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMAX3000, V(7,15,10,1666));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_VISTA, IntelGMAX4500HD, V(8,15,10,2202));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMA500, V(5,0,0,2026));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMA900, GfxDriverInfo::allDriverVersions);
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMA950, V(8,15,10,1930));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMA3150, V(8,14,10,2117));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMAX3000, V(8,15,10,1930));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST_D2D(DRIVER_OS_WINDOWS_7, IntelGMAX4500HD, V(8,15,10,2202));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA500, V(3,0,20,3200));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA900, V(6,14,10,4764));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA950, V(6,14,10,4926));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA3150, V(6,14,10,5260));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMA3150, V(6,14,10,5134));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMAX3000, V(6,14,10,5218));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, IntelGMAX4500HD, V(6,14,10,5284));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA500, V(7,14,10,1006));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA500, V(3,0,20,3200));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA900, GfxDriverInfo::allDriverVersions);
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA950, V(7,14,10,1504));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA3150, V(7,14,10,2124));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMA3150, V(7,14,10,1910));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMAX3000, V(7,15,10,1666));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMAX4500HD, V(8,15,10,2202));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, IntelGMAX4500HD, V(8,15,10,1855));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMA500, V(5,0,0,2026));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMA900, GfxDriverInfo::allDriverVersions);
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMA950, V(8,15,10,1930));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMA3150, V(8,14,10,2117));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMA3150, V(8,14,10,1972));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMAX3000, V(8,15,10,1930));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMAX4500HD, V(8,15,10,2202));
IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, IntelGMAX4500HD, V(8,15,10,1855));
/* OpenGL on any Intel hardware is discouraged */
APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL,

View File

@ -79,57 +79,6 @@ void passed(const char* msg, ...)
putchar('\n');
}
//-----------------------------------------------------------------------------
// Code profiling
//
static const char* gCurrentProfile;
/**
* If the build has been configured properly, start the best code profiler
* available on this platform.
*
* This is NOT thread safe.
*
* @precondition Profiling is not started
* @param profileName A descriptive name for this profiling run. Every
* attempt is made to name the profile data according
* to this name, but check your platform's profiler
* documentation for what this means.
* @return true if profiling was available and successfully started.
* @see StopProfiling
*/
inline bool
StartProfiling(const char* profileName)
{
NS_ASSERTION(profileName, "need a name for this profile");
NS_PRECONDITION(!gCurrentProfile, "started a new profile before stopping another");
JSBool ok = JS_StartProfiling(profileName);
gCurrentProfile = profileName;
return ok ? true : false;
}
/**
* Stop the platform's profiler. For what this means, what happens after
* stopping, and how the profile data can be accessed, check the
* documentation of your platform's profiler.
*
* This is NOT thread safe.
*
* @precondition Profiling was started
* @return true if profiling was successfully stopped.
* @see StartProfiling
*/
inline bool
StopProfiling()
{
NS_PRECONDITION(gCurrentProfile, "tried to stop profile before starting one");
const char* profileName = gCurrentProfile;
gCurrentProfile = 0;
return JS_StopProfiling(profileName) ? true : false;
}
//-----------------------------------------------------------------------------
class ScopedLogging