зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
c715836c7f
|
@ -34,7 +34,7 @@ unwantedBlocked=The site at %S has been reported as serving unwanted software an
|
|||
deceptiveBlocked=This web page at %S has been reported as a deceptive site and has been blocked based on your security preferences.
|
||||
forbiddenBlocked=The site at %S has been blocked by your browser configuration.
|
||||
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
|
||||
corruptedContentError=The site at %S has experienced a network protocol violation that cannot be repaired.
|
||||
corruptedContentErrorv2=The site at %S has experienced a network protocol violation that cannot be repaired.
|
||||
remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.
|
||||
sslv3Used=Firefox cannot guarantee the safety of your data on %S because it uses SSLv3, a broken security protocol.
|
||||
weakCryptoUsed=The owner of %S has configured their website improperly. To protect your information from being stolen, Firefox has not connected to this website.
|
||||
|
|
|
@ -87,5 +87,8 @@ tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME)
|
|||
rsync -aL $(DIST)/bin/$(MOZ_APP_NAME) $(dist_dest)/Contents/MacOS
|
||||
cp -RL $(DIST)/branding/firefox.icns $(dist_dest)/Contents/Resources/firefox.icns
|
||||
cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns
|
||||
$(MKDIR) -p $(dist_dest)/Contents/Library/LaunchServices
|
||||
mv -f $(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater $(dist_dest)/Contents/Library/LaunchServices
|
||||
ln -s ../../../../Library/LaunchServices/org.mozilla.updater $(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater
|
||||
printf APPLMOZB > $(dist_dest)/Contents/PkgInfo
|
||||
endif
|
||||
|
|
|
@ -211,6 +211,11 @@
|
|||
<true/>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>GeckoNSApplication</string>
|
||||
<key>SMPrivilegedExecutables</key>
|
||||
<dict>
|
||||
<key>org.mozilla.updater</key>
|
||||
<string>identifier "org.mozilla.updater" and ((anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9]) or (anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] and certificate leaf[field.1.2.840.113635.100.6.1.13] and certificate leaf[subject.OU] = "43AQ936H96"))</string>
|
||||
</dict>
|
||||
<key>NSDisablePersistence</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
|
|
@ -10,6 +10,9 @@ Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
|
||||
"resource://gre/modules/UpdateUtils.jsm");
|
||||
|
||||
const PREF_APP_UPDATE_CANCELATIONS_OSX = "app.update.cancelations.osx";
|
||||
const PREF_APP_UPDATE_ELEVATE_NEVER = "app.update.elevate.never";
|
||||
|
||||
var gAppUpdater;
|
||||
|
||||
function onUnload(aEvent) {
|
||||
|
@ -76,7 +79,8 @@ function appUpdater()
|
|||
// update checks, but also in the About dialog, by presenting a
|
||||
// "Check for updates" button.
|
||||
// If updates are found, the user is then asked if he wants to "Update to <version>".
|
||||
if (!this.updateEnabled) {
|
||||
if (!this.updateEnabled ||
|
||||
Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_NEVER)) {
|
||||
this.selectPanel("checkForUpdates");
|
||||
return;
|
||||
}
|
||||
|
@ -98,11 +102,13 @@ appUpdater.prototype =
|
|||
get isPending() {
|
||||
if (this.update) {
|
||||
return this.update.state == "pending" ||
|
||||
this.update.state == "pending-service";
|
||||
this.update.state == "pending-service" ||
|
||||
this.update.state == "pending-elevate";
|
||||
}
|
||||
return this.um.activeUpdate &&
|
||||
(this.um.activeUpdate.state == "pending" ||
|
||||
this.um.activeUpdate.state == "pending-service");
|
||||
this.um.activeUpdate.state == "pending-service" ||
|
||||
this.um.activeUpdate.state == "pending-elevate");
|
||||
},
|
||||
|
||||
// true when there is an update already installed in the background.
|
||||
|
@ -183,6 +189,13 @@ appUpdater.prototype =
|
|||
* Check for updates
|
||||
*/
|
||||
checkForUpdates: function() {
|
||||
// Clear prefs that could prevent a user from discovering available updates.
|
||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS_OSX)) {
|
||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS_OSX);
|
||||
}
|
||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_NEVER)) {
|
||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_ELEVATE_NEVER);
|
||||
}
|
||||
this.selectPanel("checkingForUpdates");
|
||||
this.isChecking = true;
|
||||
this.checker.checkForUpdates(this.updateCheckListener, true);
|
||||
|
@ -194,8 +207,9 @@ appUpdater.prototype =
|
|||
* which is presented after the download has been downloaded.
|
||||
*/
|
||||
buttonRestartAfterDownload: function() {
|
||||
if (!this.isPending && !this.isApplied)
|
||||
if (!this.isPending && !this.isApplied) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify all windows that an application quit has been requested.
|
||||
let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
|
||||
|
@ -203,8 +217,9 @@ appUpdater.prototype =
|
|||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
|
||||
|
||||
// Something aborted the quit process.
|
||||
if (cancelQuit.data)
|
||||
if (cancelQuit.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
|
||||
getService(Components.interfaces.nsIAppStartup);
|
||||
|
@ -371,7 +386,8 @@ appUpdater.prototype =
|
|||
// Update the UI when the background updater is finished
|
||||
let status = aData;
|
||||
if (status == "applied" || status == "applied-service" ||
|
||||
status == "pending" || status == "pending-service") {
|
||||
status == "pending" || status == "pending-service" ||
|
||||
status == "pending-elevate") {
|
||||
// If the update is successfully applied, or if the updater has
|
||||
// fallen back to non-staged updates, show the "Restart to Update"
|
||||
// button.
|
||||
|
|
|
@ -521,7 +521,7 @@
|
|||
<h1 id="et_nssBadCert">&certerror.longpagetitle1;</h1>
|
||||
<h1 id="et_cspBlocked">&cspBlocked.title;</h1>
|
||||
<h1 id="et_remoteXUL">&remoteXUL.title;</h1>
|
||||
<h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
|
||||
<h1 id="et_corruptedContentErrorv2">&corruptedContentErrorv2.title;</h1>
|
||||
<h1 id="et_sslv3Used">&sslv3Used.title;</h1>
|
||||
<h1 id="et_weakCryptoUsed">&weakCryptoUsed.title;</h1>
|
||||
<h1 id="et_inadequateSecurityError">&inadequateSecurityError.title;</h1>
|
||||
|
@ -550,7 +550,7 @@
|
|||
<div id="ed_nssBadCert">&certerror.introPara;</div>
|
||||
<div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
|
||||
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
|
||||
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>
|
||||
<div id="ed_corruptedContentErrorv2">&corruptedContentErrorv2.longDesc;</div>
|
||||
<div id="ed_sslv3Used">&sslv3Used.longDesc2;</div>
|
||||
<div id="ed_weakCryptoUsed">&weakCryptoUsed.longDesc2;</div>
|
||||
<div id="ed_inadequateSecurityError">&inadequateSecurityError.longDesc;</div>
|
||||
|
|
|
@ -2568,6 +2568,7 @@ var gMenuButtonUpdateBadge = {
|
|||
enabled: false,
|
||||
badgeWaitTime: 0,
|
||||
timer: null,
|
||||
cancelObserverRegistered: false,
|
||||
|
||||
init: function () {
|
||||
try {
|
||||
|
@ -2592,6 +2593,10 @@ var gMenuButtonUpdateBadge = {
|
|||
Services.obs.removeObserver(this, "update-downloaded");
|
||||
this.enabled = false;
|
||||
}
|
||||
if (this.cancelObserverRegistered) {
|
||||
Services.obs.removeObserver(this, "update-canceled");
|
||||
this.cancelObserverRegistered = false;
|
||||
}
|
||||
},
|
||||
|
||||
onMenuPanelCommand: function(event) {
|
||||
|
@ -2612,11 +2617,15 @@ var gMenuButtonUpdateBadge = {
|
|||
},
|
||||
|
||||
observe: function (subject, topic, status) {
|
||||
if (topic == "update-canceled") {
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
if (status == "failed") {
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
this.displayBadge(false);
|
||||
this.uninit();
|
||||
this.displayBadge(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2631,8 +2640,8 @@ var gMenuButtonUpdateBadge = {
|
|||
// If the update is successfully applied, or if the updater has fallen back
|
||||
// to non-staged updates, add a badge to the hamburger menu to indicate an
|
||||
// update will be applied once the browser restarts.
|
||||
this.displayBadge(true);
|
||||
this.uninit();
|
||||
this.displayBadge(true);
|
||||
},
|
||||
|
||||
displayBadge: function (succeeded) {
|
||||
|
@ -2648,6 +2657,8 @@ var gMenuButtonUpdateBadge = {
|
|||
stringId = "appmenu.restartNeeded.description";
|
||||
updateButtonText = gNavigatorBundle.getFormattedString(stringId,
|
||||
[brandShortName]);
|
||||
Services.obs.addObserver(this, "update-canceled", false);
|
||||
this.cancelObserverRegistered = true;
|
||||
} else {
|
||||
stringId = "appmenu.updateFailed.description";
|
||||
updateButtonText = gNavigatorBundle.getString(stringId);
|
||||
|
@ -2657,6 +2668,15 @@ var gMenuButtonUpdateBadge = {
|
|||
updateButton.setAttribute("label", updateButtonText);
|
||||
updateButton.setAttribute("update-status", status);
|
||||
updateButton.hidden = false;
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
gMenuButtonBadgeManager.removeBadge(
|
||||
gMenuButtonBadgeManager.BADGEID_APPUPDATE);
|
||||
let updateButton = document.getElementById("PanelUI-update-status");
|
||||
updateButton.hidden = true;
|
||||
this.uninit();
|
||||
this.init();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -60,6 +60,73 @@ var TabStateCacheInternal = {
|
|||
return this._data.get(browserOrTab.permanentKey);
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function used by update (see below). For message size
|
||||
* optimization sometimes we don't update the whole session storage
|
||||
* only the values those have been changed.
|
||||
*
|
||||
* @param data (object)
|
||||
* The cached data where we want to update the changes.
|
||||
* @param change (object)
|
||||
* The actual changed values per domain.
|
||||
*/
|
||||
updatePartialStorageChange: function (data, change) {
|
||||
if (!data.storage) {
|
||||
data.storage = {};
|
||||
}
|
||||
|
||||
let storage = data.storage;
|
||||
for (let domain of Object.keys(change)) {
|
||||
for (let key of Object.keys(change[domain])) {
|
||||
let value = change[domain][key];
|
||||
if (value === null) {
|
||||
if (storage[domain] && storage[domain][key]) {
|
||||
delete storage[domain][key];
|
||||
}
|
||||
} else {
|
||||
if (!storage[domain]) {
|
||||
storage[domain] = {};
|
||||
}
|
||||
storage[domain][key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function used by update (see below). For message size
|
||||
* optimization sometimes we don't update the whole browser history
|
||||
* only the current index and the tail of the history from a certain
|
||||
* index (specified by change.fromIdx)
|
||||
*
|
||||
* @param data (object)
|
||||
* The cached data where we want to update the changes.
|
||||
* @param change (object)
|
||||
* Object containing the tail of the history array, and
|
||||
* some additional metadata.
|
||||
*/
|
||||
updatePartialHistoryChange: function (data, change) {
|
||||
const kLastIndex = Number.MAX_SAFE_INTEGER - 1;
|
||||
|
||||
if (!data.history) {
|
||||
data.history = { entries: [] };
|
||||
}
|
||||
|
||||
let history = data.history;
|
||||
for (let key of Object.keys(change)) {
|
||||
if (key == "entries") {
|
||||
if (change.fromIdx != kLastIndex) {
|
||||
history.entries.splice(change.fromIdx + 1);
|
||||
while (change.entries.length) {
|
||||
history.entries.push(change.entries.shift());
|
||||
}
|
||||
}
|
||||
} else if (key != "fromIndex") {
|
||||
history[key] = change[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates cached data for a given |tab| or associated |browser|.
|
||||
*
|
||||
|
@ -73,6 +140,16 @@ var TabStateCacheInternal = {
|
|||
let data = this._data.get(browserOrTab.permanentKey) || {};
|
||||
|
||||
for (let key of Object.keys(newData)) {
|
||||
if (key == "storagechange") {
|
||||
this.updatePartialStorageChange(data, newData.storagechange);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == "historychange") {
|
||||
this.updatePartialHistoryChange(data, newData.historychange);
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = newData[key];
|
||||
if (value === null) {
|
||||
delete data[key];
|
||||
|
|
|
@ -49,6 +49,9 @@ const DOM_STORAGE_MAX_CHARS = 10000000; // 10M characters
|
|||
// or not, and should only be used for tests or debugging.
|
||||
const TIMEOUT_DISABLED_PREF = "browser.sessionstore.debug.no_auto_updates";
|
||||
|
||||
const kNoIndex = Number.MAX_SAFE_INTEGER;
|
||||
const kLastIndex = Number.MAX_SAFE_INTEGER - 1;
|
||||
|
||||
/**
|
||||
* Returns a lazy function that will evaluate the given
|
||||
* function |fn| only once and cache its return value.
|
||||
|
@ -252,11 +255,51 @@ var SessionHistoryListener = {
|
|||
},
|
||||
|
||||
collect: function () {
|
||||
this._fromIdx = kNoIndex;
|
||||
if (docShell) {
|
||||
MessageQueue.push("history", () => SessionHistory.collect(docShell));
|
||||
}
|
||||
},
|
||||
|
||||
_fromIdx: kNoIndex,
|
||||
|
||||
// History can grow relatively big with the nested elements, so if we don't have to, we
|
||||
// don't want to send the entire history all the time. For a simple optimization
|
||||
// we keep track of the smallest index from after any change has occured and we just send
|
||||
// the elements from that index. If something more complicated happens we just clear it
|
||||
// and send the entire history. We always send the additional info like the current selected
|
||||
// index (so for going back and forth between history entries we set the index to kLastIndex
|
||||
// if nothing else changed send an empty array and the additonal info like the selected index)
|
||||
collectFrom: function (idx) {
|
||||
if (this._fromIdx <= idx) {
|
||||
// If we already know that we need to update history fromn index N we can ignore any changes
|
||||
// tha happened with an element with index larger than N.
|
||||
// Note: initially we use kNoIndex which is MAX_SAFE_INTEGER which means we don't ignore anything
|
||||
// here, and in case of navigation in the history back and forth we use kLastIndex which ignores
|
||||
// only the subsequent navigations, but not any new elements added.
|
||||
return;
|
||||
}
|
||||
|
||||
this._fromIdx = idx;
|
||||
MessageQueue.push("historychange", () => {
|
||||
if (this._fromIdx === kNoIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let history = SessionHistory.collect(docShell);
|
||||
if (kLastIndex == idx) {
|
||||
history.entries = [];
|
||||
} else {
|
||||
history.entries.splice(0, this._fromIdx + 1);
|
||||
}
|
||||
|
||||
history.fromIdx = this._fromIdx;
|
||||
|
||||
this._fromIdx = kNoIndex;
|
||||
return history;
|
||||
});
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
this.collect();
|
||||
},
|
||||
|
@ -269,22 +312,22 @@ var SessionHistoryListener = {
|
|||
this.collect();
|
||||
},
|
||||
|
||||
OnHistoryNewEntry: function (newURI) {
|
||||
this.collect();
|
||||
OnHistoryNewEntry: function (newURI, oldIndex) {
|
||||
this.collectFrom(oldIndex);
|
||||
},
|
||||
|
||||
OnHistoryGoBack: function (backURI) {
|
||||
this.collect();
|
||||
this.collectFrom(kLastIndex);
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryGoForward: function (forwardURI) {
|
||||
this.collect();
|
||||
this.collectFrom(kLastIndex);
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryGotoIndex: function (index, gotoURI) {
|
||||
this.collect();
|
||||
this.collectFrom(kLastIndex);
|
||||
return true;
|
||||
},
|
||||
|
||||
|
@ -496,7 +539,7 @@ var SessionStorageListener = {
|
|||
|
||||
handleEvent: function (event) {
|
||||
if (gFrameTree.contains(event.target)) {
|
||||
this.collect();
|
||||
this.collectFromEvent(event);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -537,8 +580,47 @@ var SessionStorageListener = {
|
|||
return size;
|
||||
},
|
||||
|
||||
// We don't want to send all the session storage data for all the frames
|
||||
// for every change. So if only a few value changed we send them over as
|
||||
// a "storagechange" event. If however for some reason before we send these
|
||||
// changes we have to send over the entire sessions storage data, we just
|
||||
// reset these changes.
|
||||
_changes: undefined,
|
||||
|
||||
resetChanges: function () {
|
||||
this._changes = undefined;
|
||||
},
|
||||
|
||||
collectFromEvent: function (event) {
|
||||
// TODO: we should take browser.sessionstore.dom_storage_limit into an account here.
|
||||
if (docShell) {
|
||||
let {url, key, newValue} = event;
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
let domain = uri.prePath;
|
||||
if (!this._changes) {
|
||||
this._changes = {};
|
||||
}
|
||||
if (!this._changes[domain]) {
|
||||
this._changes[domain] = {};
|
||||
}
|
||||
this._changes[domain][key] = newValue;
|
||||
|
||||
MessageQueue.push("storagechange", () => {
|
||||
let tmp = this._changes;
|
||||
// If there were multiple changes we send them merged.
|
||||
// First one will collect all the changes the rest of
|
||||
// these messages will be ignored.
|
||||
this.resetChanges();
|
||||
return tmp;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
collect: function () {
|
||||
if (docShell) {
|
||||
// We need the entire session storage, let's reset the pending individual change
|
||||
// messages.
|
||||
this.resetChanges();
|
||||
MessageQueue.push("storage", () => {
|
||||
let collected = SessionStorage.collect(docShell, gFrameTree);
|
||||
|
||||
|
@ -727,7 +809,7 @@ var MessageQueue = {
|
|||
for (let histogramId of Object.keys(value)) {
|
||||
telemetry[histogramId] = value[histogramId];
|
||||
}
|
||||
} else {
|
||||
} else if (value || (key != "storagechange" && key != "historychange")) {
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#ifdef XP_MACOSX
|
||||
; Mac bundle stuff
|
||||
@APPNAME@/Contents/Info.plist
|
||||
@APPNAME@/Contents/Library/LaunchServices
|
||||
@APPNAME@/Contents/PkgInfo
|
||||
@RESPATH@/firefox.icns
|
||||
@RESPATH@/document.icns
|
||||
|
|
|
@ -35,7 +35,7 @@ unwantedBlocked=The site at %S has been reported as serving unwanted software an
|
|||
deceptiveBlocked=This web page at %S has been reported as a deceptive site and has been blocked based on your security preferences.
|
||||
forbiddenBlocked=The site at %S has been blocked by your browser configuration.
|
||||
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
|
||||
corruptedContentError=The site at %S has experienced a network protocol violation that cannot be repaired.
|
||||
corruptedContentErrorv2=The site at %S has experienced a network protocol violation that cannot be repaired.
|
||||
remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.
|
||||
## LOCALIZATION NOTE (sslv3Used) - Do not translate "%S".
|
||||
sslv3Used=Firefox cannot guarantee the safety of your data on %S because it uses SSLv3, a broken security protocol.
|
||||
|
|
|
@ -165,8 +165,8 @@ was trying to connect. -->
|
|||
<!ENTITY cspBlocked.title "Blocked by Content Security Policy">
|
||||
<!ENTITY cspBlocked.longDesc "<p>&brandShortName; prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">
|
||||
|
||||
<!ENTITY corruptedContentError.title "Corrupted Content Error">
|
||||
<!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
|
||||
<!ENTITY corruptedContentErrorv2.title "Corrupted Content Error">
|
||||
<!ENTITY corruptedContentErrorv2.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
|
||||
|
||||
|
||||
<!ENTITY securityOverride.exceptionButtonLabel "Add Exception…">
|
||||
|
|
|
@ -251,7 +251,6 @@ def old_configure_options(*options):
|
|||
'--enable-system-pixman',
|
||||
'--enable-system-sqlite',
|
||||
'--enable-tasktracer',
|
||||
'--enable-tests',
|
||||
'--enable-thread-sanitizer',
|
||||
'--enable-trace-logging',
|
||||
'--enable-tree-freetype',
|
||||
|
|
|
@ -36,12 +36,15 @@ def get_hg_info(workdir):
|
|||
repo = 'https://' + repo[6:]
|
||||
repo = repo.rstrip('/')
|
||||
|
||||
changeset = get_program_output(
|
||||
'hg', '-R', workdir, 'parent', '--template={node}')
|
||||
changeset = get_hg_changeset(workdir)
|
||||
|
||||
return repo, changeset
|
||||
|
||||
|
||||
def get_hg_changeset(path):
|
||||
return get_program_output('hg', '-R', path, 'parent', '--template={node}')
|
||||
|
||||
|
||||
def source_repo_header(output):
|
||||
# We allow the source repo and changeset to be specified via the
|
||||
# environment (see configure)
|
||||
|
@ -50,13 +53,14 @@ def source_repo_header(output):
|
|||
changeset = buildconfig.substs.get('MOZ_SOURCE_CHANGESET')
|
||||
source = ''
|
||||
|
||||
if bool(repo) != bool(changeset):
|
||||
raise Exception('MOZ_SOURCE_REPO and MOZ_SOURCE_CHANGESET both must '
|
||||
'be set (or not set).')
|
||||
|
||||
if not repo:
|
||||
if os.path.exists(os.path.join(buildconfig.topsrcdir, '.hg')):
|
||||
repo, changeset = get_hg_info(buildconfig.topsrcdir)
|
||||
elif not changeset:
|
||||
changeset = get_hg_changeset(buildconfig.topsrcdir)
|
||||
if not changeset:
|
||||
raise Exception('could not resolve changeset; '
|
||||
'try setting MOZ_SOURCE_CHANGESET')
|
||||
|
||||
if changeset:
|
||||
output.write('#define MOZ_SOURCE_STAMP %s\n' % changeset)
|
||||
|
|
|
@ -690,6 +690,7 @@ SSL_SetSockPeerID
|
|||
SSL_SetSRTPCiphers
|
||||
SSL_SetStapledOCSPResponses
|
||||
SSL_SetURL
|
||||
SSL_ShutdownServerSessionIDCache
|
||||
SSL_SNISocketConfigHook
|
||||
SSL_VersionRangeGet
|
||||
SSL_VersionRangeGetDefault
|
||||
|
|
|
@ -73,14 +73,14 @@ class _MozTestResult(_TestResult):
|
|||
|
||||
def printFail(self, test, err):
|
||||
exctype, value, tb = err
|
||||
message = value.message.splitlines()[0]
|
||||
# Skip test runner traceback levels
|
||||
while tb and self._is_relevant_tb_level(tb):
|
||||
tb = tb.tb_next
|
||||
if not tb:
|
||||
self.stream.writeln("TEST-UNEXPECTED-FAIL | NO TRACEBACK |")
|
||||
_f, _ln, _t = inspect.getframeinfo(tb)[:3]
|
||||
self.printStatus('TEST-UNEXPECTED-FAIL', test,
|
||||
'line {0}: {1}'.format(_ln, value.message))
|
||||
if tb:
|
||||
_, ln, _ = inspect.getframeinfo(tb)[:3]
|
||||
message = 'line {0}: {1}'.format(ln, message)
|
||||
self.printStatus("TEST-UNEXPECTED-FAIL", test, message)
|
||||
|
||||
|
||||
class MozTestRunner(_TestRunner):
|
||||
|
|
|
@ -23,7 +23,7 @@ var testData = [
|
|||
["n", {}, "none", -1, 0, true],
|
||||
["VK_TAB", {shiftKey: true}, "display", -1, 0, true],
|
||||
["VK_BACK_SPACE", {}, "", -1, 0, false],
|
||||
["o", {}, "overflow", 13, 16, false],
|
||||
["o", {}, "overflow", 13, 17, false],
|
||||
["u", {}, "outline", 0, 5, false],
|
||||
["VK_DOWN", {}, "outline-color", 1, 5, false],
|
||||
["VK_TAB", {}, "none", -1, 0, true],
|
||||
|
|
|
@ -602,19 +602,19 @@ ResponsiveUI.prototype = {
|
|||
let volumeUp = this.chromeDoc.createElement("button");
|
||||
volumeUp.className = "devtools-responsiveui-volume-up-button";
|
||||
volumeUp.addEventListener("mousedown", () => {
|
||||
SystemAppProxy.dispatchKeyboardEvent("keydown", {key: "VolumeUp"});
|
||||
SystemAppProxy.dispatchKeyboardEvent("keydown", {key: "AudioVolumeUp"});
|
||||
});
|
||||
volumeUp.addEventListener("mouseup", () => {
|
||||
SystemAppProxy.dispatchKeyboardEvent("keyup", {key: "VolumeUp"});
|
||||
SystemAppProxy.dispatchKeyboardEvent("keyup", {key: "AudioVolumeUp"});
|
||||
});
|
||||
|
||||
let volumeDown = this.chromeDoc.createElement("button");
|
||||
volumeDown.className = "devtools-responsiveui-volume-down-button";
|
||||
volumeDown.addEventListener("mousedown", () => {
|
||||
SystemAppProxy.dispatchKeyboardEvent("keydown", {key: "VolumeDown"});
|
||||
SystemAppProxy.dispatchKeyboardEvent("keydown", {key: "AudioVolumeDown"});
|
||||
});
|
||||
volumeDown.addEventListener("mouseup", () => {
|
||||
SystemAppProxy.dispatchKeyboardEvent("keyup", {key: "VolumeDown"});
|
||||
SystemAppProxy.dispatchKeyboardEvent("keyup", {key: "AudioVolumeDown"});
|
||||
});
|
||||
|
||||
volumeButtons.appendChild(volumeUp);
|
||||
|
|
|
@ -5066,11 +5066,11 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
|
|||
break;
|
||||
case NS_ERROR_CORRUPTED_CONTENT:
|
||||
// Broken Content Detected. e.g. Content-MD5 check failure.
|
||||
error.AssignLiteral("corruptedContentError");
|
||||
error.AssignLiteral("corruptedContentErrorv2");
|
||||
break;
|
||||
case NS_ERROR_INTERCEPTION_FAILED:
|
||||
// ServiceWorker intercepted request, but something went wrong.
|
||||
error.AssignLiteral("corruptedContentError");
|
||||
error.AssignLiteral("corruptedContentErrorv2");
|
||||
break;
|
||||
case NS_ERROR_NET_INADEQUATE_SECURITY:
|
||||
// Server negotiated bad TLS for HTTP/2.
|
||||
|
|
|
@ -307,7 +307,7 @@
|
|||
<h1 id="et_nssBadCert">&nssBadCert.title;</h1>
|
||||
<h1 id="et_cspBlocked">&cspBlocked.title;</h1>
|
||||
<h1 id="et_remoteXUL">&remoteXUL.title;</h1>
|
||||
<h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
|
||||
<h1 id="et_corruptedContentErrorv2">&corruptedContentErrorv2.title;</h1>
|
||||
<h1 id="et_inadequateSecurityError">&inadequateSecurityError.title;</h1>
|
||||
</div>
|
||||
<div id="errorDescriptionsContainer">
|
||||
|
@ -334,7 +334,7 @@
|
|||
<div id="ed_nssBadCert">&nssBadCert.longDesc2;</div>
|
||||
<div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
|
||||
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
|
||||
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>
|
||||
<div id="ed_corruptedContentErrorv2">&corruptedContentErrorv2.longDesc;</div>
|
||||
<div id="ed_inadequateSecurityError">&inadequateSecurityError.longDesc;</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -30,8 +30,9 @@ interface nsISHistoryListener : nsISupports
|
|||
* or content area, for example via nsIWebNavigation::loadURI()
|
||||
*
|
||||
* @param aNewURI The URI of the document to be added to session history.
|
||||
* @param aOldIndex The index of the current history item before the operation.
|
||||
*/
|
||||
void OnHistoryNewEntry(in nsIURI aNewURI);
|
||||
void OnHistoryNewEntry(in nsIURI aNewURI, in long aOldIndex);
|
||||
|
||||
/**
|
||||
* Called when navigating to a previous session history entry, for example
|
||||
|
|
|
@ -402,7 +402,7 @@ nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool aPersist)
|
|||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
aSHEntry->GetURI(getter_AddRefs(uri));
|
||||
NOTIFY_LISTENERS(OnHistoryNewEntry, (uri));
|
||||
NOTIFY_LISTENERS(OnHistoryNewEntry, (uri, currentIndex));
|
||||
|
||||
// If a listener has changed mIndex, we need to get currentTxn again,
|
||||
// otherwise we'll be left at an inconsistent state (see bug 320742)
|
||||
|
|
|
@ -553,7 +553,8 @@ ScreenOrientation::UpdateActiveOrientationLock(ScreenOrientationInternal aOrient
|
|||
if (aOrientation == eScreenOrientation_None) {
|
||||
hal::UnlockScreenOrientation();
|
||||
} else {
|
||||
hal::LockScreenOrientation(aOrientation);
|
||||
bool rv = hal::LockScreenOrientation(aOrientation);
|
||||
NS_WARN_IF(!rv);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -444,6 +444,7 @@ LOCAL_INCLUDES += [
|
|||
'/js/xpconnect/src',
|
||||
'/js/xpconnect/wrappers',
|
||||
'/layout/base',
|
||||
'/layout/forms',
|
||||
'/layout/generic',
|
||||
'/layout/style',
|
||||
'/layout/svg',
|
||||
|
|
|
@ -3056,10 +3056,11 @@ nsContentUtils::GetImgLoaderForDocument(nsIDocument* aDoc)
|
|||
NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aDoc), nullptr);
|
||||
|
||||
if (!aDoc) {
|
||||
return imgLoader::Singleton();
|
||||
return imgLoader::NormalLoader();
|
||||
}
|
||||
bool isPrivate = IsInPrivateBrowsing(aDoc);
|
||||
return isPrivate ? imgLoader::PBSingleton() : imgLoader::Singleton();
|
||||
return isPrivate ? imgLoader::PrivateBrowsingLoader()
|
||||
: imgLoader::NormalLoader();
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -3069,11 +3070,14 @@ nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel,
|
|||
{
|
||||
NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aContext), nullptr);
|
||||
|
||||
if (!aChannel)
|
||||
return imgLoader::Singleton();
|
||||
if (!aChannel) {
|
||||
return imgLoader::NormalLoader();
|
||||
}
|
||||
nsCOMPtr<nsILoadContext> context;
|
||||
NS_QueryNotificationCallbacks(aChannel, context);
|
||||
return context && context->UsePrivateBrowsing() ? imgLoader::PBSingleton() : imgLoader::Singleton();
|
||||
return context && context->UsePrivateBrowsing() ?
|
||||
imgLoader::PrivateBrowsingLoader() :
|
||||
imgLoader::NormalLoader();
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -2634,15 +2634,6 @@ private:
|
|||
static nsIIOService *sIOService;
|
||||
static nsIUUIDGenerator *sUUIDGenerator;
|
||||
|
||||
static bool sImgLoaderInitialized;
|
||||
static void InitImgLoader();
|
||||
|
||||
// The following four members are initialized lazily
|
||||
static imgLoader* sImgLoader;
|
||||
static imgLoader* sPrivateImgLoader;
|
||||
static imgICache* sImgCache;
|
||||
static imgICache* sPrivateImgCache;
|
||||
|
||||
static nsIConsoleService* sConsoleService;
|
||||
|
||||
static nsDataHashtable<nsISupportsHashKey, EventNameMapping>* sAtomEventTable;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "nsStyleCoord.h"
|
||||
#include "TabChild.h"
|
||||
#include "nsFrameLoader.h"
|
||||
#include "nsNumberControlFrame.h"
|
||||
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
@ -310,6 +311,24 @@ nsFocusManager::GetFocusedDescendant(nsPIDOMWindowOuter* aWindow, bool aDeep,
|
|||
nsIContent*
|
||||
nsFocusManager::GetRedirectedFocus(nsIContent* aContent)
|
||||
{
|
||||
// For input number, redirect focus to our anonymous text control.
|
||||
if (aContent->IsHTMLElement(nsGkAtoms::input)) {
|
||||
bool typeIsNumber =
|
||||
static_cast<dom::HTMLInputElement*>(aContent)->GetType() ==
|
||||
NS_FORM_INPUT_NUMBER;
|
||||
|
||||
if (typeIsNumber) {
|
||||
nsNumberControlFrame* numberControlFrame =
|
||||
do_QueryFrame(aContent->GetPrimaryFrame());
|
||||
|
||||
if (numberControlFrame) {
|
||||
HTMLInputElement* textControl =
|
||||
numberControlFrame->GetAnonTextControl();
|
||||
return static_cast<nsIContent*>(textControl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
if (aContent->IsXULElement()) {
|
||||
nsCOMPtr<nsIDOMNode> inputField;
|
||||
|
@ -1505,8 +1524,8 @@ nsFocusManager::CheckIfFocusable(nsIContent* aContent, uint32_t aFlags)
|
|||
if (!aContent)
|
||||
return nullptr;
|
||||
|
||||
// this is a special case for some XUL elements where an anonymous child is
|
||||
// actually focusable and not the element itself.
|
||||
// this is a special case for some XUL elements or input number, where an
|
||||
// anonymous child is actually focusable and not the element itself.
|
||||
nsIContent* redirectedFocus = GetRedirectedFocus(aContent);
|
||||
if (redirectedFocus)
|
||||
return CheckIfFocusable(redirectedFocus, aFlags);
|
||||
|
|
|
@ -114,7 +114,7 @@ public:
|
|||
/**
|
||||
* Returns the content node that focus will be redirected to if aContent was
|
||||
* focused. This is used for the special case of certain XUL elements such
|
||||
* as textboxes which redirect focus to an anonymous child.
|
||||
* as textboxes or input number which redirect focus to an anonymous child.
|
||||
*
|
||||
* aContent must be non-null.
|
||||
*
|
||||
|
|
|
@ -2770,9 +2770,9 @@ function runKeyTests()
|
|||
{ key: "F24", keyCode: KeyboardEvent.DOM_VK_F24 },
|
||||
{ key: "NumLock", keyCode: KeyboardEvent.DOM_VK_NUM_LOCK, isModifier: true, isLockableModifier: true },
|
||||
{ key: "ScrollLock", keyCode: KeyboardEvent.DOM_VK_SCROLL_LOCK, isModifier: true, isLockableModifier: true },
|
||||
{ key: "VolumeMute", keyCode: KeyboardEvent.DOM_VK_VOLUME_MUTE },
|
||||
{ key: "VolumeDown", keyCode: KeyboardEvent.DOM_VK_VOLUME_DOWN },
|
||||
{ key: "VolumeUp", keyCode: KeyboardEvent.DOM_VK_VOLUME_UP },
|
||||
{ key: "AudioVolumeMute", keyCode: KeyboardEvent.DOM_VK_VOLUME_MUTE },
|
||||
{ key: "AudioVolumeDown", keyCode: KeyboardEvent.DOM_VK_VOLUME_DOWN },
|
||||
{ key: "AudioVolumeUp", keyCode: KeyboardEvent.DOM_VK_VOLUME_UP },
|
||||
{ key: "Meta", keyCode: KeyboardEvent.DOM_VK_META, isModifier: true },
|
||||
{ key: "AltGraph", keyCode: KeyboardEvent.DOM_VK_ALTGR, isModifier: true },
|
||||
{ key: "Attn", keyCode: KeyboardEvent.DOM_VK_ATTN },
|
||||
|
|
|
@ -1673,7 +1673,7 @@ BrowserElementChild.prototype = {
|
|||
sendAsyncMsg('error', { type: 'unsafeContentType' });
|
||||
return;
|
||||
case Cr.NS_ERROR_CORRUPTED_CONTENT :
|
||||
sendAsyncMsg('error', { type: 'corruptedContentError' });
|
||||
sendAsyncMsg('error', { type: 'corruptedContentErrorv2' });
|
||||
return;
|
||||
|
||||
default:
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/EventTargetBinding.h"
|
||||
#include "mozilla/dom/TouchEvent.h"
|
||||
#include "mozilla/TimelineConsumers.h"
|
||||
#include "mozilla/EventTimelineMarker.h"
|
||||
|
||||
|
@ -1714,12 +1715,25 @@ EventListenerManager::IsApzAwareListener(Listener* aListener)
|
|||
bool
|
||||
EventListenerManager::IsApzAwareEvent(nsIAtom* aEvent)
|
||||
{
|
||||
return aEvent == nsGkAtoms::ontouchstart ||
|
||||
aEvent == nsGkAtoms::ontouchmove ||
|
||||
aEvent == nsGkAtoms::onwheel ||
|
||||
if (aEvent == nsGkAtoms::onwheel ||
|
||||
aEvent == nsGkAtoms::onDOMMouseScroll ||
|
||||
aEvent == nsHtml5Atoms::onmousewheel ||
|
||||
aEvent == nsGkAtoms::onMozMousePixelScroll;
|
||||
aEvent == nsGkAtoms::onMozMousePixelScroll) {
|
||||
return true;
|
||||
}
|
||||
// In theory we should schedule a repaint if the touch event pref changes,
|
||||
// because the event regions might be out of date. In practice that seems like
|
||||
// overkill because users generally shouldn't be flipping this pref, much
|
||||
// less expecting touch listeners on the page to immediately start preventing
|
||||
// scrolling without so much as a repaint. Tests that we write can work
|
||||
// around this constraint easily enough.
|
||||
if (TouchEvent::PrefEnabled()) {
|
||||
if (aEvent == nsGkAtoms::ontouchstart ||
|
||||
aEvent == nsGkAtoms::ontouchmove) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIScriptGlobalObject>
|
||||
|
|
|
@ -29,12 +29,14 @@ DEFINE_KEYNAME_WITH_SAME_NAME(Unidentified)
|
|||
* Our Internal Key Values (must have "Moz" prefix)
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_INTERNAL(PrintableKey, "MozPrintableKey")
|
||||
DEFINE_KEYNAME_INTERNAL(HomeScreen, "MozHomeScreen")
|
||||
DEFINE_KEYNAME_INTERNAL(CameraFocusAdjust, "MozCameraFocusAdjust")
|
||||
DEFINE_KEYNAME_INTERNAL(PhoneCall, "MozPhoneCall")
|
||||
DEFINE_KEYNAME_INTERNAL(SoftLeft, "MozSoftLeft")
|
||||
DEFINE_KEYNAME_INTERNAL(SoftRight, "MozSoftRight")
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
DEFINE_KEYNAME_INTERNAL(HomeScreen, "MozHomeScreen")
|
||||
DEFINE_KEYNAME_INTERNAL(CameraFocusAdjust, "MozCameraFocusAdjust")
|
||||
#endif // #ifdef MOZ_B2G
|
||||
|
||||
/******************************************************************************
|
||||
* Modifier Keys
|
||||
*****************************************************************************/
|
||||
|
@ -248,9 +250,16 @@ DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderRear)
|
|||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioSurroundModeNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioTrebleDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioTrebleUp)
|
||||
#ifndef MOZ_B2G
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioVolumeDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioVolumeUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioVolumeMute)
|
||||
#else
|
||||
// Temporarily, remaining for B2G
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeMute)
|
||||
#endif
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MicrophoneToggle)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MicrophoneVolumeDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MicrophoneVolumeUp)
|
||||
|
|
|
@ -165,10 +165,16 @@ TouchEvent::ChangedTouches()
|
|||
bool
|
||||
TouchEvent::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
|
||||
{
|
||||
static bool sPrefCached = false;
|
||||
static int32_t sPrefCacheValue = 0;
|
||||
|
||||
if (!sPrefCached) {
|
||||
sPrefCached = true;
|
||||
Preferences::AddIntVarCache(&sPrefCacheValue, "dom.w3c_touch_events.enabled");
|
||||
}
|
||||
|
||||
bool prefValue = false;
|
||||
int32_t flag = 0;
|
||||
if (NS_SUCCEEDED(Preferences::GetInt("dom.w3c_touch_events.enabled", &flag))) {
|
||||
if (flag == 2) {
|
||||
if (sPrefCacheValue == 2) {
|
||||
#if defined(MOZ_B2G) || defined(MOZ_WIDGET_ANDROID)
|
||||
// Touch support is always enabled on B2G and android.
|
||||
prefValue = true;
|
||||
|
@ -185,8 +191,7 @@ TouchEvent::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
|
|||
prefValue = false;
|
||||
#endif
|
||||
} else {
|
||||
prefValue = !!flag;
|
||||
}
|
||||
prefValue = !!sPrefCacheValue;
|
||||
}
|
||||
if (prefValue) {
|
||||
nsContentUtils::InitializeTouchEventTable();
|
||||
|
|
|
@ -51,6 +51,7 @@ skip-if = os == "android" || buildapp == "mulet"
|
|||
[test_input_number_validation.html]
|
||||
# We don't build ICU for Firefox for Android or Firefox OS:
|
||||
skip-if = os == "android" || appname == "b2g"
|
||||
[test_input_number_focus.html]
|
||||
[test_input_range_attr_order.html]
|
||||
[test_input_range_key_events.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1268556
|
||||
-->
|
||||
<head>
|
||||
<title>Test focus behaviour for <input type='number'></title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268556">Mozilla Bug 1268556</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<input id="input" type="number">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/**
|
||||
* Test for Bug 1268556.
|
||||
* This test checks that when focusing on an input type=number, the focus is
|
||||
* redirected to the anonymous text control, but the document.activeElement
|
||||
* still returns the <input type=number>.
|
||||
**/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
test();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
function test() {
|
||||
var number = document.getElementById("input");
|
||||
number.focus();
|
||||
|
||||
// The active element returns the input type=number.
|
||||
var activeElement = document.activeElement;
|
||||
is (activeElement, number, "activeElement should be the number element");
|
||||
is (activeElement.localName, "input", "activeElement should be an input element");
|
||||
is (activeElement.getAttribute("type"), "number", "activeElement should of type number");
|
||||
|
||||
// Use FocusManager to check that the actual focus is on the anonymous
|
||||
// text control.
|
||||
var fm = SpecialPowers.Cc["@mozilla.org/focus-manager;1"]
|
||||
.getService(SpecialPowers.Ci.nsIFocusManager);
|
||||
var focusedElement = fm.focusedElement;
|
||||
is (focusedElement.localName, "input", "focusedElement should be an input element");
|
||||
is (focusedElement.getAttribute("type"), "text", "focusedElement should of type text");
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -141,7 +141,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=369370
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set":[["browser.enable_automatic_image_resizing", true]]}, function() {
|
||||
kidWin = window.open("bug369370-popup.png", "bug369370", "width=400,height=300");
|
||||
kidWin = window.open("bug369370-popup.png", "bug369370", "width=400,height=300,scrollbars=no");
|
||||
// will init onload
|
||||
ok(kidWin, "opened child window");
|
||||
kidWin.onload = childLoaded;
|
||||
|
|
|
@ -202,12 +202,21 @@ function guessKeyNameFromKeyCode(KeyboardEvent, aKeyCode) {
|
|||
return "NumLock";
|
||||
case KeyboardEvent.DOM_VK_SCROLL_LOCK:
|
||||
return "ScrollLock";
|
||||
#ifndef MOZ_B2G
|
||||
case KeyboardEvent.DOM_VK_VOLUME_MUTE:
|
||||
return "AudioVolumeMute";
|
||||
case KeyboardEvent.DOM_VK_VOLUME_DOWN:
|
||||
return "AudioVolumeDown";
|
||||
case KeyboardEvent.DOM_VK_VOLUME_UP:
|
||||
return "AudioVolumeUp";
|
||||
#else
|
||||
case KeyboardEvent.DOM_VK_VOLUME_MUTE:
|
||||
return "VolumeMute";
|
||||
case KeyboardEvent.DOM_VK_VOLUME_DOWN:
|
||||
return "VolumeDown";
|
||||
case KeyboardEvent.DOM_VK_VOLUME_UP:
|
||||
return "VolumeUp";
|
||||
#endif
|
||||
case KeyboardEvent.DOM_VK_META:
|
||||
return "Meta";
|
||||
case KeyboardEvent.DOM_VK_ALTGR:
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
toolkit.jar:
|
||||
content/global/forms.js (forms.js)
|
||||
* content/global/forms.js (forms.js)
|
||||
|
|
|
@ -34,7 +34,7 @@ unwantedBlocked=The site at %S has been reported as serving unwanted software an
|
|||
deceptiveBlocked=This web page at %S has been reported as a deceptive site and has been blocked based on your security preferences.
|
||||
forbiddenBlocked=The site at %S has been blocked by your browser configuration.
|
||||
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
|
||||
corruptedContentError=The site at %S has experienced a network protocol violation that cannot be repaired.
|
||||
corruptedContentErrorv2=The site at %S has experienced a network protocol violation that cannot be repaired.
|
||||
remoteXUL=This page uses an unsupported technology that is no longer available by default.
|
||||
sslv3Used=The safety of your data on %S could not be guaranteed because it uses SSLv3, a broken security protocol.
|
||||
weakCryptoUsed=The owner of %S has configured their website improperly. To protect your information from being stolen, the connection to this website has not been established.
|
||||
|
|
|
@ -87,8 +87,8 @@
|
|||
<!ENTITY cspBlocked.title "Blocked by Content Security Policy">
|
||||
<!ENTITY cspBlocked.longDesc "<p>The browser prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">
|
||||
|
||||
<!ENTITY corruptedContentError.title "Corrupted Content Error">
|
||||
<!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
|
||||
<!ENTITY corruptedContentErrorv2.title "Corrupted Content Error">
|
||||
<!ENTITY corruptedContentErrorv2.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
|
||||
|
||||
<!ENTITY remoteXUL.title "Remote XUL">
|
||||
<!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
|
||||
|
|
|
@ -473,6 +473,7 @@ nsMathMLElement::ParseNumericValue(const nsString& aString,
|
|||
else if (unit.EqualsLiteral("mm")) cssUnit = eCSSUnit_Millimeter;
|
||||
else if (unit.EqualsLiteral("pt")) cssUnit = eCSSUnit_Point;
|
||||
else if (unit.EqualsLiteral("pc")) cssUnit = eCSSUnit_Pica;
|
||||
else if (unit.EqualsLiteral("q")) cssUnit = eCSSUnit_Quarter;
|
||||
else { // unexpected unit
|
||||
if (!(aFlags & PARSE_SUPPRESS_WARNINGS)) {
|
||||
ReportLengthParseError(aString, aDocument);
|
||||
|
|
|
@ -1251,7 +1251,8 @@ MediaDecoder::OnSeekResolved(SeekResolveValue aVal)
|
|||
mLogicallySeeking = false;
|
||||
}
|
||||
|
||||
UpdateLogicalPosition(aVal.mEventVisibility);
|
||||
// Ensure logical position is updated after seek.
|
||||
UpdateLogicalPositionInternal(aVal.mEventVisibility);
|
||||
|
||||
if (aVal.mEventVisibility != MediaDecoderEventVisibility::Suppressed) {
|
||||
mOwner->SeekCompleted();
|
||||
|
@ -1302,14 +1303,10 @@ MediaDecoder::ChangeState(PlayState aState)
|
|||
}
|
||||
|
||||
void
|
||||
MediaDecoder::UpdateLogicalPosition(MediaDecoderEventVisibility aEventVisibility)
|
||||
MediaDecoder::UpdateLogicalPositionInternal(MediaDecoderEventVisibility aEventVisibility)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mShuttingDown)
|
||||
return;
|
||||
|
||||
// Per spec, offical position remains stable during pause and seek.
|
||||
if (mPlayState == PLAY_STATE_PAUSED || IsSeeking()) {
|
||||
if (mShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -411,11 +411,15 @@ private:
|
|||
// thread.
|
||||
void SeekingStarted(MediaDecoderEventVisibility aEventVisibility = MediaDecoderEventVisibility::Observable);
|
||||
|
||||
void UpdateLogicalPosition(MediaDecoderEventVisibility aEventVisibility);
|
||||
void UpdateLogicalPositionInternal(MediaDecoderEventVisibility aEventVisibility);
|
||||
void UpdateLogicalPosition()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
UpdateLogicalPosition(MediaDecoderEventVisibility::Observable);
|
||||
// Per spec, offical position remains stable during pause and seek.
|
||||
if (mPlayState == PLAY_STATE_PAUSED || IsSeeking()) {
|
||||
return;
|
||||
}
|
||||
UpdateLogicalPositionInternal(MediaDecoderEventVisibility::Observable);
|
||||
}
|
||||
|
||||
// Find the end of the cached data starting at the current decoder
|
||||
|
|
|
@ -87,10 +87,6 @@ MediaFormatReader::Shutdown()
|
|||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (HasVideo()) {
|
||||
ReportDroppedFramesTelemetry();
|
||||
}
|
||||
|
||||
mDemuxerInitRequest.DisconnectIfExists();
|
||||
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mSeekPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
||||
|
@ -959,9 +955,6 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack,
|
|||
LOG("%s stream id has changed from:%d to:%d, draining decoder.",
|
||||
TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
|
||||
info->GetID());
|
||||
if (aTrack == TrackType::kVideoTrack) {
|
||||
ReportDroppedFramesTelemetry();
|
||||
}
|
||||
decoder.mNeedDraining = true;
|
||||
decoder.mNextStreamSourceID = Some(info->GetID());
|
||||
ScheduleUpdate(aTrack);
|
||||
|
@ -1160,7 +1153,6 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
Some(TimeInterval(TimeUnit::FromMicroseconds(output->mTime),
|
||||
TimeUnit::FromMicroseconds(output->GetEndTime())));
|
||||
decoder.mNumSamplesOutputTotal++;
|
||||
decoder.mNumSamplesOutputTotalSinceTelemetry++;
|
||||
ReturnOutput(output, aTrack);
|
||||
// We have a decoded sample ready to be returned.
|
||||
if (aTrack == TrackType::kVideoTrack) {
|
||||
|
@ -1205,6 +1197,15 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
LOGV("Nothing more to do");
|
||||
return;
|
||||
}
|
||||
} else if (decoder.mDemuxEOS && !decoder.mNeedDraining &&
|
||||
!decoder.mDraining && !decoder.mDrainComplete &&
|
||||
decoder.mQueuedSamples.IsEmpty()) {
|
||||
// It is possible to transition from WAITING_FOR_DATA directly to EOS
|
||||
// state during the internal seek; in which case no draining would occur.
|
||||
// There is no more samples left to be decoded and we are already in
|
||||
// EOS state. We can immediately reject the data promise.
|
||||
LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
|
||||
decoder.RejectPromise(END_OF_STREAM, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1452,7 +1453,6 @@ MediaFormatReader::VideoSkipReset(uint32_t aSkipped)
|
|||
}
|
||||
|
||||
mVideo.mNumSamplesSkippedTotal += aSkipped;
|
||||
mVideo.mNumSamplesSkippedTotalSinceTelemetry += aSkipped;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1894,51 +1894,4 @@ MediaFormatReader::GetMozDebugReaderData(nsAString& aString)
|
|||
aString += NS_ConvertUTF8toUTF16(result);
|
||||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::ReportDroppedFramesTelemetry()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
const VideoInfo* info =
|
||||
mVideo.mInfo ? mVideo.mInfo->GetAsVideoInfo() : &mInfo.mVideo;
|
||||
|
||||
if (!info || !mVideo.mDecoder) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCString keyPhrase = nsCString("MimeType=");
|
||||
keyPhrase.Append(info->mMimeType);
|
||||
keyPhrase.Append("; ");
|
||||
|
||||
keyPhrase.Append("Resolution=");
|
||||
keyPhrase.AppendInt(info->mDisplay.width);
|
||||
keyPhrase.Append('x');
|
||||
keyPhrase.AppendInt(info->mDisplay.height);
|
||||
keyPhrase.Append("; ");
|
||||
|
||||
keyPhrase.Append("HardwareAcceleration=");
|
||||
if (VideoIsHardwareAccelerated()) {
|
||||
keyPhrase.Append(mVideo.mDecoder->GetDescriptionName());
|
||||
keyPhrase.Append("enabled");
|
||||
} else {
|
||||
keyPhrase.Append("disabled");
|
||||
}
|
||||
|
||||
if (mVideo.mNumSamplesOutputTotalSinceTelemetry) {
|
||||
uint32_t percentage =
|
||||
100 * mVideo.mNumSamplesSkippedTotalSinceTelemetry /
|
||||
mVideo.mNumSamplesOutputTotalSinceTelemetry;
|
||||
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() -> void {
|
||||
LOG("Reporting telemetry DROPPED_FRAMES_IN_VIDEO_PLAYBACK");
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DETAILED_DROPPED_FRAMES_PROPORTION,
|
||||
keyPhrase,
|
||||
percentage);
|
||||
});
|
||||
AbstractThread::MainThread()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
mVideo.mNumSamplesSkippedTotalSinceTelemetry = 0;
|
||||
mVideo.mNumSamplesOutputTotalSinceTelemetry = 0;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -243,8 +243,6 @@ private:
|
|||
, mNumSamplesOutput(0)
|
||||
, mNumSamplesOutputTotal(0)
|
||||
, mNumSamplesSkippedTotal(0)
|
||||
, mNumSamplesOutputTotalSinceTelemetry(0)
|
||||
, mNumSamplesSkippedTotalSinceTelemetry(0)
|
||||
, mSizeOfQueue(0)
|
||||
, mIsHardwareAccelerated(false)
|
||||
, mLastStreamSourceID(UINT32_MAX)
|
||||
|
@ -325,9 +323,6 @@ private:
|
|||
uint64_t mNumSamplesOutputTotal;
|
||||
uint64_t mNumSamplesSkippedTotal;
|
||||
|
||||
uint64_t mNumSamplesOutputTotalSinceTelemetry;
|
||||
uint64_t mNumSamplesSkippedTotalSinceTelemetry;
|
||||
|
||||
// These get overridden in the templated concrete class.
|
||||
// Indicate if we have a pending promise for decoded frame.
|
||||
// Rejecting the promise will stop the reader from decoding ahead.
|
||||
|
@ -538,9 +533,6 @@ private:
|
|||
{
|
||||
OnSeekFailed(TrackType::kAudioTrack, aFailure);
|
||||
}
|
||||
|
||||
void ReportDroppedFramesTelemetry();
|
||||
|
||||
// The SeekTarget that was last given to Seek()
|
||||
SeekTarget mOriginalSeekTarget;
|
||||
// Temporary seek information while we wait for the data
|
||||
|
|
|
@ -4,18 +4,19 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaShutdownManager.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "MediaDecoder.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "MediaDecoder.h"
|
||||
#include "MediaShutdownManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern LazyLogModule gMediaDecoderLog;
|
||||
#define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
|
||||
|
||||
NS_IMPL_ISUPPORTS(MediaShutdownManager, nsIObserver)
|
||||
NS_IMPL_ISUPPORTS(MediaShutdownManager, nsIAsyncShutdownBlocker)
|
||||
|
||||
MediaShutdownManager::MediaShutdownManager()
|
||||
: mIsObservingShutdown(false)
|
||||
|
@ -45,6 +46,23 @@ MediaShutdownManager::Instance()
|
|||
return *sInstance;
|
||||
}
|
||||
|
||||
static nsCOMPtr<nsIAsyncShutdownClient>
|
||||
GetShutdownBarrier()
|
||||
{
|
||||
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
|
||||
MOZ_RELEASE_ASSERT(svc);
|
||||
|
||||
nsCOMPtr<nsIAsyncShutdownClient> barrier;
|
||||
nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(barrier));
|
||||
if (!barrier) {
|
||||
// We are probably in a content process.
|
||||
rv = svc->GetContentChildShutdown(getter_AddRefs(barrier));
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
MOZ_RELEASE_ASSERT(barrier);
|
||||
return barrier.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MediaShutdownManager::EnsureCorrectShutdownObserverState()
|
||||
{
|
||||
|
@ -52,12 +70,16 @@ MediaShutdownManager::EnsureCorrectShutdownObserverState()
|
|||
if (needShutdownObserver != mIsObservingShutdown) {
|
||||
mIsObservingShutdown = needShutdownObserver;
|
||||
if (mIsObservingShutdown) {
|
||||
nsContentUtils::RegisterShutdownObserver(this);
|
||||
nsresult rv = GetShutdownBarrier()->AddBlocker(
|
||||
this, NS_LITERAL_STRING(__FILE__), __LINE__,
|
||||
NS_LITERAL_STRING("MediaShutdownManager shutdown"));
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
} else {
|
||||
nsContentUtils::UnregisterShutdownObserver(this);
|
||||
GetShutdownBarrier()->RemoveBlocker(this);
|
||||
// Clear our singleton reference. This will probably delete
|
||||
// this instance, so don't deref |this| clearing sInstance.
|
||||
sInstance = nullptr;
|
||||
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,24 +108,25 @@ MediaShutdownManager::Unregister(MediaDecoder* aDecoder)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaShutdownManager::Observe(nsISupports *aSubjet,
|
||||
const char *aTopic,
|
||||
const char16_t *someData)
|
||||
MediaShutdownManager::GetName(nsAString& aName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
|
||||
Shutdown();
|
||||
}
|
||||
aName = NS_LITERAL_STRING("MediaShutdownManager: shutdown");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaShutdownManager::Shutdown()
|
||||
NS_IMETHODIMP
|
||||
MediaShutdownManager::GetState(nsIPropertyBag**)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaShutdownManager::BlockShutdown(nsIAsyncShutdownClient*)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(sInstance);
|
||||
|
||||
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::Shutdown() start..."));
|
||||
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() start..."));
|
||||
|
||||
// Set this flag to ensure no Register() is allowed when Shutdown() begins.
|
||||
mIsDoingXPCOMShutDown = true;
|
||||
|
@ -119,15 +142,7 @@ MediaShutdownManager::Shutdown()
|
|||
MOZ_ASSERT(mDecoders.Count() == oldCount);
|
||||
}
|
||||
|
||||
// Spin the loop until all decoders are unregistered
|
||||
// which will then clear |sInstance|.
|
||||
while (sInstance) {
|
||||
NS_ProcessNextEvent(NS_GetCurrentThread(), true);
|
||||
}
|
||||
|
||||
// Note: Don't access |this| which might be deleted after clearing sInstance.
|
||||
|
||||
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::Shutdown() end."));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,43 +7,35 @@
|
|||
#if !defined(MediaShutdownManager_h_)
|
||||
#define MediaShutdownManager_h_
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsIAsyncShutdown.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaDecoder;
|
||||
|
||||
// The MediaShutdownManager manages shutting down the MediaDecoder
|
||||
// infrastructure in response to an xpcom-shutdown notification. This happens
|
||||
// when Gecko is shutting down in the middle of operation. This is tricky, as
|
||||
// there are a number of moving parts that must be shutdown in a particular
|
||||
// order. Additionally the xpcom-shutdown observer *must* block until all
|
||||
// threads are shutdown, which is tricky since we have a number of threads
|
||||
// here and their shutdown is asynchronous. We can't have each element of
|
||||
// our pipeline listening for xpcom-shutdown, as if each observer blocks
|
||||
// waiting for its threads to shutdown it will block other xpcom-shutdown
|
||||
// notifications from firing, and shutdown of one part of the media pipeline
|
||||
// (say the State Machine thread) may depend another part to be shutdown
|
||||
// first (the MediaDecoder threads). The MediaShutdownManager encapsulates
|
||||
// all these dependencies, and provides a single xpcom-shutdown listener
|
||||
// for the MediaDecoder infrastructure, to ensure that no shutdown order
|
||||
// dependencies leak out of the MediaDecoder stack. The MediaShutdownManager
|
||||
// is a singleton.
|
||||
// infrastructure in response to an xpcom-shutdown notification.
|
||||
// This happens when Gecko is shutting down in the middle of operation.
|
||||
// This is tricky, as there are a number of moving parts that must
|
||||
// be shutdown in a particular order. The MediaShutdownManager
|
||||
// encapsulates all these dependencies to ensure that no shutdown
|
||||
// order dependencies leak out of the MediaDecoder stack.
|
||||
// The MediaShutdownManager is a singleton.
|
||||
//
|
||||
// The MediaShutdownManager ensures that the MediaDecoder stack is shutdown
|
||||
// before returning from its xpcom-shutdown observer by keeping track of all
|
||||
// the active MediaDecoders, and upon xpcom-shutdown calling Shutdown() on
|
||||
// every MediaDecoder and then spinning the main thread event loop until all
|
||||
// SharedThreadPools have shutdown. Once the SharedThreadPools are shutdown,
|
||||
// all the state machines and their threads have been shutdown, the
|
||||
// xpcom-shutdown observer returns.
|
||||
// The MediaShutdownManager ensures that the MediaDecoder stack
|
||||
// is shutdown before exiting xpcom-shutdown stage by registering
|
||||
// itself with nsIAsyncShutdownService to receive notification
|
||||
// when the stage of shutdown has started and then calls Shutdown()
|
||||
// on every MediaDecoder. Shutdown will not proceed until all
|
||||
// MediaDecoders finish shutdown and MediaShutdownManager unregisters
|
||||
// itself from the async shutdown service.
|
||||
//
|
||||
// Note that calling the Unregister() functions may result in the singleton
|
||||
// being deleted, so don't store references to the singleton, always use the
|
||||
|
@ -57,10 +49,10 @@ class MediaDecoder;
|
|||
// MediaShutdownManager& instance = MediaShutdownManager::Instance();
|
||||
// instance.Unregister(someDecoder); // Warning! May delete instance!
|
||||
// instance.Register(someOtherDecoder); // BAD! instance may be dangling!
|
||||
class MediaShutdownManager : public nsIObserver {
|
||||
class MediaShutdownManager : public nsIAsyncShutdownBlocker {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIASYNCSHUTDOWNBLOCKER
|
||||
|
||||
// The MediaShutdownManager is a singleton, access its instance with
|
||||
// this accessor.
|
||||
|
@ -80,8 +72,6 @@ private:
|
|||
MediaShutdownManager();
|
||||
virtual ~MediaShutdownManager();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
// Ensures we have a shutdown listener if we need one, and removes the
|
||||
// listener and destroys the singleton if we don't.
|
||||
void EnsureCorrectShutdownObserverState();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "VorbisDecoder.h" // For VorbisLayout
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h> // For PRId64
|
||||
|
@ -21,7 +22,7 @@ extern mozilla::LogModule* GetPDMLog();
|
|||
namespace mozilla {
|
||||
|
||||
OpusDataDecoder::OpusDataDecoder(const AudioInfo& aConfig,
|
||||
FlushableTaskQueue* aTaskQueue,
|
||||
TaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
: mInfo(aConfig)
|
||||
, mTaskQueue(aTaskQueue)
|
||||
|
@ -31,6 +32,7 @@ OpusDataDecoder::OpusDataDecoder(const AudioInfo& aConfig,
|
|||
, mDecodedHeader(false)
|
||||
, mPaddingDiscarded(false)
|
||||
, mFrames(0)
|
||||
, mIsFlushing(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -133,15 +135,17 @@ nsresult
|
|||
OpusDataDecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
|
||||
this, &OpusDataDecoder::Decode,
|
||||
RefPtr<MediaRawData>(aSample)));
|
||||
this, &OpusDataDecoder::ProcessDecode, aSample));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
OpusDataDecoder::Decode(MediaRawData* aSample)
|
||||
OpusDataDecoder::ProcessDecode(MediaRawData* aSample)
|
||||
{
|
||||
if (mIsFlushing) {
|
||||
return;
|
||||
}
|
||||
if (DoDecode(aSample) == -1) {
|
||||
mCallback->Error();
|
||||
} else if(mTaskQueue->IsEmpty()) {
|
||||
|
@ -299,7 +303,7 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample)
|
|||
}
|
||||
|
||||
void
|
||||
OpusDataDecoder::DoDrain()
|
||||
OpusDataDecoder::ProcessDrain()
|
||||
{
|
||||
mCallback->DrainComplete();
|
||||
}
|
||||
|
@ -307,21 +311,27 @@ OpusDataDecoder::DoDrain()
|
|||
nsresult
|
||||
OpusDataDecoder::Drain()
|
||||
{
|
||||
mTaskQueue->Dispatch(NewRunnableMethod(this, &OpusDataDecoder::DoDrain));
|
||||
mTaskQueue->Dispatch(NewRunnableMethod(this, &OpusDataDecoder::ProcessDrain));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpusDataDecoder::Flush()
|
||||
{
|
||||
mTaskQueue->Flush();
|
||||
if (mOpusDecoder) {
|
||||
if (!mOpusDecoder) {
|
||||
return NS_OK;
|
||||
}
|
||||
mIsFlushing = true;
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction([this] () {
|
||||
MOZ_ASSERT(mOpusDecoder);
|
||||
// Reset the decoder.
|
||||
opus_multistream_decoder_ctl(mOpusDecoder, OPUS_RESET_STATE);
|
||||
mSkip = mOpusParser->mPreSkip;
|
||||
mPaddingDiscarded = false;
|
||||
mLastFrameTime.reset();
|
||||
}
|
||||
});
|
||||
SyncRunnable::DispatchToThread(mTaskQueue, runnable);
|
||||
mIsFlushing = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ class OpusDataDecoder : public MediaDataDecoder
|
|||
{
|
||||
public:
|
||||
OpusDataDecoder(const AudioInfo& aConfig,
|
||||
FlushableTaskQueue* aTaskQueue,
|
||||
TaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
~OpusDataDecoder();
|
||||
|
||||
|
@ -38,12 +38,12 @@ public:
|
|||
private:
|
||||
nsresult DecodeHeader(const unsigned char* aData, size_t aLength);
|
||||
|
||||
void Decode (MediaRawData* aSample);
|
||||
int DoDecode (MediaRawData* aSample);
|
||||
void DoDrain ();
|
||||
void ProcessDecode(MediaRawData* aSample);
|
||||
int DoDecode(MediaRawData* aSample);
|
||||
void ProcessDrain();
|
||||
|
||||
const AudioInfo& mInfo;
|
||||
RefPtr<FlushableTaskQueue> mTaskQueue;
|
||||
const RefPtr<TaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
|
||||
// Opus decoder state
|
||||
|
@ -60,6 +60,8 @@ private:
|
|||
int64_t mFrames;
|
||||
Maybe<int64_t> mLastFrameTime;
|
||||
uint8_t mMappingTable[MAX_AUDIO_CHANNELS]; // Channel mapping table.
|
||||
|
||||
Atomic<bool> mIsFlushing;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -808,17 +808,6 @@ WMFVideoMFTManager::IsHardwareAccelerated(nsACString& aFailureReason) const
|
|||
return mDecoder && mUseHwAccel;
|
||||
}
|
||||
|
||||
const char*
|
||||
WMFVideoMFTManager::GetDescriptionName() const
|
||||
{
|
||||
if (mDecoder && mUseHwAccel && mDXVA2Manager) {
|
||||
return (mDXVA2Manager->IsD3D11()) ?
|
||||
"D3D11 Hardware Decoder" : "D3D9 Hardware Decoder";
|
||||
} else {
|
||||
return "wmf software video decoder";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WMFVideoMFTManager::ConfigurationChanged(const TrackInfo& aConfig)
|
||||
{
|
||||
|
|
|
@ -41,7 +41,12 @@ public:
|
|||
|
||||
void ConfigurationChanged(const TrackInfo& aConfig) override;
|
||||
|
||||
const char* GetDescriptionName() const override;
|
||||
const char* GetDescriptionName() const override
|
||||
{
|
||||
nsCString failureReason;
|
||||
return IsHardwareAccelerated(failureReason)
|
||||
? "wmf hardware video decoder" : "wmf software video decoder";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -91,8 +91,6 @@ MediaEngineRemoteVideoSource::Shutdown()
|
|||
Deallocate();
|
||||
}
|
||||
|
||||
mozilla::camera::Shutdown();
|
||||
|
||||
mState = kReleased;
|
||||
mInitDone = false;
|
||||
return;
|
||||
|
|
|
@ -55,6 +55,11 @@ onmessage = function(event) {
|
|||
}
|
||||
|
||||
onpush = function(event) {
|
||||
var pushResolve;
|
||||
event.waitUntil(new Promise(function(resolve) {
|
||||
pushResolve = resolve;
|
||||
}));
|
||||
|
||||
// FIXME(catalinb): push message carry no data. So we assume the only
|
||||
// push message we get is "wait"
|
||||
clients.matchAll().then(function(client) {
|
||||
|
@ -65,11 +70,10 @@ onpush = function(event) {
|
|||
client[0].postMessage({type: "push", state: state});
|
||||
|
||||
state = "wait";
|
||||
event.waitUntil(new Promise(function(res, rej) {
|
||||
if (resolvePromiseCallback) {
|
||||
dump("ERROR: service worker was already waiting on a promise.\n");
|
||||
} else {
|
||||
resolvePromiseCallback = pushResolve;
|
||||
}
|
||||
resolvePromiseCallback = res;
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@
|
|||
.then(setShutdownObserver(false))
|
||||
.then(checkStateAndUpdate(pushEvent, "from_scope", "wait"))
|
||||
.then(setShutdownObserver(true))
|
||||
.then(checkStateAndUpdate(messageEventIframe, "wait", "update"))
|
||||
.then(checkStateAndUpdate(messageEventIframe, "wait", "release"))
|
||||
.then(waitOnShutdownObserver)
|
||||
.then(closeIframe)
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ function testWindow(w)
|
|||
checkFeature('menubar');
|
||||
checkFeature('toolbar');
|
||||
checkFeature('personalbar');
|
||||
checkFeature('scrollbars');
|
||||
checkFeature('statusbar', 'status');
|
||||
checkFeature('locationbar', 'location');
|
||||
|
||||
|
|
|
@ -205,42 +205,152 @@ namespace {
|
|||
|
||||
// Holds the worker alive until the waitUntil promise is resolved or
|
||||
// rejected.
|
||||
class KeepAliveHandler final : public PromiseNativeHandler
|
||||
class KeepAliveHandler final
|
||||
{
|
||||
// Use an internal class to listen for the promise resolve/reject
|
||||
// callbacks. This class also registers a feature so that it can
|
||||
// preemptively cleanup if the service worker is timed out and
|
||||
// terminated.
|
||||
class InternalHandler final : public PromiseNativeHandler
|
||||
, public WorkerFeature
|
||||
{
|
||||
nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
|
||||
|
||||
virtual ~KeepAliveHandler()
|
||||
{}
|
||||
// Worker thread only
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
RefPtr<Promise> mPromise;
|
||||
bool mFeatureAdded;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
~InternalHandler()
|
||||
{
|
||||
MaybeCleanup();
|
||||
}
|
||||
|
||||
explicit KeepAliveHandler(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken)
|
||||
: mKeepAliveToken(aKeepAliveToken)
|
||||
{ }
|
||||
bool
|
||||
AddFeature()
|
||||
{
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(!mFeatureAdded);
|
||||
mFeatureAdded = mWorkerPrivate->AddFeature(this);
|
||||
return mFeatureAdded;
|
||||
}
|
||||
|
||||
void
|
||||
MaybeCleanup()
|
||||
{
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
if (!mPromise) {
|
||||
return;
|
||||
}
|
||||
if (mFeatureAdded) {
|
||||
mWorkerPrivate->RemoveFeature(this);
|
||||
}
|
||||
mPromise = nullptr;
|
||||
mKeepAliveToken = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
#ifdef DEBUG
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
#endif
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MaybeCleanup();
|
||||
}
|
||||
|
||||
void
|
||||
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MaybeCleanup();
|
||||
}
|
||||
|
||||
bool
|
||||
Notify(Status aStatus) override
|
||||
{
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
if (aStatus < Terminating) {
|
||||
return true;
|
||||
}
|
||||
MaybeCleanup();
|
||||
return true;
|
||||
}
|
||||
|
||||
InternalHandler(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aPromise)
|
||||
: mKeepAliveToken(aKeepAliveToken)
|
||||
, mWorkerPrivate(aWorkerPrivate)
|
||||
, mPromise(aPromise)
|
||||
, mFeatureAdded(false)
|
||||
{
|
||||
MOZ_ASSERT(mKeepAliveToken);
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
MOZ_ASSERT(mPromise);
|
||||
}
|
||||
|
||||
public:
|
||||
static already_AddRefed<InternalHandler>
|
||||
Create(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aPromise)
|
||||
{
|
||||
RefPtr<InternalHandler> ref = new InternalHandler(aKeepAliveToken,
|
||||
aWorkerPrivate,
|
||||
aPromise);
|
||||
|
||||
if (NS_WARN_IF(!ref->AddFeature())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
// This is really just a wrapper class to keep the InternalHandler
|
||||
// private. We don't want any code to accidentally call
|
||||
// Promise::AppendNativeHandler() without also referencing the promise.
|
||||
// Therefore we force all code through the static CreateAndAttachToPromise()
|
||||
// and use the private InternalHandler object.
|
||||
KeepAliveHandler() = delete;
|
||||
~KeepAliveHandler() = delete;
|
||||
|
||||
public:
|
||||
// Create a private handler object and attach it to the given Promise.
|
||||
// This will also create a strong ref to the Promise in a ref cycle. The
|
||||
// ref cycle is broken when the Promise is fulfilled or the worker thread
|
||||
// is Terminated.
|
||||
static void
|
||||
CreateAndAttachToPromise(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
|
||||
Promise* aPromise)
|
||||
{
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
#endif
|
||||
MOZ_ASSERT(aKeepAliveToken);
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
||||
// This creates a strong ref to the promise.
|
||||
RefPtr<InternalHandler> handler = InternalHandler::Create(aKeepAliveToken,
|
||||
workerPrivate,
|
||||
aPromise);
|
||||
if (NS_WARN_IF(!handler)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This then creates a strong ref cycle between the promise and the
|
||||
// handler. The cycle is broken when the Promise is fulfilled or
|
||||
// the worker thread is Terminated.
|
||||
aPromise->AppendNativeHandler(handler);
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(KeepAliveHandler)
|
||||
NS_IMPL_ISUPPORTS0(KeepAliveHandler::InternalHandler)
|
||||
|
||||
class RegistrationUpdateRunnable : public Runnable
|
||||
{
|
||||
|
@ -311,9 +421,8 @@ public:
|
|||
}
|
||||
|
||||
MOZ_ASSERT(waitUntilPromise);
|
||||
RefPtr<KeepAliveHandler> keepAliveHandler =
|
||||
new KeepAliveHandler(mKeepAliveToken);
|
||||
waitUntilPromise->AppendNativeHandler(keepAliveHandler);
|
||||
KeepAliveHandler::CreateAndAttachToPromise(mKeepAliveToken,
|
||||
waitUntilPromise);
|
||||
|
||||
if (aWaitUntilPromise) {
|
||||
waitUntilPromise.forget(aWaitUntilPromise);
|
||||
|
@ -1389,9 +1498,8 @@ private:
|
|||
|
||||
RefPtr<Promise> waitUntilPromise = event->GetPromise();
|
||||
if (waitUntilPromise) {
|
||||
RefPtr<KeepAliveHandler> keepAliveHandler =
|
||||
new KeepAliveHandler(mKeepAliveToken);
|
||||
waitUntilPromise->AppendNativeHandler(keepAliveHandler);
|
||||
KeepAliveHandler::CreateAndAttachToPromise(mKeepAliveToken,
|
||||
waitUntilPromise);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
function postMessageToTest(msg) {
|
||||
return clients.matchAll({ includeUncontrolled: true })
|
||||
.then(list => {
|
||||
for (var client of list) {
|
||||
if (client.url.endsWith('test_install_event_gc.html')) {
|
||||
client.postMessage(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addEventListener('install', evt => {
|
||||
// This must be a simple promise to trigger the CC failure.
|
||||
evt.waitUntil(new Promise(function() { }));
|
||||
postMessageToTest({ type: 'INSTALL_EVENT' });
|
||||
});
|
||||
|
||||
addEventListener('message', evt => {
|
||||
if (evt.data.type === 'ping') {
|
||||
postMessageToTest({ type: 'pong' });
|
||||
}
|
||||
});
|
|
@ -203,6 +203,7 @@ support-files =
|
|||
!/dom/security/test/cors/file_CrossSiteXHR_server.sjs
|
||||
!/dom/tests/mochitest/notification/MockServices.js
|
||||
!/dom/tests/mochitest/notification/NotificationTest.js
|
||||
blocking_install_event_worker.js
|
||||
|
||||
[test_bug1151916.html]
|
||||
[test_bug1240436.html]
|
||||
|
@ -235,6 +236,7 @@ skip-if = (debug && e10s) # Bug 1262224
|
|||
[test_importscript_mixedcontent.html]
|
||||
tags = mcb
|
||||
[test_install_event.html]
|
||||
[test_install_event_gc.html]
|
||||
[test_installation_simple.html]
|
||||
[test_match_all.html]
|
||||
[test_match_all_advanced.html]
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test install event being GC'd before waitUntil fulfills</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
var script = 'blocking_install_event_worker.js';
|
||||
var scope = 'sw_clients/simple.html?install-event-gc';
|
||||
var registration;
|
||||
|
||||
function register() {
|
||||
return navigator.serviceWorker.register(script, { scope: scope })
|
||||
.then(swr => registration = swr);
|
||||
}
|
||||
|
||||
function unregister() {
|
||||
if (!registration) {
|
||||
return;
|
||||
}
|
||||
return registration.unregister();
|
||||
}
|
||||
|
||||
function waitForInstallEvent() {
|
||||
return new Promise((resolve, reject) => {
|
||||
navigator.serviceWorker.addEventListener('message', evt => {
|
||||
if (evt.data.type === 'INSTALL_EVENT') {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function gcWorker() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
// We are able to trigger asynchronous garbage collection and cycle
|
||||
// collection by emitting "child-cc-request" and "child-gc-request"
|
||||
// observer notifications. The worker RuntimeService will translate
|
||||
// these notifications into the appropriate operation on all known
|
||||
// worker threads.
|
||||
//
|
||||
// In the failure case where GC/CC causes us to abort the installation,
|
||||
// we will know something happened from the statechange event.
|
||||
const statechangeHandler = evt => {
|
||||
// Reject rather than resolving to avoid the possibility of us seeing
|
||||
// an unrelated racing statechange somehow. Since in the success case we
|
||||
// will still see a state change on termination, we do explicitly need to
|
||||
// be removed on the success path.
|
||||
ok(registration.installing, 'service worker is still installing?');
|
||||
reject();
|
||||
};
|
||||
registration.installing.addEventListener('statechange', statechangeHandler);
|
||||
// In the success case since the service worker installation is effectively
|
||||
// hung, we instead depend on sending a 'ping' message to the service worker
|
||||
// and hearing it 'pong' back. Since we issue our postMessage after we
|
||||
// trigger the GC/CC, our 'ping' will only be processed after the GC/CC and
|
||||
// therefore the pong will also strictly occur after the cycle collection.
|
||||
navigator.serviceWorker.addEventListener('message', evt => {
|
||||
if (evt.data.type === 'pong') {
|
||||
registration.installing.removeEventListener(
|
||||
'statechange', statechangeHandler);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
// At the current time, the service worker will exist in our same process
|
||||
// and notifyObservers is synchronous. However, in the future, service
|
||||
// workers may end up in a separate process and in that case it will be
|
||||
// appropriate to use notifyObserversInParentProcess or something like it.
|
||||
// (notifyObserversInParentProcess is a synchronous IPC call to the parent
|
||||
// process's main thread. IPDL PContent::CycleCollect is an async message.
|
||||
// Ordering will be maintained if the postMessage goes via PContent as well,
|
||||
// but that seems unlikely.)
|
||||
SpecialPowers.notifyObservers(null, 'child-gc-request', null);
|
||||
SpecialPowers.notifyObservers(null, 'child-cc-request', null);
|
||||
SpecialPowers.notifyObservers(null, 'child-gc-request', null);
|
||||
// (Only send the ping after we set the gc/cc/gc in motion.)
|
||||
registration.installing.postMessage({ type: 'ping' });
|
||||
});
|
||||
}
|
||||
|
||||
function terminateWorker() {
|
||||
return SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["dom.serviceWorkers.idle_timeout", 0],
|
||||
["dom.serviceWorkers.idle_extended_timeout", 0]
|
||||
]
|
||||
}).then(_ => {
|
||||
registration.installing.postMessage({ type: 'RESET_TIMER' });
|
||||
});
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
Promise.all([
|
||||
waitForInstallEvent(),
|
||||
register()
|
||||
]).then(_ => ok(registration.installing, 'service worker is installing'))
|
||||
.then(gcWorker)
|
||||
.then(_ => ok(registration.installing, 'service worker is still installing'))
|
||||
.then(terminateWorker)
|
||||
.catch(e => ok(false, e))
|
||||
.then(unregister)
|
||||
.then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.caches.enabled", true],
|
||||
]}, runTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -58,6 +58,7 @@
|
|||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -203,6 +204,10 @@ nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElem
|
|||
// (2) The children's parent back pointer should not be to this synthetic root
|
||||
// but should instead point to the enclosing parent element.
|
||||
nsIDocument* doc = aElement->GetUncomposedDoc();
|
||||
ServoStyleSet* servoStyleSet = nullptr;
|
||||
if (nsIPresShell* presShell = aElement->OwnerDoc()->GetShell()) {
|
||||
servoStyleSet = presShell->StyleSet()->GetAsServo();
|
||||
}
|
||||
bool allowScripts = AllowScripts();
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
@ -233,6 +238,10 @@ nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElem
|
|||
if (xuldoc)
|
||||
xuldoc->AddSubtreeToDocument(child);
|
||||
#endif
|
||||
|
||||
if (servoStyleSet) {
|
||||
servoStyleSet->RestyleSubtree(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -296,7 +296,7 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode* aDOMNode,
|
|||
NS_NewURI(getter_AddRefs(bgUri), bgStringValue);
|
||||
NS_ENSURE_TRUE(bgUri, NS_ERROR_FAILURE);
|
||||
|
||||
RefPtr<imgLoader> il = imgLoader::GetInstance();
|
||||
imgLoader* il = imgLoader::NormalLoader();
|
||||
NS_ENSURE_TRUE(il, NS_ERROR_FAILURE);
|
||||
|
||||
return il->LoadImage(bgUri, nullptr, nullptr,
|
||||
|
|
|
@ -1078,10 +1078,13 @@ nsFind::Find(const char16_t* aPatText, nsIDOMRange* aSearchRange,
|
|||
c = ToLowerCase(c);
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
if (c == CH_SHY) {
|
||||
// ignore soft hyphens in the document
|
||||
case CH_SHY:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mCaseSensitive) {
|
||||
switch (c) {
|
||||
// treat curly and straight quotes as identical
|
||||
case CH_LEFT_SINGLE_QUOTE:
|
||||
case CH_RIGHT_SINGLE_QUOTE:
|
||||
|
@ -1104,6 +1107,7 @@ nsFind::Find(const char16_t* aPatText, nsIDOMRange* aSearchRange,
|
|||
patc = CH_QUOTE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// a '\n' between CJ characters is ignored
|
||||
if (pindex != (mFindBackward ? patLen : 0) && c != patc && !inWhitespace) {
|
||||
|
|
|
@ -1658,13 +1658,16 @@ nsWindowWatcher::CalculateChromeFlags(mozIDOMWindowProxy* aParent,
|
|||
nsIWebBrowserChrome::CHROME_STATUSBAR);
|
||||
NS_CALCULATE_CHROME_FLAG_FOR("menubar",
|
||||
nsIWebBrowserChrome::CHROME_MENUBAR);
|
||||
NS_CALCULATE_CHROME_FLAG_FOR("scrollbars",
|
||||
nsIWebBrowserChrome::CHROME_SCROLLBARS);
|
||||
NS_CALCULATE_CHROME_FLAG_FOR("resizable",
|
||||
nsIWebBrowserChrome::CHROME_WINDOW_RESIZE);
|
||||
NS_CALCULATE_CHROME_FLAG_FOR("minimizable",
|
||||
nsIWebBrowserChrome::CHROME_WINDOW_MIN);
|
||||
|
||||
// default scrollbar to "on," unless explicitly turned off
|
||||
if (WinHasOption(aFeatures, "scrollbars", 1, &presenceFlag) || !presenceFlag) {
|
||||
chromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS;
|
||||
}
|
||||
|
||||
chromeFlags |= WinHasOption(aFeatures, "popup", 0, &presenceFlag) ?
|
||||
nsIWebBrowserChrome::CHROME_WINDOW_POPUP : 0;
|
||||
|
||||
|
|
|
@ -219,6 +219,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=450048
|
|||
|
||||
assertNotFound(quotes, "\"doesn't\"");
|
||||
assertNotFound(quotes, "\u201Cdoesn't\u201D");
|
||||
|
||||
// Curly quotes and straight quotes should not match.
|
||||
rf.caseSensitive = true;
|
||||
|
||||
assertFound(quotes, "\"straight\"");
|
||||
assertNotFound(quotes, "\u201Cstraight\u201D");
|
||||
|
||||
assertNotFound(quotes, "\"curly\"");
|
||||
assertFound(quotes, "\u201Ccurly\u201D");
|
||||
|
||||
assertFound(quotes, "\u2018didn't\u2019");
|
||||
assertNotFound(quotes, "'didn't'");
|
||||
|
||||
assertFound(quotes, "'doesn\u2019t'");
|
||||
assertNotFound(quotes, "'doesn\u2018t'");
|
||||
assertNotFound(quotes, "'doesn't'");
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -40,6 +40,10 @@
|
|||
#include "mozilla/Snprintf.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIHttpAuthenticatorCallback.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsICancelable.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -51,6 +55,7 @@ static const char kNegotiateAuthAllowNonFqdn[] = "network.negotiate-auth.allow-n
|
|||
static const char kNegotiateAuthSSPI[] = "network.auth.use-sspi";
|
||||
|
||||
#define kNegotiateLen (sizeof(kNegotiate)-1)
|
||||
#define DEFAULT_THREAD_TIMEOUT_MS 30000
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -185,6 +190,236 @@ nsHttpNegotiateAuth::ChallengeReceived(nsIHttpAuthenticableChannel *authChannel,
|
|||
|
||||
NS_IMPL_ISUPPORTS(nsHttpNegotiateAuth, nsIHttpAuthenticator)
|
||||
|
||||
namespace {
|
||||
|
||||
//
|
||||
// GetNextTokenCompleteEvent
|
||||
//
|
||||
// This event is fired on main thread when async call of
|
||||
// nsHttpNegotiateAuth::GenerateCredentials is finished. During the Run()
|
||||
// method the nsIHttpAuthenticatorCallback::OnCredsAvailable is called with
|
||||
// obtained credentials, flags and NS_OK when successful, otherwise
|
||||
// NS_ERROR_FAILURE is returned as a result of failed operation.
|
||||
//
|
||||
class GetNextTokenCompleteEvent final : public nsIRunnable,
|
||||
public nsICancelable
|
||||
{
|
||||
virtual ~GetNextTokenCompleteEvent()
|
||||
{
|
||||
if (mCreds) {
|
||||
free(mCreds);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
explicit GetNextTokenCompleteEvent(nsIHttpAuthenticatorCallback* aCallback)
|
||||
: mCallback(aCallback)
|
||||
, mCreds(nullptr)
|
||||
, mCancelled(false)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DispatchSuccess(char *aCreds,
|
||||
uint32_t aFlags,
|
||||
nsISupports *aSessionState,
|
||||
nsISupports *aContinuationState)
|
||||
{
|
||||
// Called from worker thread
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
mCreds = aCreds;
|
||||
mFlags = aFlags;
|
||||
mResult = NS_OK;
|
||||
mSessionState = aSessionState;
|
||||
mContinuationState = aContinuationState;
|
||||
return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DispatchError()
|
||||
{
|
||||
// Called from worker thread
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
mResult = NS_ERROR_FAILURE;
|
||||
return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run() override
|
||||
{
|
||||
// Runs on main thread
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mCancelled) {
|
||||
nsCOMPtr<nsIHttpAuthenticatorCallback> callback;
|
||||
callback.swap(mCallback);
|
||||
callback->OnCredsGenerated(mCreds, mFlags, mResult, mSessionState, mContinuationState);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Cancel(nsresult aReason) override
|
||||
{
|
||||
// Supposed to be called from main thread
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mCancelled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIHttpAuthenticatorCallback> mCallback;
|
||||
char *mCreds; // This class owns it, freed in destructor
|
||||
uint32_t mFlags;
|
||||
nsresult mResult;
|
||||
bool mCancelled;
|
||||
nsCOMPtr<nsISupports> mSessionState;
|
||||
nsCOMPtr<nsISupports> mContinuationState;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(GetNextTokenCompleteEvent, nsIRunnable, nsICancelable)
|
||||
|
||||
//
|
||||
// GetNextTokenRunnable
|
||||
//
|
||||
// This runnable is created by GenerateCredentialsAsync and it runs
|
||||
// in nsHttpNegotiateAuth::mNegotiateThread and calling GenerateCredentials.
|
||||
//
|
||||
class GetNextTokenRunnable final : public mozilla::Runnable
|
||||
{
|
||||
virtual ~GetNextTokenRunnable() {}
|
||||
public:
|
||||
GetNextTokenRunnable(nsIHttpAuthenticableChannel *authChannel,
|
||||
const char *challenge,
|
||||
bool isProxyAuth,
|
||||
const char16_t *domain,
|
||||
const char16_t *username,
|
||||
const char16_t *password,
|
||||
nsISupports *sessionState,
|
||||
nsISupports *continuationState,
|
||||
GetNextTokenCompleteEvent *aCompleteEvent
|
||||
)
|
||||
: mAuthChannel(authChannel)
|
||||
, mChallenge(challenge)
|
||||
, mIsProxyAuth(isProxyAuth)
|
||||
, mDomain(domain)
|
||||
, mUsername(username)
|
||||
, mPassword(password)
|
||||
, mSessionState(sessionState)
|
||||
, mContinuationState(continuationState)
|
||||
, mCompleteEvent(aCompleteEvent)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run() override
|
||||
{
|
||||
// Runs on worker thread
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
char *creds;
|
||||
uint32_t flags;
|
||||
nsresult rv = ObtainCredentialsAndFlags(&creds, &flags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return mCompleteEvent->DispatchError();
|
||||
}
|
||||
|
||||
return mCompleteEvent->DispatchSuccess(creds, flags, mSessionState, mContinuationState);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ObtainCredentialsAndFlags(char **aCreds, uint32_t *aFlags)
|
||||
{
|
||||
// Use negotiate service to call GenerateCredentials outside of main thread
|
||||
nsAutoCString contractId;
|
||||
contractId.Assign(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX);
|
||||
contractId.Append("negotiate");
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIHttpAuthenticator> authenticator = do_GetService(contractId.get(), &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsISupports *sessionState = mSessionState;
|
||||
nsISupports *continuationState = mContinuationState;
|
||||
// The continuationState is for the sake of completeness propagated
|
||||
// to the caller (despite it is not changed in any GenerateCredentials
|
||||
// implementation).
|
||||
//
|
||||
// The only implementation that use sessionState is the
|
||||
// nsHttpDigestAuth::GenerateCredentials. Since there's no reason
|
||||
// to implement nsHttpDigestAuth::GenerateCredentialsAsync
|
||||
// because digest auth does not block the main thread, we won't
|
||||
// propagate changes to sessionState to the caller because of
|
||||
// the change is too complicated on the caller side.
|
||||
rv = authenticator->GenerateCredentials(mAuthChannel,
|
||||
mChallenge.get(),
|
||||
mIsProxyAuth,
|
||||
mDomain.get(),
|
||||
mUsername.get(),
|
||||
mPassword.get(),
|
||||
&sessionState,
|
||||
&continuationState,
|
||||
aFlags,
|
||||
aCreds);
|
||||
mSessionState = sessionState;
|
||||
mContinuationState = continuationState;
|
||||
return rv;
|
||||
}
|
||||
private:
|
||||
nsCOMPtr<nsIHttpAuthenticableChannel> mAuthChannel;
|
||||
nsCString mChallenge;
|
||||
bool mIsProxyAuth;
|
||||
nsString mDomain;
|
||||
nsString mUsername;
|
||||
nsString mPassword;
|
||||
nsCOMPtr<nsISupports> mSessionState;
|
||||
nsCOMPtr<nsISupports> mContinuationState;
|
||||
RefPtr<GetNextTokenCompleteEvent> mCompleteEvent;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpNegotiateAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
|
||||
nsIHttpAuthenticatorCallback* aCallback,
|
||||
const char *challenge,
|
||||
bool isProxyAuth,
|
||||
const char16_t *domain,
|
||||
const char16_t *username,
|
||||
const char16_t *password,
|
||||
nsISupports *sessionState,
|
||||
nsISupports *continuationState,
|
||||
nsICancelable **aCancelable)
|
||||
{
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
NS_ENSURE_ARG_POINTER(aCancelable);
|
||||
|
||||
RefPtr<GetNextTokenCompleteEvent> cancelEvent =
|
||||
new GetNextTokenCompleteEvent(aCallback);
|
||||
|
||||
|
||||
nsCOMPtr<nsIRunnable> getNextTokenRunnable =
|
||||
new GetNextTokenRunnable(authChannel,
|
||||
challenge,
|
||||
isProxyAuth,
|
||||
domain,
|
||||
username,
|
||||
password,
|
||||
sessionState,
|
||||
continuationState,
|
||||
cancelEvent);
|
||||
cancelEvent.forget(aCancelable);
|
||||
|
||||
nsresult rv;
|
||||
if (!mNegotiateThread) {
|
||||
mNegotiateThread =
|
||||
new mozilla::LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
|
||||
NS_LITERAL_CSTRING("NegotiateAuth"));
|
||||
NS_ENSURE_TRUE(mNegotiateThread, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
rv = mNegotiateThread->Dispatch(getNextTokenRunnable, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// GenerateCredentials
|
||||
//
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "nsIURI.h"
|
||||
#include "nsSubstring.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
|
||||
// The nsHttpNegotiateAuth class provides responses for the GSS-API Negotiate method
|
||||
// as specified by Microsoft in draft-brezak-spnego-http-04.txt
|
||||
|
@ -17,7 +18,7 @@
|
|||
class nsHttpNegotiateAuth final : public nsIHttpAuthenticator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIHTTPAUTHENTICATOR
|
||||
|
||||
private:
|
||||
|
@ -37,5 +38,7 @@ private:
|
|||
int32_t port,
|
||||
const char *baseStart,
|
||||
const char *baseEnd);
|
||||
// Thread for GenerateCredentialsAsync
|
||||
RefPtr<mozilla::LazyIdleThread> mNegotiateThread;
|
||||
};
|
||||
#endif /* nsHttpNegotiateAuth_h__ */
|
||||
|
|
|
@ -1018,9 +1018,13 @@ DrawTargetSkia::FillGlyphs(ScaledFont *aFont,
|
|||
#endif
|
||||
|
||||
ScaledFontBase* skiaFont = static_cast<ScaledFontBase*>(aFont);
|
||||
SkTypeface* typeface = skiaFont->GetSkTypeface();
|
||||
if (!typeface) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
|
||||
paint.mPaint.setTypeface(skiaFont->GetSkTypeface());
|
||||
paint.mPaint.setTypeface(typeface);
|
||||
paint.mPaint.setTextSize(SkFloatToScalar(skiaFont->mSize));
|
||||
paint.mPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||
|
||||
|
|
|
@ -115,31 +115,65 @@ ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget
|
|||
|
||||
|
||||
#ifdef USE_SKIA
|
||||
bool
|
||||
ScaledFontDWrite::DefaultToArialFont(IDWriteFontCollection* aSystemFonts)
|
||||
{
|
||||
// If we can't find the same font face as we're given, fallback to arial
|
||||
static const WCHAR fontFamilyName[] = L"Arial";
|
||||
|
||||
UINT32 fontIndex;
|
||||
BOOL exists;
|
||||
HRESULT hr = aSystemFonts->FindFamilyName(fontFamilyName, &fontIndex, &exists);
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "Failed to get backup arial font font from system fonts. Code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = aSystemFonts->GetFontFamily(fontIndex, getter_AddRefs(mFontFamily));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "Failed to get font family for arial. Code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = mFontFamily->GetFirstMatchingFont(DWRITE_FONT_WEIGHT_NORMAL,
|
||||
DWRITE_FONT_STRETCH_NORMAL,
|
||||
DWRITE_FONT_STYLE_NORMAL,
|
||||
getter_AddRefs(mFont));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalNote << "Failed to get a matching font for arial. Code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This can happen if we have mixed backends which create DWrite
|
||||
// fonts in a mixed environment. e.g. a cairo content backend
|
||||
// but Skia canvas backend.
|
||||
void
|
||||
bool
|
||||
ScaledFontDWrite::GetFontDataFromSystemFonts(IDWriteFactory* aFactory)
|
||||
{
|
||||
MOZ_ASSERT(mFontFace);
|
||||
RefPtr<IDWriteFontCollection> systemFonts;
|
||||
HRESULT hr = aFactory->GetSystemFontCollection(getter_AddRefs(systemFonts));
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to get system font collection from file data. Code: " << hexa(hr);
|
||||
return;
|
||||
gfxCriticalNote << "Failed to get system font collection from file data. Code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = systemFonts->GetFontFromFontFace(mFontFace, getter_AddRefs(mFont));
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to get system font from font face. Code: " << hexa(hr);
|
||||
return;
|
||||
gfxCriticalNote << "Failed to get system font from font face. Code: " << hexa(hr);
|
||||
return DefaultToArialFont(systemFonts);
|
||||
}
|
||||
|
||||
hr = mFont->GetFontFamily(getter_AddRefs(mFontFamily));
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to get font family from font face. Code: " << hexa(hr);
|
||||
return;
|
||||
gfxCriticalNote << "Failed to get font family from font face. Code: " << hexa(hr);
|
||||
return DefaultToArialFont(systemFonts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SkTypeface*
|
||||
|
@ -147,8 +181,14 @@ ScaledFontDWrite::GetSkTypeface()
|
|||
{
|
||||
if (!mTypeface) {
|
||||
IDWriteFactory *factory = DrawTargetD2D1::GetDWriteFactory();
|
||||
if (!factory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mFont || !mFontFamily) {
|
||||
GetFontDataFromSystemFonts(factory);
|
||||
if (!GetFontDataFromSystemFonts(factory)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mTypeface = SkCreateTypefaceFromDWriteFont(factory, mFontFace, mFont, mFontFamily);
|
||||
|
|
|
@ -46,7 +46,8 @@ public:
|
|||
|
||||
#ifdef USE_SKIA
|
||||
virtual SkTypeface* GetSkTypeface();
|
||||
void GetFontDataFromSystemFonts(IDWriteFactory* aFactory);
|
||||
bool GetFontDataFromSystemFonts(IDWriteFactory* aFactory);
|
||||
bool DefaultToArialFont(IDWriteFontCollection* aSystemFonts);
|
||||
#endif
|
||||
|
||||
// The font and font family are only used with Skia
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace gfx {
|
|||
_(D3D11_COMPOSITING, Feature, "Direct3D11 Compositing") \
|
||||
_(D3D9_COMPOSITING, Feature, "Direct3D9 Compositing") \
|
||||
_(DIRECT2D, Feature, "Direct2D") \
|
||||
_(D3D11_ANGLE, Feature, "Direct3D11 ANGLE") \
|
||||
_(D3D11_HW_ANGLE, Feature, "Direct3D11 hardware ANGLE") \
|
||||
/* Add new entries above this comment */
|
||||
|
||||
enum class Feature : uint32_t {
|
||||
|
|
|
@ -170,7 +170,7 @@ GetAndInitDisplayForAccelANGLE(GLLibraryEGL& egl)
|
|||
{
|
||||
EGLDisplay ret = 0;
|
||||
|
||||
FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_ANGLE);
|
||||
FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
|
||||
|
||||
if (!gfxPrefs::WebGLANGLETryD3D11())
|
||||
d3d11ANGLE.UserDisable("User disabled D3D11 ANGLE by pref");
|
||||
|
@ -178,7 +178,7 @@ GetAndInitDisplayForAccelANGLE(GLLibraryEGL& egl)
|
|||
if (gfxPrefs::WebGLANGLEForceD3D11())
|
||||
d3d11ANGLE.UserForceEnable("User force-enabled D3D11 ANGLE on disabled hardware");
|
||||
|
||||
if (gfxConfig::IsForcedOnByUser(Feature::D3D11_ANGLE))
|
||||
if (gfxConfig::IsForcedOnByUser(Feature::D3D11_HW_ANGLE))
|
||||
return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
|
||||
|
||||
if (d3d11ANGLE.IsEnabled()) {
|
||||
|
|
|
@ -219,10 +219,10 @@ LayerManager::LayerUserDataDestroy(void* data)
|
|||
delete static_cast<LayerUserData*>(data);
|
||||
}
|
||||
|
||||
nsAutoPtr<LayerUserData>
|
||||
UniquePtr<LayerUserData>
|
||||
LayerManager::RemoveUserData(void* aKey)
|
||||
{
|
||||
nsAutoPtr<LayerUserData> d(static_cast<LayerUserData*>(mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
|
||||
UniquePtr<LayerUserData> d(static_cast<LayerUserData*>(mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
|
||||
return d;
|
||||
}
|
||||
|
||||
|
@ -2148,10 +2148,10 @@ Layer::IsBackfaceHidden()
|
|||
return false;
|
||||
}
|
||||
|
||||
nsAutoPtr<LayerUserData>
|
||||
UniquePtr<LayerUserData>
|
||||
Layer::RemoveUserData(void* aKey)
|
||||
{
|
||||
nsAutoPtr<LayerUserData> d(static_cast<LayerUserData*>(mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
|
||||
UniquePtr<LayerUserData> d(static_cast<LayerUserData*>(mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
|
||||
return d;
|
||||
}
|
||||
|
||||
|
|
|
@ -505,7 +505,7 @@ public:
|
|||
/**
|
||||
* This can be used anytime. Ownership passes to the caller!
|
||||
*/
|
||||
nsAutoPtr<LayerUserData> RemoveUserData(void* aKey);
|
||||
UniquePtr<LayerUserData> RemoveUserData(void* aKey);
|
||||
|
||||
/**
|
||||
* This getter can be used anytime.
|
||||
|
@ -1462,7 +1462,7 @@ public:
|
|||
/**
|
||||
* This can be used anytime. Ownership passes to the caller!
|
||||
*/
|
||||
nsAutoPtr<LayerUserData> RemoveUserData(void* aKey);
|
||||
UniquePtr<LayerUserData> RemoveUserData(void* aKey);
|
||||
/**
|
||||
* This getter can be used anytime.
|
||||
*/
|
||||
|
|
|
@ -47,3 +47,5 @@ skip-if = (toolkit == 'windows') || (toolkit == 'cocoa')
|
|||
[test_group_wheelevents.html]
|
||||
skip-if = (toolkit == 'android') # wheel events not supported on mobile
|
||||
[test_group_mouseevents.html]
|
||||
[test_touch_listeners_impacting_wheel.html]
|
||||
skip-if = (toolkit == 'android') || (toolkit == 'cocoa') # wheel events not supported on mobile, and synthesized wheel smooth-scrolling not supported on OS X
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1203140
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1203140</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<script type="application/javascript" src="apz_test_utils.js"></script>
|
||||
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1203140">Mozilla Bug 1203140</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="overflow-y:scroll; height: 400px">
|
||||
<p>The box below has a touch listener and a passive wheel listener. With touch events disabled, APZ shouldn't wait for any listeners.</p>
|
||||
<div id="box" style="width: 200px; height: 200px; background-color: blue"></div>
|
||||
<div style="height: 1000px; width: 10px">Div to make 'content' scrollable</div>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
const kResponseTimeoutMs = 2 * 60 * 1000; // 2 minutes
|
||||
|
||||
function parentProcessSnapshot() {
|
||||
addMessageListener('snapshot', function(rect) {
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
var topWin = Services.wm.getMostRecentWindow('navigator:browser');
|
||||
|
||||
// reposition the rect relative to the top-level browser window
|
||||
rect = JSON.parse(rect);
|
||||
rect.x -= topWin.mozInnerScreenX;
|
||||
rect.y -= topWin.mozInnerScreenY;
|
||||
|
||||
// take the snapshot
|
||||
var canvas = topWin.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
canvas.width = rect.w;
|
||||
canvas.height = rect.h;
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.drawWindow(topWin, rect.x, rect.y, rect.w, rect.h, 'rgb(255,255,255)', ctx.DRAWWINDOW_DRAW_VIEW | ctx.DRAWWINDOW_USE_WIDGET_LAYERS | ctx.DRAWWINDOW_DRAW_CARET);
|
||||
return canvas.toDataURL();
|
||||
});
|
||||
}
|
||||
|
||||
function takeSnapshots(e) {
|
||||
// Grab some snapshots, and make sure some of them are different (i.e. check
|
||||
// the page is scrolling in the compositor, concurrently with this wheel
|
||||
// listener running).
|
||||
// Note that we want this function to take less time than the content response
|
||||
// timeout, otherwise the scrolling will start even if we haven't returned,
|
||||
// and that would invalidate purpose of the test.
|
||||
var start = Date.now();
|
||||
var lastSnapshot = null;
|
||||
var success = false;
|
||||
|
||||
var chromeHelper = SpecialPowers.loadChromeScript(parentProcessSnapshot);
|
||||
SimpleTest.registerCleanupFunction(function() { chromeHelper.destroy() });
|
||||
|
||||
// Get the position of the 'content' div relative to the screen
|
||||
var contentDiv = document.getElementById('content');
|
||||
var rect = coordinatesRelativeToWindow(0, 0, contentDiv);
|
||||
rect.w = contentDiv.getBoundingClientRect().width * window.devicePixelRatio;
|
||||
rect.h = contentDiv.getBoundingClientRect().height * window.devicePixelRatio;
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(16);
|
||||
var snapshot = chromeHelper.sendSyncMessage('snapshot', JSON.stringify(rect)).toString();
|
||||
//dump("Took snapshot " + snapshot + "\n"); // this might help with debugging
|
||||
|
||||
if (lastSnapshot && lastSnapshot != snapshot) {
|
||||
ok(true, "Found some different pixels in snapshot " + i + " compared to previous");
|
||||
success = true;
|
||||
}
|
||||
lastSnapshot = snapshot;
|
||||
}
|
||||
ok(success, "Found some snapshots that were different");
|
||||
ok((Date.now() - start) < kResponseTimeoutMs, "Snapshotting ran quickly enough");
|
||||
|
||||
// Until now, no scroll events will have been dispatched to content. That's
|
||||
// because scroll events are dispatched on the main thread, which we've been
|
||||
// hogging with the code above. At this point we restore the normal refresh
|
||||
// behaviour and let the main thread go back to C++ code, so the scroll events
|
||||
// fire and we unwind from the main test continuation.
|
||||
SpecialPowers.DOMWindowUtils.restoreNormalRefresh();
|
||||
}
|
||||
|
||||
function* runTest() {
|
||||
var box = document.getElementById('box');
|
||||
box.addEventListener('touchstart', function(e) {
|
||||
ok(false, "This should never be run");
|
||||
}, false);
|
||||
box.addEventListener('wheel', takeSnapshots, { capture: false, passive: true });
|
||||
|
||||
// Let the event regions propagate to the APZ
|
||||
yield waitForAllPaints(function() {
|
||||
flushApzRepaints(driveTest);
|
||||
});
|
||||
|
||||
// Take over control of the refresh driver and compositor
|
||||
var utils = SpecialPowers.DOMWindowUtils;
|
||||
utils.advanceTimeAndRefresh(0);
|
||||
|
||||
// Trigger an APZ scroll using a wheel event. If APZ is waiting for a
|
||||
// content response, it will wait for takeSnapshots to finish running before
|
||||
// it starts scrolling, which will cause the checks in takeSnapshots to fail.
|
||||
yield synthesizeNativeMouseMoveAndWaitForMoveEvent(box, 10, 10, driveTest);
|
||||
yield synthesizeNativeWheelAndWaitForScrollEvent(box, 10, 10, 0, -50, driveTest);
|
||||
}
|
||||
|
||||
var gTestContinuation = null;
|
||||
function driveTest() {
|
||||
if (!gTestContinuation) {
|
||||
gTestContinuation = runTest();
|
||||
}
|
||||
var ret = gTestContinuation.next();
|
||||
if (ret.done) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
// This test requires APZ - if it's not enabled, skip it.
|
||||
var apzEnabled = SpecialPowers.getDOMWindowUtils(window).asyncPanZoomEnabled;
|
||||
if (!apzEnabled) {
|
||||
ok(true, "APZ not enabled, skipping test");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
waitForAllPaints(function() {
|
||||
flushApzRepaints(driveTest);
|
||||
})
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Disable touch events, so that APZ knows not to wait for touch listeners.
|
||||
// Also explicitly set the content response timeout, so we know how long it
|
||||
// is (see comment in takeSnapshots).
|
||||
// Finally, enable smooth scrolling, so that the wheel-scroll we do as part
|
||||
// of the test triggers an APZ animation rather than doing an instant scroll.
|
||||
// Note that this pref doesn't work for the synthesized wheel events on OS X,
|
||||
// those are hard-coded to be instant scrolls.
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.w3c_touch_events.enabled", 0],
|
||||
["apz.content_response_timeout", kResponseTimeoutMs],
|
||||
["general.smoothscroll", true]]},
|
||||
function() {
|
||||
SimpleTest.waitForFocus(startTest, window);
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -506,8 +506,9 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
|
|||
BufferMode bufferMode = BufferMode::BUFFERED;
|
||||
if (mTarget) {
|
||||
// If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Use a dummy
|
||||
// placeholder so that CreateRenderTarget() works.
|
||||
mDrawTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
// placeholder so that CreateRenderTarget() works. This is only used to create a new buffered
|
||||
// draw target that we composite into, then copy the results the destination.
|
||||
mDrawTarget = mTarget;
|
||||
} else {
|
||||
// StartRemoteDrawingInRegion can mutate mInvalidRegion.
|
||||
mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion, &bufferMode);
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
|
||||
// The resizer background area in a status bar
|
||||
// for the resizer widget in the corner of a window.
|
||||
#define NS_THEME_RESIZER_PANEL 25
|
||||
#define NS_THEME_RESIZERPANEL 25
|
||||
|
||||
// The resizer itself.
|
||||
#define NS_THEME_RESIZER 26
|
||||
|
@ -174,7 +174,7 @@
|
|||
#define NS_THEME_TEXTFIELD 95
|
||||
|
||||
// The caret of a text area
|
||||
#define NS_THEME_TEXTFIELD_CARET 96
|
||||
#define NS_THEME_CARET 96
|
||||
|
||||
// A multiline text field
|
||||
#define NS_THEME_TEXTFIELD_MULTILINE 97
|
||||
|
|
|
@ -150,9 +150,9 @@ TEST(Layers, UserData) {
|
|||
layer.SetUserData(key3, data3);
|
||||
|
||||
// Also checking that the user data is returned but not free'd
|
||||
UniquePtr<LayerUserData> d1(layer.RemoveUserData(key1).forget());
|
||||
UniquePtr<LayerUserData> d2(layer.RemoveUserData(key2).forget());
|
||||
UniquePtr<LayerUserData> d3(layer.RemoveUserData(key3).forget());
|
||||
UniquePtr<LayerUserData> d1(layer.RemoveUserData(key1));
|
||||
UniquePtr<LayerUserData> d2(layer.RemoveUserData(key2));
|
||||
UniquePtr<LayerUserData> d3(layer.RemoveUserData(key3));
|
||||
ASSERT_EQ(data1, d1.get());
|
||||
ASSERT_EQ(data2, d2.get());
|
||||
ASSERT_EQ(data3, d3.get());
|
||||
|
|
|
@ -2067,7 +2067,6 @@ gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
|
|||
* and remember the values. Changing these preferences during the run will
|
||||
* not have any effect until we restart.
|
||||
*/
|
||||
bool gANGLESupportsD3D11 = false;
|
||||
static mozilla::Atomic<bool> sLayersSupportsHardwareVideoDecoding(false);
|
||||
static bool sLayersHardwareVideoDecodingFailed = false;
|
||||
static bool sBufferRotationCheckPref = true;
|
||||
|
@ -2096,15 +2095,6 @@ gfxPlatform::InitAcceleration()
|
|||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
nsCString discardFailureId;
|
||||
int32_t status;
|
||||
#ifdef XP_WIN
|
||||
if (!gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly() && gfxInfo) {
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, discardFailureId, &status))) {
|
||||
if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
gANGLESupportsD3D11 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) &&
|
||||
#ifdef XP_WIN
|
||||
|
|
|
@ -97,11 +97,11 @@ public:
|
|||
// Public textrun API for general use
|
||||
|
||||
bool IsClusterStart(uint32_t aPos) const {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
MOZ_ASSERT(aPos < GetLength());
|
||||
return mCharacterGlyphs[aPos].IsClusterStart();
|
||||
}
|
||||
bool IsLigatureGroupStart(uint32_t aPos) const {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
MOZ_ASSERT(aPos < GetLength());
|
||||
return mCharacterGlyphs[aPos].IsLigatureGroupStart();
|
||||
}
|
||||
bool CanBreakLineBefore(uint32_t aPos) const {
|
||||
|
@ -114,24 +114,24 @@ public:
|
|||
// Returns a gfxShapedText::CompressedGlyph::FLAG_BREAK_TYPE_* value
|
||||
// as defined in gfxFont.h (may be NONE, NORMAL or HYPHEN).
|
||||
uint8_t CanBreakBefore(uint32_t aPos) const {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
MOZ_ASSERT(aPos < GetLength());
|
||||
return mCharacterGlyphs[aPos].CanBreakBefore();
|
||||
}
|
||||
|
||||
bool CharIsSpace(uint32_t aPos) const {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
MOZ_ASSERT(aPos < GetLength());
|
||||
return mCharacterGlyphs[aPos].CharIsSpace();
|
||||
}
|
||||
bool CharIsTab(uint32_t aPos) const {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
MOZ_ASSERT(aPos < GetLength());
|
||||
return mCharacterGlyphs[aPos].CharIsTab();
|
||||
}
|
||||
bool CharIsNewline(uint32_t aPos) const {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
MOZ_ASSERT(aPos < GetLength());
|
||||
return mCharacterGlyphs[aPos].CharIsNewline();
|
||||
}
|
||||
bool CharMayHaveEmphasisMark(uint32_t aPos) const {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
MOZ_ASSERT(aPos < GetLength());
|
||||
return mCharacterGlyphs[aPos].CharMayHaveEmphasisMark();
|
||||
}
|
||||
|
||||
|
@ -394,7 +394,7 @@ public:
|
|||
* SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
|
||||
*
|
||||
* @param aCanWordWrap true if we can break between any two grapheme
|
||||
* clusters. This is set by word-wrap: break-word
|
||||
* clusters. This is set by overflow-wrap|word-wrap: break-word
|
||||
*
|
||||
* @param aBreakPriority in/out the priority of the break opportunity
|
||||
* saved in the line. If we are prioritizing break opportunities, we will
|
||||
|
@ -513,7 +513,7 @@ public:
|
|||
void SanitizeGlyphRuns();
|
||||
|
||||
CompressedGlyph* GetCharacterGlyphs() final {
|
||||
NS_ASSERTION(mCharacterGlyphs, "failed to initialize mCharacterGlyphs");
|
||||
MOZ_ASSERT(mCharacterGlyphs, "failed to initialize mCharacterGlyphs");
|
||||
return mCharacterGlyphs;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ typedef double gfxFloat;
|
|||
*
|
||||
* eNoBreak The line has no break opportunities
|
||||
* eWordWrapBreak The line has a break opportunity only within a word. With
|
||||
* word-wrap: break-word we will break at this point only if
|
||||
* overflow-wrap|word-wrap: break-word we will break at this point only if
|
||||
* there are no other break opportunities in the line.
|
||||
* eNormalBreak The line has a break opportunity determined by the standard
|
||||
* line-breaking algorithm.
|
||||
|
|
|
@ -373,6 +373,14 @@ gfxWindowsPlatform::~gfxWindowsPlatform()
|
|||
CoUninitialize();
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateANGLEConfig()
|
||||
{
|
||||
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
|
||||
gfxConfig::Disable(Feature::D3D11_HW_ANGLE, FeatureStatus::Disabled, "D3D11 compositing is disabled");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitAcceleration()
|
||||
{
|
||||
|
@ -389,6 +397,7 @@ gfxWindowsPlatform::InitAcceleration()
|
|||
|
||||
InitializeConfig();
|
||||
InitializeDevices();
|
||||
UpdateANGLEConfig();
|
||||
UpdateRenderMode();
|
||||
}
|
||||
|
||||
|
@ -455,11 +464,14 @@ gfxWindowsPlatform::HandleDeviceReset()
|
|||
mCompositorD3D11TextureSharingWorks = false;
|
||||
mDeviceResetReason = DeviceResetReason::OK;
|
||||
|
||||
imgLoader::Singleton()->ClearCache(true);
|
||||
imgLoader::Singleton()->ClearCache(false);
|
||||
imgLoader::NormalLoader()->ClearCache(true);
|
||||
imgLoader::NormalLoader()->ClearCache(false);
|
||||
imgLoader::PrivateBrowsingLoader()->ClearCache(true);
|
||||
imgLoader::PrivateBrowsingLoader()->ClearCache(false);
|
||||
gfxAlphaBoxBlur::ShutdownBlurCache();
|
||||
|
||||
InitializeDevices();
|
||||
UpdateANGLEConfig();
|
||||
BumpDeviceCounter();
|
||||
return true;
|
||||
}
|
||||
|
@ -1920,6 +1932,25 @@ IsWARPStable()
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
InitializeANGLEConfig()
|
||||
{
|
||||
FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
|
||||
|
||||
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
|
||||
d3d11ANGLE.DisableByDefault(FeatureStatus::Unavailable, "D3D11 compositing is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
d3d11ANGLE.EnableByDefault();
|
||||
|
||||
nsCString message;
|
||||
if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, &message)) {
|
||||
d3d11ANGLE.Disable(FeatureStatus::Blacklisted, message.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitializeConfig()
|
||||
{
|
||||
|
@ -1930,6 +1961,7 @@ gfxWindowsPlatform::InitializeConfig()
|
|||
|
||||
InitializeD3D9Config();
|
||||
InitializeD3D11Config();
|
||||
InitializeANGLEConfig();
|
||||
InitializeD2DConfig();
|
||||
}
|
||||
|
||||
|
@ -2033,6 +2065,9 @@ gfxWindowsPlatform::UpdateDeviceInitData()
|
|||
FeatureStatus::Disabled,
|
||||
"Disabled by parent process");
|
||||
|
||||
|
||||
InitializeANGLEConfig();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2097,13 +2132,13 @@ gfxWindowsPlatform::AttemptD3D11DeviceCreation(FeatureState& d3d11)
|
|||
mCompositorD3D11TextureSharingWorks = ::DoesD3D11TextureSharingWork(mD3D11Device);
|
||||
|
||||
if (!mCompositorD3D11TextureSharingWorks) {
|
||||
gfxConfig::SetFailed(Feature::D3D11_ANGLE,
|
||||
gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE,
|
||||
FeatureStatus::Broken,
|
||||
"Texture sharing doesn't work");
|
||||
}
|
||||
|
||||
if (DoesRenderTargetViewNeedsRecreating(mD3D11Device)) {
|
||||
gfxConfig::SetFailed(Feature::D3D11_ANGLE,
|
||||
gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE,
|
||||
FeatureStatus::Broken,
|
||||
"RenderTargetViews need recreating");
|
||||
}
|
||||
|
@ -2352,12 +2387,6 @@ gfxWindowsPlatform::InitializeDevices()
|
|||
InitializeD3D11();
|
||||
InitializeD2D();
|
||||
|
||||
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
|
||||
gfxConfig::DisableByDefault(Feature::D3D11_ANGLE, FeatureStatus::Disabled, "D3D11 compositing is disabled");
|
||||
} else {
|
||||
gfxConfig::EnableByDefault(Feature::D3D11_ANGLE);
|
||||
}
|
||||
|
||||
if (!gfxConfig::IsEnabled(Feature::DIRECT2D)) {
|
||||
if (XRE_IsContentProcess() && GetParentDevicePrefs().useD2D1()) {
|
||||
RecordContentDeviceFailure(TelemetryDeviceCode::D2D1);
|
||||
|
|
|
@ -394,7 +394,7 @@ void NotifyScreenConfigurationChange(const hal::ScreenConfiguration& aScreenConf
|
|||
* Lock the screen orientation to the specific orientation.
|
||||
* @return Whether the lock has been accepted.
|
||||
*/
|
||||
bool LockScreenOrientation(const dom::ScreenOrientationInternal& aOrientation);
|
||||
MOZ_MUST_USE bool LockScreenOrientation(const dom::ScreenOrientationInternal& aOrientation);
|
||||
|
||||
/**
|
||||
* Unlock the screen orientation.
|
||||
|
@ -438,7 +438,7 @@ void NotifySwitchStateFromInputDevice(hal::SwitchDevice aDevice,
|
|||
*
|
||||
* Currently, there can only be 0 or 1 alarm observers.
|
||||
*/
|
||||
bool RegisterTheOneAlarmObserver(hal::AlarmObserver* aObserver);
|
||||
MOZ_MUST_USE bool RegisterTheOneAlarmObserver(hal::AlarmObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Unregister the alarm observer. Doing so will implicitly cancel any
|
||||
|
@ -465,7 +465,7 @@ void NotifyAlarmFired();
|
|||
* This API is currently only allowed to be used from non-sandboxed
|
||||
* contexts.
|
||||
*/
|
||||
bool SetAlarm(int32_t aSeconds, int32_t aNanoseconds);
|
||||
MOZ_MUST_USE bool SetAlarm(int32_t aSeconds, int32_t aNanoseconds);
|
||||
|
||||
/**
|
||||
* Set the priority of the given process.
|
||||
|
@ -585,7 +585,7 @@ hal::FMRadioSettings GetFMBandSettings(hal::FMRadioCountry aCountry);
|
|||
/**
|
||||
* Enable RDS data reception
|
||||
*/
|
||||
bool EnableRDS(uint32_t aMask);
|
||||
MOZ_MUST_USE bool EnableRDS(uint32_t aMask);
|
||||
|
||||
/**
|
||||
* Disable RDS data reception
|
||||
|
|
|
@ -67,7 +67,7 @@ void DisableSwitchNotifications(hal::SwitchDevice aDevice);
|
|||
/**
|
||||
* Enable alarm notifications from the backend.
|
||||
*/
|
||||
bool EnableAlarm();
|
||||
MOZ_MUST_USE bool EnableAlarm();
|
||||
|
||||
/**
|
||||
* Disable alarm notifications from the backend.
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
// objects that just require generic constructors
|
||||
using namespace mozilla::image;
|
||||
|
||||
// XXX We would like to get rid of the imgLoader factory constructor. See the
|
||||
// comment documenting the imgLoader constructor.
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(imgLoader, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequestProxy)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(imgTools)
|
||||
|
@ -85,9 +87,14 @@ static const mozilla::Module::CategoryEntry kImageCategories[] = {
|
|||
|
||||
static bool sInitialized = false;
|
||||
nsresult
|
||||
mozilla::image::InitModule()
|
||||
mozilla::image::EnsureModuleInitialized()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Make sure the preferences are initialized
|
||||
gfxPrefs::GetSingleton();
|
||||
|
||||
|
@ -118,7 +125,7 @@ static const mozilla::Module kImageModule = {
|
|||
kImageContracts,
|
||||
kImageCategories,
|
||||
nullptr,
|
||||
mozilla::image::InitModule,
|
||||
mozilla::image::EnsureModuleInitialized,
|
||||
// We need to be careful about shutdown ordering to avoid intermittent crashes
|
||||
// when hashtable enumeration decides to destroy modules in an unfortunate
|
||||
// order. So our shutdown is invoked explicitly during layout module shutdown.
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
nsresult InitModule();
|
||||
nsresult EnsureModuleInitialized();
|
||||
void ShutdownModule();
|
||||
|
||||
} /* namespace image */
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/ChaosMode.h"
|
||||
|
||||
#include "ImageLogging.h"
|
||||
#include "nsImageModule.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "imgLoader.h"
|
||||
#include "imgRequestProxy.h"
|
||||
|
@ -1133,26 +1134,40 @@ imgMemoryReporter* imgLoader::sMemReporter;
|
|||
NS_IMPL_ISUPPORTS(imgLoader, imgILoader, nsIContentSniffer, imgICache,
|
||||
nsISupportsWeakReference, nsIObserver)
|
||||
|
||||
static imgLoader* gSingleton = nullptr;
|
||||
static imgLoader* gPBSingleton = nullptr;
|
||||
static imgLoader* gNormalLoader = nullptr;
|
||||
static imgLoader* gPrivateBrowsingLoader = nullptr;
|
||||
|
||||
imgLoader*
|
||||
imgLoader::Singleton()
|
||||
/* static */ already_AddRefed<imgLoader>
|
||||
imgLoader::CreateImageLoader()
|
||||
{
|
||||
if (!gSingleton) {
|
||||
gSingleton = imgLoader::Create().take();
|
||||
}
|
||||
return gSingleton;
|
||||
// In some cases, such as xpctests, XPCOM modules are not automatically
|
||||
// initialized. We need to make sure that our module is initialized before
|
||||
// we hand out imgLoader instances and code starts using them.
|
||||
mozilla::image::EnsureModuleInitialized();
|
||||
|
||||
RefPtr<imgLoader> loader = new imgLoader();
|
||||
loader->Init();
|
||||
|
||||
return loader.forget();
|
||||
}
|
||||
|
||||
imgLoader*
|
||||
imgLoader::PBSingleton()
|
||||
imgLoader::NormalLoader()
|
||||
{
|
||||
if (!gPBSingleton) {
|
||||
gPBSingleton = imgLoader::Create().take();
|
||||
gPBSingleton->RespectPrivacyNotifications();
|
||||
if (!gNormalLoader) {
|
||||
gNormalLoader = CreateImageLoader().take();
|
||||
}
|
||||
return gPBSingleton;
|
||||
return gNormalLoader;
|
||||
}
|
||||
|
||||
imgLoader*
|
||||
imgLoader::PrivateBrowsingLoader()
|
||||
{
|
||||
if (!gPrivateBrowsingLoader) {
|
||||
gPrivateBrowsingLoader = CreateImageLoader().take();
|
||||
gPrivateBrowsingLoader->RespectPrivacyNotifications();
|
||||
}
|
||||
return gPrivateBrowsingLoader;
|
||||
}
|
||||
|
||||
imgLoader::imgLoader()
|
||||
|
@ -1162,21 +1177,6 @@ imgLoader::imgLoader()
|
|||
sMemReporter->RegisterLoader(this);
|
||||
}
|
||||
|
||||
already_AddRefed<imgLoader>
|
||||
imgLoader::GetInstance()
|
||||
{
|
||||
static RefPtr<imgLoader> singleton;
|
||||
if (!singleton) {
|
||||
singleton = imgLoader::Create();
|
||||
if (!singleton) {
|
||||
return nullptr;
|
||||
}
|
||||
ClearOnShutdown(&singleton);
|
||||
}
|
||||
RefPtr<imgLoader> loader = singleton.get();
|
||||
return loader.forget();
|
||||
}
|
||||
|
||||
imgLoader::~imgLoader()
|
||||
{
|
||||
ClearChromeImageCache();
|
||||
|
@ -1400,8 +1400,10 @@ imgLoader::ClearCacheForControlledDocument(nsIDocument* aDoc)
|
|||
void
|
||||
imgLoader::Shutdown()
|
||||
{
|
||||
NS_IF_RELEASE(gSingleton);
|
||||
NS_IF_RELEASE(gPBSingleton);
|
||||
NS_IF_RELEASE(gNormalLoader);
|
||||
gNormalLoader = nullptr;
|
||||
NS_IF_RELEASE(gPrivateBrowsingLoader);
|
||||
gPrivateBrowsingLoader = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -246,30 +246,50 @@ public:
|
|||
NS_DECL_IMGICACHE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static imgLoader* Singleton();
|
||||
static imgLoader* PBSingleton();
|
||||
/**
|
||||
* Get the normal image loader instance that is used by gecko code, creating
|
||||
* it if necessary.
|
||||
*/
|
||||
static imgLoader* NormalLoader();
|
||||
|
||||
/**
|
||||
* Get the Private Browsing image loader instance that is used by gecko code,
|
||||
* creating it if necessary.
|
||||
*
|
||||
* The nsIChannel objects that this instance creates are created with the
|
||||
* nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING flag.
|
||||
*/
|
||||
static imgLoader* PrivateBrowsingLoader();
|
||||
|
||||
/**
|
||||
* Gecko code should use NormalLoader() or PrivateBrowsingLoader() to get the
|
||||
* appropriate image loader.
|
||||
*
|
||||
* This constructor is public because the XPCOM module code that creates
|
||||
* instances of "@mozilla.org/image/loader;1" / "@mozilla.org/image/cache;1"
|
||||
* for nsIComponentManager.createInstance()/nsIServiceManager.getService()
|
||||
* calls (now only made by add-ons) needs access to it.
|
||||
*
|
||||
* XXX We would like to get rid of the nsIServiceManager.getService (and
|
||||
* nsIComponentManager.createInstance) method of creating imgLoader objects,
|
||||
* but there are add-ons that are still using it. These add-ons don't
|
||||
* actually do anything useful with the loaders that they create since nobody
|
||||
* who creates an imgLoader using this method actually QIs to imgILoader and
|
||||
* loads images. They all just QI to imgICache and either call clearCache()
|
||||
* or findEntryProperties(). Since they're doing this on an imgLoader that
|
||||
* has never loaded images, these calls are useless. It seems likely that
|
||||
* the code that is doing this is just legacy code left over from a time when
|
||||
* there was only one imgLoader instance for the entire process. (Nowadays
|
||||
* the correct method to get an imgILoader/imgICache is to call
|
||||
* imgITools::getImgCacheForDocument/imgITools::getImgLoaderForDocument.)
|
||||
* All the same, even though what these add-ons are doing is a no-op,
|
||||
* removing the nsIServiceManager.getService method of creating/getting an
|
||||
* imgLoader objects would cause an exception in these add-ons that could
|
||||
* break things.
|
||||
*/
|
||||
imgLoader();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
static already_AddRefed<imgLoader>
|
||||
Create()
|
||||
{
|
||||
// Unfortunately, we rely on XPCOM module init happening
|
||||
// before imgLoader creation. For now, it's easier
|
||||
// to just call CallCreateInstance() which will init
|
||||
// the image module instead of calling new imgLoader
|
||||
// directly.
|
||||
nsCOMPtr<imgILoader> loader = do_CreateInstance("@mozilla.org/image/loader;1");
|
||||
// There's only one imgLoader implementation so we
|
||||
// can safely cast to it.
|
||||
return loader.forget().downcast<imgLoader>();
|
||||
}
|
||||
|
||||
static already_AddRefed<imgLoader>
|
||||
GetInstance();
|
||||
|
||||
nsresult LoadImage(nsIURI* aURI,
|
||||
nsIURI* aInitialDocumentURI,
|
||||
nsIURI* aReferrerURI,
|
||||
|
@ -373,6 +393,8 @@ public:
|
|||
|
||||
private: // methods
|
||||
|
||||
static already_AddRefed<imgLoader> CreateImageLoader();
|
||||
|
||||
bool ValidateEntry(imgCacheEntry* aEntry, nsIURI* aKey,
|
||||
nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
|
|
|
@ -26,6 +26,9 @@ extern "C" char* PrintJSStack();
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "nsDebug.h"
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
|
@ -158,7 +161,14 @@ ProcessLink::EchoMessage(Message *msg)
|
|||
void
|
||||
ProcessLink::SendMessage(Message *msg)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(msg->size() < IPC::Channel::kMaximumMessageSize);
|
||||
if (msg->size() > IPC::Channel::kMaximumMessageSize) {
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCMessageName"), nsDependentCString(msg->name()));
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCMessageSize"), nsPrintfCString("%d", msg->size()));
|
||||
#endif
|
||||
MOZ_CRASH("IPC message size is too large");
|
||||
}
|
||||
|
||||
mChan->AssertWorkerThread();
|
||||
mChan->mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
|
|
|
@ -1851,11 +1851,12 @@ class ValueOperations
|
|||
JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
|
||||
gc::Cell* toGCThing() const { return value().toGCThing(); }
|
||||
JS::TraceKind traceKind() const { return value().traceKind(); }
|
||||
uint64_t asRawBits() const { return value().asRawBits(); }
|
||||
|
||||
JSValueType extractNonDoubleType() const { return value().extractNonDoubleType(); }
|
||||
void* toPrivate() const { return value().toPrivate(); }
|
||||
uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
|
||||
|
||||
uint64_t asRawBits() const { return value().asRawBits(); }
|
||||
JSValueType extractNonDoubleType() const { return value().extractNonDoubleType(); }
|
||||
|
||||
JSWhyMagic whyMagic() const { return value().whyMagic(); }
|
||||
uint32_t magicUint32() const { return value().magicUint32(); }
|
||||
};
|
||||
|
@ -1885,6 +1886,8 @@ class MutableValueOperations : public ValueOperations<Outer>
|
|||
void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); }
|
||||
void setObject(JSObject& obj) { this->value().setObject(obj); }
|
||||
void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); }
|
||||
void setPrivate(void* ptr) { this->value().setPrivate(ptr); }
|
||||
void setPrivateUint32(uint32_t ui) { this->value().setPrivateUint32(ui); }
|
||||
void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); }
|
||||
};
|
||||
|
||||
|
|
|
@ -248,7 +248,6 @@ ifneq (,$(TAR))
|
|||
source-package:
|
||||
SRCDIR=$(srcdir) \
|
||||
DIST=$(DIST) \
|
||||
MAKE=$(MAKE) \
|
||||
MKDIR=$(MKDIR) \
|
||||
TAR=$(TAR) \
|
||||
MOZJS_MAJOR_VERSION=$(MOZJS_MAJOR_VERSION) \
|
||||
|
|
|
@ -78,6 +78,8 @@ class AstDecodeContext
|
|||
AstIndexVector funcSigs_;
|
||||
AstDecodeExprIter *iter_;
|
||||
const ValTypeVector* locals_;
|
||||
AstNameVector blockLabels_;
|
||||
uint32_t currentLabelIndex_;
|
||||
|
||||
public:
|
||||
AstDecodeContext(JSContext* cx, LifoAlloc& lifo, Decoder& d, AstModule& module, bool generateNames)
|
||||
|
@ -91,23 +93,31 @@ class AstDecodeContext
|
|||
module_(module),
|
||||
funcSigs_(lifo),
|
||||
iter_(nullptr),
|
||||
locals_(nullptr)
|
||||
locals_(nullptr),
|
||||
blockLabels_(lifo)
|
||||
{}
|
||||
|
||||
AstModule& module() { return module_; }
|
||||
AstIndexVector& funcSigs() { return funcSigs_; }
|
||||
AstDecodeExprIter& iter() { return *iter_; }
|
||||
const ValTypeVector& locals() { return *locals_; }
|
||||
AstNameVector& blockLabels() { return blockLabels_; }
|
||||
|
||||
void startFunction(AstDecodeExprIter *iter, const ValTypeVector* locals)
|
||||
{
|
||||
iter_ = iter;
|
||||
locals_ = locals;
|
||||
currentLabelIndex_ = 0;
|
||||
}
|
||||
void endFunction()
|
||||
{
|
||||
iter_ = nullptr;
|
||||
locals_ = nullptr;
|
||||
MOZ_ASSERT(blockLabels_.length() == 0);
|
||||
}
|
||||
uint32_t nextLabelIndex()
|
||||
{
|
||||
return currentLabelIndex_++;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -232,11 +242,12 @@ AstDecodeCall(AstDecodeContext& c)
|
|||
if (!AstDecodeCallReturn(c, *sig))
|
||||
return false;
|
||||
|
||||
uint32_t argsLength = args.length();
|
||||
AstCall* call = new(c.lifo) AstCall(Expr::Call, funcRef, Move(args));
|
||||
if (!call)
|
||||
return false;
|
||||
|
||||
c.iter().setResult(AstDecodeStackItem(call, args.length()));
|
||||
c.iter().setResult(AstDecodeStackItem(call, argsLength));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -268,11 +279,12 @@ AstDecodeCallIndirect(AstDecodeContext& c)
|
|||
if (!AstDecodeCallReturn(c, *sig))
|
||||
return false;
|
||||
|
||||
uint32_t argsLength = args.length();
|
||||
AstCallIndirect* call = new(c.lifo) AstCallIndirect(sigRef, index.expr, Move(args));
|
||||
if (!call)
|
||||
return false;
|
||||
|
||||
c.iter().setResult(AstDecodeStackItem(call, 1 + args.length()));
|
||||
c.iter().setResult(AstDecodeStackItem(call, 1 + argsLength));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -300,11 +312,31 @@ AstDecodeCallImport(AstDecodeContext& c)
|
|||
if (!AstDecodeCallReturn(c, *sig))
|
||||
return false;
|
||||
|
||||
uint32_t argsLength = args.length();
|
||||
AstCall* call = new(c.lifo) AstCall(Expr::CallImport, funcRef, Move(args));
|
||||
if (!call)
|
||||
return false;
|
||||
|
||||
c.iter().setResult(AstDecodeStackItem(call, args.length()));
|
||||
c.iter().setResult(AstDecodeStackItem(call, argsLength));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
AstDecodeGetBlockRef(AstDecodeContext& c, uint32_t depth, AstRef* ref)
|
||||
{
|
||||
if (!c.generateNames || depth >= c.blockLabels().length()) {
|
||||
// Also ignoring if it's a function body label.
|
||||
*ref = AstRef(AstName(), depth);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t index = c.blockLabels().length() - depth - 1;
|
||||
if (c.blockLabels()[index].empty()) {
|
||||
if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$label$"), 7), c.nextLabelIndex(), &c.blockLabels()[index]))
|
||||
return false;
|
||||
}
|
||||
*ref = AstRef(c.blockLabels()[index], AstNoIndex);
|
||||
ref->setIndex(depth);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -326,14 +358,18 @@ AstDecodeBrTable(AstDecodeContext& c)
|
|||
for (size_t i = 0, e = tableLength; i < e; ++i) {
|
||||
if (!c.iter().readBrTableEntry(type, &depth))
|
||||
return false;
|
||||
table[i] = AstRef(AstName(), depth);
|
||||
if (!AstDecodeGetBlockRef(c, depth, &table[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the default label.
|
||||
if (!c.iter().readBrTableEntry(type, &depth))
|
||||
return false;
|
||||
|
||||
AstRef def(AstName(), depth);
|
||||
AstRef def;
|
||||
if (!AstDecodeGetBlockRef(c, depth, &def))
|
||||
return false;
|
||||
|
||||
AstBranchTable* branchTable = new(c.lifo) AstBranchTable(*index.expr, def, Move(table), value.expr);
|
||||
if (!branchTable)
|
||||
return false;
|
||||
|
@ -348,9 +384,13 @@ AstDecodeBlock(AstDecodeContext& c, Expr expr)
|
|||
MOZ_ASSERT(expr == Expr::Block || expr == Expr::Loop);
|
||||
|
||||
if (expr == Expr::Loop) {
|
||||
if (!c.blockLabels().append(AstName()) || !c.blockLabels().append(AstName()))
|
||||
return false;
|
||||
if (!c.iter().readLoop())
|
||||
return false;
|
||||
} else {
|
||||
if (!c.blockLabels().append(AstName()))
|
||||
return false;
|
||||
if (!c.iter().readBlock())
|
||||
return false;
|
||||
}
|
||||
|
@ -369,7 +409,11 @@ AstDecodeBlock(AstDecodeContext& c, Expr expr)
|
|||
return false;
|
||||
}
|
||||
|
||||
AstBlock* block = new(c.lifo) AstBlock(expr, AstName(), AstName(), Move(exprs));
|
||||
AstName continueName;
|
||||
if (expr == Expr::Loop)
|
||||
continueName = c.blockLabels().popCopy();
|
||||
AstName breakName = c.blockLabels().popCopy();
|
||||
AstBlock* block = new(c.lifo) AstBlock(expr, breakName, continueName, Move(exprs));
|
||||
if (!block)
|
||||
return false;
|
||||
|
||||
|
@ -386,6 +430,8 @@ AstDecodeIf(AstDecodeContext& c)
|
|||
|
||||
bool hasElse = false;
|
||||
|
||||
if (!c.blockLabels().append(AstName()))
|
||||
return false;
|
||||
AstExprVector thenExprs(c.lifo);
|
||||
while (true) {
|
||||
if (!AstDecodeExpr(c))
|
||||
|
@ -401,9 +447,13 @@ AstDecodeIf(AstDecodeContext& c)
|
|||
if (!thenExprs.append(item.expr))
|
||||
return false;
|
||||
}
|
||||
AstName thenName = c.blockLabels().popCopy();
|
||||
|
||||
AstName elseName;
|
||||
AstExprVector elseExprs(c.lifo);
|
||||
if (hasElse) {
|
||||
if (!c.blockLabels().append(AstName()))
|
||||
return false;
|
||||
while (true) {
|
||||
if (!AstDecodeExpr(c))
|
||||
return false;
|
||||
|
@ -416,9 +466,10 @@ AstDecodeIf(AstDecodeContext& c)
|
|||
if (!elseExprs.append(item.expr))
|
||||
return false;
|
||||
}
|
||||
elseName = c.blockLabels().popCopy();
|
||||
}
|
||||
|
||||
AstIf* if_ = new(c.lifo) AstIf(cond.expr, AstName(), Move(thenExprs), AstName(), Move(elseExprs));
|
||||
AstIf* if_ = new(c.lifo) AstIf(cond.expr, thenName, Move(thenExprs), elseName, Move(elseExprs));
|
||||
if (!if_)
|
||||
return false;
|
||||
|
||||
|
@ -590,7 +641,10 @@ AstDecodeBranch(AstDecodeContext& c, Expr expr)
|
|||
popped = value.expr ? 2 : 1;
|
||||
}
|
||||
|
||||
AstRef depthRef(AstName(), depth);
|
||||
AstRef depthRef;
|
||||
if (!AstDecodeGetBlockRef(c, depth, &depthRef))
|
||||
return false;
|
||||
|
||||
AstBranch* branch = new(c.lifo) AstBranch(expr, cond.expr, depthRef, value.expr);
|
||||
if (!branch)
|
||||
return false;
|
||||
|
@ -1187,7 +1241,7 @@ AstDecodeMemorySection(AstDecodeContext& c)
|
|||
if (!c.d.readVarU32(&initialSizePages))
|
||||
return AstDecodeFail(c, "expected initial memory size");
|
||||
|
||||
CheckedInt<int32_t> initialSize = initialSizePages;
|
||||
CheckedInt<uint32_t> initialSize = initialSizePages;
|
||||
initialSize *= PageSize;
|
||||
if (!initialSize.isValid())
|
||||
return AstDecodeFail(c, "initial memory size too big");
|
||||
|
@ -1196,10 +1250,10 @@ AstDecodeMemorySection(AstDecodeContext& c)
|
|||
if (!c.d.readVarU32(&maxSizePages))
|
||||
return AstDecodeFail(c, "expected initial memory size");
|
||||
|
||||
CheckedInt<int32_t> maxSize = maxSizePages;
|
||||
CheckedInt<uint32_t> maxSize = maxSizePages;
|
||||
maxSize *= PageSize;
|
||||
if (!maxSize.isValid())
|
||||
return AstDecodeFail(c, "initial memory size too big");
|
||||
return AstDecodeFail(c, "maximum memory size too big");
|
||||
|
||||
uint8_t exported;
|
||||
if (!c.d.readFixedU8(&exported))
|
||||
|
@ -1304,6 +1358,10 @@ AstDecodeFunctionBody(AstDecodeContext &c, uint32_t funcIndex, AstFunc** func)
|
|||
|
||||
c.startFunction(&iter, &locals);
|
||||
|
||||
AstName funcName;
|
||||
if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$func$"), 6), funcIndex, &funcName))
|
||||
return false;
|
||||
|
||||
uint32_t numParams = sig->args().length();
|
||||
uint32_t numLocals = locals.length();
|
||||
for (uint32_t i = numParams; i < numLocals; i++) {
|
||||
|
@ -1339,10 +1397,6 @@ AstDecodeFunctionBody(AstDecodeContext &c, uint32_t funcIndex, AstFunc** func)
|
|||
if (c.d.currentPosition() != bodyEnd)
|
||||
return AstDecodeFail(c, "function body length mismatch");
|
||||
|
||||
AstName funcName;
|
||||
if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$func$"), 6), funcIndex, &funcName))
|
||||
return false;
|
||||
|
||||
AstRef sigRef;
|
||||
if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$type$"), 6), sigIndex, &sigRef))
|
||||
return false;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef wasm_binary_to_experimental_text_h
|
||||
#define wasm_binary_to_experimental_text_h
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
#include "gc/Rooting.h"
|
||||
#include "js/Class.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class StringBuffer;
|
||||
|
||||
namespace wasm {
|
||||
|
||||
struct ExperimentalTextFormatting
|
||||
{
|
||||
bool allowAsciiOperators:1;
|
||||
bool reduceParens:1;
|
||||
bool groupBlocks:1;
|
||||
|
||||
ExperimentalTextFormatting()
|
||||
: allowAsciiOperators(true),
|
||||
reduceParens(true),
|
||||
groupBlocks(true)
|
||||
{}
|
||||
};
|
||||
|
||||
// Translate the given binary representation of a wasm module into the module's textual
|
||||
// representation.
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
BinaryToExperimentalText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer,
|
||||
const ExperimentalTextFormatting& formatting);
|
||||
|
||||
} // namespace wasm
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // namespace wasm_binary_to_experimental_text_h
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
#include "asmjs/WasmBinaryToText.h"
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
||||
#include "jsnum.h"
|
||||
#include "jsprf.h"
|
||||
|
||||
|
@ -33,7 +31,6 @@
|
|||
using namespace js;
|
||||
using namespace js::wasm;
|
||||
|
||||
using mozilla::CheckedInt;
|
||||
using mozilla::IsInfinite;
|
||||
using mozilla::IsNaN;
|
||||
using mozilla::IsNegativeZero;
|
||||
|
@ -45,11 +42,6 @@ struct WasmRenderContext
|
|||
StringBuffer& buffer;
|
||||
uint32_t indent;
|
||||
|
||||
DeclaredSigVector signatures;
|
||||
Uint32Vector funcSigs;
|
||||
Uint32Vector funcLocals;
|
||||
Uint32Vector importSigs;
|
||||
|
||||
uint32_t currentFuncIndex;
|
||||
|
||||
WasmRenderContext(JSContext* cx, AstModule* module, StringBuffer& buffer)
|
||||
|
@ -298,6 +290,10 @@ RenderCallIndirect(WasmRenderContext& c, AstCallIndirect& call)
|
|||
return false;
|
||||
if (!RenderCallArgs(c, call.args()))
|
||||
return false;
|
||||
|
||||
if (!c.buffer.append(")"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -385,9 +381,25 @@ RenderBlock(WasmRenderContext& c, AstBlock& block)
|
|||
if (block.expr() == Expr::Block) {
|
||||
if (!c.buffer.append("(block "))
|
||||
return false;
|
||||
if (!RenderName(c, block.breakName()))
|
||||
return false;
|
||||
} else if (block.expr() == Expr::Loop) {
|
||||
if (!c.buffer.append("(loop "))
|
||||
return false;
|
||||
if (block.breakName().empty() && !block.continueName().empty()) {
|
||||
// Giving auto label if continue label is present.
|
||||
if (!c.buffer.append("$exit$"))
|
||||
return false;
|
||||
} else {
|
||||
if (!RenderName(c, block.breakName()))
|
||||
return false;
|
||||
}
|
||||
if (!block.continueName().empty()) {
|
||||
if (!c.buffer.append(" "))
|
||||
return false;
|
||||
if (!RenderName(c, block.continueName()))
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
|
||||
|
@ -655,6 +667,9 @@ RenderIf(WasmRenderContext& c, AstIf& if_)
|
|||
if (!c.buffer.append(" (then "))
|
||||
return false;
|
||||
|
||||
if (!RenderName(c, if_.thenName()))
|
||||
return false;
|
||||
|
||||
c.indent++;
|
||||
if (!RenderExprList(c, if_.thenExprs()))
|
||||
return false;
|
||||
|
@ -664,6 +679,9 @@ RenderIf(WasmRenderContext& c, AstIf& if_)
|
|||
if (!c.buffer.append(") (else "))
|
||||
return false;
|
||||
|
||||
if (!RenderName(c, if_.elseName()))
|
||||
return false;
|
||||
|
||||
c.indent++;
|
||||
if (!RenderExprList(c, if_.elseExprs()))
|
||||
return false;
|
||||
|
@ -1068,10 +1086,15 @@ RenderTableSection(WasmRenderContext& c, AstTable* maybeTable, const AstModule::
|
|||
|
||||
uint32_t numTableElems = maybeTable->elems().length();
|
||||
|
||||
if (!c.buffer.append("(table "))
|
||||
if (!RenderIndent(c))
|
||||
return false;
|
||||
|
||||
if (!c.buffer.append("(table"))
|
||||
return false;
|
||||
|
||||
for (uint32_t i = 0; i < numTableElems; i++) {
|
||||
if (!c.buffer.append(" "))
|
||||
return false;
|
||||
AstRef& elem = maybeTable->elems()[i];
|
||||
AstFunc* func = funcs[elem.index()];
|
||||
if (func->name().empty()) {
|
||||
|
@ -1083,7 +1106,7 @@ RenderTableSection(WasmRenderContext& c, AstTable* maybeTable, const AstModule::
|
|||
}
|
||||
}
|
||||
|
||||
if (!c.buffer.append(")"))
|
||||
if (!c.buffer.append(")\n"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "jsprf.h"
|
||||
|
||||
#include "asmjs/WasmBinaryToExperimentalText.h"
|
||||
#include "asmjs/WasmBinaryToText.h"
|
||||
#include "asmjs/WasmSerialize.h"
|
||||
#include "builtin/AtomicsObject.h"
|
||||
|
@ -1673,7 +1674,7 @@ Module::createText(JSContext* cx)
|
|||
if (!source_.empty()) {
|
||||
if (!buffer.append(experimentalWarning))
|
||||
return nullptr;
|
||||
if (!BinaryToText(cx, source_.begin(), source_.length(), buffer))
|
||||
if (!BinaryToExperimentalText(cx, source_.begin(), source_.length(), buffer, ExperimentalTextFormatting()))
|
||||
return nullptr;
|
||||
} else {
|
||||
if (!buffer.append(enabledMessage))
|
||||
|
|
|
@ -467,8 +467,8 @@ class Module : public mozilla::LinkedListElement<Module>
|
|||
struct ImportExit {
|
||||
void* code;
|
||||
jit::BaselineScript* baselineScript;
|
||||
HeapPtrFunction fun;
|
||||
static_assert(sizeof(HeapPtrFunction) == sizeof(void*), "for JIT access");
|
||||
GCPtrFunction fun;
|
||||
static_assert(sizeof(GCPtrFunction) == sizeof(void*), "for JIT access");
|
||||
};
|
||||
struct EntryArg {
|
||||
uint64_t lo;
|
||||
|
@ -485,8 +485,8 @@ class Module : public mozilla::LinkedListElement<Module>
|
|||
};
|
||||
typedef Vector<FuncPtrTable, 0, SystemAllocPolicy> FuncPtrTableVector;
|
||||
typedef Vector<CacheableChars, 0, SystemAllocPolicy> FuncLabelVector;
|
||||
typedef RelocatablePtrArrayBufferObjectMaybeShared BufferPtr;
|
||||
typedef HeapPtr<WasmModuleObject*> ModuleObjectPtr;
|
||||
typedef HeapPtr<ArrayBufferObjectMaybeShared*> BufferPtr;
|
||||
typedef GCPtr<WasmModuleObject*> ModuleObjectPtr;
|
||||
|
||||
// Initialized when constructed:
|
||||
const UniqueConstModuleData module_;
|
||||
|
@ -538,7 +538,7 @@ class Module : public mozilla::LinkedListElement<Module>
|
|||
virtual void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
|
||||
|
||||
void setOwner(WasmModuleObject* owner) { MOZ_ASSERT(!ownerObject_); ownerObject_ = owner; }
|
||||
inline const HeapPtr<WasmModuleObject*>& owner() const;
|
||||
inline const GCPtr<WasmModuleObject*>& owner() const;
|
||||
|
||||
void setSource(Bytes&& source) { source_ = Move(source); }
|
||||
|
||||
|
@ -688,7 +688,7 @@ class WasmModuleObject : public NativeObject
|
|||
static const Class class_;
|
||||
};
|
||||
|
||||
inline const HeapPtr<WasmModuleObject*>&
|
||||
inline const GCPtr<WasmModuleObject*>&
|
||||
wasm::Module::owner() const {
|
||||
MOZ_ASSERT(&ownerObject_->module() == this);
|
||||
return ownerObject_;
|
||||
|
|
|
@ -293,14 +293,20 @@ EvalKernel(JSContext* cx, HandleValue v, EvalType evalType, AbstractFramePtr cal
|
|||
return false;
|
||||
|
||||
CompileOptions options(cx);
|
||||
options.setFileAndLine(filename, 1)
|
||||
.setIsRunOnce(true)
|
||||
options.setIsRunOnce(true)
|
||||
.setForEval(true)
|
||||
.setNoScriptRval(false)
|
||||
.setMutedErrors(mutedErrors)
|
||||
.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset)
|
||||
.maybeMakeStrictMode(evalType == DIRECT_EVAL && IsStrictEvalPC(pc));
|
||||
|
||||
if (introducerFilename) {
|
||||
options.setFileAndLine(filename, 1);
|
||||
options.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);
|
||||
} else {
|
||||
options.setFileAndLine("eval", 1);
|
||||
options.setIntroductionType("eval");
|
||||
}
|
||||
|
||||
AutoStableStringChars linearChars(cx);
|
||||
if (!linearChars.initTwoByte(cx, linearStr))
|
||||
return false;
|
||||
|
@ -375,14 +381,20 @@ js::DirectEvalStringFromIon(JSContext* cx,
|
|||
return false;
|
||||
|
||||
CompileOptions options(cx);
|
||||
options.setFileAndLine(filename, 1)
|
||||
.setIsRunOnce(true)
|
||||
options.setIsRunOnce(true)
|
||||
.setForEval(true)
|
||||
.setNoScriptRval(false)
|
||||
.setMutedErrors(mutedErrors)
|
||||
.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset)
|
||||
.maybeMakeStrictMode(IsStrictEvalPC(pc));
|
||||
|
||||
if (introducerFilename) {
|
||||
options.setFileAndLine(filename, 1);
|
||||
options.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);
|
||||
} else {
|
||||
options.setFileAndLine("eval", 1);
|
||||
options.setIntroductionType("eval");
|
||||
}
|
||||
|
||||
AutoStableStringChars linearChars(cx);
|
||||
if (!linearChars.initTwoByte(cx, linearStr))
|
||||
return false;
|
||||
|
|
|
@ -438,7 +438,7 @@ MapObject::set(JSContext* cx, HandleObject obj, HandleValue k, HandleValue v)
|
|||
if (!key.setValue(cx, k))
|
||||
return false;
|
||||
|
||||
RelocatableValue rval(v);
|
||||
HeapPtr<Value> rval(v);
|
||||
if (!map->put(key, rval)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
|
@ -538,7 +538,7 @@ MapObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!hkey.setValue(cx, key))
|
||||
return false;
|
||||
|
||||
RelocatableValue rval(val);
|
||||
HeapPtr<Value> rval(val);
|
||||
if (!map->put(hkey, rval)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
|
@ -688,7 +688,7 @@ MapObject::set_impl(JSContext* cx, const CallArgs& args)
|
|||
|
||||
ValueMap& map = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
RelocatableValue rval(args.get(1));
|
||||
HeapPtr<Value> rval(args.get(1));
|
||||
if (!map.put(key, rval)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
|
@ -725,14 +725,14 @@ bool
|
|||
MapObject::delete_impl(JSContext *cx, const CallArgs& args)
|
||||
{
|
||||
// MapObject::mark does not mark deleted entries. Incremental GC therefore
|
||||
// requires that no RelocatableValue objects pointing to heap values be
|
||||
// left alive in the ValueMap.
|
||||
// requires that no HeapPtr<Value> objects pointing to heap values be left
|
||||
// alive in the ValueMap.
|
||||
//
|
||||
// OrderedHashMap::remove() doesn't destroy the removed entry. It merely
|
||||
// calls OrderedHashMap::MapOps::makeEmpty. But that is sufficient, because
|
||||
// makeEmpty clears the value by doing e->value = Value(), and in the case
|
||||
// of a ValueMap, Value() means RelocatableValue(), which is the same as
|
||||
// RelocatableValue(UndefinedValue()).
|
||||
// of a ValueMap, Value() means HeapPtr<Value>(), which is the same as
|
||||
// HeapPtr<Value>(UndefinedValue()).
|
||||
MOZ_ASSERT(MapObject::is(args.thisv()));
|
||||
|
||||
ValueMap& map = extract(args);
|
||||
|
|
|
@ -66,7 +66,7 @@ template <class T, class OrderedHashPolicy, class AllocPolicy>
|
|||
class OrderedHashSet;
|
||||
|
||||
typedef OrderedHashMap<HashableValue,
|
||||
RelocatableValue,
|
||||
HeapPtr<Value>,
|
||||
HashableValue::Hasher,
|
||||
RuntimeAllocPolicy> ValueMap;
|
||||
|
||||
|
|
|
@ -118,8 +118,8 @@ class IndirectBindingMap
|
|||
struct Binding
|
||||
{
|
||||
Binding(ModuleEnvironmentObject* environment, Shape* shape);
|
||||
RelocatablePtr<ModuleEnvironmentObject*> environment;
|
||||
RelocatablePtrShape shape;
|
||||
HeapPtr<ModuleEnvironmentObject*> environment;
|
||||
HeapPtr<Shape*> shape;
|
||||
};
|
||||
|
||||
typedef HashMap<jsid, Binding, DefaultHasher<jsid>, ZoneAllocPolicy> Map;
|
||||
|
@ -194,8 +194,8 @@ struct FunctionDeclaration
|
|||
FunctionDeclaration(HandleAtom name, HandleFunction fun);
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
RelocatablePtrAtom name;
|
||||
RelocatablePtrFunction fun;
|
||||
HeapPtr<JSAtom*> name;
|
||||
HeapPtr<JSFunction*> fun;
|
||||
};
|
||||
|
||||
using FunctionDeclarationVector = GCVector<FunctionDeclaration, 0, ZoneAllocPolicy>;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче