merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-06-16 16:08:27 +02:00
commit 56a152e92c
190 changed files with 2487 additions and 5102 deletions

View File

@ -1,3 +1 @@
41.0a1
# Version to display in the about box:
41.0a1

View File

@ -0,0 +1 @@
41.0a1

View File

@ -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) {

View File

@ -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.])

View File

@ -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",

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -101,7 +101,7 @@ public:
}
virtual void GetMozFullPathInternal(nsAString& aFullPath,
ErrorResult& aRv) override;
ErrorResult& aRv) const override;
virtual nsresult
SetMutable(bool aMutable) override;

View File

@ -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)
{

View File

@ -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());

View File

@ -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,

View File

@ -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,

View File

@ -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>";
}

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -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
{
/**

View File

@ -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

View File

@ -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
{
/**

View File

@ -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;
}

View File

@ -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,

View File

@ -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());

View File

@ -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);

View File

@ -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()

View File

@ -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>

View File

@ -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();

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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; }
}

View File

@ -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,

View File

@ -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 =

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -79,13 +79,6 @@ public:
return mRequest->Context();
}
// [ChromeOnly]
void
SetContext(RequestContext aContext)
{
mRequest->SetContext(aContext);
}
void
SetContentPolicyType(nsContentPolicyType aContentPolicyType)
{

View File

@ -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();

View File

@ -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,

View File

@ -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;
}

View File

@ -125,7 +125,7 @@ BlobImplSnapshot::CreateSlice(uint64_t aStart,
void
BlobImplSnapshot::GetMozFullPathInternal(nsAString& aFilename,
ErrorResult& aRv)
ErrorResult& aRv) const
{
AssertSanity();
MOZ_ASSERT(mIsFile);

View File

@ -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;

View File

@ -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" } }

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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;

View File

@ -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;

View File

@ -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']

View File

@ -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,

View File

@ -289,19 +289,18 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
}
buffer->Unlock();
int64_t timestamp;
hr = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate, &timestamp);
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,

View File

@ -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>

View File

@ -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

View 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(&timestampHns);
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

View File

@ -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);

View File

@ -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']

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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, &timestampHns, 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, &currentLength);
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, &timestamp);
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, &timestampHns, 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

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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(&timestampHns);
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

View File

@ -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']

View File

@ -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));

View File

@ -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"});

View File

@ -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);
}
}
}
},

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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*

View File

@ -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',

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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];

View File

@ -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

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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};

View File

@ -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')

View File

@ -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
*/

View File

@ -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);

View File

@ -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)
{ }

View File

@ -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;

View File

@ -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();

View File

@ -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