mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
56a152e92c
@ -1,3 +1 @@
|
||||
41.0a1
|
||||
# Version to display in the about box:
|
||||
41.0a1
|
||||
|
1
browser/config/version_about.txt
Normal file
1
browser/config/version_about.txt
Normal file
@ -0,0 +1 @@
|
||||
41.0a1
|
@ -127,19 +127,20 @@ bool isInIgnoredNamespaceForImplicitCtor(const Decl *decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return name == "std" || // standard C++ lib
|
||||
name == "__gnu_cxx" || // gnu C++ lib
|
||||
name == "boost" || // boost
|
||||
name == "webrtc" || // upstream webrtc
|
||||
name == "icu_52" || // icu
|
||||
name == "google" || // protobuf
|
||||
name == "google_breakpad" || // breakpad
|
||||
name == "soundtouch" || // libsoundtouch
|
||||
name == "stagefright" || // libstagefright
|
||||
name == "MacFileUtilities" || // MacFileUtilities
|
||||
name == "dwarf2reader" || // dwarf2reader
|
||||
name == "arm_ex_to_module" || // arm_ex_to_module
|
||||
name == "testing"; // gtest
|
||||
|
||||
return name == "std" || // standard C++ lib
|
||||
name == "__gnu_cxx" || // gnu C++ lib
|
||||
name == "boost" || // boost
|
||||
name == "webrtc" || // upstream webrtc
|
||||
name.substr(0, 4) == "icu_" || // icu
|
||||
name == "google" || // protobuf
|
||||
name == "google_breakpad" || // breakpad
|
||||
name == "soundtouch" || // libsoundtouch
|
||||
name == "stagefright" || // libstagefright
|
||||
name == "MacFileUtilities" || // MacFileUtilities
|
||||
name == "dwarf2reader" || // dwarf2reader
|
||||
name == "arm_ex_to_module" || // arm_ex_to_module
|
||||
name == "testing"; // gtest
|
||||
}
|
||||
|
||||
bool isInIgnoredNamespaceForImplicitConversion(const Decl *decl) {
|
||||
|
@ -1958,8 +1958,8 @@ MOZILLA_UAVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsr
|
||||
MOZILLA_SYMBOLVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --symbolversion`
|
||||
|
||||
dnl Get version of various core apps from the version files.
|
||||
FIREFOX_VERSION=`cat $_topsrcdir/browser/config/version.txt|head -1`
|
||||
FIREFOX_VERSION_ABOUT=`cat $_topsrcdir/browser/config/version.txt|tail -1`
|
||||
FIREFOX_VERSION=`cat $_topsrcdir/browser/config/version.txt`
|
||||
FIREFOX_VERSION_ABOUT=`cat $_topsrcdir/browser/config/version_about.txt`
|
||||
|
||||
if test -z "$FIREFOX_VERSION"; then
|
||||
AC_MSG_ERROR([FIREFOX_VERSION is unexpectedly blank.])
|
||||
|
@ -203,6 +203,7 @@ this.DOMApplicationRegistry = {
|
||||
dirKey: DIRECTORY_NAME,
|
||||
|
||||
init: function() {
|
||||
// Keep the messages in sync with the lazy-loading in browser.js (bug 1171013).
|
||||
this.messages = ["Webapps:Install",
|
||||
"Webapps:Uninstall",
|
||||
"Webapps:GetSelf",
|
||||
|
@ -531,13 +531,13 @@ File::GetLastModified(ErrorResult& aRv)
|
||||
}
|
||||
|
||||
void
|
||||
File::GetMozFullPath(nsAString& aFilename, ErrorResult& aRv)
|
||||
File::GetMozFullPath(nsAString& aFilename, ErrorResult& aRv) const
|
||||
{
|
||||
mImpl->GetMozFullPath(aFilename, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
File::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv)
|
||||
File::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const
|
||||
{
|
||||
mImpl->GetMozFullPathInternal(aFileName, aRv);
|
||||
}
|
||||
@ -735,7 +735,7 @@ BlobImplBase::GetPath(nsAString& aPath, ErrorResult& aRv)
|
||||
}
|
||||
|
||||
void
|
||||
BlobImplBase::GetMozFullPath(nsAString& aFileName, ErrorResult& aRv)
|
||||
BlobImplBase::GetMozFullPath(nsAString& aFileName, ErrorResult& aRv) const
|
||||
{
|
||||
NS_ASSERTION(mIsFile, "Should only be called on files");
|
||||
|
||||
@ -759,7 +759,7 @@ BlobImplBase::GetMozFullPath(nsAString& aFileName, ErrorResult& aRv)
|
||||
}
|
||||
|
||||
void
|
||||
BlobImplBase::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv)
|
||||
BlobImplBase::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const
|
||||
{
|
||||
if (!mIsFile) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
@ -950,7 +950,7 @@ BlobImplFile::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
}
|
||||
|
||||
void
|
||||
BlobImplFile::GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv)
|
||||
BlobImplFile::GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv) const
|
||||
{
|
||||
NS_ASSERTION(mIsFile, "Should only be called on files");
|
||||
aRv = mFile->GetPath(aFilename);
|
||||
|
@ -261,9 +261,9 @@ public:
|
||||
|
||||
void GetPath(nsAString& aName, ErrorResult& aRv);
|
||||
|
||||
void GetMozFullPath(nsAString& aFilename, ErrorResult& aRv);
|
||||
void GetMozFullPath(nsAString& aFilename, ErrorResult& aRv) const;
|
||||
|
||||
void GetMozFullPathInternal(nsAString& aName, ErrorResult& aRv);
|
||||
void GetMozFullPathInternal(nsAString& aName, ErrorResult& aRv) const;
|
||||
|
||||
protected:
|
||||
virtual bool HasFileInterface() const override { return true; }
|
||||
@ -293,9 +293,9 @@ public:
|
||||
|
||||
virtual void SetLastModified(int64_t aLastModified) = 0;
|
||||
|
||||
virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) = 0;
|
||||
virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) const = 0;
|
||||
|
||||
virtual void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) = 0;
|
||||
virtual void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const = 0;
|
||||
|
||||
virtual uint64_t GetSize(ErrorResult& aRv) = 0;
|
||||
|
||||
@ -434,10 +434,10 @@ public:
|
||||
|
||||
virtual void SetLastModified(int64_t aLastModified) override;
|
||||
|
||||
virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) override;
|
||||
virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) const override;
|
||||
|
||||
virtual void GetMozFullPathInternal(nsAString& aFileName,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual uint64_t GetSize(ErrorResult& aRv) override
|
||||
{
|
||||
@ -822,7 +822,7 @@ public:
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) override;
|
||||
virtual void SetLastModified(int64_t aLastModified) override;
|
||||
virtual void GetMozFullPathInternal(nsAString& aFullPath,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
virtual void GetInternalStream(nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
|
@ -240,7 +240,7 @@ MultipartBlobImpl::SetLengthAndModifiedDate()
|
||||
|
||||
void
|
||||
MultipartBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
|
||||
ErrorResult& aRv)
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
if (!mIsFromNsIFile || mBlobImpls.Length() == 0) {
|
||||
BlobImplBase::GetMozFullPathInternal(aFilename, aRv);
|
||||
|
@ -101,7 +101,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void GetMozFullPathInternal(nsAString& aFullPath,
|
||||
ErrorResult& aRv) override;
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
SetMutable(bool aMutable) override;
|
||||
|
@ -313,34 +313,7 @@ AutoJSAPI::~AutoJSAPI()
|
||||
if (mOwnErrorReporting) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "See corresponding assertion in TakeOwnershipOfErrorReporting()");
|
||||
|
||||
if (HasException()) {
|
||||
|
||||
// AutoJSAPI uses a JSAutoNullableCompartment, and may be in a null
|
||||
// compartment when the destructor is called. However, the JS engine
|
||||
// requires us to be in a compartment when we fetch the pending exception.
|
||||
// In this case, we enter the privileged junk scope and don't dispatch any
|
||||
// error events.
|
||||
JS::Rooted<JSObject*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx()));
|
||||
if (!errorGlobal)
|
||||
errorGlobal = xpc::PrivilegedJunkScope();
|
||||
JSAutoCompartment ac(cx(), errorGlobal);
|
||||
nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
|
||||
JS::Rooted<JS::Value> exn(cx());
|
||||
js::ErrorReport jsReport(cx());
|
||||
if (StealException(&exn) && jsReport.init(cx(), exn)) {
|
||||
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
xpcReport->Init(jsReport.report(), jsReport.message(),
|
||||
nsContentUtils::IsCallerChrome(),
|
||||
win ? win->WindowID() : 0);
|
||||
if (win) {
|
||||
DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
|
||||
} else {
|
||||
xpcReport->LogToConsole();
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
|
||||
}
|
||||
}
|
||||
ReportException();
|
||||
|
||||
// We need to do this _after_ processing the existing exception, because the
|
||||
// JS engine can throw while doing that, and uses this bit to determine what
|
||||
@ -508,6 +481,41 @@ AutoJSAPI::TakeOwnershipOfErrorReporting()
|
||||
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
|
||||
}
|
||||
|
||||
void
|
||||
AutoJSAPI::ReportException()
|
||||
{
|
||||
MOZ_ASSERT(OwnsErrorReporting(), "This is not our exception to report!");
|
||||
if (!HasException()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// AutoJSAPI uses a JSAutoNullableCompartment, and may be in a null
|
||||
// compartment when the destructor is called. However, the JS engine
|
||||
// requires us to be in a compartment when we fetch the pending exception.
|
||||
// In this case, we enter the privileged junk scope and don't dispatch any
|
||||
// error events.
|
||||
JS::Rooted<JSObject*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx()));
|
||||
if (!errorGlobal)
|
||||
errorGlobal = xpc::PrivilegedJunkScope();
|
||||
JSAutoCompartment ac(cx(), errorGlobal);
|
||||
nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
|
||||
JS::Rooted<JS::Value> exn(cx());
|
||||
js::ErrorReport jsReport(cx());
|
||||
if (StealException(&exn) && jsReport.init(cx(), exn)) {
|
||||
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
xpcReport->Init(jsReport.report(), jsReport.message(),
|
||||
nsContentUtils::IsCallerChrome(),
|
||||
win ? win->WindowID() : 0);
|
||||
if (win) {
|
||||
DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
|
||||
} else {
|
||||
xpcReport->LogToConsole();
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
|
||||
{
|
||||
|
@ -274,6 +274,9 @@ public:
|
||||
// while keeping the old behavior as the default.
|
||||
void TakeOwnershipOfErrorReporting();
|
||||
bool OwnsErrorReporting() { return mOwnErrorReporting; }
|
||||
// If HasException, report it. Otherwise, a no-op. This must be
|
||||
// called only if OwnsErrorReporting().
|
||||
void ReportException();
|
||||
|
||||
bool HasException() const {
|
||||
MOZ_ASSERT(CxPusherIsStackTop());
|
||||
|
@ -68,7 +68,7 @@ nsContentPolicy::~nsContentPolicy()
|
||||
inline nsresult
|
||||
nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||
SCPMethod simplePolicyMethod,
|
||||
uint32_t contentType,
|
||||
nsContentPolicyType contentType,
|
||||
nsIURI *contentLocation,
|
||||
nsIURI *requestingLocation,
|
||||
nsISupports *requestingContext,
|
||||
@ -110,6 +110,9 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||
}
|
||||
}
|
||||
|
||||
nsContentPolicyType externalType =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternal(contentType);
|
||||
|
||||
/*
|
||||
* Enumerate mPolicies and ask each of them, taking the logical AND of
|
||||
* their permissions.
|
||||
@ -120,7 +123,7 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||
int32_t count = entries.Count();
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
/* check the appropriate policy */
|
||||
rv = (entries[i]->*policyMethod)(contentType, contentLocation,
|
||||
rv = (entries[i]->*policyMethod)(externalType, contentLocation,
|
||||
requestingLocation, requestingContext,
|
||||
mimeType, extra, requestPrincipal,
|
||||
decision);
|
||||
@ -166,7 +169,7 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||
count = simpleEntries.Count();
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
/* check the appropriate policy */
|
||||
rv = (simpleEntries[i]->*simplePolicyMethod)(contentType, contentLocation,
|
||||
rv = (simpleEntries[i]->*simplePolicyMethod)(externalType, contentLocation,
|
||||
requestingLocation,
|
||||
topFrameElement, isTopLevel,
|
||||
mimeType, extra, requestPrincipal,
|
||||
|
@ -49,7 +49,7 @@ class nsContentPolicy : public nsIContentPolicy
|
||||
//Helper method that applies policyMethod across all policies in mPolicies
|
||||
// with the given parameters
|
||||
nsresult CheckPolicy(CPMethod policyMethod, SCPMethod simplePolicyMethod,
|
||||
uint32_t contentType,
|
||||
nsContentPolicyType contentType,
|
||||
nsIURI *aURI, nsIURI *origURI,
|
||||
nsISupports *requestingContext,
|
||||
const nsACString &mimeGuess, nsISupports *extra,
|
||||
|
@ -92,28 +92,38 @@ inline const char *
|
||||
NS_CP_ContentTypeName(uint32_t contentType)
|
||||
{
|
||||
switch (contentType) {
|
||||
CASE_RETURN( TYPE_OTHER );
|
||||
CASE_RETURN( TYPE_SCRIPT );
|
||||
CASE_RETURN( TYPE_IMAGE );
|
||||
CASE_RETURN( TYPE_STYLESHEET );
|
||||
CASE_RETURN( TYPE_OBJECT );
|
||||
CASE_RETURN( TYPE_DOCUMENT );
|
||||
CASE_RETURN( TYPE_SUBDOCUMENT );
|
||||
CASE_RETURN( TYPE_REFRESH );
|
||||
CASE_RETURN( TYPE_XBL );
|
||||
CASE_RETURN( TYPE_PING );
|
||||
CASE_RETURN( TYPE_XMLHTTPREQUEST );
|
||||
CASE_RETURN( TYPE_OBJECT_SUBREQUEST );
|
||||
CASE_RETURN( TYPE_DTD );
|
||||
CASE_RETURN( TYPE_FONT );
|
||||
CASE_RETURN( TYPE_MEDIA );
|
||||
CASE_RETURN( TYPE_WEBSOCKET );
|
||||
CASE_RETURN( TYPE_CSP_REPORT );
|
||||
CASE_RETURN( TYPE_XSLT );
|
||||
CASE_RETURN( TYPE_BEACON );
|
||||
CASE_RETURN( TYPE_FETCH );
|
||||
CASE_RETURN( TYPE_IMAGESET );
|
||||
CASE_RETURN( TYPE_WEB_MANIFEST );
|
||||
CASE_RETURN( TYPE_OTHER );
|
||||
CASE_RETURN( TYPE_SCRIPT );
|
||||
CASE_RETURN( TYPE_IMAGE );
|
||||
CASE_RETURN( TYPE_STYLESHEET );
|
||||
CASE_RETURN( TYPE_OBJECT );
|
||||
CASE_RETURN( TYPE_DOCUMENT );
|
||||
CASE_RETURN( TYPE_SUBDOCUMENT );
|
||||
CASE_RETURN( TYPE_REFRESH );
|
||||
CASE_RETURN( TYPE_XBL );
|
||||
CASE_RETURN( TYPE_PING );
|
||||
CASE_RETURN( TYPE_XMLHTTPREQUEST );
|
||||
CASE_RETURN( TYPE_OBJECT_SUBREQUEST );
|
||||
CASE_RETURN( TYPE_DTD );
|
||||
CASE_RETURN( TYPE_FONT );
|
||||
CASE_RETURN( TYPE_MEDIA );
|
||||
CASE_RETURN( TYPE_WEBSOCKET );
|
||||
CASE_RETURN( TYPE_CSP_REPORT );
|
||||
CASE_RETURN( TYPE_XSLT );
|
||||
CASE_RETURN( TYPE_BEACON );
|
||||
CASE_RETURN( TYPE_FETCH );
|
||||
CASE_RETURN( TYPE_IMAGESET );
|
||||
CASE_RETURN( TYPE_WEB_MANIFEST );
|
||||
CASE_RETURN( TYPE_INTERNAL_SCRIPT );
|
||||
CASE_RETURN( TYPE_INTERNAL_WORKER );
|
||||
CASE_RETURN( TYPE_INTERNAL_SHARED_WORKER );
|
||||
CASE_RETURN( TYPE_INTERNAL_EMBED );
|
||||
CASE_RETURN( TYPE_INTERNAL_OBJECT );
|
||||
CASE_RETURN( TYPE_INTERNAL_FRAME );
|
||||
CASE_RETURN( TYPE_INTERNAL_IFRAME );
|
||||
CASE_RETURN( TYPE_INTERNAL_AUDIO );
|
||||
CASE_RETURN( TYPE_INTERNAL_VIDEO );
|
||||
CASE_RETURN( TYPE_INTERNAL_TRACK );
|
||||
default:
|
||||
return "<Unknown Type>";
|
||||
}
|
||||
|
@ -7812,3 +7812,31 @@ nsContentUtils::GetWindowRoot(nsIDocument* aDoc)
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsContentPolicyType
|
||||
nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
|
||||
return nsIContentPolicy::TYPE_SCRIPT;
|
||||
|
||||
case nsIContentPolicy::TYPE_INTERNAL_EMBED:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_OBJECT:
|
||||
return nsIContentPolicy::TYPE_OBJECT;
|
||||
|
||||
case nsIContentPolicy::TYPE_INTERNAL_FRAME:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_IFRAME:
|
||||
return nsIContentPolicy::TYPE_SUBDOCUMENT;
|
||||
|
||||
case nsIContentPolicy::TYPE_INTERNAL_AUDIO:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_VIDEO:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_TRACK:
|
||||
return nsIContentPolicy::TYPE_MEDIA;
|
||||
|
||||
default:
|
||||
return aType;
|
||||
}
|
||||
}
|
||||
|
@ -916,6 +916,11 @@ public:
|
||||
*/
|
||||
static nsIContentPolicy *GetContentPolicy();
|
||||
|
||||
/**
|
||||
* Map internal content policy types to external ones.
|
||||
*/
|
||||
static nsContentPolicyType InternalContentPolicyTypeToExternal(nsContentPolicyType aType);
|
||||
|
||||
/**
|
||||
* Quick helper to determine whether there are any mutation listeners
|
||||
* of a given type that apply to this content or any of its ancestors.
|
||||
|
@ -43,6 +43,9 @@ nsDataDocumentContentPolicy::ShouldLoad(uint32_t aContentType,
|
||||
nsIPrincipal *aRequestPrincipal,
|
||||
int16_t *aDecision)
|
||||
{
|
||||
MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
|
||||
"We should only see external content policy types here.");
|
||||
|
||||
*aDecision = nsIContentPolicy::ACCEPT;
|
||||
// Look for the document. In most cases, aRequestingContext is a node.
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
|
@ -12463,6 +12463,7 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
|
||||
// New script entry point required, due to the "Create a script" sub-step of
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
|
||||
AutoEntryScript entryScript(this, reason, true, aScx->GetNativeContext());
|
||||
entryScript.TakeOwnershipOfErrorReporting();
|
||||
JS::CompileOptions options(entryScript.cx());
|
||||
options.setFileAndLine(filename, lineNo)
|
||||
.setVersion(JSVERSION_DEFAULT);
|
||||
|
@ -20,7 +20,7 @@ interface nsIPrincipal;
|
||||
* by launching a dialog to prompt the user for something).
|
||||
*/
|
||||
|
||||
[scriptable,uuid(cb978019-0c5b-4067-abb6-c914461208c1)]
|
||||
[scriptable,uuid(b545899e-42bd-434c-8fec-a0af3448ea15)]
|
||||
interface nsIContentPolicy : nsIContentPolicyBase
|
||||
{
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ typedef unsigned long nsContentPolicyType;
|
||||
* by launching a dialog to prompt the user for something).
|
||||
*/
|
||||
|
||||
[scriptable,uuid(4f2655e8-6365-4583-8510-732bff2186c5)]
|
||||
[scriptable,uuid(11b8d725-7c2b-429e-b51f-8b5b542d5009)]
|
||||
interface nsIContentPolicyBase : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -57,6 +57,10 @@ interface nsIContentPolicyBase : nsISupports
|
||||
* Implementations of nsIContentPolicy should treat this the same way they
|
||||
* treat unknown types, because existing users of TYPE_OTHER may be converted
|
||||
* to use new content types.
|
||||
*
|
||||
* Note that the TYPE_INTERNAL_* constants are never passed to content
|
||||
* policy implementations. They are mapped to other TYPE_* constants, and
|
||||
* are only intended for internal usage inside Gecko.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_OTHER = 1;
|
||||
|
||||
@ -177,6 +181,82 @@ interface nsIContentPolicyBase : nsISupports
|
||||
*/
|
||||
const nsContentPolicyType TYPE_WEB_MANIFEST = 22;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for scripts loaded through script
|
||||
* elements.
|
||||
*
|
||||
* This will be mapped to TYPE_SCRIPT before being passed to content policy
|
||||
* implementations.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_SCRIPT = 23;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for scripts loaded through a dedicated
|
||||
* worker.
|
||||
*
|
||||
* This will be mapped to TYPE_SCRIPT before being passed to content policy
|
||||
* implementations.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_WORKER = 24;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for scripts loaded through a shared
|
||||
* worker.
|
||||
*
|
||||
* This will be mapped to TYPE_SCRIPT before being passed to content policy
|
||||
* implementations.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_SHARED_WORKER = 25;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for content loaded from embed elements.
|
||||
*
|
||||
* This will be mapped to TYPE_OBJECT.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_EMBED = 26;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for content loaded from object elements.
|
||||
*
|
||||
* This will be mapped to TYPE_OBJECT.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_OBJECT = 27;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for content loaded from frame elements.
|
||||
*
|
||||
* This will be mapped to TYPE_SUBDOCUMENT.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_FRAME = 28;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for content loaded from iframe elements.
|
||||
*
|
||||
* This will be mapped to TYPE_SUBDOCUMENT.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_IFRAME = 29;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for content loaded from audio elements.
|
||||
*
|
||||
* This will be mapped to TYPE_MEDIA.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_AUDIO = 30;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for content loaded from video elements.
|
||||
*
|
||||
* This will be mapped to TYPE_MEDIA.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_VIDEO = 31;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for content loaded from track elements.
|
||||
*
|
||||
* This will be mapped to TYPE_MEDIA.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_TRACK = 32;
|
||||
|
||||
/* When adding new content types, please update nsContentBlocker,
|
||||
* NS_CP_ContentTypeName, nsCSPContext, all nsIContentPolicy
|
||||
* implementations, and other things that are not listed here that are
|
||||
|
@ -28,7 +28,7 @@ interface nsIDOMElement;
|
||||
* by launching a dialog to prompt the user for something).
|
||||
*/
|
||||
|
||||
[scriptable,uuid(704b4b8e-2287-498a-9c0a-d1bde547a2d4)]
|
||||
[scriptable,uuid(b181c97c-9d67-4da1-95a0-e0a202e1807c)]
|
||||
interface nsISimpleContentPolicy : nsIContentPolicyBase
|
||||
{
|
||||
/**
|
||||
|
@ -98,41 +98,6 @@ nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
|
||||
return innerWindowID;
|
||||
}
|
||||
|
||||
void
|
||||
nsJSUtils::ReportPendingException(JSContext *aContext)
|
||||
{
|
||||
if (JS_IsExceptionPending(aContext)) {
|
||||
bool saved = JS_SaveFrameChain(aContext);
|
||||
{
|
||||
// JS_SaveFrameChain set the compartment of aContext to null, so we need
|
||||
// to enter a compartment. The question is, which one? We don't want to
|
||||
// enter the original compartment of aContext (or the compartment of the
|
||||
// current exception on aContext, for that matter) because when we
|
||||
// JS_ReportPendingException the JS engine can try to duck-type the
|
||||
// exception and produce a JSErrorReport. It will then pass that
|
||||
// JSErrorReport to the error reporter on aContext, which might expose
|
||||
// information from it to script via onerror handlers. So it's very
|
||||
// important that the duck typing happen in the same compartment as the
|
||||
// onerror handler. In practice, that's the compartment of the window (or
|
||||
// otherwise default global) of aContext, so use that here.
|
||||
nsIScriptContext* scx = GetScriptContextFromJSContext(aContext);
|
||||
JS::Rooted<JSObject*> scope(aContext);
|
||||
scope = scx ? scx->GetWindowProxy() : nullptr;
|
||||
if (!scope) {
|
||||
// The SafeJSContext has no default object associated with it.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aContext == nsContentUtils::GetSafeJSContext());
|
||||
scope = xpc::UnprivilegedJunkScope(); // Usage approved by bholley
|
||||
}
|
||||
JSAutoCompartment ac(aContext, scope);
|
||||
JS_ReportPendingException(aContext);
|
||||
}
|
||||
if (saved) {
|
||||
JS_RestoreFrameChain(aContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJSUtils::CompileFunction(AutoJSAPI& jsapi,
|
||||
JS::AutoObjectVector& aScopeChain,
|
||||
@ -199,12 +164,11 @@ nsJSUtils::EvaluateString(JSContext* aCx,
|
||||
PROFILER_LABEL("nsJSUtils", "EvaluateString",
|
||||
js::ProfileEntry::Category::JS);
|
||||
|
||||
MOZ_ASSERT(JS::ContextOptionsRef(aCx).autoJSAPIOwnsErrorReporting(),
|
||||
"Caller must own error reporting");
|
||||
MOZ_ASSERT_IF(aCompileOptions.versionSet,
|
||||
aCompileOptions.version != JSVERSION_UNKNOWN);
|
||||
MOZ_ASSERT_IF(aEvaluateOptions.coerceToString, !aCompileOptions.noScriptRval);
|
||||
MOZ_ASSERT_IF(!aEvaluateOptions.reportUncaught, !aCompileOptions.noScriptRval);
|
||||
// Note that the above assert means that if aCompileOptions.noScriptRval then
|
||||
// also aEvaluateOptions.reportUncaught.
|
||||
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
|
||||
MOZ_ASSERT(aSrcBuf.get());
|
||||
MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aEvaluationGlobal) ==
|
||||
@ -225,13 +189,6 @@ nsJSUtils::EvaluateString(JSContext* aCx,
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
NS_ENSURE_TRUE(ssm->ScriptAllowed(aEvaluationGlobal), NS_OK);
|
||||
|
||||
mozilla::Maybe<AutoDontReportUncaught> dontReport;
|
||||
if (!aEvaluateOptions.reportUncaught) {
|
||||
// We need to prevent AutoLastFrameCheck from reporting and clearing
|
||||
// any pending exceptions.
|
||||
dontReport.emplace(aCx);
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
// Scope the JSAutoCompartment so that we can later wrap the return value
|
||||
// into the caller's cx.
|
||||
@ -275,24 +232,14 @@ nsJSUtils::EvaluateString(JSContext* aCx,
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
if (aEvaluateOptions.reportUncaught) {
|
||||
ReportPendingException(aCx);
|
||||
if (!aCompileOptions.noScriptRval) {
|
||||
aRetValue.setUndefined();
|
||||
}
|
||||
} else {
|
||||
rv = JS_IsExceptionPending(aCx) ? NS_ERROR_FAILURE
|
||||
: NS_ERROR_OUT_OF_MEMORY;
|
||||
JS::Rooted<JS::Value> exn(aCx);
|
||||
JS_GetPendingException(aCx, &exn);
|
||||
MOZ_ASSERT(!aCompileOptions.noScriptRval); // we asserted this on entry
|
||||
aRetValue.set(exn);
|
||||
JS_ClearPendingException(aCx);
|
||||
rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW;
|
||||
if (!aCompileOptions.noScriptRval) {
|
||||
aRetValue.setUndefined();
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap the return value into whatever compartment aCx was in.
|
||||
if (!aCompileOptions.noScriptRval) {
|
||||
if (ok && !aCompileOptions.noScriptRval) {
|
||||
if (!JS_WrapValue(aCx, aRetValue)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -53,13 +53,6 @@ public:
|
||||
*/
|
||||
static uint64_t GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext);
|
||||
|
||||
/**
|
||||
* Report a pending exception on aContext, if any. Note that this
|
||||
* can be called when the context has a JS stack. If that's the
|
||||
* case, the stack will be set aside before reporting the exception.
|
||||
*/
|
||||
static void ReportPendingException(JSContext *aContext);
|
||||
|
||||
static nsresult CompileFunction(mozilla::dom::AutoJSAPI& jsapi,
|
||||
JS::AutoObjectVector& aScopeChain,
|
||||
JS::CompileOptions& aOptions,
|
||||
@ -71,12 +64,10 @@ public:
|
||||
|
||||
struct MOZ_STACK_CLASS EvaluateOptions {
|
||||
bool coerceToString;
|
||||
bool reportUncaught;
|
||||
JS::AutoObjectVector scopeChain;
|
||||
|
||||
explicit EvaluateOptions(JSContext* cx)
|
||||
: coerceToString(false)
|
||||
, reportUncaught(true)
|
||||
, scopeChain(cx)
|
||||
{}
|
||||
|
||||
@ -84,16 +75,13 @@ public:
|
||||
coerceToString = aCoerce;
|
||||
return *this;
|
||||
}
|
||||
|
||||
EvaluateOptions& setReportUncaught(bool aReport) {
|
||||
reportUncaught = aReport;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// aEvaluationGlobal is the global to evaluate in. The return value
|
||||
// will then be wrapped back into the compartment aCx is in when
|
||||
// this function is called.
|
||||
// this function is called. For all the EvaluateString overloads,
|
||||
// the JSContext must come from an AutoJSAPI that has had
|
||||
// TakeOwnershipOfErrorReporting() called on it.
|
||||
static nsresult EvaluateString(JSContext* aCx,
|
||||
const nsAString& aScript,
|
||||
JS::Handle<JSObject*> aEvaluationGlobal,
|
||||
|
@ -1120,6 +1120,7 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
|
||||
AutoEntryScript entryScript(globalObject, "<script> element", true,
|
||||
context->GetNativeContext());
|
||||
entryScript.TakeOwnershipOfErrorReporting();
|
||||
JS::Rooted<JSObject*> global(entryScript.cx(),
|
||||
globalObject->GetGlobalJSObject());
|
||||
|
||||
|
@ -34,8 +34,6 @@
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/DOMErrorBinding.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/DOMExceptionBinding.h"
|
||||
#include "mozilla/dom/ElementBinding.h"
|
||||
#include "mozilla/dom/HTMLObjectElement.h"
|
||||
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
||||
@ -284,26 +282,16 @@ ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx)
|
||||
MOZ_ASSERT(!mMightHaveUnreportedJSException,
|
||||
"Why didn't you tell us you planned to handle JS exceptions?");
|
||||
|
||||
dom::DOMException* domException;
|
||||
nsresult rv =
|
||||
UNWRAP_OBJECT(DOMException, &mJSException.toObject(), domException);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Check for a DOMError, since we convert that into an Error in the content
|
||||
// compartment. We can probably remove that now; see bug 1174954.
|
||||
dom::DOMError* domError;
|
||||
nsresult rv = UNWRAP_OBJECT(DOMError, &mJSException.toObject(), domError);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Just report it.
|
||||
ReportJSException(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
dom::DOMError* domError;
|
||||
rv = UNWRAP_OBJECT(DOMError, &mJSException.toObject(), domError);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Unwrapping really shouldn't fail here: if mExceptionHandling is set to
|
||||
// eRethrowContentExceptions then the CallSetup destructor only stores an
|
||||
// exception if it unwraps to DOMError or DOMException. If we reach this
|
||||
// then either mExceptionHandling wasn't set to eRethrowContentExceptions
|
||||
// and we shouldn't be calling ReportJSExceptionFromJSImplementation or
|
||||
// something went really wrong.
|
||||
NS_RUNTIMEABORT("We stored a non-DOMError exception!");
|
||||
}
|
||||
|
||||
nsString message;
|
||||
domError->GetMessage(message);
|
||||
|
||||
|
@ -6,10 +6,6 @@
|
||||
|
||||
#include "mozilla/dom/CallbackObject.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/DOMErrorBinding.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/DOMExceptionBinding.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIXPConnect.h"
|
||||
@ -224,8 +220,7 @@ CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aExcepti
|
||||
MOZ_ASSERT(mCompartment);
|
||||
|
||||
// Now we only want to throw an exception to the caller if the object that was
|
||||
// thrown is a DOMError or DOMException object in the caller compartment
|
||||
// (which we stored in mCompartment).
|
||||
// thrown is in the caller compartment (which we stored in mCompartment).
|
||||
|
||||
if (!aException.isObject()) {
|
||||
return false;
|
||||
@ -233,14 +228,7 @@ CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aExcepti
|
||||
|
||||
JS::Rooted<JSObject*> obj(mCx, &aException.toObject());
|
||||
obj = js::UncheckedUnwrap(obj, /* stopAtOuter = */ false);
|
||||
if (js::GetObjectCompartment(obj) != mCompartment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DOMError* domError;
|
||||
DOMException* domException;
|
||||
return NS_SUCCEEDED(UNWRAP_OBJECT(DOMError, obj, domError)) ||
|
||||
NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException));
|
||||
return js::GetObjectCompartment(obj) == mCompartment;
|
||||
}
|
||||
|
||||
CallbackObject::CallSetup::~CallSetup()
|
||||
|
@ -142,9 +142,9 @@ ThrowAndReport(nsPIDOMWindow* aWindow, nsresult aRv, const char* aMessage)
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(aWindow))) {
|
||||
return;
|
||||
}
|
||||
jsapi.TakeOwnershipOfErrorReporting();
|
||||
|
||||
Throw(jsapi.cx(), aRv, aMessage);
|
||||
(void) JS_ReportPendingException(jsapi.cx());
|
||||
}
|
||||
|
||||
already_AddRefed<Exception>
|
||||
|
@ -73,6 +73,22 @@ TestInterfaceJS.prototype = {
|
||||
"NotSupportedError");
|
||||
},
|
||||
|
||||
testThrowTypeError: function() {
|
||||
throw new this._win.TypeError("We are a TypeError");
|
||||
},
|
||||
|
||||
testThrowCallbackError: function(callback) {
|
||||
callback();
|
||||
},
|
||||
|
||||
testThrowXraySelfHosted: function() {
|
||||
this._win.Array.indexOf();
|
||||
},
|
||||
|
||||
testThrowSelfHosted: function() {
|
||||
Array.indexOf();
|
||||
},
|
||||
|
||||
testPromiseWithThrowingChromePromiseInit: function() {
|
||||
return new this._win.Promise(function() {
|
||||
noSuchMethodExistsYo1();
|
||||
|
@ -51,9 +51,86 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
|
||||
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
|
||||
"Should still have the right file name");
|
||||
is(e.lineNumber, 38, "Should still have the right line number");
|
||||
todo_is(e.columnNumber, 7,
|
||||
"No column number support for DOMException yet");
|
||||
todo_isnot(e.columnNumber, 0,
|
||||
"No column number support for DOMException yet");
|
||||
}
|
||||
|
||||
try {
|
||||
t.testThrowTypeError();
|
||||
} catch (e) {
|
||||
ok(e instanceof TypeError, "Should have a TypeError here");
|
||||
ok(!(e instanceof DOMException), "Should not have DOMException here (2)");
|
||||
ok(!("code" in e), "Should not have a 'code' property (2)");
|
||||
is(e.name, "TypeError", "Should be named TypeError");
|
||||
is(e.message, "We are a TypeError",
|
||||
"Should also have the right message (2)");
|
||||
is(e.stack,
|
||||
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:59:7\n",
|
||||
"Exception stack for TypeError should only show our code");
|
||||
is(e.fileName,
|
||||
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
|
||||
"Should still have the right file name for TypeError");
|
||||
is(e.lineNumber, 59, "Should still have the right line number for TypeError");
|
||||
is(e.columnNumber, 7, "Should have the right column number for TypeError");
|
||||
}
|
||||
|
||||
try {
|
||||
t.testThrowCallbackError(function() { Array.indexOf() });
|
||||
} catch (e) {
|
||||
ok(e instanceof TypeError, "Should have a TypeError here (3)");
|
||||
ok(!(e instanceof DOMException), "Should not have DOMException here (3)");
|
||||
ok(!("code" in e), "Should not have a 'code' property (3)");
|
||||
is(e.name, "TypeError", "Should be named TypeError (3)");
|
||||
is(e.message, "missing argument 0 when calling function Array.indexOf",
|
||||
"Should also have the right message (3)");
|
||||
is(e.stack,
|
||||
"doTest/<@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:78:45\n" +
|
||||
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:78:7\n"
|
||||
,
|
||||
"Exception stack for TypeError should only show our code (3)");
|
||||
is(e.fileName,
|
||||
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
|
||||
"Should still have the right file name for TypeError (3)");
|
||||
is(e.lineNumber, 78, "Should still have the right line number for TypeError (3)");
|
||||
is(e.columnNumber, 45, "Should have the right column number for TypeError (3)");
|
||||
}
|
||||
|
||||
try {
|
||||
t.testThrowXraySelfHosted();
|
||||
} catch (e) {
|
||||
ok(!(e instanceof Error), "Should have an Exception here (4)");
|
||||
ok(!(e instanceof DOMException), "Should not have DOMException here (4)");
|
||||
ok(!("code" in e), "Should not have a 'code' property (4)");
|
||||
is(e.name, "NS_ERROR_UNEXPECTED", "Name should be sanitized (4)");
|
||||
is(e.message, "", "Message should be sanitized (5)");
|
||||
is(e.stack,
|
||||
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:99:7\n",
|
||||
"Exception stack for sanitized exception should only show our code (4)");
|
||||
is(e.filename,
|
||||
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
|
||||
"Should still have the right file name for sanitized exception (4)");
|
||||
is(e.lineNumber, 99, "Should still have the right line number for sanitized exception (4)");
|
||||
todo_isnot(e.columnNumber, 0, "Should have the right column number for sanitized exception (4)");
|
||||
}
|
||||
|
||||
try {
|
||||
t.testThrowSelfHosted();
|
||||
} catch (e) {
|
||||
ok(!(e instanceof Error), "Should have an Exception here (5)");
|
||||
ok(!(e instanceof DOMException), "Should not have DOMException here (5)");
|
||||
ok(!("code" in e), "Should not have a 'code' property (5)");
|
||||
is(e.name, "NS_ERROR_UNEXPECTED", "Name should be sanitized (5)");
|
||||
is(e.message, "", "Message should be sanitized (5)");
|
||||
is(e.stack,
|
||||
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:117:7\n",
|
||||
"Exception stack for sanitized exception should only show our code (5)");
|
||||
is(e.filename,
|
||||
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
|
||||
"Should still have the right file name for sanitized exception (5)");
|
||||
is(e.lineNumber, 117, "Should still have the right line number for sanitized exception (5)");
|
||||
todo_isnot(e.columnNumber, 0, "Should have the right column number for sanitized exception (5)");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
2
dom/cache/CacheTypes.ipdlh
vendored
2
dom/cache/CacheTypes.ipdlh
vendored
@ -12,7 +12,6 @@ using HeadersGuardEnum from "mozilla/dom/cache/IPCUtils.h";
|
||||
using RequestCredentials from "mozilla/dom/cache/IPCUtils.h";
|
||||
using RequestMode from "mozilla/dom/cache/IPCUtils.h";
|
||||
using RequestCache from "mozilla/dom/cache/IPCUtils.h";
|
||||
using RequestContext from "mozilla/dom/cache/IPCUtils.h";
|
||||
using ResponseType from "mozilla/dom/cache/IPCUtils.h";
|
||||
using mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
using struct nsID from "nsID.h";
|
||||
@ -63,7 +62,6 @@ struct CacheRequest
|
||||
RequestCredentials credentials;
|
||||
CacheReadStreamOrVoid body;
|
||||
uint32_t contentPolicyType;
|
||||
RequestContext context;
|
||||
RequestCache requestCache;
|
||||
};
|
||||
|
||||
|
58
dom/cache/DBSchema.cpp
vendored
58
dom/cache/DBSchema.cpp
vendored
@ -29,11 +29,11 @@ namespace dom {
|
||||
namespace cache {
|
||||
namespace db {
|
||||
|
||||
const int32_t kMaxWipeSchemaVersion = 11;
|
||||
const int32_t kMaxWipeSchemaVersion = 13;
|
||||
|
||||
namespace {
|
||||
|
||||
const int32_t kLatestSchemaVersion = 11;
|
||||
const int32_t kLatestSchemaVersion = 13;
|
||||
const int32_t kMaxEntriesPerStatement = 255;
|
||||
|
||||
const uint32_t kPageSize = 4 * 1024;
|
||||
@ -77,40 +77,6 @@ static_assert(int(RequestCredentials::Omit) == 0 &&
|
||||
int(RequestCredentials::Include) == 2 &&
|
||||
int(RequestCredentials::EndGuard_) == 3,
|
||||
"RequestCredentials values are as expected");
|
||||
static_assert(int(RequestContext::Audio) == 0 &&
|
||||
int(RequestContext::Beacon) == 1 &&
|
||||
int(RequestContext::Cspreport) == 2 &&
|
||||
int(RequestContext::Download) == 3 &&
|
||||
int(RequestContext::Embed) == 4 &&
|
||||
int(RequestContext::Eventsource) == 5 &&
|
||||
int(RequestContext::Favicon) == 6 &&
|
||||
int(RequestContext::Fetch) == 7 &&
|
||||
int(RequestContext::Font) == 8 &&
|
||||
int(RequestContext::Form) == 9 &&
|
||||
int(RequestContext::Frame) == 10 &&
|
||||
int(RequestContext::Hyperlink) == 11 &&
|
||||
int(RequestContext::Iframe) == 12 &&
|
||||
int(RequestContext::Image) == 13 &&
|
||||
int(RequestContext::Imageset) == 14 &&
|
||||
int(RequestContext::Import) == 15 &&
|
||||
int(RequestContext::Internal) == 16 &&
|
||||
int(RequestContext::Location) == 17 &&
|
||||
int(RequestContext::Manifest) == 18 &&
|
||||
int(RequestContext::Object) == 19 &&
|
||||
int(RequestContext::Ping) == 20 &&
|
||||
int(RequestContext::Plugin) == 21 &&
|
||||
int(RequestContext::Prefetch) == 22 &&
|
||||
int(RequestContext::Script) == 23 &&
|
||||
int(RequestContext::Serviceworker) == 24 &&
|
||||
int(RequestContext::Sharedworker) == 25 &&
|
||||
int(RequestContext::Subresource) == 26 &&
|
||||
int(RequestContext::Style) == 27 &&
|
||||
int(RequestContext::Track) == 28 &&
|
||||
int(RequestContext::Video) == 29 &&
|
||||
int(RequestContext::Worker) == 30 &&
|
||||
int(RequestContext::Xmlhttprequest) == 31 &&
|
||||
int(RequestContext::Xslt) == 32,
|
||||
"RequestContext values are as expected");
|
||||
static_assert(int(RequestCache::Default) == 0 &&
|
||||
int(RequestCache::No_store) == 1 &&
|
||||
int(RequestCache::Reload) == 2 &&
|
||||
@ -291,7 +257,6 @@ CreateSchema(mozIStorageConnection* aConn)
|
||||
"request_mode INTEGER NOT NULL, "
|
||||
"request_credentials INTEGER NOT NULL, "
|
||||
"request_contentpolicytype INTEGER NOT NULL, "
|
||||
"request_context INTEGER NOT NULL, "
|
||||
"request_cache INTEGER NOT NULL, "
|
||||
"request_body_id TEXT NULL, "
|
||||
"response_type INTEGER NOT NULL, "
|
||||
@ -1462,7 +1427,6 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
"request_mode, "
|
||||
"request_credentials, "
|
||||
"request_contentpolicytype, "
|
||||
"request_context, "
|
||||
"request_cache, "
|
||||
"request_body_id, "
|
||||
"response_type, "
|
||||
@ -1484,7 +1448,6 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
":request_mode, "
|
||||
":request_credentials, "
|
||||
":request_contentpolicytype, "
|
||||
":request_context, "
|
||||
":request_cache, "
|
||||
":request_body_id, "
|
||||
":response_type, "
|
||||
@ -1533,10 +1496,6 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
static_cast<int32_t>(aRequest.contentPolicyType()));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("request_context"),
|
||||
static_cast<int32_t>(aRequest.context()));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("request_cache"),
|
||||
static_cast<int32_t>(aRequest.requestCache()));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
@ -1780,7 +1739,6 @@ ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
"request_mode, "
|
||||
"request_credentials, "
|
||||
"request_contentpolicytype, "
|
||||
"request_context, "
|
||||
"request_cache, "
|
||||
"request_body_id "
|
||||
"FROM entries "
|
||||
@ -1830,25 +1788,19 @@ ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
aSavedRequestOut->mValue.contentPolicyType() =
|
||||
static_cast<nsContentPolicyType>(requestContentPolicyType);
|
||||
|
||||
int32_t requestContext;
|
||||
rv = state->GetInt32(8, &requestContext);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
aSavedRequestOut->mValue.context() =
|
||||
static_cast<RequestContext>(requestContext);
|
||||
|
||||
int32_t requestCache;
|
||||
rv = state->GetInt32(9, &requestCache);
|
||||
rv = state->GetInt32(8, &requestCache);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
aSavedRequestOut->mValue.requestCache() =
|
||||
static_cast<RequestCache>(requestCache);
|
||||
|
||||
bool nullBody = false;
|
||||
rv = state->GetIsNull(10, &nullBody);
|
||||
rv = state->GetIsNull(9, &nullBody);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
aSavedRequestOut->mHasBodyId = !nullBody;
|
||||
|
||||
if (aSavedRequestOut->mHasBodyId) {
|
||||
rv = ExtractId(state, 10, &aSavedRequestOut->mBodyId);
|
||||
rv = ExtractId(state, 9, &aSavedRequestOut->mBodyId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
}
|
||||
|
||||
|
5
dom/cache/IPCUtils.h
vendored
5
dom/cache/IPCUtils.h
vendored
@ -39,11 +39,6 @@ namespace IPC {
|
||||
mozilla::dom::RequestCache::Default,
|
||||
mozilla::dom::RequestCache::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::RequestContext> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::RequestContext,
|
||||
mozilla::dom::RequestContext::Audio,
|
||||
mozilla::dom::RequestContext::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::ResponseType> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::ResponseType,
|
||||
mozilla::dom::ResponseType::Basic,
|
||||
|
5
dom/cache/TypeUtils.cpp
vendored
5
dom/cache/TypeUtils.cpp
vendored
@ -177,7 +177,6 @@ TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||
aOut.mode() = aIn->Mode();
|
||||
aOut.credentials() = aIn->GetCredentialsMode();
|
||||
aOut.contentPolicyType() = aIn->ContentPolicyType();
|
||||
aOut.context() = aIn->Context();
|
||||
aOut.requestCache() = aIn->GetCacheMode();
|
||||
|
||||
if (aBodyAction == IgnoreBody) {
|
||||
@ -328,10 +327,6 @@ TypeUtils::ToInternalRequest(const CacheRequest& aIn)
|
||||
internalRequest->SetMode(aIn.mode());
|
||||
internalRequest->SetCredentialsMode(aIn.credentials());
|
||||
internalRequest->SetContentPolicyType(aIn.contentPolicyType());
|
||||
DebugOnly<RequestContext> contextAfterSetContentPolicyType = internalRequest->Context();
|
||||
internalRequest->SetContext(aIn.context());
|
||||
MOZ_ASSERT(contextAfterSetContentPolicyType.value == internalRequest->Context(),
|
||||
"The RequestContext and nsContentPolicyType values should not get out of sync");
|
||||
internalRequest->SetCacheMode(aIn.requestCache());
|
||||
|
||||
nsRefPtr<InternalHeaders> internalHeaders =
|
||||
|
@ -894,6 +894,10 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
||||
NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
|
||||
|
||||
bool disabled = Preferences::GetBool("webgl.disabled", false);
|
||||
|
||||
// TODO: When we have software webgl support we should use that instead.
|
||||
disabled |= gfxPlatform::InSafeMode();
|
||||
|
||||
if (disabled) {
|
||||
GenerateWarning("WebGL creation is disabled, and so disallowed here.");
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -492,7 +492,16 @@ WebGLContext::GenerateWarning(const char* fmt, va_list ap)
|
||||
|
||||
// no need to print to stderr, as JS_ReportWarning takes care of this for us.
|
||||
|
||||
AutoJSContext cx;
|
||||
if (!mCanvasElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoJSAPI api;
|
||||
if (!api.Init(mCanvasElement->OwnerDoc()->GetScopeObject())) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = api.cx();
|
||||
JS_ReportWarning(cx, "WebGL: %s", buf);
|
||||
if (!ShouldGenerateWarnings()) {
|
||||
JS_ReportWarning(cx,
|
||||
|
@ -39,7 +39,6 @@ InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult
|
||||
// The default referrer is already about:client.
|
||||
|
||||
copy->mContentPolicyType = nsIContentPolicy::TYPE_FETCH;
|
||||
copy->mContext = RequestContext::Fetch;
|
||||
copy->mMode = mMode;
|
||||
copy->mCredentialsMode = mCredentialsMode;
|
||||
copy->mCacheMode = mCacheMode;
|
||||
@ -76,7 +75,6 @@ InternalRequest::InternalRequest(const InternalRequest& aOther)
|
||||
, mURL(aOther.mURL)
|
||||
, mHeaders(new InternalHeaders(*aOther.mHeaders))
|
||||
, mContentPolicyType(aOther.mContentPolicyType)
|
||||
, mContext(aOther.mContext)
|
||||
, mReferrer(aOther.mReferrer)
|
||||
, mMode(aOther.mMode)
|
||||
, mCredentialsMode(aOther.mCredentialsMode)
|
||||
@ -104,78 +102,85 @@ void
|
||||
InternalRequest::SetContentPolicyType(nsContentPolicyType aContentPolicyType)
|
||||
{
|
||||
mContentPolicyType = aContentPolicyType;
|
||||
}
|
||||
|
||||
/* static */
|
||||
RequestContext
|
||||
InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aContentPolicyType)
|
||||
{
|
||||
RequestContext context = RequestContext::Internal;
|
||||
switch (aContentPolicyType) {
|
||||
case nsIContentPolicy::TYPE_OTHER:
|
||||
mContext = RequestContext::Internal;
|
||||
context = RequestContext::Internal;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_SCRIPT:
|
||||
mContext = RequestContext::Script;
|
||||
context = RequestContext::Script;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_IMAGE:
|
||||
mContext = RequestContext::Image;
|
||||
context = RequestContext::Image;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_STYLESHEET:
|
||||
mContext = RequestContext::Style;
|
||||
context = RequestContext::Style;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_OBJECT:
|
||||
mContext = RequestContext::Object;
|
||||
context = RequestContext::Object;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_DOCUMENT:
|
||||
mContext = RequestContext::Internal;
|
||||
context = RequestContext::Internal;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_SUBDOCUMENT:
|
||||
mContext = RequestContext::Iframe;
|
||||
context = RequestContext::Iframe;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_REFRESH:
|
||||
mContext = RequestContext::Internal;
|
||||
context = RequestContext::Internal;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_XBL:
|
||||
mContext = RequestContext::Internal;
|
||||
context = RequestContext::Internal;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_PING:
|
||||
mContext = RequestContext::Ping;
|
||||
context = RequestContext::Ping;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
|
||||
mContext = RequestContext::Xmlhttprequest;
|
||||
context = RequestContext::Xmlhttprequest;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST:
|
||||
mContext = RequestContext::Plugin;
|
||||
context = RequestContext::Plugin;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_DTD:
|
||||
mContext = RequestContext::Internal;
|
||||
context = RequestContext::Internal;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_FONT:
|
||||
mContext = RequestContext::Font;
|
||||
context = RequestContext::Font;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_MEDIA:
|
||||
mContext = RequestContext::Audio;
|
||||
context = RequestContext::Audio;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_WEBSOCKET:
|
||||
mContext = RequestContext::Internal;
|
||||
context = RequestContext::Internal;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_CSP_REPORT:
|
||||
mContext = RequestContext::Cspreport;
|
||||
context = RequestContext::Cspreport;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_XSLT:
|
||||
mContext = RequestContext::Xslt;
|
||||
context = RequestContext::Xslt;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_BEACON:
|
||||
mContext = RequestContext::Beacon;
|
||||
context = RequestContext::Beacon;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_FETCH:
|
||||
mContext = RequestContext::Fetch;
|
||||
context = RequestContext::Fetch;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_IMAGESET:
|
||||
mContext = RequestContext::Imageset;
|
||||
context = RequestContext::Imageset;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_WEB_MANIFEST:
|
||||
mContext = RequestContext::Manifest;
|
||||
context = RequestContext::Manifest;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unhandled nsContentPolicyType value");
|
||||
mContext = RequestContext::Internal;
|
||||
break;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -26,8 +26,7 @@ namespace dom {
|
||||
/*
|
||||
* The mapping of RequestContext and nsContentPolicyType is currently as the
|
||||
* following. Note that this mapping is not perfect yet (see the TODO comments
|
||||
* below for examples), so for now we'll have to keep both an mContext and an
|
||||
* mContentPolicyType, because we cannot have a two way conversion.
|
||||
* below for examples).
|
||||
*
|
||||
* RequestContext | nsContentPolicyType
|
||||
* ------------------+--------------------
|
||||
@ -55,7 +54,6 @@ namespace dom {
|
||||
* plugin | TYPE_OBJECT_SUBREQUEST
|
||||
* prefetch |
|
||||
* script | TYPE_SCRIPT
|
||||
* serviceworker |
|
||||
* sharedworker |
|
||||
* subresource | Not supported by Gecko
|
||||
* style | TYPE_STYLESHEET
|
||||
@ -282,13 +280,7 @@ public:
|
||||
RequestContext
|
||||
Context() const
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
|
||||
void
|
||||
SetContext(RequestContext aContext)
|
||||
{
|
||||
mContext = aContext;
|
||||
return MapContentPolicyTypeToRequestContext(mContentPolicyType);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -372,13 +364,15 @@ private:
|
||||
|
||||
~InternalRequest();
|
||||
|
||||
static RequestContext
|
||||
MapContentPolicyTypeToRequestContext(nsContentPolicyType aContentPolicyType);
|
||||
|
||||
nsCString mMethod;
|
||||
nsCString mURL;
|
||||
nsRefPtr<InternalHeaders> mHeaders;
|
||||
nsCOMPtr<nsIInputStream> mBodyStream;
|
||||
|
||||
nsContentPolicyType mContentPolicyType;
|
||||
RequestContext mContext;
|
||||
|
||||
// Empty string: no-referrer
|
||||
// "about:client": client (default)
|
||||
|
@ -79,13 +79,6 @@ public:
|
||||
return mRequest->Context();
|
||||
}
|
||||
|
||||
// [ChromeOnly]
|
||||
void
|
||||
SetContext(RequestContext aContext)
|
||||
{
|
||||
mRequest->SetContext(aContext);
|
||||
}
|
||||
|
||||
void
|
||||
SetContentPolicyType(nsContentPolicyType aContentPolicyType)
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ Directory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
}
|
||||
|
||||
void
|
||||
Directory::GetName(nsString& aRetval) const
|
||||
Directory::GetName(nsAString& aRetval) const
|
||||
{
|
||||
aRetval.Truncate();
|
||||
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void
|
||||
GetName(nsString& aRetval) const;
|
||||
GetName(nsAString& aRetval) const;
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
||||
|
@ -113,6 +113,7 @@
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsLayoutStylesheetCache.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -146,26 +147,6 @@ static bool ConvertToMidasInternalCommand(const nsAString & inCommandID,
|
||||
// ==================================================================
|
||||
// =
|
||||
// ==================================================================
|
||||
static nsresult
|
||||
RemoveFromAgentSheets(nsCOMArray<nsIStyleSheet> &aAgentSheets, const nsAString& url)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
for (int32_t i = aAgentSheets.Count() - 1; i >= 0; --i) {
|
||||
nsIStyleSheet* sheet = aAgentSheets[i];
|
||||
nsIURI* sheetURI = sheet->GetSheetURI();
|
||||
|
||||
bool equals = false;
|
||||
uri->Equals(sheetURI, &equals);
|
||||
if (equals) {
|
||||
aAgentSheets.RemoveObjectAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewHTMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData)
|
||||
@ -2660,9 +2641,9 @@ nsHTMLDocument::TearingDownEditor(nsIEditor *aEditor)
|
||||
nsCOMArray<nsIStyleSheet> agentSheets;
|
||||
presShell->GetAgentStyleSheets(agentSheets);
|
||||
|
||||
RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
|
||||
agentSheets.RemoveObject(nsLayoutStylesheetCache::ContentEditableSheet());
|
||||
if (oldState == eDesignMode)
|
||||
RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css"));
|
||||
agentSheets.RemoveObject(nsLayoutStylesheetCache::DesignModeSheet());
|
||||
|
||||
presShell->SetAgentStyleSheets(agentSheets);
|
||||
|
||||
@ -2800,41 +2781,34 @@ nsHTMLDocument::EditingStateChanged()
|
||||
rv = presShell->GetAgentStyleSheets(agentSheets);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_NewURI(getter_AddRefs(uri),
|
||||
NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
CSSStyleSheet* contentEditableSheet =
|
||||
nsLayoutStylesheetCache::ContentEditableSheet();
|
||||
|
||||
nsRefPtr<CSSStyleSheet> sheet;
|
||||
rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
|
||||
NS_ENSURE_TRUE(sheet, rv);
|
||||
bool result;
|
||||
|
||||
bool result = agentSheets.AppendObject(sheet);
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
|
||||
if (!agentSheets.Contains(contentEditableSheet)) {
|
||||
bool result = agentSheets.AppendObject(contentEditableSheet);
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
// Should we update the editable state of all the nodes in the document? We
|
||||
// need to do this when the designMode value changes, as that overrides
|
||||
// specific states on the elements.
|
||||
if (designMode) {
|
||||
// designMode is being turned on (overrides contentEditable).
|
||||
rv = NS_NewURI(getter_AddRefs(uri),
|
||||
NS_LITERAL_STRING("resource://gre/res/designmode.css"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
|
||||
NS_ENSURE_TRUE(sheet, rv);
|
||||
|
||||
result = agentSheets.AppendObject(sheet);
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
|
||||
CSSStyleSheet* designModeSheet =
|
||||
nsLayoutStylesheetCache::DesignModeSheet();
|
||||
if (!agentSheets.Contains(designModeSheet)) {
|
||||
result = agentSheets.AppendObject(designModeSheet);
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
updateState = true;
|
||||
spellRecheckAll = oldState == eContentEditable;
|
||||
}
|
||||
else if (oldState == eDesignMode) {
|
||||
// designMode is being turned off (contentEditable is still on).
|
||||
RemoveFromAgentSheets(agentSheets,
|
||||
NS_LITERAL_STRING("resource://gre/res/designmode.css"));
|
||||
|
||||
agentSheets.RemoveObject(nsLayoutStylesheetCache::DesignModeSheet());
|
||||
updateState = true;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ BlobImplSnapshot::CreateSlice(uint64_t aStart,
|
||||
|
||||
void
|
||||
BlobImplSnapshot::GetMozFullPathInternal(nsAString& aFilename,
|
||||
ErrorResult& aRv)
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
AssertSanity();
|
||||
MOZ_ASSERT(mIsFile);
|
||||
|
@ -74,7 +74,7 @@ private:
|
||||
#endif
|
||||
|
||||
virtual void
|
||||
GetMozFullPathInternal(nsAString& aFullPath, ErrorResult& aRv) override;
|
||||
GetMozFullPathInternal(nsAString& aFullPath, ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv) override;
|
||||
|
Binary file not shown.
@ -63,6 +63,18 @@ function testSteps()
|
||||
// This one lives in storage/default/file++++c++
|
||||
{ url: "file:///c:/", dbName: "dbQ", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/file++++Users+joe+c+++index.html
|
||||
{ url: "file:///Users/joe/c++/index.html", dbName: "dbR", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/file++++Users+joe+c+++index.html
|
||||
{ url: "file:///Users/joe/c///index.html", dbName: "dbR", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/file++++++index.html
|
||||
{ url: "file:///+/index.html", dbName: "dbS", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/default/file++++++index.html
|
||||
{ url: "file://///index.html", dbName: "dbS", dbVersion: 1 },
|
||||
|
||||
// This one lives in storage/temporary/http+++localhost
|
||||
{ url: "http://localhost", dbName: "dbZ",
|
||||
dbOptions: { version: 1, storage: "temporary" } }
|
||||
|
@ -1918,7 +1918,7 @@ public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
virtual void
|
||||
GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) override;
|
||||
GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart,
|
||||
@ -2078,10 +2078,10 @@ public:
|
||||
SetLastModified(int64_t aLastModified) override;
|
||||
|
||||
virtual void
|
||||
GetMozFullPath(nsAString& aName, ErrorResult& aRv) override;
|
||||
GetMozFullPath(nsAString& aName, ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) override;
|
||||
GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const override;
|
||||
|
||||
virtual uint64_t
|
||||
GetSize(ErrorResult& aRv) override;
|
||||
@ -2319,7 +2319,7 @@ NS_IMPL_QUERY_INTERFACE_INHERITED(BlobChild::RemoteBlobImpl,
|
||||
void
|
||||
BlobChild::
|
||||
RemoteBlobImpl::GetMozFullPathInternal(nsAString& aFilePath,
|
||||
ErrorResult& aRv)
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
if (!EventTargetIsOnCurrentThread(mActorTarget)) {
|
||||
MOZ_CRASH("Not implemented!");
|
||||
@ -2774,14 +2774,14 @@ RemoteBlobImpl::SetLastModified(int64_t aLastModified)
|
||||
|
||||
void
|
||||
BlobParent::
|
||||
RemoteBlobImpl::GetMozFullPath(nsAString& aName, ErrorResult& aRv)
|
||||
RemoteBlobImpl::GetMozFullPath(nsAString& aName, ErrorResult& aRv) const
|
||||
{
|
||||
mBlobImpl->GetMozFullPath(aName, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
BlobParent::
|
||||
RemoteBlobImpl::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv)
|
||||
RemoteBlobImpl::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const
|
||||
{
|
||||
mBlobImpl->GetMozFullPathInternal(aFileName, aRv);
|
||||
}
|
||||
|
@ -423,6 +423,7 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
|
||||
defaultZoom <= viewportInfo.GetMaxZoom());
|
||||
metrics.SetZoom(CSSToParentLayerScale2D(ConvertScaleForRoot(defaultZoom)));
|
||||
|
||||
metrics.SetPresShellId(presShellId);
|
||||
metrics.SetScrollId(viewId);
|
||||
}
|
||||
|
||||
@ -561,13 +562,9 @@ TabChildBase::UpdateFrameHandler(const FrameMetrics& aFrameMetrics)
|
||||
} else {
|
||||
// aFrameMetrics.mIsRoot is false, so we are trying to update a subframe.
|
||||
// This requires special handling.
|
||||
nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(
|
||||
aFrameMetrics.GetScrollId());
|
||||
if (content) {
|
||||
FrameMetrics newSubFrameMetrics(aFrameMetrics);
|
||||
APZCCallbackHelper::UpdateSubFrame(content, newSubFrameMetrics);
|
||||
return true;
|
||||
}
|
||||
FrameMetrics newSubFrameMetrics(aFrameMetrics);
|
||||
APZCCallbackHelper::UpdateSubFrame(newSubFrameMetrics);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -580,9 +577,7 @@ TabChildBase::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
}
|
||||
|
||||
FrameMetrics newMetrics = aFrameMetrics;
|
||||
if (nsCOMPtr<nsIPresShell> presShell = GetPresShell()) {
|
||||
APZCCallbackHelper::UpdateRootFrame(presShell, newMetrics);
|
||||
}
|
||||
APZCCallbackHelper::UpdateRootFrame(newMetrics);
|
||||
|
||||
CSSSize cssCompositedSize = newMetrics.CalculateCompositedSizeInCssPixels();
|
||||
// The BrowserElementScrolling helper must know about these updated metrics
|
||||
|
@ -79,7 +79,7 @@ function fetchManifest() {
|
||||
reqInit.credentials = 'include';
|
||||
}
|
||||
const req = new content.Request(manifestURL, reqInit);
|
||||
req.setContext('manifest');
|
||||
req.setContentPolicyType(Ci.nsIContentPolicy.TYPE_WEB_MANIFEST);
|
||||
const response = yield content.fetch(req);
|
||||
const manifest = yield processResponse(response, content);
|
||||
return manifest;
|
||||
|
@ -251,6 +251,10 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol
|
||||
AutoEntryScript entryScript(innerGlobal, "javascript: URI", true,
|
||||
scriptContext->GetNativeContext());
|
||||
// We want to make sure we report any exceptions that happen before we
|
||||
// return, since whatever happens inside our execution shouldn't affect any
|
||||
// other scripts that might happen to be running.
|
||||
entryScript.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = entryScript.cx();
|
||||
JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject());
|
||||
NS_ENSURE_TRUE(globalJSObject, NS_ERROR_UNEXPECTED);
|
||||
@ -278,20 +282,13 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
|
||||
rv = nsJSUtils::EvaluateString(cx, NS_ConvertUTF8toUTF16(script),
|
||||
globalJSObject, options, evalOptions, &v);
|
||||
|
||||
// If there's an error on cx as a result of that call, report
|
||||
// it now -- either we're just running under the event loop,
|
||||
// so we shouldn't propagate JS exceptions out of here, or we
|
||||
// can't be sure that our caller is JS (and if it's not we'll
|
||||
// lose the error), or it might be JS that then proceeds to
|
||||
// cause an error of its own (which will also make us lose
|
||||
// this error).
|
||||
::JS_ReportPendingException(cx);
|
||||
|
||||
if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
} else if (v.isUndefined()) {
|
||||
return NS_ERROR_DOM_RETVAL_UNDEFINED;
|
||||
} else {
|
||||
MOZ_ASSERT(rv != NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW,
|
||||
"How did we get a non-undefined return value?");
|
||||
nsAutoJSString result;
|
||||
if (!result.init(cx, v)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -104,12 +104,13 @@ void InitPreferredSampleRate()
|
||||
cubeb* GetCubebContextUnlocked()
|
||||
{
|
||||
sMutex.AssertCurrentThreadOwns();
|
||||
if (sCubebContext ||
|
||||
cubeb_init(&sCubebContext, "CubebUtils") == CUBEB_OK) {
|
||||
return sCubebContext;
|
||||
if (!sCubebContext) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (cubeb_init(&sCubebContext, "CubebUtils") != CUBEB_OK) {
|
||||
NS_WARNING("cubeb_init failed");
|
||||
}
|
||||
}
|
||||
NS_WARNING("cubeb_init failed");
|
||||
return nullptr;
|
||||
return sCubebContext;
|
||||
}
|
||||
|
||||
uint32_t GetCubebLatency()
|
||||
|
@ -56,10 +56,6 @@
|
||||
#include "RtspOmxDecoder.h"
|
||||
#include "RtspOmxReader.h"
|
||||
#endif
|
||||
#ifdef MOZ_WMF
|
||||
#include "WMFDecoder.h"
|
||||
#include "WMFReader.h"
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
#include "DirectShowDecoder.h"
|
||||
#include "DirectShowReader.h"
|
||||
@ -334,14 +330,6 @@ IsAndroidMediaType(const nsACString& aType)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WMF
|
||||
static bool
|
||||
IsWMFSupportedType(const nsACString& aType)
|
||||
{
|
||||
return WMFDecoder::CanPlayType(aType, NS_LITERAL_STRING(""));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
static bool
|
||||
IsDirectShowSupportedType(const nsACString& aType)
|
||||
@ -481,23 +469,10 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
// Note: DirectShow should come before WMF, so that we prefer DirectShow's
|
||||
// MP3 support over WMF's.
|
||||
if (DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), &codecList)) {
|
||||
result = CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_WMF
|
||||
if (!Preferences::GetBool("media.fragmented-mp4.exposed", false) &&
|
||||
IsWMFSupportedType(nsDependentCString(aMIMEType))) {
|
||||
if (!aHaveRequestedCodecs) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
return WMFDecoder::CanPlayType(nsDependentCString(aMIMEType),
|
||||
aRequestedCodecs)
|
||||
? CANPLAY_YES : CANPLAY_NO;
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
if (IsAppleMediaSupportedType(nsDependentCString(aMIMEType), &codecList)) {
|
||||
result = CANPLAY_MAYBE;
|
||||
@ -637,12 +612,6 @@ InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_WMF
|
||||
if (IsWMFSupportedType(aType)) {
|
||||
decoder = new WMFDecoder();
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
if (IsAppleMediaSupportedType(aType)) {
|
||||
decoder = new AppleDecoder();
|
||||
@ -727,17 +696,10 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
// Note: DirectShowReader is preferred for MP3, but if it's disabled we
|
||||
// fallback to the WMFReader.
|
||||
if (IsDirectShowSupportedType(aType)) {
|
||||
decoderReader = new DirectShowReader(aDecoder);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_WMF
|
||||
if (IsWMFSupportedType(aType)) {
|
||||
decoderReader = new WMFReader(aDecoder);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
if (IsAppleMediaSupportedType(aType)) {
|
||||
decoderReader = new AppleMP3Reader(aDecoder);
|
||||
@ -781,9 +743,6 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
|
||||
IsMP4SupportedType(aType) ||
|
||||
#endif
|
||||
IsMP3SupportedType(aType) ||
|
||||
#ifdef MOZ_WMF
|
||||
IsWMFSupportedType(aType) ||
|
||||
#endif
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
IsDirectShowSupportedType(aType) ||
|
||||
#endif
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <limits>
|
||||
#include "nsIObserver.h"
|
||||
#include "nsTArray.h"
|
||||
#include "CubebUtils.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "ImageContainer.h"
|
||||
@ -28,10 +29,6 @@
|
||||
#include "mozilla/dom/VideoTrack.h"
|
||||
#include "mozilla/dom/VideoTrackList.h"
|
||||
|
||||
#ifdef MOZ_WMF
|
||||
#include "WMFDecoder.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::media;
|
||||
@ -404,6 +401,11 @@ bool MediaDecoder::Init(MediaDecoderOwner* aOwner)
|
||||
mOwner = aOwner;
|
||||
mVideoFrameContainer = aOwner->GetVideoFrameContainer();
|
||||
MediaShutdownManager::Instance().Register(this);
|
||||
// We don't use the cubeb context yet, but need to ensure it is created on
|
||||
// the main thread.
|
||||
if (!CubebUtils::GetCubebContext()) {
|
||||
NS_WARNING("Audio backend initialization failed.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1509,14 +1511,6 @@ MediaDecoder::IsAndroidMediaEnabled()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WMF
|
||||
bool
|
||||
MediaDecoder::IsWMFEnabled()
|
||||
{
|
||||
return WMFDecoder::IsEnabled();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
bool
|
||||
MediaDecoder::IsAppleMP3Enabled()
|
||||
|
@ -159,10 +159,11 @@ MediaTaskQueue::AwaitShutdownAndIdle()
|
||||
nsRefPtr<ShutdownPromise>
|
||||
MediaTaskQueue::BeginShutdown()
|
||||
{
|
||||
// Make sure there are no tasks for this queue waiting in the caller's tail
|
||||
// dispatcher.
|
||||
MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
|
||||
!AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
|
||||
// Dispatch any tasks for this queue waiting in the caller's tail dispatcher,
|
||||
// since this is the last opportunity to do so.
|
||||
if (AbstractThread* currentThread = AbstractThread::GetCurrent()) {
|
||||
currentThread->TailDispatcher().DispatchTasksFor(this);
|
||||
}
|
||||
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
mIsShutdown = true;
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
already_AddRefed<nsIRunnable> aRunnable,
|
||||
AbstractThread::DispatchFailureHandling aFailureHandling = AbstractThread::AssertDispatchSuccess) = 0;
|
||||
|
||||
virtual void DispatchTasksFor(AbstractThread* aThread) = 0;
|
||||
virtual bool HasTasksFor(AbstractThread* aThread) = 0;
|
||||
virtual void DrainDirectTasks() = 0;
|
||||
};
|
||||
@ -82,14 +83,7 @@ public:
|
||||
MOZ_ASSERT(mDirectTasks.empty());
|
||||
|
||||
for (size_t i = 0; i < mTaskGroups.Length(); ++i) {
|
||||
UniquePtr<PerThreadTaskGroup> group(Move(mTaskGroups[i]));
|
||||
nsRefPtr<AbstractThread> thread = group->mThread;
|
||||
|
||||
AbstractThread::DispatchFailureHandling failureHandling = group->mFailureHandling;
|
||||
AbstractThread::DispatchReason reason = mIsTailDispatcher ? AbstractThread::TailDispatch
|
||||
: AbstractThread::NormalDispatch;
|
||||
nsCOMPtr<nsIRunnable> r = new TaskGroupRunnable(Move(group));
|
||||
thread->Dispatch(r.forget(), failureHandling, reason);
|
||||
DispatchTaskGroup(Move(mTaskGroups[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +126,17 @@ public:
|
||||
return !!GetTaskGroup(aThread) || (aThread == AbstractThread::GetCurrent() && !mDirectTasks.empty());
|
||||
}
|
||||
|
||||
void DispatchTasksFor(AbstractThread* aThread) override
|
||||
{
|
||||
for (size_t i = 0; i < mTaskGroups.Length(); ++i) {
|
||||
if (mTaskGroups[i]->mThread == aThread) {
|
||||
DispatchTaskGroup(Move(mTaskGroups[i]));
|
||||
mTaskGroups.RemoveElementAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct PerThreadTaskGroup
|
||||
@ -215,6 +220,17 @@ private:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DispatchTaskGroup(UniquePtr<PerThreadTaskGroup> aGroup)
|
||||
{
|
||||
nsRefPtr<AbstractThread> thread = aGroup->mThread;
|
||||
|
||||
AbstractThread::DispatchFailureHandling failureHandling = aGroup->mFailureHandling;
|
||||
AbstractThread::DispatchReason reason = mIsTailDispatcher ? AbstractThread::TailDispatch
|
||||
: AbstractThread::NormalDispatch;
|
||||
nsCOMPtr<nsIRunnable> r = new TaskGroupRunnable(Move(aGroup));
|
||||
thread->Dispatch(r.forget(), failureHandling, reason);
|
||||
}
|
||||
|
||||
// Direct tasks.
|
||||
std::queue<nsCOMPtr<nsIRunnable>> mDirectTasks;
|
||||
|
||||
|
@ -54,9 +54,6 @@ if CONFIG['MOZ_DIRECTSHOW']:
|
||||
if CONFIG['MOZ_ANDROID_OMX']:
|
||||
DIRS += ['android']
|
||||
|
||||
if CONFIG['MOZ_WMF']:
|
||||
DIRS += ['wmf']
|
||||
|
||||
if CONFIG['MOZ_FMP4']:
|
||||
DIRS += ['fmp4']
|
||||
|
||||
|
@ -53,68 +53,24 @@ extern "C" const CLSID CLSID_CMSAACDecMFT;
|
||||
namespace mozilla {
|
||||
namespace wmf {
|
||||
|
||||
// Loads/Unloads all the DLLs in which the WMF functions are located.
|
||||
// The DLLs must be loaded before any of the WMF functions below will work.
|
||||
// All the function definitions below are wrappers which locate the
|
||||
// corresponding WMF function in the appropriate DLL (hence why LoadDLL()
|
||||
// must be called first...).
|
||||
HRESULT LoadDLLs();
|
||||
HRESULT UnloadDLLs();
|
||||
// If successful, loads all required WMF DLLs and calls the WMF MFStartup()
|
||||
// function.
|
||||
HRESULT MFStartup();
|
||||
|
||||
// Calls the WMF MFShutdown() function. Call this once for every time
|
||||
// wmf::MFStartup() succeeds. Note: does not unload the WMF DLLs loaded by
|
||||
// MFStartup(); leaves them in memory to save I/O at next MFStartup() call.
|
||||
HRESULT MFShutdown();
|
||||
|
||||
// All functions below are wrappers around the corresponding WMF function,
|
||||
// and automatically locate and call the corresponding function in the WMF DLLs.
|
||||
|
||||
HRESULT MFStartup();
|
||||
|
||||
HRESULT MFShutdown();
|
||||
|
||||
HRESULT MFCreateAsyncResult(IUnknown *aUunkObject,
|
||||
IMFAsyncCallback *aCallback,
|
||||
IUnknown *aUnkState,
|
||||
IMFAsyncResult **aOutAsyncResult);
|
||||
|
||||
HRESULT MFInvokeCallback(IMFAsyncResult *aAsyncResult);
|
||||
|
||||
HRESULT MFCreateMediaType(IMFMediaType **aOutMFType);
|
||||
|
||||
HRESULT MFCreateSourceReaderFromByteStream(IMFByteStream *aByteStream,
|
||||
IMFAttributes *aAttributes,
|
||||
IMFSourceReader **aOutSourceReader);
|
||||
|
||||
HRESULT PropVariantToUInt32(REFPROPVARIANT aPropvar, ULONG *aOutUL);
|
||||
|
||||
HRESULT PropVariantToInt64(REFPROPVARIANT aPropVar, LONGLONG *aOutLL);
|
||||
|
||||
HRESULT MFTGetInfo(CLSID aClsidMFT,
|
||||
LPWSTR *aOutName,
|
||||
MFT_REGISTER_TYPE_INFO **aOutInputTypes,
|
||||
UINT32 *aOutNumInputTypes,
|
||||
MFT_REGISTER_TYPE_INFO **aOutOutputTypes,
|
||||
UINT32 *aOutNumOutputTypes,
|
||||
IMFAttributes **aOutAttributes);
|
||||
|
||||
HRESULT MFGetStrideForBitmapInfoHeader(DWORD aFormat,
|
||||
DWORD aWidth,
|
||||
LONG *aOutStride);
|
||||
|
||||
// Note: We shouldn't use this in production code; it's really only
|
||||
// here so we can compare behaviour of the SourceReader using WMF's
|
||||
// byte stream and ours when debugging.
|
||||
HRESULT MFCreateSourceReaderFromURL(LPCWSTR aURL,
|
||||
IMFAttributes *aAttributes,
|
||||
IMFSourceReader **aSourceReader);
|
||||
|
||||
HRESULT MFCreateAttributes(IMFAttributes **ppMFAttributes, UINT32 cInitialSize);
|
||||
|
||||
HRESULT MFGetPluginControl(IMFPluginControl **aOutPluginControl);
|
||||
|
||||
HRESULT MFTEnumEx(GUID guidCategory,
|
||||
UINT32 Flags,
|
||||
const MFT_REGISTER_TYPE_INFO *pInputType,
|
||||
const MFT_REGISTER_TYPE_INFO *pOutputType,
|
||||
IMFActivate ***pppMFTActivate,
|
||||
UINT32 *pcMFTActivate);
|
||||
|
||||
HRESULT MFGetService(IUnknown *punkObject,
|
||||
REFGUID guidService,
|
||||
REFIID riid,
|
@ -289,19 +289,18 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
|
||||
}
|
||||
|
||||
buffer->Unlock();
|
||||
int64_t timestamp;
|
||||
hr = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate, ×tamp);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
CheckedInt64 timestamp = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate);
|
||||
NS_ENSURE_TRUE(timestamp.isValid(), E_FAIL);
|
||||
|
||||
mAudioFrameSum += numFrames;
|
||||
|
||||
int64_t duration;
|
||||
hr = FramesToUsecs(numFrames, mAudioRate, &duration);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
CheckedInt64 duration = FramesToUsecs(numFrames, mAudioRate);
|
||||
NS_ENSURE_TRUE(duration.isValid(), E_FAIL);
|
||||
|
||||
aOutData = new AudioData(aStreamOffset,
|
||||
timestamp,
|
||||
duration,
|
||||
timestamp.value(),
|
||||
duration.value(),
|
||||
numFrames,
|
||||
audioData.forget(),
|
||||
mAudioChannels,
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include "WMF.h"
|
||||
#include "WMFDecoderModule.h"
|
||||
#include "WMFDecoder.h"
|
||||
#include "WMFVideoMFTManager.h"
|
||||
#include "WMFAudioMFTManager.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -22,17 +21,26 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool WMFDecoderModule::sIsWMFEnabled = false;
|
||||
bool WMFDecoderModule::sDXVAEnabled = false;
|
||||
static bool sIsWMFEnabled = false;
|
||||
static bool sDXVAEnabled = false;
|
||||
|
||||
WMFDecoderModule::WMFDecoderModule()
|
||||
: mWMFInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
WMFDecoderModule::~WMFDecoderModule()
|
||||
{
|
||||
DebugOnly<HRESULT> hr = wmf::MFShutdown();
|
||||
NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
|
||||
if (mWMFInitialized) {
|
||||
DebugOnly<HRESULT> hr = wmf::MFShutdown();
|
||||
NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WMFDecoderModule::DisableHardwareAcceleration()
|
||||
{
|
||||
sDXVAEnabled = false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
@ -41,12 +49,6 @@ WMFDecoderModule::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
sIsWMFEnabled = Preferences::GetBool("media.windows-media-foundation.enabled", false);
|
||||
if (!sIsWMFEnabled) {
|
||||
return;
|
||||
}
|
||||
if (NS_FAILED(WMFDecoder::LoadDLLs())) {
|
||||
sIsWMFEnabled = false;
|
||||
}
|
||||
sDXVAEnabled = !gfxWindowsPlatform::GetPlatform()->IsWARP() &&
|
||||
gfxPlatform::CanUseHardwareVideoDecoding();
|
||||
}
|
||||
@ -54,14 +56,10 @@ WMFDecoderModule::Init()
|
||||
nsresult
|
||||
WMFDecoderModule::Startup()
|
||||
{
|
||||
if (!sIsWMFEnabled) {
|
||||
return NS_ERROR_FAILURE;
|
||||
if (sIsWMFEnabled) {
|
||||
mWMFInitialized = SUCCEEDED(wmf::MFStartup());
|
||||
}
|
||||
if (FAILED(wmf::MFStartup())) {
|
||||
NS_WARNING("Failed to initialize Windows Media Foundation");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
return mWMFInitialized ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
|
@ -33,11 +33,7 @@ public:
|
||||
|
||||
bool SupportsMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
virtual void DisableHardwareAcceleration() override
|
||||
{
|
||||
sDXVAEnabled = false;
|
||||
}
|
||||
|
||||
virtual void DisableHardwareAcceleration() override;
|
||||
virtual bool SupportsSharedDecoders(const VideoInfo& aConfig) const override;
|
||||
|
||||
virtual ConversionRequired
|
||||
@ -54,9 +50,7 @@ public:
|
||||
static void Init();
|
||||
private:
|
||||
bool ShouldUseDXVA(const VideoInfo& aConfig) const;
|
||||
|
||||
static bool sIsWMFEnabled;
|
||||
static bool sDXVAEnabled;
|
||||
bool mWMFInitialized;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
301
dom/media/platforms/wmf/WMFUtils.cpp
Normal file
301
dom/media/platforms/wmf/WMFUtils.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WMFUtils.h"
|
||||
#include <stdint.h>
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "VideoUtils.h"
|
||||
#include <initguid.h>
|
||||
#include "nsTArray.h"
|
||||
|
||||
#ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
|
||||
// Some SDK versions don't define the AAC decoder CLSID.
|
||||
// {32D186A7-218F-4C75-8876-DD77273A8999}
|
||||
DEFINE_GUID(CLSID_CMSAACDecMFT, 0x32D186A7, 0x218F, 0x4C75, 0x88, 0x76, 0xDD, 0x77, 0x27, 0x3A, 0x89, 0x99);
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
HRESULT
|
||||
HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames)
|
||||
{
|
||||
MOZ_ASSERT(aOutFrames);
|
||||
const int64_t HNS_PER_S = USECS_PER_S * 10;
|
||||
CheckedInt<int64_t> i = aHNs;
|
||||
i *= aRate;
|
||||
i /= HNS_PER_S;
|
||||
NS_ENSURE_TRUE(i.isValid(), E_FAIL);
|
||||
*aOutFrames = i.value();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
|
||||
{
|
||||
// Try to get the default stride from the media type.
|
||||
HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride);
|
||||
if (SUCCEEDED(hr)) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Stride attribute not set, calculate it.
|
||||
GUID subtype = GUID_NULL;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
|
||||
hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG*)(aOutStride));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
MFOffsetToInt32(const MFOffset& aOffset)
|
||||
{
|
||||
return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
|
||||
}
|
||||
|
||||
int64_t
|
||||
GetSampleDuration(IMFSample* aSample)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSample, -1);
|
||||
int64_t duration = 0;
|
||||
aSample->GetSampleDuration(&duration);
|
||||
return HNsToUsecs(duration);
|
||||
}
|
||||
|
||||
int64_t
|
||||
GetSampleTime(IMFSample* aSample)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSample, -1);
|
||||
LONGLONG timestampHns = 0;
|
||||
HRESULT hr = aSample->GetSampleTime(×tampHns);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), -1);
|
||||
return HNsToUsecs(timestampHns);
|
||||
}
|
||||
|
||||
// Gets the sub-region of the video frame that should be displayed.
|
||||
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
|
||||
HRESULT
|
||||
GetPictureRegion(IMFMediaType* aMediaType, nsIntRect& aOutPictureRegion)
|
||||
{
|
||||
// Determine if "pan and scan" is enabled for this media. If it is, we
|
||||
// only display a region of the video frame, not the entire frame.
|
||||
BOOL panScan = MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
|
||||
|
||||
// If pan and scan mode is enabled. Try to get the display region.
|
||||
HRESULT hr = E_FAIL;
|
||||
MFVideoArea videoArea;
|
||||
memset(&videoArea, 0, sizeof(MFVideoArea));
|
||||
if (panScan) {
|
||||
hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE,
|
||||
(UINT8*)&videoArea,
|
||||
sizeof(MFVideoArea),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
|
||||
// check for a minimimum display aperture.
|
||||
if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
|
||||
hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
|
||||
(UINT8*)&videoArea,
|
||||
sizeof(MFVideoArea),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (hr == MF_E_ATTRIBUTENOTFOUND) {
|
||||
// Minimum display aperture is not set, for "backward compatibility with
|
||||
// some components", check for a geometric aperture.
|
||||
hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE,
|
||||
(UINT8*)&videoArea,
|
||||
sizeof(MFVideoArea),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
// The media specified a picture region, return it.
|
||||
aOutPictureRegion = nsIntRect(MFOffsetToInt32(videoArea.OffsetX),
|
||||
MFOffsetToInt32(videoArea.OffsetY),
|
||||
videoArea.Area.cx,
|
||||
videoArea.Area.cy);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// No picture region defined, fall back to using the entire video area.
|
||||
UINT32 width = 0, height = 0;
|
||||
hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
aOutPictureRegion = nsIntRect(0, 0, width, height);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
namespace wmf {
|
||||
|
||||
static const wchar_t* sDLLs[] = {
|
||||
L"mfplat.dll",
|
||||
L"mf.dll",
|
||||
L"dxva2.dll",
|
||||
L"evr.dll",
|
||||
};
|
||||
|
||||
HRESULT
|
||||
LoadDLLs()
|
||||
{
|
||||
static bool sDLLsLoaded = false;
|
||||
static bool sFailedToLoadDlls = false;
|
||||
|
||||
if (sDLLsLoaded) {
|
||||
return S_OK;
|
||||
}
|
||||
if (sFailedToLoadDlls) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Try to load all the required DLLs. If we fail to load any dll,
|
||||
// unload the dlls we succeeded in loading.
|
||||
nsTArray<const wchar_t*> loadedDlls;
|
||||
for (const wchar_t* dll : sDLLs) {
|
||||
if (!LoadLibrarySystem32(dll)) {
|
||||
NS_WARNING("Failed to load WMF DLLs");
|
||||
for (const wchar_t* loadedDll : loadedDlls) {
|
||||
FreeLibrary(GetModuleHandleW(loadedDll));
|
||||
}
|
||||
sFailedToLoadDlls = true;
|
||||
return E_FAIL;
|
||||
}
|
||||
loadedDlls.AppendElement(dll);
|
||||
}
|
||||
sDLLsLoaded = true;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \
|
||||
static FunctionType FunctionName##Ptr = nullptr; \
|
||||
if (!FunctionName##Ptr) { \
|
||||
FunctionName##Ptr = (FunctionType) GetProcAddress(GetModuleHandleW(L ## #DLL), #FunctionName); \
|
||||
if (!FunctionName##Ptr) { \
|
||||
NS_WARNING("Failed to get GetProcAddress of " #FunctionName " from " #DLL); \
|
||||
return E_FAIL; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENSURE_FUNCTION_PTR(FunctionName, DLL) \
|
||||
ENSURE_FUNCTION_PTR_HELPER(decltype(::FunctionName)*, FunctionName, DLL) \
|
||||
|
||||
#define ENSURE_FUNCTION_PTR_(FunctionName, DLL) \
|
||||
ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL) \
|
||||
|
||||
#define DECL_FUNCTION_PTR(FunctionName, ...) \
|
||||
typedef HRESULT (STDMETHODCALLTYPE * FunctionName##Ptr_t)(__VA_ARGS__)
|
||||
|
||||
HRESULT
|
||||
MFStartup()
|
||||
{
|
||||
HRESULT hr = LoadDLLs();
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
const int MF_VISTA_VERSION = (0x0001 << 16 | MF_API_VERSION);
|
||||
const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION);
|
||||
|
||||
// decltype is unusable for functions having default parameters
|
||||
DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
|
||||
ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
|
||||
if (!IsWin7OrLater())
|
||||
return MFStartupPtr(MF_VISTA_VERSION, MFSTARTUP_FULL);
|
||||
else
|
||||
return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFShutdown()
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll)
|
||||
return (MFShutdownPtr)();
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateMediaType(IMFMediaType **aOutMFType)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateMediaType, Mfplat.dll)
|
||||
return (MFCreateMediaTypePtr)(aOutMFType);
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
MFGetStrideForBitmapInfoHeader(DWORD aFormat,
|
||||
DWORD aWidth,
|
||||
LONG *aOutStride)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFGetStrideForBitmapInfoHeader, evr.dll)
|
||||
return (MFGetStrideForBitmapInfoHeaderPtr)(aFormat, aWidth, aOutStride);
|
||||
}
|
||||
|
||||
HRESULT MFGetService(IUnknown *punkObject,
|
||||
REFGUID guidService,
|
||||
REFIID riid,
|
||||
LPVOID *ppvObject)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFGetService, mf.dll)
|
||||
return (MFGetServicePtr)(punkObject, guidService, riid, ppvObject);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
DXVA2CreateDirect3DDeviceManager9(UINT *pResetToken,
|
||||
IDirect3DDeviceManager9 **ppDXVAManager)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, dxva2.dll)
|
||||
return (DXVA2CreateDirect3DDeviceManager9Ptr)(pResetToken, ppDXVAManager);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateSample(IMFSample **ppIMFSample)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateSample, mfplat.dll)
|
||||
return (MFCreateSamplePtr)(ppIMFSample);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateAlignedMemoryBuffer(DWORD cbMaxLength,
|
||||
DWORD fAlignmentFlags,
|
||||
IMFMediaBuffer **ppBuffer)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateAlignedMemoryBuffer, mfplat.dll)
|
||||
return (MFCreateAlignedMemoryBufferPtr)(cbMaxLength, fAlignmentFlags, ppBuffer);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateDXGIDeviceManager(UINT *pResetToken, IMFDXGIDeviceManager **ppDXVAManager)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateDXGIDeviceManager, mfplat.dll)
|
||||
return (MFCreateDXGIDeviceManagerPtr)(pResetToken, ppDXVAManager);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateDXGISurfaceBuffer(REFIID riid,
|
||||
IUnknown *punkSurface,
|
||||
UINT uSubresourceIndex,
|
||||
BOOL fButtomUpWhenLinear,
|
||||
IMFMediaBuffer **ppBuffer)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateDXGISurfaceBuffer, mfplat.dll)
|
||||
return (MFCreateDXGISurfaceBufferPtr)(riid, punkSurface, uSubresourceIndex, fButtomUpWhenLinear, ppBuffer);
|
||||
}
|
||||
|
||||
} // end namespace wmf
|
||||
} // end namespace mozilla
|
@ -16,38 +16,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsCString
|
||||
GetGUIDName(const GUID& guid);
|
||||
|
||||
// Returns true if the reader has a stream with the specified index.
|
||||
// Index can be a specific index, or one of:
|
||||
// MF_SOURCE_READER_FIRST_VIDEO_STREAM
|
||||
// MF_SOURCE_READER_FIRST_AUDIO_STREAM
|
||||
bool
|
||||
SourceReaderHasStream(IMFSourceReader* aReader, const DWORD aIndex);
|
||||
|
||||
// Auto manages the lifecycle of a PROPVARIANT.
|
||||
class AutoPropVar {
|
||||
public:
|
||||
AutoPropVar() {
|
||||
PropVariantInit(&mVar);
|
||||
}
|
||||
~AutoPropVar() {
|
||||
PropVariantClear(&mVar);
|
||||
}
|
||||
operator PROPVARIANT&() {
|
||||
return mVar;
|
||||
}
|
||||
PROPVARIANT* operator->() {
|
||||
return &mVar;
|
||||
}
|
||||
PROPVARIANT* operator&() {
|
||||
return &mVar;
|
||||
}
|
||||
private:
|
||||
PROPVARIANT mVar;
|
||||
};
|
||||
|
||||
// Converts from microseconds to hundreds of nanoseconds.
|
||||
// We use microseconds for our timestamps, whereas WMF uses
|
||||
// hundreds of nanoseconds.
|
||||
@ -64,17 +32,9 @@ HNsToUsecs(int64_t hNanoSecs) {
|
||||
return hNanoSecs / 10;
|
||||
}
|
||||
|
||||
// Assigns aUnknown to *aInterface, and AddRef's it.
|
||||
// Helper for MSCOM QueryInterface implementations.
|
||||
HRESULT
|
||||
DoGetInterface(IUnknown* aUnknown, void** aInterface);
|
||||
|
||||
HRESULT
|
||||
HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames);
|
||||
|
||||
HRESULT
|
||||
FramesToUsecs(int64_t aSamples, uint32_t aRate, int64_t* aOutUsecs);
|
||||
|
||||
HRESULT
|
||||
GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride);
|
||||
|
@ -5,13 +5,17 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'DXVA2Manager.h',
|
||||
'MFTDecoder.h',
|
||||
'WMF.h',
|
||||
'WMFAudioMFTManager.h',
|
||||
'WMFDecoderModule.h',
|
||||
'WMFMediaDataDecoder.h',
|
||||
'WMFUtils.h',
|
||||
'WMFVideoMFTManager.h',
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'DXVA2Manager.cpp',
|
||||
'MFTDecoder.cpp',
|
||||
'WMFAudioMFTManager.cpp',
|
||||
'WMFDecoderModule.cpp',
|
||||
@ -19,8 +23,17 @@ UNIFIED_SOURCES += [
|
||||
'WMFVideoMFTManager.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'WMFUtils.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DEFINES['NOMINMAX'] = True
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
|
||||
|
@ -110,6 +110,11 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow,
|
||||
// call them after mDestination has been set up.
|
||||
mDestination->CreateAudioChannelAgent();
|
||||
mDestination->SetIsOnlyNodeForContext(true);
|
||||
// We don't use the cubeb context yet, but need to ensure it is created on
|
||||
// the main thread.
|
||||
if (!aIsOffline && !CubebUtils::GetCubebContext()) {
|
||||
NS_WARNING("Audio backend initialization failed.");
|
||||
}
|
||||
}
|
||||
|
||||
AudioContext::~AudioContext()
|
||||
|
@ -1,680 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WMF.h"
|
||||
|
||||
#include <unknwn.h>
|
||||
#include <ole2.h>
|
||||
|
||||
#include "WMFByteStream.h"
|
||||
#include "WMFSourceReaderCallback.h"
|
||||
#include "WMFUtils.h"
|
||||
#include "MediaResource.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsIThreadPool.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "SharedThreadPool.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
PRLogModuleInfo* gWMFByteStreamLog = nullptr;
|
||||
#define WMF_BS_LOG(...) MOZ_LOG(gWMFByteStreamLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
WMFByteStream::WMFByteStream(MediaResource* aResource,
|
||||
WMFSourceReaderCallback* aSourceReaderCallback)
|
||||
: mSourceReaderCallback(aSourceReaderCallback),
|
||||
mResource(aResource),
|
||||
mReentrantMonitor("WMFByteStream.Data"),
|
||||
mOffset(0),
|
||||
mIsShutdown(false)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
|
||||
NS_ASSERTION(mSourceReaderCallback, "Must have a source reader callback.");
|
||||
|
||||
if (!gWMFByteStreamLog) {
|
||||
gWMFByteStreamLog = PR_NewLogModule("WMFByteStream");
|
||||
}
|
||||
WMF_BS_LOG("[%p] WMFByteStream CTOR", this);
|
||||
MOZ_COUNT_CTOR(WMFByteStream);
|
||||
}
|
||||
|
||||
WMFByteStream::~WMFByteStream()
|
||||
{
|
||||
MOZ_COUNT_DTOR(WMFByteStream);
|
||||
WMF_BS_LOG("[%p] WMFByteStream DTOR", this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
WMFByteStream::Init()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
|
||||
|
||||
mThreadPool = SharedThreadPool::Get(NS_LITERAL_CSTRING("WMFByteStream IO"), 4);
|
||||
NS_ENSURE_TRUE(mThreadPool, NS_ERROR_FAILURE);
|
||||
|
||||
NS_ConvertUTF8toUTF16 contentTypeUTF16(mResource->GetContentType());
|
||||
if (!contentTypeUTF16.IsEmpty()) {
|
||||
HRESULT hr = wmf::MFCreateAttributes(byRef(mAttributes), 1);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
|
||||
|
||||
hr = mAttributes->SetString(MF_BYTESTREAM_CONTENT_TYPE,
|
||||
contentTypeUTF16.get());
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
|
||||
|
||||
WMF_BS_LOG("[%p] WMFByteStream has Content-Type=%s", this, mResource->GetContentType().get());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WMFByteStream::Shutdown()
|
||||
{
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mIsShutdown = true;
|
||||
}
|
||||
mSourceReaderCallback->Cancel();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// IUnknown Methods
|
||||
STDMETHODIMP
|
||||
WMFByteStream::QueryInterface(REFIID aIId, void **aInterface)
|
||||
{
|
||||
WMF_BS_LOG("[%p] WMFByteStream::QueryInterface %s", this, GetGUIDName(aIId).get());
|
||||
|
||||
if (aIId == IID_IMFByteStream) {
|
||||
return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface);
|
||||
}
|
||||
if (aIId == IID_IUnknown) {
|
||||
return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface);
|
||||
}
|
||||
if (aIId == IID_IMFAttributes) {
|
||||
return DoGetInterface(static_cast<IMFAttributes*>(this), aInterface);
|
||||
}
|
||||
|
||||
*aInterface = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(WMFByteStream)
|
||||
NS_IMPL_RELEASE(WMFByteStream)
|
||||
|
||||
|
||||
// Stores data regarding an async read opreation.
|
||||
class ReadRequest final : public IUnknown {
|
||||
~ReadRequest() {}
|
||||
|
||||
public:
|
||||
ReadRequest(int64_t aOffset, BYTE* aBuffer, ULONG aLength)
|
||||
: mOffset(aOffset),
|
||||
mBuffer(aBuffer),
|
||||
mBufferLength(aLength),
|
||||
mBytesRead(0)
|
||||
{}
|
||||
|
||||
// IUnknown Methods
|
||||
STDMETHODIMP QueryInterface(REFIID aRIID, LPVOID *aOutObject);
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
int64_t mOffset;
|
||||
BYTE* mBuffer;
|
||||
ULONG mBufferLength;
|
||||
ULONG mBytesRead;
|
||||
|
||||
// IUnknown ref counting.
|
||||
ThreadSafeAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF(ReadRequest)
|
||||
NS_IMPL_RELEASE(ReadRequest)
|
||||
|
||||
// IUnknown Methods
|
||||
STDMETHODIMP
|
||||
ReadRequest::QueryInterface(REFIID aIId, void **aInterface)
|
||||
{
|
||||
WMF_BS_LOG("ReadRequest::QueryInterface %s", GetGUIDName(aIId).get());
|
||||
|
||||
if (aIId == IID_IUnknown) {
|
||||
return DoGetInterface(static_cast<IUnknown*>(this), aInterface);
|
||||
}
|
||||
|
||||
*aInterface = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
class ProcessReadRequestEvent final : public nsRunnable {
|
||||
public:
|
||||
ProcessReadRequestEvent(WMFByteStream* aStream,
|
||||
IMFAsyncResult* aResult,
|
||||
ReadRequest* aRequestState)
|
||||
: mStream(aStream),
|
||||
mResult(aResult),
|
||||
mRequestState(aRequestState) {}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mStream->ProcessReadRequest(mResult, mRequestState);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
RefPtr<WMFByteStream> mStream;
|
||||
RefPtr<IMFAsyncResult> mResult;
|
||||
RefPtr<ReadRequest> mRequestState;
|
||||
};
|
||||
|
||||
// IMFByteStream Methods
|
||||
STDMETHODIMP
|
||||
WMFByteStream::BeginRead(BYTE *aBuffer,
|
||||
ULONG aLength,
|
||||
IMFAsyncCallback *aCallback,
|
||||
IUnknown *aCallerState)
|
||||
{
|
||||
NS_ENSURE_TRUE(aBuffer, E_POINTER);
|
||||
NS_ENSURE_TRUE(aCallback, E_POINTER);
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
WMF_BS_LOG("[%p] WMFByteStream::BeginRead() mOffset=%lld tell=%lld length=%lu mIsShutdown=%d",
|
||||
this, mOffset, mResource->Tell(), aLength, mIsShutdown);
|
||||
|
||||
if (mIsShutdown || mOffset < 0) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// Create an object to store our state.
|
||||
RefPtr<ReadRequest> requestState = new ReadRequest(mOffset, aBuffer, aLength);
|
||||
|
||||
// Create an IMFAsyncResult, this is passed back to the caller as a token to
|
||||
// retrieve the number of bytes read.
|
||||
RefPtr<IMFAsyncResult> callersResult;
|
||||
HRESULT hr = wmf::MFCreateAsyncResult(requestState,
|
||||
aCallback,
|
||||
aCallerState,
|
||||
byRef(callersResult));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// Dispatch an event to perform the read in the thread pool.
|
||||
nsCOMPtr<nsIRunnable> r = new ProcessReadRequestEvent(this,
|
||||
callersResult,
|
||||
requestState);
|
||||
nsresult rv = mThreadPool->Dispatch(r, NS_DISPATCH_NORMAL);
|
||||
|
||||
if (mResource->GetLength() > -1) {
|
||||
mOffset = std::min<int64_t>(mOffset + aLength, mResource->GetLength());
|
||||
} else {
|
||||
mOffset += aLength;
|
||||
}
|
||||
|
||||
return NS_SUCCEEDED(rv) ? S_OK : E_FAIL;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WMFByteStream::Read(ReadRequest* aRequestState)
|
||||
{
|
||||
// Read in a loop to ensure we fill the buffer, when possible.
|
||||
ULONG totalBytesRead = 0;
|
||||
nsresult rv = NS_OK;
|
||||
while (totalBytesRead < aRequestState->mBufferLength) {
|
||||
BYTE* buffer = aRequestState->mBuffer + totalBytesRead;
|
||||
ULONG bytesRead = 0;
|
||||
ULONG length = aRequestState->mBufferLength - totalBytesRead;
|
||||
rv = mResource->ReadAt(aRequestState->mOffset + totalBytesRead,
|
||||
reinterpret_cast<char*>(buffer),
|
||||
length,
|
||||
reinterpret_cast<uint32_t*>(&bytesRead));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
totalBytesRead += bytesRead;
|
||||
if (bytesRead == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
aRequestState->mBytesRead = totalBytesRead;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note: This is called on one of the thread pool's threads.
|
||||
void
|
||||
WMFByteStream::ProcessReadRequest(IMFAsyncResult* aResult,
|
||||
ReadRequest* aRequestState)
|
||||
{
|
||||
if (mResource->GetLength() > -1 &&
|
||||
aRequestState->mOffset > mResource->GetLength()) {
|
||||
aResult->SetStatus(S_OK);
|
||||
wmf::MFInvokeCallback(aResult);
|
||||
WMF_BS_LOG("[%p] WMFByteStream::ProcessReadRequest() read offset greater than length, soft-failing read", this);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = Read(aRequestState);
|
||||
if (NS_FAILED(rv)) {
|
||||
Shutdown();
|
||||
aResult->SetStatus(E_ABORT);
|
||||
} else {
|
||||
aResult->SetStatus(S_OK);
|
||||
}
|
||||
|
||||
WMF_BS_LOG("[%p] WMFByteStream::ProcessReadRequest() read %d at %lld finished rv=%x",
|
||||
this, aRequestState->mBytesRead, aRequestState->mOffset, rv);
|
||||
|
||||
// Let caller know read is complete.
|
||||
DebugOnly<HRESULT> hr = wmf::MFInvokeCallback(aResult);
|
||||
NS_ASSERTION(SUCCEEDED(hr), "Failed to invoke callback!");
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::BeginWrite(const BYTE *, ULONG ,
|
||||
IMFAsyncCallback *,
|
||||
IUnknown *)
|
||||
{
|
||||
WMF_BS_LOG("[%p] WMFByteStream::BeginWrite()", this);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::Close()
|
||||
{
|
||||
WMF_BS_LOG("[%p] WMFByteStream::Close()", this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::EndRead(IMFAsyncResult* aResult, ULONG *aBytesRead)
|
||||
{
|
||||
NS_ENSURE_TRUE(aResult, E_POINTER);
|
||||
NS_ENSURE_TRUE(aBytesRead, E_POINTER);
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
// Extract our state object.
|
||||
RefPtr<IUnknown> unknown;
|
||||
HRESULT hr = aResult->GetObject(byRef(unknown));
|
||||
if (FAILED(hr) || !unknown) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
ReadRequest* requestState =
|
||||
static_cast<ReadRequest*>(unknown.get());
|
||||
|
||||
// Report result.
|
||||
*aBytesRead = requestState->mBytesRead;
|
||||
|
||||
WMF_BS_LOG("[%p] WMFByteStream::EndRead() offset=%lld *aBytesRead=%u mOffset=%lld status=0x%x hr=0x%x eof=%d",
|
||||
this, requestState->mOffset, *aBytesRead, mOffset, aResult->GetStatus(), hr, IsEOS());
|
||||
|
||||
return aResult->GetStatus();
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::EndWrite(IMFAsyncResult *, ULONG *)
|
||||
{
|
||||
WMF_BS_LOG("[%p] WMFByteStream::EndWrite()", this);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::Flush()
|
||||
{
|
||||
WMF_BS_LOG("[%p] WMFByteStream::Flush()", this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetCapabilities(DWORD *aCapabilities)
|
||||
{
|
||||
WMF_BS_LOG("[%p] WMFByteStream::GetCapabilities()", this);
|
||||
NS_ENSURE_TRUE(aCapabilities, E_POINTER);
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
bool seekable = mResource->IsTransportSeekable();
|
||||
bool cached = mResource->IsDataCachedToEndOfResource(0);
|
||||
*aCapabilities = MFBYTESTREAM_IS_READABLE |
|
||||
MFBYTESTREAM_IS_SEEKABLE |
|
||||
(!cached ? MFBYTESTREAM_IS_PARTIALLY_DOWNLOADED : 0) |
|
||||
(!seekable ? MFBYTESTREAM_HAS_SLOW_SEEK : 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetCurrentPosition(QWORD *aPosition)
|
||||
{
|
||||
NS_ENSURE_TRUE(aPosition, E_POINTER);
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
// Note: Returning the length of stream as position when read
|
||||
// cursor is < 0 seems to be the behaviour expected by WMF, but
|
||||
// also note it doesn't seem to expect that the position is an
|
||||
// unsigned value since if you seek to > length and read WMF
|
||||
// expects the read to succeed after reading 0 bytes, but if you
|
||||
// seek to < 0 and read, the read is expected to fails... So
|
||||
// go figure...
|
||||
*aPosition = mOffset < 0 ? mResource->GetLength() : mOffset;
|
||||
WMF_BS_LOG("[%p] WMFByteStream::GetCurrentPosition() %lld", this, mOffset);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetLength(QWORD *aLength)
|
||||
{
|
||||
NS_ENSURE_TRUE(aLength, E_POINTER);
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
*aLength = mResource->GetLength();
|
||||
WMF_BS_LOG("[%p] WMFByteStream::GetLength() %lld", this, *aLength);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
WMFByteStream::IsEOS()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mResource->GetLength() > -1 &&
|
||||
(mOffset < 0 ||
|
||||
mOffset >= mResource->GetLength());
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::IsEndOfStream(BOOL *aEndOfStream)
|
||||
{
|
||||
NS_ENSURE_TRUE(aEndOfStream, E_POINTER);
|
||||
*aEndOfStream = IsEOS();
|
||||
WMF_BS_LOG("[%p] WMFByteStream::IsEndOfStream() %d", this, *aEndOfStream);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::Read(BYTE* aBuffer, ULONG aBufferLength, ULONG* aOutBytesRead)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
nsRefPtr<ReadRequest> request = new ReadRequest(mOffset, aBuffer, aBufferLength);
|
||||
if (NS_FAILED(Read(request))) {
|
||||
WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld failed!", this, mOffset);
|
||||
return E_FAIL;
|
||||
}
|
||||
if (aOutBytesRead) {
|
||||
*aOutBytesRead = request->mBytesRead;
|
||||
}
|
||||
WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld length=%u bytesRead=%u",
|
||||
this, mOffset, aBufferLength, request->mBytesRead);
|
||||
mOffset += request->mBytesRead;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::Seek(MFBYTESTREAM_SEEK_ORIGIN aSeekOrigin,
|
||||
LONGLONG aSeekOffset,
|
||||
DWORD aSeekFlags,
|
||||
QWORD *aCurrentPosition)
|
||||
{
|
||||
WMF_BS_LOG("[%p] WMFByteStream::Seek(%d, %lld)", this, aSeekOrigin, aSeekOffset);
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
int64_t offset = mOffset;
|
||||
if (aSeekOrigin == msoBegin) {
|
||||
offset = aSeekOffset;
|
||||
} else {
|
||||
offset += aSeekOffset;
|
||||
}
|
||||
int64_t length = mResource->GetLength();
|
||||
if (length > -1) {
|
||||
mOffset = std::min<int64_t>(offset, length);
|
||||
} else {
|
||||
mOffset = offset;
|
||||
}
|
||||
if (aCurrentPosition) {
|
||||
*aCurrentPosition = mOffset;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetCurrentPosition(QWORD aPosition)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
WMF_BS_LOG("[%p] WMFByteStream::SetCurrentPosition(%lld)",
|
||||
this, aPosition);
|
||||
|
||||
int64_t length = mResource->GetLength();
|
||||
if (length > -1) {
|
||||
mOffset = std::min<int64_t>(aPosition, length);
|
||||
} else {
|
||||
mOffset = aPosition;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetLength(QWORD)
|
||||
{
|
||||
WMF_BS_LOG("[%p] WMFByteStream::SetLength()", this);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::Write(const BYTE *, ULONG, ULONG *)
|
||||
{
|
||||
WMF_BS_LOG("[%p] WMFByteStream::Write()", this);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// IMFAttributes methods
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetItem(REFGUID guidKey, PROPVARIANT* pValue)
|
||||
{
|
||||
MOZ_ASSERT(mAttributes);
|
||||
return mAttributes->GetItem(guidKey, pValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetItemType(guidKey, pType);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->CompareItem(guidKey, Value, pbResult);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::Compare(IMFAttributes* pTheirs,
|
||||
MF_ATTRIBUTES_MATCH_TYPE MatchType,
|
||||
BOOL* pbResult)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->Compare(pTheirs, MatchType, pbResult);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetUINT32(REFGUID guidKey, UINT32* punValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetUINT32(guidKey, punValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetUINT64(REFGUID guidKey, UINT64* punValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetUINT64(guidKey, punValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetDouble(REFGUID guidKey, double* pfValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetDouble(guidKey, pfValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetGUID(REFGUID guidKey, GUID* pguidValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetGUID(guidKey, pguidValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetStringLength(REFGUID guidKey, UINT32* pcchLength)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetStringLength(guidKey, pcchLength);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetBlobSize(guidKey, pcbBlobSize);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetUnknown(guidKey, riid, ppv);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetItem(REFGUID guidKey, REFPROPVARIANT Value)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->SetItem(guidKey, Value);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::DeleteItem(REFGUID guidKey)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->DeleteItem(guidKey);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::DeleteAllItems()
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->DeleteAllItems();
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetUINT32(REFGUID guidKey, UINT32 unValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->SetUINT32(guidKey, unValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetUINT64(REFGUID guidKey,UINT64 unValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->SetUINT64(guidKey, unValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetDouble(REFGUID guidKey, double fValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->SetDouble(guidKey, fValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetGUID(REFGUID guidKey, REFGUID guidValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->SetGUID(guidKey, guidValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetString(REFGUID guidKey, LPCWSTR wszValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->SetString(guidKey, wszValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->SetBlob(guidKey, pBuf, cbBufSize);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::SetUnknown(REFGUID guidKey, IUnknown* pUnknown)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->SetUnknown(guidKey, pUnknown);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::LockStore()
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->LockStore();
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::UnlockStore()
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->UnlockStore();
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetCount(UINT32* pcItems)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetCount(pcItems);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->GetItemByIndex(unIndex, pguidKey, pValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFByteStream::CopyAllItems(IMFAttributes* pDest)
|
||||
{
|
||||
assert(mAttributes);
|
||||
return mAttributes->CopyAllItems(pDest);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,162 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#if !defined(WMFByteStream_h_)
|
||||
#define WMFByteStream_h_
|
||||
|
||||
#include "WMF.h"
|
||||
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaResource;
|
||||
class ReadRequest;
|
||||
class WMFSourceReaderCallback;
|
||||
class SharedThreadPool;
|
||||
|
||||
// Wraps a MediaResource around an IMFByteStream interface, so that it can
|
||||
// be used by the IMFSourceReader. Each WMFByteStream creates a WMF Work Queue
|
||||
// on which blocking I/O is performed. The SourceReader requests reads
|
||||
// asynchronously using {Begin,End}Read(), and more rarely synchronously
|
||||
// using Read().
|
||||
//
|
||||
// Note: This implementation attempts to be bug-compatible with Windows Media
|
||||
// Foundation's implementation of IMFByteStream. The behaviour of WMF's
|
||||
// IMFByteStream was determined by creating it and testing the edge cases.
|
||||
// For details see the test code at:
|
||||
// https://github.com/cpearce/IMFByteStreamBehaviour/
|
||||
class WMFByteStream final : public IMFByteStream
|
||||
, public IMFAttributes
|
||||
{
|
||||
~WMFByteStream();
|
||||
|
||||
public:
|
||||
WMFByteStream(MediaResource* aResource, WMFSourceReaderCallback* aCallback);
|
||||
|
||||
nsresult Init();
|
||||
nsresult Shutdown();
|
||||
|
||||
// IUnknown Methods.
|
||||
STDMETHODIMP QueryInterface(REFIID aIId, LPVOID *aInterface);
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IMFByteStream Methods.
|
||||
STDMETHODIMP BeginRead(BYTE *aBuffer,
|
||||
ULONG aLength,
|
||||
IMFAsyncCallback *aCallback,
|
||||
IUnknown *aCallerState);
|
||||
STDMETHODIMP BeginWrite(const BYTE *, ULONG ,
|
||||
IMFAsyncCallback *,
|
||||
IUnknown *);
|
||||
STDMETHODIMP Close();
|
||||
STDMETHODIMP EndRead(IMFAsyncResult* aResult, ULONG *aBytesRead);
|
||||
STDMETHODIMP EndWrite(IMFAsyncResult *, ULONG *);
|
||||
STDMETHODIMP Flush();
|
||||
STDMETHODIMP GetCapabilities(DWORD *aCapabilities);
|
||||
STDMETHODIMP GetCurrentPosition(QWORD *aPosition);
|
||||
STDMETHODIMP GetLength(QWORD *pqwLength);
|
||||
STDMETHODIMP IsEndOfStream(BOOL *aIsEndOfStream);
|
||||
STDMETHODIMP Read(BYTE *, ULONG, ULONG *);
|
||||
STDMETHODIMP Seek(MFBYTESTREAM_SEEK_ORIGIN aSeekOrigin,
|
||||
LONGLONG aSeekOffset,
|
||||
DWORD aSeekFlags,
|
||||
QWORD *aCurrentPosition);
|
||||
STDMETHODIMP SetCurrentPosition(QWORD aPosition);
|
||||
STDMETHODIMP SetLength(QWORD);
|
||||
STDMETHODIMP Write(const BYTE *, ULONG, ULONG *);
|
||||
|
||||
// IMFAttributes methods
|
||||
STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT* pValue);
|
||||
STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType);
|
||||
STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult);
|
||||
STDMETHODIMP Compare(IMFAttributes* pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, BOOL* pbResult);
|
||||
STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32* punValue);
|
||||
STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64* punValue);
|
||||
STDMETHODIMP GetDouble(REFGUID guidKey, double* pfValue);
|
||||
STDMETHODIMP GetGUID(REFGUID guidKey, GUID* pguidValue);
|
||||
STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32* pcchLength);
|
||||
STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength);
|
||||
STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength);
|
||||
STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize);
|
||||
STDMETHODIMP GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize);
|
||||
STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize);
|
||||
STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv);
|
||||
STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value);
|
||||
STDMETHODIMP DeleteItem(REFGUID guidKey);
|
||||
STDMETHODIMP DeleteAllItems();
|
||||
STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue);
|
||||
STDMETHODIMP SetUINT64(REFGUID guidKey,UINT64 unValue);
|
||||
STDMETHODIMP SetDouble(REFGUID guidKey, double fValue);
|
||||
STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue);
|
||||
STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue);
|
||||
STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize);
|
||||
STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown* pUnknown);
|
||||
STDMETHODIMP LockStore();
|
||||
STDMETHODIMP UnlockStore();
|
||||
STDMETHODIMP GetCount(UINT32* pcItems);
|
||||
STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue);
|
||||
STDMETHODIMP CopyAllItems(IMFAttributes* pDest);
|
||||
|
||||
// We perform an async read operation in this callback implementation.
|
||||
// Processes an async read request, storing the result in aResult, and
|
||||
// notifying the caller when the read operation is complete.
|
||||
void ProcessReadRequest(IMFAsyncResult* aResult,
|
||||
ReadRequest* aRequestState);
|
||||
|
||||
private:
|
||||
|
||||
// Locks the MediaResource and performs the read. The other read methods
|
||||
// call this function.
|
||||
nsresult Read(ReadRequest* aRequestState);
|
||||
|
||||
// Returns true if the current position of the stream is at end of stream.
|
||||
bool IsEOS();
|
||||
|
||||
// Reference to the thread pool in which we perform the reads asynchronously.
|
||||
// Note this is pool is shared amongst all active WMFByteStreams.
|
||||
RefPtr<SharedThreadPool> mThreadPool;
|
||||
|
||||
// Reference to the source reader's callback. We use this reference to
|
||||
// notify threads waiting on a ReadSample() callback to stop waiting
|
||||
// if the stream is closed, which happens when the media element is
|
||||
// shutdown.
|
||||
RefPtr<WMFSourceReaderCallback> mSourceReaderCallback;
|
||||
|
||||
// Resource we're wrapping.
|
||||
nsRefPtr<MediaResource> mResource;
|
||||
|
||||
// Protects mOffset, which is accessed by the SourceReaders thread(s), and
|
||||
// on the work queue thread.
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
// Current offset of the logical read cursor. We maintain this separately
|
||||
// from the media resource's offset since a partially complete read (in Invoke())
|
||||
// would leave the resource's offset at a value unexpected by the caller,
|
||||
// since the read hadn't yet completed.
|
||||
int64_t mOffset;
|
||||
|
||||
// We implement IMFAttributes by forwarding all calls to an instance of the
|
||||
// standard IMFAttributes class, which we store a reference to here.
|
||||
RefPtr<IMFAttributes> mAttributes;
|
||||
|
||||
// True if the resource has been shutdown, either because the WMFReader is
|
||||
// shutting down, or because the underlying MediaResource has closed.
|
||||
bool mIsShutdown;
|
||||
|
||||
// IUnknown ref counting.
|
||||
ThreadSafeAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -1,142 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WMF.h"
|
||||
#include "WMFDecoder.h"
|
||||
#include "WMFReader.h"
|
||||
#include "WMFUtils.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
#include "DirectShowDecoder.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MediaDecoderStateMachine* WMFDecoder::CreateStateMachine()
|
||||
{
|
||||
return new MediaDecoderStateMachine(this, new WMFReader(this));
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
WMFDecoder::IsMP3Supported()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
if (!MediaDecoder::IsWMFEnabled()) {
|
||||
return false;
|
||||
}
|
||||
// MP3 works fine in WMF on Windows Vista and Windows 8.
|
||||
if (!IsWin7OrLater()) {
|
||||
return true;
|
||||
}
|
||||
// MP3 support is disabled if we're on Windows 7 and no service packs are
|
||||
// installed, since it's crashy. Win7 with service packs is not so crashy,
|
||||
// so we enable it there. Note we prefer DirectShow for MP3 playback, but
|
||||
// we still support MP3 in MP4 via WMF, or MP3 in WMF if DirectShow is
|
||||
// disabled.
|
||||
return IsWin7SP1OrLater();
|
||||
}
|
||||
|
||||
static bool
|
||||
IsSupportedH264Codec(const nsAString& aCodec)
|
||||
{
|
||||
// According to the WMF documentation:
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx
|
||||
// "The Media Foundation H.264 video decoder is a Media Foundation Transform
|
||||
// that supports decoding of Baseline, Main, and High profiles, up to level
|
||||
// 5.1.". We also report that we can play Extended profile, as there are
|
||||
// bitstreams that are Extended compliant that are also Baseline compliant.
|
||||
|
||||
int16_t profile = 0, level = 0;
|
||||
if (!ExtractH264CodecDetails(aCodec, profile, level)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return level >= H264_LEVEL_1 &&
|
||||
level <= H264_LEVEL_5_1 &&
|
||||
(profile == H264_PROFILE_BASE ||
|
||||
profile == H264_PROFILE_MAIN ||
|
||||
profile == H264_PROFILE_EXTENDED ||
|
||||
profile == H264_PROFILE_HIGH);
|
||||
}
|
||||
|
||||
bool
|
||||
WMFDecoder::CanPlayType(const nsACString& aType,
|
||||
const nsAString& aCodecs)
|
||||
{
|
||||
if (!MediaDecoder::IsWMFEnabled() ||
|
||||
NS_FAILED(LoadDLLs())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assume that if LoadDLLs() didn't fail, we can playback the types that
|
||||
// we know should be supported by Windows Media Foundation.
|
||||
if ((aType.EqualsASCII("audio/mpeg") || aType.EqualsASCII("audio/mp3")) &&
|
||||
IsMP3Supported()) {
|
||||
// Note: We block MP3 playback on Window 7 SP0 since it seems to crash
|
||||
// in some circumstances.
|
||||
return !aCodecs.Length() || aCodecs.EqualsASCII("mp3");
|
||||
}
|
||||
|
||||
// AAC-LC or MP3 in M4A.
|
||||
if (aType.EqualsASCII("audio/mp4") || aType.EqualsASCII("audio/x-m4a")) {
|
||||
return !aCodecs.Length() ||
|
||||
aCodecs.EqualsASCII("mp4a.40.2") ||
|
||||
aCodecs.EqualsASCII("mp3");
|
||||
}
|
||||
|
||||
if (!aType.EqualsASCII("video/mp4")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// H.264 + AAC in MP4. Verify that all the codecs specifed are ones that
|
||||
// we expect that we can play.
|
||||
nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
|
||||
bool expectMoreTokens = false;
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsSubstring& token = tokenizer.nextToken();
|
||||
expectMoreTokens = tokenizer.separatorAfterCurrentToken();
|
||||
if (token.EqualsASCII("mp4a.40.2") || // AAC-LC
|
||||
token.EqualsASCII("mp3") ||
|
||||
IsSupportedH264Codec(token)) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (expectMoreTokens) {
|
||||
// Last codec name was empty
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WMFDecoder::LoadDLLs()
|
||||
{
|
||||
return SUCCEEDED(wmf::LoadDLLs()) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void
|
||||
WMFDecoder::UnloadDLLs()
|
||||
{
|
||||
wmf::UnloadDLLs();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
WMFDecoder::IsEnabled()
|
||||
{
|
||||
// We only use WMF on Windows Vista and up
|
||||
return IsVistaOrLater() &&
|
||||
Preferences::GetBool("media.windows-media-foundation.enabled");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -1,51 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#if !defined(WMFDecoder_h_)
|
||||
#define WMFDecoder_h_
|
||||
|
||||
#include "MediaDecoder.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Decoder that uses Windows Media Foundation to playback H.264/AAC in MP4
|
||||
// and M4A files, and MP3 files if the DirectShow backend is disabled.
|
||||
// Playback is strictly limited to only those codecs.
|
||||
class WMFDecoder : public MediaDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
virtual MediaDecoder* Clone() {
|
||||
if (!IsWMFEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return new WMFDecoder();
|
||||
}
|
||||
|
||||
virtual MediaDecoderStateMachine* CreateStateMachine();
|
||||
|
||||
// Loads the DLLs required by Windows Media Foundation. If this returns
|
||||
// failure, you can assume that WMF is not available on the user's system.
|
||||
static nsresult LoadDLLs();
|
||||
static void UnloadDLLs();
|
||||
|
||||
// Returns true if the WMF backend is preffed on, and we're running on a
|
||||
// version of Windows which is likely to support WMF.
|
||||
static bool IsEnabled();
|
||||
|
||||
// Returns true if MP3 decoding is enabled on this system. We block
|
||||
// MP3 playback on Windows 7 SP0, since it's crashy on that platform.
|
||||
static bool IsMP3Supported();
|
||||
|
||||
// Returns the HTMLMediaElement.canPlayType() result for the mime type
|
||||
// and codecs parameter. aCodecs can be empty.
|
||||
static bool CanPlayType(const nsACString& aType,
|
||||
const nsAString& aCodecs);
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -1,929 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WMFReader.h"
|
||||
#include "WMFDecoder.h"
|
||||
#include "WMFUtils.h"
|
||||
#include "WMFByteStream.h"
|
||||
#include "WMFSourceReaderCallback.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "DXVA2Manager.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "Layers.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
|
||||
#ifndef MOZ_SAMPLE_TYPE_FLOAT32
|
||||
#error We expect 32bit float audio samples on desktop for the Windows Media Foundation media backend.
|
||||
#endif
|
||||
|
||||
#include "MediaDecoder.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "gfx2DGlue.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::media;
|
||||
using mozilla::layers::Image;
|
||||
using mozilla::layers::LayerManager;
|
||||
using mozilla::layers::LayersBackend;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern PRLogModuleInfo* gMediaDecoderLog;
|
||||
#define DECODER_LOG(...) MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
// Uncomment to enable verbose per-sample logging.
|
||||
//#define LOG_SAMPLE_DECODE 1
|
||||
|
||||
WMFReader::WMFReader(AbstractMediaDecoder* aDecoder)
|
||||
: MediaDecoderReader(aDecoder),
|
||||
mSourceReader(nullptr),
|
||||
mAudioChannels(0),
|
||||
mAudioBytesPerSample(0),
|
||||
mAudioRate(0),
|
||||
mVideoWidth(0),
|
||||
mVideoHeight(0),
|
||||
mVideoStride(0),
|
||||
mAudioFrameOffset(0),
|
||||
mAudioFrameSum(0),
|
||||
mMustRecaptureAudioPosition(true),
|
||||
mHasAudio(false),
|
||||
mHasVideo(false),
|
||||
mUseHwAccel(false),
|
||||
mIsMP3Enabled(WMFDecoder::IsMP3Supported()),
|
||||
mCOMInitialized(false)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
|
||||
MOZ_COUNT_CTOR(WMFReader);
|
||||
}
|
||||
|
||||
WMFReader::~WMFReader()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
|
||||
|
||||
// Note: We must shutdown the byte stream before calling MFShutdown, else we
|
||||
// get assertion failures when unlocking the byte stream's work queue.
|
||||
if (mByteStream) {
|
||||
DebugOnly<nsresult> rv = mByteStream->Shutdown();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to shutdown WMFByteStream");
|
||||
}
|
||||
DebugOnly<HRESULT> hr = wmf::MFShutdown();
|
||||
NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
|
||||
MOZ_COUNT_DTOR(WMFReader);
|
||||
}
|
||||
|
||||
bool
|
||||
WMFReader::InitializeDXVA()
|
||||
{
|
||||
if (gfxWindowsPlatform::GetPlatform()->IsWARP() ||
|
||||
!gfxPlatform::CanUseHardwareVideoDecoding()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mDecoder->GetImageContainer());
|
||||
|
||||
// Extract the layer manager backend type so that we can determine
|
||||
// whether it's worthwhile using DXVA. If we're not running with a D3D
|
||||
// layer manager then the readback of decoded video frames from GPU to
|
||||
// CPU memory grinds painting to a halt, and makes playback performance
|
||||
// *worse*.
|
||||
MediaDecoderOwner* owner = mDecoder->GetOwner();
|
||||
NS_ENSURE_TRUE(owner, false);
|
||||
|
||||
dom::HTMLMediaElement* element = owner->GetMediaElement();
|
||||
NS_ENSURE_TRUE(element, false);
|
||||
|
||||
nsRefPtr<LayerManager> layerManager =
|
||||
nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
|
||||
NS_ENSURE_TRUE(layerManager, false);
|
||||
|
||||
LayersBackend backend = layerManager->GetCompositorBackendType();
|
||||
if (backend != LayersBackend::LAYERS_D3D9 &&
|
||||
backend != LayersBackend::LAYERS_D3D11) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mDXVA2Manager = DXVA2Manager::CreateD3D9DXVA();
|
||||
|
||||
return mDXVA2Manager != nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WMFReader::Init(MediaDecoderReader* aCloneDonor)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
|
||||
|
||||
nsresult rv = WMFDecoder::LoadDLLs();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (FAILED(wmf::MFStartup())) {
|
||||
NS_WARNING("Failed to initialize Windows Media Foundation");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mSourceReaderCallback = new WMFSourceReaderCallback();
|
||||
|
||||
// Must be created on main thread.
|
||||
mByteStream = new WMFByteStream(mDecoder->GetResource(), mSourceReaderCallback);
|
||||
rv = mByteStream->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mDecoder->GetImageContainer() != nullptr &&
|
||||
IsVideoContentType(mDecoder->GetResource()->GetContentType())) {
|
||||
mUseHwAccel = InitializeDXVA();
|
||||
} else {
|
||||
mUseHwAccel = false;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
WMFReader::HasAudio()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
return mHasAudio;
|
||||
}
|
||||
|
||||
bool
|
||||
WMFReader::HasVideo()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
return mHasVideo;
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
ConfigureSourceReaderStream(IMFSourceReader *aReader,
|
||||
const DWORD aStreamIndex,
|
||||
const GUID& aOutputSubType,
|
||||
const GUID* aAllowedInSubTypes,
|
||||
const uint32_t aNumAllowedInSubTypes)
|
||||
{
|
||||
NS_ENSURE_TRUE(aReader, E_POINTER);
|
||||
NS_ENSURE_TRUE(aAllowedInSubTypes, E_POINTER);
|
||||
|
||||
RefPtr<IMFMediaType> nativeType;
|
||||
RefPtr<IMFMediaType> type;
|
||||
HRESULT hr;
|
||||
|
||||
// Find the native format of the stream.
|
||||
hr = aReader->GetNativeMediaType(aStreamIndex, 0, byRef(nativeType));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// Get the native output subtype of the stream. This denotes the uncompressed
|
||||
// type.
|
||||
GUID subType;
|
||||
hr = nativeType->GetGUID(MF_MT_SUBTYPE, &subType);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// Ensure the input type of the media is in the allowed formats list.
|
||||
bool isSubTypeAllowed = false;
|
||||
for (uint32_t i = 0; i < aNumAllowedInSubTypes; i++) {
|
||||
if (aAllowedInSubTypes[i] == subType) {
|
||||
isSubTypeAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isSubTypeAllowed) {
|
||||
nsCString name = GetGUIDName(subType);
|
||||
DECODER_LOG("ConfigureSourceReaderStream subType=%s is not allowed to be decoded", name.get());
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Find the major type.
|
||||
GUID majorType;
|
||||
hr = nativeType->GetGUID(MF_MT_MAJOR_TYPE, &majorType);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// Define the output type.
|
||||
hr = wmf::MFCreateMediaType(byRef(type));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = type->SetGUID(MF_MT_MAJOR_TYPE, majorType);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = type->SetGUID(MF_MT_SUBTYPE, aOutputSubType);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// Set the uncompressed format. This can fail if the decoder can't produce
|
||||
// that type.
|
||||
return aReader->SetCurrentMediaType(aStreamIndex, nullptr, type);
|
||||
}
|
||||
|
||||
// Returns the duration of the resource, in microseconds.
|
||||
HRESULT
|
||||
GetSourceReaderDuration(IMFSourceReader *aReader,
|
||||
int64_t& aOutDuration)
|
||||
{
|
||||
AutoPropVar var;
|
||||
HRESULT hr = aReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE,
|
||||
MF_PD_DURATION,
|
||||
&var);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// WMF stores duration in hundred nanosecond units.
|
||||
int64_t duration_hns = 0;
|
||||
hr = wmf::PropVariantToInt64(var, &duration_hns);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
aOutDuration = HNsToUsecs(duration_hns);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GetSourceReaderCanSeek(IMFSourceReader* aReader, bool& aOutCanSeek)
|
||||
{
|
||||
NS_ENSURE_TRUE(aReader, E_FAIL);
|
||||
|
||||
HRESULT hr;
|
||||
AutoPropVar var;
|
||||
hr = aReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE,
|
||||
MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS,
|
||||
&var);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
ULONG flags = 0;
|
||||
hr = wmf::PropVariantToUInt32(var, &flags);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
aOutCanSeek = ((flags & MFMEDIASOURCE_CAN_SEEK) == MFMEDIASOURCE_CAN_SEEK);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFReader::ConfigureVideoFrameGeometry(IMFMediaType* aMediaType)
|
||||
{
|
||||
NS_ENSURE_TRUE(aMediaType != nullptr, E_POINTER);
|
||||
HRESULT hr;
|
||||
|
||||
// Verify that the video subtype is what we expect it to be.
|
||||
// When using hardware acceleration/DXVA2 the video format should
|
||||
// be NV12, which is DXVA2's preferred format. For software decoding
|
||||
// we use YV12, as that's easier for us to stick into our rendering
|
||||
// pipeline than NV12. NV12 has interleaved UV samples, whereas YV12
|
||||
// is a planar format.
|
||||
GUID videoFormat;
|
||||
hr = aMediaType->GetGUID(MF_MT_SUBTYPE, &videoFormat);
|
||||
NS_ENSURE_TRUE(videoFormat == MFVideoFormat_NV12 || !mUseHwAccel, E_FAIL);
|
||||
NS_ENSURE_TRUE(videoFormat == MFVideoFormat_YV12 || mUseHwAccel, E_FAIL);
|
||||
|
||||
nsIntRect pictureRegion;
|
||||
hr = GetPictureRegion(aMediaType, pictureRegion);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
UINT32 width = 0, height = 0;
|
||||
hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
uint32_t aspectNum = 0, aspectDenom = 0;
|
||||
hr = MFGetAttributeRatio(aMediaType,
|
||||
MF_MT_PIXEL_ASPECT_RATIO,
|
||||
&aspectNum,
|
||||
&aspectDenom);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// Calculate and validate the picture region and frame dimensions after
|
||||
// scaling by the pixel aspect ratio.
|
||||
nsIntSize frameSize = nsIntSize(width, height);
|
||||
nsIntSize displaySize = nsIntSize(pictureRegion.width, pictureRegion.height);
|
||||
ScaleDisplayByAspectRatio(displaySize, float(aspectNum) / float(aspectDenom));
|
||||
if (!IsValidVideoRegion(frameSize, pictureRegion, displaySize)) {
|
||||
// Video track's frame sizes will overflow. Ignore the video track.
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Success! Save state.
|
||||
mInfo.mVideo.mDisplay = displaySize;
|
||||
GetDefaultStride(aMediaType, &mVideoStride);
|
||||
mVideoWidth = width;
|
||||
mVideoHeight = height;
|
||||
mPictureRegion = pictureRegion;
|
||||
|
||||
DECODER_LOG("WMFReader frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d) PAR=%d:%d",
|
||||
width, height,
|
||||
mVideoStride,
|
||||
mPictureRegion.x, mPictureRegion.y, mPictureRegion.width, mPictureRegion.height,
|
||||
displaySize.width, displaySize.height,
|
||||
aspectNum, aspectDenom);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFReader::ConfigureVideoDecoder()
|
||||
{
|
||||
NS_ASSERTION(mSourceReader, "Must have a SourceReader before configuring decoders!");
|
||||
|
||||
// Determine if we have video.
|
||||
if (!mSourceReader ||
|
||||
!SourceReaderHasStream(mSourceReader, MF_SOURCE_READER_FIRST_VIDEO_STREAM)) {
|
||||
// No stream, no error.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!mDecoder->GetImageContainer()) {
|
||||
// We can't display the video, so don't bother to decode; disable the stream.
|
||||
return mSourceReader->SetStreamSelection(MF_SOURCE_READER_FIRST_VIDEO_STREAM, FALSE);
|
||||
}
|
||||
|
||||
static const GUID MP4VideoTypes[] = {
|
||||
MFVideoFormat_H264
|
||||
};
|
||||
HRESULT hr = ConfigureSourceReaderStream(mSourceReader,
|
||||
MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
mUseHwAccel ? MFVideoFormat_NV12 : MFVideoFormat_YV12,
|
||||
MP4VideoTypes,
|
||||
ArrayLength(MP4VideoTypes));
|
||||
if (FAILED(hr)) {
|
||||
DECODER_LOG("Failed to configured video output");
|
||||
return hr;
|
||||
}
|
||||
|
||||
RefPtr<IMFMediaType> mediaType;
|
||||
hr = mSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
byRef(mediaType));
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to get configured video media type");
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (FAILED(ConfigureVideoFrameGeometry(mediaType))) {
|
||||
NS_WARNING("Failed configured video frame dimensions");
|
||||
return hr;
|
||||
}
|
||||
|
||||
DECODER_LOG("Successfully configured video stream");
|
||||
|
||||
mHasVideo = true;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WMFReader::GetSupportedAudioCodecs(const GUID** aCodecs, uint32_t* aNumCodecs)
|
||||
{
|
||||
MOZ_ASSERT(aCodecs);
|
||||
MOZ_ASSERT(aNumCodecs);
|
||||
|
||||
if (mIsMP3Enabled) {
|
||||
GUID aacOrMp3 = MFMPEG4Format_Base;
|
||||
aacOrMp3.Data1 = 0x6D703461;// FOURCC('m','p','4','a');
|
||||
static const GUID codecs[] = {
|
||||
MFAudioFormat_AAC,
|
||||
MFAudioFormat_MP3,
|
||||
aacOrMp3
|
||||
};
|
||||
*aCodecs = codecs;
|
||||
*aNumCodecs = ArrayLength(codecs);
|
||||
} else {
|
||||
static const GUID codecs[] = {
|
||||
MFAudioFormat_AAC
|
||||
};
|
||||
*aCodecs = codecs;
|
||||
*aNumCodecs = ArrayLength(codecs);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFReader::ConfigureAudioDecoder()
|
||||
{
|
||||
NS_ASSERTION(mSourceReader, "Must have a SourceReader before configuring decoders!");
|
||||
|
||||
if (!mSourceReader ||
|
||||
!SourceReaderHasStream(mSourceReader, MF_SOURCE_READER_FIRST_AUDIO_STREAM)) {
|
||||
// No stream, no error.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const GUID* codecs;
|
||||
uint32_t numCodecs = 0;
|
||||
GetSupportedAudioCodecs(&codecs, &numCodecs);
|
||||
|
||||
HRESULT hr = ConfigureSourceReaderStream(mSourceReader,
|
||||
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
|
||||
MFAudioFormat_Float,
|
||||
codecs,
|
||||
numCodecs);
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to configure WMF Audio decoder for PCM output");
|
||||
return hr;
|
||||
}
|
||||
|
||||
RefPtr<IMFMediaType> mediaType;
|
||||
hr = mSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
|
||||
byRef(mediaType));
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to get configured audio media type");
|
||||
return hr;
|
||||
}
|
||||
|
||||
mAudioRate = MFGetAttributeUINT32(mediaType, MF_MT_AUDIO_SAMPLES_PER_SECOND, 0);
|
||||
mAudioChannels = MFGetAttributeUINT32(mediaType, MF_MT_AUDIO_NUM_CHANNELS, 0);
|
||||
mAudioBytesPerSample = MFGetAttributeUINT32(mediaType, MF_MT_AUDIO_BITS_PER_SAMPLE, 16) / 8;
|
||||
|
||||
mInfo.mAudio.mChannels = mAudioChannels;
|
||||
mInfo.mAudio.mRate = mAudioRate;
|
||||
mHasAudio = true;
|
||||
|
||||
DECODER_LOG("Successfully configured audio stream. rate=%u channels=%u bitsPerSample=%u",
|
||||
mAudioRate, mAudioChannels, mAudioBytesPerSample);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFReader::CreateSourceReader()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
RefPtr<IMFAttributes> attr;
|
||||
hr = wmf::MFCreateAttributes(byRef(attr), 1);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, mSourceReaderCallback);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
if (mUseHwAccel) {
|
||||
hr = attr->SetUnknown(MF_SOURCE_READER_D3D_MANAGER,
|
||||
mDXVA2Manager->GetDXVADeviceManager());
|
||||
if (FAILED(hr)) {
|
||||
DECODER_LOG("Failed to set DXVA2 D3D Device manager on source reader attributes");
|
||||
mUseHwAccel = false;
|
||||
}
|
||||
}
|
||||
|
||||
hr = wmf::MFCreateSourceReaderFromByteStream(mByteStream, attr, byRef(mSourceReader));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = ConfigureVideoDecoder();
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = ConfigureAudioDecoder();
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
if (mUseHwAccel && mInfo.HasVideo()) {
|
||||
RefPtr<IMFTransform> videoDecoder;
|
||||
hr = mSourceReader->GetServiceForStream(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
GUID_NULL,
|
||||
IID_IMFTransform,
|
||||
(void**)(IMFTransform**)(byRef(videoDecoder)));
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
ULONG_PTR manager = ULONG_PTR(mDXVA2Manager->GetDXVADeviceManager());
|
||||
hr = videoDecoder->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER,
|
||||
manager);
|
||||
if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
|
||||
// Ignore MF_E_TRANSFORM_TYPE_NOT_SET. Vista returns this here
|
||||
// on some, perhaps all, video cards. This may be because activating
|
||||
// DXVA changes the available output types. It seems to be safe to
|
||||
// ignore this error.
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
DECODER_LOG("Failed to set DXVA2 D3D Device manager on decoder hr=0x%x", hr);
|
||||
mUseHwAccel = false;
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WMFReader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
DECODER_LOG("WMFReader::ReadMetadata()");
|
||||
HRESULT hr;
|
||||
|
||||
const bool triedToInitDXVA = mUseHwAccel;
|
||||
if (FAILED(CreateSourceReader())) {
|
||||
mSourceReader = nullptr;
|
||||
if (triedToInitDXVA && !mUseHwAccel) {
|
||||
// We tried to initialize DXVA and failed. Try again to create the
|
||||
// IMFSourceReader but this time we won't use DXVA. Note that we
|
||||
// must recreate the IMFSourceReader from scratch, as on some systems
|
||||
// (AMD Radeon 3000) we cannot successfully reconfigure an existing
|
||||
// reader to not use DXVA after we've failed to configure DXVA.
|
||||
// See bug 987127.
|
||||
if (FAILED(CreateSourceReader())) {
|
||||
mSourceReader = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mSourceReader) {
|
||||
NS_WARNING("Failed to create IMFSourceReader");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mInfo.HasVideo()) {
|
||||
DECODER_LOG("Using DXVA: %s", (mUseHwAccel ? "Yes" : "No"));
|
||||
}
|
||||
|
||||
// Abort if both video and audio failed to initialize.
|
||||
NS_ENSURE_TRUE(mInfo.HasValidMedia(), NS_ERROR_FAILURE);
|
||||
|
||||
// Get the duration, and report it to the decoder if we have it.
|
||||
int64_t duration = 0;
|
||||
hr = GetSourceReaderDuration(mSourceReader, duration);
|
||||
if (SUCCEEDED(hr)) {
|
||||
mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration));
|
||||
}
|
||||
|
||||
*aInfo = mInfo;
|
||||
*aTags = nullptr;
|
||||
// aTags can be retrieved using techniques like used here:
|
||||
// http://blogs.msdn.com/b/mf/archive/2010/01/12/mfmediapropdump.aspx
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
WMFReader::IsMediaSeekable()
|
||||
{
|
||||
// Get the duration
|
||||
int64_t duration = 0;
|
||||
HRESULT hr = GetSourceReaderDuration(mSourceReader, duration);
|
||||
// We can seek if we get a duration *and* the reader reports that it's
|
||||
// seekable.
|
||||
bool canSeek = false;
|
||||
if (FAILED(hr) || FAILED(GetSourceReaderCanSeek(mSourceReader, canSeek)) ||
|
||||
!canSeek) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WMFReader::DecodeAudioData()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
HRESULT hr;
|
||||
hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
|
||||
0, // control flags
|
||||
0, // read stream index
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
DECODER_LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x", hr);
|
||||
// End the stream.
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD flags = 0;
|
||||
LONGLONG timestampHns = 0;
|
||||
RefPtr<IMFSample> sample;
|
||||
hr = mSourceReaderCallback->Wait(&flags, ×tampHns, byRef(sample));
|
||||
if (FAILED(hr) ||
|
||||
(flags & MF_SOURCE_READERF_ERROR) ||
|
||||
(flags & MF_SOURCE_READERF_ENDOFSTREAM) ||
|
||||
(flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) {
|
||||
DECODER_LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x flags=0x%x",
|
||||
hr, flags);
|
||||
// End the stream.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sample) {
|
||||
// Not enough data? Try again...
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<IMFMediaBuffer> buffer;
|
||||
hr = sample->ConvertToContiguousBuffer(byRef(buffer));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
|
||||
|
||||
BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it.
|
||||
DWORD maxLength = 0, currentLength = 0;
|
||||
hr = buffer->Lock(&data, &maxLength, ¤tLength);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
|
||||
|
||||
uint32_t numFrames = currentLength / mAudioBytesPerSample / mAudioChannels;
|
||||
NS_ASSERTION(sizeof(AudioDataValue) == mAudioBytesPerSample, "Size calculation is wrong");
|
||||
nsAutoArrayPtr<AudioDataValue> pcmSamples(new AudioDataValue[numFrames * mAudioChannels]);
|
||||
memcpy(pcmSamples.get(), data, currentLength);
|
||||
buffer->Unlock();
|
||||
|
||||
// We calculate the timestamp and the duration based on the number of audio
|
||||
// frames we've already played. We don't trust the timestamp stored on the
|
||||
// IMFSample, as sometimes it's wrong, possibly due to buggy encoders?
|
||||
|
||||
// If this sample block comes after a discontinuity (i.e. a gap or seek)
|
||||
// reset the frame counters, and capture the timestamp. Future timestamps
|
||||
// will be offset from this block's timestamp.
|
||||
UINT32 discontinuity = false;
|
||||
sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity);
|
||||
if (mMustRecaptureAudioPosition || discontinuity) {
|
||||
mAudioFrameSum = 0;
|
||||
hr = HNsToFrames(timestampHns, mAudioRate, &mAudioFrameOffset);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
|
||||
mMustRecaptureAudioPosition = false;
|
||||
}
|
||||
|
||||
int64_t timestamp;
|
||||
hr = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate, ×tamp);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
|
||||
|
||||
mAudioFrameSum += numFrames;
|
||||
|
||||
int64_t duration;
|
||||
hr = FramesToUsecs(numFrames, mAudioRate, &duration);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
|
||||
|
||||
mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(),
|
||||
timestamp,
|
||||
duration,
|
||||
numFrames,
|
||||
pcmSamples.forget(),
|
||||
mAudioChannels,
|
||||
mAudioRate));
|
||||
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
DECODER_LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
|
||||
timestamp, duration, currentLength);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFReader::CreateBasicVideoFrame(IMFSample* aSample,
|
||||
int64_t aTimestampUsecs,
|
||||
int64_t aDurationUsecs,
|
||||
int64_t aOffsetBytes,
|
||||
VideoData** aOutVideoData)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSample, E_POINTER);
|
||||
NS_ENSURE_TRUE(aOutVideoData, E_POINTER);
|
||||
|
||||
*aOutVideoData = nullptr;
|
||||
|
||||
HRESULT hr;
|
||||
RefPtr<IMFMediaBuffer> buffer;
|
||||
|
||||
// Must convert to contiguous buffer to use IMD2DBuffer interface.
|
||||
hr = aSample->ConvertToContiguousBuffer(byRef(buffer));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// Try and use the IMF2DBuffer interface if available, otherwise fallback
|
||||
// to the IMFMediaBuffer interface. Apparently IMF2DBuffer is more efficient,
|
||||
// but only some systems (Windows 8?) support it.
|
||||
BYTE* data = nullptr;
|
||||
LONG stride = 0;
|
||||
RefPtr<IMF2DBuffer> twoDBuffer;
|
||||
hr = buffer->QueryInterface(static_cast<IMF2DBuffer**>(byRef(twoDBuffer)));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = twoDBuffer->Lock2D(&data, &stride);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
} else {
|
||||
hr = buffer->Lock(&data, nullptr, nullptr);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
stride = mVideoStride;
|
||||
}
|
||||
|
||||
// YV12, planar format: [YYYY....][VVVV....][UUUU....]
|
||||
// i.e., Y, then V, then U.
|
||||
VideoData::YCbCrBuffer b;
|
||||
|
||||
// Y (Y') plane
|
||||
b.mPlanes[0].mData = data;
|
||||
b.mPlanes[0].mStride = stride;
|
||||
b.mPlanes[0].mHeight = mVideoHeight;
|
||||
b.mPlanes[0].mWidth = mVideoWidth;
|
||||
b.mPlanes[0].mOffset = 0;
|
||||
b.mPlanes[0].mSkip = 0;
|
||||
|
||||
// The V and U planes are stored 16-row-aligned, so we need to add padding
|
||||
// to the row heights to ensure the Y'CbCr planes are referenced properly.
|
||||
uint32_t padding = 0;
|
||||
if (mVideoHeight % 16 != 0) {
|
||||
padding = 16 - (mVideoHeight % 16);
|
||||
}
|
||||
uint32_t y_size = stride * (mVideoHeight + padding);
|
||||
uint32_t v_size = stride * (mVideoHeight + padding) / 4;
|
||||
uint32_t halfStride = (stride + 1) / 2;
|
||||
uint32_t halfHeight = (mVideoHeight + 1) / 2;
|
||||
uint32_t halfWidth = (mVideoWidth + 1) / 2;
|
||||
|
||||
// U plane (Cb)
|
||||
b.mPlanes[1].mData = data + y_size + v_size;
|
||||
b.mPlanes[1].mStride = halfStride;
|
||||
b.mPlanes[1].mHeight = halfHeight;
|
||||
b.mPlanes[1].mWidth = halfWidth;
|
||||
b.mPlanes[1].mOffset = 0;
|
||||
b.mPlanes[1].mSkip = 0;
|
||||
|
||||
// V plane (Cr)
|
||||
b.mPlanes[2].mData = data + y_size;
|
||||
b.mPlanes[2].mStride = halfStride;
|
||||
b.mPlanes[2].mHeight = halfHeight;
|
||||
b.mPlanes[2].mWidth = halfWidth;
|
||||
b.mPlanes[2].mOffset = 0;
|
||||
b.mPlanes[2].mSkip = 0;
|
||||
|
||||
nsRefPtr<VideoData> v = VideoData::Create(mInfo.mVideo,
|
||||
mDecoder->GetImageContainer(),
|
||||
aOffsetBytes,
|
||||
aTimestampUsecs,
|
||||
aDurationUsecs,
|
||||
b,
|
||||
false,
|
||||
-1,
|
||||
mPictureRegion);
|
||||
if (twoDBuffer) {
|
||||
twoDBuffer->Unlock2D();
|
||||
} else {
|
||||
buffer->Unlock();
|
||||
}
|
||||
|
||||
v.forget(aOutVideoData);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFReader::CreateD3DVideoFrame(IMFSample* aSample,
|
||||
int64_t aTimestampUsecs,
|
||||
int64_t aDurationUsecs,
|
||||
int64_t aOffsetBytes,
|
||||
VideoData** aOutVideoData)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSample, E_POINTER);
|
||||
NS_ENSURE_TRUE(aOutVideoData, E_POINTER);
|
||||
NS_ENSURE_TRUE(mDXVA2Manager, E_ABORT);
|
||||
NS_ENSURE_TRUE(mUseHwAccel, E_ABORT);
|
||||
|
||||
*aOutVideoData = nullptr;
|
||||
HRESULT hr;
|
||||
|
||||
nsRefPtr<Image> image;
|
||||
hr = mDXVA2Manager->CopyToImage(aSample,
|
||||
mPictureRegion,
|
||||
mDecoder->GetImageContainer(),
|
||||
getter_AddRefs(image));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
NS_ENSURE_TRUE(image, E_FAIL);
|
||||
|
||||
nsRefPtr<VideoData> v = VideoData::CreateFromImage(mInfo.mVideo,
|
||||
mDecoder->GetImageContainer(),
|
||||
aOffsetBytes,
|
||||
aTimestampUsecs,
|
||||
aDurationUsecs,
|
||||
image.forget(),
|
||||
false,
|
||||
-1,
|
||||
mPictureRegion);
|
||||
|
||||
NS_ENSURE_TRUE(v, E_FAIL);
|
||||
v.forget(aOutVideoData);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
0, // control flags
|
||||
0, // read stream index
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
if (FAILED(hr)) {
|
||||
DECODER_LOG("WMFReader::DecodeVideoData() ReadSample failed with hr=0x%x", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD flags = 0;
|
||||
LONGLONG timestampHns = 0;
|
||||
RefPtr<IMFSample> sample;
|
||||
hr = mSourceReaderCallback->Wait(&flags, ×tampHns, byRef(sample));
|
||||
|
||||
if (flags & MF_SOURCE_READERF_ERROR) {
|
||||
NS_WARNING("WMFReader: Catastrophic failure reading video sample");
|
||||
// Future ReadSample() calls will fail, so give up and report end of stream.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// Unknown failure, ask caller to try again?
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!sample) {
|
||||
if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) {
|
||||
DECODER_LOG("WMFReader; Null sample after video decode, at end of stream");
|
||||
return false;
|
||||
}
|
||||
DECODER_LOG("WMFReader; Null sample after video decode. Maybe insufficient data...");
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) {
|
||||
DECODER_LOG("WMFReader: Video media type changed!");
|
||||
RefPtr<IMFMediaType> mediaType;
|
||||
hr = mSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
byRef(mediaType));
|
||||
if (FAILED(hr) ||
|
||||
FAILED(ConfigureVideoFrameGeometry(mediaType))) {
|
||||
NS_WARNING("Failed to reconfigure video media type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t timestamp = HNsToUsecs(timestampHns);
|
||||
if (timestamp < aTimeThreshold) {
|
||||
return true;
|
||||
}
|
||||
int64_t offset = mDecoder->GetResource()->Tell();
|
||||
int64_t duration = GetSampleDuration(sample);
|
||||
|
||||
VideoData* v = nullptr;
|
||||
if (mUseHwAccel) {
|
||||
hr = CreateD3DVideoFrame(sample, timestamp, duration, offset, &v);
|
||||
} else {
|
||||
hr = CreateBasicVideoFrame(sample, timestamp, duration, offset, &v);
|
||||
}
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr) && v, false);
|
||||
|
||||
a.mParsed++;
|
||||
a.mDecoded++;
|
||||
mVideoQueue.Push(v);
|
||||
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
DECODER_LOG("Decoded video sample timestamp=%lld duration=%lld stride=%d height=%u flags=%u",
|
||||
timestamp, duration, mVideoStride, mVideoHeight, flags);
|
||||
#endif
|
||||
|
||||
if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) {
|
||||
// End of stream.
|
||||
DECODER_LOG("End of video stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDecoderReader::SeekPromise>
|
||||
WMFReader::Seek(int64_t aTargetUs, int64_t aEndTime)
|
||||
{
|
||||
nsresult res = SeekInternal(aTargetUs);
|
||||
if (NS_FAILED(res)) {
|
||||
return SeekPromise::CreateAndReject(res, __func__);
|
||||
} else {
|
||||
return SeekPromise::CreateAndResolve(aTargetUs, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
WMFReader::SeekInternal(int64_t aTargetUs)
|
||||
{
|
||||
DECODER_LOG("WMFReader::Seek() %lld", aTargetUs);
|
||||
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
#ifdef DEBUG
|
||||
bool canSeek = false;
|
||||
GetSourceReaderCanSeek(mSourceReader, canSeek);
|
||||
NS_ASSERTION(canSeek, "WMFReader::Seek() should only be called if we can seek!");
|
||||
#endif
|
||||
|
||||
nsresult rv = ResetDecode();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Mark that we must recapture the audio frame count from the next sample.
|
||||
// WMF doesn't set a discontinuity marker when we seek to time 0, so we
|
||||
// must remember to recapture the audio frame offset and reset the frame
|
||||
// sum on the next audio packet we decode.
|
||||
mMustRecaptureAudioPosition = true;
|
||||
|
||||
AutoPropVar var;
|
||||
HRESULT hr = InitPropVariantFromInt64(UsecsToHNs(aTargetUs), &var);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
|
||||
|
||||
hr = mSourceReader->SetCurrentPosition(GUID_NULL, var);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,114 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#if !defined(WMFReader_h_)
|
||||
#define WMFReader_h_
|
||||
|
||||
#include "WMF.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WMFByteStream;
|
||||
class WMFSourceReaderCallback;
|
||||
class DXVA2Manager;
|
||||
|
||||
// Decoder backend for reading H.264/AAC in MP4/M4A, and MP3 files using
|
||||
// Windows Media Foundation.
|
||||
class WMFReader : public MediaDecoderReader
|
||||
{
|
||||
public:
|
||||
WMFReader(AbstractMediaDecoder* aDecoder);
|
||||
|
||||
virtual ~WMFReader();
|
||||
|
||||
nsresult Init(MediaDecoderReader* aCloneDonor) override;
|
||||
|
||||
bool DecodeAudioData() override;
|
||||
bool DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold) override;
|
||||
|
||||
bool HasAudio() override;
|
||||
bool HasVideo() override;
|
||||
|
||||
nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags) override;
|
||||
|
||||
nsRefPtr<SeekPromise>
|
||||
Seek(int64_t aTime, int64_t aEndTime) override;
|
||||
|
||||
bool IsMediaSeekable() override;
|
||||
|
||||
private:
|
||||
|
||||
HRESULT CreateSourceReader();
|
||||
HRESULT ConfigureAudioDecoder();
|
||||
HRESULT ConfigureVideoDecoder();
|
||||
HRESULT ConfigureVideoFrameGeometry(IMFMediaType* aMediaType);
|
||||
void GetSupportedAudioCodecs(const GUID** aCodecs, uint32_t* aNumCodecs);
|
||||
|
||||
HRESULT CreateBasicVideoFrame(IMFSample* aSample,
|
||||
int64_t aTimestampUsecs,
|
||||
int64_t aDurationUsecs,
|
||||
int64_t aOffsetBytes,
|
||||
VideoData** aOutVideoData);
|
||||
|
||||
HRESULT CreateD3DVideoFrame(IMFSample* aSample,
|
||||
int64_t aTimestampUsecs,
|
||||
int64_t aDurationUsecs,
|
||||
int64_t aOffsetBytes,
|
||||
VideoData** aOutVideoData);
|
||||
|
||||
// Attempt to initialize DXVA. Returns true on success.
|
||||
bool InitializeDXVA();
|
||||
|
||||
nsresult SeekInternal(int64_t aTime);
|
||||
|
||||
RefPtr<IMFSourceReader> mSourceReader;
|
||||
RefPtr<WMFByteStream> mByteStream;
|
||||
RefPtr<WMFSourceReaderCallback> mSourceReaderCallback;
|
||||
nsAutoPtr<DXVA2Manager> mDXVA2Manager;
|
||||
|
||||
// Region inside the video frame that makes up the picture. Pixels outside
|
||||
// of this region should not be rendered.
|
||||
nsIntRect mPictureRegion;
|
||||
|
||||
uint32_t mAudioChannels;
|
||||
uint32_t mAudioBytesPerSample;
|
||||
uint32_t mAudioRate;
|
||||
|
||||
uint32_t mVideoWidth;
|
||||
uint32_t mVideoHeight;
|
||||
uint32_t mVideoStride;
|
||||
|
||||
// The offset, in audio frames, at which playback started since the
|
||||
// last discontinuity.
|
||||
int64_t mAudioFrameOffset;
|
||||
// The number of audio frames that we've played since the last
|
||||
// discontinuity.
|
||||
int64_t mAudioFrameSum;
|
||||
// True if we need to re-initialize mAudioFrameOffset and mAudioFrameSum
|
||||
// from the next audio packet we decode. This happens after a seek, since
|
||||
// WMF doesn't mark a stream as having a discontinuity after a seek(0).
|
||||
bool mMustRecaptureAudioPosition;
|
||||
|
||||
bool mHasAudio;
|
||||
bool mHasVideo;
|
||||
bool mUseHwAccel;
|
||||
|
||||
// We can't call WMFDecoder::IsMP3Supported() on non-main threads, since it
|
||||
// checks a pref, so we cache its value in mIsMP3Enabled and use that on
|
||||
// the decode thread.
|
||||
const bool mIsMP3Enabled;
|
||||
|
||||
bool mCOMInitialized;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -1,151 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WMFSourceReaderCallback.h"
|
||||
#include "WMFUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static PRLogModuleInfo* gWMFSourceReaderCallbackLog = nullptr;
|
||||
#define WMF_CB_LOG(...) MOZ_LOG(gWMFSourceReaderCallbackLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
// IUnknown Methods
|
||||
STDMETHODIMP
|
||||
WMFSourceReaderCallback::QueryInterface(REFIID aIId, void **aInterface)
|
||||
{
|
||||
WMF_CB_LOG("WMFSourceReaderCallback::QueryInterface %s", GetGUIDName(aIId).get());
|
||||
|
||||
if (aIId == IID_IMFSourceReaderCallback) {
|
||||
return DoGetInterface(static_cast<WMFSourceReaderCallback*>(this), aInterface);
|
||||
}
|
||||
if (aIId == IID_IUnknown) {
|
||||
return DoGetInterface(static_cast<WMFSourceReaderCallback*>(this), aInterface);
|
||||
}
|
||||
|
||||
*aInterface = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(WMFSourceReaderCallback)
|
||||
NS_IMPL_RELEASE(WMFSourceReaderCallback)
|
||||
|
||||
WMFSourceReaderCallback::WMFSourceReaderCallback()
|
||||
: mMonitor("WMFSourceReaderCallback")
|
||||
, mResultStatus(S_OK)
|
||||
, mStreamFlags(0)
|
||||
, mTimestamp(0)
|
||||
, mSample(nullptr)
|
||||
, mReadFinished(false)
|
||||
{
|
||||
if (!gWMFSourceReaderCallbackLog) {
|
||||
gWMFSourceReaderCallbackLog = PR_NewLogModule("WMFSourceReaderCallback");
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFSourceReaderCallback::NotifyReadComplete(HRESULT aReadStatus,
|
||||
DWORD aStreamIndex,
|
||||
DWORD aStreamFlags,
|
||||
LONGLONG aTimestamp,
|
||||
IMFSample *aSample)
|
||||
{
|
||||
// Note: aSample can be nullptr on success if more data is required!
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
|
||||
if (mSample) {
|
||||
// The WMFReader should have called Wait() to retrieve the last
|
||||
// sample returned by the last ReadSample() call, but if we're
|
||||
// aborting the read before Wait() is called the sample ref
|
||||
// can be non-null.
|
||||
mSample->Release();
|
||||
mSample = nullptr;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(aReadStatus)) {
|
||||
if (aSample) {
|
||||
mTimestamp = aTimestamp;
|
||||
mSample = aSample;
|
||||
mSample->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
mResultStatus = aReadStatus;
|
||||
mStreamFlags = aStreamFlags;
|
||||
|
||||
// Set the sentinal value and notify the monitor, so that threads waiting
|
||||
// in Wait() are awoken.
|
||||
mReadFinished = true;
|
||||
mon.NotifyAll();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFSourceReaderCallback::OnReadSample(HRESULT aReadStatus,
|
||||
DWORD aStreamIndex,
|
||||
DWORD aStreamFlags,
|
||||
LONGLONG aTimestamp,
|
||||
IMFSample *aSample)
|
||||
{
|
||||
WMF_CB_LOG("WMFSourceReaderCallback::OnReadSample() hr=0x%x flags=0x%x time=%lld sample=%p",
|
||||
aReadStatus, aStreamFlags, aTimestamp, aSample);
|
||||
return NotifyReadComplete(aReadStatus,
|
||||
aStreamIndex,
|
||||
aStreamFlags,
|
||||
aTimestamp,
|
||||
aSample);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFSourceReaderCallback::Cancel()
|
||||
{
|
||||
WMF_CB_LOG("WMFSourceReaderCallback::Cancel()");
|
||||
return NotifyReadComplete(E_ABORT,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFSourceReaderCallback::OnEvent(DWORD, IMFMediaEvent *)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
WMFSourceReaderCallback::OnFlush(DWORD)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFSourceReaderCallback::Wait(DWORD* aStreamFlags,
|
||||
LONGLONG* aTimeStamp,
|
||||
IMFSample** aSample)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
WMF_CB_LOG("WMFSourceReaderCallback::Wait() starting wait");
|
||||
while (!mReadFinished) {
|
||||
mon.Wait();
|
||||
}
|
||||
mReadFinished = false;
|
||||
WMF_CB_LOG("WMFSourceReaderCallback::Wait() done waiting");
|
||||
|
||||
*aStreamFlags = mStreamFlags;
|
||||
*aTimeStamp = mTimestamp;
|
||||
*aSample = mSample;
|
||||
HRESULT hr = mResultStatus;
|
||||
|
||||
mSample = nullptr;
|
||||
mTimestamp = 0;
|
||||
mStreamFlags = 0;
|
||||
mResultStatus = S_OK;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,85 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#if !defined(WMFSourceReaderCallback_h_)
|
||||
#define WMFSourceReaderCallback_h_
|
||||
|
||||
#include "WMF.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// A listener which we pass into the IMFSourceReader upon creation which is
|
||||
// notified when an asynchronous call to IMFSourceReader::ReadSample()
|
||||
// completes. This allows us to abort ReadSample() operations when the
|
||||
// WMFByteStream's underlying MediaResource is closed. This ensures that
|
||||
// the decode threads don't get stuck in a synchronous ReadSample() call
|
||||
// when the MediaResource is unexpectedly shutdown.
|
||||
class WMFSourceReaderCallback final : public IMFSourceReaderCallback
|
||||
{
|
||||
~WMFSourceReaderCallback() {}
|
||||
|
||||
public:
|
||||
WMFSourceReaderCallback();
|
||||
|
||||
// IUnknown Methods.
|
||||
STDMETHODIMP QueryInterface(REFIID aIId, LPVOID *aInterface);
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IMFSourceReaderCallback methods
|
||||
STDMETHODIMP OnReadSample(HRESULT hrStatus,
|
||||
DWORD dwStreamIndex,
|
||||
DWORD dwStreamFlags,
|
||||
LONGLONG llTimestamp,
|
||||
IMFSample *pSample);
|
||||
STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *);
|
||||
STDMETHODIMP OnFlush(DWORD);
|
||||
|
||||
// Causes the calling thread to block waiting for the
|
||||
// IMFSourceReader::ReadSample() result callback to occur, or for the
|
||||
// WMFByteStream to be closed.
|
||||
HRESULT Wait(DWORD* aStreamFlags,
|
||||
LONGLONG* aTimeStamp,
|
||||
IMFSample** aSample);
|
||||
|
||||
// Cancels Wait() calls.
|
||||
HRESULT Cancel();
|
||||
|
||||
private:
|
||||
|
||||
// Sets state to record the result of a read, and awake threads
|
||||
// waiting in Wait().
|
||||
HRESULT NotifyReadComplete(HRESULT aReadStatus,
|
||||
DWORD aStreamIndex,
|
||||
DWORD aStreamFlags,
|
||||
LONGLONG aTimestamp,
|
||||
IMFSample *aSample);
|
||||
|
||||
// Synchronizes all member data in this class, and Wait() blocks on
|
||||
// and NotifyReadComplete() notifies this monitor.
|
||||
ReentrantMonitor mMonitor;
|
||||
|
||||
// Read result data.
|
||||
HRESULT mResultStatus;
|
||||
DWORD mStreamFlags;
|
||||
LONGLONG mTimestamp;
|
||||
IMFSample* mSample;
|
||||
|
||||
// Sentinal. Set to true when a read result is returned. Wait() won't exit
|
||||
// until this is set to true.
|
||||
bool mReadFinished;
|
||||
|
||||
// IUnknown ref counting.
|
||||
ThreadSafeAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // WMFSourceReaderCallback_h_
|
@ -1,698 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WMFUtils.h"
|
||||
#include <stdint.h>
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "VideoUtils.h"
|
||||
#include <initguid.h>
|
||||
|
||||
#ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
|
||||
// Some SDK versions don't define the AAC decoder CLSID.
|
||||
// {32D186A7-218F-4C75-8876-DD77273A8999}
|
||||
DEFINE_GUID(CLSID_CMSAACDecMFT, 0x32D186A7, 0x218F, 0x4C75, 0x88, 0x76, 0xDD, 0x77, 0x27, 0x3A, 0x89, 0x99);
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct GuidToName {
|
||||
GUID guid;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
#define GUID_TO_NAME_ENTRY(g) { g, #g }
|
||||
#define INTERFACE_TO_NAME_ENTRY(i) {IID_##i, #i }
|
||||
|
||||
GuidToName GuidToNameTable[] = {
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MAJOR_TYPE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MAJOR_TYPE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_SUBTYPE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_ALL_SAMPLES_INDEPENDENT),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_FIXED_SIZE_SAMPLES),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_COMPRESSED),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_SAMPLE_SIZE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_WRAPPED_TYPE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_NUM_CHANNELS),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_SAMPLES_PER_SECOND),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_AVG_BYTES_PER_SECOND),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_BLOCK_ALIGNMENT),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_BITS_PER_SAMPLE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_VALID_BITS_PER_SAMPLE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_SAMPLES_PER_BLOCK),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_CHANNEL_MASK),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_FOLDDOWN_MATRIX),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_PEAKREF),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_PEAKTARGET),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_AVGREF),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_AVGTARGET),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AUDIO_PREFER_WAVEFORMATEX),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AAC_PAYLOAD_TYPE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_FRAME_SIZE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_FRAME_RATE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_FRAME_RATE_RANGE_MAX),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_FRAME_RATE_RANGE_MIN),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_PIXEL_ASPECT_RATIO),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_DRM_FLAGS),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_PAD_CONTROL_FLAGS),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_SOURCE_CONTENT_HINT),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_VIDEO_CHROMA_SITING),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_INTERLACE_MODE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_TRANSFER_FUNCTION),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_VIDEO_PRIMARIES),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_CUSTOM_VIDEO_PRIMARIES),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_YUV_MATRIX),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_VIDEO_LIGHTING),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_VIDEO_NOMINAL_RANGE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_GEOMETRIC_APERTURE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MINIMUM_DISPLAY_APERTURE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_PAN_SCAN_APERTURE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_PAN_SCAN_ENABLED),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AVG_BITRATE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AVG_BIT_ERROR_RATE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MAX_KEYFRAME_SPACING),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_DEFAULT_STRIDE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_PALETTE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_USER_DATA),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_AM_FORMAT_TYPE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MPEG_START_TIME_CODE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MPEG2_PROFILE),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MPEG2_LEVEL),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MPEG2_FLAGS),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MPEG_SEQUENCE_HEADER),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_SRC_PACK_0),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_CTRL_PACK_0),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_SRC_PACK_1),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_CTRL_PACK_1),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_DV_VAUX_SRC_PACK),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_DV_VAUX_CTRL_PACK),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_ARBITRARY_HEADER),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_ARBITRARY_FORMAT),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_IMAGE_LOSS_TOLERANT),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MPEG4_SAMPLE_DESCRIPTION),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_ORIGINAL_4CC),
|
||||
GUID_TO_NAME_ENTRY(MF_MT_ORIGINAL_WAVE_FORMAT_TAG),
|
||||
|
||||
GUID_TO_NAME_ENTRY(MFMediaType_Audio),
|
||||
GUID_TO_NAME_ENTRY(MFMediaType_Video),
|
||||
GUID_TO_NAME_ENTRY(MFMediaType_Protected),
|
||||
GUID_TO_NAME_ENTRY(MFMediaType_SAMI),
|
||||
GUID_TO_NAME_ENTRY(MFMediaType_Script),
|
||||
GUID_TO_NAME_ENTRY(MFMediaType_Image),
|
||||
GUID_TO_NAME_ENTRY(MFMediaType_HTML),
|
||||
GUID_TO_NAME_ENTRY(MFMediaType_Binary),
|
||||
GUID_TO_NAME_ENTRY(MFMediaType_FileTransfer),
|
||||
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_AI44),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_ARGB32),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_AYUV),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_DV25),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_DV50),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_DVH1),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_DVSD),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_DVSL),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_H264),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_I420),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_IYUV),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_M4S2),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_MJPG),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_MP43),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_MP4S),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_MP4V),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_MPG1),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_MSS1),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_MSS2),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_NV11),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_NV12),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_P010),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_P016),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_P210),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_P216),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_RGB24),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_RGB32),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_RGB555),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_RGB565),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_RGB8),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_UYVY),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_v210),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_v410),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_WMV1),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_WMV2),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_WMV3),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_WVC1),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_Y210),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_Y216),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_Y410),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_Y416),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_Y41P),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_Y41T),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_YUY2),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_YV12),
|
||||
GUID_TO_NAME_ENTRY(MFVideoFormat_YVYU),
|
||||
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_PCM),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_Float),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_DTS),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_Dolby_AC3_SPDIF),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_DRM),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_WMAudioV8),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_WMAudioV9),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_WMAudio_Lossless),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_WMASPDIF),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_MSP1),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_MP3),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_MPEG),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_AAC),
|
||||
GUID_TO_NAME_ENTRY(MFAudioFormat_ADTS),
|
||||
|
||||
// Interfaces which may be implemented by WMFByteStream.
|
||||
INTERFACE_TO_NAME_ENTRY(IUnknown),
|
||||
INTERFACE_TO_NAME_ENTRY(IMFByteStream),
|
||||
INTERFACE_TO_NAME_ENTRY(IMFMediaSource),
|
||||
INTERFACE_TO_NAME_ENTRY(IMFAttributes),
|
||||
INTERFACE_TO_NAME_ENTRY(IMFByteStreamBuffering),
|
||||
};
|
||||
|
||||
nsCString GetGUIDName(const GUID& guid)
|
||||
{
|
||||
const unsigned numTypes = ArrayLength(GuidToNameTable);
|
||||
for (unsigned i = 0; i < numTypes; i++) {
|
||||
if (guid == GuidToNameTable[i].guid) {
|
||||
return nsDependentCString(GuidToNameTable[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
WCHAR* name = nullptr;
|
||||
HRESULT hr = StringFromCLSID(guid , &name);
|
||||
if (FAILED(hr)) {
|
||||
return nsDependentCString("GuidUnknown");
|
||||
}
|
||||
nsCString name_u8(NS_ConvertUTF16toUTF8(nsDependentString((char16_t*)(name))));
|
||||
CoTaskMemFree(name);
|
||||
return name_u8;
|
||||
}
|
||||
|
||||
bool
|
||||
SourceReaderHasStream(IMFSourceReader* aReader, const DWORD aIndex)
|
||||
{
|
||||
RefPtr<IMFMediaType> nativeType;
|
||||
HRESULT hr = aReader->GetNativeMediaType(aIndex, 0, byRef(nativeType));
|
||||
return FAILED(hr) ? false : true;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
DoGetInterface(IUnknown* aUnknown, void** aInterface)
|
||||
{
|
||||
if (!aInterface)
|
||||
return E_POINTER;
|
||||
*aInterface = aUnknown;
|
||||
aUnknown->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames)
|
||||
{
|
||||
MOZ_ASSERT(aOutFrames);
|
||||
const int64_t HNS_PER_S = USECS_PER_S * 10;
|
||||
CheckedInt<int64_t> i = aHNs;
|
||||
i *= aRate;
|
||||
i /= HNS_PER_S;
|
||||
NS_ENSURE_TRUE(i.isValid(), E_FAIL);
|
||||
*aOutFrames = i.value();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FramesToUsecs(int64_t aSamples, uint32_t aRate, int64_t* aOutUsecs)
|
||||
{
|
||||
MOZ_ASSERT(aOutUsecs);
|
||||
CheckedInt<int64_t> i = aSamples;
|
||||
i *= USECS_PER_S;
|
||||
i /= aRate;
|
||||
NS_ENSURE_TRUE(i.isValid(), E_FAIL);
|
||||
*aOutUsecs = i.value();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
|
||||
{
|
||||
// Try to get the default stride from the media type.
|
||||
HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride);
|
||||
if (SUCCEEDED(hr)) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Stride attribute not set, calculate it.
|
||||
GUID subtype = GUID_NULL;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
|
||||
hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG*)(aOutStride));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
MFOffsetToInt32(const MFOffset& aOffset)
|
||||
{
|
||||
return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
|
||||
}
|
||||
|
||||
int64_t
|
||||
GetSampleDuration(IMFSample* aSample)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSample, -1);
|
||||
int64_t duration = 0;
|
||||
aSample->GetSampleDuration(&duration);
|
||||
return HNsToUsecs(duration);
|
||||
}
|
||||
|
||||
int64_t
|
||||
GetSampleTime(IMFSample* aSample)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSample, -1);
|
||||
LONGLONG timestampHns = 0;
|
||||
HRESULT hr = aSample->GetSampleTime(×tampHns);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), -1);
|
||||
return HNsToUsecs(timestampHns);
|
||||
}
|
||||
|
||||
// Gets the sub-region of the video frame that should be displayed.
|
||||
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
|
||||
HRESULT
|
||||
GetPictureRegion(IMFMediaType* aMediaType, nsIntRect& aOutPictureRegion)
|
||||
{
|
||||
// Determine if "pan and scan" is enabled for this media. If it is, we
|
||||
// only display a region of the video frame, not the entire frame.
|
||||
BOOL panScan = MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
|
||||
|
||||
// If pan and scan mode is enabled. Try to get the display region.
|
||||
HRESULT hr = E_FAIL;
|
||||
MFVideoArea videoArea;
|
||||
memset(&videoArea, 0, sizeof(MFVideoArea));
|
||||
if (panScan) {
|
||||
hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE,
|
||||
(UINT8*)&videoArea,
|
||||
sizeof(MFVideoArea),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
|
||||
// check for a minimimum display aperture.
|
||||
if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
|
||||
hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
|
||||
(UINT8*)&videoArea,
|
||||
sizeof(MFVideoArea),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (hr == MF_E_ATTRIBUTENOTFOUND) {
|
||||
// Minimum display aperture is not set, for "backward compatibility with
|
||||
// some components", check for a geometric aperture.
|
||||
hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE,
|
||||
(UINT8*)&videoArea,
|
||||
sizeof(MFVideoArea),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
// The media specified a picture region, return it.
|
||||
aOutPictureRegion = nsIntRect(MFOffsetToInt32(videoArea.OffsetX),
|
||||
MFOffsetToInt32(videoArea.OffsetY),
|
||||
videoArea.Area.cx,
|
||||
videoArea.Area.cy);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// No picture region defined, fall back to using the entire video area.
|
||||
UINT32 width = 0, height = 0;
|
||||
hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
aOutPictureRegion = nsIntRect(0, 0, width, height);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
namespace wmf {
|
||||
|
||||
static bool
|
||||
IsSupportedDecoder(const GUID& aDecoderGUID)
|
||||
{
|
||||
return aDecoderGUID == CLSID_CMSH264DecoderMFT ||
|
||||
aDecoderGUID == CLSID_CMSAACDecMFT ||
|
||||
aDecoderGUID == CLSID_CMP3DecMediaObject;
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
DisableBlockedDecoders(IMFPluginControl* aPluginControl,
|
||||
const GUID& aCategory)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
UINT32 numMFTs = 0;
|
||||
IMFActivate **ppActivate = nullptr;
|
||||
hr = wmf::MFTEnumEx(aCategory,
|
||||
MFT_ENUM_FLAG_ALL,
|
||||
nullptr, // Input type, nullptr -> match all.
|
||||
nullptr, // Output type, nullptr -> match all.
|
||||
&ppActivate,
|
||||
&numMFTs);
|
||||
|
||||
if (SUCCEEDED(hr) && numMFTs == 0) {
|
||||
hr = MF_E_TOPO_CODEC_NOT_FOUND;
|
||||
}
|
||||
|
||||
for (UINT32 i = 0; i < numMFTs; i++) {
|
||||
// Note: We must release all IMFActivate objects in the list, hence
|
||||
// we're putting individual IMFActivate objects in into a smart ptr.
|
||||
RefPtr<IMFActivate> activate = ppActivate[i];
|
||||
GUID guid = GUID_NULL;
|
||||
hr = activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &guid);
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("FAILED to get IMFActivate clsid");
|
||||
continue;
|
||||
}
|
||||
if (!IsSupportedDecoder(guid)) {
|
||||
hr = aPluginControl->SetDisabled(MF_Plugin_Type_MFT, guid, TRUE);
|
||||
NS_ASSERTION(SUCCEEDED(hr), "Failed to disable plugin!");
|
||||
}
|
||||
}
|
||||
CoTaskMemFree(ppActivate);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
DisableBlockedDecoders()
|
||||
{
|
||||
RefPtr<IMFPluginControl> pluginControl;
|
||||
HRESULT hr = wmf::MFGetPluginControl(byRef(pluginControl));
|
||||
if (SUCCEEDED(hr) && pluginControl) {
|
||||
hr = DisableBlockedDecoders(pluginControl,
|
||||
MFT_CATEGORY_VIDEO_DECODER);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = DisableBlockedDecoders(pluginControl,
|
||||
MFT_CATEGORY_AUDIO_DECODER);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static bool sDLLsLoaded = false;
|
||||
static bool sFailedToLoadDlls = false;
|
||||
|
||||
struct WMFModule {
|
||||
const wchar_t* name;
|
||||
HMODULE handle;
|
||||
};
|
||||
|
||||
static WMFModule sDLLs[] = {
|
||||
{ L"mfplat.dll", nullptr },
|
||||
{ L"mfreadwrite.dll", nullptr },
|
||||
{ L"propsys.dll", nullptr },
|
||||
{ L"mf.dll", nullptr },
|
||||
{ L"dxva2.dll", nullptr }
|
||||
};
|
||||
|
||||
HRESULT
|
||||
LoadDLLs()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
if (sDLLsLoaded) {
|
||||
return S_OK;
|
||||
}
|
||||
if (sFailedToLoadDlls) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Try to load all the required DLLs.
|
||||
const uint32_t dllLength = ArrayLength(sDLLs);
|
||||
for (uint32_t i = 0; i < dllLength; i++) {
|
||||
sDLLs[i].handle = LoadLibrarySystem32(sDLLs[i].name);
|
||||
if (!sDLLs[i].handle) {
|
||||
sFailedToLoadDlls = true;
|
||||
NS_WARNING("Failed to load WMF DLLs");
|
||||
UnloadDLLs();
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// Enumerate all the decoders on the system, and disable the ones except
|
||||
// those which we expect to use, the MP3, AAC and H.264 decoders.
|
||||
if (FAILED(DisableBlockedDecoders())) {
|
||||
sFailedToLoadDlls = true;
|
||||
NS_WARNING("Failed to disable non whitelisted WMF decoders");
|
||||
UnloadDLLs();
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
sDLLsLoaded = true;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
UnloadDLLs()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
const uint32_t length = ArrayLength(sDLLs);
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
if (sDLLs[i].handle) {
|
||||
FreeLibrary(sDLLs[i].handle);
|
||||
sDLLs[i].handle = nullptr;
|
||||
}
|
||||
sDLLsLoaded = false;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \
|
||||
static FunctionType FunctionName##Ptr = nullptr; \
|
||||
if (!FunctionName##Ptr) { \
|
||||
FunctionName##Ptr = (FunctionType) GetProcAddress(GetModuleHandleW(L ## #DLL), #FunctionName); \
|
||||
if (!FunctionName##Ptr) { \
|
||||
NS_WARNING("Failed to get GetProcAddress of " #FunctionName " from " #DLL); \
|
||||
return E_FAIL; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENSURE_FUNCTION_PTR(FunctionName, DLL) \
|
||||
ENSURE_FUNCTION_PTR_HELPER(decltype(::FunctionName)*, FunctionName, DLL) \
|
||||
|
||||
#define ENSURE_FUNCTION_PTR_(FunctionName, DLL) \
|
||||
ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL) \
|
||||
|
||||
#define DECL_FUNCTION_PTR(FunctionName, ...) \
|
||||
typedef HRESULT (STDMETHODCALLTYPE * FunctionName##Ptr_t)(__VA_ARGS__)
|
||||
|
||||
HRESULT
|
||||
MFStartup()
|
||||
{
|
||||
const int MF_VISTA_VERSION = (0x0001 << 16 | MF_API_VERSION);
|
||||
const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION);
|
||||
|
||||
// decltype is unusable for functions having default parameters
|
||||
DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
|
||||
ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
|
||||
if (!IsWin7OrLater())
|
||||
return MFStartupPtr(MF_VISTA_VERSION, MFSTARTUP_FULL);
|
||||
else
|
||||
return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFShutdown()
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll)
|
||||
return (MFShutdownPtr)();
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateAsyncResult(IUnknown *aUnkObject,
|
||||
IMFAsyncCallback *aCallback,
|
||||
IUnknown *aUnkState,
|
||||
IMFAsyncResult **aOutAsyncResult)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateAsyncResult, Mfplat.dll)
|
||||
return (MFCreateAsyncResultPtr)(aUnkObject, aCallback, aUnkState, aOutAsyncResult);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFInvokeCallback(IMFAsyncResult *aAsyncResult)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFInvokeCallback, Mfplat.dll);
|
||||
return (MFInvokeCallbackPtr)(aAsyncResult);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateMediaType(IMFMediaType **aOutMFType)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateMediaType, Mfplat.dll)
|
||||
return (MFCreateMediaTypePtr)(aOutMFType);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateSourceReaderFromByteStream(IMFByteStream *aByteStream,
|
||||
IMFAttributes *aAttributes,
|
||||
IMFSourceReader **aOutSourceReader)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateSourceReaderFromByteStream, Mfreadwrite.dll)
|
||||
return (MFCreateSourceReaderFromByteStreamPtr)(aByteStream,
|
||||
aAttributes,
|
||||
aOutSourceReader);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
PropVariantToUInt32(REFPROPVARIANT aPropvar, ULONG *aOutUL)
|
||||
{
|
||||
// decltype is unusable for overloaded functions
|
||||
DECL_FUNCTION_PTR(PropVariantToUInt32, REFPROPVARIANT, ULONG *);
|
||||
ENSURE_FUNCTION_PTR_(PropVariantToUInt32, Propsys.dll)
|
||||
return (PropVariantToUInt32Ptr)(aPropvar, aOutUL);
|
||||
}
|
||||
|
||||
HRESULT PropVariantToInt64(REFPROPVARIANT aPropVar, LONGLONG *aOutLL)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(PropVariantToInt64, Propsys.dll)
|
||||
return (PropVariantToInt64Ptr)(aPropVar, aOutLL);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFTGetInfo(CLSID aClsidMFT,
|
||||
LPWSTR *aOutName,
|
||||
MFT_REGISTER_TYPE_INFO **aOutInputTypes,
|
||||
UINT32 *aOutNumInputTypes,
|
||||
MFT_REGISTER_TYPE_INFO **aOutOutputTypes,
|
||||
UINT32 *aOutNumOutputTypes,
|
||||
IMFAttributes **aOutAttributes)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFTGetInfo, Mfplat.dll)
|
||||
return (MFTGetInfoPtr)(aClsidMFT,
|
||||
aOutName,
|
||||
aOutInputTypes,
|
||||
aOutNumInputTypes,
|
||||
aOutOutputTypes,
|
||||
aOutNumOutputTypes,
|
||||
aOutAttributes);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFGetStrideForBitmapInfoHeader(DWORD aFormat,
|
||||
DWORD aWidth,
|
||||
LONG *aOutStride)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFGetStrideForBitmapInfoHeader, Mfplat.dll)
|
||||
return (MFGetStrideForBitmapInfoHeaderPtr)(aFormat, aWidth, aOutStride);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateSourceReaderFromURL(LPCWSTR aURL,
|
||||
IMFAttributes *aAttributes,
|
||||
IMFSourceReader **aSourceReader)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateSourceReaderFromURL, Mfreadwrite.dll)
|
||||
return (MFCreateSourceReaderFromURLPtr)(aURL, aAttributes, aSourceReader);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateAttributes(IMFAttributes **ppMFAttributes, UINT32 cInitialSize)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateAttributes, mfplat.dll)
|
||||
return (MFCreateAttributesPtr)(ppMFAttributes, cInitialSize);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFGetPluginControl(IMFPluginControl **aOutPluginControl)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFGetPluginControl, mfplat.dll)
|
||||
return (MFGetPluginControlPtr)(aOutPluginControl);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFTEnumEx(GUID guidCategory,
|
||||
UINT32 Flags,
|
||||
const MFT_REGISTER_TYPE_INFO *pInputType,
|
||||
const MFT_REGISTER_TYPE_INFO *pOutputType,
|
||||
IMFActivate ***pppMFTActivate,
|
||||
UINT32 *pcMFTActivate)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFTEnumEx, mfplat.dll)
|
||||
return (MFTEnumExPtr)(guidCategory, Flags, pInputType, pOutputType, pppMFTActivate, pcMFTActivate);
|
||||
}
|
||||
|
||||
HRESULT MFGetService(IUnknown *punkObject,
|
||||
REFGUID guidService,
|
||||
REFIID riid,
|
||||
LPVOID *ppvObject)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFGetService, mf.dll)
|
||||
return (MFGetServicePtr)(punkObject, guidService, riid, ppvObject);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
DXVA2CreateDirect3DDeviceManager9(UINT *pResetToken,
|
||||
IDirect3DDeviceManager9 **ppDXVAManager)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, dxva2.dll)
|
||||
return (DXVA2CreateDirect3DDeviceManager9Ptr)(pResetToken, ppDXVAManager);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateSample(IMFSample **ppIMFSample)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateSample, mfplat.dll)
|
||||
return (MFCreateSamplePtr)(ppIMFSample);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateAlignedMemoryBuffer(DWORD cbMaxLength,
|
||||
DWORD fAlignmentFlags,
|
||||
IMFMediaBuffer **ppBuffer)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateAlignedMemoryBuffer, mfplat.dll)
|
||||
return (MFCreateAlignedMemoryBufferPtr)(cbMaxLength, fAlignmentFlags, ppBuffer);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateDXGIDeviceManager(UINT *pResetToken, IMFDXGIDeviceManager **ppDXVAManager)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateDXGIDeviceManager, mfplat.dll)
|
||||
return (MFCreateDXGIDeviceManagerPtr)(pResetToken, ppDXVAManager);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MFCreateDXGISurfaceBuffer(REFIID riid,
|
||||
IUnknown *punkSurface,
|
||||
UINT uSubresourceIndex,
|
||||
BOOL fButtomUpWhenLinear,
|
||||
IMFMediaBuffer **ppBuffer)
|
||||
{
|
||||
ENSURE_FUNCTION_PTR(MFCreateDXGISurfaceBuffer, mfplat.dll)
|
||||
return (MFCreateDXGISurfaceBufferPtr)(riid, punkSurface, uSubresourceIndex, fButtomUpWhenLinear, ppBuffer);
|
||||
}
|
||||
|
||||
} // end namespace wmf
|
||||
} // end namespace mozilla
|
@ -1,36 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXPORTS += [
|
||||
'DXVA2Manager.h',
|
||||
'WMF.h',
|
||||
'WMFDecoder.h',
|
||||
'WMFReader.h',
|
||||
'WMFUtils.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DXVA2Manager.cpp',
|
||||
'WMFByteStream.cpp',
|
||||
'WMFDecoder.cpp',
|
||||
'WMFReader.cpp',
|
||||
'WMFSourceReaderCallback.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'WMFUtils.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DEFINES['NOMINMAX'] = True
|
||||
|
||||
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
|
@ -1499,6 +1499,7 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result)
|
||||
}
|
||||
|
||||
dom::AutoEntryScript aes(win, "NPAPI NPN_evaluate");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj));
|
||||
|
@ -803,8 +803,11 @@ this.PushService = {
|
||||
|
||||
return this._db.put(aRecord)
|
||||
.then(_ => aRecord, error => {
|
||||
// Unable to save.
|
||||
this._sendRequest("unregister", aRecord);
|
||||
// Unable to save. Destroy the subscription in the background.
|
||||
this._sendRequest("unregister", aRecord).catch(err => {
|
||||
debug("_onRegisterSuccess: Error unregistering stale subscription" +
|
||||
err);
|
||||
});
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
@ -879,7 +882,7 @@ this.PushService = {
|
||||
* not.
|
||||
*/
|
||||
_unregister: function(aPageRecord) {
|
||||
debug("unregisterWithServer()");
|
||||
debug("_unregister()");
|
||||
|
||||
if (!aPageRecord.scope) {
|
||||
return Promise.reject({state: 0, error: "NotFoundError"});
|
||||
|
@ -951,24 +951,22 @@ this.PushServiceWebSocket = {
|
||||
}
|
||||
|
||||
if (action == "register") {
|
||||
record.channelID = this._generateID();
|
||||
}
|
||||
var data = {channelID: record.channelID,
|
||||
messageType: action};
|
||||
let data = {channelID: this._generateID(),
|
||||
messageType: action};
|
||||
|
||||
var p = new Promise((resolve, reject) => {
|
||||
this._pendingRequests[data.channelID] = {record: record,
|
||||
resolve: resolve,
|
||||
reject: reject,
|
||||
ctime: Date.now()
|
||||
};
|
||||
this._queueRequest(data);
|
||||
});
|
||||
if (action == "unregister") {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return p;
|
||||
return new Promise((resolve, reject) => {
|
||||
this._pendingRequests[data.channelID] = {record: record,
|
||||
resolve: resolve,
|
||||
reject: reject,
|
||||
ctime: Date.now()
|
||||
};
|
||||
this._queueRequest(data);
|
||||
});
|
||||
}
|
||||
|
||||
this._queueRequest({channelID: record.channelID,
|
||||
messageType: action});
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
_queueStart: Promise.resolve(),
|
||||
@ -986,13 +984,11 @@ this.PushServiceWebSocket = {
|
||||
|
||||
_send(data) {
|
||||
if (this._currentState == STATE_READY) {
|
||||
if (data.messageType == "ack") {
|
||||
if (data.messageType != "register" ||
|
||||
typeof this._pendingRequests[data.channelID] == "object") {
|
||||
|
||||
// check if request has not been cancelled
|
||||
this._wsSendMessage(data);
|
||||
} else {
|
||||
// check if request has not been canelled
|
||||
if (typeof this._pendingRequests[data.channelID] == "object") {
|
||||
this._wsSendMessage(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -669,9 +669,8 @@ class MOZ_STACK_CLASS OriginParser final
|
||||
eExpectingEmptyToken3,
|
||||
eExpectingHost,
|
||||
eExpectingPort,
|
||||
eExpectingDriveLetterOrPathnameComponent,
|
||||
eExpectingEmptyTokenOrDriveLetterOrPathnameComponent,
|
||||
eExpectingEmptyTokenOrPathnameComponent,
|
||||
eExpectingPathnameComponent,
|
||||
eComplete,
|
||||
eHandledTrailingSeparator
|
||||
};
|
||||
@ -4996,14 +4995,14 @@ void
|
||||
OriginParser::HandlePathnameComponent(const nsDependentCSubstring& aToken)
|
||||
{
|
||||
MOZ_ASSERT(!aToken.IsEmpty());
|
||||
MOZ_ASSERT(mState == eExpectingDriveLetterOrPathnameComponent ||
|
||||
mState == eExpectingEmptyTokenOrPathnameComponent ||
|
||||
mState == eExpectingPathnameComponent);
|
||||
MOZ_ASSERT(mState == eExpectingEmptyTokenOrDriveLetterOrPathnameComponent ||
|
||||
mState == eExpectingEmptyTokenOrPathnameComponent);
|
||||
MOZ_ASSERT(mSchemaType == eFile);
|
||||
|
||||
mPathnameComponents.AppendElement(aToken);
|
||||
|
||||
mState = mTokenizer.hasMoreTokens() ? eExpectingPathnameComponent : eComplete;
|
||||
mState = mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
|
||||
: eComplete;
|
||||
}
|
||||
|
||||
void
|
||||
@ -5115,9 +5114,9 @@ OriginParser::HandleToken(const nsDependentCSubstring& aToken)
|
||||
return;
|
||||
}
|
||||
|
||||
mState =
|
||||
mTokenizer.hasMoreTokens() ? eExpectingDriveLetterOrPathnameComponent
|
||||
: eComplete;
|
||||
mState = mTokenizer.hasMoreTokens()
|
||||
? eExpectingEmptyTokenOrDriveLetterOrPathnameComponent
|
||||
: eComplete;
|
||||
|
||||
return;
|
||||
}
|
||||
@ -5166,14 +5165,16 @@ OriginParser::HandleToken(const nsDependentCSubstring& aToken)
|
||||
return;
|
||||
}
|
||||
|
||||
case eExpectingDriveLetterOrPathnameComponent: {
|
||||
case eExpectingEmptyTokenOrDriveLetterOrPathnameComponent: {
|
||||
MOZ_ASSERT(mSchemaType == eFile);
|
||||
|
||||
if (aToken.IsEmpty()) {
|
||||
QM_WARNING("Expected a drive letter or pathname component "
|
||||
"(not an empty string)!");
|
||||
mPathnameComponents.AppendElement(EmptyCString());
|
||||
|
||||
mState =
|
||||
mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
|
||||
: eComplete;
|
||||
|
||||
mError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5197,28 +5198,22 @@ OriginParser::HandleToken(const nsDependentCSubstring& aToken)
|
||||
case eExpectingEmptyTokenOrPathnameComponent: {
|
||||
MOZ_ASSERT(mSchemaType == eFile);
|
||||
|
||||
if (mMaybeDriveLetter && aToken.IsEmpty()) {
|
||||
MOZ_ASSERT(mPathnameComponents.Length() == 1);
|
||||
|
||||
nsCString& pathnameComponent = mPathnameComponents[0];
|
||||
pathnameComponent.Append(':');
|
||||
|
||||
mState = mTokenizer.hasMoreTokens() ? eExpectingPathnameComponent
|
||||
: eComplete;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HandlePathnameComponent(aToken);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case eExpectingPathnameComponent: {
|
||||
if (aToken.IsEmpty()) {
|
||||
QM_WARNING("Expected a pathname component (not an empty string)!");
|
||||
if (mMaybeDriveLetter) {
|
||||
MOZ_ASSERT(mPathnameComponents.Length() == 1);
|
||||
|
||||
nsCString& pathnameComponent = mPathnameComponents[0];
|
||||
pathnameComponent.Append(':');
|
||||
|
||||
mMaybeDriveLetter = false;
|
||||
} else {
|
||||
mPathnameComponents.AppendElement(EmptyCString());
|
||||
}
|
||||
|
||||
mState =
|
||||
mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
|
||||
: eComplete;
|
||||
|
||||
mError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,9 @@ CSPService::ShouldLoad(uint32_t aContentType,
|
||||
nsIPrincipal *aRequestPrincipal,
|
||||
int16_t *aDecision)
|
||||
{
|
||||
MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
|
||||
"We should only see external content policy types here.");
|
||||
|
||||
if (!aContentLocation) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -339,6 +339,9 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
// to them.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
|
||||
"We should only see external content policy types here.");
|
||||
|
||||
// Assume active (high risk) content and blocked by default
|
||||
MixedContentTypes classification = eMixedScript;
|
||||
// Make decision to block/reject by default
|
||||
|
@ -104,6 +104,8 @@ SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded()
|
||||
|
||||
mHasLoadedNonSVGUserAgentStyleSheets = true;
|
||||
|
||||
BeginUpdate(UPDATE_STYLE);
|
||||
|
||||
if (IsBeingUsedAsImage()) {
|
||||
// nsDocumentViewer::CreateStyleSet skipped loading all user-agent/user
|
||||
// style sheets in this case, but we'll need B2G/Fennec's
|
||||
@ -165,7 +167,15 @@ SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded()
|
||||
EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::FormsSheet());
|
||||
EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::CounterStylesSheet());
|
||||
EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::HTMLSheet());
|
||||
if (nsLayoutUtils::ShouldUseNoFramesSheet(this)) {
|
||||
EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::NoFramesSheet());
|
||||
}
|
||||
if (nsLayoutUtils::ShouldUseNoScriptSheet(this)) {
|
||||
EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::NoScriptSheet());
|
||||
}
|
||||
EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::UASheet());
|
||||
|
||||
EndUpdate(UPDATE_STYLE);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -42,7 +42,7 @@ MOCHITEST_CHROME_MANIFESTS += [
|
||||
'mochitest/whatwg/chrome.ini',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gtk2':
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] not in ('gtk2', 'gtk3'):
|
||||
# Bug 788164.
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'mochitest/pointerlock/mochitest.ini',
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
typedef (Request or USVString) RequestInfo;
|
||||
typedef unsigned long nsContentPolicyType;
|
||||
|
||||
[Constructor(RequestInfo input, optional RequestInit init),
|
||||
Exposed=(Window,Worker)]
|
||||
@ -27,7 +28,7 @@ interface Request {
|
||||
|
||||
// Bug 1124638 - Allow chrome callers to set the context.
|
||||
[ChromeOnly]
|
||||
void setContext(RequestContext context);
|
||||
void setContentPolicyType(nsContentPolicyType context);
|
||||
};
|
||||
Request implements Body;
|
||||
|
||||
@ -44,8 +45,8 @@ enum RequestContext {
|
||||
"audio", "beacon", "cspreport", "download", "embed", "eventsource", "favicon", "fetch",
|
||||
"font", "form", "frame", "hyperlink", "iframe", "image", "imageset", "import",
|
||||
"internal", "location", "manifest", "object", "ping", "plugin", "prefetch", "script",
|
||||
"serviceworker", "sharedworker", "subresource", "style", "track", "video", "worker",
|
||||
"xmlhttprequest", "xslt"
|
||||
"sharedworker", "subresource", "style", "track", "video", "worker", "xmlhttprequest",
|
||||
"xslt"
|
||||
};
|
||||
|
||||
// cors-with-forced-preflight is internal to the Fetch spec, but adding it here
|
||||
|
@ -56,6 +56,18 @@ interface TestInterfaceJS {
|
||||
[Throws]
|
||||
void testThrowDOMException();
|
||||
|
||||
[Throws]
|
||||
void testThrowTypeError();
|
||||
|
||||
[Throws]
|
||||
void testThrowCallbackError(Function callback);
|
||||
|
||||
[Throws]
|
||||
void testThrowXraySelfHosted();
|
||||
|
||||
[Throws]
|
||||
void testThrowSelfHosted();
|
||||
|
||||
// Tests for promise-rejection behavior
|
||||
Promise<void> testPromiseWithThrowingChromePromiseInit();
|
||||
Promise<void> testPromiseWithThrowingContentPromiseInit(PromiseInit func);
|
||||
|
@ -406,6 +406,7 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
|
||||
// We are going to run script via EvaluateString, so we need a script entry
|
||||
// point, but as this is XBL related it does not appear in the HTML spec.
|
||||
AutoEntryScript entryScript(globalObject, "XBL <field> initialization", true);
|
||||
entryScript.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = entryScript.cx();
|
||||
|
||||
NS_ASSERTION(!::JS_IsExceptionPending(cx),
|
||||
@ -441,6 +442,12 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW) {
|
||||
// Report the exception now, before we try using the JSContext for
|
||||
// the JS_DefineUCProperty call.
|
||||
entryScript.ReportException();
|
||||
}
|
||||
|
||||
// Now, enter the node's compartment, wrap the eval result, and define it on
|
||||
// the bound node.
|
||||
JSAutoCompartment ac2(cx, aBoundNode);
|
||||
|
@ -22,7 +22,8 @@
|
||||
#define BEHAVIOR_NOFOREIGN 3
|
||||
|
||||
// From nsIContentPolicy
|
||||
static const char *kTypeString[] = {"other",
|
||||
static const char *kTypeString[] = {
|
||||
"other",
|
||||
"script",
|
||||
"image",
|
||||
"stylesheet",
|
||||
@ -43,7 +44,18 @@ static const char *kTypeString[] = {"other",
|
||||
"beacon",
|
||||
"fetch",
|
||||
"imageset",
|
||||
"manifest"};
|
||||
"manifest",
|
||||
"", // TYPE_INTERNAL_SCRIPT
|
||||
"", // TYPE_INTERNAL_WORKER
|
||||
"", // TYPE_INTERNAL_SHARED_WORKER
|
||||
"", // TYPE_INTERNAL_EMBED
|
||||
"", // TYPE_INTERNAL_OBJECT
|
||||
"", // TYPE_INTERNAL_FRAME
|
||||
"", // TYPE_INTERNAL_IFRAME
|
||||
"", // TYPE_INTERNAL_AUDIO
|
||||
"", // TYPE_INTERNAL_VIDEO
|
||||
"" // TYPE_INTERNAL_TRACK
|
||||
};
|
||||
|
||||
#define NUMBER_OF_TYPES MOZ_ARRAY_LENGTH(kTypeString)
|
||||
uint8_t nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES];
|
||||
@ -119,7 +131,8 @@ nsContentBlocker::PrefChanged(nsIPrefBranch *aPrefBranch,
|
||||
#define PREF_CHANGED(_P) (!aPref || !strcmp(aPref, _P))
|
||||
|
||||
for(uint32_t i = 0; i < NUMBER_OF_TYPES; ++i) {
|
||||
if (PREF_CHANGED(kTypeString[i]) &&
|
||||
if (*kTypeString[i] &&
|
||||
PREF_CHANGED(kTypeString[i]) &&
|
||||
NS_SUCCEEDED(aPrefBranch->GetIntPref(kTypeString[i], &val)))
|
||||
mBehaviorPref[i] = LIMIT(val, 1, 3, 1);
|
||||
}
|
||||
@ -237,6 +250,13 @@ nsContentBlocker::TestPermission(nsIURI *aCurrentURI,
|
||||
bool *aFromPrefs)
|
||||
{
|
||||
*aFromPrefs = false;
|
||||
|
||||
if (!*kTypeString[aContentType - 1]) {
|
||||
// Disallow internal content policy types, they should not be used here.
|
||||
*aPermission = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This default will also get used if there is an unknown value in the
|
||||
// permission list, or if the permission manager returns unknown values.
|
||||
*aPermission = true;
|
||||
|
@ -97,7 +97,7 @@ CopyBGRXSurfaceDataToPackedBGRArray(uint8_t* aSrc, uint8_t* aDst,
|
||||
uint8_t* dstPx = aDst;
|
||||
|
||||
for (int row = 0; row < aSrcSize.height; ++row) {
|
||||
for (int col = 0; col < aSrcSize.height; ++col) {
|
||||
for (int col = 0; col < aSrcSize.width; ++col) {
|
||||
dstPx[0] = srcPx[0];
|
||||
dstPx[1] = srcPx[1];
|
||||
dstPx[2] = srcPx[2];
|
||||
|
@ -113,13 +113,13 @@ RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
|
||||
}
|
||||
}
|
||||
|
||||
if (aOperator == CompositionOp::OP_SOURCE) {
|
||||
// OP_SOURCE is unbounded in Azure, and we really don't want that behaviour here.
|
||||
// We also can't do a ClearRect+FillRect since we need the drawing to happen
|
||||
// as an atomic operation (to prevent flickering).
|
||||
aTarget->PushClipRect(gfx::Rect(fillRect.x, fillRect.y,
|
||||
fillRect.width, fillRect.height));
|
||||
}
|
||||
// OP_SOURCE is unbounded in Azure, and we really don't want that behaviour here.
|
||||
// We also can't do a ClearRect+FillRect since we need the drawing to happen
|
||||
// as an atomic operation (to prevent flickering).
|
||||
// We also need this clip in the case where we have a mask, since the mask surface
|
||||
// might cover more than fillRect, but we only want to touch the pixels inside
|
||||
// fillRect.
|
||||
aTarget->PushClipRect(gfx::ToRect(fillRect));
|
||||
|
||||
if (aMask) {
|
||||
Matrix oldTransform = aTarget->GetTransform();
|
||||
@ -155,9 +155,7 @@ RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
|
||||
DrawOptions(aOpacity, aOperator));
|
||||
}
|
||||
|
||||
if (aOperator == CompositionOp::OP_SOURCE) {
|
||||
aTarget->PopClip();
|
||||
}
|
||||
aTarget->PopClip();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -163,18 +163,35 @@ SetDisplayPortMargins(nsIPresShell* aPresShell,
|
||||
nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base);
|
||||
}
|
||||
|
||||
void
|
||||
APZCCallbackHelper::UpdateRootFrame(nsIPresShell* aPresShell,
|
||||
FrameMetrics& aMetrics)
|
||||
static already_AddRefed<nsIPresShell>
|
||||
GetPresShell(const nsIContent* aContent)
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> result;
|
||||
if (nsIDocument* doc = aContent->GetComposedDoc()) {
|
||||
result = doc->GetShell();
|
||||
}
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void
|
||||
APZCCallbackHelper::UpdateRootFrame(FrameMetrics& aMetrics)
|
||||
{
|
||||
// Precondition checks
|
||||
MOZ_ASSERT(aPresShell);
|
||||
MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());
|
||||
if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
|
||||
return;
|
||||
}
|
||||
nsIContent* content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
float presShellResolution = nsLayoutUtils::GetResolution(aPresShell);
|
||||
nsCOMPtr<nsIPresShell> shell = GetPresShell(content);
|
||||
if (!shell || aMetrics.GetPresShellId() != shell->GetPresShellId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());
|
||||
|
||||
float presShellResolution = nsLayoutUtils::GetResolution(shell);
|
||||
|
||||
// If the pres shell resolution has changed on the content side side
|
||||
// the time this repaint request was fired, consider this request out of date
|
||||
@ -194,45 +211,39 @@ APZCCallbackHelper::UpdateRootFrame(nsIPresShell* aPresShell,
|
||||
// Note that this needs to happen before scrolling the frame (in UpdateFrameCommon),
|
||||
// otherwise the scroll position may get clamped incorrectly.
|
||||
CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels();
|
||||
nsLayoutUtils::SetScrollPositionClampingScrollPortSize(aPresShell, scrollPort);
|
||||
nsLayoutUtils::SetScrollPositionClampingScrollPortSize(shell, scrollPort);
|
||||
|
||||
// The pres shell resolution is updated by the the async zoom since the
|
||||
// last paint.
|
||||
presShellResolution = aMetrics.GetPresShellResolution()
|
||||
* aMetrics.GetAsyncZoom().scale;
|
||||
nsLayoutUtils::SetResolutionAndScaleTo(aPresShell, presShellResolution);
|
||||
nsLayoutUtils::SetResolutionAndScaleTo(shell, presShellResolution);
|
||||
|
||||
// Do this as late as possible since scrolling can flush layout. It also
|
||||
// adjusts the display port margins, so do it before we set those.
|
||||
nsIContent* content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
|
||||
ScrollFrame(content, aMetrics);
|
||||
|
||||
SetDisplayPortMargins(aPresShell, content, aMetrics);
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIPresShell>
|
||||
GetPresShell(const nsIContent* aContent)
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> result;
|
||||
if (nsIDocument* doc = aContent->GetComposedDoc()) {
|
||||
result = doc->GetShell();
|
||||
}
|
||||
return result.forget();
|
||||
SetDisplayPortMargins(shell, content, aMetrics);
|
||||
}
|
||||
|
||||
void
|
||||
APZCCallbackHelper::UpdateSubFrame(nsIContent* aContent,
|
||||
FrameMetrics& aMetrics)
|
||||
APZCCallbackHelper::UpdateSubFrame(FrameMetrics& aMetrics)
|
||||
{
|
||||
// Precondition checks
|
||||
MOZ_ASSERT(aContent);
|
||||
if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
|
||||
return;
|
||||
}
|
||||
nsIContent* content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());
|
||||
|
||||
// We don't currently support zooming for subframes, so nothing extra
|
||||
// needs to be done beyond the tasks common to this and UpdateRootFrame.
|
||||
ScrollFrame(aContent, aMetrics);
|
||||
if (nsCOMPtr<nsIPresShell> shell = GetPresShell(aContent)) {
|
||||
SetDisplayPortMargins(shell, aContent, aMetrics);
|
||||
ScrollFrame(content, aMetrics);
|
||||
if (nsCOMPtr<nsIPresShell> shell = GetPresShell(content)) {
|
||||
SetDisplayPortMargins(shell, content, aMetrics);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,23 +41,21 @@ class APZCCallbackHelper
|
||||
typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
|
||||
|
||||
public:
|
||||
/* Applies the scroll and zoom parameters from the given FrameMetrics object to
|
||||
the root frame corresponding to the given pres shell. If tiled thebes
|
||||
layers are enabled, this will align the displayport to tile boundaries.
|
||||
Setting the scroll position can cause some small adjustments to be made
|
||||
to the actual scroll position. aMetrics' display port and scroll position
|
||||
will be updated with any modifications made. */
|
||||
static void UpdateRootFrame(nsIPresShell* aPresShell,
|
||||
FrameMetrics& aMetrics);
|
||||
/* Applies the scroll and zoom parameters from the given FrameMetrics object
|
||||
to the root frame for the given metrics' scrollId. If tiled thebes layers
|
||||
are enabled, this will align the displayport to tile boundaries. Setting
|
||||
the scroll position can cause some small adjustments to be made to the
|
||||
actual scroll position. aMetrics' display port and scroll position will
|
||||
be updated with any modifications made. */
|
||||
static void UpdateRootFrame(FrameMetrics& aMetrics);
|
||||
|
||||
/* Applies the scroll parameters from the given FrameMetrics object to the subframe
|
||||
corresponding to the given content object. If tiled thebes
|
||||
/* Applies the scroll parameters from the given FrameMetrics object to the
|
||||
subframe corresponding to given metrics' scrollId. If tiled thebes
|
||||
layers are enabled, this will align the displayport to tile boundaries.
|
||||
Setting the scroll position can cause some small adjustments to be made
|
||||
to the actual scroll position. aMetrics' display port and scroll position
|
||||
will be updated with any modifications made. */
|
||||
static void UpdateSubFrame(nsIContent* aContent,
|
||||
FrameMetrics& aMetrics);
|
||||
static void UpdateSubFrame(FrameMetrics& aMetrics);
|
||||
|
||||
/* Get the presShellId and view ID for the given content element.
|
||||
* If the view ID does not exist, one is created.
|
||||
|
@ -71,14 +71,11 @@ ChromeProcessController::RequestContentRepaint(const FrameMetrics& aFrameMetrics
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (aFrameMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> targetContent = nsLayoutUtils::FindContentFor(aFrameMetrics.GetScrollId());
|
||||
if (targetContent) {
|
||||
FrameMetrics metrics = aFrameMetrics;
|
||||
APZCCallbackHelper::UpdateSubFrame(targetContent, metrics);
|
||||
FrameMetrics metrics = aFrameMetrics;
|
||||
if (metrics.IsRootContent()) {
|
||||
APZCCallbackHelper::UpdateRootFrame(metrics);
|
||||
} else {
|
||||
APZCCallbackHelper::UpdateSubFrame(metrics);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
/* 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 <limits>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
@ -371,11 +372,9 @@ TestUnion()
|
||||
static bool
|
||||
TestFiniteGfx()
|
||||
{
|
||||
// Doesn't appear that __builtin_inf() and __builtin_nan() are available on
|
||||
// all compilers, so go the old fashioned way for inf and nan.
|
||||
float posInf = 1.0/0.0;
|
||||
float negInf = -1.0/0.0;
|
||||
float justNaN = 0.0/0.0;
|
||||
float posInf = std::numeric_limits<float>::infinity();
|
||||
float negInf = -std::numeric_limits<float>::infinity();
|
||||
float justNaN = std::numeric_limits<float>::quiet_NaN();
|
||||
|
||||
gfxFloat values[4] = {5.0, 10.0, 15.0, 20.0};
|
||||
|
||||
|
@ -15,6 +15,8 @@ UNIFIED_SOURCES += [
|
||||
'TestGfxPrefs.cpp',
|
||||
'TestGfxWidgets.cpp',
|
||||
'TestLayers.cpp',
|
||||
'TestMoz2D.cpp',
|
||||
'TestRect.cpp',
|
||||
'TestRegion.cpp',
|
||||
'TestSkipChars.cpp',
|
||||
# Hangs on linux in ApplyGdkScreenFontOptions
|
||||
@ -26,20 +28,13 @@ UNIFIED_SOURCES += [
|
||||
'TestVsync.cpp',
|
||||
]
|
||||
|
||||
# Because of gkmedia on windows we won't find these
|
||||
# symbols in xul.dll.
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'windows':
|
||||
UNIFIED_SOURCES += [ '/gfx/2d/unittest/%s' % p for p in [
|
||||
'TestBase.cpp',
|
||||
'TestBugs.cpp',
|
||||
'TestCairo.cpp',
|
||||
'TestPoint.cpp',
|
||||
'TestScaling.cpp',
|
||||
]]
|
||||
UNIFIED_SOURCES += [
|
||||
'TestMoz2D.cpp',
|
||||
'TestRect.cpp',
|
||||
]
|
||||
UNIFIED_SOURCES += [ '/gfx/2d/unittest/%s' % p for p in [
|
||||
'TestBase.cpp',
|
||||
'TestBugs.cpp',
|
||||
'TestCairo.cpp',
|
||||
'TestPoint.cpp',
|
||||
'TestScaling.cpp',
|
||||
]]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
|
@ -442,6 +442,9 @@ gfxWindowsPlatform::gfxWindowsPlatform()
|
||||
gfxWindowsPlatform::~gfxWindowsPlatform()
|
||||
{
|
||||
mDeviceManager = nullptr;
|
||||
mD3D11Device = nullptr;
|
||||
mD3D11ContentDevice = nullptr;
|
||||
mD3D11ImageBridgeDevice = nullptr;
|
||||
|
||||
// not calling FT_Done_FreeType because cairo may still hold references to
|
||||
// these FT_Faces. See bug 458169.
|
||||
@ -453,6 +456,8 @@ gfxWindowsPlatform::~gfxWindowsPlatform()
|
||||
|
||||
mozilla::gfx::Factory::D2DCleanup();
|
||||
|
||||
mAdapter = nullptr;
|
||||
|
||||
/*
|
||||
* Uninitialize COM
|
||||
*/
|
||||
|
@ -2511,6 +2511,13 @@ BacktrackingAllocator::trySplitAcrossHotcode(LiveBundle* bundle, bool* success)
|
||||
return false;
|
||||
LiveBundle* preBundle = nullptr;
|
||||
LiveBundle* postBundle = nullptr;
|
||||
LiveBundle* coldBundle = nullptr;
|
||||
|
||||
if (testbed) {
|
||||
coldBundle = LiveBundle::New(alloc(), bundle->spillSet(), bundle->spillParent());
|
||||
if (!coldBundle)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Accumulate the ranges of hot and cold code in the bundle. Note that
|
||||
// we are only comparing with the single hot range found, so the cold code
|
||||
@ -2526,33 +2533,53 @@ BacktrackingAllocator::trySplitAcrossHotcode(LiveBundle* bundle, bool* success)
|
||||
}
|
||||
|
||||
if (!coldPre.empty()) {
|
||||
if (!preBundle) {
|
||||
preBundle = LiveBundle::New(alloc(), bundle->spillSet(), bundle->spillParent());
|
||||
if (!preBundle)
|
||||
if (testbed) {
|
||||
if (!coldBundle->addRangeAndDistributeUses(alloc(), range, coldPre.from, coldPre.to))
|
||||
return false;
|
||||
} else {
|
||||
if (!preBundle) {
|
||||
preBundle = LiveBundle::New(alloc(), bundle->spillSet(), bundle->spillParent());
|
||||
if (!preBundle)
|
||||
return false;
|
||||
}
|
||||
if (!preBundle->addRangeAndDistributeUses(alloc(), range, coldPre.from, coldPre.to))
|
||||
return false;
|
||||
}
|
||||
if (!preBundle->addRangeAndDistributeUses(alloc(), range, coldPre.from, coldPre.to))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!coldPost.empty()) {
|
||||
if (!postBundle)
|
||||
postBundle = LiveBundle::New(alloc(), bundle->spillSet(), bundle->spillParent());
|
||||
if (!postBundle->addRangeAndDistributeUses(alloc(), range, coldPost.from, coldPost.to))
|
||||
return false;
|
||||
if (testbed) {
|
||||
if (!coldBundle->addRangeAndDistributeUses(alloc(), range, coldPost.from, coldPost.to))
|
||||
return false;
|
||||
} else {
|
||||
if (!postBundle) {
|
||||
postBundle = LiveBundle::New(alloc(), bundle->spillSet(), bundle->spillParent());
|
||||
if (!postBundle)
|
||||
return false;
|
||||
}
|
||||
if (!postBundle->addRangeAndDistributeUses(alloc(), range, coldPost.from, coldPost.to))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(preBundle || postBundle);
|
||||
MOZ_ASSERT(hotBundle->numRanges() != 0);
|
||||
|
||||
LiveBundleVector newBundles;
|
||||
if (!newBundles.append(hotBundle))
|
||||
return false;
|
||||
if (preBundle && !newBundles.append(preBundle))
|
||||
return false;
|
||||
if (postBundle && !newBundles.append(postBundle))
|
||||
return false;
|
||||
|
||||
if (testbed) {
|
||||
MOZ_ASSERT(coldBundle->numRanges() != 0);
|
||||
if (!newBundles.append(coldBundle))
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(preBundle || postBundle);
|
||||
if (preBundle && !newBundles.append(preBundle))
|
||||
return false;
|
||||
if (postBundle && !newBundles.append(postBundle))
|
||||
return false;
|
||||
}
|
||||
|
||||
*success = true;
|
||||
return splitAndRequeueBundles(bundle, newBundles);
|
||||
|
@ -546,6 +546,9 @@ class BacktrackingAllocator : protected RegisterAllocator
|
||||
friend class C1Spewer;
|
||||
friend class JSONSpewer;
|
||||
|
||||
// This flag is set when testing new allocator modifications.
|
||||
bool testbed;
|
||||
|
||||
BitSet* liveIn;
|
||||
FixedList<VirtualRegister> vregs;
|
||||
|
||||
@ -606,8 +609,9 @@ class BacktrackingAllocator : protected RegisterAllocator
|
||||
SpillSlotList normalSlots, doubleSlots, quadSlots;
|
||||
|
||||
public:
|
||||
BacktrackingAllocator(MIRGenerator* mir, LIRGenerator* lir, LIRGraph& graph)
|
||||
BacktrackingAllocator(MIRGenerator* mir, LIRGenerator* lir, LIRGraph& graph, bool testbed)
|
||||
: RegisterAllocator(mir, lir, graph),
|
||||
testbed(testbed),
|
||||
liveIn(nullptr),
|
||||
callRanges(nullptr)
|
||||
{ }
|
||||
|
@ -1653,14 +1653,18 @@ GenerateLIR(MIRGenerator* mir)
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_RegisterAllocation);
|
||||
|
||||
switch (mir->optimizationInfo().registerAllocator()) {
|
||||
case RegisterAllocator_Backtracking: {
|
||||
IonRegisterAllocator allocator = mir->optimizationInfo().registerAllocator();
|
||||
|
||||
switch (allocator) {
|
||||
case RegisterAllocator_Backtracking:
|
||||
case RegisterAllocator_Testbed: {
|
||||
#ifdef DEBUG
|
||||
if (!integrity.record())
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
BacktrackingAllocator regalloc(mir, &lirgen, *lir);
|
||||
BacktrackingAllocator regalloc(mir, &lirgen, *lir,
|
||||
allocator == RegisterAllocator_Testbed);
|
||||
if (!regalloc.go())
|
||||
return nullptr;
|
||||
|
||||
|
@ -23,6 +23,7 @@ static const uint32_t MAX_MAIN_THREAD_LOCALS_AND_ARGS = 256;
|
||||
// Possible register allocators which may be used.
|
||||
enum IonRegisterAllocator {
|
||||
RegisterAllocator_Backtracking,
|
||||
RegisterAllocator_Testbed,
|
||||
RegisterAllocator_Stupid
|
||||
};
|
||||
|
||||
@ -31,6 +32,8 @@ LookupRegisterAllocator(const char* name)
|
||||
{
|
||||
if (!strcmp(name, "backtracking"))
|
||||
return mozilla::Some(RegisterAllocator_Backtracking);
|
||||
if (!strcmp(name, "testbed"))
|
||||
return mozilla::Some(RegisterAllocator_Testbed);
|
||||
if (!strcmp(name, "stupid"))
|
||||
return mozilla::Some(RegisterAllocator_Stupid);
|
||||
return mozilla::Nothing();
|
||||
|
@ -233,7 +233,7 @@ ReportError(JSContext* cx, const char* message, JSErrorReport* reportp,
|
||||
* The AutoJSAPI error reporter only allows warnings to be reported so
|
||||
* just ignore this error rather than try to report it.
|
||||
*/
|
||||
if (cx->options().autoJSAPIOwnsErrorReporting())
|
||||
if (cx->options().autoJSAPIOwnsErrorReporting() && !JSREPORT_IS_WARNING(reportp->flags))
|
||||
return;
|
||||
}
|
||||
|
||||
@ -253,9 +253,9 @@ PopulateReportBlame(JSContext* cx, JSErrorReport* report)
|
||||
{
|
||||
/*
|
||||
* Walk stack until we find a frame that is associated with a non-builtin
|
||||
* rather than a builtin frame.
|
||||
* rather than a builtin frame and which we're allowed to know about.
|
||||
*/
|
||||
NonBuiltinFrameIter iter(cx);
|
||||
NonBuiltinFrameIter iter(cx, cx->compartment()->principals());
|
||||
if (iter.done())
|
||||
return;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user