зеркало из https://github.com/mozilla/gecko-dev.git
merge autoland to mozilla-central a=merge
This commit is contained in:
Коммит
d2c3fe7fd3
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1288460 requires another clobber due to bug 1298779.
|
||||
Bug 1302429 to fix also bustage.
|
||||
|
|
|
@ -1507,3 +1507,14 @@ pref("print.use_simplify_page", true);
|
|||
// Space separated list of URLS that are allowed to send objects (instead of
|
||||
// only strings) through webchannels. This list is duplicated in mobile/android/app/mobile.js
|
||||
pref("webchannel.allowObject.urlWhitelist", "https://accounts.firefox.com https://content.cdn.mozilla.net https://input.mozilla.org https://support.mozilla.org https://install.mozilla.org");
|
||||
|
||||
// Whether or not the browser should scan for unsubmitted
|
||||
// crash reports, and then show a notification for submitting
|
||||
// those reports.
|
||||
#ifdef RELEASE_BUILD
|
||||
pref("browser.crashReports.unsubmittedCheck.enabled", false);
|
||||
#else
|
||||
pref("browser.crashReports.unsubmittedCheck.enabled", true);
|
||||
#endif
|
||||
|
||||
pref("browser.crashReports.unsubmittedCheck.autoSubmit", false);
|
|
@ -777,13 +777,6 @@ html|*#fullscreen-exit-button {
|
|||
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#click-to-play-plugins-notification");
|
||||
}
|
||||
|
||||
#login-fill-notification {
|
||||
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#login-fill-notification");
|
||||
}
|
||||
|
||||
.login-fill-item {
|
||||
-moz-binding: url("chrome://passwordmgr/content/login.xml#login");
|
||||
}
|
||||
|
||||
.plugin-popupnotification-centeritem {
|
||||
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#plugin-popupnotification-center-item");
|
||||
|
@ -1185,10 +1178,6 @@ toolbarpaletteitem[place="palette"][hidden] {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#login-fill-doorhanger:not([inDetailView]) > #login-fill-clickcapturer {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.popup-notification-invalid-input {
|
||||
box-shadow: 0 0 1.5px 1px red;
|
||||
}
|
||||
|
|
|
@ -718,8 +718,6 @@
|
|||
tooltiptext="&urlbar.addonsNotificationAnchor.tooltip;"/>
|
||||
<image id="indexedDB-notification-icon" class="notification-anchor-icon indexedDB-icon" role="button"
|
||||
tooltiptext="&urlbar.indexedDBNotificationAnchor.tooltip;"/>
|
||||
<image id="login-fill-notification-icon" class="notification-anchor-icon login-icon" role="button"
|
||||
tooltiptext="&urlbar.loginFillNotificationAnchor.tooltip;"/>
|
||||
<image id="password-notification-icon" class="notification-anchor-icon login-icon" role="button"
|
||||
tooltiptext="&urlbar.passwordNotificationAnchor.tooltip;"/>
|
||||
<image id="plugins-notification-icon" class="notification-anchor-icon plugin-icon" role="button"
|
||||
|
|
|
@ -52,22 +52,6 @@
|
|||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
|
||||
<stack id="login-fill-doorhanger" hidden="true">
|
||||
<vbox id="login-fill-mainview">
|
||||
<description id="login-fill-testing"
|
||||
value="Thanks for testing the login fill doorhanger!"/>
|
||||
<textbox id="login-fill-filter"/>
|
||||
<richlistbox id="login-fill-list"/>
|
||||
</vbox>
|
||||
<vbox id="login-fill-clickcapturer"/>
|
||||
<vbox id="login-fill-details">
|
||||
<textbox id="login-fill-username" readonly="true"/>
|
||||
<textbox id="login-fill-password" type="password" disabled="true"/>
|
||||
<hbox>
|
||||
<button id="login-fill-use" label="Use in form"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</stack>
|
||||
|
||||
<popupnotification id="addon-progress-notification" hidden="true">
|
||||
<popupnotificationcontent orient="vertical">
|
||||
|
|
|
@ -2478,16 +2478,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
</handlers>
|
||||
</binding>
|
||||
|
||||
<!-- This is the XBL notification definition for the login fill doorhanger,
|
||||
which is empty because the actual panel is not implemented inside an XBL
|
||||
binding, but made of elements added to the notification panel. This
|
||||
allows accessing the full structure while the panel is hidden. -->
|
||||
<binding id="login-fill-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
|
||||
<content>
|
||||
<children/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="splitmenu">
|
||||
<content>
|
||||
<xul:hbox anonid="menuitem" flex="1"
|
||||
|
|
|
@ -71,6 +71,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", "@mozilla.org/alerts-s
|
|||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter",
|
||||
"resource:///modules/ContentCrashHandlers.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UnsubmittedCrashHandler",
|
||||
"resource:///modules/ContentCrashHandlers.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
|
||||
"resource://gre/modules/CrashSubmit.jsm");
|
||||
}
|
||||
|
@ -714,6 +716,7 @@ BrowserGlue.prototype = {
|
|||
TabCrashHandler.init();
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
PluginCrashReporter.init();
|
||||
UnsubmittedCrashHandler.init();
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
|
||||
|
@ -744,64 +747,6 @@ BrowserGlue.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
checkForPendingCrashReports: function() {
|
||||
// We don't process crash reports older than 28 days, so don't bother submitting them
|
||||
const PENDING_CRASH_REPORT_DAYS = 28;
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
let dateLimit = new Date();
|
||||
dateLimit.setDate(dateLimit.getDate() - PENDING_CRASH_REPORT_DAYS);
|
||||
CrashSubmit.pendingIDsAsync(dateLimit).then(
|
||||
function onSuccess(ids) {
|
||||
let count = ids.length;
|
||||
if (count) {
|
||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
let nb = win.document.getElementById("global-notificationbox");
|
||||
let notification = nb.getNotificationWithValue("pending-crash-reports");
|
||||
if (notification) {
|
||||
return;
|
||||
}
|
||||
let buttons = [
|
||||
{
|
||||
label: win.gNavigatorBundle.getString("pendingCrashReports.submitAll"),
|
||||
callback: function() {
|
||||
ids.forEach(function(id) {
|
||||
CrashSubmit.submit(id, {extraExtraKeyVals: {"SubmittedFromInfobar": true}});
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
label: win.gNavigatorBundle.getString("pendingCrashReports.ignoreAll"),
|
||||
callback: function() {
|
||||
ids.forEach(function(id) {
|
||||
CrashSubmit.ignore(id);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
label: win.gNavigatorBundle.getString("pendingCrashReports.viewAll"),
|
||||
callback: function() {
|
||||
win.openUILinkIn("about:crashes", "tab");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
];
|
||||
nb.appendNotification(PluralForm.get(count,
|
||||
win.gNavigatorBundle.getString("pendingCrashReports.label")).replace("#1", count),
|
||||
"pending-crash-reports",
|
||||
"chrome://browser/skin/tab-crashed.svg",
|
||||
nb.PRIORITY_INFO_HIGH, buttons);
|
||||
}
|
||||
},
|
||||
function onError(err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
_onSafeModeRestart: function BG_onSafeModeRestart() {
|
||||
// prompt the user to confirm
|
||||
let strings = gBrowserBundle;
|
||||
|
@ -1070,10 +1015,6 @@ BrowserGlue.prototype = {
|
|||
|
||||
this._checkForOldBuildUpdates();
|
||||
|
||||
if (!AppConstants.RELEASE_BUILD) {
|
||||
this.checkForPendingCrashReports();
|
||||
}
|
||||
|
||||
CaptivePortalWatcher.init();
|
||||
|
||||
AutoCompletePopup.init();
|
||||
|
|
|
@ -60,10 +60,7 @@ var gAdvancedPane = {
|
|||
setEventListener("submitHealthReportBox", "command",
|
||||
gAdvancedPane.updateSubmitHealthReport);
|
||||
}
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
setEventListener("submitCrashesBox", "command",
|
||||
gAdvancedPane.updateSubmitCrashes);
|
||||
}
|
||||
|
||||
setEventListener("connectionSettings", "command",
|
||||
gAdvancedPane.showConnections);
|
||||
setEventListener("clearCacheButton", "command",
|
||||
|
@ -243,28 +240,6 @@ var gAdvancedPane = {
|
|||
{
|
||||
this._setupLearnMoreLink("toolkit.crashreporter.infoURL",
|
||||
"crashReporterLearnMore");
|
||||
|
||||
var checkbox = document.getElementById("submitCrashesBox");
|
||||
try {
|
||||
var cr = Components.classes["@mozilla.org/toolkit/crash-reporter;1"].
|
||||
getService(Components.interfaces.nsICrashReporter);
|
||||
checkbox.checked = cr.submitReports;
|
||||
} catch (e) {
|
||||
checkbox.style.display = "none";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
updateSubmitCrashes: function ()
|
||||
{
|
||||
var checkbox = document.getElementById("submitCrashesBox");
|
||||
try {
|
||||
var cr = Components.classes["@mozilla.org/toolkit/crash-reporter;1"].
|
||||
getService(Components.interfaces.nsICrashReporter);
|
||||
cr.submitReports = checkbox.checked;
|
||||
} catch (e) { }
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,6 +54,13 @@
|
|||
type="bool"/>
|
||||
#endif
|
||||
|
||||
<!-- Data Choices tab -->
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
<preference id="browser.crashReports.unsubmittedCheck.autoSubmit"
|
||||
name="browser.crashReports.unsubmittedCheck.autoSubmit"
|
||||
type="bool"/>
|
||||
#endif
|
||||
|
||||
<!-- Network tab -->
|
||||
<preference id="browser.cache.disk.capacity"
|
||||
name="browser.cache.disk.capacity"
|
||||
|
@ -229,11 +236,13 @@
|
|||
#ifdef MOZ_CRASHREPORTER
|
||||
<groupbox>
|
||||
<caption>
|
||||
<checkbox id="submitCrashesBox" label="&enableCrashReporter.label;"
|
||||
accesskey="&enableCrashReporter.accesskey;"/>
|
||||
<checkbox id="automaticallySubmitCrashesBox"
|
||||
preference="browser.crashReports.unsubmittedCheck.autoSubmit"
|
||||
label="&alwaysSubmitCrashReports.label;"
|
||||
accesskey="&alwaysSubmitCrashReports.accesskey;"/>
|
||||
</caption>
|
||||
<hbox class="indent">
|
||||
<label flex="1">&crashReporterDesc.label;</label>
|
||||
<label flex="1">&crashReporterDesc2.label;</label>
|
||||
<spacer flex="10"/>
|
||||
<label id="crashReporterLearnMore"
|
||||
class="text-link">&crashReporterLearnMore.label;</label>
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "Visual Studio 2015 Update 2 / SDK 10.0.10586.0/212",
|
||||
"size": 332442800,
|
||||
"digest": "995394a4a515c7cb0f8595f26f5395361a638870dd0bbfcc22193fe1d98a0c47126057d5999cc494f3f3eac5cb49160e79757c468f83ee5797298e286ef6252c",
|
||||
"version": "Visual Studio 2015 Update 3 14.0.25425.01 / SDK 10.0.14393.0",
|
||||
"size": 326656969,
|
||||
"digest": "babc414ffc0457d27f5a1ed24a8e4873afbe2f1c1a4075469a27c005e1babc3b2a788f643f825efedff95b79686664c67ec4340ed535487168a3482e68559bc7",
|
||||
"algorithm": "sha512",
|
||||
"filename": "vs2015u2.zip",
|
||||
"filename": "vs2015u3.zip",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
|
|
@ -30,11 +30,11 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "Visual Studio 2015 Update 2 / SDK 10.0.10586.0/212",
|
||||
"size": 332442800,
|
||||
"digest": "995394a4a515c7cb0f8595f26f5395361a638870dd0bbfcc22193fe1d98a0c47126057d5999cc494f3f3eac5cb49160e79757c468f83ee5797298e286ef6252c",
|
||||
"version": "Visual Studio 2015 Update 3 14.0.25425.01 / SDK 10.0.14393.0",
|
||||
"size": 326656969,
|
||||
"digest": "babc414ffc0457d27f5a1ed24a8e4873afbe2f1c1a4075469a27c005e1babc3b2a788f643f825efedff95b79686664c67ec4340ed535487168a3482e68559bc7",
|
||||
"algorithm": "sha512",
|
||||
"filename": "vs2015u2.zip",
|
||||
"filename": "vs2015u3.zip",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
|
|
@ -211,7 +211,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
|||
<!ENTITY urlbar.geolocationNotificationAnchor.tooltip "Open location request panel">
|
||||
<!ENTITY urlbar.addonsNotificationAnchor.tooltip "Open add-on installation message panel">
|
||||
<!ENTITY urlbar.indexedDBNotificationAnchor.tooltip "Open offline storage message panel">
|
||||
<!ENTITY urlbar.loginFillNotificationAnchor.tooltip "Manage your login information">
|
||||
<!ENTITY urlbar.passwordNotificationAnchor.tooltip "Open save password message panel">
|
||||
<!ENTITY urlbar.pluginsNotificationAnchor.tooltip "Manage plug-in use">
|
||||
<!ENTITY urlbar.webNotificationAnchor.tooltip "Change whether you can receive notifications from the site">
|
||||
|
|
|
@ -730,10 +730,10 @@ tabgroups.migration.tabGroupBookmarkFolderName = Bookmarked Tab Groups
|
|||
# LOCALIZATION NOTE (pendingCrashReports.label): Semi-colon list of plural forms
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 is the number of pending crash reports
|
||||
pendingCrashReports.label = You have an unsubmitted crash report;You have #1 unsubmitted crash reports
|
||||
pendingCrashReports2.label = You have an unsent crash report;You have #1 unsent crash reports
|
||||
pendingCrashReports.viewAll = View
|
||||
pendingCrashReports.submitAll = Submit
|
||||
pendingCrashReports.ignoreAll = Ignore
|
||||
pendingCrashReports.send = Send
|
||||
pendingCrashReports.alwaysSend = Always Send
|
||||
|
||||
decoder.noCodecs.button = Learn how
|
||||
decoder.noCodecs.accesskey = L
|
||||
|
|
|
@ -40,9 +40,9 @@
|
|||
<!ENTITY enableTelemetryData.accesskey "T">
|
||||
<!ENTITY telemetryLearnMore.label "Learn More">
|
||||
|
||||
<!ENTITY crashReporterDesc.label "&brandShortName; submits crash reports to help &vendorShortName; make your browser more stable and secure">
|
||||
<!ENTITY enableCrashReporter.label "Enable Crash Reporter">
|
||||
<!ENTITY enableCrashReporter.accesskey "C">
|
||||
<!ENTITY crashReporterDesc2.label "Crash reports help &vendorShortName; fix problems and make your browser more stable and secure">
|
||||
<!ENTITY alwaysSubmitCrashReports.label "Allow &brandShortName; to send backlogged crash reports on your behalf">
|
||||
<!ENTITY alwaysSubmitCrashReports.accesskey "c">
|
||||
<!ENTITY crashReporterLearnMore.label "Learn More">
|
||||
|
||||
<!ENTITY networkTab.label "Network">
|
||||
|
|
|
@ -8,7 +8,9 @@ var Cc = Components.classes;
|
|||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "TabCrashHandler", "PluginCrashReporter" ];
|
||||
this.EXPORTED_SYMBOLS = [ "TabCrashHandler",
|
||||
"PluginCrashReporter",
|
||||
"UnsubmittedCrashHandler" ];
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
@ -21,6 +23,21 @@ XPCOMUtils.defineLazyModuleGetter(this, "RemotePages",
|
|||
"resource://gre/modules/RemotePageManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
|
||||
"resource:///modules/sessionstore/SessionStore.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
|
||||
"resource:///modules/RecentWindow.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gNavigatorBundle", function() {
|
||||
const url = "chrome://browser/locale/browser.properties";
|
||||
return Services.strings.createBundle(url);
|
||||
});
|
||||
|
||||
// We don't process crash reports older than 28 days, so don't bother
|
||||
// submitting them
|
||||
const PENDING_CRASH_REPORT_DAYS = 28;
|
||||
|
||||
this.TabCrashHandler = {
|
||||
_crashedTabCount: 0,
|
||||
|
@ -319,6 +336,204 @@ this.TabCrashHandler = {
|
|||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* This component is responsible for scanning the pending
|
||||
* crash report directory for reports, and (if enabled), to
|
||||
* prompt the user to submit those reports. It might also
|
||||
* submit those reports automatically without prompting if
|
||||
* the user has opted in.
|
||||
*/
|
||||
this.UnsubmittedCrashHandler = {
|
||||
init() {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
let pref = "browser.crashReports.unsubmittedCheck.enabled";
|
||||
let shouldCheck = Services.prefs.getBoolPref(pref);
|
||||
|
||||
if (shouldCheck) {
|
||||
Services.obs.addObserver(this, "browser-delayed-startup-finished",
|
||||
false);
|
||||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (topic != "browser-delayed-startup-finished") {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(this, topic);
|
||||
this.checkForUnsubmittedCrashReports();
|
||||
},
|
||||
|
||||
/**
|
||||
* Scans the profile directory for unsubmitted crash reports
|
||||
* within the past PENDING_CRASH_REPORT_DAYS days. If it
|
||||
* finds any, it will, if necessary, attempt to open a notification
|
||||
* bar to prompt the user to submit them.
|
||||
*
|
||||
* @returns Promise
|
||||
* Resolves after it tries to append a notification on
|
||||
* the most recent browser window. If a notification
|
||||
* cannot be shown, will resolve anyways.
|
||||
*/
|
||||
checkForUnsubmittedCrashReports: Task.async(function*() {
|
||||
let dateLimit = new Date();
|
||||
dateLimit.setDate(dateLimit.getDate() - PENDING_CRASH_REPORT_DAYS);
|
||||
|
||||
let reportIDs = [];
|
||||
try {
|
||||
reportIDs = yield CrashSubmit.pendingIDsAsync(dateLimit);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (reportIDs.length) {
|
||||
if (CrashNotificationBar.autoSubmit) {
|
||||
CrashNotificationBar.submitReports(reportIDs);
|
||||
} else {
|
||||
this.showPendingSubmissionsNotification(reportIDs);
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Given an array of unsubmitted crash report IDs, try to open
|
||||
* up a notification asking the user to submit them.
|
||||
*
|
||||
* @param reportIDs (Array<string>)
|
||||
* The Array of report IDs to offer the user to send.
|
||||
*/
|
||||
showPendingSubmissionsNotification(reportIDs) {
|
||||
let count = reportIDs.length;
|
||||
if (!count) {
|
||||
return;
|
||||
}
|
||||
|
||||
let messageTemplate =
|
||||
gNavigatorBundle.GetStringFromName("pendingCrashReports2.label");
|
||||
|
||||
let message = PluralForm.get(count, messageTemplate).replace("#1", count);
|
||||
|
||||
CrashNotificationBar.show({
|
||||
notificationID: "pending-crash-reports",
|
||||
message,
|
||||
reportIDs,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
this.CrashNotificationBar = {
|
||||
/**
|
||||
* Attempts to show a notification bar to the user in the most
|
||||
* recent browser window asking them to submit some crash report
|
||||
* IDs. If a notification cannot be shown (for example, there
|
||||
* is no browser window), this method exits silently.
|
||||
*
|
||||
* The notification will allow the user to submit their crash
|
||||
* reports. If the user dismissed the notification, the crash
|
||||
* reports will be marked to be ignored (though they can
|
||||
* still be manually submitted via about:crashes).
|
||||
*
|
||||
* @param JS Object
|
||||
* An Object with the following properties:
|
||||
*
|
||||
* notificationID (string)
|
||||
* The ID for the notification to be opened.
|
||||
*
|
||||
* message (string)
|
||||
* The message to be displayed in the notification.
|
||||
*
|
||||
* reportIDs (Array<string>)
|
||||
* The array of report IDs to offer to the user.
|
||||
*/
|
||||
show({ notificationID, message, reportIDs }) {
|
||||
let chromeWin = RecentWindow.getMostRecentBrowserWindow();
|
||||
if (!chromeWin) {
|
||||
// Can't show a notification in this case. We'll hopefully
|
||||
// get another opportunity to have the user submit their
|
||||
// crash reports later.
|
||||
return;
|
||||
}
|
||||
|
||||
let nb = chromeWin.document.getElementById("global-notificationbox");
|
||||
let notification = nb.getNotificationWithValue(notificationID);
|
||||
if (notification) {
|
||||
return;
|
||||
}
|
||||
|
||||
let buttons = [{
|
||||
label: gNavigatorBundle.GetStringFromName("pendingCrashReports.send"),
|
||||
callback: () => {
|
||||
this.submitReports(reportIDs);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: gNavigatorBundle.GetStringFromName("pendingCrashReports.alwaysSend"),
|
||||
callback: () => {
|
||||
this.autoSubmit = true;
|
||||
this.submitReports(reportIDs);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: gNavigatorBundle.GetStringFromName("pendingCrashReports.viewAll"),
|
||||
callback: function() {
|
||||
chromeWin.openUILinkIn("about:crashes", "tab");
|
||||
return true;
|
||||
},
|
||||
}];
|
||||
|
||||
let eventCallback = (eventType) => {
|
||||
if (eventType == "dismissed") {
|
||||
// The user intentionally dismissed the notification,
|
||||
// which we interpret as meaning that they don't care
|
||||
// to submit the reports. We'll ignore these particular
|
||||
// reports going forward.
|
||||
reportIDs.forEach(function(reportID) {
|
||||
CrashSubmit.ignore(reportID);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
nb.appendNotification(message, notificationID,
|
||||
"chrome://browser/skin/tab-crashed.svg",
|
||||
nb.PRIORITY_INFO_HIGH, buttons,
|
||||
eventCallback);
|
||||
},
|
||||
|
||||
get autoSubmit() {
|
||||
return Services.prefs
|
||||
.getBoolPref("browser.crashReports.unsubmittedCheck.autoSubmit");
|
||||
},
|
||||
|
||||
set autoSubmit(val) {
|
||||
Services.prefs.setBoolPref("browser.crashReports.unsubmittedCheck.autoSubmit",
|
||||
val);
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempt to submit reports to the crash report server. Each
|
||||
* report will have the "SubmittedFromInfobar" extra key set
|
||||
* to true.
|
||||
*
|
||||
* @param reportIDs (Array<string>)
|
||||
* The array of reportIDs to submit.
|
||||
*/
|
||||
submitReports(reportIDs) {
|
||||
for (let reportID of reportIDs) {
|
||||
CrashSubmit.submit(reportID, {
|
||||
extraExtraKeyVals: {
|
||||
"SubmittedFromInfobar": true,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
this.PluginCrashReporter = {
|
||||
/**
|
||||
* Makes the PluginCrashReporter ready to hear about and
|
||||
|
|
|
@ -1745,7 +1745,6 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton:not(:h
|
|||
background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
|
||||
}
|
||||
|
||||
%include ../shared/login-doorhanger.inc.css
|
||||
|
||||
%include downloads/indicator.css
|
||||
|
||||
|
|
|
@ -3155,7 +3155,6 @@ menulist.translate-infobar-element > .menulist-dropmarker {
|
|||
%include ../../../devtools/client/themes/responsivedesign.inc.css
|
||||
%include ../../../devtools/client/themes/commandline.inc.css
|
||||
%include ../shared/plugin-doorhanger.inc.css
|
||||
%include ../shared/login-doorhanger.inc.css
|
||||
|
||||
%include downloads/indicator.css
|
||||
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
#notification-popup[popupid="login-fill"] > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
/* Since we display a sliding subview that extends to the border, we cannot
|
||||
* keep the default padding of arrow panels. We use the same padding in the
|
||||
* individual content views instead. Since we removed the padding, we also
|
||||
* have to ensure the contents are clipped to the border box. */
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#login-fill-mainview,
|
||||
#login-fill-details {
|
||||
padding: var(--panel-arrowcontent-padding);
|
||||
}
|
||||
|
||||
#login-fill-doorhanger[inDetailView] > #login-fill-mainview {
|
||||
transform: translateX(-14px);
|
||||
}
|
||||
|
||||
#login-fill-mainview,
|
||||
#login-fill-details {
|
||||
transition: transform 150ms;
|
||||
}
|
||||
|
||||
#login-fill-doorhanger:not([inDetailView]) > #login-fill-details {
|
||||
transform: translateX(105%);
|
||||
}
|
||||
|
||||
#login-fill-doorhanger:not([inDetailView]) > #login-fill-details:-moz-locale-dir(rtl) {
|
||||
transform: translateX(-105%);
|
||||
}
|
||||
|
||||
#login-fill-doorhanger[inDetailView] > #login-fill-clickcapturer {
|
||||
background-color: hsla(210,4%,10%,.1);
|
||||
}
|
||||
|
||||
#login-fill-testing {
|
||||
color: #b33;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#login-fill-list {
|
||||
border: 1px solid black;
|
||||
max-height: 20em;
|
||||
}
|
||||
|
||||
.login-fill-item[disabled] {
|
||||
color: #888;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.login-fill-item[disabled][selected] {
|
||||
background-color: #eef;
|
||||
}
|
||||
|
||||
.login-hostname {
|
||||
margin: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.login-fill-item.different-hostname > .login-hostname {
|
||||
color: #888;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.login-username {
|
||||
margin: 4px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
#login-fill-details {
|
||||
padding: 4px;
|
||||
background: var(--panel-arrowcontent-background);
|
||||
color: var(--panel-arrowcontent-color);
|
||||
background-clip: padding-box;
|
||||
border-left: 1px solid hsla(210,4%,10%,.3);
|
||||
box-shadow: 0 3px 5px hsla(210,4%,10%,.1),
|
||||
0 0 7px hsla(210,4%,10%,.1);
|
||||
margin-inline-start: 38px;
|
||||
}
|
|
@ -129,11 +129,6 @@
|
|||
list-style-image: url(chrome://browser/skin/notification-icons.svg#login-detailed);
|
||||
}
|
||||
|
||||
#login-fill-notification-icon {
|
||||
/* Temporary solution until the capture and fill doorhangers are unified. */
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.camera-icon,
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#camera);
|
||||
|
|
|
@ -2434,7 +2434,6 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton {
|
|||
}
|
||||
}
|
||||
|
||||
%include ../shared/login-doorhanger.inc.css
|
||||
|
||||
%include downloads/indicator.css
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ Once Visual Studio 2015 Community has been installed, from a checkout
|
|||
of mozilla-central, run something like the following to produce a ZIP
|
||||
archive::
|
||||
|
||||
$ ./mach python build/windows_toolchain.py create-zip vs2015u2
|
||||
$ ./mach python build/windows_toolchain.py create-zip vs2015u3
|
||||
|
||||
The produced archive will be the argument to ``create-zip`` + ``.zip``.
|
||||
|
||||
|
|
|
@ -274,9 +274,11 @@ def get_compiler_info(compiler, language):
|
|||
raise FatalCheckError(
|
||||
'Unknown compiler or compiler not supported.')
|
||||
|
||||
# Metadata emitted by preprocessors such as GCC with LANG=ja_JP.utf-8 may
|
||||
# have non-ASCII characters. Treat the output as bytearray.
|
||||
data = {}
|
||||
for line in result.splitlines():
|
||||
if line.startswith('%'):
|
||||
if line.startswith(b'%'):
|
||||
k, _, v = line.partition(' ')
|
||||
k = k.lstrip('%')
|
||||
data[k] = v.replace(' ', '').lstrip('"').rstrip('"')
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
if [ -z "${VSPATH}" ]; then
|
||||
TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
|
||||
VSPATH="$(cd ${TOOLTOOL_DIR} && pwd)/vs2015u2"
|
||||
VSPATH="$(cd ${TOOLTOOL_DIR} && pwd)/vs2015u3"
|
||||
fi
|
||||
|
||||
VSWINPATH="$(cd ${VSPATH} && pwd -W)"
|
||||
|
@ -12,8 +12,8 @@ export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x86"
|
|||
export PATH="${VSPATH}/VC/bin/amd64_x86:${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x86:${VSPATH}/SDK/bin/x64:${VSPATH}/DIA SDK/bin:${PATH}"
|
||||
export PATH="${VSPATH}/VC/redist/x86/Microsoft.VC140.CRT:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x86:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${PATH}"
|
||||
|
||||
export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.10586.0/ucrt:${VSPATH}/SDK/Include/10.0.10586.0/shared:${VSPATH}/SDK/Include/10.0.10586.0/um:${VSPATH}/SDK/Include/10.0.10586.0/winrt:${VSPATH}/DIA SDK/include"
|
||||
export LIB="${VSPATH}/VC/lib:${VSPATH}/VC/atlmfc/lib:${VSPATH}/SDK/lib/10.0.10586.0/ucrt/x86:${VSPATH}/SDK/lib/10.0.10586.0/um/x86:${VSPATH}/DIA SDK/lib"
|
||||
export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.14393.0/ucrt:${VSPATH}/SDK/Include/10.0.14393.0/shared:${VSPATH}/SDK/Include/10.0.14393.0/um:${VSPATH}/SDK/Include/10.0.14393.0/winrt:${VSPATH}/DIA SDK/include"
|
||||
export LIB="${VSPATH}/VC/lib:${VSPATH}/VC/atlmfc/lib:${VSPATH}/SDK/lib/10.0.14393.0/ucrt/x86:${VSPATH}/SDK/lib/10.0.14393.0/um/x86:${VSPATH}/DIA SDK/lib"
|
||||
|
||||
. $topsrcdir/build/mozconfig.vs-common
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
if [ -z "${VSPATH}" ]; then
|
||||
TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
|
||||
VSPATH="$(cd ${TOOLTOOL_DIR} && pwd)/vs2015u2"
|
||||
VSPATH="$(cd ${TOOLTOOL_DIR} && pwd)/vs2015u3"
|
||||
fi
|
||||
|
||||
VSWINPATH="$(cd ${VSPATH} && pwd -W)"
|
||||
|
@ -11,8 +11,8 @@ export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x64"
|
|||
|
||||
export PATH="${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x64:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${VSPATH}/DIA SDK/bin/amd64:${PATH}"
|
||||
|
||||
export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.10586.0/ucrt:${VSPATH}/SDK/Include/10.0.10586.0/shared:${VSPATH}/SDK/Include/10.0.10586.0/um:${VSPATH}/SDK/Include/10.0.10586.0/winrt:${VSPATH}/DIA SDK/include"
|
||||
export LIB="${VSPATH}/VC/lib/amd64:${VSPATH}/VC/atlmfc/lib/amd64:${VSPATH}/SDK/lib/10.0.10586.0/ucrt/x64:${VSPATH}/SDK/lib/10.0.10586.0/um/x64:${VSPATH}/DIA SDK/lib/amd64"
|
||||
export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.14393.0/ucrt:${VSPATH}/SDK/Include/10.0.14393.0/shared:${VSPATH}/SDK/Include/10.0.14393.0/um:${VSPATH}/SDK/Include/10.0.14393.0/winrt:${VSPATH}/DIA SDK/include"
|
||||
export LIB="${VSPATH}/VC/lib/amd64:${VSPATH}/VC/atlmfc/lib/amd64:${VSPATH}/SDK/lib/10.0.14393.0/ucrt/x64:${VSPATH}/SDK/lib/10.0.14393.0/um/x64:${VSPATH}/DIA SDK/lib/amd64"
|
||||
|
||||
. $topsrcdir/build/mozconfig.vs-common
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ VS_PATTERNS = [
|
|||
},
|
||||
]
|
||||
|
||||
SDK_RELEASE = '10.0.10586.0'
|
||||
SDK_RELEASE = '10.0.14393.0'
|
||||
|
||||
# Files from the Windows 10 SDK to install.
|
||||
SDK_PATTERNS = [
|
||||
|
|
|
@ -59,7 +59,11 @@
|
|||
#pragma warning( push )
|
||||
#pragma warning( disable : 4275 4530 )
|
||||
|
||||
#ifdef __clang__
|
||||
#include_next <${HEADER}>
|
||||
#else
|
||||
#include <${HEADER_PATH}>
|
||||
#endif
|
||||
|
||||
#pragma warning( pop )
|
||||
|
||||
|
|
|
@ -82,11 +82,11 @@ function addTab(url, win, backgroundTab = false) {
|
|||
}
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
linkedBrowser.addEventListener("load", function onLoad() {
|
||||
linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser)
|
||||
.then(function () {
|
||||
info("Tab added and finished loading: " + url);
|
||||
done(tab);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -81,11 +81,11 @@ function addTab(aUrl, aWindow) {
|
|||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
linkedBrowser.addEventListener("load", function onLoad() {
|
||||
linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser)
|
||||
.then(function () {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
deferred.resolve(tab);
|
||||
}, true);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
|
@ -91,11 +91,11 @@ this.addTab = function addTab(aUrl, aWindow) {
|
|||
info("Loading frame script with url " + FRAME_SCRIPT_URL + ".");
|
||||
linkedBrowser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
|
||||
|
||||
linkedBrowser.addEventListener("load", function onLoad() {
|
||||
linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser)
|
||||
.then(function () {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
deferred.resolve(tab);
|
||||
}, true);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
|
||||
// Tests that the keybindings for opening and closing the inspector work as expected
|
||||
// Can probably make this a shared test that tests all of the tools global keybindings
|
||||
|
||||
const TEST_URL = "data:text/html,<html><head><title>Test for the " +
|
||||
"highlighter keybindings</title></head><body>" +
|
||||
"<h1>Keybindings!</h1></body></html>"
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
@ -15,17 +17,11 @@ function test()
|
|||
let inspector;
|
||||
let keysetMap = { };
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
addTab(TEST_URL).then(function () {
|
||||
doc = content.document;
|
||||
node = doc.querySelector("h1");
|
||||
waitForFocus(setupKeyBindingsTest);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,<html><head><title>Test for the " +
|
||||
"highlighter keybindings</title></head><body>" +
|
||||
"<h1>Keybindings!</h1></body></html>";
|
||||
});
|
||||
|
||||
function buildDevtoolsKeysetMap(keyset) {
|
||||
[].forEach.call(keyset.querySelectorAll("key"), function (key) {
|
||||
|
|
|
@ -3,28 +3,25 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URL = "data:text/html,test custom host";
|
||||
|
||||
function test() {
|
||||
let {Toolbox} = require("devtools/client/framework/toolbox");
|
||||
|
||||
let toolbox, iframe, target, tab;
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
let toolbox, iframe, target;
|
||||
|
||||
window.addEventListener("message", onMessage);
|
||||
|
||||
iframe = document.createElement("iframe");
|
||||
document.documentElement.appendChild(iframe);
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
|
||||
addTab(TEST_URL).then(function (tab) {
|
||||
target = TargetFactory.forTab(tab);
|
||||
let options = {customIframe: iframe};
|
||||
gDevTools.showToolbox(target, null, Toolbox.HostType.CUSTOM, options)
|
||||
.then(testCustomHost, console.error)
|
||||
.then(null, console.error);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,test custom host";
|
||||
});
|
||||
|
||||
function onMessage(event) {
|
||||
info("onMessage: " + event.data);
|
||||
|
@ -50,7 +47,7 @@ function test() {
|
|||
// toolbox.destroy() returns a singleton promise that ensures
|
||||
// everything is cleaned up before proceeding.
|
||||
toolbox.destroy().then(() => {
|
||||
toolbox = iframe = target = tab = null;
|
||||
toolbox = iframe = target = null;
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,19 +3,16 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URL = "data:text/html,test for dynamically registering and unregistering tools";
|
||||
|
||||
var toolbox;
|
||||
|
||||
function test()
|
||||
{
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
|
||||
addTab(TEST_URL).then(tab => {
|
||||
let target = TargetFactory.forTab(tab);
|
||||
gDevTools.showToolbox(target).then(testRegister);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,test for dynamically registering and unregistering tools";
|
||||
});
|
||||
}
|
||||
|
||||
function testRegister(aToolbox)
|
||||
|
|
|
@ -6,23 +6,19 @@
|
|||
/* import-globals-from shared-head.js */
|
||||
"use strict";
|
||||
|
||||
const TEST_URL = "data:text/html;charset=utf8,test for dynamically " +
|
||||
"registering and unregistering tools";
|
||||
var doc = null, toolbox = null, panelWin = null, modifiedPrefs = [];
|
||||
|
||||
function test() {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
|
||||
addTab(TEST_URL).then(tab => {
|
||||
let target = TargetFactory.forTab(tab);
|
||||
gDevTools.showToolbox(target)
|
||||
.then(testSelectTool)
|
||||
.then(testToggleToolboxButtons)
|
||||
.then(testPrefsAreRespectedWhenReopeningToolbox)
|
||||
.then(cleanup, errorHandler);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html;charset=utf8,test for dynamically " +
|
||||
"registering and unregistering tools";
|
||||
});
|
||||
}
|
||||
|
||||
function testPrefsAreRespectedWhenReopeningToolbox() {
|
||||
|
|
|
@ -8,15 +8,10 @@
|
|||
const TEST_URI = URL_ROOT + "browser_toolbox_options_disable_js.html";
|
||||
|
||||
function test() {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
|
||||
addTab(TEST_URI).then(tab => {
|
||||
let target = TargetFactory.forTab(tab);
|
||||
gDevTools.showToolbox(target).then(testSelectTool);
|
||||
}, true);
|
||||
|
||||
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TEST_URI);
|
||||
});
|
||||
}
|
||||
|
||||
function testSelectTool(toolbox) {
|
||||
|
|
|
@ -31,19 +31,15 @@ function test() {
|
|||
}
|
||||
|
||||
function init() {
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
addTab(TEST_URI).then(tab => {
|
||||
let target = TargetFactory.forTab(tab);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
linkedBrowser.messageManager.loadFrameScript(COMMON_FRAME_SCRIPT_URL, false);
|
||||
linkedBrowser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
|
||||
gDevTools.showToolbox(target).then(testSelectTool);
|
||||
}, true);
|
||||
|
||||
content.location = TEST_URI;
|
||||
});
|
||||
}
|
||||
|
||||
function testSelectTool(aToolbox) {
|
||||
|
|
|
@ -3,23 +3,20 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TEST_URL = "data:text/html,test for opening toolbox in different hosts";
|
||||
|
||||
var {Toolbox} = require("devtools/client/framework/toolbox");
|
||||
|
||||
var toolbox, target, tab1, tab2;
|
||||
var toolbox, tab1, tab2;
|
||||
|
||||
function test() {
|
||||
gBrowser.selectedTab = tab1 = gBrowser.addTab();
|
||||
addTab(TEST_URL).then(tab => {
|
||||
tab2 = gBrowser.addTab();
|
||||
target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
|
||||
let target = TargetFactory.forTab(tab);
|
||||
gDevTools.showToolbox(target)
|
||||
.then(testBottomHost, console.error)
|
||||
.then(null, console.error);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,test for opening toolbox in different hosts";
|
||||
});
|
||||
}
|
||||
|
||||
function testBottomHost(aToolbox) {
|
||||
|
@ -73,7 +70,7 @@ function cleanup() {
|
|||
Services.prefs.setCharPref("devtools.toolbox.host", Toolbox.HostType.BOTTOM);
|
||||
|
||||
toolbox.destroy().then(function () {
|
||||
toolbox = target = null;
|
||||
toolbox = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
const TEST_URL = "data:text/html,test for toolbox being ready";
|
||||
|
||||
const onLoad = Task.async(function* (evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onLoad);
|
||||
add_task(function* () {
|
||||
let tab = yield addTab(TEST_URL);
|
||||
let target = TargetFactory.forTab(tab);
|
||||
|
||||
const toolbox = yield gDevTools.showToolbox(target, "webconsole");
|
||||
ok(toolbox.isReady, "toolbox isReady is set");
|
||||
|
@ -19,9 +18,4 @@ function test() {
|
|||
|
||||
yield toolbox.destroy();
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", onLoad, true);
|
||||
content.location = "data:text/html,test for toolbox being ready";
|
||||
}
|
||||
|
|
|
@ -30,17 +30,14 @@ function test() {
|
|||
|
||||
function openTabs() {
|
||||
// Open two tabs, select the second
|
||||
gTab1 = gBrowser.addTab(TAB_URL_1);
|
||||
gTab1.linkedBrowser.addEventListener("load", function onLoad1(evt) {
|
||||
gTab1.linkedBrowser.removeEventListener("load", onLoad1);
|
||||
|
||||
gTab2 = gBrowser.selectedTab = gBrowser.addTab(TAB_URL_2);
|
||||
gTab2.linkedBrowser.addEventListener("load", function onLoad2(evt) {
|
||||
gTab2.linkedBrowser.removeEventListener("load", onLoad2);
|
||||
addTab(TAB_URL_1).then(tab1 => {
|
||||
gTab1 = tab1;
|
||||
addTab(TAB_URL_2).then(tab2 => {
|
||||
gTab2 = tab2;
|
||||
|
||||
connect();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function connect() {
|
||||
|
|
|
@ -91,12 +91,10 @@ function reloadTab(tabX) {
|
|||
let def = defer();
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
// once() doesn't work here so we use a standard handler instead.
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
BrowserTestUtils.browserLoaded(browser).then(function () {
|
||||
info("Reloaded tab " + tabX.title);
|
||||
def.resolve();
|
||||
}, true);
|
||||
});
|
||||
|
||||
info("Reloading tab " + tabX.title);
|
||||
let mm = getFrameScript();
|
||||
|
|
|
@ -113,7 +113,7 @@ var addTab = Task.async(function* (url) {
|
|||
info("Adding a new tab with URL: " + url);
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
yield once(gBrowser.selectedBrowser, "load", true);
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
|
||||
info("Tab added and finished loading");
|
||||
|
||||
|
@ -142,7 +142,7 @@ var removeTab = Task.async(function* (tab) {
|
|||
*/
|
||||
var refreshTab = Task.async(function*(tab) {
|
||||
info("Refreshing tab.");
|
||||
const finished = once(gBrowser.selectedBrowser, "load", true);
|
||||
const finished = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
gBrowser.reloadTab(gBrowser.selectedTab);
|
||||
yield finished;
|
||||
info("Tab finished refreshing.");
|
||||
|
@ -291,9 +291,7 @@ function waitForTick() {
|
|||
* @return A promise that resolves when the time is passed
|
||||
*/
|
||||
function wait(ms) {
|
||||
let def = defer();
|
||||
content.setTimeout(def.resolve, ms);
|
||||
return def.promise;
|
||||
return new promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,7 +52,7 @@ add_task(function* () {
|
|||
EventUtils.synthesizeMouse(searchField, 2, 2,
|
||||
{type: "contextmenu", button: 2}, win);
|
||||
yield onContextMenuPopup;
|
||||
yield waitForClipboard(() => cmdCopy.click(), TEST_INPUT);
|
||||
yield waitForClipboardPromise(() => cmdCopy.click(), TEST_INPUT);
|
||||
searchContextMenu.hidePopup();
|
||||
yield onContextMenuHidden;
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ function* checkCopySelection(view) {
|
|||
"font-variant-caps: small-caps;[\\r\\n]*";
|
||||
|
||||
try {
|
||||
yield waitForClipboard(() => fireCopyEvent(props[0]),
|
||||
yield waitForClipboardPromise(() => fireCopyEvent(props[0]),
|
||||
() => checkClipboardData(expectedPattern));
|
||||
} catch (e) {
|
||||
failedClipboard(expectedPattern);
|
||||
|
@ -84,7 +84,7 @@ function* checkSelectAll(view) {
|
|||
"font-variant-caps: small-caps;[\\r\\n]*";
|
||||
|
||||
try {
|
||||
yield waitForClipboard(() => fireCopyEvent(prop),
|
||||
yield waitForClipboardPromise(() => fireCopyEvent(prop),
|
||||
() => checkClipboardData(expectedPattern));
|
||||
} catch (e) {
|
||||
failedClipboard(expectedPattern);
|
||||
|
|
|
@ -25,7 +25,7 @@ add_task(function* () {
|
|||
let onTabOpened = once(gBrowser.tabContainer, "TabOpen");
|
||||
inspector.onFollowLink();
|
||||
let {target: tab} = yield onTabOpened;
|
||||
yield waitForTabLoad(tab);
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
ok(true, "A new tab opened");
|
||||
is(tab.linkedBrowser.currentURI.spec, URL_ROOT + "doc_markup_tooltip.png",
|
||||
|
@ -67,16 +67,3 @@ add_task(function* () {
|
|||
is(inspector.selection.nodeFront.tagName.toLowerCase(), "output",
|
||||
"The <output> node is still selected");
|
||||
});
|
||||
|
||||
function waitForTabLoad(tab) {
|
||||
let def = defer();
|
||||
tab.addEventListener("load", function onLoad(e) {
|
||||
// Skip load event for about:blank
|
||||
if (tab.linkedBrowser.currentURI.spec === "about:blank") {
|
||||
return;
|
||||
}
|
||||
tab.removeEventListener("load", onLoad);
|
||||
def.resolve();
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
|
|
@ -58,19 +58,6 @@ add_task(function* () {
|
|||
yield followLinkNoNewNode(linkEl, true, inspector);
|
||||
});
|
||||
|
||||
function waitForTabLoad(tab) {
|
||||
let def = defer();
|
||||
tab.addEventListener("load", function onLoad() {
|
||||
// Skip load event for about:blank
|
||||
if (tab.linkedBrowser.currentURI.spec === "about:blank") {
|
||||
return;
|
||||
}
|
||||
tab.removeEventListener("load", onLoad);
|
||||
def.resolve();
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
function performMouseDown(linkEl, metactrl) {
|
||||
let evt = linkEl.ownerDocument.createEvent("MouseEvents");
|
||||
|
||||
|
@ -95,7 +82,7 @@ function* followLinkWaitForTab(linkEl, isMetaClick, expectedTabURI) {
|
|||
let onTabOpened = once(gBrowser.tabContainer, "TabOpen");
|
||||
performMouseDown(linkEl, isMetaClick);
|
||||
let {target} = yield onTabOpened;
|
||||
yield waitForTabLoad(target);
|
||||
yield BrowserTestUtils.browserLoaded(target.linkedBrowser);
|
||||
ok(true, "A new tab opened");
|
||||
is(target.linkedBrowser.currentURI.spec, expectedTabURI,
|
||||
"The URL for the new tab is correct");
|
||||
|
|
|
@ -271,18 +271,6 @@ function searchUsingSelectorSearch(selector, inspector) {
|
|||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
}
|
||||
|
||||
/**
|
||||
* This shouldn't be used in the tests, but is useful when writing new tests or
|
||||
* debugging existing tests in order to introduce delays in the test steps
|
||||
* @param {Number} ms The time to wait
|
||||
* @return A promise that resolves when the time is passed
|
||||
*/
|
||||
function wait(ms) {
|
||||
let def = defer();
|
||||
setTimeout(def.resolve, ms);
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the inspector menu items for editing are disabled.
|
||||
* Things like Edit As HTML, Delete Node, etc.
|
||||
|
|
|
@ -267,7 +267,7 @@ function* checkCopyStyle(view, node, menuItemLabel, expectedPattern, visible) {
|
|||
visible.copyRule);
|
||||
|
||||
try {
|
||||
yield waitForClipboard(() => menuItem.click(),
|
||||
yield waitForClipboardPromise(() => menuItem.click(),
|
||||
() => checkClipboardData(expectedPattern));
|
||||
} catch (e) {
|
||||
failedClipboard(expectedPattern);
|
||||
|
|
|
@ -51,7 +51,7 @@ add_task(function* () {
|
|||
EventUtils.synthesizeMouse(searchField, 2, 2,
|
||||
{type: "contextmenu", button: 2}, win);
|
||||
yield onContextMenuPopup;
|
||||
yield waitForClipboard(() => cmdCopy.click(), TEST_INPUT);
|
||||
yield waitForClipboardPromise(() => cmdCopy.click(), TEST_INPUT);
|
||||
searchContextMenu.hidePopup();
|
||||
yield onContextMenuHidden;
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ function* checkCopySelection(view) {
|
|||
"Copy menu item is displayed as expected");
|
||||
|
||||
try {
|
||||
yield waitForClipboard(() => menuitemCopy.click(),
|
||||
yield waitForClipboardPromise(() => menuitemCopy.click(),
|
||||
() => checkClipboardData(expectedPattern));
|
||||
} catch (e) {
|
||||
failedClipboard(expectedPattern);
|
||||
|
@ -109,7 +109,7 @@ function* checkSelectAll(view) {
|
|||
"Copy menu item is displayed as expected");
|
||||
|
||||
try {
|
||||
yield waitForClipboard(() => menuitemCopy.click(),
|
||||
yield waitForClipboardPromise(() => menuitemCopy.click(),
|
||||
() => checkClipboardData(expectedPattern));
|
||||
} catch (e) {
|
||||
failedClipboard(expectedPattern);
|
||||
|
@ -137,7 +137,7 @@ function* checkCopyEditorValue(view) {
|
|||
"Copy menu item is displayed as expected");
|
||||
|
||||
try {
|
||||
yield waitForClipboard(() => menuitemCopy.click(),
|
||||
yield waitForClipboardPromise(() => menuitemCopy.click(),
|
||||
() => checkClipboardData(expectedPattern));
|
||||
} catch (e) {
|
||||
failedClipboard(expectedPattern);
|
||||
|
|
|
@ -39,7 +39,7 @@ function* testCopyToClipboard(inspector, view) {
|
|||
|
||||
ok(menuitemCopyColor.visible, "Copy color is visible");
|
||||
|
||||
yield waitForClipboard(() => menuitemCopyColor.click(),
|
||||
yield waitForClipboardPromise(() => menuitemCopyColor.click(),
|
||||
"#123ABC");
|
||||
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", { });
|
||||
|
|
|
@ -87,12 +87,12 @@ function* testCopyUrlToClipboard({view, inspector}, type, selector, expected) {
|
|||
|
||||
if (type == "data-uri") {
|
||||
info("Click Copy Data URI and wait for clipboard");
|
||||
yield waitForClipboard(() => {
|
||||
yield waitForClipboardPromise(() => {
|
||||
return menuitemCopyImageDataUrl.click();
|
||||
}, expected);
|
||||
} else {
|
||||
info("Click Copy URL and wait for clipboard");
|
||||
yield waitForClipboard(() => {
|
||||
yield waitForClipboardPromise(() => {
|
||||
return menuitemCopyUrl.click();
|
||||
}, expected);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ add_task(function* () {
|
|||
info("Make sure to wait until the eyedropper is done taking a screenshot of the page");
|
||||
yield waitForElementAttributeSet("root", "drawn", helper);
|
||||
|
||||
yield waitForClipboard(() => {
|
||||
yield waitForClipboardPromise(() => {
|
||||
info("Activate the eyedropper so the background color is copied");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}, "#FF0000");
|
||||
|
|
|
@ -34,7 +34,7 @@ function* setSelectionNodeFront(node, inspector) {
|
|||
|
||||
function* checkClipboard(expectedText, node) {
|
||||
try {
|
||||
yield waitForClipboard(() => fireCopyEvent(node), expectedText);
|
||||
yield waitForClipboardPromise(() => fireCopyEvent(node), expectedText);
|
||||
ok(true, "Clipboard successfully filled with : " + expectedText);
|
||||
} catch (e) {
|
||||
ok(false, "Clipboard could not be filled with the expected text : " +
|
||||
|
|
|
@ -44,6 +44,6 @@ add_task(function* () {
|
|||
let item = allMenuItems.find(i => i.id === id);
|
||||
ok(item, "The popup has a " + desc + " menu item.");
|
||||
|
||||
yield waitForClipboard(() => item.click(), text);
|
||||
yield waitForClipboardPromise(() => item.click(), text);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -50,7 +50,7 @@ add_task(function* () {
|
|||
EventUtils.synthesizeMouse(searchBox, 2, 2,
|
||||
{type: "contextmenu", button: 2}, win);
|
||||
yield onContextMenuPopup;
|
||||
yield waitForClipboard(() => cmdCopy.click(), TEST_INPUT);
|
||||
yield waitForClipboardPromise(() => cmdCopy.click(), TEST_INPUT);
|
||||
searchContextMenu.hidePopup();
|
||||
yield onContextMenuHidden;
|
||||
|
||||
|
|
|
@ -618,23 +618,6 @@ function waitForStyleEditor(toolbox, href) {
|
|||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SimpleTest.waitForClipboard
|
||||
*
|
||||
* @param {Function} setup
|
||||
* Function to execute before checking for the
|
||||
* clipboard content
|
||||
* @param {String|Function} expected
|
||||
* An expected string or validator function
|
||||
* @return a promise that resolves when the expected string has been found or
|
||||
* the validator function has returned true, rejects otherwise.
|
||||
*/
|
||||
function waitForClipboard(setup, expected) {
|
||||
let def = defer();
|
||||
SimpleTest.waitForClipboard(expected, setup, def.resolve, def.reject);
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if document's active element is within the given element.
|
||||
* @param {HTMLDocument} doc document with active element in question
|
||||
|
@ -662,8 +645,7 @@ var waitForTab = Task.async(function* () {
|
|||
info("Waiting for a tab to open");
|
||||
yield once(gBrowser.tabContainer, "TabOpen");
|
||||
let tab = gBrowser.selectedTab;
|
||||
let browser = tab.linkedBrowser;
|
||||
yield once(browser, "load", true);
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
info("The tab load completed");
|
||||
return tab;
|
||||
});
|
||||
|
|
|
@ -57,15 +57,13 @@ function addTab(url) {
|
|||
info("Adding a new tab with URL: '" + url + "'");
|
||||
let def = promise.defer();
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
BrowserTestUtils.browserLoaded(tab.linkedBrowser).then(function () {
|
||||
info("URL '" + url + "' loading complete");
|
||||
waitForFocus(() => {
|
||||
def.resolve(tab);
|
||||
}, content);
|
||||
}, true);
|
||||
content.location = url;
|
||||
});
|
||||
|
||||
return def.promise;
|
||||
}
|
||||
|
|
|
@ -195,18 +195,12 @@ var addTab = Task.async(function* (url) {
|
|||
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
yield once(browser, "load", true);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
info("URL '" + url + "' loading complete");
|
||||
|
||||
return tab;
|
||||
});
|
||||
|
||||
function wait(ms) {
|
||||
let def = promise.defer();
|
||||
setTimeout(def.resolve, ms);
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the next load to complete in the current browser.
|
||||
*
|
||||
|
|
|
@ -76,11 +76,10 @@ function addTab(aUrl, aWindow) {
|
|||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
linkedBrowser.addEventListener("load", function onLoad() {
|
||||
linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
deferred.resolve(tab);
|
||||
}, true);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
|
@ -12,14 +12,7 @@ function test() {
|
|||
requestLongerTimeout(3);
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
runCodeMirrorTest(browser);
|
||||
}, true);
|
||||
|
||||
browser.loadURI(URI);
|
||||
addTab(URI).then(function (tab) {
|
||||
runCodeMirrorTest(tab.linkedBrowser);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -79,13 +79,10 @@ let inspector;
|
|||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
addTab(TEST_URI).then(function () {
|
||||
doc = content.document;
|
||||
runTests();
|
||||
}, true);
|
||||
content.location = TEST_URI;
|
||||
});
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
|
|
|
@ -11,14 +11,7 @@ function test() {
|
|||
requestLongerTimeout(4);
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
runCodeMirrorTest(browser);
|
||||
}, true);
|
||||
|
||||
browser.loadURI(URI);
|
||||
addTab(URI).then(function (tab) {
|
||||
runCodeMirrorTest(tab.linkedBrowser);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -22,18 +22,16 @@ SimpleTest.registerCleanupFunction(() => {
|
|||
function addTab(url, callback) {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
content.location = url;
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
let tab = gBrowser.selectedTab;
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
function onTabLoad() {
|
||||
browser.removeEventListener("load", onTabLoad, true);
|
||||
return BrowserTestUtils.browserLoaded(browser).then(function () {
|
||||
if (typeof(callback) == "function") {
|
||||
callback(browser, tab, browser.contentDocument);
|
||||
}
|
||||
|
||||
browser.addEventListener("load", onTabLoad, true);
|
||||
return tab;
|
||||
});
|
||||
}
|
||||
|
||||
function promiseTab(url) {
|
||||
|
|
|
@ -29,11 +29,11 @@ var addTab = function (url, win) {
|
|||
let targetBrowser = targetWindow.gBrowser;
|
||||
|
||||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(url);
|
||||
targetBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
targetBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
BrowserTestUtils.browserLoaded(targetBrowser.selectedBrowser)
|
||||
.then(function () {
|
||||
info("URL '" + url + "' loading complete");
|
||||
def.resolve(tab);
|
||||
}, true);
|
||||
});
|
||||
|
||||
return def.promise;
|
||||
};
|
||||
|
|
|
@ -73,11 +73,10 @@ function addTab(aUrl, aWindow) {
|
|||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
linkedBrowser.addEventListener("load", function onLoad() {
|
||||
linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
deferred.resolve(tab);
|
||||
}, true);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
|
@ -167,11 +167,10 @@ function addTab(aUrl, aWindow) {
|
|||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
linkedBrowser.addEventListener("load", function onLoad() {
|
||||
linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
deferred.resolve(tab);
|
||||
}, true);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ add_task(function* () {
|
|||
is(mouseDownHandled, 1, "The mousedown event was handled once before navigation");
|
||||
|
||||
info("Navigating to a new page");
|
||||
let loaded = once(gBrowser.selectedBrowser, "load", true);
|
||||
let loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
content.location = TEST_URL_2;
|
||||
yield loaded;
|
||||
doc = gBrowser.selectedBrowser.contentWindow.document;
|
||||
|
|
|
@ -33,7 +33,7 @@ waitForExplicitFinish();
|
|||
var addTab = Task.async(function* (url) {
|
||||
info(`Adding a new tab with URL: ${url}`);
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
yield once(gBrowser.selectedBrowser, "load", true);
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
info(`Tab added and URL ${url} loaded`);
|
||||
|
||||
|
|
|
@ -18,14 +18,6 @@ test(function(t) {
|
|||
assert_equals(animation.id, 'anim', 'animation.id reflects the value set');
|
||||
}, 'Animation.id for CSS Animations');
|
||||
|
||||
test(function(t) {
|
||||
var div = addDiv(t);
|
||||
var animation = div.animate({}, 100 * MS_PER_SEC);
|
||||
assert_equals(animation.id, '', 'id for CSS Animation is initially empty');
|
||||
animation.id = 'anim'
|
||||
|
||||
assert_equals(animation.id, 'anim', 'animation.id reflects the value set');
|
||||
}, 'Animation.id for CSS Animations');
|
||||
done();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<script>
|
||||
'use strict';
|
||||
|
||||
async_test(function(t) {
|
||||
promise_test(function(t) {
|
||||
var div = addDiv(t, { style: 'margin-left: 0px' });
|
||||
flushComputedStyle(div);
|
||||
|
||||
|
@ -14,17 +14,16 @@ async_test(function(t) {
|
|||
flushComputedStyle(div);
|
||||
|
||||
var animation = div.getAnimations()[0];
|
||||
animation.ready.then(waitForFrame).then(t.step_func(function() {
|
||||
return animation.ready.then(waitForFrame).then(function() {
|
||||
assert_not_equals(getComputedStyle(div).marginLeft, '1000px',
|
||||
'transform style is animated before cancelling');
|
||||
animation.cancel();
|
||||
assert_equals(getComputedStyle(div).marginLeft, div.style.marginLeft,
|
||||
'transform style is no longer animated after cancelling');
|
||||
t.done();
|
||||
}));
|
||||
});
|
||||
}, 'Animated style is cleared after cancelling a running CSS transition');
|
||||
|
||||
async_test(function(t) {
|
||||
promise_test(function(t) {
|
||||
var div = addDiv(t, { style: 'margin-left: 0px' });
|
||||
flushComputedStyle(div);
|
||||
|
||||
|
@ -32,24 +31,22 @@ async_test(function(t) {
|
|||
div.style.marginLeft = '1000px';
|
||||
flushComputedStyle(div);
|
||||
|
||||
div.addEventListener('transitionend', t.step_func(function() {
|
||||
div.addEventListener('transitionend', function() {
|
||||
assert_unreached('Got unexpected end event on cancelled transition');
|
||||
}));
|
||||
});
|
||||
|
||||
var animation = div.getAnimations()[0];
|
||||
animation.ready.then(t.step_func(function() {
|
||||
return animation.ready.then(function() {
|
||||
// Seek to just before the end then cancel
|
||||
animation.currentTime = 99.9 * 1000;
|
||||
animation.cancel();
|
||||
|
||||
// Then wait a couple of frames and check that no event was dispatched
|
||||
return waitForAnimationFrames(2);
|
||||
})).then(t.step_func(function() {
|
||||
t.done();
|
||||
}));
|
||||
});
|
||||
}, 'Cancelled CSS transitions do not dispatch events');
|
||||
|
||||
async_test(function(t) {
|
||||
promise_test(function(t) {
|
||||
var div = addDiv(t, { style: 'margin-left: 0px' });
|
||||
flushComputedStyle(div);
|
||||
|
||||
|
@ -58,7 +55,7 @@ async_test(function(t) {
|
|||
flushComputedStyle(div);
|
||||
|
||||
var animation = div.getAnimations()[0];
|
||||
animation.ready.then(t.step_func(function() {
|
||||
return animation.ready.then(function() {
|
||||
animation.cancel();
|
||||
assert_equals(getComputedStyle(div).marginLeft, '1000px',
|
||||
'margin-left style is not animated after cancelling');
|
||||
|
@ -66,14 +63,13 @@ async_test(function(t) {
|
|||
assert_equals(getComputedStyle(div).marginLeft, '0px',
|
||||
'margin-left style is animated after re-starting transition');
|
||||
return animation.ready;
|
||||
})).then(t.step_func(function() {
|
||||
}).then(function() {
|
||||
assert_equals(animation.playState, 'running',
|
||||
'Transition succeeds in running after being re-started');
|
||||
t.done();
|
||||
}));
|
||||
});
|
||||
}, 'After cancelling a transition, it can still be re-used');
|
||||
|
||||
async_test(function(t) {
|
||||
promise_test(function(t) {
|
||||
var div = addDiv(t, { style: 'margin-left: 0px' });
|
||||
flushComputedStyle(div);
|
||||
|
||||
|
@ -82,7 +78,7 @@ async_test(function(t) {
|
|||
flushComputedStyle(div);
|
||||
|
||||
var animation = div.getAnimations()[0];
|
||||
animation.ready.then(t.step_func(function() {
|
||||
return animation.ready.then(function() {
|
||||
animation.finish();
|
||||
animation.cancel();
|
||||
assert_equals(getComputedStyle(div).marginLeft, '1000px',
|
||||
|
@ -91,11 +87,10 @@ async_test(function(t) {
|
|||
assert_equals(getComputedStyle(div).marginLeft, '0px',
|
||||
'margin-left style is animated after re-starting transition');
|
||||
return animation.ready;
|
||||
})).then(t.step_func(function() {
|
||||
}).then(function() {
|
||||
assert_equals(animation.playState, 'running',
|
||||
'Transition succeeds in running after being re-started');
|
||||
t.done();
|
||||
}));
|
||||
});
|
||||
}, 'After cancelling a finished transition, it can still be re-used');
|
||||
|
||||
test(function(t) {
|
||||
|
@ -123,6 +118,20 @@ test(function(t) {
|
|||
}, 'After cancelling a transition, updating transition properties doesn\'t make'
|
||||
+ ' it live again');
|
||||
|
||||
test(function(t) {
|
||||
var div = addDiv(t, { style: 'margin-left: 0px' });
|
||||
flushComputedStyle(div);
|
||||
|
||||
div.style.transition = 'margin-left 100s';
|
||||
div.style.marginLeft = '1000px';
|
||||
flushComputedStyle(div);
|
||||
|
||||
var animation = div.getAnimations()[0];
|
||||
div.style.display = 'none';
|
||||
assert_equals(animation.playState, 'idle');
|
||||
assert_equals(getComputedStyle(div).marginLeft, '1000px');
|
||||
}, 'Setting display:none on an element cancels its transitions');
|
||||
|
||||
done();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -84,7 +84,7 @@ skip-if = android_version == '18' #Android 4.3 aws only; bug 1030942
|
|||
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
|
||||
[test_webgl_compressed_texture_es3.html]
|
||||
[test_webgl_disjoint_timer_query.html]
|
||||
fail-if = (os == 'win' && (os_version == '6.1' || os_version == '6.2'))
|
||||
fail-if = (os == 'win' && (os_version == '6.1' || os_version == '6.2' || os_version == '10.0'))
|
||||
[test_webgl_force_enable.html]
|
||||
[test_webgl_request_context.html]
|
||||
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
|
||||
|
|
|
@ -4341,7 +4341,7 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
|
|||
}
|
||||
if (mIsEncrypted) {
|
||||
if (!mMediaSource && Preferences::GetBool("media.eme.mse-only", true)) {
|
||||
DecodeError();
|
||||
DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4416,7 +4416,7 @@ void HTMLMediaElement::NetworkError()
|
|||
Error(nsIDOMMediaError::MEDIA_ERR_NETWORK);
|
||||
}
|
||||
|
||||
void HTMLMediaElement::DecodeError()
|
||||
void HTMLMediaElement::DecodeError(const MediaResult& aError)
|
||||
{
|
||||
nsAutoString src;
|
||||
GetCurrentSrc(src);
|
||||
|
@ -4440,7 +4440,7 @@ void HTMLMediaElement::DecodeError()
|
|||
NS_WARNING("Should know the source we were loading from!");
|
||||
}
|
||||
} else {
|
||||
Error(nsIDOMMediaError::MEDIA_ERR_DECODE);
|
||||
Error(nsIDOMMediaError::MEDIA_ERR_DECODE, aError);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4454,7 +4454,8 @@ void HTMLMediaElement::LoadAborted()
|
|||
Error(nsIDOMMediaError::MEDIA_ERR_ABORTED);
|
||||
}
|
||||
|
||||
void HTMLMediaElement::Error(uint16_t aErrorCode)
|
||||
void HTMLMediaElement::Error(uint16_t aErrorCode,
|
||||
const MediaResult& aErrorDetails)
|
||||
{
|
||||
NS_ASSERTION(aErrorCode == nsIDOMMediaError::MEDIA_ERR_DECODE ||
|
||||
aErrorCode == nsIDOMMediaError::MEDIA_ERR_NETWORK ||
|
||||
|
@ -4467,8 +4468,12 @@ void HTMLMediaElement::Error(uint16_t aErrorCode)
|
|||
if (mError) {
|
||||
return;
|
||||
}
|
||||
nsCString message;
|
||||
if (NS_FAILED(aErrorDetails)) {
|
||||
message = aErrorDetails.Description();
|
||||
}
|
||||
mError = new MediaError(this, aErrorCode, message);
|
||||
|
||||
mError = new MediaError(this, aErrorCode);
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("error"));
|
||||
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
|
||||
|
|
|
@ -179,7 +179,7 @@ public:
|
|||
|
||||
// Called by the video decoder object, on the main thread, when the
|
||||
// resource has a decode error during metadata loading or decoding.
|
||||
virtual void DecodeError() final override;
|
||||
virtual void DecodeError(const MediaResult& aError) final override;
|
||||
|
||||
// Return true if error attribute is not null.
|
||||
virtual bool HasError() const final override;
|
||||
|
@ -1116,7 +1116,7 @@ protected:
|
|||
* Resets the media element for an error condition as per aErrorCode.
|
||||
* aErrorCode must be one of nsIDOMHTMLMediaError codes.
|
||||
*/
|
||||
void Error(uint16_t aErrorCode);
|
||||
void Error(uint16_t aErrorCode, const MediaResult& aErrorDetails = NS_OK);
|
||||
|
||||
/**
|
||||
* Returns the URL spec of the currentSrc.
|
||||
|
|
|
@ -21,9 +21,11 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaError)
|
|||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMediaError)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
MediaError::MediaError(HTMLMediaElement* aParent, uint16_t aCode)
|
||||
MediaError::MediaError(HTMLMediaElement* aParent, uint16_t aCode,
|
||||
const nsACString& aMessage)
|
||||
: mParent(aParent)
|
||||
, mCode(aCode)
|
||||
, mMessage(aMessage)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -35,6 +37,12 @@ NS_IMETHODIMP MediaError::GetCode(uint16_t* aCode)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP MediaError::GetMessage(nsAString& aResult)
|
||||
{
|
||||
CopyUTF8toUTF16(mMessage, aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MediaError::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
|
|
|
@ -22,7 +22,8 @@ class MediaError final : public nsIDOMMediaError,
|
|||
~MediaError() {}
|
||||
|
||||
public:
|
||||
MediaError(HTMLMediaElement* aParent, uint16_t aCode);
|
||||
MediaError(HTMLMediaElement* aParent, uint16_t aCode,
|
||||
const nsACString& aMessage = nsCString());
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
@ -48,6 +49,8 @@ private:
|
|||
|
||||
// Error code
|
||||
const uint16_t mCode;
|
||||
// Error details;
|
||||
const nsCString mMessage;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -24,4 +24,6 @@ interface nsIDOMMediaError : nsISupports
|
|||
const unsigned short MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
|
||||
|
||||
readonly attribute unsigned short code;
|
||||
|
||||
readonly attribute DOMString message;
|
||||
};
|
||||
|
|
|
@ -1312,6 +1312,16 @@ StartMacOSContentSandbox()
|
|||
MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> profileDir;
|
||||
ContentChild::GetSingleton()->GetProfileDir(getter_AddRefs(profileDir));
|
||||
nsCString profileDirPath;
|
||||
if (profileDir) {
|
||||
rv = profileDir->GetNativePath(profileDirPath);
|
||||
if (NS_FAILED(rv) || profileDirPath.IsEmpty()) {
|
||||
MOZ_CRASH("Failed to get profile path");
|
||||
}
|
||||
}
|
||||
|
||||
MacSandboxInfo info;
|
||||
info.type = MacSandboxType_Content;
|
||||
info.level = info.level = sandboxLevel;
|
||||
|
@ -1320,6 +1330,13 @@ StartMacOSContentSandbox()
|
|||
info.appDir.assign(appDir.get());
|
||||
info.appTempDir.assign(tempDirPath.get());
|
||||
|
||||
if (profileDir) {
|
||||
info.hasSandboxedProfile = true;
|
||||
info.profileDir.assign(profileDirPath.get());
|
||||
} else {
|
||||
info.hasSandboxedProfile = false;
|
||||
}
|
||||
|
||||
std::string err;
|
||||
if (!mozilla::StartMacSandbox(info, err)) {
|
||||
NS_WARNING(err.c_str());
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include "nsWeakPtr.h"
|
||||
#include "nsIWindowProvider.h"
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
#include "nsIFile.h"
|
||||
#endif
|
||||
|
||||
struct ChromePackage;
|
||||
class nsIObserver;
|
||||
|
@ -114,6 +117,19 @@ public:
|
|||
|
||||
void GetProcessName(nsACString& aName) const;
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
void GetProfileDir(nsIFile** aProfileDir) const
|
||||
{
|
||||
*aProfileDir = mProfileDir;
|
||||
NS_IF_ADDREF(*aProfileDir);
|
||||
}
|
||||
|
||||
void SetProfileDir(nsIFile* aProfileDir)
|
||||
{
|
||||
mProfileDir = aProfileDir;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsAlive() const;
|
||||
|
||||
bool IsShuttingDown() const;
|
||||
|
@ -681,6 +697,10 @@ private:
|
|||
nsCOMPtr<nsIDomainPolicy> mPolicy;
|
||||
nsCOMPtr<nsITimer> mForceKillTimer;
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
nsCOMPtr<nsIFile> mProfileDir;
|
||||
#endif
|
||||
|
||||
// Hashtable to keep track of the pending GetFilesHelper objects.
|
||||
// This GetFilesHelperChild objects are removed when RecvGetFilesResponse is
|
||||
// received.
|
||||
|
|
|
@ -114,6 +114,21 @@ ContentProcess::SetAppDir(const nsACString& aPath)
|
|||
mXREEmbed.SetAppDir(aPath);
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
void
|
||||
ContentProcess::SetProfile(const nsACString& aProfile)
|
||||
{
|
||||
bool flag;
|
||||
nsresult rv =
|
||||
XRE_GetFileFromPath(aProfile.BeginReading(), getter_AddRefs(mProfileDir));
|
||||
if (NS_FAILED(rv) ||
|
||||
NS_FAILED(mProfileDir->Exists(&flag)) || !flag) {
|
||||
NS_WARNING("Invalid profile directory passed to content process.");
|
||||
mProfileDir = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
ContentProcess::Init()
|
||||
{
|
||||
|
@ -124,6 +139,10 @@ ContentProcess::Init()
|
|||
mContent.InitXPCOM();
|
||||
mContent.InitGraphicsDeviceData();
|
||||
|
||||
#if (defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
mContent.SetProfileDir(mProfileDir);
|
||||
#endif
|
||||
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
SetUpSandboxEnvironment();
|
||||
#endif
|
||||
|
|
|
@ -39,9 +39,18 @@ public:
|
|||
|
||||
void SetAppDir(const nsACString& aPath);
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
void SetProfile(const nsACString& aProfile);
|
||||
#endif
|
||||
|
||||
private:
|
||||
ContentChild mContent;
|
||||
mozilla::ipc::ScopedXREEmbed mXREEmbed;
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
nsCOMPtr<nsIFile> mProfileDir;
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// This object initializes and configures COM.
|
||||
mozilla::mscom::MainThreadRuntime mCOMRuntime;
|
||||
|
|
|
@ -318,7 +318,7 @@ ADTSDemuxer::Init()
|
|||
ADTSLOG("Init() failure: waiting for data");
|
||||
|
||||
return InitPromise::CreateAndReject(
|
||||
DemuxerFailureReason::DEMUXER_ERROR, __func__);
|
||||
NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
|
||||
}
|
||||
|
||||
ADTSLOG("Init() successful");
|
||||
|
@ -515,10 +515,7 @@ ADTSTrackDemuxer::GetSamples(int32_t aNumSamples)
|
|||
aNumSamples, mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
|
||||
mSamplesPerFrame, mSamplesPerSecond, mChannels);
|
||||
|
||||
if (!aNumSamples) {
|
||||
return SamplesPromise::CreateAndReject(
|
||||
DemuxerFailureReason::DEMUXER_ERROR, __func__);
|
||||
}
|
||||
MOZ_ASSERT(aNumSamples);
|
||||
|
||||
RefPtr<SamplesHolder> frames = new SamplesHolder();
|
||||
|
||||
|
@ -540,7 +537,7 @@ ADTSTrackDemuxer::GetSamples(int32_t aNumSamples)
|
|||
|
||||
if (frames->mSamples.IsEmpty()) {
|
||||
return SamplesPromise::CreateAndReject(
|
||||
DemuxerFailureReason::END_OF_STREAM, __func__);
|
||||
NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
}
|
||||
|
||||
return SamplesPromise::CreateAndResolve(frames, __func__);
|
||||
|
@ -562,7 +559,7 @@ ADTSTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold)
|
|||
{
|
||||
// Will not be called for audio-only resources.
|
||||
return SkipAccessPointPromise::CreateAndReject(
|
||||
SkipFailureHolder(DemuxerFailureReason::DEMUXER_ERROR, 0), __func__);
|
||||
SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
|
|
@ -61,7 +61,7 @@ AccurateSeekTask::Discard()
|
|||
AssertOwnerThread();
|
||||
|
||||
// Disconnect MDSM.
|
||||
RejectIfExist(__func__);
|
||||
RejectIfExist(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
|
||||
// Disconnect MediaDecoderReaderWrapper.
|
||||
mSeekRequest.DisconnectIfExists();
|
||||
|
@ -120,7 +120,7 @@ AccurateSeekTask::DropAudioUpToSeekTarget(MediaData* aSample)
|
|||
|
||||
CheckedInt64 sampleDuration = FramesToUsecs(audio->mFrames, mAudioRate);
|
||||
if (!sampleDuration.isValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
|
||||
}
|
||||
|
||||
if (audio->mTime + sampleDuration.value() <= mTarget.GetTime().ToMicroseconds()) {
|
||||
|
@ -154,7 +154,7 @@ AccurateSeekTask::DropAudioUpToSeekTarget(MediaData* aSample)
|
|||
CheckedInt64 framesToPrune =
|
||||
UsecsToFrames(mTarget.GetTime().ToMicroseconds() - audio->mTime, mAudioRate);
|
||||
if (!framesToPrune.isValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
|
||||
}
|
||||
if (framesToPrune.value() > audio->mFrames) {
|
||||
// We've messed up somehow. Don't try to trim frames, the |frames|
|
||||
|
@ -174,7 +174,7 @@ AccurateSeekTask::DropAudioUpToSeekTarget(MediaData* aSample)
|
|||
frames * channels * sizeof(AudioDataValue));
|
||||
CheckedInt64 duration = FramesToUsecs(frames, mAudioRate);
|
||||
if (!duration.isValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
|
||||
}
|
||||
RefPtr<AudioData> data(new AudioData(audio->mOffset,
|
||||
mTarget.GetTime().ToMicroseconds(),
|
||||
|
@ -260,7 +260,7 @@ AccurateSeekTask::OnSeekRejected(nsresult aResult)
|
|||
|
||||
mSeekRequest.Complete();
|
||||
MOZ_ASSERT(NS_FAILED(aResult), "Cancels should also disconnect mSeekRequest");
|
||||
RejectIfExist(__func__);
|
||||
RejectIfExist(aResult, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -308,11 +308,14 @@ AccurateSeekTask::OnAudioDecoded(MediaData* aAudioSample)
|
|||
// Non-precise seek; we can stop the seek at the first sample.
|
||||
mSeekedAudioData = audio;
|
||||
mDoneAudioSeeking = true;
|
||||
} else if (NS_FAILED(DropAudioUpToSeekTarget(audio))) {
|
||||
} else {
|
||||
nsresult rv = DropAudioUpToSeekTarget(audio);
|
||||
if (NS_FAILED(rv)) {
|
||||
CancelCallbacks();
|
||||
RejectIfExist(__func__);
|
||||
RejectIfExist(rv, __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mDoneAudioSeeking) {
|
||||
RequestAudioData();
|
||||
|
@ -323,33 +326,26 @@ AccurateSeekTask::OnAudioDecoded(MediaData* aAudioSample)
|
|||
|
||||
void
|
||||
AccurateSeekTask::OnNotDecoded(MediaData::Type aType,
|
||||
MediaDecoderReader::NotDecodedReason aReason)
|
||||
const MediaResult& aError)
|
||||
{
|
||||
AssertOwnerThread();
|
||||
MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");
|
||||
|
||||
SAMPLE_LOG("OnNotDecoded type=%d reason=%u", aType, aReason);
|
||||
SAMPLE_LOG("OnNotDecoded type=%d reason=%u", aType, aError.Code());
|
||||
|
||||
// Ignore pending requests from video-only seek.
|
||||
if (aType == MediaData::AUDIO_DATA && mTarget.IsVideoOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aReason == MediaDecoderReader::DECODE_ERROR) {
|
||||
// If this is a decode error, delegate to the generic error path.
|
||||
CancelCallbacks();
|
||||
RejectIfExist(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the decoder is waiting for data, we tell it to call us back when the
|
||||
// data arrives.
|
||||
if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
|
||||
if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
|
||||
mReader->WaitForData(aType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aReason == MediaDecoderReader::CANCELED) {
|
||||
if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
|
||||
if (aType == MediaData::AUDIO_DATA) {
|
||||
RequestAudioData();
|
||||
} else {
|
||||
|
@ -358,7 +354,7 @@ AccurateSeekTask::OnNotDecoded(MediaData::Type aType,
|
|||
return;
|
||||
}
|
||||
|
||||
if (aReason == MediaDecoderReader::END_OF_STREAM) {
|
||||
if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
|
||||
if (aType == MediaData::AUDIO_DATA) {
|
||||
mIsAudioQueueFinished = true;
|
||||
mDoneAudioSeeking = true;
|
||||
|
@ -372,7 +368,12 @@ AccurateSeekTask::OnNotDecoded(MediaData::Type aType,
|
|||
}
|
||||
}
|
||||
MaybeFinishSeek();
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a decode error, delegate to the generic error path.
|
||||
CancelCallbacks();
|
||||
RejectIfExist(aError, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -395,11 +396,14 @@ AccurateSeekTask::OnVideoDecoded(MediaData* aVideoSample)
|
|||
// Non-precise seek. We can stop the seek at the first sample.
|
||||
mSeekedVideoData = video;
|
||||
mDoneVideoSeeking = true;
|
||||
} else if (NS_FAILED(DropVideoUpToSeekTarget(video.get()))) {
|
||||
} else {
|
||||
nsresult rv = DropVideoUpToSeekTarget(video.get());
|
||||
if (NS_FAILED(rv)) {
|
||||
CancelCallbacks();
|
||||
RejectIfExist(__func__);
|
||||
RejectIfExist(rv, __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mDoneVideoSeeking) {
|
||||
RequestVideoData();
|
||||
|
@ -419,7 +423,7 @@ AccurateSeekTask::SetCallbacks()
|
|||
OnAudioDecoded(aData.as<MediaData*>());
|
||||
} else {
|
||||
OnNotDecoded(MediaData::AUDIO_DATA,
|
||||
aData.as<MediaDecoderReader::NotDecodedReason>());
|
||||
aData.as<MediaResult>());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -430,7 +434,7 @@ AccurateSeekTask::SetCallbacks()
|
|||
OnVideoDecoded(Get<0>(aData.as<Type>()));
|
||||
} else {
|
||||
OnNotDecoded(MediaData::VIDEO_DATA,
|
||||
aData.as<MediaDecoderReader::NotDecodedReason>());
|
||||
aData.as<MediaResult>());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ private:
|
|||
|
||||
void OnVideoDecoded(MediaData* aVideoSample);
|
||||
|
||||
void OnNotDecoded(MediaData::Type, MediaDecoderReader::NotDecodedReason);
|
||||
void OnNotDecoded(MediaData::Type, const MediaResult&);
|
||||
|
||||
void SetCallbacks();
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ BenchmarkPlayback::DemuxSamples()
|
|||
}
|
||||
DemuxNextSample();
|
||||
},
|
||||
[this, ref](DemuxerFailureReason aReason) { MainThreadShutdown(); });
|
||||
[this, ref](const MediaResult& aError) { MainThreadShutdown(); });
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -190,9 +190,9 @@ BenchmarkPlayback::DemuxNextSample()
|
|||
Dispatch(NS_NewRunnableFunction([this, ref]() { DemuxNextSample(); }));
|
||||
}
|
||||
},
|
||||
[this, ref](DemuxerFailureReason aReason) {
|
||||
switch (aReason) {
|
||||
case DemuxerFailureReason::END_OF_STREAM:
|
||||
[this, ref](const MediaResult& aError) {
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
InitDecoder(Move(*mTrackDemuxer->GetInfo()));
|
||||
break;
|
||||
default:
|
||||
|
@ -218,7 +218,7 @@ BenchmarkPlayback::InitDecoder(TrackInfo&& aInfo)
|
|||
[this, ref](TrackInfo::TrackType aTrackType) {
|
||||
InputExhausted();
|
||||
},
|
||||
[this, ref](MediaDataDecoder::DecoderFailureReason aReason) {
|
||||
[this, ref](MediaResult aError) {
|
||||
MainThreadShutdown();
|
||||
});
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ BenchmarkPlayback::Output(MediaData* aData)
|
|||
}
|
||||
|
||||
void
|
||||
BenchmarkPlayback::Error(MediaDataDecoderError aError)
|
||||
BenchmarkPlayback::Error(const MediaResult& aError)
|
||||
{
|
||||
RefPtr<Benchmark> ref(mMainThreadState);
|
||||
Dispatch(NS_NewRunnableFunction([this, ref]() { MainThreadShutdown(); }));
|
||||
|
|
|
@ -32,7 +32,7 @@ class BenchmarkPlayback : public QueueObject, private MediaDataDecoderCallback
|
|||
// MediaDataDecoderCallback
|
||||
// Those methods are called on the MediaDataDecoder's task queue.
|
||||
void Output(MediaData* aData) override;
|
||||
void Error(MediaDataDecoderError aError) override;
|
||||
void Error(const MediaResult& aError) override;
|
||||
void InputExhausted() override;
|
||||
void DrainComplete() override;
|
||||
bool OnReaderTaskQueue() override;
|
||||
|
|
|
@ -55,7 +55,7 @@ MP3Demuxer::Init() {
|
|||
MP3LOG("MP3Demuxer::Init() failure: waiting for data");
|
||||
|
||||
return InitPromise::CreateAndReject(
|
||||
DemuxerFailureReason::DEMUXER_ERROR, __func__);
|
||||
NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
|
||||
}
|
||||
|
||||
MP3LOG("MP3Demuxer::Init() successful");
|
||||
|
@ -276,7 +276,7 @@ MP3TrackDemuxer::GetSamples(int32_t aNumSamples) {
|
|||
|
||||
if (!aNumSamples) {
|
||||
return SamplesPromise::CreateAndReject(
|
||||
DemuxerFailureReason::DEMUXER_ERROR, __func__);
|
||||
NS_ERROR_DOM_MEDIA_DEMUXER_ERR, __func__);
|
||||
}
|
||||
|
||||
RefPtr<SamplesHolder> frames = new SamplesHolder();
|
||||
|
@ -300,7 +300,7 @@ MP3TrackDemuxer::GetSamples(int32_t aNumSamples) {
|
|||
|
||||
if (frames->mSamples.IsEmpty()) {
|
||||
return SamplesPromise::CreateAndReject(
|
||||
DemuxerFailureReason::END_OF_STREAM, __func__);
|
||||
NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
}
|
||||
return SamplesPromise::CreateAndResolve(frames, __func__);
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ RefPtr<MP3TrackDemuxer::SkipAccessPointPromise>
|
|||
MP3TrackDemuxer::SkipToNextRandomAccessPoint(TimeUnit aTimeThreshold) {
|
||||
// Will not be called for audio-only resources.
|
||||
return SkipAccessPointPromise::CreateAndReject(
|
||||
SkipFailureHolder(DemuxerFailureReason::DEMUXER_ERROR, 0), __func__);
|
||||
SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "MediaData.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "MediaResult.h"
|
||||
#include "TimeUnits.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
@ -22,16 +23,6 @@ namespace mozilla {
|
|||
class MediaTrackDemuxer;
|
||||
class TrackMetadataHolder;
|
||||
|
||||
enum class DemuxerFailureReason : int8_t
|
||||
{
|
||||
WAITING_FOR_DATA,
|
||||
END_OF_STREAM,
|
||||
DEMUXER_ERROR,
|
||||
CANCELED,
|
||||
SHUTDOWN,
|
||||
};
|
||||
|
||||
|
||||
// Allows reading the media data: to retrieve the metadata and demux samples.
|
||||
// MediaDataDemuxer isn't designed to be thread safe.
|
||||
// When used by the MediaFormatDecoder, care is taken to ensure that the demuxer
|
||||
|
@ -41,7 +32,7 @@ class MediaDataDemuxer
|
|||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDataDemuxer)
|
||||
|
||||
typedef MozPromise<nsresult, DemuxerFailureReason, /* IsExclusive = */ true> InitPromise;
|
||||
typedef MozPromise<nsresult, MediaResult, /* IsExclusive = */ true> InitPromise;
|
||||
|
||||
// Initializes the demuxer. Other methods cannot be called unless
|
||||
// initialization has completed and succeeded.
|
||||
|
@ -120,16 +111,16 @@ public:
|
|||
|
||||
class SkipFailureHolder {
|
||||
public:
|
||||
SkipFailureHolder(DemuxerFailureReason aFailure, uint32_t aSkipped)
|
||||
SkipFailureHolder(const MediaResult& aFailure, uint32_t aSkipped)
|
||||
: mFailure(aFailure)
|
||||
, mSkipped(aSkipped)
|
||||
{}
|
||||
DemuxerFailureReason mFailure;
|
||||
MediaResult mFailure;
|
||||
uint32_t mSkipped;
|
||||
};
|
||||
|
||||
typedef MozPromise<media::TimeUnit, DemuxerFailureReason, /* IsExclusive = */ true> SeekPromise;
|
||||
typedef MozPromise<RefPtr<SamplesHolder>, DemuxerFailureReason, /* IsExclusive = */ true> SamplesPromise;
|
||||
typedef MozPromise<media::TimeUnit, MediaResult, /* IsExclusive = */ true> SeekPromise;
|
||||
typedef MozPromise<RefPtr<SamplesHolder>, MediaResult, /* IsExclusive = */ true> SamplesPromise;
|
||||
typedef MozPromise<uint32_t, SkipFailureHolder, /* IsExclusive = */ true> SkipAccessPointPromise;
|
||||
|
||||
// Returns the TrackInfo (a.k.a Track Description) for this track.
|
||||
|
|
|
@ -198,7 +198,7 @@ MediaDecoder::ResourceCallback::NotifyDecodeError()
|
|||
RefPtr<ResourceCallback> self = this;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
||||
if (self->mDecoder) {
|
||||
self->mDecoder->DecodeError();
|
||||
self->mDecoder->DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
}
|
||||
});
|
||||
AbstractThread::MainThread()->Dispatch(r.forget());
|
||||
|
@ -607,6 +607,7 @@ MediaDecoder::Shutdown()
|
|||
mMetadataLoadedListener.Disconnect();
|
||||
mFirstFrameLoadedListener.Disconnect();
|
||||
mOnPlaybackEvent.Disconnect();
|
||||
mOnPlaybackErrorEvent.Disconnect();
|
||||
mOnMediaNotSeekable.Disconnect();
|
||||
|
||||
mDecoderStateMachine->BeginShutdown()
|
||||
|
@ -661,9 +662,6 @@ MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
|
|||
case MediaEventType::SeekStarted:
|
||||
SeekingStarted();
|
||||
break;
|
||||
case MediaEventType::DecodeError:
|
||||
DecodeError();
|
||||
break;
|
||||
case MediaEventType::Invalidate:
|
||||
Invalidate();
|
||||
break;
|
||||
|
@ -676,6 +674,12 @@ MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError)
|
||||
{
|
||||
DecodeError(aError);
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoder::FinishShutdown()
|
||||
{
|
||||
|
@ -749,6 +753,8 @@ MediaDecoder::SetStateMachineParameters()
|
|||
|
||||
mOnPlaybackEvent = mDecoderStateMachine->OnPlaybackEvent().Connect(
|
||||
AbstractThread::MainThread(), this, &MediaDecoder::OnPlaybackEvent);
|
||||
mOnPlaybackErrorEvent = mDecoderStateMachine->OnPlaybackErrorEvent().Connect(
|
||||
AbstractThread::MainThread(), this, &MediaDecoder::OnPlaybackErrorEvent);
|
||||
mOnMediaNotSeekable = mDecoderStateMachine->OnMediaNotSeekable().Connect(
|
||||
AbstractThread::MainThread(), this, &MediaDecoder::OnMediaNotSeekable);
|
||||
}
|
||||
|
@ -1006,11 +1012,11 @@ MediaDecoder::NetworkError()
|
|||
}
|
||||
|
||||
void
|
||||
MediaDecoder::DecodeError()
|
||||
MediaDecoder::DecodeError(const MediaResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!IsShutdown());
|
||||
mOwner->DecodeError();
|
||||
mOwner->DecodeError(aError);
|
||||
MOZ_ASSERT(IsShutdown());
|
||||
}
|
||||
|
||||
|
|
|
@ -436,7 +436,7 @@ private:
|
|||
int64_t GetDownloadPosition();
|
||||
|
||||
// Notifies the element that decoding has failed.
|
||||
void DecodeError();
|
||||
void DecodeError(const MediaResult& aError);
|
||||
|
||||
// Indicate whether the media is same-origin with the element.
|
||||
void UpdateSameOriginStatus(bool aSameOrigin);
|
||||
|
@ -592,6 +592,7 @@ private:
|
|||
DataArrivedEvent() override { return &mDataArrivedEvent; }
|
||||
|
||||
void OnPlaybackEvent(MediaEventType aEvent);
|
||||
void OnPlaybackErrorEvent(const MediaResult& aError);
|
||||
|
||||
void OnMediaNotSeekable()
|
||||
{
|
||||
|
@ -731,6 +732,7 @@ protected:
|
|||
MediaEventListener mFirstFrameLoadedListener;
|
||||
|
||||
MediaEventListener mOnPlaybackEvent;
|
||||
MediaEventListener mOnPlaybackErrorEvent;
|
||||
MediaEventListener mOnMediaNotSeekable;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
namespace mozilla {
|
||||
|
||||
class VideoFrameContainer;
|
||||
class MediaResult;
|
||||
|
||||
namespace dom {
|
||||
class HTMLMediaElement;
|
||||
|
@ -67,7 +68,7 @@ public:
|
|||
// resource has a decode error during metadata loading or decoding.
|
||||
// The decoder owner should call Shutdown() on the decoder and drop the
|
||||
// reference to the decoder to prevent further calls into the decoder.
|
||||
virtual void DecodeError() = 0;
|
||||
virtual void DecodeError(const MediaResult& aError) = 0;
|
||||
|
||||
// Return true if media element error attribute is not null.
|
||||
virtual bool HasError() const = 0;
|
||||
|
|
|
@ -289,12 +289,12 @@ nsresult MediaDecoderReader::ResetDecode(TrackSet aTracks)
|
|||
{
|
||||
if (aTracks.contains(TrackInfo::kVideoTrack)) {
|
||||
VideoQueue().Reset();
|
||||
mBaseVideoPromise.RejectIfExists(CANCELED, __func__);
|
||||
mBaseVideoPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
if (aTracks.contains(TrackInfo::kAudioTrack)) {
|
||||
AudioQueue().Reset();
|
||||
mBaseAudioPromise.RejectIfExists(CANCELED, __func__);
|
||||
mBaseAudioPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -323,7 +323,7 @@ MediaDecoderReader::DecodeToFirstVideoData()
|
|||
p->Resolve(self->VideoQueue().PeekFront(), __func__);
|
||||
}, [p] () {
|
||||
// We don't have a way to differentiate EOS, error, and shutdown here. :-(
|
||||
p->Reject(END_OF_STREAM, __func__);
|
||||
p->Reject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
});
|
||||
|
||||
return p.forget();
|
||||
|
@ -360,8 +360,6 @@ MediaDecoderReader::GetBuffered()
|
|||
RefPtr<MediaDecoderReader::MetadataPromise>
|
||||
MediaDecoderReader::AsyncReadMetadata()
|
||||
{
|
||||
typedef ReadMetadataFailureReason Reason;
|
||||
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
DECODER_LOG("MediaDecoderReader::AsyncReadMetadata");
|
||||
|
||||
|
@ -374,7 +372,7 @@ MediaDecoderReader::AsyncReadMetadata()
|
|||
// error.
|
||||
if (NS_FAILED(rv) || !metadata->mInfo.HasValidMedia()) {
|
||||
DECODER_WARN("ReadMetadata failed, rv=%x HasValidMedia=%d", rv, metadata->mInfo.HasValidMedia());
|
||||
return MetadataPromise::CreateAndReject(Reason::METADATA_ERROR, __func__);
|
||||
return MetadataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
|
||||
}
|
||||
|
||||
// Success!
|
||||
|
@ -456,7 +454,7 @@ MediaDecoderReader::RequestVideoData(bool aSkipToNextKeyframe,
|
|||
RefPtr<VideoData> v = VideoQueue().PopFront();
|
||||
mBaseVideoPromise.Resolve(v, __func__);
|
||||
} else if (VideoQueue().IsFinished()) {
|
||||
mBaseVideoPromise.Reject(END_OF_STREAM, __func__);
|
||||
mBaseVideoPromise.Reject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Dropping this promise on the floor");
|
||||
}
|
||||
|
@ -488,7 +486,9 @@ MediaDecoderReader::RequestAudioData()
|
|||
RefPtr<AudioData> a = AudioQueue().PopFront();
|
||||
mBaseAudioPromise.Resolve(a, __func__);
|
||||
} else if (AudioQueue().IsFinished()) {
|
||||
mBaseAudioPromise.Reject(mHitAudioDecodeError ? DECODE_ERROR : END_OF_STREAM, __func__);
|
||||
mBaseAudioPromise.Reject(mHitAudioDecodeError
|
||||
? NS_ERROR_DOM_MEDIA_FATAL_ERR
|
||||
: NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
mHitAudioDecodeError = false;
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Dropping this promise on the floor");
|
||||
|
@ -503,8 +503,8 @@ MediaDecoderReader::Shutdown()
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
mShutdown = true;
|
||||
|
||||
mBaseAudioPromise.RejectIfExists(END_OF_STREAM, __func__);
|
||||
mBaseVideoPromise.RejectIfExists(END_OF_STREAM, __func__);
|
||||
mBaseAudioPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
mBaseVideoPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
|
||||
mDataArrivedListener.DisconnectIfExists();
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "AbstractMediaDecoder.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "MediaData.h"
|
||||
#include "MediaResult.h"
|
||||
#include "MediaMetadataManager.h"
|
||||
#include "MediaQueue.h"
|
||||
#include "MediaTimer.h"
|
||||
|
@ -50,11 +51,6 @@ private:
|
|||
virtual ~MetadataHolder() {}
|
||||
};
|
||||
|
||||
enum class ReadMetadataFailureReason : int8_t
|
||||
{
|
||||
METADATA_ERROR
|
||||
};
|
||||
|
||||
// Encapsulates the decoding and reading of media data. Reading can either
|
||||
// synchronous and done on the calling "decode" thread, or asynchronous and
|
||||
// performed on a background thread, with the result being returned by
|
||||
|
@ -68,19 +64,12 @@ class MediaDecoderReader {
|
|||
static const bool IsExclusive = true;
|
||||
|
||||
public:
|
||||
enum NotDecodedReason {
|
||||
END_OF_STREAM,
|
||||
DECODE_ERROR,
|
||||
WAITING_FOR_DATA,
|
||||
CANCELED
|
||||
};
|
||||
|
||||
using TrackSet = EnumSet<TrackInfo::TrackType>;
|
||||
|
||||
using MetadataPromise =
|
||||
MozPromise<RefPtr<MetadataHolder>, ReadMetadataFailureReason, IsExclusive>;
|
||||
MozPromise<RefPtr<MetadataHolder>, MediaResult, IsExclusive>;
|
||||
using MediaDataPromise =
|
||||
MozPromise<RefPtr<MediaData>, NotDecodedReason, IsExclusive>;
|
||||
MozPromise<RefPtr<MediaData>, MediaResult, IsExclusive>;
|
||||
using SeekPromise = MozPromise<media::TimeUnit, nsresult, IsExclusive>;
|
||||
|
||||
// Note that, conceptually, WaitForData makes sense in a non-exclusive sense.
|
||||
|
|
|
@ -76,22 +76,22 @@ public:
|
|||
p->Resolve(data, __func__);
|
||||
},
|
||||
[p] () {
|
||||
p->Reject(MediaDecoderReader::CANCELED, __func__);
|
||||
p->Reject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
});
|
||||
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
template<MediaData::Type SampleType>
|
||||
void FirstSampleRejected(MediaDecoderReader::NotDecodedReason aReason)
|
||||
void FirstSampleRejected(const MediaResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
||||
if (aReason == MediaDecoderReader::DECODE_ERROR) {
|
||||
mHaveStartTimePromise.RejectIfExists(false, __func__);
|
||||
} else if (aReason == MediaDecoderReader::END_OF_STREAM) {
|
||||
if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
|
||||
LOG("StartTimeRendezvous=%p SampleType(%d) Has no samples.",
|
||||
this, SampleType);
|
||||
MaybeSetChannelStartTime<SampleType>(INT64_MAX);
|
||||
} else if (aError != NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
|
||||
mHaveStartTimePromise.RejectIfExists(false, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,9 +200,9 @@ MediaDecoderReaderWrapper::RequestAudioData()
|
|||
aAudioSample->AdjustForStartTime(self->StartTime().ToMicroseconds());
|
||||
self->mAudioCallback.Notify(AsVariant(aAudioSample));
|
||||
},
|
||||
[self] (MediaDecoderReader::NotDecodedReason aReason) {
|
||||
[self] (const MediaResult& aError) {
|
||||
self->mAudioDataRequest.Complete();
|
||||
self->mAudioCallback.Notify(AsVariant(aReason));
|
||||
self->mAudioCallback.Notify(AsVariant(aError));
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -240,9 +240,9 @@ MediaDecoderReaderWrapper::RequestVideoData(bool aSkipToNextKeyframe,
|
|||
aVideoSample->AdjustForStartTime(self->StartTime().ToMicroseconds());
|
||||
self->mVideoCallback.Notify(AsVariant(MakeTuple(aVideoSample, videoDecodeStartTime)));
|
||||
},
|
||||
[self] (MediaDecoderReader::NotDecodedReason aReason) {
|
||||
[self] (const MediaResult& aError) {
|
||||
self->mVideoDataRequest.Complete();
|
||||
self->mVideoCallback.Notify(AsVariant(aReason));
|
||||
self->mVideoCallback.Notify(AsVariant(aError));
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ class StartTimeRendezvous;
|
|||
|
||||
typedef MozPromise<bool, bool, /* isExclusive = */ false> HaveStartTimePromise;
|
||||
|
||||
typedef Variant<MediaData*, MediaDecoderReader::NotDecodedReason> AudioCallbackData;
|
||||
typedef Variant<Tuple<MediaData*, TimeStamp>, MediaDecoderReader::NotDecodedReason> VideoCallbackData;
|
||||
typedef Variant<MediaData*, MediaResult> AudioCallbackData;
|
||||
typedef Variant<Tuple<MediaData*, TimeStamp>, MediaResult> VideoCallbackData;
|
||||
typedef Variant<MediaData::Type, WaitForDataRejectValue> WaitCallbackData;
|
||||
|
||||
/**
|
||||
|
|
|
@ -263,8 +263,8 @@ public:
|
|||
[this] (MetadataHolder* aMetadata) {
|
||||
OnMetadataRead(aMetadata);
|
||||
},
|
||||
[this] (ReadMetadataFailureReason aReason) {
|
||||
OnMetadataNotRead(aReason);
|
||||
[this] (const MediaResult& aError) {
|
||||
OnMetadataNotRead(aError);
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -355,11 +355,11 @@ private:
|
|||
SetState(DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
}
|
||||
|
||||
void OnMetadataNotRead(ReadMetadataFailureReason aReason)
|
||||
void OnMetadataNotRead(const MediaResult& aError)
|
||||
{
|
||||
mMetadataRequest.Complete();
|
||||
SWARN("Decode metadata failed, shutting down decoder");
|
||||
mMaster->DecodeError();
|
||||
mMaster->DecodeError(aError);
|
||||
}
|
||||
|
||||
MozPromiseRequestHolder<MediaDecoderReader::MetadataPromise> mMetadataRequest;
|
||||
|
@ -979,12 +979,12 @@ MediaDecoderStateMachine::OnVideoPopped(const RefPtr<MediaData>& aSample)
|
|||
|
||||
void
|
||||
MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
MediaDecoderReader::NotDecodedReason aReason)
|
||||
const MediaResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(mState != DECODER_STATE_SEEKING);
|
||||
|
||||
SAMPLE_LOG("OnNotDecoded (aType=%u, aReason=%u)", aType, aReason);
|
||||
SAMPLE_LOG("OnNotDecoded (aType=%u, aError=%u)", aType, aError.Code());
|
||||
bool isAudio = aType == MediaData::AUDIO_DATA;
|
||||
MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA);
|
||||
|
||||
|
@ -993,15 +993,9 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
|||
return;
|
||||
}
|
||||
|
||||
// If this is a decode error, delegate to the generic error path.
|
||||
if (aReason == MediaDecoderReader::DECODE_ERROR) {
|
||||
DecodeError();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the decoder is waiting for data, we tell it to call us back when the
|
||||
// data arrives.
|
||||
if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
|
||||
if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
|
||||
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
|
||||
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
|
||||
mReader->WaitForData(aType);
|
||||
|
@ -1017,7 +1011,7 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
|||
return;
|
||||
}
|
||||
|
||||
if (aReason == MediaDecoderReader::CANCELED) {
|
||||
if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
|
||||
if (isAudio) {
|
||||
EnsureAudioDecodeTaskQueued();
|
||||
} else {
|
||||
|
@ -1026,9 +1020,14 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
|||
return;
|
||||
}
|
||||
|
||||
// If this is a decode error, delegate to the generic error path.
|
||||
if (aError != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
|
||||
DecodeError(aError);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is an EOS. Finish off the queue, and then handle things based on our
|
||||
// state.
|
||||
MOZ_ASSERT(aReason == MediaDecoderReader::END_OF_STREAM);
|
||||
if (isAudio) {
|
||||
AudioQueue().Finish();
|
||||
StopPrerollingAudio();
|
||||
|
@ -1219,7 +1218,7 @@ MediaDecoderStateMachine::SetMediaDecoderReaderWrapperCallback()
|
|||
if (aData.is<MediaData*>()) {
|
||||
OnAudioDecoded(aData.as<MediaData*>());
|
||||
} else {
|
||||
OnNotDecoded(MediaData::AUDIO_DATA, aData.as<MediaDecoderReader::NotDecodedReason>());
|
||||
OnNotDecoded(MediaData::AUDIO_DATA, aData.as<MediaResult>());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1230,7 +1229,7 @@ MediaDecoderStateMachine::SetMediaDecoderReaderWrapperCallback()
|
|||
auto&& v = aData.as<Type>();
|
||||
OnVideoDecoded(Get<0>(v), Get<1>(v));
|
||||
} else {
|
||||
OnNotDecoded(MediaData::VIDEO_DATA, aData.as<MediaDecoderReader::NotDecodedReason>());
|
||||
OnNotDecoded(MediaData::VIDEO_DATA, aData.as<MediaResult>());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2083,7 +2082,7 @@ MediaDecoderStateMachine::OnSeekTaskRejected(SeekTaskRejectValue aValue)
|
|||
StopPrerollingVideo();
|
||||
}
|
||||
|
||||
DecodeError();
|
||||
DecodeError(aValue.mError);
|
||||
|
||||
DiscardSeekTaskIfExist();
|
||||
}
|
||||
|
@ -2292,13 +2291,13 @@ bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs)
|
|||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::DecodeError()
|
||||
MediaDecoderStateMachine::DecodeError(const MediaResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(!IsShutdown());
|
||||
DECODER_WARN("Decode error");
|
||||
// Notify the decode error and MediaDecoder will shut down MDSM.
|
||||
mOnPlaybackEvent.Notify(MediaEventType::DecodeError);
|
||||
mOnPlaybackErrorEvent.Notify(aError);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2919,7 +2918,7 @@ MediaDecoderStateMachine::OnMediaSinkVideoError()
|
|||
if (HasAudio()) {
|
||||
return;
|
||||
}
|
||||
DecodeError();
|
||||
DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::OnMediaSinkAudioComplete()
|
||||
|
@ -2950,7 +2949,7 @@ void MediaDecoderStateMachine::OnMediaSinkAudioError()
|
|||
|
||||
// Otherwise notify media decoder/element about this error for it makes
|
||||
// no sense to play an audio-only file without sound output.
|
||||
DecodeError();
|
||||
DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
|
|
|
@ -119,7 +119,6 @@ enum class MediaEventType : int8_t {
|
|||
PlaybackStopped,
|
||||
PlaybackEnded,
|
||||
SeekStarted,
|
||||
DecodeError,
|
||||
Invalidate,
|
||||
EnterVideoSuspend,
|
||||
ExitVideoSuspend
|
||||
|
@ -245,6 +244,8 @@ public:
|
|||
|
||||
MediaEventSource<MediaEventType>&
|
||||
OnPlaybackEvent() { return mOnPlaybackEvent; }
|
||||
MediaEventSource<MediaResult>&
|
||||
OnPlaybackErrorEvent() { return mOnPlaybackErrorEvent; }
|
||||
|
||||
size_t SizeOfVideoQueue() const;
|
||||
|
||||
|
@ -344,7 +345,7 @@ private:
|
|||
// Need to figure out a suitable API name for this case.
|
||||
void OnAudioDecoded(MediaData* aAudioSample);
|
||||
void OnVideoDecoded(MediaData* aVideoSample, TimeStamp aDecodeStartTime);
|
||||
void OnNotDecoded(MediaData::Type aType, MediaDecoderReader::NotDecodedReason aReason);
|
||||
void OnNotDecoded(MediaData::Type aType, const MediaResult& aError);
|
||||
|
||||
// Resets all state related to decoding and playback, emptying all buffers
|
||||
// and aborting all pending operations on the decode task queue.
|
||||
|
@ -481,7 +482,7 @@ protected:
|
|||
// event to the media element. This begins shutting down the decoder.
|
||||
// The decoder monitor must be held. This is only called on the
|
||||
// decode thread.
|
||||
void DecodeError();
|
||||
void DecodeError(const MediaResult& aError);
|
||||
|
||||
// Dispatches a LoadedMetadataEvent.
|
||||
// This is threadsafe and can be called on any thread.
|
||||
|
@ -892,6 +893,7 @@ private:
|
|||
MediaDecoderEventVisibility> mFirstFrameLoadedEvent;
|
||||
|
||||
MediaEventProducer<MediaEventType> mOnPlaybackEvent;
|
||||
MediaEventProducer<MediaResult> mOnPlaybackErrorEvent;
|
||||
|
||||
// True if audio is offloading.
|
||||
// Playback will not start when audio is offloading.
|
||||
|
|
|
@ -93,14 +93,14 @@ MediaFormatReader::Shutdown()
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
mDemuxerInitRequest.DisconnectIfExists();
|
||||
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mSeekPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
||||
mMetadataPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
mSeekPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
mSkipRequest.DisconnectIfExists();
|
||||
|
||||
if (mAudio.mDecoder) {
|
||||
Reset(TrackInfo::kAudioTrack);
|
||||
if (mAudio.HasPromise()) {
|
||||
mAudio.RejectPromise(CANCELED, __func__);
|
||||
mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
mAudio.ShutdownDecoder();
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ MediaFormatReader::Shutdown()
|
|||
if (mVideo.mDecoder) {
|
||||
Reset(TrackInfo::kVideoTrack);
|
||||
if (mVideo.HasPromise()) {
|
||||
mVideo.RejectPromise(CANCELED, __func__);
|
||||
mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
mVideo.ShutdownDecoder();
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
|
|||
// We currently only handle the first video track.
|
||||
mVideo.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
|
||||
if (!mVideo.mTrackDemuxer) {
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
|
|||
if (videoActive) {
|
||||
if (platform && !platform->SupportsMimeType(videoInfo->mMimeType, nullptr)) {
|
||||
// We have no decoder for this track. Error.
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
|
||||
return;
|
||||
}
|
||||
mInfo.mVideo = *videoInfo->GetAsVideoInfo();
|
||||
|
@ -312,7 +312,7 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
|
|||
if (audioActive) {
|
||||
mAudio.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
|
||||
if (!mAudio.mTrackDemuxer) {
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -364,7 +364,7 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
|
|||
mDemuxer->IsSeekableOnlyInBufferedRanges();
|
||||
|
||||
if (!videoActive && !audioActive) {
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -376,13 +376,13 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
|
|||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::OnDemuxerInitFailed(DemuxerFailureReason aFailure)
|
||||
MediaFormatReader::OnDemuxerInitFailed(const MediaResult& aError)
|
||||
{
|
||||
mDemuxerInitRequest.Complete();
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mMetadataPromise.Reject(aError, __func__);
|
||||
}
|
||||
|
||||
bool
|
||||
MediaResult
|
||||
MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
@ -391,19 +391,17 @@ MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
|
|||
auto& decoder = GetDecoderData(aTrack);
|
||||
|
||||
if (decoder.mDecoder) {
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mPlatform) {
|
||||
mPlatform = new PDMFactory();
|
||||
NS_ENSURE_TRUE(mPlatform, false);
|
||||
if (IsEncrypted()) {
|
||||
#ifdef MOZ_EME
|
||||
MOZ_ASSERT(mCDMProxy);
|
||||
mPlatform->SetCDMProxy(mCDMProxy);
|
||||
#else
|
||||
// EME not supported.
|
||||
return false;
|
||||
return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, "EME not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -443,10 +441,10 @@ MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
|
|||
}
|
||||
if (decoder.mDecoder ) {
|
||||
decoder.mDescription = decoder.mDecoder->GetDescriptionName();
|
||||
} else {
|
||||
decoder.mDescription = "error creating decoder";
|
||||
return NS_OK;
|
||||
}
|
||||
return decoder.mDecoder != nullptr;
|
||||
decoder.mDescription = "error creating decoder";
|
||||
return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, "error creating decoder");
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -479,11 +477,11 @@ MediaFormatReader::EnsureDecoderInitialized(TrackType aTrack)
|
|||
self->SetVideoDecodeThreshold();
|
||||
self->ScheduleUpdate(aTrack);
|
||||
},
|
||||
[self, aTrack] (MediaDataDecoder::DecoderFailureReason aResult) {
|
||||
[self, aTrack] (MediaResult aError) {
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mInitPromise.Complete();
|
||||
decoder.ShutdownDecoder();
|
||||
self->NotifyError(aTrack);
|
||||
self->NotifyError(aTrack, aError);
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
|
@ -534,21 +532,21 @@ MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe,
|
|||
|
||||
if (!HasVideo()) {
|
||||
LOG("called with no video track");
|
||||
return MediaDataPromise::CreateAndReject(DECODE_ERROR, __func__);
|
||||
return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
}
|
||||
|
||||
if (IsSeeking()) {
|
||||
LOG("called mid-seek. Rejecting.");
|
||||
return MediaDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
if (mShutdown) {
|
||||
NS_WARNING("RequestVideoData on shutdown MediaFormatReader!");
|
||||
return MediaDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
if (IsSuspended()) {
|
||||
return MediaDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
media::TimeUnit timeThreshold{media::TimeUnit::FromMicroseconds(aTimeThreshold)};
|
||||
|
@ -568,37 +566,33 @@ MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe,
|
|||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::OnDemuxFailed(TrackType aTrack, DemuxerFailureReason aFailure)
|
||||
MediaFormatReader::OnDemuxFailed(TrackType aTrack, const MediaResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOG("Failed to demux %s, failure:%d",
|
||||
aTrack == TrackType::kVideoTrack ? "video" : "audio", aFailure);
|
||||
LOG("Failed to demux %s, failure:%u",
|
||||
aTrack == TrackType::kVideoTrack ? "video" : "audio", aError.Code());
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mDemuxRequest.Complete();
|
||||
switch (aFailure) {
|
||||
case DemuxerFailureReason::END_OF_STREAM:
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
if (!decoder.mWaitingForData) {
|
||||
decoder.mNeedDraining = true;
|
||||
}
|
||||
NotifyEndOfStream(aTrack);
|
||||
break;
|
||||
case DemuxerFailureReason::DEMUXER_ERROR:
|
||||
NotifyError(aTrack);
|
||||
break;
|
||||
case DemuxerFailureReason::WAITING_FOR_DATA:
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
if (!decoder.mWaitingForData) {
|
||||
decoder.mNeedDraining = true;
|
||||
}
|
||||
NotifyWaitingForData(aTrack);
|
||||
break;
|
||||
case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH;
|
||||
case DemuxerFailureReason::SHUTDOWN:
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
if (decoder.HasPromise()) {
|
||||
decoder.RejectPromise(CANCELED, __func__);
|
||||
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
NotifyError(aTrack, aError);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -638,21 +632,21 @@ MediaFormatReader::RequestAudioData()
|
|||
|
||||
if (!HasAudio()) {
|
||||
LOG("called with no audio track");
|
||||
return MediaDataPromise::CreateAndReject(DECODE_ERROR, __func__);
|
||||
return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
}
|
||||
|
||||
if (IsSuspended()) {
|
||||
return MediaDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
if (IsSeeking()) {
|
||||
LOG("called mid-seek. Rejecting.");
|
||||
return MediaDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
if (mShutdown) {
|
||||
NS_WARNING("RequestAudioData on shutdown MediaFormatReader!");
|
||||
return MediaDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
RefPtr<MediaDataPromise> p = mAudio.EnsurePromise(__func__);
|
||||
|
@ -723,7 +717,7 @@ MediaFormatReader::NotifyDrainComplete(TrackType aTrack)
|
|||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::NotifyError(TrackType aTrack, MediaDataDecoderError aError)
|
||||
MediaFormatReader::NotifyError(TrackType aTrack, const MediaResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("%s Decoding error", TrackTypeToStr(aTrack));
|
||||
|
@ -938,9 +932,10 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!EnsureDecoderCreated(aTrack)) {
|
||||
MediaResult rv = EnsureDecoderCreated(aTrack);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Error constructing decoders");
|
||||
NotifyError(aTrack);
|
||||
NotifyError(aTrack, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1052,24 +1047,23 @@ MediaFormatReader::InternalSeek(TrackType aTrack, const InternalSeekTarget& aTar
|
|||
self->SetVideoDecodeThreshold();
|
||||
self->ScheduleUpdate(aTrack);
|
||||
},
|
||||
[self, aTrack] (DemuxerFailureReason aResult) {
|
||||
[self, aTrack] (const MediaResult& aError) {
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mSeekRequest.Complete();
|
||||
switch (aResult) {
|
||||
case DemuxerFailureReason::WAITING_FOR_DATA:
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
self->NotifyWaitingForData(aTrack);
|
||||
break;
|
||||
case DemuxerFailureReason::END_OF_STREAM:
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyEndOfStream(aTrack);
|
||||
break;
|
||||
case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH;
|
||||
case DemuxerFailureReason::SHUTDOWN:
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
decoder.mTimeThreshold.reset();
|
||||
break;
|
||||
default:
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyError(aTrack);
|
||||
self->NotifyError(aTrack, aError);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
@ -1205,7 +1199,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
}
|
||||
} else if (decoder.HasFatalError()) {
|
||||
LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
|
||||
decoder.RejectPromise(DECODE_ERROR, __func__);
|
||||
decoder.RejectPromise(decoder.mError.ref(), __func__);
|
||||
return;
|
||||
} else if (decoder.mDrainComplete) {
|
||||
bool wasDraining = decoder.mDraining;
|
||||
|
@ -1213,7 +1207,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
decoder.mDraining = false;
|
||||
if (decoder.mDemuxEOS) {
|
||||
LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
|
||||
decoder.RejectPromise(END_OF_STREAM, __func__);
|
||||
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
} else if (decoder.mWaitingForData) {
|
||||
if (wasDraining && decoder.mLastSampleTime &&
|
||||
!decoder.mNextStreamSourceID) {
|
||||
|
@ -1226,7 +1220,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
}
|
||||
if (!decoder.mReceivedNewData) {
|
||||
LOG("Rejecting %s promise: WAITING_FOR_DATA", TrackTypeToStr(aTrack));
|
||||
decoder.RejectPromise(WAITING_FOR_DATA, __func__);
|
||||
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
|
||||
}
|
||||
}
|
||||
// Now that draining has completed, we check if we have received
|
||||
|
@ -1243,7 +1237,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
// 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__);
|
||||
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1252,14 +1246,13 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
return;
|
||||
}
|
||||
|
||||
if (decoder.mError &&
|
||||
decoder.mError.ref() == MediaDataDecoderError::DECODE_ERROR) {
|
||||
if (decoder.mError && !decoder.HasFatalError()) {
|
||||
decoder.mDecodePending = false;
|
||||
decoder.mError.reset();
|
||||
if (++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
|
||||
NotifyError(aTrack);
|
||||
NotifyError(aTrack, decoder.mError.ref());
|
||||
return;
|
||||
}
|
||||
decoder.mError.reset();
|
||||
LOG("%s decoded error count %d", TrackTypeToStr(aTrack),
|
||||
decoder.mNumOfConsecutiveError);
|
||||
media::TimeUnit nextKeyframe;
|
||||
|
@ -1398,7 +1391,7 @@ MediaFormatReader::ResetDecode(TrackSet aTracks)
|
|||
mVideo.ResetDemuxer();
|
||||
Reset(TrackInfo::kVideoTrack);
|
||||
if (mVideo.HasPromise()) {
|
||||
mVideo.RejectPromise(CANCELED, __func__);
|
||||
mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1406,7 +1399,7 @@ MediaFormatReader::ResetDecode(TrackSet aTracks)
|
|||
mAudio.ResetDemuxer();
|
||||
Reset(TrackInfo::kAudioTrack);
|
||||
if (mAudio.HasPromise()) {
|
||||
mAudio.RejectPromise(CANCELED, __func__);
|
||||
mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1418,7 +1411,7 @@ MediaFormatReader::Output(TrackType aTrack, MediaData* aSample)
|
|||
{
|
||||
if (!aSample) {
|
||||
NS_WARNING("MediaFormatReader::Output() passed a null sample");
|
||||
Error(aTrack);
|
||||
Error(aTrack, MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, __func__));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1451,10 +1444,10 @@ MediaFormatReader::InputExhausted(TrackType aTrack)
|
|||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::Error(TrackType aTrack, MediaDataDecoderError aError)
|
||||
MediaFormatReader::Error(TrackType aTrack, const MediaResult& aError)
|
||||
{
|
||||
RefPtr<nsIRunnable> task =
|
||||
NewRunnableMethod<TrackType, MediaDataDecoderError>(
|
||||
NewRunnableMethod<TrackType, MediaResult>(
|
||||
this, &MediaFormatReader::NotifyError, aTrack, aError);
|
||||
OwnerThread()->Dispatch(task.forget());
|
||||
}
|
||||
|
@ -1567,9 +1560,9 @@ MediaFormatReader::OnVideoSkipFailed(MediaTrackDemuxer::SkipFailureHolder aFailu
|
|||
LOG("Skipping failed, skipped %u frames", aFailure.mSkipped);
|
||||
mSkipRequest.Complete();
|
||||
|
||||
switch (aFailure.mFailure) {
|
||||
case DemuxerFailureReason::END_OF_STREAM: MOZ_FALLTHROUGH;
|
||||
case DemuxerFailureReason::WAITING_FOR_DATA:
|
||||
switch (aFailure.mFailure.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
// Some frames may have been output by the decoder since we initiated the
|
||||
// videoskip process and we know they would be late.
|
||||
DropDecodedSamples(TrackInfo::kVideoTrack);
|
||||
|
@ -1577,14 +1570,13 @@ MediaFormatReader::OnVideoSkipFailed(MediaTrackDemuxer::SkipFailureHolder aFailu
|
|||
// normally.
|
||||
ScheduleUpdate(TrackInfo::kVideoTrack);
|
||||
break;
|
||||
case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH;
|
||||
case DemuxerFailureReason::SHUTDOWN:
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
if (mVideo.HasPromise()) {
|
||||
mVideo.RejectPromise(CANCELED, __func__);
|
||||
mVideo.RejectPromise(aFailure.mFailure, __func__);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NotifyError(TrackType::kVideoTrack);
|
||||
NotifyError(TrackType::kVideoTrack, aFailure.mFailure);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1696,17 +1688,17 @@ MediaFormatReader::AttemptSeek()
|
|||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::OnSeekFailed(TrackType aTrack, DemuxerFailureReason aResult)
|
||||
MediaFormatReader::OnSeekFailed(TrackType aTrack, const MediaResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("%s failure:%d", TrackTypeToStr(aTrack), aResult);
|
||||
LOGV("%s failure:%u", TrackTypeToStr(aTrack), aError.Code());
|
||||
if (aTrack == TrackType::kVideoTrack) {
|
||||
mVideo.mSeekRequest.Complete();
|
||||
} else {
|
||||
mAudio.mSeekRequest.Complete();
|
||||
}
|
||||
|
||||
if (aResult == DemuxerFailureReason::WAITING_FOR_DATA) {
|
||||
if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
|
||||
if (HasVideo() && aTrack == TrackType::kAudioTrack &&
|
||||
mFallbackSeekTime.isSome() &&
|
||||
mPendingSeekTime.ref() != mFallbackSeekTime.ref()) {
|
||||
|
@ -1740,7 +1732,7 @@ MediaFormatReader::OnSeekFailed(TrackType aTrack, DemuxerFailureReason aResult)
|
|||
}
|
||||
MOZ_ASSERT(!mVideo.mSeekRequest.Exists() && !mAudio.mSeekRequest.Exists());
|
||||
mPendingSeekTime.reset();
|
||||
mSeekPromise.Reject(NS_ERROR_FAILURE, __func__);
|
||||
mSeekPromise.Reject(aError, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1781,10 +1773,10 @@ MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime)
|
|||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::OnVideoSeekFailed(DemuxerFailureReason aFailure)
|
||||
MediaFormatReader::OnVideoSeekFailed(const MediaResult& aError)
|
||||
{
|
||||
mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
|
||||
OnSeekFailed(TrackType::kVideoTrack, aFailure);
|
||||
OnSeekFailed(TrackType::kVideoTrack, aError);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1848,9 +1840,9 @@ MediaFormatReader::OnAudioSeekCompleted(media::TimeUnit aTime)
|
|||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::OnAudioSeekFailed(DemuxerFailureReason aFailure)
|
||||
MediaFormatReader::OnAudioSeekFailed(const MediaResult& aError)
|
||||
{
|
||||
OnSeekFailed(TrackType::kAudioTrack, aFailure);
|
||||
OnSeekFailed(TrackType::kAudioTrack, aError);
|
||||
}
|
||||
|
||||
media::TimeIntervals
|
||||
|
|
|
@ -117,7 +117,7 @@ private:
|
|||
void NotifyDemuxer();
|
||||
void ReturnOutput(MediaData* aData, TrackType aTrack);
|
||||
|
||||
bool EnsureDecoderCreated(TrackType aTrack);
|
||||
MediaResult EnsureDecoderCreated(TrackType aTrack);
|
||||
bool EnsureDecoderInitialized(TrackType aTrack);
|
||||
|
||||
// Enqueues a task to call Update(aTrack) on the decoder task queue.
|
||||
|
@ -166,7 +166,7 @@ private:
|
|||
void NotifyNewOutput(TrackType aTrack, MediaData* aSample);
|
||||
void NotifyInputExhausted(TrackType aTrack);
|
||||
void NotifyDrainComplete(TrackType aTrack);
|
||||
void NotifyError(TrackType aTrack, MediaDataDecoderError aError = MediaDataDecoderError::FATAL_ERROR);
|
||||
void NotifyError(TrackType aTrack, const MediaResult& aError);
|
||||
void NotifyWaitingForData(TrackType aTrack);
|
||||
void NotifyEndOfStream(TrackType aTrack);
|
||||
|
||||
|
@ -179,7 +179,7 @@ private:
|
|||
// functions.
|
||||
void Output(TrackType aType, MediaData* aSample);
|
||||
void InputExhausted(TrackType aTrack);
|
||||
void Error(TrackType aTrack, MediaDataDecoderError aError = MediaDataDecoderError::FATAL_ERROR);
|
||||
void Error(TrackType aTrack, const MediaResult& aError);
|
||||
void Reset(TrackType aTrack);
|
||||
void DrainComplete(TrackType aTrack);
|
||||
void DropDecodedSamples(TrackType aTrack);
|
||||
|
@ -206,7 +206,7 @@ private:
|
|||
void InputExhausted() override {
|
||||
mReader->InputExhausted(mType);
|
||||
}
|
||||
void Error(MediaDataDecoderError aError) override {
|
||||
void Error(const MediaResult& aError) override {
|
||||
mReader->Error(mType, aError);
|
||||
}
|
||||
void DrainComplete() override {
|
||||
|
@ -327,10 +327,10 @@ private:
|
|||
uint32_t mNumOfConsecutiveError;
|
||||
uint32_t mMaxConsecutiveError;
|
||||
|
||||
Maybe<MediaDataDecoderError> mError;
|
||||
Maybe<MediaResult> mError;
|
||||
bool HasFatalError() const
|
||||
{
|
||||
return mError.isSome() && mError.ref() == MediaDataDecoderError::FATAL_ERROR;
|
||||
return mError.isSome() && mError.ref() != NS_ERROR_DOM_MEDIA_DECODE_ERR;
|
||||
}
|
||||
|
||||
// If set, all decoded samples prior mTimeThreshold will be dropped.
|
||||
|
@ -354,7 +354,7 @@ private:
|
|||
virtual bool HasPromise() const = 0;
|
||||
virtual RefPtr<MediaDataPromise> EnsurePromise(const char* aMethodName) = 0;
|
||||
virtual void ResolvePromise(MediaData* aData, const char* aMethodName) = 0;
|
||||
virtual void RejectPromise(MediaDecoderReader::NotDecodedReason aReason,
|
||||
virtual void RejectPromise(const MediaResult& aError,
|
||||
const char* aMethodName) = 0;
|
||||
|
||||
// Clear track demuxer related data.
|
||||
|
@ -462,11 +462,11 @@ private:
|
|||
mHasPromise = false;
|
||||
}
|
||||
|
||||
void RejectPromise(MediaDecoderReader::NotDecodedReason aReason,
|
||||
void RejectPromise(const MediaResult& aError,
|
||||
const char* aMethodName) override
|
||||
{
|
||||
MOZ_ASSERT(mOwner->OnTaskQueue());
|
||||
mPromise.Reject(aReason, aMethodName);
|
||||
mPromise.Reject(aError, aMethodName);
|
||||
mHasPromise = false;
|
||||
}
|
||||
|
||||
|
@ -487,22 +487,22 @@ private:
|
|||
RefPtr<MediaDataDemuxer> mDemuxer;
|
||||
bool mDemuxerInitDone;
|
||||
void OnDemuxerInitDone(nsresult);
|
||||
void OnDemuxerInitFailed(DemuxerFailureReason aFailure);
|
||||
void OnDemuxerInitFailed(const MediaResult& aError);
|
||||
MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest;
|
||||
void OnDemuxFailed(TrackType aTrack, DemuxerFailureReason aFailure);
|
||||
void OnDemuxFailed(TrackType aTrack, const MediaResult& aError);
|
||||
|
||||
void DoDemuxVideo();
|
||||
void OnVideoDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
|
||||
void OnVideoDemuxFailed(DemuxerFailureReason aFailure)
|
||||
void OnVideoDemuxFailed(const MediaResult& aError)
|
||||
{
|
||||
OnDemuxFailed(TrackType::kVideoTrack, aFailure);
|
||||
OnDemuxFailed(TrackType::kVideoTrack, aError);
|
||||
}
|
||||
|
||||
void DoDemuxAudio();
|
||||
void OnAudioDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);
|
||||
void OnAudioDemuxFailed(DemuxerFailureReason aFailure)
|
||||
void OnAudioDemuxFailed(const MediaResult& aError)
|
||||
{
|
||||
OnDemuxFailed(TrackType::kAudioTrack, aFailure);
|
||||
OnDemuxFailed(TrackType::kAudioTrack, aError);
|
||||
}
|
||||
|
||||
void SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold);
|
||||
|
@ -550,15 +550,15 @@ private:
|
|||
}
|
||||
void ScheduleSeek();
|
||||
void AttemptSeek();
|
||||
void OnSeekFailed(TrackType aTrack, DemuxerFailureReason aFailure);
|
||||
void OnSeekFailed(TrackType aTrack, const MediaResult& aError);
|
||||
void DoVideoSeek();
|
||||
void OnVideoSeekCompleted(media::TimeUnit aTime);
|
||||
void OnVideoSeekFailed(DemuxerFailureReason aFailure);
|
||||
void OnVideoSeekFailed(const MediaResult& aError);
|
||||
bool mSeekScheduled;
|
||||
|
||||
void DoAudioSeek();
|
||||
void OnAudioSeekCompleted(media::TimeUnit aTime);
|
||||
void OnAudioSeekFailed(DemuxerFailureReason aFailure);
|
||||
void OnAudioSeekFailed(const MediaResult& aError);
|
||||
// The SeekTarget that was last given to Seek()
|
||||
SeekTarget mOriginalSeekTarget;
|
||||
// Temporary seek information while we wait for the data
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MediaResult_h_
|
||||
#define MediaResult_h_
|
||||
|
||||
#include "nsError.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
// MediaResult can be used interchangeably with nsresult.
|
||||
// It allows to store extra information such as where the error occurred.
|
||||
// While nsresult is typically passed by value; due to its potential size, using
|
||||
// MediaResult const references is recommended.
|
||||
namespace mozilla {
|
||||
|
||||
class MediaResult
|
||||
{
|
||||
public:
|
||||
MOZ_IMPLICIT MediaResult(nsresult aResult)
|
||||
: mCode(aResult)
|
||||
{
|
||||
}
|
||||
MediaResult(nsresult aResult, const nsACString& aMessage)
|
||||
: mCode(aResult)
|
||||
, mMessage(aMessage)
|
||||
{
|
||||
}
|
||||
MediaResult(nsresult aResult, const char* aMessage)
|
||||
: mCode(aResult)
|
||||
, mMessage(aMessage)
|
||||
{
|
||||
}
|
||||
MediaResult(const MediaResult& aOther) = default;
|
||||
MediaResult(MediaResult&& aOther) = default;
|
||||
MediaResult& operator=(const MediaResult& aOther) = default;
|
||||
MediaResult& operator=(MediaResult&& aOther) = default;
|
||||
|
||||
nsresult Code() const { return mCode; }
|
||||
const nsCString& Message() const { return mMessage; }
|
||||
|
||||
// Interoperations with nsresult.
|
||||
bool operator==(nsresult aResult) const { return aResult == mCode; }
|
||||
bool operator!=(nsresult aResult) const { return aResult != mCode; }
|
||||
operator nsresult () const { return mCode; }
|
||||
|
||||
nsCString Description() const
|
||||
{
|
||||
return nsPrintfCString("0x%08x: %s", mCode, mMessage.get());
|
||||
}
|
||||
|
||||
private:
|
||||
nsresult mCode;
|
||||
nsCString mMessage;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
#endif // MediaResult_h_
|
|
@ -53,7 +53,7 @@ NextFrameSeekTask::Discard()
|
|||
AssertOwnerThread();
|
||||
|
||||
// Disconnect MDSM.
|
||||
RejectIfExist(__func__);
|
||||
RejectIfExist(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
|
||||
// Disconnect MediaDecoderReader.
|
||||
CancelCallbacks();
|
||||
|
@ -183,12 +183,12 @@ NextFrameSeekTask::OnAudioDecoded(MediaData* aAudioSample)
|
|||
}
|
||||
|
||||
void
|
||||
NextFrameSeekTask::OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
|
||||
NextFrameSeekTask::OnAudioNotDecoded(const MediaResult& aError)
|
||||
{
|
||||
AssertOwnerThread();
|
||||
MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");
|
||||
|
||||
SAMPLE_LOG("OnAudioNotDecoded (aReason=%u)", aReason);
|
||||
SAMPLE_LOG("OnAudioNotDecoded (aError=%u)", aError.Code());
|
||||
|
||||
// We don't really handle audio deocde error here. Let MDSM to trigger further
|
||||
// audio decoding tasks if it needs to play audio, and MDSM will then receive
|
||||
|
@ -224,36 +224,36 @@ NextFrameSeekTask::OnVideoDecoded(MediaData* aVideoSample)
|
|||
}
|
||||
|
||||
void
|
||||
NextFrameSeekTask::OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
|
||||
NextFrameSeekTask::OnVideoNotDecoded(const MediaResult& aError)
|
||||
{
|
||||
AssertOwnerThread();
|
||||
MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");
|
||||
|
||||
SAMPLE_LOG("OnVideoNotDecoded (aReason=%u)", aReason);
|
||||
SAMPLE_LOG("OnVideoNotDecoded (aError=%u)", aError.Code());
|
||||
|
||||
if (aReason == MediaDecoderReader::END_OF_STREAM) {
|
||||
if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
|
||||
mIsVideoQueueFinished = true;
|
||||
}
|
||||
|
||||
// Video seek not finished.
|
||||
if (NeedMoreVideo()) {
|
||||
switch (aReason) {
|
||||
case MediaDecoderReader::DECODE_ERROR:
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
mReader->WaitForData(MediaData::VIDEO_DATA);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
RequestVideoData();
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
MOZ_ASSERT(false, "Shouldn't want more data for ended video.");
|
||||
break;
|
||||
default:
|
||||
// We might lose the audio sample after canceling the callbacks.
|
||||
// However it doesn't really matter because MDSM is gonna shut down
|
||||
// when seek fails.
|
||||
CancelCallbacks();
|
||||
// Reject the promise since we can't finish video seek anyway.
|
||||
RejectIfExist(__func__);
|
||||
break;
|
||||
case MediaDecoderReader::WAITING_FOR_DATA:
|
||||
mReader->WaitForData(MediaData::VIDEO_DATA);
|
||||
break;
|
||||
case MediaDecoderReader::CANCELED:
|
||||
RequestVideoData();
|
||||
break;
|
||||
case MediaDecoderReader::END_OF_STREAM:
|
||||
MOZ_ASSERT(false, "Shouldn't want more data for ended video.");
|
||||
RejectIfExist(aError, __func__);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
@ -274,7 +274,7 @@ NextFrameSeekTask::SetCallbacks()
|
|||
if (aData.is<MediaData*>()) {
|
||||
OnAudioDecoded(aData.as<MediaData*>());
|
||||
} else {
|
||||
OnAudioNotDecoded(aData.as<MediaDecoderReader::NotDecodedReason>());
|
||||
OnAudioNotDecoded(aData.as<MediaResult>());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -284,7 +284,7 @@ NextFrameSeekTask::SetCallbacks()
|
|||
if (aData.is<Type>()) {
|
||||
OnVideoDecoded(Get<0>(aData.as<Type>()));
|
||||
} else {
|
||||
OnVideoNotDecoded(aData.as<MediaDecoderReader::NotDecodedReason>());
|
||||
OnVideoNotDecoded(aData.as<MediaResult>());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -303,7 +303,7 @@ NextFrameSeekTask::SetCallbacks()
|
|||
} else {
|
||||
// Reject if we can't finish video seeking.
|
||||
CancelCallbacks();
|
||||
RejectIfExist(__func__);
|
||||
RejectIfExist(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -57,11 +57,11 @@ private:
|
|||
|
||||
void OnAudioDecoded(MediaData* aAudioSample);
|
||||
|
||||
void OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
|
||||
void OnAudioNotDecoded(const MediaResult& aError);
|
||||
|
||||
void OnVideoDecoded(MediaData* aVideoSample);
|
||||
|
||||
void OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
|
||||
void OnVideoNotDecoded(const MediaResult& aError);
|
||||
|
||||
void SetCallbacks();
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче