mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Merge autoland to m-c. a=merge
This commit is contained in:
commit
4eacb032f5
@ -146,12 +146,12 @@ static int do_main(int argc, char* argv[])
|
||||
Output("Couldn't read application.ini");
|
||||
return 255;
|
||||
}
|
||||
int result = XRE_main(argc, argv, appData, 0);
|
||||
int result = XRE_main(argc, argv, appData);
|
||||
XRE_FreeAppData(appData);
|
||||
return result;
|
||||
}
|
||||
|
||||
return XRE_main(argc, argv, &sAppData, 0);
|
||||
return XRE_main(argc, argv, &sAppData);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
@ -192,9 +192,6 @@ int main(int argc, char* argv[])
|
||||
DllBlocklist_Initialize();
|
||||
#endif
|
||||
|
||||
// We do this because of data in bug 771745
|
||||
XPCOMGlueEnablePreload();
|
||||
|
||||
rv = XPCOMGlueStartup(exePath);
|
||||
if (NS_FAILED(rv)) {
|
||||
Output("Couldn't load XPCOM.\n");
|
||||
|
@ -161,40 +161,7 @@ static bool IsArg(const char* arg, const char* s)
|
||||
return false;
|
||||
}
|
||||
|
||||
XRE_GetFileFromPathType XRE_GetFileFromPath;
|
||||
XRE_ParseAppDataType XRE_ParseAppData;
|
||||
XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
|
||||
XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
|
||||
XRE_mainType XRE_main;
|
||||
XRE_StopLateWriteChecksType XRE_StopLateWriteChecks;
|
||||
XRE_XPCShellMainType XRE_XPCShellMain;
|
||||
XRE_GetProcessTypeType XRE_GetProcessType;
|
||||
XRE_SetProcessTypeType XRE_SetProcessType;
|
||||
XRE_InitChildProcessType XRE_InitChildProcess;
|
||||
XRE_EnableSameExecutableForContentProcType XRE_EnableSameExecutableForContentProc;
|
||||
#ifdef LIBFUZZER
|
||||
XRE_LibFuzzerSetMainType XRE_LibFuzzerSetMain;
|
||||
XRE_LibFuzzerGetFuncsType XRE_LibFuzzerGetFuncs;
|
||||
#endif
|
||||
|
||||
static const nsDynamicFunctionLoad kXULFuncs[] = {
|
||||
{ "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
|
||||
{ "XRE_ParseAppData", (NSFuncPtr*) &XRE_ParseAppData },
|
||||
{ "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
|
||||
{ "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
|
||||
{ "XRE_main", (NSFuncPtr*) &XRE_main },
|
||||
{ "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks },
|
||||
{ "XRE_XPCShellMain", (NSFuncPtr*) &XRE_XPCShellMain },
|
||||
{ "XRE_GetProcessType", (NSFuncPtr*) &XRE_GetProcessType },
|
||||
{ "XRE_SetProcessType", (NSFuncPtr*) &XRE_SetProcessType },
|
||||
{ "XRE_InitChildProcess", (NSFuncPtr*) &XRE_InitChildProcess },
|
||||
{ "XRE_EnableSameExecutableForContentProc", (NSFuncPtr*) &XRE_EnableSameExecutableForContentProc },
|
||||
#ifdef LIBFUZZER
|
||||
{ "XRE_LibFuzzerSetMain", (NSFuncPtr*) &XRE_LibFuzzerSetMain },
|
||||
{ "XRE_LibFuzzerGetFuncs", (NSFuncPtr*) &XRE_LibFuzzerGetFuncs },
|
||||
#endif
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
Bootstrap::UniquePtr gBootstrap;
|
||||
|
||||
#ifdef LIBFUZZER
|
||||
int libfuzzer_main(int argc, char **argv);
|
||||
@ -203,37 +170,22 @@ int libfuzzer_main(int argc, char **argv);
|
||||
|
||||
void libFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc,
|
||||
LibFuzzerTestingFunc* testingFunc) {
|
||||
return XRE_LibFuzzerGetFuncs(moduleName, initFunc, testingFunc);
|
||||
return gBootstrap->XRE_LibFuzzerGetFuncs(moduleName, initFunc, testingFunc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory)
|
||||
static int do_main(int argc, char* argv[], char* envp[])
|
||||
{
|
||||
nsCOMPtr<nsIFile> appini;
|
||||
nsresult rv;
|
||||
uint32_t mainFlags = 0;
|
||||
|
||||
// Allow firefox.exe to launch XULRunner apps via -app <application.ini>
|
||||
// Note that -app must be the *first* argument.
|
||||
const char *appDataFile = getenv("XUL_APP_FILE");
|
||||
if (appDataFile && *appDataFile) {
|
||||
rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini));
|
||||
if (NS_FAILED(rv)) {
|
||||
Output("Invalid path found: '%s'", appDataFile);
|
||||
return 255;
|
||||
}
|
||||
}
|
||||
else if (argc > 1 && IsArg(argv[1], "app")) {
|
||||
if ((!appDataFile || !*appDataFile) &&
|
||||
(argc > 1 && IsArg(argv[1], "app"))) {
|
||||
if (argc == 2) {
|
||||
Output("Incorrect number of arguments passed to -app");
|
||||
return 255;
|
||||
}
|
||||
|
||||
rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini));
|
||||
if (NS_FAILED(rv)) {
|
||||
Output("application.ini path not recognized: '%s'", argv[2]);
|
||||
return 255;
|
||||
}
|
||||
appDataFile = argv[2];
|
||||
|
||||
char appEnv[MAXPATHLEN];
|
||||
SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]);
|
||||
@ -255,50 +207,20 @@ static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory)
|
||||
sandboxing::GetInitializedBrokerServices();
|
||||
#endif
|
||||
|
||||
return XRE_XPCShellMain(--argc, argv, envp, &shellData);
|
||||
return gBootstrap->XRE_XPCShellMain(--argc, argv, envp, &shellData);
|
||||
}
|
||||
|
||||
XREAppData appData;
|
||||
appData.xreDirectory = xreDirectory;
|
||||
BootstrapConfig config;
|
||||
|
||||
if (appini) {
|
||||
rv = XRE_ParseAppData(appini, appData);
|
||||
if (NS_FAILED(rv)) {
|
||||
Output("Couldn't read application.ini");
|
||||
return 255;
|
||||
}
|
||||
|
||||
appini->GetParent(getter_AddRefs(appData.directory));
|
||||
if (appDataFile && *appDataFile) {
|
||||
config.appData = nullptr;
|
||||
config.appDataPath = appDataFile;
|
||||
} else {
|
||||
// no -app flag so we use the compiled-in app data
|
||||
appData = sAppData;
|
||||
|
||||
nsCOMPtr<nsIFile> exeFile;
|
||||
rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
Output("Couldn't find the application directory.\n");
|
||||
return 255;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> greDir;
|
||||
exeFile->GetParent(getter_AddRefs(greDir));
|
||||
#ifdef XP_MACOSX
|
||||
greDir->SetNativeLeafName(NS_LITERAL_CSTRING(kOSXResourcesFolder));
|
||||
#endif
|
||||
nsCOMPtr<nsIFile> appSubdir;
|
||||
greDir->Clone(getter_AddRefs(appSubdir));
|
||||
appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder));
|
||||
appData.directory = appSubdir;
|
||||
config.appData = &sAppData;
|
||||
config.appDataPath = kDesktopFolder;
|
||||
}
|
||||
|
||||
#if defined(HAS_DLL_BLOCKLIST)
|
||||
// The dll blocklist operates in the exe vs. xullib. Pass a flag to
|
||||
// xullib so automated tests can check the result once the browser
|
||||
// is up and running.
|
||||
appData.flags |=
|
||||
DllBlocklist_CheckStatus() ? NS_XRE_DLL_BLOCKLIST_ENABLED : 0;
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
sandbox::BrokerServices* brokerServices =
|
||||
sandboxing::GetInitializedBrokerServices();
|
||||
@ -308,15 +230,15 @@ static int do_main(int argc, char* argv[], char* envp[], nsIFile *xreDirectory)
|
||||
return 255;
|
||||
}
|
||||
#endif
|
||||
appData.sandboxBrokerServices = brokerServices;
|
||||
config.sandboxBrokerServices = brokerServices;
|
||||
#endif
|
||||
|
||||
#ifdef LIBFUZZER
|
||||
if (getenv("LIBFUZZER"))
|
||||
XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main);
|
||||
gBootstrap->XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main);
|
||||
#endif
|
||||
|
||||
return XRE_main(argc, argv, appData, mainFlags);
|
||||
return gBootstrap->XRE_main(argc, argv, config);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -333,7 +255,7 @@ FileExists(const char *path)
|
||||
}
|
||||
|
||||
static nsresult
|
||||
InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory)
|
||||
InitXPCOMGlue(const char *argv0)
|
||||
{
|
||||
char exePath[MAXPATHLEN];
|
||||
|
||||
@ -355,41 +277,16 @@ InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// We do this because of data in bug 771745
|
||||
XPCOMGlueEnablePreload();
|
||||
|
||||
rv = XPCOMGlueStartup(exePath);
|
||||
if (NS_FAILED(rv)) {
|
||||
gBootstrap = mozilla::GetBootstrap(exePath);
|
||||
if (!gBootstrap) {
|
||||
Output("Couldn't load XPCOM.\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
|
||||
if (NS_FAILED(rv)) {
|
||||
Output("Couldn't load XRE functions.\n");
|
||||
return rv;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// This will set this thread as the main thread.
|
||||
NS_LogInit();
|
||||
gBootstrap->NS_LogInit();
|
||||
|
||||
if (xreDirectory) {
|
||||
// chop XPCOM_DLL off exePath
|
||||
*lastSlash = '\0';
|
||||
#ifdef XP_MACOSX
|
||||
lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
|
||||
strcpy(lastSlash + 1, kOSXResourcesFolder);
|
||||
#endif
|
||||
#ifdef XP_WIN
|
||||
rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false,
|
||||
xreDirectory);
|
||||
#else
|
||||
rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false,
|
||||
xreDirectory);
|
||||
#endif
|
||||
}
|
||||
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[], char* envp[])
|
||||
@ -421,38 +318,35 @@ int main(int argc, char* argv[], char* envp[])
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult rv = InitXPCOMGlue(argv[0], nullptr);
|
||||
nsresult rv = InitXPCOMGlue(argv[0]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
int result = content_process_main(argc, argv);
|
||||
int result = content_process_main(gBootstrap.get(), argc, argv);
|
||||
|
||||
// InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
|
||||
NS_LogTerm();
|
||||
gBootstrap->NS_LogTerm();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
nsCOMPtr<nsIFile> xreDirectory;
|
||||
|
||||
nsresult rv = InitXPCOMGlue(argv[0], getter_AddRefs(xreDirectory));
|
||||
nsresult rv = InitXPCOMGlue(argv[0]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
|
||||
gBootstrap->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
|
||||
|
||||
#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
|
||||
XRE_EnableSameExecutableForContentProc();
|
||||
gBootstrap->XRE_EnableSameExecutableForContentProc();
|
||||
#endif
|
||||
|
||||
int result = do_main(argc, argv, envp, xreDirectory);
|
||||
int result = do_main(argc, argv, envp);
|
||||
|
||||
xreDirectory = nullptr;
|
||||
NS_LogTerm();
|
||||
gBootstrap->NS_LogTerm();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// Allow writes again. While we would like to catch writes from static
|
||||
@ -460,8 +354,10 @@ int main(int argc, char* argv[], char* envp[])
|
||||
// at least one such write that we don't control (see bug 826029). For
|
||||
// now we enable writes again and early exits will have to use exit instead
|
||||
// of _exit.
|
||||
XRE_StopLateWriteChecks();
|
||||
gBootstrap->XRE_StopLateWriteChecks();
|
||||
#endif
|
||||
|
||||
gBootstrap.reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ pref("lightweightThemes.update.enabled", true);
|
||||
pref("lightweightThemes.getMoreURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes");
|
||||
pref("lightweightThemes.recommendedThemes", "[{\"id\":\"recommended-1\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/a-web-browser-renaissance/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.footer.jpg\",\"textcolor\":\"#000000\",\"accentcolor\":\"#f2d9b1\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.preview.jpg\",\"author\":\"Sean.Martell\",\"version\":\"0\"},{\"id\":\"recommended-2\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/space-fantasy/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.footer.jpg\",\"textcolor\":\"#ffffff\",\"accentcolor\":\"#d9d9d9\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.preview.jpg\",\"author\":\"fx5800p\",\"version\":\"1.0\"},{\"id\":\"recommended-3\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/linen-light/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.footer.png\",\"accentcolor\":\"#ada8a8\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.preview.png\",\"author\":\"DVemer\",\"version\":\"1.0\"},{\"id\":\"recommended-4\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/pastel-gradient/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.footer.png\",\"textcolor\":\"#000000\",\"accentcolor\":\"#000000\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.preview.png\",\"author\":\"darrinhenein\",\"version\":\"1.0\"},{\"id\":\"recommended-5\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/carbon-light/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.footer.png\",\"textcolor\":\"#3b3b3b\",\"accentcolor\":\"#2e2e2e\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.preview.jpg\",\"author\":\"Jaxivo\",\"version\":\"1.0\"}]");
|
||||
|
||||
#if defined(MOZ_ADOBE_EME) || defined(MOZ_WIDEVINE_EME)
|
||||
#if defined(MOZ_WIDEVINE_EME)
|
||||
pref("browser.eme.ui.enabled", true);
|
||||
#else
|
||||
pref("browser.eme.ui.enabled", false);
|
||||
@ -1356,16 +1356,6 @@ pref("media.eme.enabled", true);
|
||||
#endif
|
||||
pref("media.eme.apiVisible", true);
|
||||
|
||||
// Decode using Gecko Media Plugins in <video>, if a system decoder is not
|
||||
// availble and the preferred GMP is available.
|
||||
pref("media.gmp.decoder.enabled", false);
|
||||
|
||||
// If decoding-via-GMP is turned on for <video>, use Adobe's GMP for decoding,
|
||||
// if it's available. Note: We won't fallback to another GMP if Adobe's is not
|
||||
// installed.
|
||||
pref("media.gmp.decoder.aac", 2);
|
||||
pref("media.gmp.decoder.h264", 2);
|
||||
|
||||
// Whether we should run a test-pattern through EME GMPs before assuming they'll
|
||||
// decode H.264.
|
||||
pref("media.gmp.trial-create.enabled", true);
|
||||
@ -1378,15 +1368,6 @@ pref("media.gmp.trial-create.enabled", true);
|
||||
// to enable the CDM if its disabled; it's as if the keysystem is completely
|
||||
// unsupported.
|
||||
|
||||
#ifdef MOZ_ADOBE_EME
|
||||
pref("media.gmp-eme-adobe.visible", true);
|
||||
// When Adobe EME is enabled in the build system, we don't actually enable
|
||||
// the plugin by default, so that it doesn't download and install by default.
|
||||
// When Adobe EME is first used, Firefox will prompt the user to enable it,
|
||||
// and then download the CDM.
|
||||
pref("media.gmp-eme-adobe.enabled", false);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDEVINE_EME
|
||||
pref("media.gmp-widevinecdm.visible", true);
|
||||
pref("media.gmp-widevinecdm.enabled", true);
|
||||
|
@ -83,6 +83,28 @@ var gFxAccounts = {
|
||||
return Services.prefs.getBoolPref("services.sync.sendTabToDevice.enabled");
|
||||
},
|
||||
|
||||
isSendableURI(aURISpec) {
|
||||
if (!aURISpec) {
|
||||
return false;
|
||||
}
|
||||
// Disallow sending tabs with more than 65535 characters.
|
||||
if (aURISpec.length > 65535) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
// Filter out un-sendable URIs -- things like local files, object urls, etc.
|
||||
const unsendableRegexp = new RegExp(
|
||||
Services.prefs.getCharPref("services.sync.engine.tabs.filteredUrls"), "i");
|
||||
return !unsendableRegexp.test(aURISpec);
|
||||
} catch (e) {
|
||||
// The preference has been removed, or is an invalid regexp, so we log an
|
||||
// error and treat it as a valid URI -- and the more problematic case is
|
||||
// the length, which we've already addressed.
|
||||
Cu.reportError(`Failed to build url filter regexp for send tab: ${e}`);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
get remoteClients() {
|
||||
return Weave.Service.clientsEngine.remoteClients
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
@ -410,14 +432,16 @@ var gFxAccounts = {
|
||||
devicesPopup.appendChild(fragment);
|
||||
},
|
||||
|
||||
updateTabContextMenu(aPopupMenu) {
|
||||
updateTabContextMenu(aPopupMenu, aTargetTab) {
|
||||
if (!this.sendTabToDeviceEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const remoteClientPresent = this.remoteClients.length > 0;
|
||||
const targetURI = aTargetTab.linkedBrowser.currentURI.spec;
|
||||
const showSendTab = this.remoteClients.length > 0 && this.isSendableURI(targetURI);
|
||||
|
||||
["context_sendTabToDevice", "context_sendTabToDevice_separator"]
|
||||
.forEach(id => { document.getElementById(id).hidden = !remoteClientPresent });
|
||||
.forEach(id => { document.getElementById(id).hidden = !showSendTab });
|
||||
},
|
||||
|
||||
initPageContextMenu(contextMenu) {
|
||||
@ -427,13 +451,20 @@ var gFxAccounts = {
|
||||
|
||||
const remoteClientPresent = this.remoteClients.length > 0;
|
||||
// showSendLink and showSendPage are mutually exclusive
|
||||
const showSendLink = remoteClientPresent
|
||||
&& (contextMenu.onSaveableLink || contextMenu.onPlainTextLink);
|
||||
let showSendLink = remoteClientPresent
|
||||
&& (contextMenu.onSaveableLink || contextMenu.onPlainTextLink);
|
||||
const showSendPage = !showSendLink && remoteClientPresent
|
||||
&& !(contextMenu.isContentSelected ||
|
||||
contextMenu.onImage || contextMenu.onCanvas ||
|
||||
contextMenu.onVideo || contextMenu.onAudio ||
|
||||
contextMenu.onLink || contextMenu.onTextInput);
|
||||
contextMenu.onLink || contextMenu.onTextInput)
|
||||
&& this.isSendableURI(contextMenu.browser.currentURI.spec);
|
||||
|
||||
if (showSendLink) {
|
||||
// This isn't part of the condition above since we don't want to try and
|
||||
// send the page if a link is clicked on or selected but is not sendable.
|
||||
showSendLink = this.isSendableURI(contextMenu.linkURL);
|
||||
}
|
||||
|
||||
["context-sendpagetodevice", "context-sep-sendpagetodevice"]
|
||||
.forEach(id => contextMenu.showItem(id, showSendPage));
|
||||
|
@ -16,16 +16,11 @@ var gEMEHandler = {
|
||||
},
|
||||
ensureEMEEnabled(browser, keySystem) {
|
||||
Services.prefs.setBoolPref("media.eme.enabled", true);
|
||||
if (keySystem) {
|
||||
if (keySystem.startsWith("com.adobe") &&
|
||||
Services.prefs.getPrefType("media.gmp-eme-adobe.enabled") &&
|
||||
!Services.prefs.getBoolPref("media.gmp-eme-adobe.enabled")) {
|
||||
Services.prefs.setBoolPref("media.gmp-eme-adobe.enabled", true);
|
||||
} else if (keySystem == "com.widevine.alpha" &&
|
||||
Services.prefs.getPrefType("media.gmp-widevinecdm.enabled") &&
|
||||
!Services.prefs.getBoolPref("media.gmp-widevinecdm.enabled")) {
|
||||
Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", true);
|
||||
}
|
||||
if (keySystem &&
|
||||
keySystem == "com.widevine.alpha" &&
|
||||
Services.prefs.getPrefType("media.gmp-widevinecdm.enabled") &&
|
||||
!Services.prefs.getBoolPref("media.gmp-widevinecdm.enabled")) {
|
||||
Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", true);
|
||||
}
|
||||
browser.reload();
|
||||
},
|
||||
@ -33,10 +28,6 @@ var gEMEHandler = {
|
||||
if (!keySystem) {
|
||||
return false;
|
||||
}
|
||||
if (keySystem.startsWith("com.adobe") &&
|
||||
Services.prefs.getPrefType("media.gmp-eme-adobe.visible")) {
|
||||
return Services.prefs.getBoolPref("media.gmp-eme-adobe.visible");
|
||||
}
|
||||
if (keySystem == "com.widevine.alpha" &&
|
||||
Services.prefs.getPrefType("media.gmp-widevinecdm.visible")) {
|
||||
return Services.prefs.getBoolPref("media.gmp-widevinecdm.visible");
|
||||
|
@ -7872,7 +7872,7 @@ var TabContextMenu = {
|
||||
this.contextTab.addEventListener("TabAttrModified", this);
|
||||
aPopupMenu.addEventListener("popuphiding", this);
|
||||
|
||||
gFxAccounts.updateTabContextMenu(aPopupMenu);
|
||||
gFxAccounts.updateTabContextMenu(aPopupMenu, this.contextTab);
|
||||
},
|
||||
handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
|
@ -177,6 +177,7 @@
|
||||
<menulist popuponly="true" id="ContentSelectDropdown" hidden="true">
|
||||
<menupopup rolluponmousewheel="true"
|
||||
activateontab="true" position="after_start"
|
||||
level="parent"
|
||||
#ifdef XP_WIN
|
||||
consumeoutsideclicks="false" ignorekeys="shortcuts"
|
||||
#endif
|
||||
|
@ -580,6 +580,15 @@
|
||||
return true;
|
||||
},
|
||||
|
||||
_isForInitialAboutBlank(aWebProgress, aLocation) {
|
||||
if (!this.mBlank || !aWebProgress.isTopLevel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let location = aLocation ? aLocation.spec : "";
|
||||
return location == "about:blank";
|
||||
},
|
||||
|
||||
onProgressChange(aWebProgress, aRequest,
|
||||
aCurSelfProgress, aMaxSelfProgress,
|
||||
aCurTotalProgress, aMaxTotalProgress) {
|
||||
@ -609,8 +618,6 @@
|
||||
if (!aRequest)
|
||||
return;
|
||||
|
||||
var oldBlank = this.mBlank;
|
||||
|
||||
const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
|
||||
const nsIChannel = Components.interfaces.nsIChannel;
|
||||
let location, originalLocation;
|
||||
@ -620,6 +627,18 @@
|
||||
originalLocation = aRequest.originalURI;
|
||||
} catch (ex) {}
|
||||
|
||||
let ignoreBlank = this._isForInitialAboutBlank(aWebProgress, location);
|
||||
// If we were ignoring some messages about the initial about:blank, and we
|
||||
// got the STATE_STOP for it, we'll want to pay attention to those messages
|
||||
// from here forward. Similarly, if we conclude that this state change
|
||||
// is one that we shouldn't be ignoring, then stop ignoring.
|
||||
if ((ignoreBlank &&
|
||||
aStateFlags & nsIWebProgressListener.STATE_STOP &&
|
||||
aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) ||
|
||||
!ignoreBlank && this.mBlank) {
|
||||
this.mBlank = false;
|
||||
}
|
||||
|
||||
if (aStateFlags & nsIWebProgressListener.STATE_START) {
|
||||
this.mRequestCount++;
|
||||
} else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
|
||||
@ -706,9 +725,6 @@
|
||||
this.mTabBrowser.useDefaultIcon(this.mTab);
|
||||
}
|
||||
|
||||
if (this.mBlank)
|
||||
this.mBlank = false;
|
||||
|
||||
// For keyword URIs clear the user typed value since they will be changed into real URIs
|
||||
if (location.scheme == "keyword")
|
||||
this.mBrowser.userTypedValue = null;
|
||||
@ -720,7 +736,7 @@
|
||||
this.mTabBrowser.mIsBusy = false;
|
||||
}
|
||||
|
||||
if (oldBlank) {
|
||||
if (ignoreBlank) {
|
||||
this._callProgressListeners("onUpdateCurrentBrowser",
|
||||
[aStateFlags, aStatus, "", 0],
|
||||
true, false);
|
||||
@ -1772,7 +1788,7 @@
|
||||
// Create a new tab progress listener for the new browser we just injected,
|
||||
// since tab progress listeners have logic for handling the initial about:blank
|
||||
// load
|
||||
listener = this.mTabProgressListener(tab, aBrowser, false, false);
|
||||
listener = this.mTabProgressListener(tab, aBrowser, true, false);
|
||||
this._tabListeners.set(tab, listener);
|
||||
filter.addProgressListener(listener, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
|
||||
|
@ -41,6 +41,21 @@ const PAGECONTENT_SMALL =
|
||||
" <option value='Six'>Six</option>" +
|
||||
"</select></body></html>";
|
||||
|
||||
const PAGECONTENT_GROUPS =
|
||||
"<html>" +
|
||||
"<body><select id='one'>" +
|
||||
" <optgroup label='Group 1'>" +
|
||||
" <option value='G1 O1'>G1 O1</option>" +
|
||||
" <option value='G1 O2'>G1 O2</option>" +
|
||||
" <option value='G1 O3'>G1 O3</option>" +
|
||||
" </optgroup>" +
|
||||
" <optgroup label='Group 2'>" +
|
||||
" <option value='G2 O1'>G2 O4</option>" +
|
||||
" <option value='G2 O2'>G2 O5</option>" +
|
||||
" <option value='Hidden' style='display: none;'>Hidden</option>" +
|
||||
" </optgroup>" +
|
||||
"</select></body></html>";
|
||||
|
||||
const PAGECONTENT_SOMEHIDDEN =
|
||||
"<html><head><style>.hidden { display: none; }</style></head>" +
|
||||
"<body><select id='one'>" +
|
||||
@ -446,13 +461,19 @@ function* performLargePopupTests(win) {
|
||||
if (positions.length > 0) {
|
||||
let cs = win.getComputedStyle(selectPopup);
|
||||
let bpBottom = parseFloat(cs.paddingBottom) + parseFloat(cs.borderBottomWidth);
|
||||
let selectedOption = 60;
|
||||
|
||||
if (Services.prefs.getBoolPref("dom.forms.selectSearch")) {
|
||||
// Use option 61 instead of 60, as the 60th option element is actually the
|
||||
// 61st child, since the first child is now the search input field.
|
||||
selectedOption = 61;
|
||||
}
|
||||
// Some of the styles applied to the menuitems are percentages, meaning
|
||||
// that the final layout calculations returned by getBoundingClientRect()
|
||||
// might return floating point values. We don't care about sub-pixel
|
||||
// accuracy, and only care about the final pixel value, so we add a
|
||||
// fuzz-factor of 1.
|
||||
SimpleTest.isfuzzy(selectPopup.childNodes[60].getBoundingClientRect().bottom,
|
||||
SimpleTest.isfuzzy(selectPopup.childNodes[selectedOption].getBoundingClientRect().bottom,
|
||||
selectPopup.getBoundingClientRect().bottom - bpBottom,
|
||||
1, "Popup scroll at correct position " + bpBottom);
|
||||
}
|
||||
@ -474,6 +495,78 @@ function* performLargePopupTests(win) {
|
||||
}
|
||||
}
|
||||
|
||||
function* performSelectSearchTests(win) {
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
yield ContentTask.spawn(browser, null, function*() {
|
||||
let doc = content.document;
|
||||
let select = doc.getElementById("one");
|
||||
|
||||
for (var i = 0; i < 40; i++) {
|
||||
select.add(new content.Option("Test" + i));
|
||||
}
|
||||
|
||||
select.options[1].selected = true;
|
||||
select.focus();
|
||||
});
|
||||
|
||||
let selectPopup = win.document.getElementById("ContentSelectDropdown").menupopup;
|
||||
yield openSelectPopup(selectPopup, false, "select", win);
|
||||
|
||||
let searchElement = selectPopup.querySelector("textbox");
|
||||
searchElement.focus();
|
||||
|
||||
EventUtils.synthesizeKey("O", {}, win);
|
||||
is(selectPopup.childNodes[2].hidden, false, "First option should be visible");
|
||||
is(selectPopup.childNodes[3].hidden, false, "Second option should be visible");
|
||||
|
||||
EventUtils.synthesizeKey("3", {}, win);
|
||||
is(selectPopup.childNodes[2].hidden, true, "First option should be hidden");
|
||||
is(selectPopup.childNodes[3].hidden, true, "Second option should be hidden");
|
||||
is(selectPopup.childNodes[4].hidden, false, "Third option should be visible");
|
||||
|
||||
EventUtils.synthesizeKey("Z", {}, win);
|
||||
is(selectPopup.childNodes[4].hidden, true, "Third option should be hidden");
|
||||
is(selectPopup.childNodes[1].hidden, true, "First group header should be hidden");
|
||||
|
||||
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, win);
|
||||
is(selectPopup.childNodes[4].hidden, false, "Third option should be visible");
|
||||
|
||||
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, win);
|
||||
is(selectPopup.childNodes[5].hidden, false, "Second group header should be visible");
|
||||
|
||||
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, win);
|
||||
EventUtils.synthesizeKey("O", {}, win);
|
||||
EventUtils.synthesizeKey("5", {}, win);
|
||||
is(selectPopup.childNodes[5].hidden, false, "Second group header should be visible");
|
||||
is(selectPopup.childNodes[1].hidden, true, "First group header should be hidden");
|
||||
|
||||
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, win);
|
||||
is(selectPopup.childNodes[1].hidden, false, "First group header should be shown");
|
||||
|
||||
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, win);
|
||||
is(selectPopup.childNodes[8].hidden, true, "Option hidden by content should remain hidden");
|
||||
|
||||
yield hideSelectPopup(selectPopup, "escape", win);
|
||||
}
|
||||
|
||||
// This test checks the functionality of search in select elements with groups
|
||||
// and a large number of options.
|
||||
add_task(function* test_select_search() {
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["dom.forms.selectSearch", true],
|
||||
],
|
||||
});
|
||||
const pageUrl = "data:text/html," + escape(PAGECONTENT_GROUPS);
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||
|
||||
yield performSelectSearchTests(window);
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
|
||||
yield SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
||||
// This test checks select elements with a large number of options to ensure that
|
||||
// the popup appears within the browser area.
|
||||
add_task(function* test_large_popup() {
|
||||
|
@ -18,6 +18,8 @@ add_task(function* test() {
|
||||
|
||||
|
||||
if (gFxAccounts.sendTabToDeviceEnabled) {
|
||||
const origIsSendableURI = gFxAccounts.isSendableURI;
|
||||
gFxAccounts.isSendableURI = () => true;
|
||||
// Check the send tab to device menu item
|
||||
const oldGetter = setupRemoteClientsFixture(remoteClientsFixture);
|
||||
yield updateTabContextMenu(origTab, function* () {
|
||||
@ -28,7 +30,11 @@ add_task(function* test() {
|
||||
is(targets[0].getAttribute("label"), "Foo", "Foo target is present");
|
||||
is(targets[1].getAttribute("label"), "Bar", "Bar target is present");
|
||||
is(targets[3].getAttribute("label"), "All Devices", "All Devices target is present");
|
||||
gFxAccounts.isSendableURI = () => false;
|
||||
updateTabContextMenu(origTab);
|
||||
is(document.getElementById("context_sendTabToDevice").hidden, true, "Send tab to device is hidden");
|
||||
restoreRemoteClients(oldGetter);
|
||||
gFxAccounts.isSendableURI = origIsSendableURI;
|
||||
}
|
||||
|
||||
// Hide the original tab.
|
||||
|
@ -128,10 +128,8 @@
|
||||
</tabpanel>
|
||||
<tabpanel id="cookies-tabpanel"
|
||||
class="tabpanel-content">
|
||||
<vbox flex="1">
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-cookies-tabpanel-hook"/>
|
||||
</vbox>
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-cookies-tabpanel-hook"/>
|
||||
</tabpanel>
|
||||
<tabpanel id="params-tabpanel"
|
||||
class="tabpanel-content">
|
||||
|
@ -53,11 +53,13 @@ function CookiesPanel({
|
||||
}
|
||||
|
||||
return (
|
||||
PropertiesView({
|
||||
object,
|
||||
filterPlaceHolder: COOKIES_FILTER_TEXT,
|
||||
sectionNames: SECTION_NAMES,
|
||||
})
|
||||
div({ className: "panel-container" },
|
||||
PropertiesView({
|
||||
object,
|
||||
filterPlaceHolder: COOKIES_FILTER_TEXT,
|
||||
sectionNames: SECTION_NAMES,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ const HeadersPanel = createClass({
|
||||
}
|
||||
|
||||
return (
|
||||
div({},
|
||||
div({ className: "panel-container" },
|
||||
div({ className: "summary" },
|
||||
summaryUrl,
|
||||
summaryMethod,
|
||||
|
@ -92,11 +92,13 @@ function ParamsPanel({
|
||||
}
|
||||
|
||||
return (
|
||||
PropertiesView({
|
||||
object,
|
||||
filterPlaceHolder: PARAMS_FILTER_TEXT,
|
||||
sectionNames: SECTION_NAMES,
|
||||
})
|
||||
div({ className: "panel-container" },
|
||||
PropertiesView({
|
||||
object,
|
||||
filterPlaceHolder: PARAMS_FILTER_TEXT,
|
||||
sectionNames: SECTION_NAMES,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ const PropertiesView = createClass({
|
||||
// Display source editor when specifying to EDITOR_CONFIG_ID along with config
|
||||
if (level === 1 && name === EDITOR_CONFIG_ID) {
|
||||
return (
|
||||
tr({},
|
||||
tr({ className: "editor-row-container" },
|
||||
td({ colSpan: 2 },
|
||||
Editor(value)
|
||||
)
|
||||
|
@ -121,7 +121,7 @@ const ResponsePanel = createClass({
|
||||
let { width, height } = this.state.imageDimensions;
|
||||
|
||||
return (
|
||||
div({ className: "response-image-box devtools-monospace" },
|
||||
div({ className: "panel-container response-image-box devtools-monospace" },
|
||||
img({
|
||||
className: "response-image",
|
||||
src: formDataURI(mimeType, encoding, response),
|
||||
@ -167,7 +167,7 @@ const ResponsePanel = createClass({
|
||||
}
|
||||
|
||||
return (
|
||||
div({},
|
||||
div({ className: "panel-container" },
|
||||
error && div({ className: "response-error-header", title: error },
|
||||
error
|
||||
),
|
||||
|
@ -10,6 +10,9 @@
|
||||
add_task(function* () {
|
||||
let { L10N } = require("devtools/client/netmonitor/l10n");
|
||||
|
||||
// Set a higher panel height in order to get full CodeMirror content
|
||||
Services.prefs.setIntPref("devtools.toolbox.footer.height", 400);
|
||||
|
||||
let { tab, monitor } = yield initNetMonitor(POST_DATA_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
"background-clip", "background-color", "background-image",
|
||||
"background-origin", "background-position", "background-position-x",
|
||||
"background-position-y", "background-repeat", "background-size"]],
|
||||
[[21, 9], ["-moz-calc", "auto", "calc", "inherit", "initial","unset"]],
|
||||
[[21, 9], ["auto", "calc", "inherit", "initial","unset"]],
|
||||
[[25, 26], [".devtools-toolbarbutton > tab",
|
||||
".devtools-toolbarbutton > hbox",
|
||||
".devtools-toolbarbutton > .toolbarbutton-menubutton-button"]],
|
||||
|
@ -1077,8 +1077,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Overwrite tree-view cell colon and use l10n string instead */
|
||||
.treeTable .treeLabelCell::after {
|
||||
/* Overwrite tree-view cell colon `:` for security panel and tree section */
|
||||
#security-tabpanel .treeTable .treeLabelCell::after,
|
||||
.treeTable .tree-section .treeLabelCell::after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
@ -1100,18 +1101,17 @@
|
||||
box-shadow: var(--theme-focus-box-shadow-textbox);
|
||||
}
|
||||
|
||||
.properties-view {
|
||||
/* FIXME: Minus 24px * 2 for toolbox height + panel height
|
||||
* Give a fixed panel container height in order to force tree view scrollable */
|
||||
.panel-container {
|
||||
/* FIXME: To avoid the issue which panel exceeds visible range,
|
||||
* we set view heigh - 24px * 2 for toolbox height + tabs height */
|
||||
height: calc(100vh - 48px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#headers-tabpanel .properties-view {
|
||||
/* FIXME: Minus 24px * 2 + 87.5 for toolbox height + panel height + headers summary
|
||||
* Give a fixed panel container height in order to force tree view scrollable */
|
||||
height: calc(100vh - 135.5px);
|
||||
.panel-container,
|
||||
.properties-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.properties-view .searchbox-section {
|
||||
@ -1142,6 +1142,36 @@
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* Apply flex to table tbody in order to fill available vertical space */
|
||||
.tree-container .treeTable tbody {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* Apply flex to table will create an anonymous table element outside of tbody
|
||||
* See also http://stackoverflow.com/a/30851678
|
||||
* Therefore, we set height with this magic number in order to remove the
|
||||
* redundant scrollbar when source editor appears.
|
||||
*/
|
||||
height: calc(100% - 3px);
|
||||
}
|
||||
|
||||
.tree-container .treeTable tr {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Make right td fill available horizontal space */
|
||||
.tree-container .treeTable td:last-child {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* If there is a source editor shows up in the last row of TreeView,
|
||||
* it should occupy the available vertical space.
|
||||
*/
|
||||
.tree-container .treeTable .editor-row-container,
|
||||
.tree-container .treeTable tr:last-child td[colspan="2"] {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.properties-view .devtools-searchbox,
|
||||
.tree-container .treeTable .tree-section {
|
||||
width: 100%;
|
||||
@ -1278,7 +1308,12 @@
|
||||
#react-preview-tabpanel-hook,
|
||||
#react-response-tabpanel-hook,
|
||||
#react-security-tabpanel-hook,
|
||||
#react-timings-tabpanel-hook,
|
||||
#react-timings-tabpanel-hook {
|
||||
display: flex;
|
||||
-moz-box-flex: 1;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
#network-statistics-charts,
|
||||
#primed-cache-chart,
|
||||
#empty-cache-chart {
|
||||
@ -1286,19 +1321,6 @@
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
/* For vbox */
|
||||
#react-cookies-tabpanel-hook,
|
||||
#react-headers-tabpanel-hook,
|
||||
#react-params-tabpanel-hook,
|
||||
#react-preview-tabpanel-hook,
|
||||
#react-response-tabpanel-hook,
|
||||
#react-security-tabpanel-hook,
|
||||
#react-timings-tabpanel-hook,
|
||||
#primed-cache-chart,
|
||||
#empty-cache-chart {
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
#primed-cache-chart,
|
||||
#empty-cache-chart {
|
||||
-moz-box-pack: center;
|
||||
|
@ -82,7 +82,7 @@ window.onload = function() {
|
||||
"A CSS variable with spaces fails");
|
||||
|
||||
is(toSortedString(cssProperties.getValues('margin')),
|
||||
toSortedString(["-moz-calc","auto","calc","inherit","initial","unset"]),
|
||||
toSortedString(["auto","calc","inherit","initial","unset"]),
|
||||
"Can get values for the CSS margin.");
|
||||
is(cssProperties.getValues('foobar').length, 0,
|
||||
"Unknown values return an empty array.");
|
||||
|
@ -375,7 +375,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -453,7 +452,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -539,7 +537,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -617,7 +614,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -784,7 +780,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -805,7 +800,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -883,7 +877,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -902,7 +895,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -921,7 +913,6 @@ exports.CSS_PROPERTIES = {
|
||||
7
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -1033,7 +1024,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -1051,7 +1041,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -1163,7 +1152,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -1180,7 +1168,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -1241,7 +1228,6 @@ exports.CSS_PROPERTIES = {
|
||||
7
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -2052,7 +2038,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -2074,7 +2059,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -2499,7 +2483,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"hsl",
|
||||
@ -2545,7 +2528,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -3118,7 +3100,6 @@ exports.CSS_PROPERTIES = {
|
||||
"-moz-available",
|
||||
"-moz-block-height",
|
||||
"-moz-box",
|
||||
"-moz-calc",
|
||||
"-moz-center",
|
||||
"-moz-crisp-edges",
|
||||
"-moz-deck",
|
||||
@ -4015,7 +3996,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -4054,7 +4034,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"-moz-element",
|
||||
"-moz-image-rect",
|
||||
"-moz-linear-gradient",
|
||||
@ -4104,7 +4083,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -4182,7 +4160,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -4205,7 +4182,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -4283,7 +4259,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -4306,7 +4281,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -4414,7 +4388,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -4596,7 +4569,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -4674,7 +4646,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -4697,7 +4668,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -4775,7 +4745,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -4798,7 +4767,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -4876,7 +4844,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -4917,7 +4884,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -4995,7 +4961,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -5057,7 +5022,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -5165,7 +5129,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -5187,7 +5150,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -5207,7 +5169,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -5459,7 +5420,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -5480,7 +5440,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"currentColor",
|
||||
"dashed",
|
||||
@ -5558,7 +5517,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -5577,7 +5535,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -5596,7 +5553,6 @@ exports.CSS_PROPERTIES = {
|
||||
7
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -5832,7 +5788,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -5854,7 +5809,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -6025,7 +5979,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-block-height",
|
||||
"-moz-calc",
|
||||
"all-petite-caps",
|
||||
"all-small-caps",
|
||||
"auto",
|
||||
@ -6124,7 +6077,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -6342,7 +6294,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -6447,7 +6398,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -6479,7 +6429,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -6525,7 +6474,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -6616,7 +6564,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -6700,7 +6647,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -6813,7 +6759,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -6830,7 +6775,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -6871,7 +6815,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-block-height",
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -6954,7 +6897,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -6972,7 +6914,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -6990,7 +6931,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7008,7 +6948,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7026,7 +6965,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7044,7 +6982,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7062,7 +6999,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7080,7 +7016,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7098,7 +7033,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7429,7 +7363,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -7448,7 +7381,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -7470,7 +7402,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -7492,7 +7423,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -7513,7 +7443,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7532,7 +7461,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -7554,7 +7482,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -7576,7 +7503,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -7657,7 +7583,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7675,7 +7600,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7693,7 +7617,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7711,7 +7634,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -7760,7 +7682,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"COLOR",
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"currentColor",
|
||||
@ -7816,7 +7737,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -7854,7 +7774,6 @@ exports.CSS_PROPERTIES = {
|
||||
6
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -7943,7 +7862,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -7960,7 +7878,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -7977,7 +7894,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -7994,7 +7910,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -8011,7 +7926,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -8028,7 +7942,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -8045,7 +7958,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -8062,7 +7974,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -8079,7 +7990,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -8334,7 +8244,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -8896,7 +8805,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
@ -8989,7 +8897,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"auto",
|
||||
"calc",
|
||||
"inherit",
|
||||
@ -9209,7 +9116,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"-moz-middle-with-baseline",
|
||||
"baseline",
|
||||
"bottom",
|
||||
@ -9269,7 +9175,6 @@ exports.CSS_PROPERTIES = {
|
||||
],
|
||||
"values": [
|
||||
"-moz-available",
|
||||
"-moz-calc",
|
||||
"-moz-fit-content",
|
||||
"-moz-max-content",
|
||||
"-moz-min-content",
|
||||
@ -9317,7 +9222,6 @@ exports.CSS_PROPERTIES = {
|
||||
8
|
||||
],
|
||||
"values": [
|
||||
"-moz-calc",
|
||||
"calc",
|
||||
"inherit",
|
||||
"initial",
|
||||
|
@ -1284,8 +1284,6 @@ nsIDocument::nsIDocument()
|
||||
mUpgradeInsecurePreloads(false),
|
||||
mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
|
||||
mNodeInfoManager(nullptr),
|
||||
mCompatMode(eCompatibility_FullStandards),
|
||||
mVisibilityState(dom::VisibilityState::Hidden),
|
||||
mIsInitialDocumentInWindow(false),
|
||||
mMayStartLayout(true),
|
||||
mVisible(true),
|
||||
@ -1300,6 +1298,8 @@ nsIDocument::nsIDocument()
|
||||
mFontFaceSetDirty(true),
|
||||
mGetUserFontSetCalled(false),
|
||||
mPostedFlushUserFontSet(false),
|
||||
mCompatMode(eCompatibility_FullStandards),
|
||||
mVisibilityState(dom::VisibilityState::Hidden),
|
||||
mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
|
||||
mPartID(0),
|
||||
mDidFireDOMContentLoaded(true),
|
||||
|
@ -2937,6 +2937,8 @@ nsFrameLoader::TryRemoteBrowser()
|
||||
if (!mRemoteBrowser) {
|
||||
return false;
|
||||
}
|
||||
// Now that mRemoteBrowser is set, we can initialize the RenderFrameParent
|
||||
mRemoteBrowser->InitRenderFrame();
|
||||
|
||||
MaybeUpdatePrimaryTabParent(eTabParentChanged);
|
||||
|
||||
|
@ -3032,24 +3032,12 @@ protected:
|
||||
// container for per-context fonts (downloadable, SVG, etc.)
|
||||
RefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
|
||||
|
||||
// Compatibility mode
|
||||
nsCompatibility mCompatMode;
|
||||
|
||||
// Our readyState
|
||||
ReadyState mReadyState;
|
||||
|
||||
// Whether this document has (or will have, once we have a pres shell) a
|
||||
// Gecko- or Servo-backed style system.
|
||||
mozilla::StyleBackendType mStyleBackendType;
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
// Our visibility state
|
||||
mozilla::dom::VisibilityState mVisibilityState;
|
||||
static_assert(sizeof(mozilla::dom::VisibilityState) == sizeof(uint8_t),
|
||||
"Error size of mVisibilityState and mDummy");
|
||||
#else
|
||||
uint8_t mDummy;
|
||||
#endif
|
||||
// XXXheycam rust-bindgen currently doesn't generate correctly aligned fields
|
||||
// to represent the following bitfields if they are preceded by something
|
||||
// non-pointer aligned, so if adding non-pointer sized fields, please do so
|
||||
// somewhere other than right here.
|
||||
//
|
||||
// https://github.com/servo/rust-bindgen/issues/111
|
||||
|
||||
// True if BIDI is enabled.
|
||||
bool mBidiEnabled : 1;
|
||||
@ -3199,6 +3187,25 @@ protected:
|
||||
// True is document has ever been in a foreground window.
|
||||
bool mEverInForeground : 1;
|
||||
|
||||
// Compatibility mode
|
||||
nsCompatibility mCompatMode;
|
||||
|
||||
// Our readyState
|
||||
ReadyState mReadyState;
|
||||
|
||||
// Whether this document has (or will have, once we have a pres shell) a
|
||||
// Gecko- or Servo-backed style system.
|
||||
mozilla::StyleBackendType mStyleBackendType;
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
// Our visibility state
|
||||
mozilla::dom::VisibilityState mVisibilityState;
|
||||
static_assert(sizeof(mozilla::dom::VisibilityState) == sizeof(uint8_t),
|
||||
"Error size of mVisibilityState and mDummy");
|
||||
#else
|
||||
uint8_t mDummy;
|
||||
#endif
|
||||
|
||||
enum Type {
|
||||
eUnknown, // should never be used
|
||||
eHTML,
|
||||
|
@ -6066,16 +6066,6 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
|
||||
if (mMediaKeys) {
|
||||
nsAutoString keySystem;
|
||||
mMediaKeys->GetKeySystem(keySystem);
|
||||
// If we're using Primetime we need to shutdown the key system and
|
||||
// decoder to preserve secure stop like behavior, other CDMs don't
|
||||
// implement this so we don't need to worry with them on a suspend.
|
||||
if (IsPrimetimeKeySystem(keySystem)) {
|
||||
mMediaKeys->Shutdown();
|
||||
mMediaKeys = nullptr;
|
||||
if (mDecoder) {
|
||||
ShutdownDecoder();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->Pause();
|
||||
|
@ -631,12 +631,13 @@ child:
|
||||
*/
|
||||
async Show(ScreenIntSize size,
|
||||
ShowInfo info,
|
||||
TextureFactoryIdentifier textureFactoryIdentifier,
|
||||
uint64_t layersId,
|
||||
nullable PRenderFrame renderFrame,
|
||||
bool parentIsActive,
|
||||
nsSizeMode sizeMode);
|
||||
|
||||
async InitRendering(TextureFactoryIdentifier textureFactoryIdentifier,
|
||||
uint64_t layersId,
|
||||
nullable PRenderFrame renderFrame);
|
||||
|
||||
async LoadURL(nsCString uri, ShowInfo info);
|
||||
|
||||
async UpdateDimensions(CSSRect rect, CSSSize size,
|
||||
|
@ -427,10 +427,10 @@ TabChild::TabChild(nsIContentChild* aManager,
|
||||
bool
|
||||
TabChild::AsyncPanZoomEnabled() const
|
||||
{
|
||||
// If we have received the CompositorOptions we can answer definitively. If
|
||||
// not, return a best guess based on gfxPlaform values.
|
||||
return mCompositorOptions ? mCompositorOptions->UseAPZ()
|
||||
: gfxPlatform::AsyncPanZoomEnabled();
|
||||
// By the time anybody calls this, we must have had InitRenderingState called
|
||||
// already, and so mCompositorOptions should be populated.
|
||||
MOZ_RELEASE_ASSERT(mCompositorOptions);
|
||||
return mCompositorOptions->UseAPZ();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1167,8 +1167,8 @@ TabChild::DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
|
||||
const uint64_t& aLayersId,
|
||||
PRenderFrameChild* aRenderFrame, const ShowInfo& aShowInfo)
|
||||
{
|
||||
RecvShow(ScreenIntSize(0, 0), aShowInfo, aTextureFactoryIdentifier,
|
||||
aLayersId, aRenderFrame, mParentIsActive, nsSizeMode_Normal);
|
||||
InitRenderingState(aTextureFactoryIdentifier, aLayersId, aRenderFrame);
|
||||
RecvShow(ScreenIntSize(0, 0), aShowInfo, mParentIsActive, nsSizeMode_Normal);
|
||||
mDidFakeShow = true;
|
||||
}
|
||||
|
||||
@ -1224,39 +1224,41 @@ TabChild::ApplyShowInfo(const ShowInfo& aInfo)
|
||||
mozilla::ipc::IPCResult
|
||||
TabChild::RecvShow(const ScreenIntSize& aSize,
|
||||
const ShowInfo& aInfo,
|
||||
const TextureFactoryIdentifier& aTextureFactoryIdentifier,
|
||||
const uint64_t& aLayersId,
|
||||
PRenderFrameChild* aRenderFrame,
|
||||
const bool& aParentIsActive,
|
||||
const nsSizeMode& aSizeMode)
|
||||
{
|
||||
MOZ_ASSERT((!mDidFakeShow && aRenderFrame) || (mDidFakeShow && !aRenderFrame));
|
||||
|
||||
mPuppetWidget->SetSizeMode(aSizeMode);
|
||||
if (mDidFakeShow) {
|
||||
ApplyShowInfo(aInfo);
|
||||
RecvParentActivated(aParentIsActive);
|
||||
return IPC_OK();
|
||||
}
|
||||
bool res = true;
|
||||
|
||||
mPuppetWidget->SetSizeMode(aSizeMode);
|
||||
if (!mDidFakeShow) {
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
|
||||
if (!baseWindow) {
|
||||
NS_ERROR("WebNavigation() doesn't QI to nsIBaseWindow");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
InitRenderingState(aTextureFactoryIdentifier, aLayersId, aRenderFrame);
|
||||
|
||||
baseWindow->SetVisibility(true);
|
||||
res = InitTabChildGlobal();
|
||||
}
|
||||
|
||||
bool res = InitTabChildGlobal();
|
||||
ApplyShowInfo(aInfo);
|
||||
RecvParentActivated(aParentIsActive);
|
||||
ApplyShowInfo(aInfo);
|
||||
RecvParentActivated(aParentIsActive);
|
||||
|
||||
if (!res) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
if (!res) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabChild::RecvInitRendering(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
|
||||
const uint64_t& aLayersId,
|
||||
PRenderFrameChild* aRenderFrame)
|
||||
{
|
||||
MOZ_ASSERT((!mDidFakeShow && aRenderFrame) || (mDidFakeShow && !aRenderFrame));
|
||||
|
||||
InitRenderingState(aTextureFactoryIdentifier, aLayersId, aRenderFrame);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
|
@ -338,12 +338,14 @@ public:
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvShow(const ScreenIntSize& aSize,
|
||||
const ShowInfo& aInfo,
|
||||
const TextureFactoryIdentifier& aTextureFactoryIdentifier,
|
||||
const uint64_t& aLayersId,
|
||||
PRenderFrameChild* aRenderFrame,
|
||||
const bool& aParentIsActive,
|
||||
const nsSizeMode& aSizeMode) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvInitRendering(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
|
||||
const uint64_t& aLayersId,
|
||||
PRenderFrameChild* aRenderFrame) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvUpdateDimensions(const CSSRect& aRect,
|
||||
const CSSSize& aSize,
|
||||
|
@ -620,6 +620,34 @@ TabParent::LoadURL(nsIURI* aURI)
|
||||
Unused << SendLoadURL(spec, GetShowInfo());
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::InitRenderFrame()
|
||||
{
|
||||
if (IsInitedByParent()) {
|
||||
// If TabParent is initialized by parent side then the RenderFrame must also
|
||||
// be created here. If TabParent is initialized by child side,
|
||||
// child side will create RenderFrame.
|
||||
MOZ_ASSERT(!GetRenderFrame());
|
||||
RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||
MOZ_ASSERT(frameLoader);
|
||||
if (frameLoader) {
|
||||
bool success;
|
||||
RenderFrameParent* renderFrame = new RenderFrameParent(frameLoader, &success);
|
||||
uint64_t layersId = renderFrame->GetLayersId();
|
||||
AddTabParentToTable(layersId, this);
|
||||
Unused << SendPRenderFrameConstructor(renderFrame);
|
||||
|
||||
TextureFactoryIdentifier textureFactoryIdentifier;
|
||||
renderFrame->GetTextureFactoryIdentifier(&textureFactoryIdentifier);
|
||||
Unused << SendInitRendering(textureFactoryIdentifier, layersId, renderFrame);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the child should have constructed the RenderFrame,
|
||||
// and we should already know about it.
|
||||
MOZ_ASSERT(GetRenderFrame());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::Show(const ScreenIntSize& size, bool aParentIsActive)
|
||||
{
|
||||
@ -628,28 +656,7 @@ TabParent::Show(const ScreenIntSize& size, bool aParentIsActive)
|
||||
return;
|
||||
}
|
||||
|
||||
TextureFactoryIdentifier textureFactoryIdentifier;
|
||||
uint64_t layersId = 0;
|
||||
bool success = false;
|
||||
RenderFrameParent* renderFrame = nullptr;
|
||||
if (IsInitedByParent()) {
|
||||
// If TabParent is initialized by parent side then the RenderFrame must also
|
||||
// be created here. If TabParent is initialized by child side,
|
||||
// child side will create RenderFrame.
|
||||
MOZ_ASSERT(!GetRenderFrame());
|
||||
RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||
if (frameLoader) {
|
||||
renderFrame = new RenderFrameParent(frameLoader, &success);
|
||||
layersId = renderFrame->GetLayersId();
|
||||
renderFrame->GetTextureFactoryIdentifier(&textureFactoryIdentifier);
|
||||
AddTabParentToTable(layersId, this);
|
||||
Unused << SendPRenderFrameConstructor(renderFrame);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the child should have constructed the RenderFrame,
|
||||
// and we should already know about it.
|
||||
MOZ_ASSERT(GetRenderFrame());
|
||||
}
|
||||
MOZ_ASSERT(GetRenderFrame());
|
||||
|
||||
nsCOMPtr<nsISupports> container = mFrameElement->OwnerDoc()->GetContainer();
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
|
||||
@ -657,8 +664,7 @@ TabParent::Show(const ScreenIntSize& size, bool aParentIsActive)
|
||||
baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
|
||||
mSizeMode = mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal;
|
||||
|
||||
Unused << SendShow(size, GetShowInfo(), textureFactoryIdentifier,
|
||||
layersId, renderFrame, aParentIsActive, mSizeMode);
|
||||
Unused << SendShow(size, GetShowInfo(), aParentIsActive, mSizeMode);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
|
@ -368,6 +368,8 @@ public:
|
||||
|
||||
void LoadURL(nsIURI* aURI);
|
||||
|
||||
void InitRenderFrame();
|
||||
|
||||
// XXX/cjones: it's not clear what we gain by hiding these
|
||||
// message-sending functions under a layer of indirection and
|
||||
// eating the return values
|
||||
|
@ -31,7 +31,6 @@ gmp_privacy_info=Privacy Information
|
||||
openH264_name=OpenH264 Video Codec provided by Cisco Systems, Inc.
|
||||
openH264_description2=This plugin is automatically installed by Mozilla to comply with the WebRTC specification and to enable WebRTC calls with devices that require the H.264 video codec. Visit http://www.openh264.org/ to view the codec source code and learn more about the implementation.
|
||||
|
||||
eme-adobe_name=Primetime Content Decryption Module provided by Adobe Systems, Incorporated
|
||||
eme-adobe_description=Play back protected web video.
|
||||
cdm_description=Play back protected web video.
|
||||
|
||||
widevine_description=Widevine Content Decryption Module provided by Google Inc.
|
||||
|
@ -32,7 +32,6 @@ namespace mozilla {
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(kEMEKeySystemClearkey, "org.w3.clearkey");
|
||||
NS_NAMED_LITERAL_CSTRING(kEMEKeySystemWidevine, "com.widevine.alpha");
|
||||
NS_NAMED_LITERAL_CSTRING(kEMEKeySystemPrimetime, "com.adobe.primetime");
|
||||
|
||||
using layers::PlanarYCbCrImage;
|
||||
|
||||
|
@ -46,7 +46,6 @@ class MediaContentType;
|
||||
// EME Key System String.
|
||||
extern const nsLiteralCString kEMEKeySystemClearkey;
|
||||
extern const nsLiteralCString kEMEKeySystemWidevine;
|
||||
extern const nsLiteralCString kEMEKeySystemPrimetime;
|
||||
|
||||
/**
|
||||
* ReentrantMonitorConditionallyEnter
|
||||
|
@ -53,12 +53,6 @@ IsClearkeyKeySystem(const nsAString& aKeySystem)
|
||||
return !CompareUTF8toUTF16(kEMEKeySystemClearkey, aKeySystem);
|
||||
}
|
||||
|
||||
bool
|
||||
IsPrimetimeKeySystem(const nsAString& aKeySystem)
|
||||
{
|
||||
return !CompareUTF8toUTF16(kEMEKeySystemPrimetime, aKeySystem);
|
||||
}
|
||||
|
||||
bool
|
||||
IsWidevineKeySystem(const nsAString& aKeySystem)
|
||||
{
|
||||
@ -68,9 +62,6 @@ IsWidevineKeySystem(const nsAString& aKeySystem)
|
||||
nsString
|
||||
KeySystemToGMPName(const nsAString& aKeySystem)
|
||||
{
|
||||
if (IsPrimetimeKeySystem(aKeySystem)) {
|
||||
return NS_LITERAL_STRING("gmp-eme-adobe");
|
||||
}
|
||||
if (IsClearkeyKeySystem(aKeySystem)) {
|
||||
return NS_LITERAL_STRING("gmp-clearkey");
|
||||
}
|
||||
@ -88,8 +79,6 @@ ToCDMTypeTelemetryEnum(const nsString& aKeySystem)
|
||||
return CDMType::eWidevine;
|
||||
} else if (IsClearkeyKeySystem(aKeySystem)) {
|
||||
return CDMType::eClearKey;
|
||||
} else if (IsPrimetimeKeySystem(aKeySystem)) {
|
||||
return CDMType::ePrimetime;
|
||||
}
|
||||
return CDMType::eUnknown;
|
||||
}
|
||||
|
@ -86,15 +86,15 @@ KeySystemToGMPName(const nsAString& aKeySystem);
|
||||
bool
|
||||
IsClearkeyKeySystem(const nsAString& aKeySystem);
|
||||
|
||||
bool
|
||||
IsPrimetimeKeySystem(const nsAString& aKeySystem);
|
||||
|
||||
bool
|
||||
IsWidevineKeySystem(const nsAString& aKeySystem);
|
||||
|
||||
// Note: Primetime is now unsupported, but we leave it in the enum so
|
||||
// that the telemetry enum values are not changed; doing so would break
|
||||
// existing telemetry probes.
|
||||
enum CDMType {
|
||||
eClearKey = 0,
|
||||
ePrimetime = 1,
|
||||
ePrimetime = 1, // Note: Unsupported.
|
||||
eWidevine = 2,
|
||||
eUnknown = 3
|
||||
};
|
||||
|
@ -27,8 +27,6 @@
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "gmp-audio-decode.h"
|
||||
#include "gmp-video-decode.h"
|
||||
#include "DecoderDoctorDiagnostics.h"
|
||||
#include "WebMDecoder.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
@ -134,16 +132,6 @@ MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
|
||||
return EnsureCDMInstalled(aKeySystem, aOutMessage);
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("media.gmp-eme-adobe.visible", false)) {
|
||||
if (IsPrimetimeKeySystem(aKeySystem)) {
|
||||
if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) {
|
||||
aOutMessage = NS_LITERAL_CSTRING("Adobe EME disabled");
|
||||
return MediaKeySystemStatus::Cdm_disabled;
|
||||
}
|
||||
return EnsureCDMInstalled(aKeySystem, aOutMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsWidevineKeySystem(aKeySystem)) {
|
||||
if (Preferences::GetBool("media.gmp-widevinecdm.visible", false)) {
|
||||
if (!Preferences::GetBool("media.gmp-widevinecdm.enabled", false)) {
|
||||
@ -324,9 +312,8 @@ GetSupportedKeySystems()
|
||||
#if defined(XP_WIN)
|
||||
// Widevine CDM doesn't include an AAC decoder. So if WMF can't
|
||||
// decode AAC, and a codec wasn't specified, be conservative
|
||||
// and reject the MediaKeys request, since our policy is to prevent
|
||||
// the Adobe GMP's unencrypted AAC decoding path being used to
|
||||
// decode content decrypted by the Widevine CDM.
|
||||
// and reject the MediaKeys request, since we assume Widevine
|
||||
// will be used with AAC.
|
||||
if (WMFDecoderModule::HasAAC()) {
|
||||
widevine.mMP4.SetCanDecrypt(EME_CODEC_AAC);
|
||||
}
|
||||
@ -376,19 +363,6 @@ GetSupportedKeySystems()
|
||||
keySystemConfigs.AppendElement(Move(widevine));
|
||||
}
|
||||
}
|
||||
{
|
||||
if (HavePluginForKeySystem(kEMEKeySystemPrimetime)) {
|
||||
KeySystemConfig primetime;
|
||||
primetime.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemPrimetime);
|
||||
primetime.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
|
||||
primetime.mPersistentState = KeySystemFeatureSupport::Required;
|
||||
primetime.mDistinctiveIdentifier = KeySystemFeatureSupport::Required;
|
||||
primetime.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
|
||||
primetime.mMP4.SetCanDecryptAndDecode(EME_CODEC_AAC);
|
||||
primetime.mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
|
||||
keySystemConfigs.AppendElement(Move(primetime));
|
||||
}
|
||||
}
|
||||
|
||||
return keySystemConfigs;
|
||||
}
|
||||
@ -453,9 +427,8 @@ CanDecryptAndDecode(const nsString& aKeySystem,
|
||||
#if defined(XP_WIN)
|
||||
// Widevine CDM doesn't include an AAC decoder. So if WMF can't
|
||||
// decode AAC, and a codec wasn't specified, be conservative
|
||||
// and reject the MediaKeys request, since our policy is to prevent
|
||||
// the Adobe GMP's unencrypted AAC decoding path being used to
|
||||
// decode content decrypted by the Widevine CDM.
|
||||
// and reject the MediaKeys request, since we assume Widevine
|
||||
// will be used with AAC.
|
||||
if (codec == EME_CODEC_AAC &&
|
||||
IsWidevineKeySystem(aKeySystem) &&
|
||||
!WMFDecoderModule::HasAAC()) {
|
||||
|
@ -94,9 +94,7 @@ MediaKeySystemAccessManager::Request(DetailedPromise* aPromise,
|
||||
DecoderDoctorDiagnostics diagnostics;
|
||||
|
||||
// Ensure keysystem is supported.
|
||||
if (!IsWidevineKeySystem(aKeySystem) &&
|
||||
!IsClearkeyKeySystem(aKeySystem) &&
|
||||
!IsPrimetimeKeySystem(aKeySystem)) {
|
||||
if (!IsWidevineKeySystem(aKeySystem) && !IsClearkeyKeySystem(aKeySystem)) {
|
||||
// Not to inform user, because nothing to do if the keySystem is not
|
||||
// supported.
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||
@ -132,7 +130,7 @@ MediaKeySystemAccessManager::Request(DetailedPromise* aPromise,
|
||||
LogToBrowserConsole(NS_ConvertUTF8toUTF16(msg));
|
||||
|
||||
if (status == MediaKeySystemStatus::Cdm_not_installed &&
|
||||
(IsPrimetimeKeySystem(aKeySystem) || IsWidevineKeySystem(aKeySystem))) {
|
||||
IsWidevineKeySystem(aKeySystem)) {
|
||||
// These are cases which could be resolved by downloading a new(er) CDM.
|
||||
// When we send the status to chrome, chrome's GMPProvider will attempt to
|
||||
// download or update the CDM. In AwaitInstall() we add listeners to wait
|
||||
|
@ -1,5 +1,5 @@
|
||||
Name: fake
|
||||
Description: Fake GMP Plugin, which deliberately uses GMP_API_DECRYPTOR_BACKWARDS_COMPAT for its decryptor.
|
||||
Description: Fake GMP Plugin.
|
||||
Version: 1.0
|
||||
APIs: decode-video[h264:broken], eme-decrypt-v7[fake]
|
||||
APIs: decode-video[h264:broken], eme-decrypt-v9[fake]
|
||||
Libraries: dxva2.dll
|
||||
|
@ -72,7 +72,7 @@ extern "C" {
|
||||
// happens when decoder init fails.
|
||||
return GMPGenericErr;
|
||||
#if defined(GMP_FAKE_SUPPORT_DECRYPT)
|
||||
} else if (!strcmp (aApiName, GMP_API_DECRYPTOR_BACKWARDS_COMPAT)) {
|
||||
} else if (!strcmp (aApiName, GMP_API_DECRYPTOR)) {
|
||||
*aPluginApi = new FakeDecryptor(static_cast<GMPDecryptorHost*> (aHostAPI));
|
||||
return GMPNoErr;
|
||||
} else if (!strcmp (aApiName, GMP_API_ASYNC_SHUTDOWN)) {
|
||||
|
@ -11,12 +11,15 @@
|
||||
#include <string>
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class FakeDecryptor : public GMPDecryptor7 {
|
||||
class FakeDecryptor : public GMPDecryptor {
|
||||
public:
|
||||
|
||||
explicit FakeDecryptor(GMPDecryptorHost* aHost);
|
||||
|
||||
void Init(GMPDecryptorCallback* aCallback) override {
|
||||
void Init(GMPDecryptorCallback* aCallback,
|
||||
bool aDistinctiveIdentifierRequired,
|
||||
bool aPersistentStateRequired) override
|
||||
{
|
||||
mCallback = aCallback;
|
||||
}
|
||||
|
||||
|
@ -1,172 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPAudioDecoderChild.h"
|
||||
#include "GMPContentChild.h"
|
||||
#include "GMPAudioHost.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPAudioDecoderChild::GMPAudioDecoderChild(GMPContentChild* aPlugin)
|
||||
: mPlugin(aPlugin)
|
||||
, mAudioDecoder(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin);
|
||||
}
|
||||
|
||||
GMPAudioDecoderChild::~GMPAudioDecoderChild()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoderChild::Init(GMPAudioDecoder* aDecoder)
|
||||
{
|
||||
MOZ_ASSERT(aDecoder, "Cannot initialize Audio decoder child without a Audio decoder!");
|
||||
mAudioDecoder = aDecoder;
|
||||
}
|
||||
|
||||
GMPAudioHostImpl&
|
||||
GMPAudioDecoderChild::Host()
|
||||
{
|
||||
return mAudioHost;
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoderChild::Decoded(GMPAudioSamples* aDecodedSamples)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
if (!aDecodedSamples) {
|
||||
MOZ_CRASH("Not given decoded audio samples!");
|
||||
}
|
||||
|
||||
GMPAudioDecodedSampleData samples;
|
||||
samples.mData().AppendElements((int16_t*)aDecodedSamples->Buffer(),
|
||||
aDecodedSamples->Size() / sizeof(int16_t));
|
||||
samples.mTimeStamp() = aDecodedSamples->TimeStamp();
|
||||
samples.mChannelCount() = aDecodedSamples->Channels();
|
||||
samples.mSamplesPerSecond() = aDecodedSamples->Rate();
|
||||
|
||||
Unused << SendDecoded(samples);
|
||||
|
||||
aDecodedSamples->Destroy();
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoderChild::InputDataExhausted()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
Unused << SendInputDataExhausted();
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoderChild::DrainComplete()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
Unused << SendDrainComplete();
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoderChild::ResetComplete()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
Unused << SendResetComplete();
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoderChild::Error(GMPErr aError)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
|
||||
|
||||
Unused << SendError(aError);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderChild::RecvInitDecode(const GMPAudioCodecData& a)
|
||||
{
|
||||
MOZ_ASSERT(mAudioDecoder);
|
||||
if (!mAudioDecoder) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
GMPAudioCodec codec;
|
||||
codec.mCodecType = a.mCodecType();
|
||||
codec.mChannelCount = a.mChannelCount();
|
||||
codec.mBitsPerChannel = a.mBitsPerChannel();
|
||||
codec.mSamplesPerSecond = a.mSamplesPerSecond();
|
||||
codec.mExtraData = a.mExtraData().Elements();
|
||||
codec.mExtraDataLen = a.mExtraData().Length();
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mAudioDecoder->InitDecode(codec, this);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderChild::RecvDecode(const GMPAudioEncodedSampleData& aEncodedSamples)
|
||||
{
|
||||
if (!mAudioDecoder) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
GMPAudioSamples* samples = new GMPAudioSamplesImpl(aEncodedSamples);
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mAudioDecoder->Decode(samples);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderChild::RecvReset()
|
||||
{
|
||||
if (!mAudioDecoder) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mAudioDecoder->Reset();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderChild::RecvDrain()
|
||||
{
|
||||
if (!mAudioDecoder) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mAudioDecoder->Drain();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderChild::RecvDecodingComplete()
|
||||
{
|
||||
if (mAudioDecoder) {
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mAudioDecoder->DecodingComplete();
|
||||
mAudioDecoder = nullptr;
|
||||
}
|
||||
|
||||
mPlugin = nullptr;
|
||||
|
||||
Unused << Send__delete__(this);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
@ -1,51 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPAudioDecoderChild_h_
|
||||
#define GMPAudioDecoderChild_h_
|
||||
|
||||
#include "mozilla/gmp/PGMPAudioDecoderChild.h"
|
||||
#include "gmp-audio-decode.h"
|
||||
#include "GMPAudioHost.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPContentChild;
|
||||
|
||||
class GMPAudioDecoderChild : public PGMPAudioDecoderChild,
|
||||
public GMPAudioDecoderCallback
|
||||
{
|
||||
public:
|
||||
explicit GMPAudioDecoderChild(GMPContentChild* aPlugin);
|
||||
virtual ~GMPAudioDecoderChild();
|
||||
|
||||
void Init(GMPAudioDecoder* aDecoder);
|
||||
GMPAudioHostImpl& Host();
|
||||
|
||||
// GMPAudioDecoderCallback
|
||||
void Decoded(GMPAudioSamples* aEncodedSamples) override;
|
||||
void InputDataExhausted() override;
|
||||
void DrainComplete() override;
|
||||
void ResetComplete() override;
|
||||
void Error(GMPErr aError) override;
|
||||
|
||||
private:
|
||||
// PGMPAudioDecoderChild
|
||||
mozilla::ipc::IPCResult RecvInitDecode(const GMPAudioCodecData& codecSettings) override;
|
||||
mozilla::ipc::IPCResult RecvDecode(const GMPAudioEncodedSampleData& input) override;
|
||||
mozilla::ipc::IPCResult RecvReset() override;
|
||||
mozilla::ipc::IPCResult RecvDrain() override;
|
||||
mozilla::ipc::IPCResult RecvDecodingComplete() override;
|
||||
|
||||
GMPContentChild* mPlugin;
|
||||
GMPAudioDecoder* mAudioDecoder;
|
||||
GMPAudioHostImpl mAudioHost;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPAudioDecoderChild_h_
|
@ -1,369 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPAudioDecoderParent.h"
|
||||
#include "GMPContentParent.h"
|
||||
#include <stdio.h>
|
||||
#include "mozilla/Unused.h"
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#ifdef LOG
|
||||
#undef LOG
|
||||
#endif
|
||||
|
||||
extern LogModule* GetGMPLog();
|
||||
|
||||
#define LOGV(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Verbose, msg)
|
||||
#define LOGD(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Debug, msg)
|
||||
#define LOG(level, msg) MOZ_LOG(GetGMPLog(), (level), msg)
|
||||
|
||||
namespace gmp {
|
||||
|
||||
GMPAudioDecoderParent::GMPAudioDecoderParent(GMPContentParent* aPlugin)
|
||||
: mIsOpen(false)
|
||||
, mShuttingDown(false)
|
||||
, mActorDestroyed(false)
|
||||
, mIsAwaitingResetComplete(false)
|
||||
, mIsAwaitingDrainComplete(false)
|
||||
, mPlugin(aPlugin)
|
||||
, mCallback(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin);
|
||||
}
|
||||
|
||||
GMPAudioDecoderParent::~GMPAudioDecoderParent()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPAudioDecoderParent::InitDecode(GMPAudioCodecType aCodecType,
|
||||
uint32_t aChannelCount,
|
||||
uint32_t aBitsPerChannel,
|
||||
uint32_t aSamplesPerSecond,
|
||||
nsTArray<uint8_t>& aExtraData,
|
||||
GMPAudioDecoderCallbackProxy* aCallback)
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::InitDecode()", this));
|
||||
|
||||
if (mIsOpen) {
|
||||
NS_WARNING("Trying to re-init an in-use GMP audio decoder!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!aCallback) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mCallback = aCallback;
|
||||
|
||||
GMPAudioCodecData data;
|
||||
data.mCodecType() = aCodecType;
|
||||
data.mChannelCount() = aChannelCount;
|
||||
data.mBitsPerChannel() = aBitsPerChannel;
|
||||
data.mSamplesPerSecond() = aSamplesPerSecond;
|
||||
data.mExtraData() = aExtraData;
|
||||
if (!SendInitDecode(data)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mIsOpen = true;
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPAudioDecoderParent::Decode(GMPAudioSamplesImpl& aEncodedSamples)
|
||||
{
|
||||
LOGV(("GMPAudioDecoderParent[%p]::Decode() timestamp=%lld",
|
||||
this, aEncodedSamples.TimeStamp()));
|
||||
|
||||
if (!mIsOpen) {
|
||||
NS_WARNING("Trying to use a dead GMP Audio decoder!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
GMPAudioEncodedSampleData samples;
|
||||
aEncodedSamples.RelinquishData(samples);
|
||||
|
||||
if (!SendDecode(samples)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPAudioDecoderParent::Reset()
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::Reset()", this));
|
||||
|
||||
if (!mIsOpen) {
|
||||
NS_WARNING("Trying to use a dead GMP Audio decoder!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendReset()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mIsAwaitingResetComplete = true;
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPAudioDecoderParent::Drain()
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::Drain()", this));
|
||||
|
||||
if (!mIsOpen) {
|
||||
NS_WARNING("Trying to use a dead GMP Audio decoder!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (!SendDrain()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mIsAwaitingDrainComplete = true;
|
||||
|
||||
// Async IPC, we don't have access to a return value.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note: Consider keeping ActorDestroy sync'd up when making changes here.
|
||||
nsresult
|
||||
GMPAudioDecoderParent::Close()
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::Close()", this));
|
||||
MOZ_ASSERT(!mPlugin || mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
// Ensure if we've received a Close while waiting for a ResetComplete
|
||||
// or DrainComplete notification, we'll unblock the caller before processing
|
||||
// the close. This seems unlikely to happen, but better to be careful.
|
||||
UnblockResetAndDrain();
|
||||
|
||||
// Consumer is done with us; we can shut down. No more callbacks should
|
||||
// be made to mCallback. Note: do this before Shutdown()!
|
||||
mCallback = nullptr;
|
||||
// Let Shutdown mark us as dead so it knows if we had been alive
|
||||
|
||||
// In case this is the last reference
|
||||
RefPtr<GMPAudioDecoderParent> kungfudeathgrip(this);
|
||||
Release();
|
||||
Shutdown();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note: Consider keeping ActorDestroy sync'd up when making changes here.
|
||||
nsresult
|
||||
GMPAudioDecoderParent::Shutdown()
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::Shutdown()", this));
|
||||
MOZ_ASSERT(!mPlugin || mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
if (mShuttingDown) {
|
||||
return NS_OK;
|
||||
}
|
||||
mShuttingDown = true;
|
||||
|
||||
// Ensure if we've received a shutdown while waiting for a ResetComplete
|
||||
// or DrainComplete notification, we'll unblock the caller before processing
|
||||
// the shutdown.
|
||||
UnblockResetAndDrain();
|
||||
|
||||
// Notify client we're gone! Won't occur after Close()
|
||||
if (mCallback) {
|
||||
mCallback->Terminated();
|
||||
mCallback = nullptr;
|
||||
}
|
||||
|
||||
mIsOpen = false;
|
||||
if (!mActorDestroyed) {
|
||||
Unused << SendDecodingComplete();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note: Keep this sync'd up with DecodingComplete
|
||||
void
|
||||
GMPAudioDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::ActorDestroy(reason=%d)", this, aWhy));
|
||||
|
||||
mIsOpen = false;
|
||||
mActorDestroyed = true;
|
||||
|
||||
// Ensure if we've received a destroy while waiting for a ResetComplete
|
||||
// or DrainComplete notification, we'll unblock the caller before processing
|
||||
// the error.
|
||||
UnblockResetAndDrain();
|
||||
|
||||
if (mCallback) {
|
||||
// May call Close() (and Shutdown()) immediately or with a delay
|
||||
mCallback->Terminated();
|
||||
mCallback = nullptr;
|
||||
}
|
||||
if (mPlugin) {
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mPlugin->AudioDecoderDestroyed(this);
|
||||
mPlugin = nullptr;
|
||||
}
|
||||
MaybeDisconnect(aWhy == AbnormalShutdown);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderParent::RecvDecoded(const GMPAudioDecodedSampleData& aDecoded)
|
||||
{
|
||||
LOGV(("GMPAudioDecoderParent[%p]::RecvDecoded() timestamp=%lld",
|
||||
this, aDecoded.mTimeStamp()));
|
||||
|
||||
if (!mCallback) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
mCallback->Decoded(aDecoded.mData(),
|
||||
aDecoded.mTimeStamp(),
|
||||
aDecoded.mChannelCount(),
|
||||
aDecoded.mSamplesPerSecond());
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderParent::RecvInputDataExhausted()
|
||||
{
|
||||
LOGV(("GMPAudioDecoderParent[%p]::RecvInputDataExhausted()", this));
|
||||
|
||||
if (!mCallback) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->InputDataExhausted();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderParent::RecvDrainComplete()
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::RecvDrainComplete()", this));
|
||||
|
||||
if (!mCallback) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
if (!mIsAwaitingDrainComplete) {
|
||||
return IPC_OK();
|
||||
}
|
||||
mIsAwaitingDrainComplete = false;
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->DrainComplete();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderParent::RecvResetComplete()
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::RecvResetComplete()", this));
|
||||
|
||||
if (!mCallback) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
if (!mIsAwaitingResetComplete) {
|
||||
return IPC_OK();
|
||||
}
|
||||
mIsAwaitingResetComplete = false;
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->ResetComplete();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderParent::RecvError(const GMPErr& aError)
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::RecvError(error=%d)", this, aError));
|
||||
|
||||
if (!mCallback) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
// Ensure if we've received an error while waiting for a ResetComplete
|
||||
// or DrainComplete notification, we'll unblock the caller before processing
|
||||
// the error.
|
||||
UnblockResetAndDrain();
|
||||
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mCallback->Error(aError);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderParent::RecvShutdown()
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::RecvShutdown()", this));
|
||||
|
||||
Shutdown();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPAudioDecoderParent::Recv__delete__()
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::Recv__delete__()", this));
|
||||
|
||||
if (mPlugin) {
|
||||
// Ignore any return code. It is OK for this to fail without killing the process.
|
||||
mPlugin->AudioDecoderDestroyed(this);
|
||||
mPlugin = nullptr;
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoderParent::UnblockResetAndDrain()
|
||||
{
|
||||
LOGD(("GMPAudioDecoderParent[%p]::UnblockResetAndDrain()", this));
|
||||
|
||||
if (!mCallback) {
|
||||
MOZ_ASSERT(!mIsAwaitingResetComplete);
|
||||
MOZ_ASSERT(!mIsAwaitingDrainComplete);
|
||||
return;
|
||||
}
|
||||
if (mIsAwaitingResetComplete) {
|
||||
mIsAwaitingResetComplete = false;
|
||||
mCallback->ResetComplete();
|
||||
}
|
||||
if (mIsAwaitingDrainComplete) {
|
||||
mIsAwaitingDrainComplete = false;
|
||||
mCallback->DrainComplete();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
@ -1,72 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPAudioDecoderParent_h_
|
||||
#define GMPAudioDecoderParent_h_
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "gmp-audio-decode.h"
|
||||
#include "gmp-audio-codec.h"
|
||||
#include "mozilla/gmp/PGMPAudioDecoderParent.h"
|
||||
#include "GMPMessageUtils.h"
|
||||
#include "GMPAudioDecoderProxy.h"
|
||||
#include "GMPCrashHelperHolder.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPContentParent;
|
||||
|
||||
class GMPAudioDecoderParent final : public GMPAudioDecoderProxy
|
||||
, public PGMPAudioDecoderParent
|
||||
, public GMPCrashHelperHolder
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(GMPAudioDecoderParent)
|
||||
|
||||
explicit GMPAudioDecoderParent(GMPContentParent *aPlugin);
|
||||
|
||||
nsresult Shutdown();
|
||||
|
||||
// GMPAudioDecoderProxy
|
||||
nsresult InitDecode(GMPAudioCodecType aCodecType,
|
||||
uint32_t aChannelCount,
|
||||
uint32_t aBitsPerChannel,
|
||||
uint32_t aSamplesPerSecond,
|
||||
nsTArray<uint8_t>& aExtraData,
|
||||
GMPAudioDecoderCallbackProxy* aCallback) override;
|
||||
nsresult Decode(GMPAudioSamplesImpl& aInput) override;
|
||||
nsresult Reset() override;
|
||||
nsresult Drain() override;
|
||||
nsresult Close() override;
|
||||
|
||||
private:
|
||||
~GMPAudioDecoderParent();
|
||||
|
||||
// PGMPAudioDecoderParent
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
mozilla::ipc::IPCResult RecvDecoded(const GMPAudioDecodedSampleData& aDecoded) override;
|
||||
mozilla::ipc::IPCResult RecvInputDataExhausted() override;
|
||||
mozilla::ipc::IPCResult RecvDrainComplete() override;
|
||||
mozilla::ipc::IPCResult RecvResetComplete() override;
|
||||
mozilla::ipc::IPCResult RecvError(const GMPErr& aError) override;
|
||||
mozilla::ipc::IPCResult RecvShutdown() override;
|
||||
mozilla::ipc::IPCResult Recv__delete__() override;
|
||||
|
||||
void UnblockResetAndDrain();
|
||||
|
||||
bool mIsOpen;
|
||||
bool mShuttingDown;
|
||||
bool mActorDestroyed;
|
||||
bool mIsAwaitingResetComplete;
|
||||
bool mIsAwaitingDrainComplete;
|
||||
RefPtr<GMPContentParent> mPlugin;
|
||||
GMPAudioDecoderCallbackProxy* mCallback;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPAudioDecoderParent_h_
|
@ -1,48 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPAudioDecoderProxy_h_
|
||||
#define GMPAudioDecoderProxy_h_
|
||||
|
||||
#include "GMPCallbackBase.h"
|
||||
#include "gmp-audio-codec.h"
|
||||
#include "GMPAudioHost.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
|
||||
class GMPAudioDecoderCallbackProxy : public GMPCallbackBase {
|
||||
public:
|
||||
virtual ~GMPAudioDecoderCallbackProxy() {}
|
||||
// Note: aChannelCount and aSamplesPerSecond may not be consistent from
|
||||
// one invocation to the next.
|
||||
virtual void Decoded(const nsTArray<int16_t>& aPCM,
|
||||
uint64_t aTimeStamp,
|
||||
uint32_t aChannelCount,
|
||||
uint32_t aSamplesPerSecond) = 0;
|
||||
virtual void InputDataExhausted() = 0;
|
||||
virtual void DrainComplete() = 0;
|
||||
virtual void ResetComplete() = 0;
|
||||
virtual void Error(GMPErr aError) = 0;
|
||||
};
|
||||
|
||||
class GMPAudioDecoderProxy {
|
||||
public:
|
||||
virtual ~GMPAudioDecoderProxy() {}
|
||||
|
||||
virtual nsresult InitDecode(GMPAudioCodecType aCodecType,
|
||||
uint32_t aChannelCount,
|
||||
uint32_t aBitsPerChannel,
|
||||
uint32_t aSamplesPerSecond,
|
||||
nsTArray<uint8_t>& aExtraData,
|
||||
GMPAudioDecoderCallbackProxy* aCallback) = 0;
|
||||
virtual nsresult Decode(mozilla::gmp::GMPAudioSamplesImpl& aSamples) = 0;
|
||||
virtual nsresult Reset() = 0;
|
||||
virtual nsresult Drain() = 0;
|
||||
// Call to tell GMP/plugin the consumer will no longer use this
|
||||
// interface/codec.
|
||||
virtual nsresult Close() = 0;
|
||||
};
|
||||
|
||||
#endif // GMPAudioDecoderProxy_h_
|
@ -1,162 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPAudioHost.h"
|
||||
#include "gmp-audio-samples.h"
|
||||
#include "gmp-errors.h"
|
||||
#include "GMPEncryptedBufferDataImpl.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPAudioSamplesImpl::GMPAudioSamplesImpl(GMPAudioFormat aFormat)
|
||||
: mFormat(aFormat)
|
||||
, mTimeStamp(0)
|
||||
, mChannels(0)
|
||||
, mRate(0)
|
||||
{
|
||||
}
|
||||
|
||||
GMPAudioSamplesImpl::GMPAudioSamplesImpl(const GMPAudioEncodedSampleData& aData)
|
||||
: mFormat(kGMPAudioEncodedSamples)
|
||||
, mBuffer(aData.mData())
|
||||
, mTimeStamp(aData.mTimeStamp())
|
||||
, mChannels(aData.mChannelCount())
|
||||
, mRate(aData.mSamplesPerSecond())
|
||||
{
|
||||
if (aData.mDecryptionData().mKeyId().Length() > 0) {
|
||||
mCrypto = new GMPEncryptedBufferDataImpl(aData.mDecryptionData());
|
||||
}
|
||||
}
|
||||
|
||||
GMPAudioSamplesImpl::GMPAudioSamplesImpl(MediaRawData* aSample,
|
||||
uint32_t aChannels,
|
||||
uint32_t aRate)
|
||||
: mFormat(kGMPAudioEncodedSamples)
|
||||
, mTimeStamp(aSample->mTime)
|
||||
, mChannels(aChannels)
|
||||
, mRate(aRate)
|
||||
{
|
||||
mBuffer.AppendElements(aSample->Data(), aSample->Size());
|
||||
if (aSample->mCrypto.mValid) {
|
||||
mCrypto = new GMPEncryptedBufferDataImpl(aSample->mCrypto);
|
||||
}
|
||||
}
|
||||
|
||||
GMPAudioSamplesImpl::~GMPAudioSamplesImpl()
|
||||
{
|
||||
}
|
||||
|
||||
GMPAudioFormat
|
||||
GMPAudioSamplesImpl::GetFormat()
|
||||
{
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioSamplesImpl::Destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
GMPErr
|
||||
GMPAudioSamplesImpl::SetBufferSize(uint32_t aSize)
|
||||
{
|
||||
mBuffer.SetLength(aSize);
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPAudioSamplesImpl::Size()
|
||||
{
|
||||
return mBuffer.Length();
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioSamplesImpl::SetTimeStamp(uint64_t aTimeStamp)
|
||||
{
|
||||
mTimeStamp = aTimeStamp;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
GMPAudioSamplesImpl::TimeStamp()
|
||||
{
|
||||
return mTimeStamp;
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
GMPAudioSamplesImpl::Buffer() const
|
||||
{
|
||||
return mBuffer.Elements();
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
GMPAudioSamplesImpl::Buffer()
|
||||
{
|
||||
return mBuffer.Elements();
|
||||
}
|
||||
|
||||
const GMPEncryptedBufferMetadata*
|
||||
GMPAudioSamplesImpl::GetDecryptionData() const
|
||||
{
|
||||
return mCrypto;
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioSamplesImpl::InitCrypto(const CryptoSample& aCrypto)
|
||||
{
|
||||
if (!aCrypto.mValid) {
|
||||
return;
|
||||
}
|
||||
mCrypto = new GMPEncryptedBufferDataImpl(aCrypto);
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioSamplesImpl::RelinquishData(GMPAudioEncodedSampleData& aData)
|
||||
{
|
||||
aData.mData() = Move(mBuffer);
|
||||
aData.mTimeStamp() = TimeStamp();
|
||||
if (mCrypto) {
|
||||
mCrypto->RelinquishData(aData.mDecryptionData());
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPAudioSamplesImpl::Channels() const
|
||||
{
|
||||
return mChannels;
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioSamplesImpl::SetChannels(uint32_t aChannels)
|
||||
{
|
||||
mChannels = aChannels;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPAudioSamplesImpl::Rate() const
|
||||
{
|
||||
return mRate;
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioSamplesImpl::SetRate(uint32_t aRate)
|
||||
{
|
||||
mRate = aRate;
|
||||
}
|
||||
|
||||
|
||||
GMPErr
|
||||
GMPAudioHostImpl::CreateSamples(GMPAudioFormat aFormat,
|
||||
GMPAudioSamples** aSamples)
|
||||
{
|
||||
|
||||
*aSamples = new GMPAudioSamplesImpl(aFormat);
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
@ -1,71 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GMPAudioHost_h_
|
||||
#define GMPAudioHost_h_
|
||||
|
||||
#include "gmp-audio-host.h"
|
||||
#include "gmp-audio-samples.h"
|
||||
#include "nsTArray.h"
|
||||
#include "gmp-decryption.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "GMPEncryptedBufferDataImpl.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
class CryptoSample;
|
||||
class MediaRawData;
|
||||
|
||||
namespace gmp {
|
||||
|
||||
class GMPAudioSamplesImpl : public GMPAudioSamples {
|
||||
public:
|
||||
explicit GMPAudioSamplesImpl(GMPAudioFormat aFormat);
|
||||
explicit GMPAudioSamplesImpl(const GMPAudioEncodedSampleData& aData);
|
||||
GMPAudioSamplesImpl(MediaRawData* aSample,
|
||||
uint32_t aChannels,
|
||||
uint32_t aRate);
|
||||
virtual ~GMPAudioSamplesImpl();
|
||||
|
||||
GMPAudioFormat GetFormat() override;
|
||||
void Destroy() override;
|
||||
GMPErr SetBufferSize(uint32_t aSize) override;
|
||||
uint32_t Size() override;
|
||||
void SetTimeStamp(uint64_t aTimeStamp) override;
|
||||
uint64_t TimeStamp() override;
|
||||
const uint8_t* Buffer() const override;
|
||||
uint8_t* Buffer() override;
|
||||
const GMPEncryptedBufferMetadata* GetDecryptionData() const override;
|
||||
|
||||
void InitCrypto(const CryptoSample& aCrypto);
|
||||
|
||||
void RelinquishData(GMPAudioEncodedSampleData& aData);
|
||||
|
||||
uint32_t Channels() const override;
|
||||
void SetChannels(uint32_t aChannels) override;
|
||||
uint32_t Rate() const override;
|
||||
void SetRate(uint32_t aRate) override;
|
||||
|
||||
private:
|
||||
GMPAudioFormat mFormat;
|
||||
nsTArray<uint8_t> mBuffer;
|
||||
int64_t mTimeStamp;
|
||||
nsAutoPtr<GMPEncryptedBufferDataImpl> mCrypto;
|
||||
uint32_t mChannels;
|
||||
uint32_t mRate;
|
||||
};
|
||||
|
||||
class GMPAudioHostImpl : public GMPAudioHost
|
||||
{
|
||||
public:
|
||||
GMPErr CreateSamples(GMPAudioFormat aFormat,
|
||||
GMPAudioSamples** aSamples) override;
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPAudioHost_h_
|
@ -9,7 +9,6 @@
|
||||
#include "GMPLoader.h"
|
||||
#include "GMPVideoDecoderChild.h"
|
||||
#include "GMPVideoEncoderChild.h"
|
||||
#include "GMPAudioDecoderChild.h"
|
||||
#include "GMPDecryptorChild.h"
|
||||
#include "GMPVideoHost.h"
|
||||
#include "nsDebugImpl.h"
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "GMPContentChild.h"
|
||||
#include "GMPChild.h"
|
||||
#include "GMPAudioDecoderChild.h"
|
||||
#include "GMPDecryptorChild.h"
|
||||
#include "GMPVideoDecoderChild.h"
|
||||
#include "GMPVideoEncoderChild.h"
|
||||
@ -49,19 +48,6 @@ GMPContentChild::ProcessingError(Result aCode, const char* aReason)
|
||||
mGMPChild->ProcessingError(aCode, aReason);
|
||||
}
|
||||
|
||||
PGMPAudioDecoderChild*
|
||||
GMPContentChild::AllocPGMPAudioDecoderChild()
|
||||
{
|
||||
return new GMPAudioDecoderChild(this);
|
||||
}
|
||||
|
||||
bool
|
||||
GMPContentChild::DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PGMPDecryptorChild*
|
||||
GMPContentChild::AllocPGMPDecryptorChild()
|
||||
{
|
||||
@ -109,96 +95,6 @@ GMPContentChild::DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adapts GMPDecryptor7 to the current GMPDecryptor version.
|
||||
class GMPDecryptor7BackwardsCompat : public GMPDecryptor {
|
||||
public:
|
||||
explicit GMPDecryptor7BackwardsCompat(GMPDecryptor7* aDecryptorV7)
|
||||
: mDecryptorV7(aDecryptorV7)
|
||||
{
|
||||
}
|
||||
|
||||
void Init(GMPDecryptorCallback* aCallback,
|
||||
bool aDistinctiveIdentifierRequired,
|
||||
bool aPersistentStateRequired) override
|
||||
{
|
||||
// Distinctive identifier and persistent state arguments not present
|
||||
// in v7 interface.
|
||||
mDecryptorV7->Init(aCallback);
|
||||
}
|
||||
|
||||
void CreateSession(uint32_t aCreateSessionToken,
|
||||
uint32_t aPromiseId,
|
||||
const char* aInitDataType,
|
||||
uint32_t aInitDataTypeSize,
|
||||
const uint8_t* aInitData,
|
||||
uint32_t aInitDataSize,
|
||||
GMPSessionType aSessionType) override
|
||||
{
|
||||
mDecryptorV7->CreateSession(aCreateSessionToken,
|
||||
aPromiseId,
|
||||
aInitDataType,
|
||||
aInitDataTypeSize,
|
||||
aInitData,
|
||||
aInitDataSize,
|
||||
aSessionType);
|
||||
}
|
||||
|
||||
void LoadSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) override
|
||||
{
|
||||
mDecryptorV7->LoadSession(aPromiseId, aSessionId, aSessionIdLength);
|
||||
}
|
||||
|
||||
void UpdateSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aResponse,
|
||||
uint32_t aResponseSize) override
|
||||
{
|
||||
mDecryptorV7->UpdateSession(aPromiseId,
|
||||
aSessionId,
|
||||
aSessionIdLength,
|
||||
aResponse,
|
||||
aResponseSize);
|
||||
}
|
||||
|
||||
void CloseSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) override
|
||||
{
|
||||
mDecryptorV7->CloseSession(aPromiseId, aSessionId, aSessionIdLength);
|
||||
}
|
||||
|
||||
void RemoveSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) override
|
||||
{
|
||||
mDecryptorV7->RemoveSession(aPromiseId, aSessionId, aSessionIdLength);
|
||||
}
|
||||
|
||||
void SetServerCertificate(uint32_t aPromiseId,
|
||||
const uint8_t* aServerCert,
|
||||
uint32_t aServerCertSize) override
|
||||
{
|
||||
mDecryptorV7->SetServerCertificate(aPromiseId, aServerCert, aServerCertSize);
|
||||
}
|
||||
|
||||
void Decrypt(GMPBuffer* aBuffer,
|
||||
GMPEncryptedBufferMetadata* aMetadata) override
|
||||
{
|
||||
mDecryptorV7->Decrypt(aBuffer, aMetadata);
|
||||
}
|
||||
|
||||
void DecryptingComplete() override
|
||||
{
|
||||
mDecryptorV7->DecryptingComplete();
|
||||
delete this;
|
||||
}
|
||||
private:
|
||||
GMPDecryptor7* mDecryptorV7;
|
||||
};
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPContentChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
|
||||
{
|
||||
@ -207,38 +103,11 @@ GMPContentChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
|
||||
|
||||
void* ptr = nullptr;
|
||||
GMPErr err = mGMPChild->GetAPI(GMP_API_DECRYPTOR, host, &ptr, aActor->Id());
|
||||
GMPDecryptor* decryptor = nullptr;
|
||||
if (GMP_SUCCEEDED(err) && ptr) {
|
||||
decryptor = static_cast<GMPDecryptor*>(ptr);
|
||||
} else if (err != GMPNoErr) {
|
||||
// We Adapt the previous GMPDecryptor version to the current, so that
|
||||
// Gecko thinks it's only talking to the current version. v7 differs
|
||||
// from v9 in its Init() function arguments, and v9 has extra enumeration
|
||||
// members at the end of the key status enumerations.
|
||||
err = mGMPChild->GetAPI(GMP_API_DECRYPTOR_BACKWARDS_COMPAT, host, &ptr);
|
||||
if (err != GMPNoErr || !ptr) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
decryptor = new GMPDecryptor7BackwardsCompat(static_cast<GMPDecryptor7*>(ptr));
|
||||
}
|
||||
|
||||
child->Init(decryptor);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPContentChild::RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor)
|
||||
{
|
||||
auto vdc = static_cast<GMPAudioDecoderChild*>(aActor);
|
||||
|
||||
void* vd = nullptr;
|
||||
GMPErr err = mGMPChild->GetAPI(GMP_API_AUDIO_DECODER, &vdc->Host(), &vd);
|
||||
if (err != GMPNoErr || !vd) {
|
||||
if (err != GMPNoErr || !ptr) {
|
||||
NS_WARNING("GMPGetAPI call failed trying to construct decryptor.");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
vdc->Init(static_cast<GMPAudioDecoder*>(vd));
|
||||
child->Init(static_cast<GMPDecryptor*>(ptr));
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
@ -282,12 +151,6 @@ void
|
||||
GMPContentChild::CloseActive()
|
||||
{
|
||||
// Invalidate and remove any remaining API objects.
|
||||
const ManagedContainer<PGMPAudioDecoderChild>& audioDecoders =
|
||||
ManagedPGMPAudioDecoderChild();
|
||||
for (auto iter = audioDecoders.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
iter.Get()->GetKey()->SendShutdown();
|
||||
}
|
||||
|
||||
const ManagedContainer<PGMPDecryptorChild>& decryptors =
|
||||
ManagedPGMPDecryptorChild();
|
||||
for (auto iter = decryptors.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
@ -310,8 +173,7 @@ GMPContentChild::CloseActive()
|
||||
bool
|
||||
GMPContentChild::IsUsed()
|
||||
{
|
||||
return !ManagedPGMPAudioDecoderChild().IsEmpty() ||
|
||||
!ManagedPGMPDecryptorChild().IsEmpty() ||
|
||||
return !ManagedPGMPDecryptorChild().IsEmpty() ||
|
||||
!ManagedPGMPVideoDecoderChild().IsEmpty() ||
|
||||
!ManagedPGMPVideoEncoderChild().IsEmpty();
|
||||
}
|
||||
|
@ -23,14 +23,10 @@ public:
|
||||
|
||||
MessageLoop* GMPMessageLoop();
|
||||
|
||||
mozilla::ipc::IPCResult RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor) override;
|
||||
mozilla::ipc::IPCResult RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor) override;
|
||||
mozilla::ipc::IPCResult RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor, const uint32_t& aDecryptorId) override;
|
||||
mozilla::ipc::IPCResult RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) override;
|
||||
|
||||
PGMPAudioDecoderChild* AllocPGMPAudioDecoderChild() override;
|
||||
bool DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor) override;
|
||||
|
||||
PGMPDecryptorChild* AllocPGMPDecryptorChild() override;
|
||||
bool DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor) override;
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPContentParent.h"
|
||||
#include "GMPAudioDecoderParent.h"
|
||||
#include "GMPDecryptorParent.h"
|
||||
#include "GMPParent.h"
|
||||
#include "GMPServiceChild.h"
|
||||
@ -66,8 +65,7 @@ private:
|
||||
void
|
||||
GMPContentParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
MOZ_ASSERT(mAudioDecoders.IsEmpty() &&
|
||||
mDecryptors.IsEmpty() &&
|
||||
MOZ_ASSERT(mDecryptors.IsEmpty() &&
|
||||
mVideoDecoders.IsEmpty() &&
|
||||
mVideoEncoders.IsEmpty());
|
||||
NS_DispatchToCurrentThread(new ReleaseGMPContentParent(this));
|
||||
@ -79,15 +77,6 @@ GMPContentParent::CheckThread()
|
||||
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
|
||||
}
|
||||
|
||||
void
|
||||
GMPContentParent::AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder)
|
||||
{
|
||||
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
|
||||
|
||||
MOZ_ALWAYS_TRUE(mAudioDecoders.RemoveElement(aDecoder));
|
||||
CloseIfUnused();
|
||||
}
|
||||
|
||||
void
|
||||
GMPContentParent::VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder)
|
||||
{
|
||||
@ -135,8 +124,7 @@ GMPContentParent::RemoveCloseBlocker()
|
||||
void
|
||||
GMPContentParent::CloseIfUnused()
|
||||
{
|
||||
if (mAudioDecoders.IsEmpty() &&
|
||||
mDecryptors.IsEmpty() &&
|
||||
if (mDecryptors.IsEmpty() &&
|
||||
mVideoDecoders.IsEmpty() &&
|
||||
mVideoEncoders.IsEmpty() &&
|
||||
mCloseBlockerCount == 0) {
|
||||
@ -192,23 +180,6 @@ GMPContentParent::GMPThread()
|
||||
return mGMPThread;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPContentParent::GetGMPAudioDecoder(GMPAudioDecoderParent** aGMPAD)
|
||||
{
|
||||
PGMPAudioDecoderParent* pvap = SendPGMPAudioDecoderConstructor();
|
||||
if (!pvap) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
GMPAudioDecoderParent* vap = static_cast<GMPAudioDecoderParent*>(pvap);
|
||||
// This addref corresponds to the Proxy pointer the consumer is returned.
|
||||
// It's dropped by calling Close() on the interface.
|
||||
NS_ADDREF(vap);
|
||||
*aGMPAD = vap;
|
||||
mAudioDecoders.AppendElement(vap);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPContentParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD,
|
||||
uint32_t aDecryptorId)
|
||||
@ -294,21 +265,5 @@ GMPContentParent::DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor)
|
||||
return true;
|
||||
}
|
||||
|
||||
PGMPAudioDecoderParent*
|
||||
GMPContentParent::AllocPGMPAudioDecoderParent()
|
||||
{
|
||||
GMPAudioDecoderParent* vdp = new GMPAudioDecoderParent(this);
|
||||
NS_ADDREF(vdp);
|
||||
return vdp;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPContentParent::DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor)
|
||||
{
|
||||
GMPAudioDecoderParent* vdp = static_cast<GMPAudioDecoderParent*>(aActor);
|
||||
NS_RELEASE(vdp);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
@ -13,7 +13,6 @@
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPAudioDecoderParent;
|
||||
class GMPDecryptorParent;
|
||||
class GMPParent;
|
||||
class GMPVideoDecoderParent;
|
||||
@ -37,9 +36,6 @@ public:
|
||||
nsresult GetGMPDecryptor(GMPDecryptorParent** aGMPKS);
|
||||
void DecryptorDestroyed(GMPDecryptorParent* aSession);
|
||||
|
||||
nsresult GetGMPAudioDecoder(GMPAudioDecoderParent** aGMPAD);
|
||||
void AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder);
|
||||
|
||||
nsIThread* GMPThread();
|
||||
|
||||
// GMPSharedMem
|
||||
@ -96,9 +92,6 @@ private:
|
||||
PGMPDecryptorParent* AllocPGMPDecryptorParent() override;
|
||||
bool DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor) override;
|
||||
|
||||
PGMPAudioDecoderParent* AllocPGMPAudioDecoderParent() override;
|
||||
bool DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) override;
|
||||
|
||||
void CloseIfUnused();
|
||||
// Needed because NewRunnableMethod tried to use the class that the method
|
||||
// lives on to store the receiver, but PGMPContentParent isn't refcounted.
|
||||
@ -110,7 +103,6 @@ private:
|
||||
nsTArray<RefPtr<GMPVideoDecoderParent>> mVideoDecoders;
|
||||
nsTArray<RefPtr<GMPVideoEncoderParent>> mVideoEncoders;
|
||||
nsTArray<RefPtr<GMPDecryptorParent>> mDecryptors;
|
||||
nsTArray<RefPtr<GMPAudioDecoderParent>> mAudioDecoders;
|
||||
nsCOMPtr<nsIThread> mGMPThread;
|
||||
RefPtr<GMPParent> mParent;
|
||||
nsCString mDisplayName;
|
||||
|
@ -24,8 +24,8 @@ namespace gmp {
|
||||
|
||||
class GMPLoaderImpl : public GMPLoader {
|
||||
public:
|
||||
explicit GMPLoaderImpl(SandboxStarter* aStarter)
|
||||
: mSandboxStarter(aStarter)
|
||||
explicit GMPLoaderImpl(UniquePtr<SandboxStarter> aStarter)
|
||||
: mSandboxStarter(Move(aStarter))
|
||||
, mAdapter(nullptr)
|
||||
{}
|
||||
~GMPLoaderImpl() override = default;
|
||||
@ -49,12 +49,12 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
SandboxStarter* mSandboxStarter;
|
||||
UniquePtr<SandboxStarter> mSandboxStarter;
|
||||
UniquePtr<GMPAdapter> mAdapter;
|
||||
};
|
||||
|
||||
UniquePtr<GMPLoader> CreateGMPLoader(SandboxStarter* aStarter) {
|
||||
return MakeUnique<GMPLoaderImpl>(aStarter);
|
||||
UniquePtr<GMPLoader> CreateGMPLoader(UniquePtr<SandboxStarter> aStarter) {
|
||||
return MakeUnique<GMPLoaderImpl>(Move(aStarter));
|
||||
}
|
||||
|
||||
class PassThroughGMPAdapter : public GMPAdapter {
|
||||
|
@ -105,7 +105,7 @@ public:
|
||||
|
||||
// On Desktop, this function resides in plugin-container.
|
||||
// On Mobile, this function resides in XUL.
|
||||
UniquePtr<GMPLoader> CreateGMPLoader(SandboxStarter* aStarter);
|
||||
UniquePtr<GMPLoader> CreateGMPLoader(UniquePtr<SandboxStarter> aStarter);
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "gmp-video-codec.h"
|
||||
#include "gmp-video-frame-encoded.h"
|
||||
#include "gmp-audio-codec.h"
|
||||
#include "gmp-decryption.h"
|
||||
|
||||
namespace IPC {
|
||||
@ -75,13 +74,6 @@ struct ParamTraits<GMPSessionType>
|
||||
kGMPSessionInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPAudioCodecType>
|
||||
: public ContiguousEnumSerializer<GMPAudioCodecType,
|
||||
kGMPAudioCodecAAC,
|
||||
kGMPAudioCodecInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPVideoCodecComplexity>
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecComplexity,
|
||||
|
@ -884,12 +884,6 @@ GMPParent::ReadGMPInfoFile(nsIFile* aFile)
|
||||
}
|
||||
}
|
||||
|
||||
// We support the current GMPDecryptor version, and the previous.
|
||||
// We Adapt the previous to the current in the GMPContentChild.
|
||||
if (cap.mAPIName.EqualsLiteral(GMP_API_DECRYPTOR_BACKWARDS_COMPAT)) {
|
||||
cap.mAPIName.AssignLiteral(GMP_API_DECRYPTOR);
|
||||
}
|
||||
|
||||
if (cap.mAPIName.EqualsLiteral(GMP_API_DECRYPTOR)) {
|
||||
mCanDecrypt = true;
|
||||
|
||||
@ -901,15 +895,6 @@ GMPParent::ReadGMPInfoFile(nsIFile* aFile)
|
||||
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
#endif
|
||||
#ifdef XP_WIN
|
||||
// Adobe GMP doesn't work without SSE2. Check the tags to see if
|
||||
// the decryptor is for the Adobe GMP, and refuse to load it if
|
||||
// SSE2 isn't supported.
|
||||
if (cap.mAPITags.Contains(kEMEKeySystemPrimetime) &&
|
||||
!mozilla::supports_sse2()) {
|
||||
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
#endif // XP_WIN
|
||||
}
|
||||
|
||||
mCapabilities.AppendElement(Move(cap));
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "GMPProcessParent.h"
|
||||
#include "GMPServiceParent.h"
|
||||
#include "GMPAudioDecoderParent.h"
|
||||
#include "GMPDecryptorParent.h"
|
||||
#include "GMPVideoDecoderParent.h"
|
||||
#include "GMPVideoEncoderParent.h"
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "nsIConsoleService.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "GMPDecryptorParent.h"
|
||||
#include "GMPAudioDecoderParent.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "runnable_utils.h"
|
||||
#include "VideoUtils.h"
|
||||
@ -307,42 +306,6 @@ GeckoMediaPluginService::GetAbstractGMPThread()
|
||||
return mAbstractGMPThread;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPAudioDecoder(GMPCrashHelper* aHelper,
|
||||
nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
|
||||
if (mShuttingDownOnGMPThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
GetGMPAudioDecoderCallback* rawCallback = aCallback.release();
|
||||
RefPtr<AbstractThread> thread(GetAbstractGMPThread());
|
||||
RefPtr<GMPCrashHelper> helper(aHelper);
|
||||
GetContentParent(aHelper, aNodeId, NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER), *aTags)
|
||||
->Then(thread, __func__,
|
||||
[rawCallback, helper](RefPtr<GMPContentParent::CloseBlocker> wrapper) {
|
||||
RefPtr<GMPContentParent> parent = wrapper->mParent;
|
||||
UniquePtr<GetGMPAudioDecoderCallback> callback(rawCallback);
|
||||
GMPAudioDecoderParent* actor = nullptr;
|
||||
if (parent && NS_SUCCEEDED(parent->GetGMPAudioDecoder(&actor))) {
|
||||
actor->SetCrashHelper(helper);
|
||||
}
|
||||
callback->Done(actor);
|
||||
},
|
||||
[rawCallback] {
|
||||
UniquePtr<GetGMPAudioDecoderCallback> callback(rawCallback);
|
||||
callback->Done(nullptr);
|
||||
});
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetDecryptingGMPVideoDecoder(GMPCrashHelper* aHelper,
|
||||
nsTArray<nsCString>* aTags,
|
||||
|
@ -59,11 +59,6 @@ public:
|
||||
const nsACString& aNodeId,
|
||||
UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
|
||||
override;
|
||||
NS_IMETHOD GetGMPAudioDecoder(GMPCrashHelper* aHelper,
|
||||
nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
|
||||
override;
|
||||
NS_IMETHOD GetGMPDecryptor(GMPCrashHelper* aHelper,
|
||||
nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "nsIConsoleService.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "GMPDecryptorParent.h"
|
||||
#include "GMPAudioDecoderParent.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "runnable_utils.h"
|
||||
#include "VideoUtils.h"
|
||||
@ -172,70 +171,6 @@ CloneAndAppend(nsIFile* aFile, const nsAString& aDir)
|
||||
return f.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
MoveAndOverwrite(nsIFile* aOldParentDir,
|
||||
nsIFile* aNewParentDir,
|
||||
const nsAString& aSubDir)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIFile> srcDir(CloneAndAppend(aOldParentDir, aSubDir));
|
||||
if (NS_WARN_IF(!srcDir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FileExists(srcDir)) {
|
||||
// No sub-directory to be migrated.
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure destination parent directory exists.
|
||||
rv = aNewParentDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> dstDir(CloneAndAppend(aNewParentDir, aSubDir));
|
||||
if (FileExists(dstDir)) {
|
||||
// We must have migrated before already, and then ran an old version
|
||||
// of Gecko again which created storage at the old location. Overwrite
|
||||
// the previously migrated storage.
|
||||
rv = dstDir->Remove(true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// MoveTo will fail.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rv = srcDir->MoveTo(aNewParentDir, EmptyString());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
MigratePreGecko42StorageDir(nsIFile* aOldStorageDir,
|
||||
nsIFile* aNewStorageDir)
|
||||
{
|
||||
MoveAndOverwrite(aOldStorageDir, aNewStorageDir, NS_LITERAL_STRING("id"));
|
||||
MoveAndOverwrite(aOldStorageDir, aNewStorageDir, NS_LITERAL_STRING("storage"));
|
||||
}
|
||||
|
||||
static void
|
||||
MigratePreGecko45StorageDir(nsIFile* aStorageDirBase)
|
||||
{
|
||||
nsCOMPtr<nsIFile> adobeStorageDir(CloneAndAppend(aStorageDirBase, NS_LITERAL_STRING("gmp-eme-adobe")));
|
||||
if (NS_WARN_IF(!adobeStorageDir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The base storage dir in pre-45 contained "id" and "storage" subdirs.
|
||||
// We assume all storage in the base storage dir that aren't known to GMP
|
||||
// storage are records for the Adobe GMP.
|
||||
MoveAndOverwrite(aStorageDirBase, adobeStorageDir, NS_LITERAL_STRING("id"));
|
||||
MoveAndOverwrite(aStorageDirBase, adobeStorageDir, NS_LITERAL_STRING("storage"));
|
||||
}
|
||||
|
||||
static nsresult
|
||||
GMPPlatformString(nsAString& aOutPlatform)
|
||||
{
|
||||
@ -322,19 +257,6 @@ GeckoMediaPluginServiceParent::InitStorage()
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Prior to 42, GMP storage was stored in $profileDir/gmp/. After 42, it's
|
||||
// stored in $profileDir/gmp/$platform/. So we must migrate any old records
|
||||
// from the old location to the new location, for forwards compatibility.
|
||||
MigratePreGecko42StorageDir(gmpDirWithoutPlatform, mStorageBaseDir);
|
||||
|
||||
// Prior to 45, GMP storage was not separated by plugin. In 45 and after,
|
||||
// it's stored in $profile/gmp/$platform/$gmpName. So we must migrate old
|
||||
// records from the old location to the new location, for forwards
|
||||
// compatibility. We assume all directories in the base storage dir that
|
||||
// aren't known to GMP storage are records for the Adobe GMP, since it
|
||||
// was first.
|
||||
MigratePreGecko45StorageDir(mStorageBaseDir);
|
||||
|
||||
return GeckoMediaPluginService::Init();
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
using GMPBufferType from "gmp-video-codec.h";
|
||||
using GMPAudioCodecType from "gmp-audio-codec.h";
|
||||
using GMPMediaKeyStatus from "gmp-decryption.h";
|
||||
|
||||
namespace mozilla {
|
||||
@ -50,33 +49,6 @@ struct GMPVideoi420FrameData
|
||||
uint64_t mDuration; // microseconds
|
||||
};
|
||||
|
||||
struct GMPAudioCodecData
|
||||
{
|
||||
GMPAudioCodecType mCodecType;
|
||||
uint32_t mChannelCount;
|
||||
uint32_t mBitsPerChannel;
|
||||
uint32_t mSamplesPerSecond;
|
||||
|
||||
uint8_t[] mExtraData;
|
||||
};
|
||||
|
||||
struct GMPAudioEncodedSampleData
|
||||
{
|
||||
uint8_t[] mData;
|
||||
uint64_t mTimeStamp; // microseconds.
|
||||
GMPDecryptionData mDecryptionData;
|
||||
uint32_t mChannelCount;
|
||||
uint32_t mSamplesPerSecond;
|
||||
};
|
||||
|
||||
struct GMPAudioDecodedSampleData
|
||||
{
|
||||
int16_t[] mData;
|
||||
uint64_t mTimeStamp; // microseconds.
|
||||
uint32_t mChannelCount;
|
||||
uint32_t mSamplesPerSecond;
|
||||
};
|
||||
|
||||
struct GMPKeyInformation {
|
||||
uint8_t[] keyId;
|
||||
GMPMediaKeyStatus status;
|
||||
|
@ -1,37 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PGMPContent;
|
||||
include GMPTypes;
|
||||
|
||||
using GMPCodecSpecificInfo from "gmp-audio-codec.h";
|
||||
using GMPErr from "gmp-errors.h";
|
||||
|
||||
include "GMPMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
async protocol PGMPAudioDecoder
|
||||
{
|
||||
manager PGMPContent;
|
||||
child:
|
||||
async InitDecode(GMPAudioCodecData aCodecSettings);
|
||||
async Decode(GMPAudioEncodedSampleData aInput);
|
||||
async Reset();
|
||||
async Drain();
|
||||
async DecodingComplete();
|
||||
parent:
|
||||
async __delete__();
|
||||
async Decoded(GMPAudioDecodedSampleData aDecoded);
|
||||
async InputDataExhausted();
|
||||
async DrainComplete();
|
||||
async ResetComplete();
|
||||
async Error(GMPErr aErr);
|
||||
async Shutdown();
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
@ -8,7 +8,6 @@ include protocol PGMPService;
|
||||
include protocol PGMPVideoDecoder;
|
||||
include protocol PGMPVideoEncoder;
|
||||
include protocol PGMPDecryptor;
|
||||
include protocol PGMPAudioDecoder;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
@ -17,13 +16,11 @@ intr protocol PGMPContent
|
||||
{
|
||||
bridges PGMPService, PGMP;
|
||||
|
||||
manages PGMPAudioDecoder;
|
||||
manages PGMPDecryptor;
|
||||
manages PGMPVideoDecoder;
|
||||
manages PGMPVideoEncoder;
|
||||
|
||||
child:
|
||||
async PGMPAudioDecoder();
|
||||
async PGMPDecryptor();
|
||||
async PGMPVideoDecoder(uint32_t aDecryptorId);
|
||||
async PGMPVideoEncoder();
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GMP_AUDIO_CODEC_h_
|
||||
#define GMP_AUDIO_CODEC_h_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum GMPAudioCodecType
|
||||
{
|
||||
kGMPAudioCodecAAC,
|
||||
kGMPAudioCodecVorbis,
|
||||
kGMPAudioCodecInvalid // Should always be last.
|
||||
};
|
||||
|
||||
struct GMPAudioCodec
|
||||
{
|
||||
GMPAudioCodecType mCodecType;
|
||||
uint32_t mChannelCount;
|
||||
uint32_t mBitsPerChannel;
|
||||
uint32_t mSamplesPerSecond;
|
||||
|
||||
// Codec extra data, such as vorbis setup header, or
|
||||
// AAC AudioSpecificConfig.
|
||||
// These are null/0 if not externally negotiated
|
||||
const uint8_t* mExtraData;
|
||||
uint32_t mExtraDataLen;
|
||||
};
|
||||
|
||||
#endif // GMP_AUDIO_CODEC_h_
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GMP_AUDIO_DECODE_h_
|
||||
#define GMP_AUDIO_DECODE_h_
|
||||
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-audio-samples.h"
|
||||
#include "gmp-audio-codec.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
|
||||
class GMPAudioDecoderCallback
|
||||
{
|
||||
public:
|
||||
virtual ~GMPAudioDecoderCallback() {}
|
||||
|
||||
virtual void Decoded(GMPAudioSamples* aDecodedSamples) = 0;
|
||||
|
||||
virtual void InputDataExhausted() = 0;
|
||||
|
||||
virtual void DrainComplete() = 0;
|
||||
|
||||
virtual void ResetComplete() = 0;
|
||||
|
||||
// Called when the decoder encounters a catestrophic error and cannot
|
||||
// continue. Gecko will not send any more input for decoding.
|
||||
virtual void Error(GMPErr aError) = 0;
|
||||
};
|
||||
|
||||
#define GMP_API_AUDIO_DECODER "decode-audio"
|
||||
|
||||
// Audio decoding for a single stream. A GMP may be asked to create multiple
|
||||
// decoders concurrently.
|
||||
//
|
||||
// API name macro: GMP_API_AUDIO_DECODER
|
||||
// Host API: GMPAudioHost
|
||||
//
|
||||
// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
|
||||
class GMPAudioDecoder
|
||||
{
|
||||
public:
|
||||
virtual ~GMPAudioDecoder() {}
|
||||
|
||||
// aCallback: Subclass should retain reference to it until DecodingComplete
|
||||
// is called. Do not attempt to delete it, host retains ownership.
|
||||
// TODO: Pass AudioHost so decoder can create GMPAudioEncodedFrame objects?
|
||||
virtual void InitDecode(const GMPAudioCodec& aCodecSettings,
|
||||
GMPAudioDecoderCallback* aCallback) = 0;
|
||||
|
||||
// Decode encoded audio frames (as a part of an audio stream). The decoded
|
||||
// frames must be returned to the user through the decode complete callback.
|
||||
virtual void Decode(GMPAudioSamples* aEncodedSamples) = 0;
|
||||
|
||||
// Reset decoder state and prepare for a new call to Decode(...).
|
||||
// Flushes the decoder pipeline.
|
||||
// The decoder should enqueue a task to run ResetComplete() on the main
|
||||
// thread once the reset has finished.
|
||||
virtual void Reset() = 0;
|
||||
|
||||
// Output decoded frames for any data in the pipeline, regardless of ordering.
|
||||
// All remaining decoded frames should be immediately returned via callback.
|
||||
// The decoder should enqueue a task to run DrainComplete() on the main
|
||||
// thread once the reset has finished.
|
||||
virtual void Drain() = 0;
|
||||
|
||||
// May free decoder memory.
|
||||
virtual void DecodingComplete() = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_VIDEO_DECODE_h_
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GMP_AUDIO_HOST_h_
|
||||
#define GMP_AUDIO_HOST_h_
|
||||
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-audio-samples.h"
|
||||
|
||||
class GMPAudioHost
|
||||
{
|
||||
public:
|
||||
// Construct various Audio API objects. Host does not retain reference,
|
||||
// caller is owner and responsible for deleting.
|
||||
virtual GMPErr CreateSamples(GMPAudioFormat aFormat,
|
||||
GMPAudioSamples** aSamples) = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_AUDIO_HOST_h_
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013, Mozilla Foundation and contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GMP_AUDIO_FRAME_h_
|
||||
#define GMP_AUDIO_FRAME_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "gmp-errors.h"
|
||||
#include "gmp-decryption.h"
|
||||
|
||||
enum GMPAudioFormat
|
||||
{
|
||||
kGMPAudioEncodedSamples, // Raw compressed data, i.e. an AAC/Vorbis packet.
|
||||
kGMPAudioIS16Samples, // Interleaved int16_t PCM samples.
|
||||
kGMPAudioSamplesFormatInvalid // Should always be last.
|
||||
};
|
||||
|
||||
class GMPAudioSamples {
|
||||
public:
|
||||
// The format of the buffer.
|
||||
virtual GMPAudioFormat GetFormat() = 0;
|
||||
virtual void Destroy() = 0;
|
||||
|
||||
// MAIN THREAD ONLY
|
||||
// Buffer size must be exactly what's required to contain all samples in
|
||||
// the buffer; every byte is assumed to be part of a sample.
|
||||
virtual GMPErr SetBufferSize(uint32_t aSize) = 0;
|
||||
|
||||
// Size of the buffer in bytes.
|
||||
virtual uint32_t Size() = 0;
|
||||
|
||||
// Timestamps are in microseconds, and are the playback start time of the
|
||||
// first sample in the buffer.
|
||||
virtual void SetTimeStamp(uint64_t aTimeStamp) = 0;
|
||||
virtual uint64_t TimeStamp() = 0;
|
||||
virtual const uint8_t* Buffer() const = 0;
|
||||
virtual uint8_t* Buffer() = 0;
|
||||
|
||||
// Get metadata describing how this frame is encrypted, or nullptr if the
|
||||
// buffer is not encrypted.
|
||||
virtual const GMPEncryptedBufferMetadata* GetDecryptionData() const = 0;
|
||||
|
||||
virtual uint32_t Channels() const = 0;
|
||||
virtual void SetChannels(uint32_t aChannels) = 0;
|
||||
|
||||
// Rate; the number of frames per second, where a "frame" is one sample for
|
||||
// each channel.
|
||||
//
|
||||
// For IS16 samples, the number of samples should be:
|
||||
// Size() / (Channels() * sizeof(int16_t)).
|
||||
//
|
||||
// Note: Channels() and Rate() may not be constant across a decoding
|
||||
// session. For example the rate for decoded samples may be different
|
||||
// than the rate advertised by the MP4 container for encoded samples
|
||||
// for HE-AAC streams with SBR/PS, and an EME-GMP may need to downsample
|
||||
// to satisfy DRM requirements.
|
||||
virtual uint32_t Rate() const = 0;
|
||||
virtual void SetRate(uint32_t aRate) = 0;
|
||||
};
|
||||
|
||||
#endif // GMP_AUDIO_FRAME_h_
|
@ -234,10 +234,7 @@ enum GMPSessionType {
|
||||
kGMPSessionInvalid = 2 // Must always be last.
|
||||
};
|
||||
|
||||
// Gecko supports the current GMPDecryptor version, and the obsolete
|
||||
// version that the Adobe GMP still uses.
|
||||
#define GMP_API_DECRYPTOR "eme-decrypt-v9"
|
||||
#define GMP_API_DECRYPTOR_BACKWARDS_COMPAT "eme-decrypt-v7"
|
||||
|
||||
// API exposed by plugin library to manage decryption sessions.
|
||||
// When the Host requests this by calling GMPGetAPIFunc().
|
||||
@ -349,111 +346,4 @@ public:
|
||||
virtual ~GMPDecryptor() {}
|
||||
};
|
||||
|
||||
// v7 is the latest decryptor version supported by the Adobe GMP.
|
||||
//
|
||||
// API name macro: GMP_API_DECRYPTOR_BACKWARDS_COMPAT
|
||||
// Host API: GMPDecryptorHost
|
||||
class GMPDecryptor7 {
|
||||
public:
|
||||
|
||||
// Sets the callback to use with the decryptor to return results
|
||||
// to Gecko.
|
||||
virtual void Init(GMPDecryptorCallback* aCallback) = 0;
|
||||
|
||||
// Initiates the creation of a session given |aType| and |aInitData|, and
|
||||
// the generation of a license request message.
|
||||
//
|
||||
// This corresponds to a MediaKeySession.generateRequest() call in JS.
|
||||
//
|
||||
// The GMPDecryptor must do the following, in order, upon this method
|
||||
// being called:
|
||||
//
|
||||
// 1. Generate a sessionId to expose to JS, and call
|
||||
// GMPDecryptorCallback::SetSessionId(aCreateSessionToken, sessionId...)
|
||||
// with the sessionId to be exposed to JS/EME on the MediaKeySession
|
||||
// object on which generateRequest() was called, and then
|
||||
// 2. send any messages to JS/EME required to generate a license request
|
||||
// given the supplied initData, and then
|
||||
// 3. generate a license request message, and send it to JS/EME, and then
|
||||
// 4. call GMPDecryptorCallback::ResolvePromise().
|
||||
//
|
||||
// Note: GMPDecryptorCallback::SetSessionId(aCreateSessionToken, sessionId, ...)
|
||||
// *must* be called before GMPDecryptorCallback::SendMessage(sessionId, ...)
|
||||
// will work.
|
||||
//
|
||||
// If generating the request fails, reject aPromiseId by calling
|
||||
// GMPDecryptorCallback::RejectPromise().
|
||||
virtual void CreateSession(uint32_t aCreateSessionToken,
|
||||
uint32_t aPromiseId,
|
||||
const char* aInitDataType,
|
||||
uint32_t aInitDataTypeSize,
|
||||
const uint8_t* aInitData,
|
||||
uint32_t aInitDataSize,
|
||||
GMPSessionType aSessionType) = 0;
|
||||
|
||||
// Loads a previously loaded persistent session.
|
||||
//
|
||||
// This corresponds to a MediaKeySession.load() call in JS.
|
||||
//
|
||||
// The GMPDecryptor must do the following, in order, upon this method
|
||||
// being called:
|
||||
//
|
||||
// 1. Send any messages to JS/EME, or read from storage, whatever is
|
||||
// required to load the session, and then
|
||||
// 2. if there is no session with the given sessionId loadable, call
|
||||
// ResolveLoadSessionPromise(aPromiseId, false), otherwise
|
||||
// 2. mark the session's keys as usable, and then
|
||||
// 3. update the session's expiration, and then
|
||||
// 4. call GMPDecryptorCallback::ResolveLoadSessionPromise(aPromiseId, true).
|
||||
//
|
||||
// If loading the session fails due to error, reject aPromiseId by calling
|
||||
// GMPDecryptorCallback::RejectPromise().
|
||||
virtual void LoadSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) = 0;
|
||||
|
||||
// Updates the session with |aResponse|.
|
||||
// This corresponds to a MediaKeySession.update() call in JS.
|
||||
virtual void UpdateSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aResponse,
|
||||
uint32_t aResponseSize) = 0;
|
||||
|
||||
// Releases the resources (keys) for the specified session.
|
||||
// This corresponds to a MediaKeySession.close() call in JS.
|
||||
virtual void CloseSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) = 0;
|
||||
|
||||
// Removes the resources (keys) for the specified session.
|
||||
// This corresponds to a MediaKeySession.remove() call in JS.
|
||||
virtual void RemoveSession(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdLength) = 0;
|
||||
|
||||
// Resolve/reject promise on completion.
|
||||
// This corresponds to a MediaKeySession.setServerCertificate() call in JS.
|
||||
virtual void SetServerCertificate(uint32_t aPromiseId,
|
||||
const uint8_t* aServerCert,
|
||||
uint32_t aServerCertSize) = 0;
|
||||
|
||||
// Asynchronously decrypts aBuffer in place. When the decryption is
|
||||
// complete, GMPDecryptor should write the decrypted data back into the
|
||||
// same GMPBuffer object and return it to Gecko by calling Decrypted(),
|
||||
// with the GMPNoErr successcode. If decryption fails, call Decrypted()
|
||||
// with a failure code, and an error event will fire on the media element.
|
||||
// Note: When Decrypted() is called and aBuffer is passed back, aBuffer
|
||||
// is deleted. Don't forget to call Decrypted(), as otherwise aBuffer's
|
||||
// memory will leak!
|
||||
virtual void Decrypt(GMPBuffer* aBuffer,
|
||||
GMPEncryptedBufferMetadata* aMetadata) = 0;
|
||||
|
||||
// Called when the decryption operations are complete.
|
||||
// Do not call the GMPDecryptorCallback's functions after this is called.
|
||||
virtual void DecryptingComplete() = 0;
|
||||
|
||||
virtual ~GMPDecryptor7() {}
|
||||
};
|
||||
|
||||
#endif // GMP_DECRYPTION_h_
|
||||
|
@ -13,10 +13,6 @@ XPIDL_SOURCES += [
|
||||
|
||||
EXPORTS += [
|
||||
'gmp-api/gmp-async-shutdown.h',
|
||||
'gmp-api/gmp-audio-codec.h',
|
||||
'gmp-api/gmp-audio-decode.h',
|
||||
'gmp-api/gmp-audio-host.h',
|
||||
'gmp-api/gmp-audio-samples.h',
|
||||
'gmp-api/gmp-decryption.h',
|
||||
'gmp-api/gmp-entrypoints.h',
|
||||
'gmp-api/gmp-errors.h',
|
||||
@ -30,10 +26,6 @@ EXPORTS += [
|
||||
'gmp-api/gmp-video-frame.h',
|
||||
'gmp-api/gmp-video-host.h',
|
||||
'gmp-api/gmp-video-plane.h',
|
||||
'GMPAudioDecoderChild.h',
|
||||
'GMPAudioDecoderParent.h',
|
||||
'GMPAudioDecoderProxy.h',
|
||||
'GMPAudioHost.h',
|
||||
'GMPCallbackBase.h',
|
||||
'GMPCDMCallbackProxy.h',
|
||||
'GMPCDMProxy.h',
|
||||
@ -85,9 +77,6 @@ if CONFIG['OS_ARCH'] == 'Linux':
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'GMPAudioDecoderChild.cpp',
|
||||
'GMPAudioDecoderParent.cpp',
|
||||
'GMPAudioHost.cpp',
|
||||
'GMPCDMCallbackProxy.cpp',
|
||||
'GMPCDMProxy.cpp',
|
||||
'GMPChild.cpp',
|
||||
@ -130,7 +119,6 @@ DIRS += [
|
||||
IPDL_SOURCES += [
|
||||
'GMPTypes.ipdlh',
|
||||
'PGMP.ipdl',
|
||||
'PGMPAudioDecoder.ipdl',
|
||||
'PGMPContent.ipdl',
|
||||
'PGMPDecryptor.ipdl',
|
||||
'PGMPService.ipdl',
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsStringGlue.h"
|
||||
class GMPAudioDecoderProxy;
|
||||
class GMPDecryptorProxy;
|
||||
class GMPVideoDecoderProxy;
|
||||
class GMPVideoEncoderProxy;
|
||||
@ -37,7 +36,6 @@ public:
|
||||
virtual void Done(T*, GMPVideoHost*) = 0;
|
||||
};
|
||||
typedef GMPGetterCallback<GMPDecryptorProxy> GetGMPDecryptorCallback;
|
||||
typedef GMPGetterCallback<GMPAudioDecoderProxy> GetGMPAudioDecoderCallback;
|
||||
typedef GMPVideoGetterCallback<GMPVideoDecoderProxy> GetGMPVideoDecoderCallback;
|
||||
typedef GMPVideoGetterCallback<GMPVideoEncoderProxy> GetGMPVideoEncoderCallback;
|
||||
class GetNodeIdCallback
|
||||
@ -51,7 +49,6 @@ public:
|
||||
|
||||
[ptr] native TagArray(nsTArray<nsCString>);
|
||||
native GetGMPDecryptorCallback(mozilla::UniquePtr<GetGMPDecryptorCallback>&&);
|
||||
native GetGMPAudioDecoderCallback(mozilla::UniquePtr<GetGMPAudioDecoderCallback>&&);
|
||||
native GetGMPVideoDecoderCallback(mozilla::UniquePtr<GetGMPVideoDecoderCallback>&&);
|
||||
native GetGMPVideoEncoderCallback(mozilla::UniquePtr<GetGMPVideoEncoderCallback>&&);
|
||||
native GetNodeIdCallback(mozilla::UniquePtr<GetNodeIdCallback>&&);
|
||||
@ -126,23 +123,6 @@ interface mozIGeckoMediaPluginService : nsISupports
|
||||
[optional] in ACString nodeId,
|
||||
in GetGMPVideoEncoderCallback callback);
|
||||
|
||||
/**
|
||||
* Returns an audio decoder that supports the specified tags.
|
||||
* The array of tags should at least contain a codec tag, and optionally
|
||||
* other tags such as for EME keysystem.
|
||||
* Callable only on GMP thread.
|
||||
* This is an asynchronous operation, the Done method of the callback object
|
||||
* will be called on the GMP thread with the result (which might be null in
|
||||
* the case of failure). This method always takes ownership of the callback
|
||||
* object, but if this method returns an error then the Done method of the
|
||||
* callback object will not be called at all.
|
||||
*/
|
||||
[noscript]
|
||||
void getGMPAudioDecoder(in GMPCrashHelperPtr helper,
|
||||
in TagArray tags,
|
||||
[optional] in ACString nodeId,
|
||||
in GetGMPAudioDecoderCallback callback);
|
||||
|
||||
/**
|
||||
* Returns a decryption session manager that supports the specified tags.
|
||||
* The array of tags should at least contain a key system tag, and optionally
|
||||
|
@ -88,6 +88,7 @@ void
|
||||
VPXDecoder::Shutdown()
|
||||
{
|
||||
vpx_codec_destroy(&mVPX);
|
||||
vpx_codec_destroy(&mVPXAlpha);
|
||||
}
|
||||
|
||||
RefPtr<MediaDataDecoder::InitPromise>
|
||||
|
@ -1,44 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "EMEAudioDecoder.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
EMEAudioCallbackAdapter::Error(GMPErr aErr)
|
||||
{
|
||||
if (aErr == GMPNoKeyErr) {
|
||||
// The GMP failed to decrypt a frame due to not having a key. This can
|
||||
// happen if a key expires or a session is closed during playback.
|
||||
NS_WARNING("GMP failed to decrypt due to lack of key");
|
||||
return;
|
||||
}
|
||||
AudioCallbackAdapter::Error(aErr);
|
||||
}
|
||||
|
||||
EMEAudioDecoder::EMEAudioDecoder(CDMProxy* aProxy,
|
||||
const GMPAudioDecoderParams& aParams)
|
||||
: GMPAudioDecoder(GMPAudioDecoderParams(aParams).WithAdapter(
|
||||
new EMEAudioCallbackAdapter(aParams.mCallback)))
|
||||
, mProxy(aProxy)
|
||||
{}
|
||||
|
||||
void
|
||||
EMEAudioDecoder::InitTags(nsTArray<nsCString>& aTags)
|
||||
{
|
||||
aTags.AppendElement(NS_LITERAL_CSTRING("aac"));
|
||||
aTags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
|
||||
}
|
||||
|
||||
nsCString
|
||||
EMEAudioDecoder::GetNodeId()
|
||||
{
|
||||
return mProxy->GetNodeId();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,37 +0,0 @@
|
||||
/* -*- 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 EMEAudioDecoder_h_
|
||||
#define EMEAudioDecoder_h_
|
||||
|
||||
#include "GMPAudioDecoder.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EMEAudioCallbackAdapter : public AudioCallbackAdapter {
|
||||
public:
|
||||
explicit EMEAudioCallbackAdapter(MediaDataDecoderCallbackProxy* aCallback)
|
||||
: AudioCallbackAdapter(aCallback)
|
||||
{}
|
||||
|
||||
void Error(GMPErr aErr) override;
|
||||
};
|
||||
|
||||
class EMEAudioDecoder : public GMPAudioDecoder {
|
||||
public:
|
||||
EMEAudioDecoder(CDMProxy* aProxy, const GMPAudioDecoderParams& aParams);
|
||||
|
||||
private:
|
||||
void InitTags(nsTArray<nsCString>& aTags) override;
|
||||
nsCString GetNodeId() override;
|
||||
|
||||
RefPtr<CDMProxy> mProxy;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -5,7 +5,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "EMEDecoderModule.h"
|
||||
#include "EMEAudioDecoder.h"
|
||||
#include "EMEVideoDecoder.h"
|
||||
#include "MediaDataDecoderProxy.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
@ -100,11 +99,7 @@ public:
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
// The Adobe GMP AAC decoder gets confused if we pass it non-encrypted
|
||||
// samples with valid crypto data. So clear the crypto data, since the
|
||||
// sample should be decrypted now anyway. If we don't do this and we're
|
||||
// using the Adobe GMP for unencrypted decoding of data that is decrypted
|
||||
// by gmp-clearkey, decoding will fail.
|
||||
// The sample is no longer encrypted, so clear its crypto metadata.
|
||||
UniquePtr<MediaRawDataWriter> writer(aDecrypted.mSample->CreateWriter());
|
||||
writer->mCrypto = CryptoSample();
|
||||
mDecoder->Input(aDecrypted.mSample);
|
||||
@ -264,16 +259,10 @@ EMEDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(aParams.mConfig.mCrypto.mValid);
|
||||
|
||||
if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) {
|
||||
// GMP decodes. Assume that means it can decrypt too.
|
||||
RefPtr<MediaDataDecoderProxy> wrapper =
|
||||
CreateDecoderWrapper(aParams.mCallback, mProxy, aParams.mTaskQueue);
|
||||
auto gmpParams = GMPAudioDecoderParams(aParams).WithCallback(wrapper);
|
||||
wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy, gmpParams));
|
||||
return wrapper.forget();
|
||||
}
|
||||
|
||||
// We don't support using the GMP to decode audio.
|
||||
MOZ_ASSERT(!SupportsMimeType(aParams.mConfig.mMimeType, nullptr));
|
||||
MOZ_ASSERT(mPDM);
|
||||
|
||||
RefPtr<MediaDataDecoder> decoder(mPDM->CreateDecoder(aParams));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
|
@ -5,14 +5,12 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'EMEAudioDecoder.h',
|
||||
'EMEDecoderModule.h',
|
||||
'EMEVideoDecoder.h',
|
||||
'SamplesWaitingForKey.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'EMEAudioDecoder.cpp',
|
||||
'EMEDecoderModule.cpp',
|
||||
'EMEVideoDecoder.cpp',
|
||||
'SamplesWaitingForKey.cpp',
|
||||
|
@ -1,306 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "GMPAudioDecoder.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "GMPDecoderModule.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#if defined(DEBUG)
|
||||
bool IsOnGMPThread()
|
||||
{
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
MOZ_ASSERT(mps);
|
||||
|
||||
nsCOMPtr<nsIThread> gmpThread;
|
||||
nsresult rv = mps->GetThread(getter_AddRefs(gmpThread));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) && gmpThread);
|
||||
return NS_GetCurrentThread() == gmpThread;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
AudioCallbackAdapter::Decoded(const nsTArray<int16_t>& aPCM, uint64_t aTimeStamp, uint32_t aChannels, uint32_t aRate)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
if (aRate == 0 || aChannels == 0) {
|
||||
mCallback->Error(MediaResult(
|
||||
NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL(
|
||||
"Invalid rate or num channels returned on GMP audio samples")));
|
||||
return;
|
||||
}
|
||||
|
||||
size_t numFrames = aPCM.Length() / aChannels;
|
||||
MOZ_ASSERT((aPCM.Length() % aChannels) == 0);
|
||||
AlignedAudioBuffer audioData(aPCM.Length());
|
||||
if (!audioData) {
|
||||
mCallback->Error(
|
||||
MediaResult(NS_ERROR_OUT_OF_MEMORY,
|
||||
RESULT_DETAIL("Unable to allocate audio buffer")));
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < aPCM.Length(); ++i) {
|
||||
audioData[i] = AudioSampleToFloat(aPCM[i]);
|
||||
}
|
||||
|
||||
if (mMustRecaptureAudioPosition) {
|
||||
mAudioFrameSum = 0;
|
||||
auto timestamp = UsecsToFrames(aTimeStamp, aRate);
|
||||
if (!timestamp.isValid()) {
|
||||
mCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
|
||||
RESULT_DETAIL("Invalid timestamp")));
|
||||
return;
|
||||
}
|
||||
mAudioFrameOffset = timestamp.value();
|
||||
mMustRecaptureAudioPosition = false;
|
||||
}
|
||||
|
||||
auto timestamp = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, aRate);
|
||||
if (!timestamp.isValid()) {
|
||||
mCallback->Error(
|
||||
MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
|
||||
RESULT_DETAIL("Invalid timestamp on audio samples")));
|
||||
return;
|
||||
}
|
||||
mAudioFrameSum += numFrames;
|
||||
|
||||
auto duration = FramesToUsecs(numFrames, aRate);
|
||||
if (!duration.isValid()) {
|
||||
mCallback->Error(
|
||||
MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
|
||||
RESULT_DETAIL("Invalid duration on audio samples")));
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<AudioData> audio(new AudioData(mLastStreamOffset,
|
||||
timestamp.value(),
|
||||
duration.value(),
|
||||
numFrames,
|
||||
Move(audioData),
|
||||
aChannels,
|
||||
aRate));
|
||||
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
|
||||
timestamp, duration, currentLength);
|
||||
#endif
|
||||
|
||||
mCallback->Output(audio);
|
||||
}
|
||||
|
||||
void
|
||||
AudioCallbackAdapter::InputDataExhausted()
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
mCallback->InputExhausted();
|
||||
}
|
||||
|
||||
void
|
||||
AudioCallbackAdapter::DrainComplete()
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
mCallback->DrainComplete();
|
||||
}
|
||||
|
||||
void
|
||||
AudioCallbackAdapter::ResetComplete()
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
mMustRecaptureAudioPosition = true;
|
||||
mCallback->FlushComplete();
|
||||
}
|
||||
|
||||
void
|
||||
AudioCallbackAdapter::Error(GMPErr aErr)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
mCallback->Error(MediaResult(aErr == GMPDecodeErr
|
||||
? NS_ERROR_DOM_MEDIA_DECODE_ERR
|
||||
: NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("GMPErr:%x", aErr)));
|
||||
}
|
||||
|
||||
void
|
||||
AudioCallbackAdapter::Terminated()
|
||||
{
|
||||
mCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("Audio GMP decoder terminated.")));
|
||||
}
|
||||
|
||||
GMPAudioDecoderParams::GMPAudioDecoderParams(const CreateDecoderParams& aParams)
|
||||
: mConfig(aParams.AudioConfig())
|
||||
, mTaskQueue(aParams.mTaskQueue)
|
||||
, mCallback(nullptr)
|
||||
, mAdapter(nullptr)
|
||||
, mCrashHelper(aParams.mCrashHelper)
|
||||
{}
|
||||
|
||||
GMPAudioDecoderParams&
|
||||
GMPAudioDecoderParams::WithCallback(MediaDataDecoderProxy* aWrapper)
|
||||
{
|
||||
MOZ_ASSERT(aWrapper);
|
||||
MOZ_ASSERT(!mCallback); // Should only be called once per instance.
|
||||
mCallback = aWrapper->Callback();
|
||||
mAdapter = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GMPAudioDecoderParams&
|
||||
GMPAudioDecoderParams::WithAdapter(AudioCallbackAdapter* aAdapter)
|
||||
{
|
||||
MOZ_ASSERT(aAdapter);
|
||||
MOZ_ASSERT(!mAdapter); // Should only be called once per instance.
|
||||
mCallback = aAdapter->Callback();
|
||||
mAdapter = aAdapter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GMPAudioDecoder::GMPAudioDecoder(const GMPAudioDecoderParams& aParams)
|
||||
: mConfig(aParams.mConfig)
|
||||
, mCallback(aParams.mCallback)
|
||||
, mGMP(nullptr)
|
||||
, mAdapter(aParams.mAdapter)
|
||||
, mCrashHelper(aParams.mCrashHelper)
|
||||
{
|
||||
MOZ_ASSERT(!mAdapter || mCallback == mAdapter->Callback());
|
||||
if (!mAdapter) {
|
||||
mAdapter = new AudioCallbackAdapter(mCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoder::InitTags(nsTArray<nsCString>& aTags)
|
||||
{
|
||||
aTags.AppendElement(NS_LITERAL_CSTRING("aac"));
|
||||
const Maybe<nsCString> gmp(
|
||||
GMPDecoderModule::PreferredGMP(NS_LITERAL_CSTRING("audio/mp4a-latm")));
|
||||
if (gmp.isSome()) {
|
||||
aTags.AppendElement(gmp.value());
|
||||
}
|
||||
}
|
||||
|
||||
nsCString
|
||||
GMPAudioDecoder::GetNodeId()
|
||||
{
|
||||
return SHARED_GMP_DECODING_NODE_ID;
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoder::GMPInitDone(GMPAudioDecoderProxy* aGMP)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
if (!aGMP) {
|
||||
mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
return;
|
||||
}
|
||||
if (mInitPromise.IsEmpty()) {
|
||||
// GMP must have been shutdown while we were waiting for Init operation
|
||||
// to complete.
|
||||
aGMP->Close();
|
||||
return;
|
||||
}
|
||||
nsTArray<uint8_t> codecSpecific;
|
||||
codecSpecific.AppendElements(mConfig.mCodecSpecificConfig->Elements(),
|
||||
mConfig.mCodecSpecificConfig->Length());
|
||||
|
||||
nsresult rv = aGMP->InitDecode(kGMPAudioCodecAAC,
|
||||
mConfig.mChannels,
|
||||
mConfig.mBitDepth,
|
||||
mConfig.mRate,
|
||||
codecSpecific,
|
||||
mAdapter);
|
||||
if (NS_FAILED(rv)) {
|
||||
aGMP->Close();
|
||||
mInitPromise.Reject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
mGMP = aGMP;
|
||||
mInitPromise.Resolve(TrackInfo::kAudioTrack, __func__);
|
||||
}
|
||||
|
||||
RefPtr<MediaDataDecoder::InitPromise>
|
||||
GMPAudioDecoder::Init()
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
MOZ_ASSERT(mMPS);
|
||||
|
||||
RefPtr<InitPromise> promise(mInitPromise.Ensure(__func__));
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
InitTags(tags);
|
||||
UniquePtr<GetGMPAudioDecoderCallback> callback(new GMPInitDoneCallback(this));
|
||||
if (NS_FAILED(mMPS->GetGMPAudioDecoder(mCrashHelper, &tags, GetNodeId(), Move(callback)))) {
|
||||
mInitPromise.Reject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoder::Input(MediaRawData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
RefPtr<MediaRawData> sample(aSample);
|
||||
if (!mGMP) {
|
||||
mCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("mGMP not initialized")));
|
||||
return;
|
||||
}
|
||||
|
||||
mAdapter->SetLastStreamOffset(sample->mOffset);
|
||||
|
||||
gmp::GMPAudioSamplesImpl samples(sample, mConfig.mChannels, mConfig.mRate);
|
||||
nsresult rv = mGMP->Decode(samples);
|
||||
if (NS_FAILED(rv)) {
|
||||
mCallback->Error(MediaResult(rv, __func__));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoder::Flush()
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
if (!mGMP || NS_FAILED(mGMP->Reset())) {
|
||||
// Abort the flush.
|
||||
mCallback->FlushComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoder::Drain()
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
if (!mGMP || NS_FAILED(mGMP->Drain())) {
|
||||
mCallback->DrainComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoder::Shutdown()
|
||||
{
|
||||
mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
if (!mGMP) {
|
||||
return;
|
||||
}
|
||||
// Note this unblocks flush and drain operations waiting for callbacks.
|
||||
mGMP->Close();
|
||||
mGMP = nullptr;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,112 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#if !defined(GMPAudioDecoder_h_)
|
||||
#define GMPAudioDecoder_h_
|
||||
|
||||
#include "GMPAudioDecoderProxy.h"
|
||||
#include "MediaDataDecoderProxy.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AudioCallbackAdapter : public GMPAudioDecoderCallbackProxy {
|
||||
public:
|
||||
explicit AudioCallbackAdapter(MediaDataDecoderCallbackProxy* aCallback)
|
||||
: mCallback(aCallback)
|
||||
, mLastStreamOffset(0)
|
||||
, mAudioFrameSum(0)
|
||||
, mAudioFrameOffset(0)
|
||||
, mMustRecaptureAudioPosition(true)
|
||||
{}
|
||||
|
||||
MediaDataDecoderCallbackProxy* Callback() const { return mCallback; }
|
||||
|
||||
// GMPAudioDecoderCallbackProxy
|
||||
void Decoded(const nsTArray<int16_t>& aPCM, uint64_t aTimeStamp, uint32_t aChannels, uint32_t aRate) override;
|
||||
void InputDataExhausted() override;
|
||||
void DrainComplete() override;
|
||||
void ResetComplete() override;
|
||||
void Error(GMPErr aErr) override;
|
||||
void Terminated() override;
|
||||
|
||||
void SetLastStreamOffset(int64_t aStreamOffset) {
|
||||
mLastStreamOffset = aStreamOffset;
|
||||
}
|
||||
|
||||
private:
|
||||
MediaDataDecoderCallbackProxy* mCallback;
|
||||
int64_t mLastStreamOffset;
|
||||
|
||||
int64_t mAudioFrameSum;
|
||||
int64_t mAudioFrameOffset;
|
||||
bool mMustRecaptureAudioPosition;
|
||||
};
|
||||
|
||||
struct GMPAudioDecoderParams {
|
||||
explicit GMPAudioDecoderParams(const CreateDecoderParams& aParams);
|
||||
GMPAudioDecoderParams& WithCallback(MediaDataDecoderProxy* aWrapper);
|
||||
GMPAudioDecoderParams& WithAdapter(AudioCallbackAdapter* aAdapter);
|
||||
|
||||
const AudioInfo& mConfig;
|
||||
TaskQueue* mTaskQueue;
|
||||
MediaDataDecoderCallbackProxy* mCallback;
|
||||
AudioCallbackAdapter* mAdapter;
|
||||
RefPtr<GMPCrashHelper> mCrashHelper;
|
||||
};
|
||||
|
||||
class GMPAudioDecoder : public MediaDataDecoder {
|
||||
public:
|
||||
explicit GMPAudioDecoder(const GMPAudioDecoderParams& aParams);
|
||||
|
||||
RefPtr<InitPromise> Init() override;
|
||||
void Input(MediaRawData* aSample) override;
|
||||
void Flush() override;
|
||||
void Drain() override;
|
||||
void Shutdown() override;
|
||||
const char* GetDescriptionName() const override
|
||||
{
|
||||
return "GMP audio decoder";
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void InitTags(nsTArray<nsCString>& aTags);
|
||||
virtual nsCString GetNodeId();
|
||||
|
||||
private:
|
||||
|
||||
class GMPInitDoneCallback : public GetGMPAudioDecoderCallback
|
||||
{
|
||||
public:
|
||||
explicit GMPInitDoneCallback(GMPAudioDecoder* aDecoder)
|
||||
: mDecoder(aDecoder)
|
||||
{
|
||||
}
|
||||
|
||||
void Done(GMPAudioDecoderProxy* aGMP) override
|
||||
{
|
||||
mDecoder->GMPInitDone(aGMP);
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<GMPAudioDecoder> mDecoder;
|
||||
};
|
||||
void GMPInitDone(GMPAudioDecoderProxy* aGMP);
|
||||
|
||||
const AudioInfo mConfig;
|
||||
MediaDataDecoderCallbackProxy* mCallback;
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
|
||||
GMPAudioDecoderProxy* mGMP;
|
||||
nsAutoPtr<AudioCallbackAdapter> mAdapter;
|
||||
MozPromiseHolder<InitPromise> mInitPromise;
|
||||
RefPtr<GMPCrashHelper> mCrashHelper;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // GMPAudioDecoder_h_
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include "GMPDecoderModule.h"
|
||||
#include "DecoderDoctorDiagnostics.h"
|
||||
#include "GMPAudioDecoder.h"
|
||||
#include "GMPVideoDecoder.h"
|
||||
#include "GMPUtils.h"
|
||||
#include "MediaDataDecoderProxy.h"
|
||||
@ -15,7 +14,6 @@
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "gmp-audio-decode.h"
|
||||
#include "gmp-video-decode.h"
|
||||
#include "MP4Decoder.h"
|
||||
#include "VPXDecoder.h"
|
||||
@ -57,13 +55,6 @@ GMPDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aParams.mDiagnostics) {
|
||||
const Maybe<nsCString> preferredGMP = PreferredGMP(aParams.mConfig.mMimeType);
|
||||
if (preferredGMP.isSome()) {
|
||||
aParams.mDiagnostics->SetGMP(preferredGMP.value());
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aParams.mCallback);
|
||||
auto params = GMPVideoDecoderParams(aParams).WithCallback(wrapper);
|
||||
wrapper->SetProxyTarget(new GMPVideoDecoder(params));
|
||||
@ -73,21 +64,7 @@ GMPDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
GMPDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
|
||||
{
|
||||
if (!aParams.mConfig.mMimeType.EqualsLiteral("audio/mp4a-latm")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aParams.mDiagnostics) {
|
||||
const Maybe<nsCString> preferredGMP = PreferredGMP(aParams.mConfig.mMimeType);
|
||||
if (preferredGMP.isSome()) {
|
||||
aParams.mDiagnostics->SetGMP(preferredGMP.value());
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aParams.mCallback);
|
||||
auto params = GMPAudioDecoderParams(aParams).WithCallback(wrapper);
|
||||
wrapper->SetProxyTarget(new GMPAudioDecoder(params));
|
||||
return wrapper.forget();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
@ -101,30 +78,6 @@ GMPDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
const Maybe<nsCString>
|
||||
GMPDecoderModule::PreferredGMP(const nsACString& aMimeType)
|
||||
{
|
||||
Maybe<nsCString> rv;
|
||||
if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
|
||||
switch (MediaPrefs::GMPAACPreferred()) {
|
||||
case 1: rv.emplace(kEMEKeySystemClearkey); break;
|
||||
case 2: rv.emplace(kEMEKeySystemPrimetime); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (MP4Decoder::IsH264(aMimeType)) {
|
||||
switch (MediaPrefs::GMPH264Preferred()) {
|
||||
case 1: rv.emplace(kEMEKeySystemClearkey); break;
|
||||
case 2: rv.emplace(kEMEKeySystemPrimetime); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
GMPDecoderModule::SupportsMimeType(const nsACString& aMimeType,
|
||||
@ -149,11 +102,6 @@ GMPDecoderModule::SupportsMimeType(const nsACString& aMimeType,
|
||||
{ NS_LITERAL_CSTRING("vp8"), aGMP.value()});
|
||||
}
|
||||
|
||||
if (MP4Decoder::IsAAC(aMimeType)) {
|
||||
return HaveGMPFor(NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
|
||||
{ NS_LITERAL_CSTRING("aac"), aGMP.value()});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -161,12 +109,7 @@ bool
|
||||
GMPDecoderModule::SupportsMimeType(const nsACString& aMimeType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics) const
|
||||
{
|
||||
const Maybe<nsCString> preferredGMP = PreferredGMP(aMimeType);
|
||||
bool rv = SupportsMimeType(aMimeType, preferredGMP);
|
||||
if (rv && aDiagnostics && preferredGMP.isSome()) {
|
||||
aDiagnostics->SetGMP(preferredGMP.value());
|
||||
}
|
||||
return rv;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -46,8 +46,6 @@ public:
|
||||
SupportsMimeType(const nsACString& aMimeType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics) const override;
|
||||
|
||||
static const Maybe<nsCString> PreferredGMP(const nsACString& aMimeType);
|
||||
|
||||
static bool SupportsMimeType(const nsACString& aMimeType,
|
||||
const Maybe<nsCString>& aGMP);
|
||||
};
|
||||
|
@ -15,7 +15,16 @@
|
||||
namespace mozilla {
|
||||
|
||||
#if defined(DEBUG)
|
||||
extern bool IsOnGMPThread();
|
||||
static bool IsOnGMPThread()
|
||||
{
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
MOZ_ASSERT(mps);
|
||||
|
||||
nsCOMPtr<nsIThread> gmpThread;
|
||||
nsresult rv = mps->GetThread(getter_AddRefs(gmpThread));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) && gmpThread);
|
||||
return NS_GetCurrentThread() == gmpThread;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
@ -162,11 +171,6 @@ GMPVideoDecoder::InitTags(nsTArray<nsCString>& aTags)
|
||||
{
|
||||
if (MP4Decoder::IsH264(mConfig.mMimeType)) {
|
||||
aTags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
const Maybe<nsCString> gmp(
|
||||
GMPDecoderModule::PreferredGMP(NS_LITERAL_CSTRING("video/avc")));
|
||||
if (gmp.isSome()) {
|
||||
aTags.AppendElement(gmp.value());
|
||||
}
|
||||
} else if (VPXDecoder::IsVP8(mConfig.mMimeType)) {
|
||||
aTags.AppendElement(NS_LITERAL_CSTRING("vp8"));
|
||||
} else if (VPXDecoder::IsVP9(mConfig.mMimeType)) {
|
||||
|
@ -5,14 +5,12 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'GMPAudioDecoder.h',
|
||||
'GMPDecoderModule.h',
|
||||
'GMPVideoDecoder.h',
|
||||
'MediaDataDecoderProxy.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'GMPAudioDecoder.cpp',
|
||||
'GMPDecoderModule.cpp',
|
||||
'GMPVideoDecoder.cpp',
|
||||
'MediaDataDecoderProxy.cpp',
|
||||
|
@ -200,19 +200,6 @@ class NetworkBandwidthTestsMixin(object):
|
||||
self.run_videos(timeout=120)
|
||||
|
||||
|
||||
reset_adobe_gmp_script = """
|
||||
navigator.requestMediaKeySystemAccess('com.adobe.primetime',
|
||||
[{initDataTypes: ['cenc']}]).then(
|
||||
function(access) {
|
||||
marionetteScriptFinished('success');
|
||||
},
|
||||
function(ex) {
|
||||
marionetteScriptFinished(ex);
|
||||
}
|
||||
);
|
||||
"""
|
||||
|
||||
|
||||
reset_widevine_gmp_script = """
|
||||
navigator.requestMediaKeySystemAccess('com.widevine.alpha',
|
||||
[{initDataTypes: ['cenc']}]).then(
|
||||
@ -229,7 +216,7 @@ navigator.requestMediaKeySystemAccess('com.widevine.alpha',
|
||||
class EMESetupMixin(object):
|
||||
|
||||
"""
|
||||
An object that needs to use the Adobe or Widevine GMP system must inherit
|
||||
An object that needs to use the Widevine GMP system must inherit
|
||||
from this class, and then call check_eme_system() to insure that everything
|
||||
is setup correctly.
|
||||
"""
|
||||
@ -238,7 +225,7 @@ class EMESetupMixin(object):
|
||||
|
||||
def check_eme_system(self):
|
||||
"""
|
||||
Download the most current version of the Adobe and Widevine GMP
|
||||
Download the most current version of the Widevine GMP
|
||||
Plugins. Verify that all MSE and EME prefs are set correctly. Raises
|
||||
if things are not OK.
|
||||
"""
|
||||
@ -256,21 +243,12 @@ class EMESetupMixin(object):
|
||||
def reset_GMP_version(self):
|
||||
if EMESetupMixin.version_needs_reset:
|
||||
with self.marionette.using_context(Marionette.CONTEXT_CHROME):
|
||||
if self.marionette.get_pref('media.gmp-eme-adobe.version'):
|
||||
self.marionette.reset_pref('media.gmp-eme-adobe.version')
|
||||
if self.marionette.get_pref('media.gmp-widevinecdm.version'):
|
||||
self.marionette.reset_pref('media.gmp-widevinecdm.version')
|
||||
with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
|
||||
adobe_result = self.marionette.execute_async_script(
|
||||
reset_adobe_gmp_script,
|
||||
script_timeout=60000)
|
||||
widevine_result = self.marionette.execute_async_script(
|
||||
reset_widevine_gmp_script,
|
||||
script_timeout=60000)
|
||||
if not adobe_result == 'success':
|
||||
raise VideoException(
|
||||
'ERROR: Resetting Adobe GMP failed {}'
|
||||
.format(adobe_result))
|
||||
if not widevine_result == 'success':
|
||||
raise VideoException(
|
||||
'ERROR: Resetting Widevine GMP failed {}'
|
||||
@ -351,10 +329,6 @@ class EMESetupMixin(object):
|
||||
'media.eme.enabled', True),
|
||||
self.check_and_log_boolean_pref(
|
||||
'media.mediasource.mp4.enabled', True),
|
||||
self.check_and_log_boolean_pref(
|
||||
'media.gmp-eme-adobe.enabled', True),
|
||||
self.check_and_log_integer_pref(
|
||||
'media.gmp-eme-adobe.version', 1),
|
||||
self.check_and_log_boolean_pref(
|
||||
'media.gmp-widevinecdm.enabled', True),
|
||||
self.chceck_and_log_version_string_pref(
|
||||
|
@ -486,7 +486,7 @@ function testCalcFontSize()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
|
||||
var anim = createAnimSetTo("font-size", "-moz-calc(110% + 0.1em)");
|
||||
var anim = createAnimSetTo("font-size", "calc(110% + 0.1em)");
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
|
||||
|
@ -27,3 +27,18 @@ skip-if = !e10s
|
||||
skip-if = !e10s
|
||||
[test_appid_facet_subdomain.html]
|
||||
skip-if = !e10s
|
||||
[test_webauthn_loopback.html]
|
||||
skip-if = !e10s
|
||||
scheme = https
|
||||
[test_webauthn_no_token.html]
|
||||
skip-if = !e10s
|
||||
scheme = https
|
||||
[test_webauthn_make_credential.html]
|
||||
skip-if = !e10s
|
||||
scheme = https
|
||||
[test_webauthn_get_assertion.html]
|
||||
skip-if = !e10s
|
||||
scheme = https
|
||||
[test_webauthn_sameorigin.html]
|
||||
skip-if = !e10s
|
||||
scheme = https
|
91
dom/u2f/tests/test_webauthn_get_assertion.html
Normal file
91
dom/u2f/tests/test_webauthn_get_assertion.html
Normal file
@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<title>Tests for GetAssertion for W3C Web Authentication</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="u2futil.js"></script>
|
||||
<script type="text/javascript" src="pkijs/common.js"></script>
|
||||
<script type="text/javascript" src="pkijs/asn1.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_schema.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_simpl.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Tests for GetAssertion for W3C Web Authentication</h1>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
// Execute the full-scope test
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function arrivingHereIsBad(aResult) {
|
||||
ok(false, "Bad result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectNotAllowedError(aResult) {
|
||||
ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectTypeError(aResult) {
|
||||
ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.webauth.w3c", true],
|
||||
["security.webauth.u2f_enable_softtoken", true],
|
||||
["security.webauth.u2f_enable_usbtoken", false]]},
|
||||
function() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
|
||||
let gAssertionChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(gAssertionChallenge);
|
||||
|
||||
let invalidCred = { type: "Magic", id: base64ToBytes("AAA=") };
|
||||
let unknownCred = { type: "ScopedCred", id: base64ToBytes("AAA=") };
|
||||
|
||||
Promise.all([
|
||||
// Test basic good call, but without giving a credential so expect failures
|
||||
// this is OK by the standard, but not supported by U2F-backed authenticators
|
||||
// like the soft token in use here.
|
||||
authn.getAssertion(gAssertionChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError),
|
||||
|
||||
// Test with an unexpected option
|
||||
authn.getAssertion(gAssertionChallenge, { unknownValue: "hi" })
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError),
|
||||
|
||||
// Test with an invalid credential
|
||||
authn.getAssertion(gAssertionChallenge, { allowList: [invalidCred] })
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
// Test with an unknown credential
|
||||
authn.getAssertion(gAssertionChallenge, { allowList: [unknownCred] })
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError),
|
||||
|
||||
// Test with an unexpected option and an invalid credential
|
||||
authn.getAssertion(gAssertionChallenge, { unknownValue: "hi" })
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError)
|
||||
])
|
||||
.then(function(){
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
170
dom/u2f/tests/test_webauthn_loopback.html
Normal file
170
dom/u2f/tests/test_webauthn_loopback.html
Normal file
@ -0,0 +1,170 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<title>Full-run test for MakeCredential/GetAssertion for W3C Web Authentication</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="u2futil.js"></script>
|
||||
<script type="text/javascript" src="pkijs/common.js"></script>
|
||||
<script type="text/javascript" src="pkijs/asn1.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_schema.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_simpl.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Full-run test for MakeCredential/GetAssertion for W3C Web Authentication</h1>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
// Execute the full-scope test
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.webauth.w3c", true],
|
||||
["security.webauth.u2f_enable_softtoken", true],
|
||||
["security.webauth.u2f_enable_usbtoken", false]]},
|
||||
function() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
|
||||
let gCredentialChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(gCredentialChallenge);
|
||||
let gAssertionChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(gAssertionChallenge);
|
||||
|
||||
testMakeCredential();
|
||||
|
||||
function checkCredentialValid(aCredInfo) {
|
||||
/* ScopedCredentialInfo
|
||||
- Credential
|
||||
-- ID: Key Handle buffer pulled from U2F Register() Response
|
||||
-- Type: "ScopedCred"
|
||||
- WebAuthnAttestation
|
||||
-- Format: "u2f"
|
||||
-- ClientData: serialized JSON
|
||||
-- AuthenticatorData: RP ID Hash || U2F Sign() Response
|
||||
-- Attestation: U2F Register() Response */
|
||||
|
||||
is(aCredInfo.credential.type, "ScopedCred", "Type is correct");
|
||||
ok(aCredInfo.credential.id.length > 0, "Key ID exists");
|
||||
|
||||
is(aCredInfo.attestation.format, "u2f", "Format is correct");
|
||||
is(aCredInfo.attestation.attestation[0], 0x05, "Reserved byte is correct");
|
||||
ok(aCredInfo.attestation.authenticatorData.length > 0, "Authenticator data exists");
|
||||
let clientData = JSON.parse(buffer2string(aCredInfo.attestation.clientData));
|
||||
is(clientData.challenge, bytesToBase64UrlSafe(gCredentialChallenge), "Challenge is correct");
|
||||
is(clientData.origin, window.location.origin, "Origin is correct");
|
||||
is(clientData.hashAlg, "S256", "Hash algorithm is correct");
|
||||
|
||||
return decodeU2FRegistration(aCredInfo.attestation.attestation)
|
||||
.then(function(u2fObj) {
|
||||
aCredInfo.u2fReg = u2fObj;
|
||||
return aCredInfo;
|
||||
});
|
||||
}
|
||||
|
||||
function checkAssertionAndSigValid(aPublicKey, aAssertion) {
|
||||
/* WebAuthnAssertion
|
||||
- Credential
|
||||
-- ID: ID of Credential from AllowList that succeeded
|
||||
-- Type: "ScopedCred"
|
||||
- ClientData: serialized JSON
|
||||
- AuthenticatorData: RP ID Hash || U2F Sign() Response
|
||||
- Signature: U2F Sign() Response */
|
||||
|
||||
is(aAssertion.credential.type, "ScopedCred", "Type is correct");
|
||||
ok(aAssertion.credential.id.length > 0, "Key ID exists");
|
||||
|
||||
ok(aAssertion.authenticatorData.length > 0, "Authenticator data exists");
|
||||
let clientData = JSON.parse(buffer2string(aAssertion.clientData));
|
||||
is(clientData.challenge, bytesToBase64UrlSafe(gAssertionChallenge), "Challenge is correct");
|
||||
is(clientData.origin, window.location.origin, "Origin is correct");
|
||||
is(clientData.hashAlg, "S256", "Hash algorithm is correct");
|
||||
|
||||
// Parse the signature data
|
||||
if (aAssertion.signature[0] != 0x01) {
|
||||
throw "User presence byte not set";
|
||||
}
|
||||
let presenceAndCounter = aAssertion.signature.slice(0,5);
|
||||
let signatureValue = aAssertion.signature.slice(5);
|
||||
|
||||
let rpIdHash = aAssertion.authenticatorData.slice(0,32);
|
||||
|
||||
// Assemble the signed data and verify the signature
|
||||
return deriveAppAndChallengeParam(clientData.origin, aAssertion.clientData)
|
||||
.then(function(aParams) {
|
||||
console.log(aParams.appParam, rpIdHash, presenceAndCounter, aParams.challengeParam);
|
||||
console.log("ClientData buffer: ", hexEncode(aAssertion.clientData));
|
||||
console.log("ClientDataHash: ", hexEncode(aParams.challengeParam));
|
||||
return assembleSignedData(aParams.appParam, presenceAndCounter, aParams.challengeParam);
|
||||
})
|
||||
.then(function(aSignedData) {
|
||||
console.log(aPublicKey, aSignedData, signatureValue);
|
||||
return verifySignature(aPublicKey, aSignedData, signatureValue);
|
||||
})
|
||||
}
|
||||
|
||||
function testMakeCredential() {
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
|
||||
authn.makeCredential(acct, [param], gCredentialChallenge)
|
||||
.then(checkCredentialValid)
|
||||
.then(testMakeDuplicate)
|
||||
.catch(function(aReason) {
|
||||
ok(false, aReason);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
function testMakeDuplicate(aCredInfo) {
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
let options = {rpId: document.origin,
|
||||
excludeList: [aCredInfo.credential]};
|
||||
|
||||
authn.makeCredential(acct, [param], gCredentialChallenge, options)
|
||||
.then(function() {
|
||||
// We should have errored here!
|
||||
ok(false, "The excludeList didn't stop a duplicate being created!");
|
||||
SimpleTest.finish();
|
||||
})
|
||||
.catch(function(aReason) {
|
||||
ok(aReason.toString().startsWith("NotAllowedError"), "Expect NotAllowedError, got" + aReason);
|
||||
testAssertion(aCredInfo);
|
||||
});
|
||||
}
|
||||
|
||||
function testAssertion(aCredInfo) {
|
||||
let newCredential = {
|
||||
type: aCredInfo.credential.type,
|
||||
id: Uint8Array.from(aCredInfo.credential.id),
|
||||
transports: [ "usb" ],
|
||||
}
|
||||
|
||||
let assertOptions = {rpId: document.origin, timeoutSeconds: 5,
|
||||
allowList: [ newCredential ]};
|
||||
authn.getAssertion(gAssertionChallenge, assertOptions)
|
||||
.then(function(aAssertion) {
|
||||
/* Pass along the pubKey. */
|
||||
return checkAssertionAndSigValid(aCredInfo.u2fReg.publicKey, aAssertion);
|
||||
})
|
||||
.then(function(aSigVerifyResult) {
|
||||
ok(aSigVerifyResult, "Signing signature verified");
|
||||
SimpleTest.finish();
|
||||
})
|
||||
.catch(function(reason) {
|
||||
ok(false, "Signing signature invalid: " + reason);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
158
dom/u2f/tests/test_webauthn_make_credential.html
Normal file
158
dom/u2f/tests/test_webauthn_make_credential.html
Normal file
@ -0,0 +1,158 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<title>Test for MakeCredential for W3C Web Authentication</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="u2futil.js"></script>
|
||||
<script type="text/javascript" src="pkijs/common.js"></script>
|
||||
<script type="text/javascript" src="pkijs/asn1.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_schema.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_simpl.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Test for MakeCredential for W3C Web Authentication</h1>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
// Execute the full-scope test
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function arrivingHereIsGood(aResult) {
|
||||
ok(true, "Good result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function arrivingHereIsBad(aResult) {
|
||||
ok(false, "Bad result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectNotAllowedError(aResult) {
|
||||
ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectTypeError(aResult) {
|
||||
ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectNotSupportedError(aResult) {
|
||||
ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.webauth.w3c", true],
|
||||
["security.webauth.u2f_enable_softtoken", true],
|
||||
["security.webauth.u2f_enable_usbtoken", false]]},
|
||||
function() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
|
||||
let gCredentialChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(gCredentialChallenge);
|
||||
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
let unsupportedParam = {type: "ScopedCred", algorithm: "3DES"};
|
||||
let badParam = {type: "SimplePassword", algorithm: "MaxLength=2"};
|
||||
|
||||
Promise.all([
|
||||
// Test basic good call
|
||||
authn.makeCredential(acct, [param], gCredentialChallenge)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad),
|
||||
|
||||
// Test empty account
|
||||
authn.makeCredential({}, [param], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
// Test without a parameter
|
||||
authn.makeCredential(acct, [], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotSupportedError),
|
||||
|
||||
// Test without a parameter array at all
|
||||
authn.makeCredential(acct, null, gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
// Test with an unsupported parameter
|
||||
authn.makeCredential(acct, [unsupportedParam], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotSupportedError),
|
||||
|
||||
// Test with an unsupported parameter and a good one
|
||||
authn.makeCredential(acct, [unsupportedParam, param], gCredentialChallenge)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad),
|
||||
|
||||
// Test with a bad parameter
|
||||
authn.makeCredential(acct, [badParam], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
// Test with an unsupported parameter, and a bad one
|
||||
authn.makeCredential(acct, [unsupportedParam, badParam],
|
||||
gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
// Test with an unsupported parameter, a bad one, and a good one. This
|
||||
// should still fail, as anything with a badParam should fail.
|
||||
authn.makeCredential(acct, [unsupportedParam, badParam, param],
|
||||
gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
// Test without a challenge
|
||||
authn.makeCredential(acct, [param], null)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
// Test with an invalid challenge
|
||||
authn.makeCredential(acct, [param], "begone, thou ill-fitting moist glove!")
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
// Test with duplicate parameters
|
||||
authn.makeCredential(acct, [param, param, param], gCredentialChallenge)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad),
|
||||
|
||||
// Test an incomplete account
|
||||
authn.makeCredential({id: "none"}, [param], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
authn.makeCredential({name: "none", imageURL: "http://example.com/404"},
|
||||
[param], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError),
|
||||
|
||||
// Test a complete account
|
||||
authn.makeCredential({rpDisplayName: "Foxxy", displayName: "Foxxy V",
|
||||
id: "foxes_are_the_best@example.com",
|
||||
name: "Fox F. Foxington",
|
||||
imageURL: "https://example.com/fox.svg"},
|
||||
[param], gCredentialChallenge)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad)
|
||||
])
|
||||
.then(function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
80
dom/u2f/tests/test_webauthn_no_token.html
Normal file
80
dom/u2f/tests/test_webauthn_no_token.html
Normal file
@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<title>Test for W3C Web Authentication with no token</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="u2futil.js"></script>
|
||||
<script type="text/javascript" src="pkijs/common.js"></script>
|
||||
<script type="text/javascript" src="pkijs/asn1.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_schema.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_simpl.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Test for W3C Web Authentication with no token</h1>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
// Execute the full-scope test
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.webauth.w3c", true],
|
||||
["security.webauth.u2f_enable_softtoken", false],
|
||||
["security.webauth.u2f_enable_usbtoken", false]]},
|
||||
function() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
|
||||
let credentialChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(credentialChallenge);
|
||||
let assertionChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(assertionChallenge);
|
||||
let credentialId = new Uint8Array(128);
|
||||
window.crypto.getRandomValues(credentialId);
|
||||
|
||||
testMakeCredential();
|
||||
|
||||
function testMakeCredential() {
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
authn.makeCredential(acct, [param], credentialChallenge)
|
||||
.then(function(aResult) {
|
||||
ok(false, "Should have failed.");
|
||||
testAssertion();
|
||||
})
|
||||
.catch(function(aReason) {
|
||||
ok(aReason.toString().startsWith("NotAllowedError"), aReason);
|
||||
testAssertion();
|
||||
});
|
||||
}
|
||||
|
||||
function testAssertion() {
|
||||
let newCredential = {
|
||||
type: "ScopedCred",
|
||||
id: credentialId,
|
||||
transports: [ "usb" ],
|
||||
}
|
||||
let assertOptions = {rpId: document.origin, timeoutSeconds: 5,
|
||||
allowList: [ newCredential ]};
|
||||
authn.getAssertion(assertionChallenge, assertOptions)
|
||||
.then(function(aResult) {
|
||||
ok(false, "Should have failed.");
|
||||
SimpleTest.finish();
|
||||
})
|
||||
.catch(function(aReason) {
|
||||
ok(aReason.toString().startsWith("NotAllowedError"), aReason);
|
||||
SimpleTest.finish();
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
162
dom/u2f/tests/test_webauthn_sameorigin.html
Normal file
162
dom/u2f/tests/test_webauthn_sameorigin.html
Normal file
@ -0,0 +1,162 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<title>Test for MakeCredential for W3C Web Authentication</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="u2futil.js"></script>
|
||||
<script type="text/javascript" src="pkijs/common.js"></script>
|
||||
<script type="text/javascript" src="pkijs/asn1.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_schema.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_simpl.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Test Same Origin Policy for W3C Web Authentication</h1>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
// Execute the full-scope test
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var gTrackedCredential = {};
|
||||
|
||||
function arrivingHereIsGood(aResult) {
|
||||
ok(true, "Good result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function arrivingHereIsBad(aResult) {
|
||||
// TODO: Change to `ok` when Bug 1329764 lands
|
||||
todo(false, "Bad result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectSecurityError(aResult) {
|
||||
// TODO: Change to `ok` when Bug 1329764 lands
|
||||
todo(aResult.toString().startsWith("SecurityError"), "Expecting a SecurityError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function keepThisScopedCredential(aScopedCredInfo) {
|
||||
gTrackedCredential = {
|
||||
type: aScopedCredInfo.credential.type,
|
||||
id: Uint8Array.from(aScopedCredInfo.credential.id),
|
||||
transports: [ "usb" ],
|
||||
}
|
||||
return Promise.resolve(aScopedCredInfo);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.webauth.w3c", true],
|
||||
["security.webauth.u2f_enable_softtoken", true],
|
||||
["security.webauth.u2f_enable_usbtoken", false]]},
|
||||
function() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined,
|
||||
"WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.authentication.getAssertion, undefined,
|
||||
"WebAuthn getAssertion API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
|
||||
let chall = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(chall);
|
||||
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
|
||||
Promise.all([
|
||||
// Test basic good call
|
||||
authn.makeCredential(acct, [param], chall, {rpId: document.origin})
|
||||
.then(keepThisScopedCredential)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad),
|
||||
|
||||
// Test rpId being unset
|
||||
authn.makeCredential(acct, [param], chall, {})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad),
|
||||
|
||||
// Test this origin with optional fields
|
||||
authn.makeCredential(acct, [param], chall,
|
||||
{rpId: "user:pass@" + document.origin + ":8888"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError),
|
||||
|
||||
// Test blank rpId
|
||||
authn.makeCredential(acct, [param], chall, {rpId: ""})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError),
|
||||
|
||||
// Test subdomain of this origin
|
||||
authn.makeCredential(acct, [param], chall,
|
||||
{rpId: "subdomain." + document.origin})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError),
|
||||
|
||||
// Test another origin
|
||||
authn.makeCredential(acct, [param], chall, {rpId: "example.com"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError),
|
||||
|
||||
// est a different domain within the same TLD
|
||||
authn.makeCredential(acct, [param], chall, {rpId: "alt.test"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError)
|
||||
|
||||
])
|
||||
.then(function(){
|
||||
return Promise.all([
|
||||
// Test basic good call
|
||||
authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: document.origin})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad),
|
||||
|
||||
// Test rpId being unset
|
||||
authn.getAssertion(chall, {allowList: [ gTrackedCredential ]})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad),
|
||||
|
||||
// Test this origin with optional fields
|
||||
authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: "user:pass@" + document.origin + ":8888"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError),
|
||||
|
||||
// Test blank rpId
|
||||
authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: ""})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError),
|
||||
|
||||
// Test subdomain of this origin
|
||||
authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: "subdomain." + document.origin})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError),
|
||||
|
||||
// Test another origin
|
||||
authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: "example.com"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError),
|
||||
|
||||
// Test a different domain within the same TLD
|
||||
authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: "alt.test"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError)
|
||||
]);
|
||||
})
|
||||
.then(function(){
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -127,6 +127,27 @@ function hexDecode(str) {
|
||||
return new Uint8Array(str.match(/../g).map(x => parseInt(x, 16)));
|
||||
}
|
||||
|
||||
function decodeU2FRegistration(aRegData) {
|
||||
if (aRegData[0] != 0x05) {
|
||||
return Promise.reject("Sentinal byte != 0x05");
|
||||
}
|
||||
|
||||
let keyHandleLength = aRegData[66];
|
||||
let u2fRegObj = {
|
||||
publicKeyBytes: aRegData.slice(1, 66),
|
||||
keyHandleBytes: aRegData.slice(67, 67 + keyHandleLength),
|
||||
attestationBytes: aRegData.slice(67 + keyHandleLength)
|
||||
}
|
||||
|
||||
u2fRegObj.keyHandle = bytesToBase64UrlSafe(u2fRegObj.keyHandleBytes);
|
||||
|
||||
return importPublicKey(u2fRegObj.publicKeyBytes)
|
||||
.then(function(keyObj) {
|
||||
u2fRegObj.publicKey = keyObj;
|
||||
return u2fRegObj;
|
||||
});
|
||||
}
|
||||
|
||||
function importPublicKey(keyBytes) {
|
||||
if (keyBytes[0] != 0x04 || keyBytes.byteLength != 65) {
|
||||
throw "Bad public key octet string";
|
||||
|
@ -91,6 +91,6 @@ int main(int argc, char * argv[]) {
|
||||
mozilla::SetStrongPtr(appData.directory, static_cast<nsIFile*>(appSubdir.get()));
|
||||
greDir.forget(&appData.xreDirectory);
|
||||
|
||||
int result = XRE_main(argc, argv, &appData, 0);
|
||||
int result = XRE_main(argc, argv, &appData);
|
||||
return result;
|
||||
}
|
||||
|
@ -6,8 +6,11 @@
|
||||
|
||||
#include "../contentproc/plugin-container.cpp"
|
||||
|
||||
#include "mozilla/Bootstrap.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@ -15,5 +18,10 @@ main(int argc, char *argv[])
|
||||
DllBlocklist_Initialize();
|
||||
#endif
|
||||
|
||||
return content_process_main(argc, argv);
|
||||
Bootstrap::UniquePtr bootstrap;
|
||||
XRE_GetBootstrap(bootstrap);
|
||||
if (!bootstrap) {
|
||||
return 2;
|
||||
}
|
||||
return content_process_main(bootstrap.get(), argc, argv);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/Bootstrap.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
@ -58,20 +59,20 @@ private:
|
||||
};
|
||||
#endif
|
||||
|
||||
mozilla::gmp::SandboxStarter*
|
||||
mozilla::UniquePtr<mozilla::gmp::SandboxStarter>
|
||||
MakeSandboxStarter()
|
||||
{
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
return new WinSandboxStarter();
|
||||
return mozilla::MakeUnique<WinSandboxStarter>();
|
||||
#elif defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
return new MacSandboxStarter();
|
||||
return mozilla::MakeUnique<MacSandboxStarter>();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
content_process_main(int argc, char* argv[])
|
||||
content_process_main(mozilla::Bootstrap* bootstrap, int argc, char* argv[])
|
||||
{
|
||||
// Check for the absolute minimum number of args we need to move
|
||||
// forward here. We expect the last arg to be the child process type.
|
||||
@ -93,13 +94,13 @@ content_process_main(int argc, char* argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
XRE_SetProcessType(argv[--argc]);
|
||||
bootstrap->XRE_SetProcessType(argv[--argc]);
|
||||
|
||||
#ifdef XP_WIN
|
||||
// For plugins, this is done in PluginProcessChild::Init, as we need to
|
||||
// avoid it for unsupported plugins. See PluginProcessChild::Init for
|
||||
// the details.
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Plugin) {
|
||||
if (bootstrap->XRE_GetProcessType() != GeckoProcessType_Plugin) {
|
||||
mozilla::SanitizeEnvironmentVariables();
|
||||
SetDllDirectoryW(L"");
|
||||
}
|
||||
@ -107,13 +108,10 @@ content_process_main(int argc, char* argv[])
|
||||
#if !defined(XP_LINUX) && defined(MOZ_PLUGIN_CONTAINER)
|
||||
// On Windows and MacOS, the GMPLoader lives in plugin-container, so that its
|
||||
// code can be covered by an EME/GMP vendor's voucher.
|
||||
nsAutoPtr<mozilla::gmp::SandboxStarter> starter(MakeSandboxStarter());
|
||||
if (XRE_GetProcessType() == GeckoProcessType_GMPlugin) {
|
||||
childData.gmpLoader = mozilla::gmp::CreateGMPLoader(starter);
|
||||
if (bootstrap->XRE_GetProcessType() == GeckoProcessType_GMPlugin) {
|
||||
childData.gmpLoader = mozilla::gmp::CreateGMPLoader(MakeSandboxStarter());
|
||||
}
|
||||
#endif
|
||||
nsresult rv = XRE_InitChildProcess(argc, argv, &childData);
|
||||
NS_ENSURE_SUCCESS(rv, 1);
|
||||
|
||||
return 0;
|
||||
nsresult rv = bootstrap->XRE_InitChildProcess(argc, argv, &childData);
|
||||
return NS_FAILED(rv);
|
||||
}
|
||||
|
@ -2,13 +2,16 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsXULAppAPI.h"
|
||||
#define MOZ_IPDL_TESTS
|
||||
#include "mozilla/Bootstrap.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include <windows.h>
|
||||
#include "nsWindowsWMain.cpp"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
@ -16,5 +19,10 @@ main(int argc, char** argv)
|
||||
if (argc < 2)
|
||||
return 1;
|
||||
|
||||
return XRE_RunIPDLTest(argc, argv);
|
||||
Bootstrap::UniquePtr bootstrap;
|
||||
XRE_GetBootstrap(bootstrap);
|
||||
if (!bootstrap) {
|
||||
return 2;
|
||||
}
|
||||
return bootstrap->XRE_RunIPDLTest(argc, argv);
|
||||
}
|
||||
|
@ -49,11 +49,14 @@ class CrossProcessCpowHolder : public CpowHolder
|
||||
CrossProcessCpowHolder(dom::CPOWManagerGetter* managerGetter,
|
||||
const InfallibleTArray<CpowEntry>& cpows);
|
||||
|
||||
~CrossProcessCpowHolder();
|
||||
|
||||
bool ToObject(JSContext* cx, JS::MutableHandleObject objp);
|
||||
|
||||
private:
|
||||
CPOWManager* js_;
|
||||
const InfallibleTArray<CpowEntry>& cpows_;
|
||||
bool unwrapped_;
|
||||
};
|
||||
|
||||
CPOWManager*
|
||||
|
@ -650,16 +650,38 @@ JavaScriptShared::fromObjectOrNullVariant(JSContext* cx, const ObjectOrNullVaria
|
||||
CrossProcessCpowHolder::CrossProcessCpowHolder(dom::CPOWManagerGetter* managerGetter,
|
||||
const InfallibleTArray<CpowEntry>& cpows)
|
||||
: js_(nullptr),
|
||||
cpows_(cpows)
|
||||
cpows_(cpows),
|
||||
unwrapped_(false)
|
||||
{
|
||||
// Only instantiate the CPOW manager if we might need it later.
|
||||
if (cpows.Length())
|
||||
js_ = managerGetter->GetCPOWManager();
|
||||
}
|
||||
|
||||
CrossProcessCpowHolder::~CrossProcessCpowHolder()
|
||||
{
|
||||
if (cpows_.Length() && !unwrapped_) {
|
||||
// This should only happen if a message manager message
|
||||
// containing CPOWs gets ignored for some reason. We need to
|
||||
// unwrap every incoming CPOW in this process to ensure that
|
||||
// the corresponding part of the CPOW in the other process
|
||||
// will eventually be collected. The scope for this object
|
||||
// doesn't really matter, because it immediately becomes
|
||||
// garbage.
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(xpc::PrivilegedJunkScope()))
|
||||
return;
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> cpows(cx);
|
||||
js_->Unwrap(cx, cpows_, &cpows);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CrossProcessCpowHolder::ToObject(JSContext* cx, JS::MutableHandleObject objp)
|
||||
{
|
||||
unwrapped_ = true;
|
||||
|
||||
if (!cpows_.Length())
|
||||
return true;
|
||||
|
||||
|
@ -717,7 +717,6 @@ WrapperOwner::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue
|
||||
return false;
|
||||
|
||||
ReturnStatus status;
|
||||
JSVariant result;
|
||||
if (!SendHasInstance(objId, vVar, &status, bp))
|
||||
return ipcfail(cx);
|
||||
|
||||
|
@ -63,7 +63,6 @@ var ignoreClasses = {
|
||||
"JSLocaleCallbacks" : true,
|
||||
"JSC::ExecutableAllocator" : true,
|
||||
"PRIOMethods": true,
|
||||
"XPCOMFunctions" : true, // I'm a little unsure of this one
|
||||
"_MD_IOVector" : true,
|
||||
"malloc_table_t": true, // replace_malloc
|
||||
"malloc_hook_table_t": true, // replace_malloc
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
#include "mozilla/Bootstrap.h"
|
||||
|
||||
#include "nsXULAppAPI.h"
|
||||
#ifdef XP_MACOSX
|
||||
@ -59,7 +60,13 @@ main(int argc, char** argv, char** envp)
|
||||
mozilla::sandboxing::GetInitializedBrokerServices();
|
||||
#endif
|
||||
|
||||
int result = XRE_XPCShellMain(argc, argv, envp, &shellData);
|
||||
mozilla::Bootstrap::UniquePtr bootstrap;
|
||||
XRE_GetBootstrap(bootstrap);
|
||||
if (!bootstrap) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
int result = bootstrap->XRE_XPCShellMain(argc, argv, envp, &shellData);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
FinishAutoreleasePool();
|
||||
|
@ -16,10 +16,10 @@ setTimeout(function(){
|
||||
document.addEventListener("DOMContentLoaded", initCF);
|
||||
window.onload = initCF;
|
||||
</script><!--
|
||||
--> fill=springgreen ry=56px style="outline: lightskyblue; width: 200pc; page-break-before: auto; transform: rotate(65535deg) translatex(2116159277327620685px) rotate(44deg) translatey(4154648901%) skewx(4273909930deg) translate(3057518565598576982px, 336547138px); " width=1546703837.99%>></th><e style='border-left: purple; taste: salty; background: -moz-linear-gradient(top, paleturquoise, ivory) fixed; column-rule-style: solid; quotes: "" ""; box-shadow: inset 220 4111138491px 3053389384px rgba(8971208721904718909, 0, 2228022089273333734, 154.269191058), 9223372036854775808 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px 14321134px rgba(237, 3316992035388341101, -15, 118354783.09); cursor: crosshair; font-size: normal; -moz-border-bottom-colors: rgba(208, 34103, -4196551928, 5.13284545187x+18) rgba(709904815962541130, 29, -221, 209.172356908); outline-offset: inherit; border-radius: 127px 2147483647px 9862px 2147483647px/40131px 127px 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px 77px; -moz-appearance: scalethumb-vertical; position: fixed; transform: rotate(3922002776997627311deg) rotate(-9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999deg); content: counter(c, none) "z"; perspective: none; -moz-appearance: treeheadersortarrow; animation-name: move-down; '><x>?9(p`r|Agvc@m7]yrXKV.eI`mM+apR]d^UvtpnF xf]{HT~2rROiK(O,o]*XO_jgjJ+B?.EFba!(Fr v@4+=KNIKlC,<fieldset>Ta,c2 ph5ii?/duk?RWcLlmjq3!+U^6e?]^Y9 M5IglbqW;`Gwar.FPvHw0 ++cT2_(.,ZERlDsP|qL_oxzlWf7d=]1w[A%}4e1eNhq$VfqAn|TBq]Ez=.PH`GbZq PH{@L1Q[atH%XT@27m0uya/Z_-:sJ89S!/$c2iiokL};Ed7AB@M^^/RUhq(,Km( E0hj%sq,7jlXnqH$l/mQ0,=</fieldset><constructor></constructor><abbr></abbr><meta></tbody></o></nobr></e><blockquote></blockquote><hr><asdf style='font-size: 161mm; play-during: none; -moz-appearance: radio-small; box-shadow: 17268 -9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px 220 hsla(1140355849941740746, 120%, 131%, 2903913.12919) inset; opacity: auto; content: "This> '>> style='margin: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999em 8933668495516524730 -144.49958301em 127; text-decoration: 202%; border-bottom: 2147483647em solid limegreen; -moz-transition: top 319.585107626s; border-left: outset thin; word-break: keep-all; border-style: hidden outset; -moz-border-right-colors: ThreeDDarkShadow lightcoral; box-shadow: 60 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px -2953355671px hsla(103, 6839212866957213050%, 159%, 11.3751589012) inset, 191 6964375947664294657 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 60108px hsla(1475245254742113175, 47277189%, 255%, 148.45826034) inset, 29984 65535px 50252 hsla(247, 215%, -115%, 38497.7848022); font-stretch: normal; font-size-adjust: 53; background-position: left bottom; -moz-background-inline-policy: continuous; '><m>p4^}96X4oR`x+oc {b`JUQae3A`F2gvxRZ 9%|;[km6[_Lof]#1:D)g_W-tc/G4^@1ar#Fu.vH@D+[utM(9jt-,0i.KMcSfHKb4ZOeMV^(:8sM*d#?NB$eH!49rW_POT*|4@CBGqU;k_++V1AVHo2qI!UWxnXp)eH}O R]:3mjHpu[8E#O$K7Fpg4_e{Jeb<fooz style='top: -moz-calc(9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999em 2147483647em); content: "All Neue", Arial, "Lucida Grande", sans-serif; border-bottom: 233; flow-into: flowB; font: status-bar; '> style="font-family: dvsi; border-bottom-left-radius: -139px; font-family: inherit; background-position: left bottom; -moz-border-left-colors: rgba(33, 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, 58, 3983166662.49) mediumslateblue; counter-reset: c 128 f 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; -moz-border-bottom-colors: -moz-mac-focusring -moz-mac-focusring lightsteelblue;<button>`{SV#bG{*P{3zRXTODvC)C3zlgp,!S81J.YH|,x]U=%P%8)U#]04H5o/Bno;gZDo]H1LMK I?~O,^Hqw@6k%J9FQ|{jkXv QgeAGtzM1# :Ue1-VAa+N0sNP`yINYAIy:d!?I{_FsB7sAx Jfr,4w~cV#:I3H0,z0b$5C.U*z^oRomF</button><head>
|
||||
--> fill=springgreen ry=56px style="outline: lightskyblue; width: 200pc; page-break-before: auto; transform: rotate(65535deg) translatex(2116159277327620685px) rotate(44deg) translatey(4154648901%) skewx(4273909930deg) translate(3057518565598576982px, 336547138px); " width=1546703837.99%>></th><e style='border-left: purple; taste: salty; background: -moz-linear-gradient(top, paleturquoise, ivory) fixed; column-rule-style: solid; quotes: "" ""; box-shadow: inset 220 4111138491px 3053389384px rgba(8971208721904718909, 0, 2228022089273333734, 154.269191058), 9223372036854775808 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px 14321134px rgba(237, 3316992035388341101, -15, 118354783.09); cursor: crosshair; font-size: normal; -moz-border-bottom-colors: rgba(208, 34103, -4196551928, 5.13284545187x+18) rgba(709904815962541130, 29, -221, 209.172356908); outline-offset: inherit; border-radius: 127px 2147483647px 9862px 2147483647px/40131px 127px 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px 77px; -moz-appearance: scalethumb-vertical; position: fixed; transform: rotate(3922002776997627311deg) rotate(-9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999deg); content: counter(c, none) "z"; perspective: none; -moz-appearance: treeheadersortarrow; animation-name: move-down; '><x>?9(p`r|Agvc@m7]yrXKV.eI`mM+apR]d^UvtpnF xf]{HT~2rROiK(O,o]*XO_jgjJ+B?.EFba!(Fr v@4+=KNIKlC,<fieldset>Ta,c2 ph5ii?/duk?RWcLlmjq3!+U^6e?]^Y9 M5IglbqW;`Gwar.FPvHw0 ++cT2_(.,ZERlDsP|qL_oxzlWf7d=]1w[A%}4e1eNhq$VfqAn|TBq]Ez=.PH`GbZq PH{@L1Q[atH%XT@27m0uya/Z_-:sJ89S!/$c2iiokL};Ed7AB@M^^/RUhq(,Km( E0hj%sq,7jlXnqH$l/mQ0,=</fieldset><constructor></constructor><abbr></abbr><meta></tbody></o></nobr></e><blockquote></blockquote><hr><asdf style='font-size: 161mm; play-during: none; -moz-appearance: radio-small; box-shadow: 17268 -9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px 220 hsla(1140355849941740746, 120%, 131%, 2903913.12919) inset; opacity: auto; content: "This> '>> style='margin: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999em 8933668495516524730 -144.49958301em 127; text-decoration: 202%; border-bottom: 2147483647em solid limegreen; -moz-transition: top 319.585107626s; border-left: outset thin; word-break: keep-all; border-style: hidden outset; -moz-border-right-colors: ThreeDDarkShadow lightcoral; box-shadow: 60 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px -2953355671px hsla(103, 6839212866957213050%, 159%, 11.3751589012) inset, 191 6964375947664294657 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 60108px hsla(1475245254742113175, 47277189%, 255%, 148.45826034) inset, 29984 65535px 50252 hsla(247, 215%, -115%, 38497.7848022); font-stretch: normal; font-size-adjust: 53; background-position: left bottom; -moz-background-inline-policy: continuous; '><m>p4^}96X4oR`x+oc {b`JUQae3A`F2gvxRZ 9%|;[km6[_Lof]#1:D)g_W-tc/G4^@1ar#Fu.vH@D+[utM(9jt-,0i.KMcSfHKb4ZOeMV^(:8sM*d#?NB$eH!49rW_POT*|4@CBGqU;k_++V1AVHo2qI!UWxnXp)eH}O R]:3mjHpu[8E#O$K7Fpg4_e{Jeb<fooz style='top: calc(9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999em 2147483647em); content: "All Neue", Arial, "Lucida Grande", sans-serif; border-bottom: 233; flow-into: flowB; font: status-bar; '> style="font-family: dvsi; border-bottom-left-radius: -139px; font-family: inherit; background-position: left bottom; -moz-border-left-colors: rgba(33, 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, 58, 3983166662.49) mediumslateblue; counter-reset: c 128 f 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; -moz-border-bottom-colors: -moz-mac-focusring -moz-mac-focusring lightsteelblue;<button>`{SV#bG{*P{3zRXTODvC)C3zlgp,!S81J.YH|,x]U=%P%8)U#]04H5o/Bno;gZDo]H1LMK I?~O,^Hqw@6k%J9FQ|{jkXv QgeAGtzM1# :Ue1-VAa+N0sNP`yINYAIy:d!?I{_FsB7sAx Jfr,4w~cV#:I3H0,z0b$5C.U*z^oRomF</button><head>
|
||||
></title>
|
||||
<link href=/tests/SimpleTest/test.css<b></b><frame>MS|;yTvb=DyYx=lZ5?NTu=.N@mwsqT!v:=zew_XR7O8YY1o%1=$Oqh=2%a|{M?e/q6]/0VH?s,l4wf!00M7BMNP+j*T?E:POnu? yKL8[Y_nlz+u%QSJB9<csaction>><bdi>w!7RF+P3o}#/~=5hL{2dypxHnV4|@}.jSm@IQ-Ia*i[^/cip/.PKGEX|`bu6+/2RG6}m_*iFTeK~5iI/Zvl.*~32e(_$L#f|1UEh~[Oc_Ej;5Ff:#-?/*W=SLD,kda-7.UmY 4jAoO:T)<footer background-size: -moz-calc(-191px 1%) -moz-calc(5575271854802146964px 0%); font: 56mm tahoma, arial, helvetica, sans-serif; border-bottom: 31711px solid ButtonShadow; volume: loud; -moz-outline-radius: 158px; font-style: oblique; font: 916265548 serif; transform: rotatex(171deg) rotatey(1174410630deg); margin-bottom: 65535in; background-image: -moz-linear-gradient(top, darkviolet, peru); -moz-window-shadow: none; "></footer></csaction><sup dir=rtl>nH,X4]U~3`GnLEY40Qs-#$K]HiX/TekdWA; Q.IGJJwTi%sB^TF^_MFf%3q; wo#]Jy[t8hywiU`ev+8no:+1!Vo?A1tbO{A$iee~-@3Xmt?jzISs1u]B!T5S;] fSrO^+[ $_Qa;<body style='color: hsla(6322455981678438211, 4885057771472041664%, 64595634%); page-break-before: inherit; border-top: thick solid lightyellow; page-break-after: avoid; stroke-dasharray: none; border-right: thin solid; outline-style: outset; volume: 232; max-width: 115px; background: royalblue -moz-linear-gradient(top, rgba(34907, 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, 4705143634018575181, 134.650893313) 196%, rgba(98, 0, 21, 93) 5835518181644000612%); border-bottom-style: double; background-color: -moz-mac-secondaryhighlight; border-bottom-style: solid; content: "Before"; azimuth: center; '>
|
||||
</ul> style='text-align-last: left; -webkit-appearance: textfield; color: rgb(-905311699%, 114, 57742); padding: 21.8234098837em 9.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999em 9.51366390673em 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999em; border-color: rgba(202, 9223372036854775808, -127, 4.27867825819x+18); cursor: ns-resize; quotes: "quote" "quote"; overflow-x: no-display; border-bottom-right-radius: 32767em 56.2654742136em; box-shadow: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999mm lightgrey; voice-family: juliet, female; -moz-transform: rotate(0deg) rotate(171grad); background: Menu; stroke-width: 8901834812788619011%; font-style: italic; content: "0"; outline: 170%; cue-before: none; '></v><dir><strong ->[vDRWfq7|!j5~J^5eQL.?J5VYFl{Vgied3%-fH^bH6?O 4mTi#]%o1xFl.O5hoZ3B;ZRx;1$T2,mgbh5dOeQ*m01547dC1/0V#Y.~WW$ragJ0n!EvBkg8Uegi+]ou1j/^QO*femQC2O!P!j,M5Vk@.-`g`$$+f+^ VP~G{1U</mi><noscript></noscript><rdf>Z[kyp(Mt0@4F~xj@v b=,K#nikG!cNac%qU(O/iUs62cwzV#,6jC[!1y5,PBNr@,Gh~Yn43l1B}p1KEh$m|bn}saNpLjZaspCwM4}XA?CWl)%V]lmIORhh y}o(CHz*vog3iSJ#On-w65NZ=}?5lh/x;xgps-#FD6l,MuASFyd$r.}x6;:v0iM4-S`El`hX%x</rdf><sub></sub><textarea>Fi~{@7J{EVzWdri*Uy+C2nP=gmz.Y;Wvp*:F]]VIVMqdJM=oU,.`Veo:L_x~1u`*f2(!*SGS*!Tsm+VYIeWA^CD10rrxyeMbNhM:SL-}Zf*A4Lf= 81Ka{/gieIN3Ru?#*Sl@~tYe]D.~pEm=s.=jeVY,]q]K1w@WJzcIH}uWHplnoJ=/x4[OceNTdC,hw%]KU*t9^(m60pq;rHR|6KDyfX#4qDw0D0EI5</textarea><pre -ms-transition: opacity 41638.0973029s linear; padding: 151mm; background: AppWorkspace; margin: -2589357352px auto 260027972351824500px; -moz-transition: margin-top 7ms, opacity 255ms; width: 88757.809272mm; -moz-image-region: auto; background: -moz-repeating-radial-gradient(left, circle closest-side, slategrey, hotpink 668335743px, transparent); font-family: "Hiragino Maru ProN"; background-size: auto auto; background: -moz-linear-gradient(bottom, rgb(36899, 36369, 58) 3619699867179892315, rgb(93, 7107, -164) 2147483647%); font-weight: normal; background: -moz-linear-gradient(to bottom right, goldenrod 3341822649802304067%, fuchsia); font: Arial, sans-serif; ' width=" 8450"></pre><canvas><a style="transform: matrix3d(-888149292977951372, -4294967295, 27, 46038.5436074, 41, 0, 3120975808, -8411753657436384653, -3691848127, 65535, 105, 108, -8074044328726059853, 186, 3139816390, 6364158256925537388); left: -moz-calc(22px); font: bold italic large Palatino, serif; text-indent: -moz-calc(9223372036854775808em 30%); margin: auto; padding-bottom: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; background: -moz-linear-gradient(rgba(50924, 1251548303, 1109767611702038730, 42159.1644524), rgba(55, 2591341078, 10, 143) 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999%, rgba(43, 246, 149, 1.28599451055x+18) 58741%, rgba(-69, 8229554636392401175, 33463, 67.9323179507)); border-top: -67.3406928376em solid; content: counter(item); border-bottom-width: medium; " target=_blank></a>
|
||||
<link href=/tests/SimpleTest/test.css<b></b><frame>MS|;yTvb=DyYx=lZ5?NTu=.N@mwsqT!v:=zew_XR7O8YY1o%1=$Oqh=2%a|{M?e/q6]/0VH?s,l4wf!00M7BMNP+j*T?E:POnu? yKL8[Y_nlz+u%QSJB9<csaction>><bdi>w!7RF+P3o}#/~=5hL{2dypxHnV4|@}.jSm@IQ-Ia*i[^/cip/.PKGEX|`bu6+/2RG6}m_*iFTeK~5iI/Zvl.*~32e(_$L#f|1UEh~[Oc_Ej;5Ff:#-?/*W=SLD,kda-7.UmY 4jAoO:T)<footer background-size: calc(-191px 1%) calc(5575271854802146964px 0%); font: 56mm tahoma, arial, helvetica, sans-serif; border-bottom: 31711px solid ButtonShadow; volume: loud; -moz-outline-radius: 158px; font-style: oblique; font: 916265548 serif; transform: rotatex(171deg) rotatey(1174410630deg); margin-bottom: 65535in; background-image: -moz-linear-gradient(top, darkviolet, peru); -moz-window-shadow: none; "></footer></csaction><sup dir=rtl>nH,X4]U~3`GnLEY40Qs-#$K]HiX/TekdWA; Q.IGJJwTi%sB^TF^_MFf%3q; wo#]Jy[t8hywiU`ev+8no:+1!Vo?A1tbO{A$iee~-@3Xmt?jzISs1u]B!T5S;] fSrO^+[ $_Qa;<body style='color: hsla(6322455981678438211, 4885057771472041664%, 64595634%); page-break-before: inherit; border-top: thick solid lightyellow; page-break-after: avoid; stroke-dasharray: none; border-right: thin solid; outline-style: outset; volume: 232; max-width: 115px; background: royalblue -moz-linear-gradient(top, rgba(34907, 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, 4705143634018575181, 134.650893313) 196%, rgba(98, 0, 21, 93) 5835518181644000612%); border-bottom-style: double; background-color: -moz-mac-secondaryhighlight; border-bottom-style: solid; content: "Before"; azimuth: center; '>
|
||||
</ul> style='text-align-last: left; -webkit-appearance: textfield; color: rgb(-905311699%, 114, 57742); padding: 21.8234098837em 9.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999em 9.51366390673em 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999em; border-color: rgba(202, 9223372036854775808, -127, 4.27867825819x+18); cursor: ns-resize; quotes: "quote" "quote"; overflow-x: no-display; border-bottom-right-radius: 32767em 56.2654742136em; box-shadow: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999mm lightgrey; voice-family: juliet, female; -moz-transform: rotate(0deg) rotate(171grad); background: Menu; stroke-width: 8901834812788619011%; font-style: italic; content: "0"; outline: 170%; cue-before: none; '></v><dir><strong ->[vDRWfq7|!j5~J^5eQL.?J5VYFl{Vgied3%-fH^bH6?O 4mTi#]%o1xFl.O5hoZ3B;ZRx;1$T2,mgbh5dOeQ*m01547dC1/0V#Y.~WW$ragJ0n!EvBkg8Uegi+]ou1j/^QO*femQC2O!P!j,M5Vk@.-`g`$$+f+^ VP~G{1U</mi><noscript></noscript><rdf>Z[kyp(Mt0@4F~xj@v b=,K#nikG!cNac%qU(O/iUs62cwzV#,6jC[!1y5,PBNr@,Gh~Yn43l1B}p1KEh$m|bn}saNpLjZaspCwM4}XA?CWl)%V]lmIORhh y}o(CHz*vog3iSJ#On-w65NZ=}?5lh/x;xgps-#FD6l,MuASFyd$r.}x6;:v0iM4-S`El`hX%x</rdf><sub></sub><textarea>Fi~{@7J{EVzWdri*Uy+C2nP=gmz.Y;Wvp*:F]]VIVMqdJM=oU,.`Veo:L_x~1u`*f2(!*SGS*!Tsm+VYIeWA^CD10rrxyeMbNhM:SL-}Zf*A4Lf= 81Ka{/gieIN3Ru?#*Sl@~tYe]D.~pEm=s.=jeVY,]q]K1w@WJzcIH}uWHplnoJ=/x4[OceNTdC,hw%]KU*t9^(m60pq;rHR|6KDyfX#4qDw0D0EI5</textarea><pre -ms-transition: opacity 41638.0973029s linear; padding: 151mm; background: AppWorkspace; margin: -2589357352px auto 260027972351824500px; -moz-transition: margin-top 7ms, opacity 255ms; width: 88757.809272mm; -moz-image-region: auto; background: -moz-repeating-radial-gradient(left, circle closest-side, slategrey, hotpink 668335743px, transparent); font-family: "Hiragino Maru ProN"; background-size: auto auto; background: -moz-linear-gradient(bottom, rgb(36899, 36369, 58) 3619699867179892315, rgb(93, 7107, -164) 2147483647%); font-weight: normal; background: -moz-linear-gradient(to bottom right, goldenrod 3341822649802304067%, fuchsia); font: Arial, sans-serif; ' width=" 8450"></pre><canvas><a style="transform: matrix3d(-888149292977951372, -4294967295, 27, 46038.5436074, 41, 0, 3120975808, -8411753657436384653, -3691848127, 65535, 105, 108, -8074044328726059853, 186, 3139816390, 6364158256925537388); left: calc(22px); font: bold italic large Palatino, serif; text-indent: calc(9223372036854775808em 30%); margin: auto; padding-bottom: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; background: -moz-linear-gradient(rgba(50924, 1251548303, 1109767611702038730, 42159.1644524), rgba(55, 2591341078, 10, 143) 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999%, rgba(43, 246, 149, 1.28599451055x+18) 58741%, rgba(-69, 8229554636392401175, 33463, 67.9323179507)); border-top: -67.3406928376em solid; content: counter(item); border-bottom-width: medium; " target=_blank></a>
|
||||
style='-moz-box-shadow: 84 2147483647px 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px rgba(-2858581034, 110, 2460321770, 164.188187767), inset 18 255px -2461791714 rgba(65, 2147483647, 118, 120365.670275); border-color: khaki rgb(9223372036854775808, 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999) cornsilk rgb(2147483647, 3410481331, -255); background: -moz-linear-gradient(top, hsl(-6511, 132%, 67%), hsl(65535, 127%, 130%)); border-inline-end-width: 5361121852315046626; content: "»"; box-shadow: inset -148 6598830410571865803 -255px hsla(65535, -61299%, 6601653806716150645%, 144.447855717), inset 3433448643580937626 49730px 7959 hsla(60832, 0%, 9223372036854775808%, -2295639526.68); transform: translate3d(9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px, 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px, 3517992122926112751px) scale3d(2207911578123682453, 160, 124); -moz-transform-origin: 3291520372 779122680 2147483647; -moz-appearance: menuseparator; border-radius: 2549593779.31px 2.00538639825x+18px 65px 28px; transform: translate(127px, 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px) translate(9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px, -176px); margin-left: 210.617676718em; border-inline-start: dotted lightgreen 37018px; word-spacing: 2174513215933018269ch; border-left: solid; columns: 64383 auto -3982463664em; -moz-transform: scale(9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999); stroke-width: 3.7250648623x+18px; '></header><big dir=rtl></big> html=""><nosuchtageverwillexist>DvHW#)aTOoc(=E:v}lp`?)_zpj%f#fy$q~~w1,;%.rsdVNR9=AW8h#y**wpXSlY}R/L|vnxW7?EC`lK,4GcMz[9}{V#d+@d (`JUMD2gD:N1ci7Q#i_hR-p.,dM|s/D-bzFn@8g[.qr;+Kh!]tI3B?2xM;E,oW`GHsjqV>b(vf_HY9If%6.t7z2@ql6|L@SrsUoaG^AX{46e5^;p;8Pphf5f3_],qD)X!kizvdkcp8YtJZe!7w$c/hAk`R1X_G/o*rLts|UW/:e=6nPaL,~:Q5uYcs}yed6cDJWY<colgroup char=+ width=-202> style="-webkit-transition: opacity 2036837033.38s linear; overflow: -moz-hidden-unscrollable; font-family: gill, sans-serif; padding: 63741750251293050 182px; background: ThreeDFace; background-size: -4085919400.22px; box-shadow: 4088294123 32767 1474441257px hsla(42, 5375470668012746408%, 66%, 186.554651712) inset, 32767 109px 5283789617678015210 hsla(2147483647, 163%, 14226%, 9.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999); border-width: 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999px -170px 3284222322px 5.14851574865x+17px; box-shadow: inset 113 -0 -4px hsla(9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, 35273%, 2245175778%, 47085.004822), inset 9223372036854775808 76px 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 hsla(2375057167019052381, 4294967295%, 127%, 5.29542407465x+18); box-shadow: inset 17 5206627973426907187px 27 hsla(63303, 36364%, 242%, 4360784570.91), inset 18428 0px 138 hsla(-357953447, 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999%, 8058132474996186951%, 100.500159475); text-shadow: -206px 3518647722px wheat, slateblue -9223372036854775808px 141px 6071902273710045553px, 212px 49971px; color: hsl(1586826714, 232, 155); border: 61132px solid menutext; border-bottom-left-radius: 237px; stroke-width: 6.74219888253x+18; -o-flow-into: flowB; "><legend>>>>>>></wbr>>> id=content lang=ja style="display: none">
|
||||
|
||||
</div>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user