mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-i to m-c, a=merge
This commit is contained in:
commit
8357a01ca0
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1109248 - This needed a CLOBBER on Windows and OSX.
|
||||
Bug 870366 - Blacklisting PREF_JS_EXPORTS in Makefile.ins (because of 852814)
|
||||
|
@ -15,6 +15,9 @@ namespace a11y {
|
||||
bool
|
||||
DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
|
||||
{
|
||||
if (mShutdown)
|
||||
return true;
|
||||
|
||||
if (aData.NewTree().IsEmpty()) {
|
||||
NS_ERROR("no children being added");
|
||||
return false;
|
||||
@ -95,6 +98,9 @@ DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
|
||||
bool
|
||||
DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID)
|
||||
{
|
||||
if (mShutdown)
|
||||
return true;
|
||||
|
||||
ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
|
||||
if (!rootEntry) {
|
||||
NS_ERROR("invalid root being removed!");
|
||||
@ -151,17 +157,21 @@ PLDHashOperator
|
||||
DocAccessibleParent::ShutdownAccessibles(ProxyEntry* entry, void*)
|
||||
{
|
||||
ProxyDestroyed(entry->mProxy);
|
||||
return PL_DHASH_NEXT;
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleParent::Destroy()
|
||||
{
|
||||
MOZ_ASSERT(mChildDocs.IsEmpty(),
|
||||
"why weren't the child docs destroyed already?");
|
||||
NS_ASSERTION(mChildDocs.IsEmpty(),
|
||||
"why weren't the child docs destroyed already?");
|
||||
MOZ_ASSERT(!mShutdown);
|
||||
mShutdown = true;
|
||||
|
||||
uint32_t childDocCount = mChildDocs.Length();
|
||||
for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
|
||||
mChildDocs[i]->Destroy();
|
||||
|
||||
mAccessibles.EnumerateEntries(ShutdownAccessibles, nullptr);
|
||||
ProxyDestroyed(this);
|
||||
mParentDoc ? mParentDoc->RemoveChildDoc(this)
|
||||
|
@ -15,7 +15,7 @@ namespace a11y {
|
||||
void
|
||||
ProxyAccessible::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(!mOuterDoc);
|
||||
NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");
|
||||
|
||||
// XXX Ideally this wouldn't be necessary, but it seems OuterDoc accessibles
|
||||
// can be destroyed before the doc they own.
|
||||
|
@ -5,8 +5,6 @@
|
||||
USE_RCS_MK := 1
|
||||
include $(topsrcdir)/config/makefiles/rcs.mk
|
||||
|
||||
PREF_JS_EXPORTS = $(srcdir)/b2g.js
|
||||
|
||||
UA_UPDATE_FILE = ua-update.json
|
||||
|
||||
$(UA_UPDATE_FILE): % : %.in
|
||||
|
@ -76,3 +76,8 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
JS_PREFERENCE_FILES += [
|
||||
'b2g.js',
|
||||
]
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
PREF_JS_EXPORTS += $(topsrcdir)/b2g/app/b2g.js
|
@ -4,3 +4,8 @@
|
||||
|
||||
DIST_SUBDIR = 'browser'
|
||||
export('DIST_SUBDIR')
|
||||
|
||||
JS_PREFERENCE_FILES += [
|
||||
'/b2g/app/b2g.js',
|
||||
]
|
||||
|
||||
|
@ -25,7 +25,10 @@ RETRIEVE_WINDOWS_INSTALLER = 1
|
||||
|
||||
MOZ_LANGPACK_EID=langpack-$(AB_CD)@b2g.mozilla.org
|
||||
|
||||
PREF_JS_EXPORTS = $(call MERGE_FILE,b2g-l10n.js)
|
||||
L10N_PREF_JS_EXPORTS = $(call MERGE_FILE,b2g-l10n.js)
|
||||
L10N_PREF_JS_EXPORTS_PATH = $(FINAL_TARGET)/$(PREF_DIR)
|
||||
L10N_PREF_JS_EXPORTS_FLAGS = $(PREF_PPFLAGS) --silence-missing-directive-warnings
|
||||
PP_TARGETS += L10N_PREF_JS_EXPORTS
|
||||
|
||||
ifneq (,$(filter cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
||||
MOZ_PKG_MAC_DSSTORE=$(_ABS_DIST)/branding/dsstore
|
||||
|
@ -4,9 +4,6 @@
|
||||
|
||||
dist_dest = $(DIST)/$(MOZ_MACBUNDLE_NAME)
|
||||
|
||||
PREF_JS_EXPORTS = $(srcdir)/profile/firefox.js \
|
||||
$(NULL)
|
||||
|
||||
# hardcode en-US for the moment
|
||||
AB_CD = en-US
|
||||
|
||||
@ -18,10 +15,6 @@ DEFINES += \
|
||||
-DPBMODE_ICO='"$(DIST)/branding/pbmode.ico"' \
|
||||
$(NULL)
|
||||
|
||||
ifdef LIBXUL_SDK #{
|
||||
PREF_JS_EXPORTS += $(srcdir)/profile/channel-prefs.js
|
||||
endif #} LIBXUL_SDK
|
||||
|
||||
# Build a binary bootstrapping with XRE_main
|
||||
|
||||
ifndef MOZ_WINCONSOLE
|
||||
|
@ -11,6 +11,15 @@ if CONFIG['OS_ARCH'] == 'WINNT' and (CONFIG['MOZ_METRO'] or CONFIG['MOZ_ASAN']):
|
||||
else:
|
||||
GeckoProgram(CONFIG['MOZ_APP_NAME'], msvcrt='static')
|
||||
|
||||
JS_PREFERENCE_FILES += [
|
||||
'profile/firefox.js',
|
||||
]
|
||||
|
||||
if CONFIG['LIBXUL_SDK']:
|
||||
PREF_JS_EXPORTS += [
|
||||
'profile/channel-prefs.js',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'nsBrowserApp.cpp',
|
||||
]
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
PREF_JS_EXPORTS = $(srcdir)/pref/firefox-branding.js
|
||||
|
||||
# On Windows only do this step for browser, skip for metro.
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows browser)
|
||||
BRANDING_FILES := \
|
||||
|
@ -8,3 +8,8 @@ DIRS += ['content', 'locales']
|
||||
|
||||
DIST_SUBDIR = 'browser'
|
||||
export('DIST_SUBDIR')
|
||||
|
||||
JS_PREFERENCE_FILES += [
|
||||
'pref/firefox-branding.js',
|
||||
]
|
||||
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
PREF_JS_EXPORTS = $(srcdir)/pref/firefox-branding.js
|
||||
|
||||
# On Windows only do this step for browser, skip for metro.
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows browser)
|
||||
BRANDING_FILES := \
|
||||
|
@ -8,3 +8,8 @@ DIRS += ['content', 'locales']
|
||||
|
||||
DIST_SUBDIR = 'browser'
|
||||
export('DIST_SUBDIR')
|
||||
|
||||
JS_PREFERENCE_FILES += [
|
||||
'pref/firefox-branding.js',
|
||||
]
|
||||
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
PREF_JS_EXPORTS = $(srcdir)/pref/firefox-branding.js
|
||||
|
||||
# On Windows only do this step for browser, skip for metro.
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows browser)
|
||||
BRANDING_FILES := \
|
||||
|
@ -8,3 +8,8 @@ DIRS += ['content', 'locales']
|
||||
|
||||
DIST_SUBDIR = 'browser'
|
||||
export('DIST_SUBDIR')
|
||||
|
||||
JS_PREFERENCE_FILES += [
|
||||
'pref/firefox-branding.js',
|
||||
]
|
||||
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
PREF_JS_EXPORTS = $(srcdir)/pref/firefox-branding.js
|
||||
|
||||
# On Windows only do this step for browser, skip for metro.
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows browser)
|
||||
BRANDING_FILES := \
|
||||
|
@ -8,3 +8,8 @@ DIRS += ['content', 'locales']
|
||||
|
||||
DIST_SUBDIR = 'browser'
|
||||
export('DIST_SUBDIR')
|
||||
|
||||
JS_PREFERENCE_FILES += [
|
||||
'pref/firefox-branding.js',
|
||||
]
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
PREF_JS_EXPORTS = $(srcdir)/webide-prefs.js
|
@ -23,3 +23,8 @@ EXTRA_JS_MODULES.devtools.webide += [
|
||||
'modules/tab-store.js',
|
||||
'modules/utils.js'
|
||||
]
|
||||
|
||||
JS_PREFERENCE_FILES += [
|
||||
'webide-prefs.js',
|
||||
]
|
||||
|
||||
|
@ -44,7 +44,10 @@ RETRIEVE_WINDOWS_INSTALLER = 1
|
||||
|
||||
MOZ_LANGPACK_EID=langpack-$(AB_CD)@firefox.mozilla.org
|
||||
|
||||
PREF_JS_EXPORTS = $(call MERGE_FILE,firefox-l10n.js)
|
||||
L10N_PREF_JS_EXPORTS = $(call MERGE_FILE,firefox-l10n.js)
|
||||
L10N_PREF_JS_EXPORTS_PATH = $(FINAL_TARGET)/$(PREF_DIR)
|
||||
L10N_PREF_JS_EXPORTS_FLAGS = $(PREF_PPFLAGS) --silence-missing-directive-warnings
|
||||
PP_TARGETS += L10N_PREF_JS_EXPORTS
|
||||
|
||||
ifneq (,$(filter cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
||||
MOZ_PKG_MAC_DSSTORE=$(_ABS_DIST)/branding/dsstore
|
||||
|
@ -11,8 +11,11 @@ include $(topsrcdir)/config/config.mk
|
||||
# l10s prefs file
|
||||
|
||||
# copying firefox-l10n.js over from LOCALE_SRCDIR or browser
|
||||
PREF_JS_EXPORTS = $(firstword $(wildcard $(LOCALE_SRCDIR)/firefox-l10n.js) \
|
||||
$(topsrcdir)/$(relativesrcdir)/en-US/firefox-l10n.js )
|
||||
L10N_PREF_JS_EXPORTS = $(firstword $(wildcard $(LOCALE_SRCDIR)/firefox-l10n.js) \
|
||||
$(srcdir)/en-US/firefox-l10n.js )
|
||||
L10N_PREF_JS_EXPORTS_PATH = $(FINAL_TARGET)/$(PREF_DIR)
|
||||
L10N_PREF_JS_EXPORTS_FLAGS = $(PREF_PPFLAGS) --silence-missing-directive-warnings
|
||||
PP_TARGETS += L10N_PREF_JS_EXPORTS
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
PREF_JS_EXPORTS = $(srcdir)/metro.js
|
@ -4,3 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
JS_PREFERENCE_FILES += [
|
||||
'metro.js',
|
||||
]
|
||||
|
||||
|
@ -116,7 +116,6 @@ nsNullPrincipal::Init(uint32_t aAppId, bool aInMozBrowser)
|
||||
}
|
||||
|
||||
mURI = new nsNullPrincipalURI(str);
|
||||
NS_ENSURE_TRUE(mURI, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -986,8 +986,6 @@ nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, uint32_t aAppId,
|
||||
}
|
||||
|
||||
nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
|
||||
if (!codebase)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = codebase->Init(aURI, aAppId, aInMozBrowser);
|
||||
if (NS_FAILED(rv))
|
||||
@ -1269,7 +1267,6 @@ nsresult nsScriptSecurityManager::Init()
|
||||
|
||||
// Create our system principal singleton
|
||||
nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
|
||||
NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
mSystemPrincipal = system;
|
||||
|
||||
|
@ -90,6 +90,7 @@ _MOZBUILD_EXTERNAL_VARIABLES := \
|
||||
NO_DIST_INSTALL \
|
||||
OS_LIBS \
|
||||
PARALLEL_DIRS \
|
||||
PREF_JS_EXPORTS \
|
||||
PROGRAM \
|
||||
PYTHON_UNIT_TESTS \
|
||||
RESOURCE_FILES \
|
||||
|
@ -626,7 +626,7 @@ File::Constructor(const GlobalObject& aGlobal,
|
||||
const ChromeFilePropertyBag& aBag,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
@ -648,6 +648,7 @@ File::Constructor(const GlobalObject& aGlobal,
|
||||
const ChromeFilePropertyBag& aBag,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
@ -672,7 +673,7 @@ File::Constructor(const GlobalObject& aGlobal,
|
||||
const ChromeFilePropertyBag& aBag,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -112,6 +112,13 @@ GetObjectLog()
|
||||
#define LOG(args) PR_LOG(GetObjectLog(), PR_LOG_DEBUG, args)
|
||||
#define LOG_ENABLED() PR_LOG_TEST(GetObjectLog(), PR_LOG_DEBUG)
|
||||
|
||||
static bool
|
||||
IsJavaMIME(const nsACString & aMIMEType)
|
||||
{
|
||||
return
|
||||
nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Java;
|
||||
}
|
||||
|
||||
static bool
|
||||
InActiveDocument(nsIContent *aContent)
|
||||
{
|
||||
@ -992,7 +999,7 @@ nsObjectLoadingContent::BuildParametersArray()
|
||||
mCachedAttributes.AppendElement(param);
|
||||
}
|
||||
|
||||
bool isJava = nsPluginHost::IsJavaMIMEType(mContentType.get());
|
||||
bool isJava = IsJavaMIME(mContentType);
|
||||
|
||||
nsCString codebase;
|
||||
if (isJava) {
|
||||
@ -1584,8 +1591,8 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
|
||||
if (aJavaURI || thisContent->NodeInfo()->Equals(nsGkAtoms::applet)) {
|
||||
nsAdoptingCString javaMIME = Preferences::GetCString(kPrefJavaMIME);
|
||||
newMime = javaMIME;
|
||||
NS_ASSERTION(nsPluginHost::IsJavaMIMEType(newMime.get()),
|
||||
"plugin.mime.java should be recognized by IsJavaMIMEType");
|
||||
NS_ASSERTION(IsJavaMIME(newMime),
|
||||
"plugin.mime.java should be recognized as java");
|
||||
isJava = true;
|
||||
} else {
|
||||
nsAutoString rawTypeAttr;
|
||||
@ -1593,7 +1600,7 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
|
||||
if (!rawTypeAttr.IsEmpty()) {
|
||||
typeAttr = rawTypeAttr;
|
||||
CopyUTF16toUTF8(rawTypeAttr, newMime);
|
||||
isJava = nsPluginHost::IsJavaMIMEType(newMime.get());
|
||||
isJava = IsJavaMIME(newMime);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1607,8 +1614,8 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
|
||||
if (!classIDAttr.IsEmpty()) {
|
||||
// Our classid support is limited to 'java:' ids
|
||||
nsAdoptingCString javaMIME = Preferences::GetCString(kPrefJavaMIME);
|
||||
NS_ASSERTION(nsPluginHost::IsJavaMIMEType(javaMIME.get()),
|
||||
"plugin.mime.java should be recognized by IsJavaMIMEType");
|
||||
NS_ASSERTION(IsJavaMIME(javaMIME),
|
||||
"plugin.mime.java should be recognized as java");
|
||||
if (StringBeginsWith(classIDAttr, NS_LITERAL_STRING("java:")) &&
|
||||
PluginExistsForType(javaMIME)) {
|
||||
newMime = javaMIME;
|
||||
@ -1720,7 +1727,7 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
|
||||
(caps & eAllowPluginSkipChannel) &&
|
||||
IsPluginEnabledByExtension(newURI, newMime)) {
|
||||
LOG(("OBJLC [%p]: Using extension as type hint (%s)", this, newMime.get()));
|
||||
if (!isJava && nsPluginHost::IsJavaMIMEType(newMime.get())) {
|
||||
if (!isJava && IsJavaMIME(newMime)) {
|
||||
return UpdateObjectParameters(true);
|
||||
}
|
||||
}
|
||||
@ -1836,7 +1843,7 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
|
||||
}
|
||||
} else {
|
||||
newMime = channelType;
|
||||
if (nsPluginHost::IsJavaMIMEType(newMime.get())) {
|
||||
if (IsJavaMIME(newMime)) {
|
||||
// Java does not load with a channel, and being java retroactively
|
||||
// changes how we may have interpreted the codebase to construct this
|
||||
// URI above. Because the behavior here is more or less undefined, play
|
||||
@ -2107,7 +2114,7 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
|
||||
|
||||
if (mType != eType_Null) {
|
||||
bool allowLoad = true;
|
||||
if (nsPluginHost::IsJavaMIMEType(mContentType.get())) {
|
||||
if (IsJavaMIME(mContentType)) {
|
||||
allowLoad = CheckJavaCodebase();
|
||||
}
|
||||
int16_t contentPolicy = nsIContentPolicy::ACCEPT;
|
||||
@ -3017,7 +3024,8 @@ nsObjectLoadingContent::StopPluginInstance()
|
||||
if (inst) {
|
||||
const char* mime = nullptr;
|
||||
if (NS_SUCCEEDED(inst->GetMIMEType(&mime)) && mime) {
|
||||
if (strcmp(mime, "audio/x-pn-realaudio-plugin") == 0) {
|
||||
if (nsPluginHost::GetSpecialType(nsDependentCString(mime)) ==
|
||||
nsPluginHost::eSpecialType_RealPlayer) {
|
||||
delayedStop = true;
|
||||
}
|
||||
}
|
||||
|
@ -2726,6 +2726,10 @@ UnwrapArgImpl(JS::Handle<JSObject*> src,
|
||||
const nsIID &iid,
|
||||
void **ppArg)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsISupports *iface = xpc::UnwrapReflectorToISupports(src);
|
||||
if (iface) {
|
||||
if (NS_FAILED(iface->QueryInterface(iid, ppArg))) {
|
||||
|
@ -633,6 +633,10 @@ DOMInterfaces = {
|
||||
'headerFile': 'nsIMediaList.h',
|
||||
},
|
||||
|
||||
'MediaKeyStatusMap' : {
|
||||
'implicitJSContext': [ 'size', 'get', 'has' ]
|
||||
},
|
||||
|
||||
'MediaStream': {
|
||||
'headerFile': 'DOMMediaStream.h',
|
||||
'nativeType': 'mozilla::DOMMediaStream'
|
||||
|
@ -57,3 +57,4 @@ skip-if = debug == false
|
||||
skip-if = debug == false
|
||||
[test_promise_rejections_from_jsimplemented.html]
|
||||
skip-if = debug == false
|
||||
[test_worker_UnwrapArg.html]
|
||||
|
58
dom/bindings/test/test_worker_UnwrapArg.html
Normal file
58
dom/bindings/test/test_worker_UnwrapArg.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1127206
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1127206</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1127206 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var blob = new Blob([
|
||||
`try { new File({}); }
|
||||
catch (e) {
|
||||
postMessage("throwing on random object");
|
||||
}
|
||||
try { new File(new Blob(["abc"])); }
|
||||
catch (e) {
|
||||
postMessage("throwing on Blob");
|
||||
}
|
||||
try { new File("abc"); }
|
||||
catch (e) {
|
||||
postMessage("throwing on string");
|
||||
}
|
||||
postMessage('finishTest')`]);
|
||||
var url = URL.createObjectURL(blob);
|
||||
var w = new Worker(url);
|
||||
var expectedResults = [
|
||||
"throwing on random object",
|
||||
"throwing on Blob",
|
||||
"throwing on string",
|
||||
];
|
||||
var curIndex = 0;
|
||||
w.onmessage = function(e) {
|
||||
if (curIndex == expectedResults.length) {
|
||||
is(e.data, "finishTest", "What message is this?");
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
is(e.data, expectedResults[curIndex],
|
||||
"Message " + (curIndex+1) + " should be correct");
|
||||
++curIndex;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1127206">Mozilla Bug 1127206</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -314,6 +314,17 @@ ContentEventHandler::GetNativeTextLength(nsIContent* aContent,
|
||||
return GetTextLength(aContent, LINE_BREAK_TYPE_NATIVE, aMaxLength);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
GetBRLength(LineBreakType aLineBreakType)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
// Length of \r\n
|
||||
return (aLineBreakType == LINE_BREAK_TYPE_NATIVE) ? 2 : 1;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */ uint32_t
|
||||
ContentEventHandler::GetTextLength(nsIContent* aContent,
|
||||
LineBreakType aLineBreakType,
|
||||
@ -344,12 +355,7 @@ ContentEventHandler::GetTextLength(nsIContent* aContent,
|
||||
uint32_t length = std::min(text->GetLength(), aMaxLength);
|
||||
return length + textLengthDifference;
|
||||
} else if (IsContentBR(aContent)) {
|
||||
#if defined(XP_WIN)
|
||||
// Length of \r\n
|
||||
return (aLineBreakType == LINE_BREAK_TYPE_NATIVE) ? 2 : 1;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
return GetBRLength(aLineBreakType);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -393,7 +399,6 @@ static nsresult GenerateFlatTextContent(nsRange* aRange,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString tmpStr;
|
||||
for (; !iter->IsDone(); iter->Next()) {
|
||||
nsINode* node = iter->GetCurrentNode();
|
||||
if (!node) {
|
||||
@ -423,6 +428,171 @@ static nsresult GenerateFlatTextContent(nsRange* aRange,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static FontRange*
|
||||
AppendFontRange(nsTArray<FontRange>& aFontRanges, uint32_t aBaseOffset)
|
||||
{
|
||||
FontRange* fontRange = aFontRanges.AppendElement();
|
||||
fontRange->mStartOffset = aBaseOffset;
|
||||
return fontRange;
|
||||
}
|
||||
|
||||
/* static */ uint32_t
|
||||
ContentEventHandler::GetTextLengthInRange(nsIContent* aContent,
|
||||
uint32_t aXPStartOffset,
|
||||
uint32_t aXPEndOffset,
|
||||
LineBreakType aLineBreakType)
|
||||
{
|
||||
return aLineBreakType == LINE_BREAK_TYPE_NATIVE ?
|
||||
GetNativeTextLength(aContent, aXPStartOffset, aXPEndOffset) :
|
||||
aXPEndOffset - aXPStartOffset;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ContentEventHandler::AppendFontRanges(FontRangeArray& aFontRanges,
|
||||
nsIContent* aContent,
|
||||
int32_t aBaseOffset,
|
||||
int32_t aXPStartOffset,
|
||||
int32_t aXPEndOffset,
|
||||
LineBreakType aLineBreakType)
|
||||
{
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
if (!frame) {
|
||||
// It is a non-rendered content, create an empty range for it.
|
||||
AppendFontRange(aFontRanges, aBaseOffset);
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t baseOffset = aBaseOffset;
|
||||
nsTextFrame* curr = do_QueryFrame(frame);
|
||||
MOZ_ASSERT(curr, "Not a text frame");
|
||||
while (curr) {
|
||||
int32_t frameXPStart = std::max(curr->GetContentOffset(), aXPStartOffset);
|
||||
int32_t frameXPEnd = std::min(curr->GetContentEnd(), aXPEndOffset);
|
||||
if (frameXPStart >= frameXPEnd) {
|
||||
curr = static_cast<nsTextFrame*>(curr->GetNextContinuation());
|
||||
continue;
|
||||
}
|
||||
|
||||
gfxSkipCharsIterator iter = curr->EnsureTextRun(nsTextFrame::eInflated);
|
||||
gfxTextRun* textRun = curr->GetTextRun(nsTextFrame::eInflated);
|
||||
|
||||
nsTextFrame* next = nullptr;
|
||||
if (frameXPEnd < aXPEndOffset) {
|
||||
next = static_cast<nsTextFrame*>(curr->GetNextContinuation());
|
||||
while (next && next->GetTextRun(nsTextFrame::eInflated) == textRun) {
|
||||
frameXPEnd = std::min(next->GetContentEnd(), aXPEndOffset);
|
||||
next = frameXPEnd < aXPEndOffset ?
|
||||
static_cast<nsTextFrame*>(next->GetNextContinuation()) : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t skipStart = iter.ConvertOriginalToSkipped(frameXPStart);
|
||||
uint32_t skipEnd = iter.ConvertOriginalToSkipped(frameXPEnd);
|
||||
gfxTextRun::GlyphRunIterator runIter(
|
||||
textRun, skipStart, skipEnd - skipStart);
|
||||
int32_t lastXPEndOffset = frameXPStart;
|
||||
while (runIter.NextRun()) {
|
||||
gfxFont* font = runIter.GetGlyphRun()->mFont.get();
|
||||
int32_t startXPOffset =
|
||||
iter.ConvertSkippedToOriginal(runIter.GetStringStart());
|
||||
// It is possible that the first glyph run has exceeded the frame,
|
||||
// because the whole frame is filled by skipped chars.
|
||||
if (startXPOffset >= frameXPEnd) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (startXPOffset > lastXPEndOffset) {
|
||||
// Create range for skipped leading chars.
|
||||
AppendFontRange(aFontRanges, baseOffset);
|
||||
baseOffset += GetTextLengthInRange(
|
||||
aContent, lastXPEndOffset, startXPOffset, aLineBreakType);
|
||||
lastXPEndOffset = startXPOffset;
|
||||
}
|
||||
|
||||
FontRange* fontRange = AppendFontRange(aFontRanges, baseOffset);
|
||||
fontRange->mFontName = font->GetName();
|
||||
fontRange->mFontSize = font->GetAdjustedSize();
|
||||
|
||||
// The converted original offset may exceed the range,
|
||||
// hence we need to clamp it.
|
||||
int32_t endXPOffset =
|
||||
iter.ConvertSkippedToOriginal(runIter.GetStringEnd());
|
||||
endXPOffset = std::min(frameXPEnd, endXPOffset);
|
||||
baseOffset += GetTextLengthInRange(aContent, startXPOffset, endXPOffset,
|
||||
aLineBreakType);
|
||||
lastXPEndOffset = endXPOffset;
|
||||
}
|
||||
if (lastXPEndOffset < frameXPEnd) {
|
||||
// Create range for skipped trailing chars. It also handles case
|
||||
// that the whole frame contains only skipped chars.
|
||||
AppendFontRange(aFontRanges, baseOffset);
|
||||
baseOffset += GetTextLengthInRange(
|
||||
aContent, lastXPEndOffset, frameXPEnd, aLineBreakType);
|
||||
}
|
||||
|
||||
curr = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
ContentEventHandler::GenerateFlatFontRanges(nsRange* aRange,
|
||||
FontRangeArray& aFontRanges,
|
||||
uint32_t& aLength,
|
||||
LineBreakType aLineBreakType)
|
||||
{
|
||||
MOZ_ASSERT(aFontRanges.IsEmpty(), "aRanges must be empty array");
|
||||
|
||||
nsINode* startNode = aRange->GetStartParent();
|
||||
nsINode* endNode = aRange->GetEndParent();
|
||||
if (NS_WARN_IF(!startNode || !endNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// baseOffset is the flattened offset of each content node.
|
||||
int32_t baseOffset = 0;
|
||||
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
|
||||
for (iter->Init(aRange); !iter->IsDone(); iter->Next()) {
|
||||
nsINode* node = iter->GetCurrentNode();
|
||||
if (NS_WARN_IF(!node)) {
|
||||
break;
|
||||
}
|
||||
if (!node->IsContent()) {
|
||||
continue;
|
||||
}
|
||||
nsIContent* content = node->AsContent();
|
||||
|
||||
if (content->IsNodeOfType(nsINode::eTEXT)) {
|
||||
int32_t startOffset = content != startNode ? 0 : aRange->StartOffset();
|
||||
int32_t endOffset = content != endNode ?
|
||||
content->TextLength() : aRange->EndOffset();
|
||||
AppendFontRanges(aFontRanges, content, baseOffset,
|
||||
startOffset, endOffset, aLineBreakType);
|
||||
baseOffset += GetTextLengthInRange(content, startOffset, endOffset,
|
||||
aLineBreakType);
|
||||
} else if (IsContentBR(content)) {
|
||||
if (aFontRanges.IsEmpty()) {
|
||||
MOZ_ASSERT(baseOffset == 0);
|
||||
FontRange* fontRange = AppendFontRange(aFontRanges, baseOffset);
|
||||
nsIFrame* frame = content->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
const nsFont& font = frame->GetParent()->StyleFont()->mFont;
|
||||
const FontFamilyList& fontList = font.fontlist;
|
||||
const FontFamilyName& fontName = fontList.IsEmpty() ?
|
||||
FontFamilyName(fontList.GetDefaultFontType()) :
|
||||
fontList.GetFontlist()[0];
|
||||
fontName.AppendToString(fontRange->mFontName, false);
|
||||
fontRange->mFontSize =
|
||||
frame->PresContext()->AppUnitsToDevPixels(font.size);
|
||||
}
|
||||
}
|
||||
baseOffset += GetBRLength(aLineBreakType);
|
||||
}
|
||||
}
|
||||
|
||||
aLength = baseOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent,
|
||||
bool aForward,
|
||||
@ -697,6 +867,18 @@ ContentEventHandler::OnQueryTextContent(WidgetQueryContentEvent* aEvent)
|
||||
rv = GenerateFlatTextContent(range, aEvent->mReply.mString, lineBreakType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aEvent->mWithFontRanges) {
|
||||
uint32_t fontRangeLength;
|
||||
rv = GenerateFlatFontRanges(range, aEvent->mReply.mFontRanges,
|
||||
fontRangeLength, lineBreakType);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(fontRangeLength == aEvent->mReply.mString.Length(),
|
||||
"Font ranges doesn't match the string");
|
||||
}
|
||||
|
||||
aEvent->mSucceeded = true;
|
||||
|
||||
return NS_OK;
|
||||
|
@ -94,6 +94,12 @@ public:
|
||||
// Get the native text length of a content node excluding any children
|
||||
static uint32_t GetNativeTextLength(nsIContent* aContent,
|
||||
uint32_t aMaxLength = UINT32_MAX);
|
||||
// Get the text length of a given range of a content node in
|
||||
// the given line break type.
|
||||
static uint32_t GetTextLengthInRange(nsIContent* aContent,
|
||||
uint32_t aXPStartOffset,
|
||||
uint32_t aXPEndOffset,
|
||||
LineBreakType aLineBreakType);
|
||||
protected:
|
||||
static uint32_t GetTextLength(nsIContent* aContent,
|
||||
LineBreakType aLineBreakType,
|
||||
@ -129,6 +135,18 @@ protected:
|
||||
// true, it is expanded to forward.
|
||||
nsresult ExpandToClusterBoundary(nsIContent* aContent, bool aForward,
|
||||
uint32_t* aXPOffset);
|
||||
|
||||
typedef nsTArray<mozilla::FontRange> FontRangeArray;
|
||||
static void AppendFontRanges(FontRangeArray& aFontRanges,
|
||||
nsIContent* aContent,
|
||||
int32_t aBaseOffset,
|
||||
int32_t aXPStartOffset,
|
||||
int32_t aXPEndOffset,
|
||||
LineBreakType aLineBreakType);
|
||||
static nsresult GenerateFlatFontRanges(nsRange* aRange,
|
||||
FontRangeArray& aFontRanges,
|
||||
uint32_t& aLength,
|
||||
LineBreakType aLineBreakType);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -1889,7 +1889,6 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
|
||||
// back into the output stream.
|
||||
out->mStream->GetStream()->ChangeExplicitBlockerCount(1);
|
||||
if (mDecoder) {
|
||||
mDecoder->SetAudioCaptured(true);
|
||||
mDecoder->AddOutputStream(
|
||||
out->mStream->GetStream()->AsProcessedStream(), aFinishWhenEnded);
|
||||
}
|
||||
@ -2705,7 +2704,6 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
// available immediately.
|
||||
mDecoder->SetResource(aStream);
|
||||
mDecoder->SetAudioChannel(mAudioChannel);
|
||||
mDecoder->SetAudioCaptured(mAudioCaptured);
|
||||
mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
|
||||
mDecoder->SetPreservesPitch(mPreservesPitch);
|
||||
mDecoder->SetPlaybackRate(mPlaybackRate);
|
||||
|
@ -98,7 +98,7 @@ TimeRanges::GetEndTime()
|
||||
}
|
||||
|
||||
void
|
||||
TimeRanges::Normalize(double aError)
|
||||
TimeRanges::Normalize(double aTolerance)
|
||||
{
|
||||
if (mRanges.Length() >= 2) {
|
||||
nsAutoTArray<TimeRange,4> normalized;
|
||||
@ -112,7 +112,7 @@ TimeRanges::Normalize(double aError)
|
||||
current.mEnd >= mRanges[i].mEnd) {
|
||||
continue;
|
||||
}
|
||||
if (current.mEnd + aError >= mRanges[i].mStart) {
|
||||
if (current.mEnd + aTolerance >= mRanges[i].mStart) {
|
||||
current.mEnd = mRanges[i].mEnd;
|
||||
} else {
|
||||
normalized.AppendElement(current);
|
||||
@ -127,10 +127,10 @@ TimeRanges::Normalize(double aError)
|
||||
}
|
||||
|
||||
void
|
||||
TimeRanges::Union(const TimeRanges* aOtherRanges, double aError)
|
||||
TimeRanges::Union(const TimeRanges* aOtherRanges, double aTolerance)
|
||||
{
|
||||
mRanges.AppendElements(aOtherRanges->mRanges);
|
||||
Normalize(aError);
|
||||
Normalize(aTolerance);
|
||||
}
|
||||
|
||||
void
|
||||
@ -156,10 +156,10 @@ TimeRanges::Intersection(const TimeRanges* aOtherRanges)
|
||||
}
|
||||
|
||||
TimeRanges::index_type
|
||||
TimeRanges::Find(double aTime, double aError /* = 0 */)
|
||||
TimeRanges::Find(double aTime, double aTolerance /* = 0 */)
|
||||
{
|
||||
for (index_type i = 0; i < mRanges.Length(); ++i) {
|
||||
if (aTime < mRanges[i].mEnd && (aTime + aError) >= mRanges[i].mStart) {
|
||||
if (aTime < mRanges[i].mEnd && (aTime + aTolerance) >= mRanges[i].mStart) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -42,10 +42,10 @@ public:
|
||||
double GetEndTime();
|
||||
|
||||
// See http://www.whatwg.org/html/#normalized-timeranges-object
|
||||
void Normalize(double aError = 0.0);
|
||||
void Normalize(double aTolerance = 0.0);
|
||||
|
||||
// Mutate this TimeRange to be the union of this and aOtherRanges.
|
||||
void Union(const TimeRanges* aOtherRanges, double aError);
|
||||
void Union(const TimeRanges* aOtherRanges, double aTolerance);
|
||||
|
||||
// Mutate this TimeRange to be the intersection of this and aOtherRanges.
|
||||
void Intersection(const TimeRanges* aOtherRanges);
|
||||
@ -91,7 +91,7 @@ public:
|
||||
typedef nsTArray<TimeRange>::index_type index_type;
|
||||
static const index_type NoIndex = index_type(-1);
|
||||
|
||||
index_type Find(double aTime, double aError = 0);
|
||||
index_type Find(double aTime, double aTolerance = 0);
|
||||
|
||||
bool Contains(double aStart, double aEnd) {
|
||||
index_type target = Find(aStart);
|
||||
|
@ -2496,7 +2496,10 @@ ContentChild::RecvGetProfile(nsCString* aProfile)
|
||||
bool
|
||||
ContentChild::RecvLoadPluginResult(const uint32_t& aPluginId, const bool& aResult)
|
||||
{
|
||||
bool finalResult = aResult && SendConnectPluginBridge(aPluginId);
|
||||
nsresult rv;
|
||||
bool finalResult = aResult &&
|
||||
SendConnectPluginBridge(aPluginId, &rv) &&
|
||||
NS_SUCCEEDED(rv);
|
||||
plugins::PluginModuleContentParent::OnLoadPluginResult(aPluginId,
|
||||
finalResult);
|
||||
return true;
|
||||
|
@ -979,15 +979,17 @@ static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement)
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvLoadPlugin(const uint32_t& aPluginId)
|
||||
ContentParent::RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv)
|
||||
{
|
||||
return mozilla::plugins::SetupBridge(aPluginId, this);
|
||||
*aRv = NS_OK;
|
||||
return mozilla::plugins::SetupBridge(aPluginId, this, false, aRv);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvConnectPluginBridge(const uint32_t& aPluginId)
|
||||
ContentParent::RecvConnectPluginBridge(const uint32_t& aPluginId, nsresult* aRv)
|
||||
{
|
||||
return mozilla::plugins::SetupBridge(aPluginId, this, true);
|
||||
*aRv = NS_OK;
|
||||
return mozilla::plugins::SetupBridge(aPluginId, this, true, aRv);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -153,8 +153,8 @@ public:
|
||||
TabId* aTabId) MOZ_OVERRIDE;
|
||||
virtual bool RecvBridgeToChildProcess(const ContentParentId& aCpId) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvLoadPlugin(const uint32_t& aPluginId) MOZ_OVERRIDE;
|
||||
virtual bool RecvConnectPluginBridge(const uint32_t& aPluginId) MOZ_OVERRIDE;
|
||||
virtual bool RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv) MOZ_OVERRIDE;
|
||||
virtual bool RecvConnectPluginBridge(const uint32_t& aPluginId, nsresult* aRv) MOZ_OVERRIDE;
|
||||
virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
|
||||
nsTArray<PluginTag>* aPlugins,
|
||||
uint32_t* aNewPluginEpoch) MOZ_OVERRIDE;
|
||||
|
@ -594,7 +594,7 @@ parent:
|
||||
* process. We use intr semantics here to ensure that the PluginModuleParent
|
||||
* allocation message is dispatched before LoadPlugin returns.
|
||||
*/
|
||||
sync LoadPlugin(uint32_t pluginId);
|
||||
sync LoadPlugin(uint32_t pluginId) returns (nsresult rv);
|
||||
|
||||
/**
|
||||
* This call is used by asynchronous plugin instantiation to notify the
|
||||
@ -602,7 +602,7 @@ parent:
|
||||
* the specified plugin id. When this call returns, the requested bridge
|
||||
* connection has been made.
|
||||
*/
|
||||
sync ConnectPluginBridge(uint32_t aPluginId);
|
||||
sync ConnectPluginBridge(uint32_t aPluginId) returns (nsresult rv);
|
||||
|
||||
/**
|
||||
* This call returns the set of plugins loaded in the chrome
|
||||
|
@ -2126,6 +2126,7 @@ TabParent::RecvGetDefaultScale(double* aValue)
|
||||
bool
|
||||
TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
|
||||
{
|
||||
*aValue = 0;
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
|
||||
if (content) {
|
||||
nsIPresShell* shell = content->OwnerDoc()->GetShell();
|
||||
@ -2136,11 +2137,10 @@ TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
|
||||
if (widget) {
|
||||
*aValue = reinterpret_cast<WindowsHandle>(
|
||||
widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -263,15 +263,6 @@ void MediaDecoder::SetVolume(double aVolume)
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoder::SetAudioCaptured(bool aCaptured)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mInitialAudioCaptured = aCaptured;
|
||||
if (mDecoderStateMachine) {
|
||||
mDecoderStateMachine->SetAudioCaptured(aCaptured);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoder::ConnectDecodedStreamToOutputStream(OutputStreamData* aStream)
|
||||
{
|
||||
NS_ASSERTION(!aStream->mPort, "Already connected?");
|
||||
@ -360,13 +351,6 @@ MediaDecoder::DecodedStreamGraphListener::NotifyEvent(MediaStreamGraph* aGraph,
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoder::RecreateDecodedStreamIfNecessary(int64_t aStartTimeUSecs)
|
||||
{
|
||||
if (mInitialAudioCaptured) {
|
||||
RecreateDecodedStream(aStartTimeUSecs);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoder::DestroyDecodedStream()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
@ -470,9 +454,13 @@ void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
if (!mDecodedStream) {
|
||||
RecreateDecodedStream(mDecoderStateMachine ?
|
||||
int64_t(mDecoderStateMachine->GetCurrentTime()*USECS_PER_S) : 0);
|
||||
if (mDecoderStateMachine) {
|
||||
mDecoderStateMachine->SetAudioCaptured();
|
||||
}
|
||||
if (!GetDecodedStream()) {
|
||||
int64_t t = mDecoderStateMachine ?
|
||||
mDecoderStateMachine->GetCurrentTimeUs() : 0;
|
||||
RecreateDecodedStream(t);
|
||||
}
|
||||
OutputStreamData* os = mOutputStreams.AppendElement();
|
||||
os->Init(aStream, aFinishWhenEnded);
|
||||
@ -672,7 +660,9 @@ void MediaDecoder::SetStateMachineParameters()
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mDecoderStateMachine->SetDuration(mDuration);
|
||||
mDecoderStateMachine->SetVolume(mInitialVolume);
|
||||
mDecoderStateMachine->SetAudioCaptured(mInitialAudioCaptured);
|
||||
if (GetDecodedStream()) {
|
||||
mDecoderStateMachine->SetAudioCaptured();
|
||||
}
|
||||
SetPlaybackRate(mInitialPlaybackRate);
|
||||
mDecoderStateMachine->SetPreservesPitch(mInitialPreservesPitch);
|
||||
if (mMinimizePreroll) {
|
||||
|
@ -374,9 +374,6 @@ public:
|
||||
virtual void Pause();
|
||||
// Adjust the speed of the playback, optionally with pitch correction,
|
||||
virtual void SetVolume(double aVolume);
|
||||
// Sets whether audio is being captured. If it is, we won't play any
|
||||
// of our audio.
|
||||
virtual void SetAudioCaptured(bool aCaptured);
|
||||
|
||||
virtual void NotifyWaitingForResourcesStatusChanged() MOZ_OVERRIDE;
|
||||
|
||||
@ -857,9 +854,6 @@ public:
|
||||
// The decoder monitor must be held.
|
||||
bool IsLogicallyPlaying();
|
||||
|
||||
// Re-create a decoded stream if audio being captured
|
||||
void RecreateDecodedStreamIfNecessary(int64_t aStartTimeUSecs);
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// This takes the decoder monitor.
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE;
|
||||
@ -1068,9 +1062,6 @@ protected:
|
||||
// only.
|
||||
int64_t mDuration;
|
||||
|
||||
// True when playback should start with audio captured (not playing).
|
||||
bool mInitialAudioCaptured;
|
||||
|
||||
// True if the media is seekable (i.e. supports random access).
|
||||
bool mMediaSeekable;
|
||||
|
||||
|
@ -1387,11 +1387,11 @@ void MediaDecoderStateMachine::SetVolume(double volume)
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured)
|
||||
void MediaDecoderStateMachine::SetAudioCaptured()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (!mAudioCaptured && aCaptured && !mStopAudioThread) {
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (!mAudioCaptured && !mStopAudioThread) {
|
||||
// Make sure the state machine runs as soon as possible. That will
|
||||
// stop the audio sink.
|
||||
// If mStopAudioThread is true then we're already stopping the audio sink
|
||||
@ -1405,7 +1405,7 @@ void MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured)
|
||||
ResyncAudioClock();
|
||||
}
|
||||
}
|
||||
mAudioCaptured = aCaptured;
|
||||
mAudioCaptured = true;
|
||||
}
|
||||
|
||||
double MediaDecoderStateMachine::GetCurrentTime() const
|
||||
@ -1418,6 +1418,16 @@ double MediaDecoderStateMachine::GetCurrentTime() const
|
||||
return static_cast<double>(mCurrentFrameTime) / static_cast<double>(USECS_PER_S);
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetCurrentTimeUs() const
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread() ||
|
||||
OnStateMachineThread() ||
|
||||
OnDecodeThread(),
|
||||
"Should be on main, decode, or state machine thread.");
|
||||
|
||||
return mCurrentFrameTime;
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::IsRealTime() const {
|
||||
return mScheduler->IsRealTime();
|
||||
}
|
||||
@ -1782,7 +1792,9 @@ MediaDecoderStateMachine::StartSeek(const SeekTarget& aTarget)
|
||||
|
||||
DECODER_LOG("Changed state to SEEKING (to %lld)", mSeekTarget.mTime);
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
mDecoder->RecreateDecodedStreamIfNecessary(seekTime - mStartTime);
|
||||
if (mAudioCaptured) {
|
||||
mDecoder->RecreateDecodedStream(seekTime - mStartTime);
|
||||
}
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ public:
|
||||
// Set the audio volume. The decoder monitor must be obtained before
|
||||
// calling this.
|
||||
void SetVolume(double aVolume);
|
||||
void SetAudioCaptured(bool aCapture);
|
||||
void SetAudioCaptured();
|
||||
|
||||
// Check if the decoder needs to become dormant state.
|
||||
bool IsDormantNeeded();
|
||||
@ -241,6 +241,7 @@ public:
|
||||
// Called from the main thread to get the current frame time. The decoder
|
||||
// monitor must be obtained before calling this.
|
||||
double GetCurrentTime() const;
|
||||
int64_t GetCurrentTimeUs() const;
|
||||
|
||||
// Clear the flag indicating that a playback position change event
|
||||
// is currently queued. This is called from the main thread and must
|
||||
|
@ -267,35 +267,18 @@ CDMCallbackProxy::SessionError(const nsCString& aSessionId,
|
||||
}
|
||||
|
||||
void
|
||||
CDMCallbackProxy::KeyIdUsable(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId)
|
||||
CDMCallbackProxy::KeyStatusChanged(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId,
|
||||
GMPMediaKeyStatus aStatus)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
bool keysChange = false;
|
||||
{
|
||||
CDMCaps::AutoLock caps(mProxy->Capabilites());
|
||||
keysChange = caps.SetKeyUsable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
|
||||
}
|
||||
if (keysChange) {
|
||||
nsRefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
|
||||
&CDMProxy::OnKeysChange,
|
||||
NS_ConvertUTF8toUTF16(aSessionId));
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMCallbackProxy::KeyIdNotUsable(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
bool keysChange = false;
|
||||
{
|
||||
CDMCaps::AutoLock caps(mProxy->Capabilites());
|
||||
keysChange = caps.SetKeyUnusable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
|
||||
keysChange = caps.SetKeyStatus(aKeyId,
|
||||
NS_ConvertUTF8toUTF16(aSessionId),
|
||||
aStatus);
|
||||
}
|
||||
if (keysChange) {
|
||||
nsRefPtr<nsIRunnable> task;
|
||||
|
@ -43,11 +43,9 @@ public:
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage) MOZ_OVERRIDE;
|
||||
|
||||
virtual void KeyIdUsable(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE;
|
||||
|
||||
virtual void KeyIdNotUsable(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE;
|
||||
virtual void KeyStatusChanged(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId,
|
||||
GMPMediaKeyStatus aStatus) MOZ_OVERRIDE;
|
||||
|
||||
virtual void SetCaps(uint64_t aCaps) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CDMCaps.h"
|
||||
#include "gmp-decryption.h"
|
||||
#include "EMELog.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "SamplesWaitingForKey.h"
|
||||
@ -80,9 +79,9 @@ bool
|
||||
CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
|
||||
{
|
||||
mData.mMonitor.AssertCurrentThreadOwns();
|
||||
const auto& keys = mData.mUsableKeyIds;
|
||||
const auto& keys = mData.mKeyStatuses;
|
||||
for (size_t i = 0; i < keys.Length(); i++) {
|
||||
if (keys[i].mId == aKeyId) {
|
||||
if (keys[i].mId == aKeyId && keys[i].mStatus == kGMPUsable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -90,15 +89,32 @@ CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::AutoLock::SetKeyUsable(const CencKeyId& aKeyId,
|
||||
const nsString& aSessionId)
|
||||
CDMCaps::AutoLock::SetKeyStatus(const CencKeyId& aKeyId,
|
||||
const nsString& aSessionId,
|
||||
GMPMediaKeyStatus aStatus)
|
||||
{
|
||||
mData.mMonitor.AssertCurrentThreadOwns();
|
||||
UsableKey key(aKeyId, aSessionId);
|
||||
if (mData.mUsableKeyIds.Contains(key)) {
|
||||
return false;
|
||||
KeyStatus key(aKeyId, aSessionId, aStatus);
|
||||
auto index = mData.mKeyStatuses.IndexOf(key);
|
||||
|
||||
if (aStatus == kGMPUnknown) {
|
||||
// Return true if the element is found to notify key changes.
|
||||
return mData.mKeyStatuses.RemoveElement(key);
|
||||
}
|
||||
mData.mUsableKeyIds.AppendElement(key);
|
||||
|
||||
if (index != mData.mKeyStatuses.NoIndex) {
|
||||
if (mData.mKeyStatuses[index].mStatus == aStatus) {
|
||||
return false;
|
||||
}
|
||||
mData.mKeyStatuses[index].mStatus = aStatus;
|
||||
} else {
|
||||
mData.mKeyStatuses.AppendElement(key);
|
||||
}
|
||||
|
||||
if (aStatus != kGMPUsable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto& waiters = mData.mWaitForKeys;
|
||||
size_t i = 0;
|
||||
while (i < waiters.Length()) {
|
||||
@ -113,26 +129,6 @@ CDMCaps::AutoLock::SetKeyUsable(const CencKeyId& aKeyId,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::AutoLock::SetKeyUnusable(const CencKeyId& aKeyId,
|
||||
const nsString& aSessionId)
|
||||
{
|
||||
mData.mMonitor.AssertCurrentThreadOwns();
|
||||
UsableKey key(aKeyId, aSessionId);
|
||||
if (!mData.mUsableKeyIds.Contains(key)) {
|
||||
return false;
|
||||
}
|
||||
auto& keys = mData.mUsableKeyIds;
|
||||
for (size_t i = 0; i < keys.Length(); i++) {
|
||||
if (keys[i].mId == aKeyId &&
|
||||
keys[i].mSessionId == aSessionId) {
|
||||
keys.RemoveElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CDMCaps::AutoLock::NotifyWhenKeyIdUsable(const CencKeyId& aKey,
|
||||
SamplesWaitingForKey* aListener)
|
||||
@ -175,15 +171,15 @@ CDMCaps::AutoLock::CanDecryptVideo()
|
||||
}
|
||||
|
||||
void
|
||||
CDMCaps::AutoLock::GetUsableKeysForSession(const nsAString& aSessionId,
|
||||
nsTArray<CencKeyId>& aOutKeyIds)
|
||||
CDMCaps::AutoLock::GetKeyStatusesForSession(const nsAString& aSessionId,
|
||||
nsTArray<KeyStatus>& aOutKeyStatuses)
|
||||
{
|
||||
for (size_t i = 0; i < mData.mUsableKeyIds.Length(); i++) {
|
||||
const auto& key = mData.mUsableKeyIds[i];
|
||||
for (size_t i = 0; i < mData.mKeyStatuses.Length(); i++) {
|
||||
const auto& key = mData.mKeyStatuses[i];
|
||||
if (key.mSessionId.Equals(aSessionId)) {
|
||||
aOutKeyIds.AppendElement(key.mId);
|
||||
aOutKeyStatuses.AppendElement(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "SamplesWaitingForKey.h"
|
||||
#include "gmp-decryption.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -24,6 +25,29 @@ public:
|
||||
CDMCaps();
|
||||
~CDMCaps();
|
||||
|
||||
struct KeyStatus {
|
||||
KeyStatus(const CencKeyId& aId,
|
||||
const nsString& aSessionId,
|
||||
GMPMediaKeyStatus aStatus)
|
||||
: mId(aId)
|
||||
, mSessionId(aSessionId)
|
||||
, mStatus(aStatus)
|
||||
{}
|
||||
KeyStatus(const KeyStatus& aOther)
|
||||
: mId(aOther.mId)
|
||||
, mSessionId(aOther.mSessionId)
|
||||
, mStatus(aOther.mStatus)
|
||||
{}
|
||||
bool operator==(const KeyStatus& aOther) const {
|
||||
return mId == aOther.mId &&
|
||||
mSessionId == aOther.mSessionId;
|
||||
};
|
||||
|
||||
CencKeyId mId;
|
||||
nsString mSessionId;
|
||||
GMPMediaKeyStatus mStatus;
|
||||
};
|
||||
|
||||
// Locks the CDMCaps. It must be locked to access its shared state.
|
||||
// Threadsafe when locked.
|
||||
class MOZ_STACK_CLASS AutoLock {
|
||||
@ -37,16 +61,12 @@ public:
|
||||
|
||||
bool IsKeyUsable(const CencKeyId& aKeyId);
|
||||
|
||||
// Returns true if setting this key usable results in the usable keys
|
||||
// changing for this session, i.e. the key was not previously marked usable.
|
||||
bool SetKeyUsable(const CencKeyId& aKeyId, const nsString& aSessionId);
|
||||
// Returns true if key status changed,
|
||||
// i.e. the key status changed from usable to expired.
|
||||
bool SetKeyStatus(const CencKeyId& aKeyId, const nsString& aSessionId, GMPMediaKeyStatus aStatus);
|
||||
|
||||
// Returns true if setting this key unusable results in the usable keys
|
||||
// changing for this session, i.e. the key was previously marked usable.
|
||||
bool SetKeyUnusable(const CencKeyId& aKeyId, const nsString& aSessionId);
|
||||
|
||||
void GetUsableKeysForSession(const nsAString& aSessionId,
|
||||
nsTArray<CencKeyId>& aOutKeyIds);
|
||||
void GetKeyStatusesForSession(const nsAString& aSessionId,
|
||||
nsTArray<KeyStatus>& aOutKeyStatuses);
|
||||
|
||||
// Sets the capabilities of the CDM. aCaps is the logical OR of the
|
||||
// GMP_EME_CAP_* flags from gmp-decryption.h.
|
||||
@ -85,25 +105,7 @@ private:
|
||||
|
||||
Monitor mMonitor;
|
||||
|
||||
struct UsableKey {
|
||||
UsableKey(const CencKeyId& aId,
|
||||
const nsString& aSessionId)
|
||||
: mId(aId)
|
||||
, mSessionId(aSessionId)
|
||||
{}
|
||||
UsableKey(const UsableKey& aOther)
|
||||
: mId(aOther.mId)
|
||||
, mSessionId(aOther.mSessionId)
|
||||
{}
|
||||
bool operator==(const UsableKey& aOther) const {
|
||||
return mId == aOther.mId &&
|
||||
mSessionId == aOther.mSessionId;
|
||||
};
|
||||
|
||||
CencKeyId mId;
|
||||
nsString mSessionId;
|
||||
};
|
||||
nsTArray<UsableKey> mUsableKeyIds;
|
||||
nsTArray<KeyStatus> mKeyStatuses;
|
||||
|
||||
nsTArray<WaitForKeys> mWaitForKeys;
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/dom/MediaKeyError.h"
|
||||
#include "mozilla/dom/MediaKeyMessageEvent.h"
|
||||
#include "mozilla/dom/MediaEncryptedEvent.h"
|
||||
#include "mozilla/dom/MediaKeyStatusMap.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
@ -22,6 +23,7 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaKeySession,
|
||||
DOMEventTargetHelper,
|
||||
mMediaKeyError,
|
||||
mKeys,
|
||||
mKeyStatusMap,
|
||||
mClosed)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaKeySession)
|
||||
@ -46,6 +48,7 @@ MediaKeySession::MediaKeySession(nsPIDOMWindow* aParent,
|
||||
, mToken(sMediaKeySessionNum++)
|
||||
, mIsClosed(false)
|
||||
, mUninitialized(true)
|
||||
, mKeyStatusMap(new MediaKeyStatusMap(aParent))
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
mClosed = mKeys->MakePromise(aRv);
|
||||
@ -106,6 +109,30 @@ MediaKeySession::Closed() const
|
||||
return mClosed;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MediaKeySession::UpdateKeyStatusMap()
|
||||
{
|
||||
MOZ_ASSERT(!IsClosed());
|
||||
if (!mKeys->GetCDMProxy()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<CDMCaps::KeyStatus> keyStatuses;
|
||||
{
|
||||
CDMCaps::AutoLock caps(mKeys->GetCDMProxy()->Capabilites());
|
||||
caps.GetKeyStatusesForSession(mSessionId, keyStatuses);
|
||||
}
|
||||
|
||||
mKeyStatusMap->Update(keyStatuses);
|
||||
}
|
||||
|
||||
MediaKeyStatusMap*
|
||||
MediaKeySession::KeyStatuses() const
|
||||
{
|
||||
return mKeyStatusMap;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeySession::GenerateRequest(const nsAString& aInitDataType,
|
||||
const ArrayBufferViewOrArrayBuffer& aInitData,
|
||||
@ -248,34 +275,6 @@ MediaKeySession::Remove(ErrorResult& aRv)
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeySession::GetUsableKeyIds(ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise(mKeys->MakePromise(aRv));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (IsClosed() || !mKeys->GetCDMProxy()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsTArray<CencKeyId> keyIds;
|
||||
{
|
||||
CDMCaps::AutoLock caps(mKeys->GetCDMProxy()->Capabilites());
|
||||
caps.GetUsableKeysForSession(mSessionId, keyIds);
|
||||
}
|
||||
|
||||
nsTArray<TypedArrayCreator<ArrayBuffer>> array;
|
||||
for (size_t i = 0; i < keyIds.Length(); i++) {
|
||||
array.AppendElement(keyIds[i]);
|
||||
}
|
||||
promise->MaybeResolve(array);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySession::DispatchKeyMessage(MediaKeyMessageType aMessageType,
|
||||
const nsTArray<uint8_t>& aMessage)
|
||||
@ -302,6 +301,9 @@ MediaKeySession::DispatchKeysChange()
|
||||
if (IsClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateKeyStatusMap();
|
||||
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, NS_LITERAL_STRING("keyschange"), false);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
|
@ -30,6 +30,7 @@ namespace dom {
|
||||
|
||||
class ArrayBufferViewOrArrayBuffer;
|
||||
class MediaKeyError;
|
||||
class MediaKeyStatusMap;
|
||||
|
||||
class MediaKeySession MOZ_FINAL : public DOMEventTargetHelper
|
||||
{
|
||||
@ -51,6 +52,8 @@ public:
|
||||
// Mark this as resultNotAddRefed to return raw pointers
|
||||
MediaKeyError* GetError() const;
|
||||
|
||||
MediaKeyStatusMap* KeyStatuses() const;
|
||||
|
||||
void GetKeySystem(nsString& aRetval) const;
|
||||
|
||||
void GetSessionId(nsString& aRetval) const;
|
||||
@ -78,8 +81,6 @@ public:
|
||||
|
||||
already_AddRefed<Promise> Remove(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> GetUsableKeyIds(ErrorResult& aRv);
|
||||
|
||||
void DispatchKeyMessage(MediaKeyMessageType aMessageType,
|
||||
const nsTArray<uint8_t>& aMessage);
|
||||
|
||||
@ -97,6 +98,8 @@ public:
|
||||
private:
|
||||
~MediaKeySession();
|
||||
|
||||
void UpdateKeyStatusMap();
|
||||
|
||||
nsRefPtr<Promise> mClosed;
|
||||
|
||||
nsRefPtr<MediaKeyError> mMediaKeyError;
|
||||
@ -107,6 +110,7 @@ private:
|
||||
const uint32_t mToken;
|
||||
bool mIsClosed;
|
||||
bool mUninitialized;
|
||||
nsRefPtr<MediaKeyStatusMap> mKeyStatusMap;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
245
dom/media/eme/MediaKeyStatusMap.cpp
Normal file
245
dom/media/eme/MediaKeyStatusMap.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsPIDOMWindow.h"
|
||||
#include "mozilla/dom/MediaKeyStatusMap.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeyStatusMap)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeyStatusMap)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeyStatusMap)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(MediaKeyStatusMap)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaKeyStatusMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
tmp->mMap = nullptr;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MediaKeyStatusMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(MediaKeyStatusMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
MediaKeyStatusMap::MediaKeyStatusMap(nsPIDOMWindow* aParent)
|
||||
: mParent(aParent)
|
||||
, mUpdateError(NS_OK)
|
||||
{
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(aParent))) {
|
||||
mUpdateError = NS_ERROR_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
mMap = JS::NewMapObject(cx);
|
||||
if (NS_WARN_IF(!mMap)) {
|
||||
mUpdateError = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
MediaKeyStatusMap::~MediaKeyStatusMap()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MediaKeyStatusMap::WrapObject(JSContext* aCx)
|
||||
{
|
||||
return MediaKeyStatusMapBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
MediaKeyStatusMap::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
MediaKeyStatus
|
||||
MediaKeyStatusMap::Get(JSContext* aCx,
|
||||
const ArrayBufferViewOrArrayBuffer& aKey,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
if (NS_FAILED(mUpdateError)) {
|
||||
aRv.Throw(mUpdateError);
|
||||
return MediaKeyStatus::Internal_error;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> map(aCx, mMap);
|
||||
JS::Rooted<JS::Value> key(aCx);
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
|
||||
if (!aKey.ToJSVal(aCx, map, &key) ||
|
||||
!JS::MapGet(aCx, map, key, &val)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return MediaKeyStatus::Internal_error;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
int index = FindEnumStringIndex<true>(
|
||||
aCx, val, MediaKeyStatusValues::strings,
|
||||
"MediaKeyStatus", "Invalid MediaKeyStatus value", &ok);
|
||||
|
||||
return ok ? static_cast<MediaKeyStatus>(index) :
|
||||
MediaKeyStatus::Internal_error;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaKeyStatusMap::Has(JSContext* aCx,
|
||||
const ArrayBufferViewOrArrayBuffer& aKey,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
if (NS_FAILED(mUpdateError)) {
|
||||
aRv.Throw(mUpdateError);
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> map(aCx, mMap);
|
||||
JS::Rooted<JS::Value> key(aCx);
|
||||
bool result = false;
|
||||
|
||||
if (!aKey.ToJSVal(aCx, map, &key) ||
|
||||
!JS::MapHas(aCx, map, key, &result)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<decltype(JS::MapKeys) Method>
|
||||
static void CallMapMethod(JSContext* aCx,
|
||||
const JS::Heap<JSObject*>& aMap,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv,
|
||||
nsresult aUpdateError)
|
||||
{
|
||||
if (NS_FAILED(aUpdateError)) {
|
||||
aRv.Throw(aUpdateError);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> map(aCx, aMap);
|
||||
JS::Rooted<JS::Value> result(aCx);
|
||||
if (!Method(aCx, map, &result)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
aResult.set(&result.toObject());
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeyStatusMap::Keys(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
CallMapMethod<JS::MapKeys>(aCx, mMap, aResult, aRv, mUpdateError);
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeyStatusMap::Values(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
CallMapMethod<JS::MapValues>(aCx, mMap, aResult, aRv, mUpdateError);
|
||||
}
|
||||
void
|
||||
MediaKeyStatusMap::Entries(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
CallMapMethod<JS::MapEntries>(aCx, mMap, aResult, aRv, mUpdateError);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MediaKeyStatusMap::GetSize(JSContext* aCx, ErrorResult& aRv) const
|
||||
{
|
||||
if (NS_FAILED(mUpdateError)) {
|
||||
aRv.Throw(mUpdateError);
|
||||
return 0;
|
||||
}
|
||||
JS::Rooted<JSObject*> map(aCx, mMap);
|
||||
return JS::MapSize(aCx, map);
|
||||
}
|
||||
|
||||
static MediaKeyStatus
|
||||
ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
|
||||
switch (aStatus) {
|
||||
case kGMPUsable: return MediaKeyStatus::Usable;
|
||||
case kGMPExpired: return MediaKeyStatus::Expired;
|
||||
case kGMPOutputNotAllowed: return MediaKeyStatus::Output_not_allowed;
|
||||
default: return MediaKeyStatus::Internal_error;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
ToJSString(JSContext* aCx, GMPMediaKeyStatus aStatus,
|
||||
JS::MutableHandle<JS::Value> aResult)
|
||||
{
|
||||
auto val = uint32_t(ToMediaKeyStatus(aStatus));
|
||||
MOZ_ASSERT(val < ArrayLength(MediaKeyStatusValues::strings));
|
||||
JSString* str = JS_NewStringCopyN(aCx,
|
||||
MediaKeyStatusValues::strings[val].value,
|
||||
MediaKeyStatusValues::strings[val].length);
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
aResult.setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaKeyStatusMap::UpdateInternal(const nsTArray<CDMCaps::KeyStatus>& keys)
|
||||
{
|
||||
AutoJSAPI jsapi;
|
||||
if (!mMap || NS_WARN_IF(!jsapi.Init(mParent))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
jsapi.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> map(cx, mMap);
|
||||
if (!JS::MapClear(cx, map)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < keys.Length(); i++) {
|
||||
const auto& ks = keys[i];
|
||||
JS::Rooted<JS::Value> key(cx);
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
if (!ToJSValue(cx, TypedArrayCreator<ArrayBuffer>(ks.mId), &key) ||
|
||||
!ToJSString(cx, ks.mStatus, &val) ||
|
||||
!JS::MapSet(cx, map, key, val)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeyStatusMap::Update(const nsTArray<CDMCaps::KeyStatus>& keys)
|
||||
{
|
||||
// Since we can't leave the map in a partial update state, we need
|
||||
// to remember the error and throw it next time the interface methods
|
||||
// are called.
|
||||
mUpdateError = UpdateInternal(keys);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
78
dom/media/eme/MediaKeyStatusMap.h
Normal file
78
dom/media/eme/MediaKeyStatusMap.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 mozilla_dom_MediaKeyStatuses_h
|
||||
#define mozilla_dom_MediaKeyStatuses_h
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/dom/MediaKeyStatusMapBinding.h"
|
||||
#include "mozilla/CDMCaps.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
class ArrayBufferViewOrArrayBuffer;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MediaKeyStatusMap MOZ_FINAL : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeyStatusMap)
|
||||
|
||||
public:
|
||||
explicit MediaKeyStatusMap(nsPIDOMWindow* aParent);
|
||||
|
||||
protected:
|
||||
~MediaKeyStatusMap();
|
||||
|
||||
public:
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
|
||||
MediaKeyStatus Get(JSContext* aCx,
|
||||
const ArrayBufferViewOrArrayBuffer& aKey,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
bool Has(JSContext* aCx,
|
||||
const ArrayBufferViewOrArrayBuffer& aKey,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
void Keys(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
void Values(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
void Entries(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
uint32_t GetSize(JSContext* aCx, ErrorResult& aRv) const;
|
||||
|
||||
void Update(const nsTArray<CDMCaps::KeyStatus>& keys);
|
||||
|
||||
private:
|
||||
nsresult UpdateInternal(const nsTArray<CDMCaps::KeyStatus>& keys);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mParent;
|
||||
JS::Heap<JSObject*> mMap;
|
||||
nsresult mUpdateError;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -10,6 +10,7 @@ EXPORTS.mozilla.dom += [
|
||||
'MediaKeyMessageEvent.h',
|
||||
'MediaKeys.h',
|
||||
'MediaKeySession.h',
|
||||
'MediaKeyStatusMap.h',
|
||||
'MediaKeySystemAccess.h',
|
||||
]
|
||||
|
||||
@ -30,6 +31,7 @@ UNIFIED_SOURCES += [
|
||||
'MediaKeyMessageEvent.cpp',
|
||||
'MediaKeys.cpp',
|
||||
'MediaKeySession.cpp',
|
||||
'MediaKeyStatusMap.cpp',
|
||||
'MediaKeySystemAccess.cpp',
|
||||
]
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
Name: fake
|
||||
Description: Fake GMP Plugin
|
||||
Version: 1.0
|
||||
APIs: encode-video[h264], decode-video[h264], eme-decrypt-v4[fake]
|
||||
APIs: encode-video[h264], decode-video[h264], eme-decrypt-v5[fake]
|
||||
Libraries: dxva2.dll
|
||||
|
@ -126,27 +126,17 @@ GMPDecryptorChild::SessionError(const char* aSessionId,
|
||||
}
|
||||
|
||||
void
|
||||
GMPDecryptorChild::KeyIdUsable(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength)
|
||||
GMPDecryptorChild::KeyStatusChanged(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength,
|
||||
GMPMediaKeyStatus aStatus)
|
||||
{
|
||||
nsAutoTArray<uint8_t, 16> kid;
|
||||
kid.AppendElements(aKeyId, aKeyIdLength);
|
||||
CALL_ON_GMP_THREAD(SendKeyIdUsable,
|
||||
nsAutoCString(aSessionId, aSessionIdLength), kid);
|
||||
}
|
||||
|
||||
void
|
||||
GMPDecryptorChild::KeyIdNotUsable(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength)
|
||||
{
|
||||
nsAutoTArray<uint8_t, 16> kid;
|
||||
kid.AppendElements(aKeyId, aKeyIdLength);
|
||||
CALL_ON_GMP_THREAD(SendKeyIdNotUsable,
|
||||
nsAutoCString(aSessionId, aSessionIdLength), kid);
|
||||
CALL_ON_GMP_THREAD(SendKeyStatusChanged,
|
||||
nsAutoCString(aSessionId, aSessionIdLength), kid,
|
||||
aStatus);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -63,15 +63,11 @@ public:
|
||||
const char* aMessage,
|
||||
uint32_t aMessageLength) MOZ_OVERRIDE;
|
||||
|
||||
virtual void KeyIdUsable(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength) MOZ_OVERRIDE;
|
||||
|
||||
virtual void KeyIdNotUsable(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength) MOZ_OVERRIDE;
|
||||
virtual void KeyStatusChanged(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength,
|
||||
GMPMediaKeyStatus aStatus) MOZ_OVERRIDE;
|
||||
|
||||
virtual void SetCapabilities(uint64_t aCaps) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -265,26 +265,15 @@ GMPDecryptorParent::RecvSessionError(const nsCString& aSessionId,
|
||||
}
|
||||
|
||||
bool
|
||||
GMPDecryptorParent::RecvKeyIdUsable(const nsCString& aSessionId,
|
||||
InfallibleTArray<uint8_t>&& aKeyId)
|
||||
GMPDecryptorParent::RecvKeyStatusChanged(const nsCString& aSessionId,
|
||||
InfallibleTArray<uint8_t>&& aKeyId,
|
||||
const GMPMediaKeyStatus& aStatus)
|
||||
{
|
||||
if (!mIsOpen) {
|
||||
NS_WARNING("Trying to use a dead GMP decrypter!");
|
||||
return false;
|
||||
}
|
||||
mCallback->KeyIdUsable(aSessionId, aKeyId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPDecryptorParent::RecvKeyIdNotUsable(const nsCString& aSessionId,
|
||||
InfallibleTArray<uint8_t>&& aKeyId)
|
||||
{
|
||||
if (!mIsOpen) {
|
||||
NS_WARNING("Trying to use a dead GMP decrypter!");
|
||||
return false;
|
||||
}
|
||||
mCallback->KeyIdNotUsable(aSessionId, aKeyId);
|
||||
mCallback->KeyStatusChanged(aSessionId, aKeyId, aStatus);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -91,11 +91,9 @@ private:
|
||||
const uint32_t& aSystemCode,
|
||||
const nsCString& aMessage) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvKeyIdUsable(const nsCString& aSessionId,
|
||||
InfallibleTArray<uint8_t>&& aKeyId) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvKeyIdNotUsable(const nsCString& aSessionId,
|
||||
InfallibleTArray<uint8_t>&& aKeyId) MOZ_OVERRIDE;
|
||||
virtual bool RecvKeyStatusChanged(const nsCString& aSessionId,
|
||||
InfallibleTArray<uint8_t>&& aKeyId,
|
||||
const GMPMediaKeyStatus& aStatus) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvDecrypted(const uint32_t& aId,
|
||||
const GMPErr& aErr,
|
||||
|
@ -44,11 +44,9 @@ public:
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage) = 0;
|
||||
|
||||
virtual void KeyIdUsable(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId) = 0;
|
||||
|
||||
virtual void KeyIdNotUsable(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId) = 0;
|
||||
virtual void KeyStatusChanged(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId,
|
||||
GMPMediaKeyStatus aStatus) = 0;
|
||||
|
||||
virtual void SetCaps(uint64_t aCaps) = 0;
|
||||
|
||||
|
@ -60,6 +60,13 @@ struct ParamTraits<GMPSessionMessageType>
|
||||
kGMPMessageInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPMediaKeyStatus>
|
||||
: public ContiguousEnumSerializer<GMPMediaKeyStatus,
|
||||
kGMPUsable,
|
||||
kGMPMediaKeyStatusInvalid>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<GMPSessionType>
|
||||
: public ContiguousEnumSerializer<GMPSessionType,
|
||||
|
@ -7,6 +7,7 @@ include protocol PGMP;
|
||||
include GMPTypes;
|
||||
|
||||
using GMPSessionMessageType from "gmp-decryption.h";
|
||||
using GMPMediaKeyStatus from "gmp-decryption.h";
|
||||
using GMPSessionType from "gmp-decryption.h";
|
||||
using GMPDOMException from "gmp-decryption.h";
|
||||
using GMPErr from "gmp-errors.h";
|
||||
@ -77,12 +78,11 @@ parent:
|
||||
uint32_t aSystemCode,
|
||||
nsCString aMessage);
|
||||
|
||||
KeyIdUsable(nsCString aSessionId, uint8_t[] aKey);
|
||||
KeyStatusChanged(nsCString aSessionId, uint8_t[] aKey,
|
||||
GMPMediaKeyStatus aStatus);
|
||||
|
||||
SetCaps(uint64_t aCaps);
|
||||
|
||||
KeyIdNotUsable(nsCString aSessionId,uint8_t[] aKey);
|
||||
|
||||
Decrypted(uint32_t aId, GMPErr aResult, uint8_t[] aBuffer);
|
||||
};
|
||||
|
||||
|
@ -76,6 +76,14 @@ enum GMPSessionMessageType {
|
||||
kGMPMessageInvalid = 4 // Must always be last.
|
||||
};
|
||||
|
||||
enum GMPMediaKeyStatus {
|
||||
kGMPUsable = 0,
|
||||
kGMPExpired = 1,
|
||||
kGMPOutputNotAllowed = 2,
|
||||
kGMPUnknown = 3,
|
||||
kGMPMediaKeyStatusInvalid = 4 // Must always be last.
|
||||
};
|
||||
|
||||
// Time in milliseconds, as offset from epoch, 1 Jan 1970.
|
||||
typedef int64_t GMPTimestamp;
|
||||
|
||||
@ -173,20 +181,14 @@ public:
|
||||
const char* aMessage,
|
||||
uint32_t aMessageLength) = 0;
|
||||
|
||||
// Marks a key as usable. Gecko will not call into the CDM to decrypt
|
||||
// Notifies the status of a key. Gecko will not call into the CDM to decrypt
|
||||
// or decode content encrypted with a key unless the CDM has marked it
|
||||
// usable first. So a CDM *MUST* mark its usable keys as usable!
|
||||
virtual void KeyIdUsable(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength) = 0;
|
||||
|
||||
// Marks a key as no longer usable.
|
||||
// Note: Keys are assumed to be not usable when a session is closed or removed.
|
||||
virtual void KeyIdNotUsable(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength) = 0;
|
||||
virtual void KeyStatusChanged(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
const uint8_t* aKeyId,
|
||||
uint32_t aKeyIdLength,
|
||||
GMPMediaKeyStatus aStatus) = 0;
|
||||
|
||||
// The CDM must report its capabilites of this CDM. aCaps should be a
|
||||
// logical OR of the GMP_EME_CAP_* flags. The CDM *MUST* call this
|
||||
@ -220,7 +222,7 @@ enum GMPSessionType {
|
||||
kGMPSessionInvalid = 2 // Must always be last.
|
||||
};
|
||||
|
||||
#define GMP_API_DECRYPTOR "eme-decrypt-v4"
|
||||
#define GMP_API_DECRYPTOR "eme-decrypt-v5"
|
||||
|
||||
// API exposed by plugin library to manage decryption sessions.
|
||||
// When the Host requests this by calling GMPGetAPIFunc().
|
||||
|
@ -1116,10 +1116,9 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
nsresult aException,
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage) MOZ_OVERRIDE {}
|
||||
virtual void KeyIdUsable(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE { }
|
||||
virtual void KeyIdNotUsable(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE {}
|
||||
virtual void KeyStatusChanged(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId,
|
||||
GMPMediaKeyStatus aStatus) MOZ_OVERRIDE { }
|
||||
virtual void SetCaps(uint64_t aCaps) MOZ_OVERRIDE {}
|
||||
virtual void Decrypted(uint32_t aId,
|
||||
GMPErr aResult,
|
||||
|
@ -341,19 +341,14 @@ MediaSource::Enabled(JSContext* cx, JSObject* aGlobal)
|
||||
}
|
||||
|
||||
// We want to restrict to YouTube only.
|
||||
// We define that as the origin being https://*.youtube.com.
|
||||
// We also support https://*.youtube-nocookie.com.
|
||||
// We define that as the origin being *.youtube.com.
|
||||
// We also support *.youtube-nocookie.com
|
||||
nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(global);
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (NS_FAILED(principal->GetURI(getter_AddRefs(uri))) || !uri) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isHttps = false;
|
||||
if (NS_FAILED(uri->SchemeIs("https", &isHttps)) || !isHttps) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldServ =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(tldServ, false);
|
||||
|
@ -225,10 +225,8 @@ MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
|
||||
AdjustEndTime(&mLastAudioTime, mAudioReader);
|
||||
}
|
||||
|
||||
// See if we can find a different reader that can pick up where we left off. We use the
|
||||
// EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
|
||||
// 1065207.
|
||||
if (SwitchAudioReader(mLastAudioTime, EOS_FUZZ_US) == READER_NEW) {
|
||||
// See if we can find a different reader that can pick up where we left off.
|
||||
if (SwitchAudioReader(mLastAudioTime) == READER_NEW) {
|
||||
mAudioSeekRequest.Begin(mAudioReader->Seek(mLastAudioTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteAudioSeekAndDoRequest,
|
||||
@ -337,10 +335,8 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
|
||||
AdjustEndTime(&mLastVideoTime, mVideoReader);
|
||||
}
|
||||
|
||||
// See if we can find a different reader that can pick up where we left off. We use the
|
||||
// EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
|
||||
// 1065207.
|
||||
if (SwitchVideoReader(mLastVideoTime, EOS_FUZZ_US) == READER_NEW) {
|
||||
// See if we can find a different reader that can pick up where we left off.
|
||||
if (SwitchVideoReader(mLastVideoTime) == READER_NEW) {
|
||||
mVideoSeekRequest.Begin(mVideoReader->Seek(mLastVideoTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteVideoSeekAndDoRequest,
|
||||
@ -437,7 +433,7 @@ MediaSourceReader::BreakCycles()
|
||||
|
||||
already_AddRefed<MediaDecoderReader>
|
||||
MediaSourceReader::SelectReader(int64_t aTarget,
|
||||
int64_t aError,
|
||||
int64_t aTolerance,
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders)
|
||||
{
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
@ -450,7 +446,7 @@ MediaSourceReader::SelectReader(int64_t aTarget,
|
||||
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
||||
aTrackDecoders[i]->GetBuffered(ranges);
|
||||
if (ranges->Find(double(aTarget) / USECS_PER_S,
|
||||
double(aError) / USECS_PER_S) == dom::TimeRanges::NoIndex) {
|
||||
double(aTolerance) / USECS_PER_S) == dom::TimeRanges::NoIndex) {
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::SelectReader(%lld) newReader=%p target not in ranges=%s",
|
||||
this, aTarget, newReader.get(), DumpTimeRanges(ranges).get());
|
||||
continue;
|
||||
@ -472,14 +468,21 @@ MediaSourceReader::HaveData(int64_t aTarget, MediaData::Type aType)
|
||||
}
|
||||
|
||||
MediaSourceReader::SwitchReaderResult
|
||||
MediaSourceReader::SwitchAudioReader(int64_t aTarget, int64_t aError)
|
||||
MediaSourceReader::SwitchAudioReader(int64_t aTarget)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
// XXX: Can't handle adding an audio track after ReadMetadata.
|
||||
if (!mAudioTrack) {
|
||||
return READER_ERROR;
|
||||
}
|
||||
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, aError, mAudioTrack->Decoders());
|
||||
|
||||
// We first search without the tolerance and then search with it, so that, in
|
||||
// the case of perfectly-aligned data, we don't prematurely jump to a new
|
||||
// reader and skip the last few samples of the current one.
|
||||
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, /* aTolerance = */ 0, mAudioTrack->Decoders());
|
||||
if (!newReader) {
|
||||
newReader = SelectReader(aTarget, EOS_FUZZ_US, mAudioTrack->Decoders());
|
||||
}
|
||||
if (newReader && newReader != mAudioReader) {
|
||||
mAudioReader->SetIdle();
|
||||
mAudioReader = newReader;
|
||||
@ -490,14 +493,21 @@ MediaSourceReader::SwitchAudioReader(int64_t aTarget, int64_t aError)
|
||||
}
|
||||
|
||||
MediaSourceReader::SwitchReaderResult
|
||||
MediaSourceReader::SwitchVideoReader(int64_t aTarget, int64_t aError)
|
||||
MediaSourceReader::SwitchVideoReader(int64_t aTarget)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
// XXX: Can't handle adding a video track after ReadMetadata.
|
||||
if (!mVideoTrack) {
|
||||
return READER_ERROR;
|
||||
}
|
||||
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, aError, mVideoTrack->Decoders());
|
||||
|
||||
// We first search without the tolerance and then search with it, so that, in
|
||||
// the case of perfectly-aligned data, we don't prematurely jump to a new
|
||||
// reader and skip the last few samples of the current one.
|
||||
nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, /* aTolerance = */ 0, mVideoTrack->Decoders());
|
||||
if (!newReader) {
|
||||
newReader = SelectReader(aTarget, EOS_FUZZ_US, mVideoTrack->Decoders());
|
||||
}
|
||||
if (newReader && newReader != mVideoReader) {
|
||||
mVideoReader->SetIdle();
|
||||
mVideoReader = newReader;
|
||||
@ -632,10 +642,10 @@ bool
|
||||
MediaSourceReader::TrackBuffersContainTime(int64_t aTime)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mAudioTrack && !mAudioTrack->ContainsTime(aTime)) {
|
||||
if (mAudioTrack && !mAudioTrack->ContainsTime(aTime, EOS_FUZZ_US)) {
|
||||
return false;
|
||||
}
|
||||
if (mVideoTrack && !mVideoTrack->ContainsTime(aTime)) {
|
||||
if (mVideoTrack && !mVideoTrack->ContainsTime(aTime, EOS_FUZZ_US)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -155,15 +155,16 @@ public:
|
||||
|
||||
private:
|
||||
// Switch the current audio/video reader to the reader that
|
||||
// contains aTarget (or up to aError after target). Both
|
||||
// aTarget and aError are in microseconds.
|
||||
// contains aTarget (or up to aTolerance after target). Both
|
||||
// aTarget and aTolerance are in microseconds.
|
||||
enum SwitchReaderResult {
|
||||
READER_ERROR = -1,
|
||||
READER_EXISTING = 0,
|
||||
READER_NEW = 1,
|
||||
};
|
||||
SwitchReaderResult SwitchAudioReader(int64_t aTarget, int64_t aError = 0);
|
||||
SwitchReaderResult SwitchVideoReader(int64_t aTarget, int64_t aError = 0);
|
||||
|
||||
SwitchReaderResult SwitchAudioReader(int64_t aTarget);
|
||||
SwitchReaderResult SwitchVideoReader(int64_t aTarget);
|
||||
|
||||
void DoAudioRequest();
|
||||
void DoVideoRequest();
|
||||
@ -199,7 +200,7 @@ private:
|
||||
// Return a reader from the set available in aTrackDecoders that has data
|
||||
// available in the range requested by aTarget.
|
||||
already_AddRefed<MediaDecoderReader> SelectReader(int64_t aTarget,
|
||||
int64_t aError,
|
||||
int64_t aTolerance,
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
|
||||
bool HaveData(int64_t aTarget, MediaData::Type aType);
|
||||
|
||||
|
@ -584,13 +584,14 @@ TrackBuffer::IsReady()
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::ContainsTime(int64_t aTime)
|
||||
TrackBuffer::ContainsTime(int64_t aTime, int64_t aTolerance)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) {
|
||||
nsRefPtr<dom::TimeRanges> r = new dom::TimeRanges();
|
||||
mInitializedDecoders[i]->GetBuffered(r);
|
||||
if (r->Find(double(aTime) / USECS_PER_S) != dom::TimeRanges::NoIndex) {
|
||||
if (r->Find(double(aTime) / USECS_PER_S,
|
||||
double(aTolerance) / USECS_PER_S) != dom::TimeRanges::NoIndex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public:
|
||||
|
||||
// Returns true if any of the decoders managed by this track buffer
|
||||
// contain aTime in their buffered ranges.
|
||||
bool ContainsTime(int64_t aTime);
|
||||
bool ContainsTime(int64_t aTime, int64_t aTolerance);
|
||||
|
||||
void BreakCycles();
|
||||
|
||||
|
@ -31,14 +31,17 @@ function UsableKeyIdsMatch(usableKeyIds, expectedKeyIds) {
|
||||
function AwaitAllKeysUsable(session, keys, token) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function listener(event) {
|
||||
session.getUsableKeyIds().then(function(usableKeyIds) {
|
||||
var u = UsableKeyIdsMatch(usableKeyIds, keys);
|
||||
if (UsableKeyIdsMatch(usableKeyIds, keys)) {
|
||||
Log(token, "resolving AwaitAllKeysUsable promise");
|
||||
session.removeEventListener("keyschange", listener);
|
||||
resolve();
|
||||
}
|
||||
}, bail(token + " failed to get usableKeyIds"));
|
||||
var map = session.keyStatuses;
|
||||
var usableKeyIds = [];
|
||||
for (var [key, val] of map.entries()) {
|
||||
is(val, "usable", token + ": key status should be usable");
|
||||
usableKeyIds.push(key);
|
||||
}
|
||||
if (UsableKeyIdsMatch(usableKeyIds, keys)) {
|
||||
Log(token, "resolving AwaitAllKeysUsable promise");
|
||||
session.removeEventListener("keyschange", listener);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
session.addEventListener("keyschange", listener);
|
||||
});
|
||||
@ -47,12 +50,11 @@ function AwaitAllKeysUsable(session, keys, token) {
|
||||
function AwaitAllKeysNotUsable(session, token) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function listener(event) {
|
||||
session.getUsableKeyIds().then(function(usableKeyIds) {
|
||||
if (usableKeyIds.length == 0) {
|
||||
session.removeEventListener("keyschange", listener);
|
||||
resolve();
|
||||
}
|
||||
}, bail(token + " failed to get usableKeyIds"));
|
||||
var map = session.keyStatuses;
|
||||
if (map.size == 0) {
|
||||
session.removeEventListener("keyschange", listener);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
session.addEventListener("keyschange", listener);
|
||||
});
|
||||
|
@ -22,13 +22,14 @@ function KeysChangeFunc(session, keys, token) {
|
||||
return function(ev) {
|
||||
var session = ev.target;
|
||||
session.gotKeysChanged = true;
|
||||
session.getUsableKeyIds().then(function(keyIds) {
|
||||
for (var k = 0; k < keyIds.length; k++) {
|
||||
var kid = Base64ToHex(window.btoa(ArrayBufferToString(keyIds[k])));
|
||||
ok(kid in session.keyIdsReceived, TimeStamp(token) + " session.keyIdsReceived contained " + kid + " as expected.");
|
||||
session.keyIdsReceived[kid] = true;
|
||||
}
|
||||
}, bail("Failed to get keyIds"));
|
||||
|
||||
var map = session.keyStatuses;
|
||||
for (var [key, val] of map.entries()) {
|
||||
is(val, "usable", token + ": key status should be usable");
|
||||
var kid = Base64ToHex(window.btoa(ArrayBufferToString(key)));
|
||||
ok(kid in session.keyIdsReceived, TimeStamp(token) + " session.keyIdsReceived contained " + kid + " as expected.");
|
||||
session.keyIdsReceived[kid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,20 +43,29 @@ skip-if = (toolkit == 'gonk' && debug) # debug-only failure, turned an intermitt
|
||||
[test_getUserMedia_constraints.html]
|
||||
skip-if = toolkit == 'gonk' || toolkit == 'android' # Bug 907352, backwards-compatible behavior on mobile only
|
||||
[test_getUserMedia_constraints_mobile.html]
|
||||
skip-if = toolkit != 'gonk' && toolkit != 'android' # Bug 907352, backwards-compatible behavior on mobile only
|
||||
skip-if = toolkit != 'android' # Bug 1063290, intermittent timeout # Bug 907352, backwards-compatible behavior on mobile only
|
||||
[test_getUserMedia_callbacks.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_gumWithinGum.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_playAudioTwice.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_playVideoAudioTwice.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) # debug-only failure; bug 926558
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout # bug 926558, debug-only failure
|
||||
[test_getUserMedia_playVideoTwice.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopAudioStreamWithFollowupAudio.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopVideoAudioStream.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) # debug-only failure
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout # bug 926558, debug-only failure
|
||||
[test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopVideoStream.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_stopVideoStreamWithFollowupVideo.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1063290, intermittent timeout
|
||||
[test_getUserMedia_peerIdentity.html]
|
||||
skip-if = toolkit == 'gonk' # b2g(Bug 1021776, too --ing slow on b2g)
|
||||
[test_peerConnection_addCandidateInHaveLocalOffer.html]
|
||||
|
@ -535,8 +535,10 @@ nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window)
|
||||
#if MOZ_WIDGET_GTK
|
||||
// bug 108347, flash plugin on linux doesn't like window->width <=
|
||||
// 0, but Java needs wants this call.
|
||||
if (!nsPluginHost::IsJavaMIMEType(mMIMEType) && window->type == NPWindowTypeWindow &&
|
||||
(window->width <= 0 || window->height <= 0)) {
|
||||
if (window && window->type == NPWindowTypeWindow &&
|
||||
(window->width <= 0 || window->height <= 0) &&
|
||||
(nsPluginHost::GetSpecialType(nsDependentCString(mMIMEType)) !=
|
||||
nsPluginHost::eSpecialType_Java)) {
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
@ -749,8 +751,8 @@ NPError nsNPAPIPluginInstance::SetWindowless(bool aWindowless)
|
||||
// property. (Last tested version: sl 4.0).
|
||||
// Changes to this code should be matched with changes in
|
||||
// PluginInstanceChild::InitQuirksMode.
|
||||
NS_NAMED_LITERAL_CSTRING(silverlight, "application/x-silverlight");
|
||||
if (!PL_strncasecmp(mMIMEType, silverlight.get(), silverlight.Length())) {
|
||||
if (nsPluginHost::GetSpecialType(nsDependentCString(mMIMEType)) ==
|
||||
nsPluginHost::eSpecialType_Silverlight) {
|
||||
mTransparent = true;
|
||||
}
|
||||
}
|
||||
|
@ -1652,19 +1652,43 @@ nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool nsPluginHost::IsJavaMIMEType(const char* aType)
|
||||
nsPluginHost::SpecialType
|
||||
nsPluginHost::GetSpecialType(const nsACString & aMIMEType)
|
||||
{
|
||||
if (aMIMEType.LowerCaseEqualsASCII("application/x-shockwave-flash") ||
|
||||
aMIMEType.LowerCaseEqualsASCII("application/futuresplash")) {
|
||||
return eSpecialType_Flash;
|
||||
}
|
||||
|
||||
if (aMIMEType.LowerCaseEqualsASCII("application/x-silverlight") ||
|
||||
aMIMEType.LowerCaseEqualsASCII("application/x-silverlight-2")) {
|
||||
return eSpecialType_Silverlight;
|
||||
}
|
||||
|
||||
if (aMIMEType.LowerCaseEqualsASCII("audio/x-pn-realaudio-plugin")) {
|
||||
NS_WARNING("You are loading RealPlayer");
|
||||
return eSpecialType_RealPlayer;
|
||||
}
|
||||
|
||||
if (aMIMEType.LowerCaseEqualsASCII("application/pdf")) {
|
||||
return eSpecialType_PDF;
|
||||
}
|
||||
|
||||
// Java registers variants of its MIME with parameters, e.g.
|
||||
// application/x-java-vm;version=1.3
|
||||
const nsACString &noParam = Substring(aMIMEType, 0, aMIMEType.FindChar(';'));
|
||||
|
||||
// The java mime pref may well not be one of these,
|
||||
// e.g. application/x-java-test used in the test suite
|
||||
nsAdoptingCString javaMIME = Preferences::GetCString(kPrefJavaMIME);
|
||||
return aType &&
|
||||
(javaMIME.EqualsIgnoreCase(aType) ||
|
||||
(0 == PL_strncasecmp(aType, "application/x-java-vm",
|
||||
sizeof("application/x-java-vm") - 1)) ||
|
||||
(0 == PL_strncasecmp(aType, "application/x-java-applet",
|
||||
sizeof("application/x-java-applet") - 1)) ||
|
||||
(0 == PL_strncasecmp(aType, "application/x-java-bean",
|
||||
sizeof("application/x-java-bean") - 1)));
|
||||
if ((!javaMIME.IsEmpty() && noParam.LowerCaseEqualsASCII(javaMIME)) ||
|
||||
noParam.LowerCaseEqualsASCII("application/x-java-vm") ||
|
||||
noParam.LowerCaseEqualsASCII("application/x-java-applet") ||
|
||||
noParam.LowerCaseEqualsASCII("application/x-java-bean")) {
|
||||
return eSpecialType_Java;
|
||||
}
|
||||
|
||||
return eSpecialType_None;
|
||||
}
|
||||
|
||||
// Check whether or not a tag is a live, valid tag, and that it's loaded.
|
||||
|
@ -171,9 +171,20 @@ public:
|
||||
// Always returns true if plugin.allowed_types is not set
|
||||
static bool IsTypeWhitelisted(const char *aType);
|
||||
|
||||
// checks whether aTag is a "java" plugin tag (a tag for a plugin
|
||||
// that does Java)
|
||||
static bool IsJavaMIMEType(const char *aType);
|
||||
// checks whether aType is a type we recognize for potential special handling
|
||||
enum SpecialType { eSpecialType_None,
|
||||
// Informs some decisions about OOP and quirks
|
||||
eSpecialType_Flash,
|
||||
// Binds to the <applet> tag, has various special
|
||||
// rules around opening channels, codebase, ...
|
||||
eSpecialType_Java,
|
||||
// Some IPC quirks
|
||||
eSpecialType_Silverlight,
|
||||
// Native widget quirks
|
||||
eSpecialType_PDF,
|
||||
// Native widget quirks
|
||||
eSpecialType_RealPlayer };
|
||||
static SpecialType GetSpecialType(const nsACString & aMIMEType);
|
||||
|
||||
static nsresult PostPluginUnloadEvent(PRLibrary* aLibrary);
|
||||
|
||||
|
@ -1096,10 +1096,10 @@ void nsPluginInstanceOwner::AddToCARefreshTimer() {
|
||||
|
||||
// Flash invokes InvalidateRect for us.
|
||||
const char* mime = nullptr;
|
||||
if (NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime) {
|
||||
if (strcmp(mime, "application/x-shockwave-flash") == 0) {
|
||||
return;
|
||||
}
|
||||
if (NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime &&
|
||||
nsPluginHost::GetSpecialType(nsDependentCString(mime)) ==
|
||||
nsPluginHost::eSpecialType_Flash) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sCARefreshListeners) {
|
||||
|
@ -97,16 +97,8 @@ void PluginWindowEvent::Init(const PluginWindowWeakRef &ref, HWND aWnd,
|
||||
* nsPluginNativeWindow Windows specific class declaration
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
nsPluginType_Unknown = 0,
|
||||
nsPluginType_Flash,
|
||||
nsPluginType_Real,
|
||||
nsPluginType_PDF,
|
||||
nsPluginType_Other
|
||||
} nsPluginType;
|
||||
|
||||
class nsPluginNativeWindowWin : public nsPluginNativeWindow {
|
||||
public:
|
||||
public:
|
||||
nsPluginNativeWindowWin();
|
||||
virtual ~nsPluginNativeWindowWin();
|
||||
|
||||
@ -135,7 +127,7 @@ private:
|
||||
HWND mParentWnd;
|
||||
LONG_PTR mParentProc;
|
||||
public:
|
||||
nsPluginType mPluginType;
|
||||
nsPluginHost::SpecialType mPluginType;
|
||||
};
|
||||
|
||||
static bool sInMessageDispatch = false;
|
||||
@ -162,7 +154,7 @@ static bool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin, nsNPAPIPl
|
||||
nsCOMPtr<nsIRunnable> pwe = aWin->GetPluginWindowEvent(hWnd, msg, wParam, lParam);
|
||||
if (pwe) {
|
||||
NS_DispatchToCurrentThread(pwe);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -183,7 +175,7 @@ private:
|
||||
NS_IMETHODIMP nsDelayedPopupsEnabledEvent::Run()
|
||||
{
|
||||
mInst->PushPopupsEnabledState(false);
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
@ -213,7 +205,7 @@ static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam
|
||||
// Real may go into a state where it recursivly dispatches the same event
|
||||
// when subclassed. If this is Real, lets examine the event and drop it
|
||||
// on the floor if we get into this recursive situation. See bug 192914.
|
||||
if (win->mPluginType == nsPluginType_Real) {
|
||||
if (win->mPluginType == nsPluginHost::eSpecialType_RealPlayer) {
|
||||
if (sInMessageDispatch && msg == sLastMsg)
|
||||
return true;
|
||||
// Cache the last message sent
|
||||
@ -263,7 +255,7 @@ static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam
|
||||
|
||||
case WM_MOUSEACTIVATE: {
|
||||
// If a child window of this plug-in is already focused,
|
||||
// don't focus the parent to avoid focus dance. We'll
|
||||
// don't focus the parent to avoid focus dance. We'll
|
||||
// receive a follow up WM_SETFOCUS which will notify
|
||||
// the appropriate window anyway.
|
||||
HWND focusedWnd = ::GetFocus();
|
||||
@ -291,7 +283,7 @@ static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam
|
||||
case WM_KILLFOCUS: {
|
||||
// RealPlayer can crash, don't process the message for those,
|
||||
// see bug 328675.
|
||||
if (win->mPluginType == nsPluginType_Real && msg == sLastMsg)
|
||||
if (win->mPluginType == nsPluginHost::eSpecialType_RealPlayer && msg == sLastMsg)
|
||||
return TRUE;
|
||||
// Make sure setfocus and killfocus get through to the widget procedure
|
||||
// even if they are eaten by the plugin. Also make sure we aren't calling
|
||||
@ -309,7 +301,7 @@ static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam
|
||||
// Macromedia Flash plugin may flood the message queue with some special messages
|
||||
// (WM_USER+1) causing 100% CPU consumption and GUI freeze, see mozilla bug 132759;
|
||||
// we can prevent this from happening by delaying the processing such messages;
|
||||
if (win->mPluginType == nsPluginType_Flash) {
|
||||
if (win->mPluginType == nsPluginHost::eSpecialType_Flash) {
|
||||
if (ProcessFlashMessageDelayed(win, inst, hWnd, msg, wParam, lParam))
|
||||
return TRUE;
|
||||
}
|
||||
@ -403,7 +395,7 @@ SetWindowLongHookCheck(HWND hWnd,
|
||||
{
|
||||
nsPluginNativeWindowWin * win =
|
||||
(nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
|
||||
if (!win || (win && win->mPluginType != nsPluginType_Flash) ||
|
||||
if (!win || (win && win->mPluginType != nsPluginHost::eSpecialType_Flash) ||
|
||||
(nIndex == GWLP_WNDPROC &&
|
||||
newLong == reinterpret_cast<LONG_PTR>(PluginWndProc)))
|
||||
return true;
|
||||
@ -425,7 +417,7 @@ SetWindowLongAHook(HWND hWnd,
|
||||
if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
|
||||
return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
|
||||
|
||||
// Set flash's new subclass to get the result.
|
||||
// Set flash's new subclass to get the result.
|
||||
LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong);
|
||||
|
||||
// We already checked this in SetWindowLongHookCheck
|
||||
@ -454,14 +446,14 @@ SetWindowLongWHook(HWND hWnd,
|
||||
if (SetWindowLongHookCheck(hWnd, nIndex, newLong))
|
||||
return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
|
||||
|
||||
// Set flash's new subclass to get the result.
|
||||
// Set flash's new subclass to get the result.
|
||||
LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong);
|
||||
|
||||
// We already checked this in SetWindowLongHookCheck
|
||||
nsPluginNativeWindowWin * win =
|
||||
(nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
|
||||
|
||||
// Hook our subclass back up, just like we do on setwindow.
|
||||
// Hook our subclass back up, just like we do on setwindow.
|
||||
win->SetPrevWindowProc(
|
||||
reinterpret_cast<WNDPROC>(sUser32SetWindowLongWHookStub(hWnd, nIndex,
|
||||
reinterpret_cast<LONG_PTR>(PluginWndProc))));
|
||||
@ -499,15 +491,15 @@ HookSetWindowLongPtr()
|
||||
nsPluginNativeWindowWin::nsPluginNativeWindowWin() : nsPluginNativeWindow()
|
||||
{
|
||||
// initialize the struct fields
|
||||
window = nullptr;
|
||||
x = 0;
|
||||
y = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
window = nullptr;
|
||||
x = 0;
|
||||
y = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
mPrevWinProc = nullptr;
|
||||
mPluginWinProc = nullptr;
|
||||
mPluginType = nsPluginType_Unknown;
|
||||
mPluginType = nsPluginHost::eSpecialType_None;
|
||||
|
||||
mParentWnd = nullptr;
|
||||
mParentProc = 0;
|
||||
@ -555,10 +547,10 @@ NS_IMETHODIMP PluginWindowEvent::Run()
|
||||
else {
|
||||
// Currently not used, but added so that processing events here
|
||||
// is more generic.
|
||||
::CallWindowProc(win->GetWindowProc(),
|
||||
hWnd,
|
||||
GetMsg(),
|
||||
GetWParam(),
|
||||
::CallWindowProc(win->GetWindowProc(),
|
||||
hWnd,
|
||||
GetMsg(),
|
||||
GetWParam(),
|
||||
GetLParam());
|
||||
}
|
||||
|
||||
@ -566,7 +558,7 @@ NS_IMETHODIMP PluginWindowEvent::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PluginWindowEvent *
|
||||
PluginWindowEvent *
|
||||
nsPluginNativeWindowWin::GetPluginWindowEvent(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam)
|
||||
{
|
||||
if (!mWeakRef) {
|
||||
@ -580,7 +572,7 @@ nsPluginNativeWindowWin::GetPluginWindowEvent(HWND aWnd, UINT aMsg, WPARAM aWPar
|
||||
// We have the ability to alloc if needed in case in the future some plugin
|
||||
// should post multiple PostMessages. However, this could lead to many
|
||||
// alloc's per second which could become a performance issue. See bug 169247.
|
||||
if (!mCachedPluginWindowEvent)
|
||||
if (!mCachedPluginWindowEvent)
|
||||
{
|
||||
event = new PluginWindowEvent();
|
||||
if (!event) return nullptr;
|
||||
@ -615,18 +607,10 @@ nsresult nsPluginNativeWindowWin::CallSetWindow(nsRefPtr<nsNPAPIPluginInstance>
|
||||
}
|
||||
|
||||
// check plugin mime type and cache it if it will need special treatment later
|
||||
if (mPluginType == nsPluginType_Unknown) {
|
||||
if (mPluginType == nsPluginHost::eSpecialType_None) {
|
||||
const char* mimetype = nullptr;
|
||||
aPluginInstance->GetMIMEType(&mimetype);
|
||||
if (mimetype) {
|
||||
if (!strcmp(mimetype, "application/x-shockwave-flash"))
|
||||
mPluginType = nsPluginType_Flash;
|
||||
else if (!strcmp(mimetype, "audio/x-pn-realaudio-plugin"))
|
||||
mPluginType = nsPluginType_Real;
|
||||
else if (!strcmp(mimetype, "application/pdf"))
|
||||
mPluginType = nsPluginType_PDF;
|
||||
else
|
||||
mPluginType = nsPluginType_Other;
|
||||
if (NS_SUCCEEDED(aPluginInstance->GetMIMEType(&mimetype)) && mimetype) {
|
||||
mPluginType = nsPluginHost::GetSpecialType(nsDependentCString(mimetype));
|
||||
}
|
||||
}
|
||||
|
||||
@ -649,7 +633,7 @@ nsresult nsPluginNativeWindowWin::CallSetWindow(nsRefPtr<nsNPAPIPluginInstance>
|
||||
|
||||
// PDF plugin v7.0.9, v8.1.3, and v9.0 subclass parent window, bug 531551
|
||||
// V8.2.2 and V9.1 don't have such problem.
|
||||
if (mPluginType == nsPluginType_PDF) {
|
||||
if (mPluginType == nsPluginHost::eSpecialType_PDF) {
|
||||
HWND parent = ::GetParent((HWND)window);
|
||||
if (mParentWnd != parent) {
|
||||
NS_ASSERTION(!mParentWnd, "Plugin's parent window changed");
|
||||
@ -663,7 +647,7 @@ nsresult nsPluginNativeWindowWin::CallSetWindow(nsRefPtr<nsNPAPIPluginInstance>
|
||||
|
||||
SubclassAndAssociateWindow();
|
||||
|
||||
if (window && mPluginType == nsPluginType_Flash &&
|
||||
if (window && mPluginType == nsPluginHost::eSpecialType_Flash &&
|
||||
!GetPropW((HWND)window, L"PluginInstanceParentProperty")) {
|
||||
HookSetWindowLongPtr();
|
||||
}
|
||||
@ -714,7 +698,7 @@ nsresult nsPluginNativeWindowWin::SubclassAndAssociateWindow()
|
||||
|
||||
DebugOnly<nsPluginNativeWindowWin *> win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
|
||||
NS_ASSERTION(!win || (win == this), "plugin window already has property and this is not us");
|
||||
|
||||
|
||||
if (!::SetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION, (HANDLE)this))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@ -741,7 +725,7 @@ nsresult nsPluginNativeWindowWin::UndoSubclassAndAssociateWindow()
|
||||
SetWindowLongPtr(hWnd, GWL_STYLE, style);
|
||||
}
|
||||
|
||||
if (mPluginType == nsPluginType_PDF && mParentWnd) {
|
||||
if (mPluginType == nsPluginHost::eSpecialType_Flash && mParentWnd) {
|
||||
::SetWindowLongPtr(mParentWnd, GWLP_WNDPROC, mParentProc);
|
||||
mParentWnd = nullptr;
|
||||
mParentProc = 0;
|
||||
|
@ -195,10 +195,16 @@ void nsPluginTag::InitMime(const char* const* aMimeTypes,
|
||||
}
|
||||
|
||||
// Look for certain special plugins.
|
||||
if (nsPluginHost::IsJavaMIMEType(mimeType.get())) {
|
||||
mIsJavaPlugin = true;
|
||||
} else if (mimeType.EqualsLiteral("application/x-shockwave-flash")) {
|
||||
mIsFlashPlugin = true;
|
||||
switch (nsPluginHost::GetSpecialType(mimeType)) {
|
||||
case nsPluginHost::eSpecialType_Java:
|
||||
mIsJavaPlugin = true;
|
||||
break;
|
||||
case nsPluginHost::eSpecialType_Flash:
|
||||
mIsFlashPlugin = true;
|
||||
break;
|
||||
case nsPluginHost::eSpecialType_None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in our MIME type array.
|
||||
|
@ -17,7 +17,7 @@ namespace plugins {
|
||||
|
||||
bool
|
||||
SetupBridge(uint32_t aPluginId, dom::ContentParent* aContentParent,
|
||||
bool aForceBridgeNow = false);
|
||||
bool aForceBridgeNow, nsresult* rv);
|
||||
|
||||
bool
|
||||
FindPluginsForContent(uint32_t aPluginEpoch,
|
||||
|
@ -2077,10 +2077,10 @@ PluginModuleChild::InitQuirksModes(const nsCString& aMimeType)
|
||||
if (mQuirks != QUIRKS_NOT_INITIALIZED)
|
||||
return;
|
||||
mQuirks = 0;
|
||||
// application/x-silverlight
|
||||
// application/x-silverlight-2
|
||||
NS_NAMED_LITERAL_CSTRING(silverlight, "application/x-silverlight");
|
||||
if (FindInReadable(silverlight, aMimeType)) {
|
||||
|
||||
nsPluginHost::SpecialType specialType = nsPluginHost::GetSpecialType(aMimeType);
|
||||
|
||||
if (specialType == nsPluginHost::eSpecialType_Silverlight) {
|
||||
mQuirks |= QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT;
|
||||
#ifdef OS_WIN
|
||||
mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
|
||||
@ -2089,11 +2089,9 @@ PluginModuleChild::InitQuirksModes(const nsCString& aMimeType)
|
||||
}
|
||||
|
||||
#ifdef OS_WIN
|
||||
// application/x-shockwave-flash
|
||||
NS_NAMED_LITERAL_CSTRING(flash, "application/x-shockwave-flash");
|
||||
if (FindInReadable(flash, aMimeType)) {
|
||||
if (specialType == nsPluginHost::eSpecialType_Flash) {
|
||||
mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
|
||||
mQuirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS;
|
||||
mQuirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS;
|
||||
mQuirks |= QUIRK_FLASH_HOOK_SETLONGPTR;
|
||||
mQuirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO;
|
||||
mQuirks |= QUIRK_FLASH_FIXUP_MOUSE_CAPTURE;
|
||||
@ -2102,20 +2100,18 @@ PluginModuleChild::InitQuirksModes(const nsCString& aMimeType)
|
||||
// QuickTime plugin usually loaded with audio/mpeg mimetype
|
||||
NS_NAMED_LITERAL_CSTRING(quicktime, "npqtplugin");
|
||||
if (FindInReadable(quicktime, mPluginFilename)) {
|
||||
mQuirks |= QUIRK_QUICKTIME_AVOID_SETWINDOW;
|
||||
mQuirks |= QUIRK_QUICKTIME_AVOID_SETWINDOW;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// Whitelist Flash and Quicktime to support offline renderer
|
||||
NS_NAMED_LITERAL_CSTRING(flash, "application/x-shockwave-flash");
|
||||
NS_NAMED_LITERAL_CSTRING(quicktime, "QuickTime Plugin.plugin");
|
||||
if (FindInReadable(flash, aMimeType)) {
|
||||
mQuirks |= QUIRK_FLASH_AVOID_CGMODE_CRASHES;
|
||||
mQuirks |= QUIRK_FLASH_HIDE_HIDPI_SUPPORT;
|
||||
}
|
||||
if (FindInReadable(flash, aMimeType) ||
|
||||
FindInReadable(quicktime, mPluginFilename)) {
|
||||
if (specialType == nsPluginHost::eSpecialType_Flash) {
|
||||
mQuirks |= QUIRK_FLASH_AVOID_CGMODE_CRASHES;
|
||||
mQuirks |= QUIRK_ALLOW_OFFLINE_RENDERER;
|
||||
mQuirks |= QUIRK_FLASH_HIDE_HIDPI_SUPPORT;
|
||||
} else if (FindInReadable(quicktime, mPluginFilename)) {
|
||||
mQuirks |= QUIRK_ALLOW_OFFLINE_RENDERER;
|
||||
}
|
||||
#endif
|
||||
|
@ -94,13 +94,14 @@ struct RunnableMethodTraits<mozilla::plugins::PluginModuleParent>
|
||||
bool
|
||||
mozilla::plugins::SetupBridge(uint32_t aPluginId,
|
||||
dom::ContentParent* aContentParent,
|
||||
bool aForceBridgeNow)
|
||||
bool aForceBridgeNow,
|
||||
nsresult* rv)
|
||||
{
|
||||
nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
|
||||
nsRefPtr<nsNPAPIPlugin> plugin;
|
||||
nsresult rv = host->GetPluginForContentProcess(aPluginId, getter_AddRefs(plugin));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
*rv = host->GetPluginForContentProcess(aPluginId, getter_AddRefs(plugin));
|
||||
if (NS_FAILED(*rv)) {
|
||||
return true;
|
||||
}
|
||||
PluginModuleChromeParent* chromeParent = static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
|
||||
chromeParent->SetContentParent(aContentParent);
|
||||
@ -293,7 +294,9 @@ PluginModuleContentParent::LoadModule(uint32_t aPluginId)
|
||||
* its module mapping. We fetch it from there after LoadPlugin finishes.
|
||||
*/
|
||||
dom::ContentChild* cp = dom::ContentChild::GetSingleton();
|
||||
if (!cp->SendLoadPlugin(aPluginId)) {
|
||||
nsresult rv;
|
||||
if (!cp->SendLoadPlugin(aPluginId, &rv) ||
|
||||
NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -669,6 +669,8 @@ var interfaceNamesInGlobalScope =
|
||||
{name: "MediaKeySystemAccess", pref: "media.eme.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MediaKeyMessageEvent", pref: "media.eme.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "MediaKeyStatusMap", pref: "media.eme.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"MediaList",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -23,22 +23,21 @@ interface MediaKeySession : EventTarget {
|
||||
|
||||
readonly attribute Promise<void> closed;
|
||||
|
||||
readonly attribute MediaKeyStatusMap keyStatuses;
|
||||
|
||||
[NewObject]
|
||||
Promise<void> generateRequest(DOMString initDataType, (ArrayBufferView or ArrayBuffer) initData);
|
||||
Promise<void> generateRequest(DOMString initDataType, BufferSource initData);
|
||||
|
||||
[NewObject]
|
||||
Promise<boolean> load(DOMString sessionId);
|
||||
|
||||
// session operations
|
||||
[NewObject]
|
||||
Promise<void> update((ArrayBufferView or ArrayBuffer) response);
|
||||
Promise<void> update(BufferSource response);
|
||||
|
||||
[NewObject]
|
||||
Promise<void> close();
|
||||
|
||||
[NewObject]
|
||||
Promise<void> remove();
|
||||
|
||||
[NewObject]
|
||||
Promise<sequence<ArrayBuffer>> getUsableKeyIds();
|
||||
};
|
||||
|
36
dom/webidl/MediaKeyStatusMap.webidl
Normal file
36
dom/webidl/MediaKeyStatusMap.webidl
Normal file
@ -0,0 +1,36 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html
|
||||
*
|
||||
* Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
|
||||
* W3C liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
enum MediaKeyStatus {
|
||||
"usable",
|
||||
"expired",
|
||||
"output-downscaled",
|
||||
"output-not-allowed",
|
||||
"internal-error"
|
||||
};
|
||||
|
||||
[Pref="media.eme.enabled"]
|
||||
interface MediaKeyStatusMap {
|
||||
[Throws]
|
||||
readonly attribute unsigned long size;
|
||||
|
||||
[Throws]
|
||||
object keys();
|
||||
|
||||
[Throws]
|
||||
object values();
|
||||
|
||||
[Throws]
|
||||
object entries();
|
||||
|
||||
// XXX: forEach, @@iterator
|
||||
};
|
@ -807,6 +807,7 @@ if CONFIG['MOZ_EME']:
|
||||
'MediaKeyMessageEvent.webidl',
|
||||
'MediaKeys.webidl',
|
||||
'MediaKeySession.webidl',
|
||||
'MediaKeyStatusMap.webidl',
|
||||
'MediaKeySystemAccess.webidl',
|
||||
]
|
||||
|
||||
|
@ -344,8 +344,7 @@ nsBindingManager::RemoveFromAttachedQueue(nsXBLBinding* aBinding)
|
||||
nsresult
|
||||
nsBindingManager::AddToAttachedQueue(nsXBLBinding* aBinding)
|
||||
{
|
||||
if (!mAttachedStack.AppendElement(aBinding))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mAttachedStack.AppendElement(aBinding);
|
||||
|
||||
// If we're in the middle of processing our queue already, don't
|
||||
// bother posting the event.
|
||||
|
@ -39,7 +39,6 @@ NS_NewXBLContentSink(nsIXMLContentSink** aResult,
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
nsXBLContentSink* it = new nsXBLContentSink();
|
||||
NS_ENSURE_TRUE(it, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
|
||||
nsresult rv = it->Init(aDoc, aURI, aContainer);
|
||||
@ -461,11 +460,9 @@ nsXBLContentSink::OnOpenContainer(const char16_t **aAtts,
|
||||
}
|
||||
nsXBLProtoImplAnonymousMethod* newMethod =
|
||||
new nsXBLProtoImplAnonymousMethod(name.get());
|
||||
if (newMethod) {
|
||||
newMethod->SetLineNumber(aLineNumber);
|
||||
mBinding->SetConstructor(newMethod);
|
||||
AddMember(newMethod);
|
||||
}
|
||||
newMethod->SetLineNumber(aLineNumber);
|
||||
mBinding->SetConstructor(newMethod);
|
||||
AddMember(newMethod);
|
||||
}
|
||||
else if (aTagName == nsGkAtoms::destructor) {
|
||||
ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
|
||||
@ -481,11 +478,9 @@ nsXBLContentSink::OnOpenContainer(const char16_t **aAtts,
|
||||
}
|
||||
nsXBLProtoImplAnonymousMethod* newMethod =
|
||||
new nsXBLProtoImplAnonymousMethod(name.get());
|
||||
if (newMethod) {
|
||||
newMethod->SetLineNumber(aLineNumber);
|
||||
mBinding->SetDestructor(newMethod);
|
||||
AddMember(newMethod);
|
||||
}
|
||||
newMethod->SetLineNumber(aLineNumber);
|
||||
mBinding->SetDestructor(newMethod);
|
||||
AddMember(newMethod);
|
||||
}
|
||||
else if (aTagName == nsGkAtoms::field) {
|
||||
ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
|
||||
@ -551,9 +546,7 @@ nsXBLContentSink::ConstructBinding(uint32_t aLineNumber)
|
||||
// performs this check.
|
||||
if (!cid.IsEmpty()) {
|
||||
mBinding = new nsXBLPrototypeBinding();
|
||||
if (!mBinding)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
|
||||
rv = mBinding->Init(cid, mDocInfo, binding, !mFoundFirstBinding);
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
NS_SUCCEEDED(mDocInfo->SetPrototypeBinding(cid, mBinding))) {
|
||||
@ -675,22 +668,17 @@ nsXBLContentSink::ConstructHandler(const char16_t **aAtts, uint32_t aLineNumber)
|
||||
clickcount, group, preventdefault,
|
||||
allowuntrusted, mBinding, aLineNumber);
|
||||
|
||||
if (newHandler) {
|
||||
// Add this handler to our chain of handlers.
|
||||
if (mHandler) {
|
||||
// Already have a chain. Just append to the end.
|
||||
mHandler->SetNextHandler(newHandler);
|
||||
}
|
||||
else {
|
||||
// We're the first handler in the chain.
|
||||
mBinding->SetPrototypeHandlers(newHandler);
|
||||
}
|
||||
// Adjust our mHandler pointer to point to the new last handler in the
|
||||
// chain.
|
||||
mHandler = newHandler;
|
||||
// Add this handler to our chain of handlers.
|
||||
if (mHandler) {
|
||||
// Already have a chain. Just append to the end.
|
||||
mHandler->SetNextHandler(newHandler);
|
||||
} else {
|
||||
mState = eXBL_Error;
|
||||
// We're the first handler in the chain.
|
||||
mBinding->SetPrototypeHandlers(newHandler);
|
||||
}
|
||||
// Adjust our mHandler pointer to point to the new last handler in the
|
||||
// chain.
|
||||
mHandler = newHandler;
|
||||
}
|
||||
|
||||
void
|
||||
@ -773,10 +761,8 @@ nsXBLContentSink::ConstructField(const char16_t **aAtts, uint32_t aLineNumber)
|
||||
// All of our pointers are now filled in. Construct our field with all of
|
||||
// these parameters.
|
||||
mField = new nsXBLProtoImplField(name, readonly);
|
||||
if (mField) {
|
||||
mField->SetLineNumber(aLineNumber);
|
||||
AddField(mField);
|
||||
}
|
||||
mField->SetLineNumber(aLineNumber);
|
||||
AddField(mField);
|
||||
}
|
||||
}
|
||||
|
||||
@ -882,8 +868,6 @@ nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
|
||||
|
||||
*aAppendContent = true;
|
||||
nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
|
||||
if (!prototype)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
prototype->mNodeInfo = aNodeInfo;
|
||||
|
||||
@ -919,8 +903,6 @@ nsXBLContentSink::AddAttributesToXULPrototype(const char16_t **aAtts,
|
||||
nsXULPrototypeAttribute* attrs = nullptr;
|
||||
if (aAttsCount > 0) {
|
||||
attrs = new nsXULPrototypeAttribute[aAttsCount];
|
||||
if (!attrs)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
aElement->mAttributes = attrs;
|
||||
|
@ -160,42 +160,24 @@ nsXBLKeyEventHandler::HandleEvent(nsIDOMEvent* aEvent)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
already_AddRefed<nsXBLEventHandler>
|
||||
NS_NewXBLEventHandler(nsXBLPrototypeHandler* aHandler,
|
||||
nsIAtom* aEventType,
|
||||
nsXBLEventHandler** aResult)
|
||||
nsIAtom* aEventType)
|
||||
{
|
||||
nsRefPtr<nsXBLEventHandler> handler;
|
||||
|
||||
switch (nsContentUtils::GetEventClassID(nsDependentAtomString(aEventType))) {
|
||||
case eDragEventClass:
|
||||
case eMouseEventClass:
|
||||
case eMouseScrollEventClass:
|
||||
case eWheelEventClass:
|
||||
case eSimpleGestureEventClass:
|
||||
*aResult = new nsXBLMouseEventHandler(aHandler);
|
||||
handler = new nsXBLMouseEventHandler(aHandler);
|
||||
break;
|
||||
default:
|
||||
*aResult = new nsXBLEventHandler(aHandler);
|
||||
handler = new nsXBLEventHandler(aHandler);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewXBLKeyEventHandler(nsIAtom* aEventType, uint8_t aPhase, uint8_t aType,
|
||||
nsXBLKeyEventHandler** aResult)
|
||||
{
|
||||
*aResult = new nsXBLKeyEventHandler(aEventType, aPhase, aType);
|
||||
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
return NS_OK;
|
||||
return handler.forget();
|
||||
}
|
||||
|
@ -113,13 +113,8 @@ private:
|
||||
bool mUsingContentXBLScope;
|
||||
};
|
||||
|
||||
nsresult
|
||||
already_AddRefed<nsXBLEventHandler>
|
||||
NS_NewXBLEventHandler(nsXBLPrototypeHandler* aHandler,
|
||||
nsIAtom* aEventType,
|
||||
nsXBLEventHandler** aResult);
|
||||
|
||||
nsresult
|
||||
NS_NewXBLKeyEventHandler(nsIAtom* aEventType, uint8_t aPhase,
|
||||
uint8_t aType, nsXBLKeyEventHandler** aResult);
|
||||
nsIAtom* aEventType);
|
||||
|
||||
#endif
|
||||
|
@ -520,8 +520,6 @@ NS_NewXBLProtoImpl(nsXBLPrototypeBinding* aBinding,
|
||||
nsXBLProtoImpl** aResult)
|
||||
{
|
||||
nsXBLProtoImpl* impl = new nsXBLProtoImpl();
|
||||
if (!impl)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
if (aClassName)
|
||||
impl->mClassName.AssignWithConversion(aClassName);
|
||||
else
|
||||
|
@ -807,11 +807,9 @@ nsXBLPrototypeBinding::CreateKeyHandlers()
|
||||
}
|
||||
|
||||
if (i == count) {
|
||||
nsRefPtr<nsXBLKeyEventHandler> newHandler;
|
||||
NS_NewXBLKeyEventHandler(eventAtom, phase, type,
|
||||
getter_AddRefs(newHandler));
|
||||
if (newHandler)
|
||||
mKeyHandlers.AppendObject(newHandler);
|
||||
nsRefPtr<nsXBLKeyEventHandler> newHandler =
|
||||
new nsXBLKeyEventHandler(eventAtom, phase, type);
|
||||
mKeyHandlers.AppendObject(newHandler);
|
||||
handler = newHandler;
|
||||
}
|
||||
|
||||
@ -1264,7 +1262,6 @@ nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
|
||||
nsIURI* documentURI = aDocument->GetDocumentURI();
|
||||
|
||||
nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
|
||||
NS_ENSURE_TRUE(prototype, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
prototype->mNodeInfo = nodeInfo;
|
||||
|
||||
|
@ -132,8 +132,7 @@ public:
|
||||
nsXBLEventHandler* GetEventHandler()
|
||||
{
|
||||
if (!mHandler) {
|
||||
NS_NewXBLEventHandler(this, mEventName, getter_AddRefs(mHandler));
|
||||
// XXX Need to signal out of memory?
|
||||
mHandler = NS_NewXBLEventHandler(this, mEventName);
|
||||
}
|
||||
|
||||
return mHandler;
|
||||
|
@ -764,12 +764,10 @@ nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(protoBinding->BindingURI()),
|
||||
NS_ERROR_OUT_OF_MEMORY);
|
||||
aDontExtendURIs.AppendElement(protoBinding->BindingURI());
|
||||
nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI();
|
||||
if (altBindingURI) {
|
||||
NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(altBindingURI),
|
||||
NS_ERROR_OUT_OF_MEMORY);
|
||||
aDontExtendURIs.AppendElement(altBindingURI);
|
||||
}
|
||||
|
||||
// Our prototype binding must have all its resources loaded.
|
||||
@ -831,7 +829,6 @@ nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
|
||||
if (!aPeekOnly) {
|
||||
// Make a new binding
|
||||
nsXBLBinding *newBinding = new nsXBLBinding(protoBinding);
|
||||
NS_ENSURE_TRUE(newBinding, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (baseBinding) {
|
||||
if (!baseProto) {
|
||||
@ -1108,7 +1105,6 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun
|
||||
// We can be asynchronous
|
||||
nsXBLStreamListener* xblListener =
|
||||
new nsXBLStreamListener(aBoundDocument, xblSink, doc);
|
||||
NS_ENSURE_TRUE(xblListener,NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Add ourselves to the list of loading docs.
|
||||
nsBindingManager *bindingManager;
|
||||
|
@ -214,9 +214,6 @@ BuildHandlerChain(nsIContent* aContent, nsXBLPrototypeHandler** aResult)
|
||||
|
||||
nsXBLPrototypeHandler* handler = new nsXBLPrototypeHandler(key);
|
||||
|
||||
if (!handler)
|
||||
return;
|
||||
|
||||
handler->SetNextHandler(*aResult);
|
||||
*aResult = handler;
|
||||
}
|
||||
|
@ -157,6 +157,7 @@ public:
|
||||
int aArg = 0) {}
|
||||
|
||||
GeckoContentController() {}
|
||||
virtual void Destroy() {}
|
||||
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
|
@ -3,15 +3,58 @@
|
||||
* 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 "mozilla/layers/ChromeProcessController.h"
|
||||
#include "ChromeProcessController.h"
|
||||
|
||||
#include "MainThreadUtils.h" // for NS_IsMainThread()
|
||||
#include "base/message_loop.h" // for MessageLoop
|
||||
#include "mozilla/layers/CompositorParent.h"
|
||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsView.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
ChromeProcessController::ChromeProcessController(nsIWidget* aWidget)
|
||||
: mWidget(aWidget)
|
||||
, mUILoop(MessageLoop::current())
|
||||
{
|
||||
// Otherwise we're initializing mUILoop incorrectly.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mUILoop->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &ChromeProcessController::InitializeRoot));
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::InitializeRoot()
|
||||
{
|
||||
// Create a view-id and set a zero-margin displayport for the root element
|
||||
// of the root document in the chrome process. This ensures that the scroll
|
||||
// frame for this element gets an APZC, which in turn ensures that all content
|
||||
// in the chrome processes is covered by an APZC.
|
||||
// The displayport is zero-margin because this element is generally not
|
||||
// actually scrollable (if it is, APZC will set proper margins when it's
|
||||
// scrolled).
|
||||
nsView* view = nsView::GetViewFor(mWidget);
|
||||
MOZ_ASSERT(view);
|
||||
nsIPresShell* presShell = view->GetPresShell();
|
||||
MOZ_ASSERT(presShell);
|
||||
MOZ_ASSERT(presShell->GetDocument());
|
||||
nsIContent* content = presShell->GetDocument()->GetDocumentElement();
|
||||
MOZ_ASSERT(content);
|
||||
uint32_t presShellId;
|
||||
FrameMetrics::ViewID viewId;
|
||||
if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(content, &presShellId, &viewId)) {
|
||||
nsLayoutUtils::SetDisplayPortMargins(content, presShell, ScreenMargin(), 0,
|
||||
nsLayoutUtils::RepaintMode::DoNotRepaint);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
|
||||
{
|
||||
@ -40,3 +83,17 @@ ChromeProcessController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aSc
|
||||
{
|
||||
APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::Destroy()
|
||||
{
|
||||
if (MessageLoop::current() != mUILoop) {
|
||||
mUILoop->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &ChromeProcessController::Destroy));
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(MessageLoop::current() == mUILoop);
|
||||
mWidget = nullptr;
|
||||
}
|
||||
|
@ -7,6 +7,11 @@
|
||||
#define mozilla_layers_ChromeProcessController_h
|
||||
|
||||
#include "mozilla/layers/GeckoContentController.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIWidget;
|
||||
|
||||
class MessageLoop;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -21,6 +26,9 @@ class ChromeProcessController : public mozilla::layers::GeckoContentController
|
||||
typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
|
||||
|
||||
public:
|
||||
explicit ChromeProcessController(nsIWidget* aWidget);
|
||||
virtual void Destroy() MOZ_OVERRIDE;
|
||||
|
||||
// GeckoContentController interface
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
|
||||
virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE;
|
||||
@ -38,6 +46,12 @@ public:
|
||||
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE {}
|
||||
virtual void SendAsyncScrollDOMEvent(bool aIsRoot, const mozilla::CSSRect &aContentRect,
|
||||
const mozilla::CSSSize &aScrollableSize) MOZ_OVERRIDE {}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
MessageLoop* mUILoop;
|
||||
|
||||
void InitializeRoot();
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -88,6 +88,13 @@ CompositorParent::LayerTreeState::LayerTreeState()
|
||||
{
|
||||
}
|
||||
|
||||
CompositorParent::LayerTreeState::~LayerTreeState()
|
||||
{
|
||||
if (mController) {
|
||||
mController->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
typedef map<uint64_t, CompositorParent::LayerTreeState> LayerTreeMap;
|
||||
static LayerTreeMap sIndirectLayerTrees;
|
||||
static StaticAutoPtr<mozilla::Monitor> sIndirectLayerTreesLock;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user