зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
b3c105d5da
|
@ -187,6 +187,7 @@
|
|||
@BINPATH@/components/dom_power.xpt
|
||||
@BINPATH@/components/dom_quota.xpt
|
||||
@BINPATH@/components/dom_range.xpt
|
||||
@BINPATH@/components/dom_security.xpt
|
||||
@BINPATH@/components/dom_settings.xpt
|
||||
@BINPATH@/components/dom_permissionsettings.xpt
|
||||
@BINPATH@/components/dom_sidebar.xpt
|
||||
|
|
|
@ -417,23 +417,9 @@ BrowserGlue.prototype = {
|
|||
if (data == POLARIS_ENABLED) {
|
||||
let enabled = Services.prefs.getBoolPref(POLARIS_ENABLED);
|
||||
if (enabled) {
|
||||
let e10sEnabled = Services.appinfo.browserTabsRemoteAutostart;
|
||||
let shouldRestart = e10sEnabled && this._promptForE10sRestart();
|
||||
// Only set the related prefs if e10s is not enabled or the user
|
||||
// saw a notification that e10s would be disabled on restart.
|
||||
if (!e10sEnabled || shouldRestart) {
|
||||
Services.prefs.setBoolPref("privacy.donottrackheader.enabled", enabled);
|
||||
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", enabled);
|
||||
Services.prefs.setBoolPref("privacy.trackingprotection.ui.enabled", enabled);
|
||||
if (shouldRestart) {
|
||||
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit |
|
||||
Ci.nsIAppStartup.eRestart);
|
||||
}
|
||||
} else {
|
||||
// The user chose not to disable E10s which is temporarily
|
||||
// incompatible with Polaris.
|
||||
Services.prefs.clearUserPref(POLARIS_ENABLED);
|
||||
}
|
||||
} else {
|
||||
// Don't reset DNT because its visible pref is independent of
|
||||
// Polaris and may have been previously set.
|
||||
|
@ -445,23 +431,6 @@ BrowserGlue.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
_promptForE10sRestart: function () {
|
||||
let win = this.getMostRecentBrowserWindow();
|
||||
let brandBundle = win.document.getElementById("bundle_brand");
|
||||
let brandName = brandBundle.getString("brandShortName");
|
||||
let prefBundle = win.document.getElementById("bundle_preferences");
|
||||
let msg = "Multiprocess Nightly (e10s) does not yet support tracking protection. Multiprocessing will be disabled if you restart Firefox. Would you like to continue?";
|
||||
let title = prefBundle.getFormattedString("shouldRestartTitle", [brandName]);
|
||||
let shouldRestart = Services.prompt.confirm(win, title, msg);
|
||||
if (shouldRestart) {
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
|
||||
shouldRestart = !cancelQuit.data;
|
||||
}
|
||||
return shouldRestart;
|
||||
},
|
||||
|
||||
_syncSearchEngines: function () {
|
||||
// Only do this if the search service is already initialized. This function
|
||||
// gets called in finalUIStartup and from a browser-search-service observer,
|
||||
|
@ -2473,12 +2442,7 @@ let E10SUINotification = {
|
|||
checkStatus: function() {
|
||||
let skipE10sChecks = false;
|
||||
try {
|
||||
// This order matters, because
|
||||
// browser.tabs.remote.autostart.disabled-because-using-a11y is not
|
||||
// always defined and will throw when not present.
|
||||
// privacy.trackingprotection.enabled is always defined.
|
||||
skipE10sChecks = (UpdateChannel.get() != "nightly") ||
|
||||
Services.prefs.getBoolPref("privacy.trackingprotection.enabled") ||
|
||||
Services.prefs.getBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y");
|
||||
} catch(e) {}
|
||||
|
||||
|
|
|
@ -4,4 +4,3 @@
|
|||
skip-if = e10s # Bug ?????? - child process crash, but only when run as part of the suite (ie, probably not actually this tests fault!?)
|
||||
|
||||
[browser_polaris_prefs.js]
|
||||
skip-if = e10s # Bug 1089774 - Tracking protection and e10s are incompatible.
|
||||
|
|
|
@ -222,6 +222,7 @@
|
|||
@BINPATH@/components/dom_power.xpt
|
||||
@BINPATH@/components/dom_quota.xpt
|
||||
@BINPATH@/components/dom_range.xpt
|
||||
@BINPATH@/components/dom_security.xpt
|
||||
@BINPATH@/components/dom_settings.xpt
|
||||
@BINPATH@/components/dom_permissionsettings.xpt
|
||||
@BINPATH@/components/dom_sidebar.xpt
|
||||
|
@ -921,3 +922,10 @@ bin/libfreebl_32int64_3.so
|
|||
@BINPATH@/clang_rt.asan_dynamic-i386.dll
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
; media
|
||||
#ifdef MOZ_EME
|
||||
@BINPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
|
||||
@BINPATH@/gmp-clearkey/0.1/clearkey.info
|
||||
#endif
|
||||
|
|
|
@ -375,7 +375,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
bool
|
||||
JS::AsmJSCacheResult
|
||||
BlockUntilOpen(AutoClose* aCloser)
|
||||
{
|
||||
MOZ_ASSERT(!mWaiting, "Can only call BlockUntilOpen once");
|
||||
|
@ -384,7 +384,9 @@ public:
|
|||
mWaiting = true;
|
||||
|
||||
nsresult rv = NS_DispatchToMainThread(this);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
@ -394,7 +396,7 @@ public:
|
|||
}
|
||||
|
||||
if (!mOpened) {
|
||||
return false;
|
||||
return mResult;
|
||||
}
|
||||
|
||||
// Now that we're open, we're guarnateed a Close() call. However, we are
|
||||
|
@ -402,7 +404,7 @@ public:
|
|||
// is closed, so we do that ourselves and Release() in OnClose().
|
||||
aCloser->Init(this);
|
||||
AddRef();
|
||||
return true;
|
||||
return JS::AsmJSCache_Success;
|
||||
}
|
||||
|
||||
// This method must be called if BlockUntilOpen returns 'true'. AutoClose
|
||||
|
@ -416,7 +418,8 @@ protected:
|
|||
: mMutex("File::mMutex"),
|
||||
mCondVar(mMutex, "File::mCondVar"),
|
||||
mWaiting(false),
|
||||
mOpened(false)
|
||||
mOpened(false),
|
||||
mResult(JS::AsmJSCache_InternalError)
|
||||
{ }
|
||||
|
||||
~File()
|
||||
|
@ -428,15 +431,16 @@ protected:
|
|||
void
|
||||
OnOpen()
|
||||
{
|
||||
Notify(true);
|
||||
Notify(JS::AsmJSCache_Success);
|
||||
}
|
||||
|
||||
void
|
||||
OnFailure()
|
||||
OnFailure(JS::AsmJSCacheResult aResult)
|
||||
{
|
||||
FileDescriptorHolder::Finish();
|
||||
MOZ_ASSERT(aResult != JS::AsmJSCache_Success);
|
||||
|
||||
Notify(false);
|
||||
FileDescriptorHolder::Finish();
|
||||
Notify(aResult);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -455,7 +459,7 @@ protected:
|
|||
|
||||
private:
|
||||
void
|
||||
Notify(bool aSuccess)
|
||||
Notify(JS::AsmJSCacheResult aResult)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -463,7 +467,8 @@ private:
|
|||
MOZ_ASSERT(mWaiting);
|
||||
|
||||
mWaiting = false;
|
||||
mOpened = aSuccess;
|
||||
mOpened = aResult == JS::AsmJSCache_Success;
|
||||
mResult = aResult;
|
||||
mCondVar.Notify();
|
||||
}
|
||||
|
||||
|
@ -471,6 +476,7 @@ private:
|
|||
CondVar mCondVar;
|
||||
bool mWaiting;
|
||||
bool mOpened;
|
||||
JS::AsmJSCacheResult mResult;
|
||||
};
|
||||
|
||||
// MainProcessRunnable is a base class shared by (Single|Parent)ProcessRunnable
|
||||
|
@ -493,6 +499,7 @@ public:
|
|||
mNeedAllowNextSynchronizedOp(false),
|
||||
mPersistence(quota::PERSISTENCE_TYPE_INVALID),
|
||||
mState(eInitial),
|
||||
mResult(JS::AsmJSCache_InternalError),
|
||||
mIsApp(false),
|
||||
mHasUnlimStoragePerm(false),
|
||||
mEnforcingQuota(true)
|
||||
|
@ -582,7 +589,7 @@ protected:
|
|||
// This method may be overridden, but it must be called from the overrider.
|
||||
// Called by MainProcessRunnable on the main thread after a call to Fail():
|
||||
virtual void
|
||||
OnFailure()
|
||||
OnFailure(JS::AsmJSCacheResult aResult)
|
||||
{
|
||||
FinishOnMainThread();
|
||||
}
|
||||
|
@ -665,6 +672,7 @@ private:
|
|||
eFinished, // Terminal state
|
||||
};
|
||||
State mState;
|
||||
JS::AsmJSCacheResult mResult;
|
||||
|
||||
bool mIsApp;
|
||||
bool mHasUnlimStoragePerm;
|
||||
|
@ -850,6 +858,7 @@ MainProcessRunnable::OpenCacheFileForWrite()
|
|||
// enough space.
|
||||
EvictEntries(mDirectory, mGroup, mOrigin, mWriteParams.mSize, mMetadata);
|
||||
if (!mQuotaObject->MaybeAllocateMoreSpace(0, mWriteParams.mSize)) {
|
||||
mResult = JS::AsmJSCache_QuotaExceeded;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -1048,7 +1057,7 @@ MainProcessRunnable::Run()
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mState = eFinished;
|
||||
OnFailure();
|
||||
OnFailure(mResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1168,10 +1177,10 @@ private:
|
|||
}
|
||||
|
||||
void
|
||||
OnFailure() MOZ_OVERRIDE
|
||||
OnFailure(JS::AsmJSCacheResult aResult) MOZ_OVERRIDE
|
||||
{
|
||||
MainProcessRunnable::OnFailure();
|
||||
File::OnFailure();
|
||||
MainProcessRunnable::OnFailure(aResult);
|
||||
File::OnFailure(aResult);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1225,7 +1234,7 @@ private:
|
|||
}
|
||||
|
||||
bool
|
||||
Recv__delete__() MOZ_OVERRIDE
|
||||
Recv__delete__(const JS::AsmJSCacheResult& aResult) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(!mFinished);
|
||||
mFinished = true;
|
||||
|
@ -1267,7 +1276,7 @@ private:
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!SendOnOpenMetadataForRead(aMetadata)) {
|
||||
unused << Send__delete__(this);
|
||||
unused << Send__delete__(this, JS::AsmJSCache_InternalError);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1296,7 +1305,7 @@ private:
|
|||
FileDescriptor::PlatformHandleType handle =
|
||||
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFileDesc));
|
||||
if (!SendOnOpenCacheFile(mFileSize, FileDescriptor(handle))) {
|
||||
unused << Send__delete__(this);
|
||||
unused << Send__delete__(this, JS::AsmJSCache_InternalError);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1316,17 +1325,17 @@ private:
|
|||
}
|
||||
|
||||
void
|
||||
OnFailure() MOZ_OVERRIDE
|
||||
OnFailure(JS::AsmJSCacheResult aResult) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mOpened);
|
||||
|
||||
mFinished = true;
|
||||
|
||||
MainProcessRunnable::OnFailure();
|
||||
MainProcessRunnable::OnFailure(aResult);
|
||||
|
||||
if (!mActorDestroyed) {
|
||||
unused << Send__delete__(this);
|
||||
unused << Send__delete__(this, aResult);
|
||||
}
|
||||
|
||||
mPrincipalHolder = nullptr;
|
||||
|
@ -1435,12 +1444,12 @@ private:
|
|||
}
|
||||
|
||||
bool
|
||||
Recv__delete__() MOZ_OVERRIDE
|
||||
Recv__delete__(const JS::AsmJSCacheResult& aResult) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mState == eOpening);
|
||||
|
||||
Fail();
|
||||
Fail(aResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1462,13 +1471,13 @@ private:
|
|||
|
||||
private:
|
||||
void
|
||||
Fail()
|
||||
Fail(JS::AsmJSCacheResult aResult)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mState == eInitial || mState == eOpening);
|
||||
|
||||
mState = eFinished;
|
||||
File::OnFailure();
|
||||
File::OnFailure(aResult);
|
||||
}
|
||||
|
||||
nsIPrincipal* const mPrincipal;
|
||||
|
@ -1507,7 +1516,7 @@ ChildProcessRunnable::Run()
|
|||
// 'this' alive until returning to the event loop.
|
||||
Release();
|
||||
|
||||
Fail();
|
||||
Fail(JS::AsmJSCache_InternalError);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1524,7 +1533,7 @@ ChildProcessRunnable::Run()
|
|||
File::OnClose();
|
||||
|
||||
if (!mActorDestroyed) {
|
||||
unused << Send__delete__(this);
|
||||
unused << Send__delete__(this, JS::AsmJSCache_Success);
|
||||
}
|
||||
|
||||
mState = eFinished;
|
||||
|
@ -1553,7 +1562,7 @@ DeallocEntryChild(PAsmJSCacheEntryChild* aActor)
|
|||
|
||||
namespace {
|
||||
|
||||
bool
|
||||
JS::AsmJSCacheResult
|
||||
OpenFile(nsIPrincipal* aPrincipal,
|
||||
OpenMode aOpenMode,
|
||||
WriteParams aWriteParams,
|
||||
|
@ -1576,7 +1585,7 @@ OpenFile(nsIPrincipal* aPrincipal,
|
|||
// in the middle of running JS (eval()) and nested event loops can be
|
||||
// semantically observable.
|
||||
if (NS_IsMainThread()) {
|
||||
return false;
|
||||
return JS::AsmJSCache_SynchronousScript;
|
||||
}
|
||||
|
||||
// If we are in a child process, we need to synchronously call into the
|
||||
|
@ -1591,11 +1600,16 @@ OpenFile(nsIPrincipal* aPrincipal,
|
|||
aReadParams);
|
||||
}
|
||||
|
||||
if (!file->BlockUntilOpen(aFile)) {
|
||||
return false;
|
||||
JS::AsmJSCacheResult openResult = file->BlockUntilOpen(aFile);
|
||||
if (openResult != JS::AsmJSCache_Success) {
|
||||
return openResult;
|
||||
}
|
||||
|
||||
return file->MapMemory(aOpenMode);
|
||||
if (!file->MapMemory(aOpenMode)) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
|
||||
return JS::AsmJSCache_Success;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -1621,7 +1635,9 @@ OpenEntryForRead(nsIPrincipal* aPrincipal,
|
|||
|
||||
File::AutoClose file;
|
||||
WriteParams notAWrite;
|
||||
if (!OpenFile(aPrincipal, eOpenForRead, notAWrite, readParams, &file)) {
|
||||
JS::AsmJSCacheResult openResult =
|
||||
OpenFile(aPrincipal, eOpenForRead, notAWrite, readParams, &file);
|
||||
if (openResult != JS::AsmJSCache_Success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1661,7 +1677,7 @@ CloseEntryForRead(size_t aSize,
|
|||
MOZ_ASSERT(aMemory - sizeof(AsmJSCookieType) == file->MappedMemory());
|
||||
}
|
||||
|
||||
bool
|
||||
JS::AsmJSCacheResult
|
||||
OpenEntryForWrite(nsIPrincipal* aPrincipal,
|
||||
bool aInstalled,
|
||||
const char16_t* aBegin,
|
||||
|
@ -1671,7 +1687,7 @@ OpenEntryForWrite(nsIPrincipal* aPrincipal,
|
|||
intptr_t* aFile)
|
||||
{
|
||||
if (size_t(aEnd - aBegin) < sMinCachedModuleLength) {
|
||||
return false;
|
||||
return JS::AsmJSCache_ModuleTooSmall;
|
||||
}
|
||||
|
||||
// Add extra space for the AsmJSCookieType (see OpenEntryForRead).
|
||||
|
@ -1688,8 +1704,10 @@ OpenEntryForWrite(nsIPrincipal* aPrincipal,
|
|||
|
||||
File::AutoClose file;
|
||||
ReadParams notARead;
|
||||
if (!OpenFile(aPrincipal, eOpenForWrite, writeParams, notARead, &file)) {
|
||||
return false;
|
||||
JS::AsmJSCacheResult openResult =
|
||||
OpenFile(aPrincipal, eOpenForWrite, writeParams, notARead, &file);
|
||||
if (openResult != JS::AsmJSCache_Success) {
|
||||
return openResult;
|
||||
}
|
||||
|
||||
// Strip off the AsmJSCookieType from the buffer returned to the caller,
|
||||
|
@ -1700,7 +1718,7 @@ OpenEntryForWrite(nsIPrincipal* aPrincipal,
|
|||
// The caller guarnatees a call to CloseEntryForWrite (on success or
|
||||
// failure) at which point the file will be closed
|
||||
file.Forget(reinterpret_cast<File**>(aFile));
|
||||
return true;
|
||||
return JS::AsmJSCache_Success;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -112,7 +112,7 @@ void
|
|||
CloseEntryForRead(size_t aSize,
|
||||
const uint8_t* aMemory,
|
||||
intptr_t aHandle);
|
||||
bool
|
||||
JS::AsmJSCacheResult
|
||||
OpenEntryForWrite(nsIPrincipal* aPrincipal,
|
||||
bool aInstalled,
|
||||
const char16_t* aBegin,
|
||||
|
@ -178,6 +178,13 @@ struct ParamTraits<mozilla::dom::asmjscache::WriteParams>
|
|||
static void Log(const paramType& aParam, std::wstring* aLog);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<JS::AsmJSCacheResult> :
|
||||
public ContiguousEnumSerializer<JS::AsmJSCacheResult,
|
||||
JS::AsmJSCache_MIN,
|
||||
JS::AsmJSCache_LIMIT>
|
||||
{ };
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // mozilla_dom_asmjscache_asmjscache_h
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
include protocol PContent;
|
||||
|
||||
using mozilla::dom::asmjscache::Metadata from "mozilla/dom/asmjscache/AsmJSCache.h";
|
||||
using JS::AsmJSCacheResult from "mozilla/dom/asmjscache/AsmJSCache.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -29,7 +30,7 @@ child:
|
|||
OnOpenCacheFile(int64_t fileSize, FileDescriptor fileDesc);
|
||||
|
||||
both:
|
||||
__delete__();
|
||||
__delete__(AsmJSCacheResult result);
|
||||
};
|
||||
|
||||
} // namespace asmjscache
|
||||
|
|
|
@ -86,6 +86,9 @@ public:
|
|||
, mScriptLine(0)
|
||||
, mInnerWindowID(0)
|
||||
, mWorkerPrivate(nullptr)
|
||||
#ifdef DEBUG
|
||||
, mHasFeatureRegistered(false)
|
||||
#endif
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
mWorkerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
|
@ -149,6 +152,7 @@ public:
|
|||
void AddRefObject();
|
||||
void ReleaseObject();
|
||||
|
||||
void RegisterFeature();
|
||||
void UnregisterFeature();
|
||||
|
||||
nsresult CancelInternal();
|
||||
|
@ -193,6 +197,25 @@ public:
|
|||
WorkerPrivate* mWorkerPrivate;
|
||||
nsAutoPtr<WorkerFeature> mWorkerFeature;
|
||||
|
||||
#ifdef DEBUG
|
||||
// This is protected by mutex.
|
||||
bool mHasFeatureRegistered;
|
||||
|
||||
bool HasFeatureRegistered()
|
||||
{
|
||||
MOZ_ASSERT(mWebSocket);
|
||||
MutexAutoLock lock(mWebSocket->mMutex);
|
||||
return mHasFeatureRegistered;
|
||||
}
|
||||
|
||||
void SetHasFeatureRegistered(bool aValue)
|
||||
{
|
||||
MOZ_ASSERT(mWebSocket);
|
||||
MutexAutoLock lock(mWebSocket->mMutex);
|
||||
mHasFeatureRegistered = aValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsWeakPtr mWeakLoadGroup;
|
||||
|
||||
private:
|
||||
|
@ -213,7 +236,7 @@ NS_IMPL_ISUPPORTS(WebSocketImpl,
|
|||
nsIRequest,
|
||||
nsIEventTarget)
|
||||
|
||||
class CallDispatchConnectionCloseEvents MOZ_FINAL : public nsRunnable
|
||||
class CallDispatchConnectionCloseEvents MOZ_FINAL : public nsCancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit CallDispatchConnectionCloseEvents(WebSocketImpl* aWebSocketImpl)
|
||||
|
@ -541,6 +564,9 @@ WebSocketImpl::DisconnectInternal()
|
|||
nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
|
||||
if (loadGroup) {
|
||||
loadGroup->RemoveRequest(this, nullptr, NS_OK);
|
||||
// mWeakLoadGroup has to be release on main-thread because WeakReferences
|
||||
// are not thread-safe.
|
||||
mWeakLoadGroup = nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
|
@ -1061,6 +1087,12 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
|||
return webSocket.forget();
|
||||
}
|
||||
|
||||
if (webSocket->mWorkerPrivate) {
|
||||
// In workers we have to keep the worker alive using a feature in order to
|
||||
// dispatch messages correctly.
|
||||
webSocket->mImpl->RegisterFeature();
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS ClearWebSocket
|
||||
{
|
||||
public:
|
||||
|
@ -1432,6 +1464,11 @@ WebSocketImpl::InitializeConnection()
|
|||
// manually adding loadinfo to the channel since it
|
||||
// was not set during channel creation.
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mOriginDocument);
|
||||
|
||||
// mOriginDocument has to be release on main-thread because WeakReferences
|
||||
// are not thread-safe.
|
||||
mOriginDocument = nullptr;
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo =
|
||||
new LoadInfo(mPrincipal,
|
||||
doc,
|
||||
|
@ -1764,9 +1801,12 @@ WebSocket::UpdateMustKeepAlive()
|
|||
}
|
||||
|
||||
bool shouldKeepAlive = false;
|
||||
uint16_t readyState = ReadyState();
|
||||
|
||||
if (mListenerManager) {
|
||||
switch (ReadyState())
|
||||
if (mWorkerPrivate && readyState != CLOSED) {
|
||||
shouldKeepAlive = true;
|
||||
} else if (mListenerManager) {
|
||||
switch (readyState)
|
||||
{
|
||||
case CONNECTING:
|
||||
{
|
||||
|
@ -1839,7 +1879,6 @@ public:
|
|||
|
||||
if (aStatus >= Canceling) {
|
||||
mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
||||
mWebSocketImpl->UnregisterFeature();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1848,7 +1887,6 @@ public:
|
|||
bool Suspend(JSContext* aCx)
|
||||
{
|
||||
mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
||||
mWebSocketImpl->UnregisterFeature();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1865,15 +1903,7 @@ WebSocketImpl::AddRefObject()
|
|||
AddRef();
|
||||
|
||||
if (mWorkerPrivate && !mWorkerFeature) {
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(!mWorkerFeature);
|
||||
mWorkerFeature = new WebSocketWorkerFeature(this);
|
||||
|
||||
JSContext* cx = GetCurrentThreadJSContext();
|
||||
if (!mWorkerPrivate->AddFeature(cx, mWorkerFeature)) {
|
||||
NS_WARNING("Failed to register a feature.");
|
||||
mWorkerFeature = nullptr;
|
||||
}
|
||||
RegisterFeature();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1882,13 +1912,32 @@ WebSocketImpl::ReleaseObject()
|
|||
{
|
||||
AssertIsOnTargetThread();
|
||||
|
||||
if (mWorkerPrivate && !mWorkerFeature) {
|
||||
if (mWorkerPrivate && mWorkerFeature) {
|
||||
UnregisterFeature();
|
||||
}
|
||||
|
||||
Release();
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketImpl::RegisterFeature()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(!mWorkerFeature);
|
||||
mWorkerFeature = new WebSocketWorkerFeature(this);
|
||||
|
||||
JSContext* cx = GetCurrentThreadJSContext();
|
||||
if (!mWorkerPrivate->AddFeature(cx, mWorkerFeature)) {
|
||||
NS_WARNING("Failed to register a feature.");
|
||||
mWorkerFeature = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
SetHasFeatureRegistered(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketImpl::UnregisterFeature()
|
||||
{
|
||||
|
@ -1899,6 +1948,10 @@ WebSocketImpl::UnregisterFeature()
|
|||
JSContext* cx = GetCurrentThreadJSContext();
|
||||
mWorkerPrivate->RemoveFeature(cx, mWorkerFeature);
|
||||
mWorkerFeature = nullptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
SetHasFeatureRegistered(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -2439,6 +2492,10 @@ WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
|
|||
return NS_DispatchToMainThread(aEvent);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(HasFeatureRegistered());
|
||||
#endif
|
||||
|
||||
// If the target is a worker, we have to use a custom WorkerRunnableDispatcher
|
||||
// runnable.
|
||||
nsRefPtr<WorkerRunnableDispatcher> event =
|
||||
|
|
|
@ -9,7 +9,6 @@ TEST_DIRS += ['test']
|
|||
XPIDL_SOURCES += [
|
||||
'nsIConsoleAPIStorage.idl',
|
||||
'nsIContentPolicy.idl',
|
||||
'nsIContentSecurityPolicy.idl',
|
||||
'nsIDocumentEncoder.idl',
|
||||
'nsIDOMDataChannel.idl',
|
||||
'nsIDOMDOMCursor.idl',
|
||||
|
@ -246,10 +245,6 @@ UNIFIED_SOURCES += [
|
|||
'nsContentSink.cpp',
|
||||
'nsCopySupport.cpp',
|
||||
'nsCrossSiteListenerProxy.cpp',
|
||||
'nsCSPContext.cpp',
|
||||
'nsCSPParser.cpp',
|
||||
'nsCSPService.cpp',
|
||||
'nsCSPUtils.cpp',
|
||||
'nsDataDocumentContentPolicy.cpp',
|
||||
'nsDocument.cpp',
|
||||
'nsDocumentEncoder.cpp',
|
||||
|
@ -288,7 +283,6 @@ UNIFIED_SOURCES += [
|
|||
'nsMappedAttributeElement.cpp',
|
||||
'nsMappedAttributes.cpp',
|
||||
'nsMimeTypeArray.cpp',
|
||||
'nsMixedContentBlocker.cpp',
|
||||
'nsNameSpaceManager.cpp',
|
||||
'nsNoDataProtocolContentPolicy.cpp',
|
||||
'nsNodeInfoManager.cpp',
|
||||
|
|
|
@ -161,7 +161,7 @@
|
|||
|
||||
// FOR CSP (autogenerated by xpidl)
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsCSPService.h"
|
||||
#include "mozilla/dom/nsCSPService.h"
|
||||
#include "nsHTMLStyleSheet.h"
|
||||
#include "nsHTMLCSSStyleSheet.h"
|
||||
#include "SVGAttrAnimationRuleProcessor.h"
|
||||
|
|
|
@ -2703,7 +2703,7 @@ AsmJSCacheOpenEntryForRead(JS::Handle<JSObject*> aGlobal,
|
|||
aHandle);
|
||||
}
|
||||
|
||||
static bool
|
||||
static JS::AsmJSCacheResult
|
||||
AsmJSCacheOpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
|
||||
bool aInstalled,
|
||||
const char16_t* aBegin,
|
||||
|
|
|
@ -126,7 +126,7 @@ public:
|
|||
*/
|
||||
void AppendTo(nsAString& aString) const {
|
||||
if (!AppendTo(aString, mozilla::fallible_t())) {
|
||||
NS_ABORT_OOM(GetLength());
|
||||
aString.AllocFailed(aString.Length() + GetLength());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ public:
|
|||
*/
|
||||
void AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength) const {
|
||||
if (!AppendTo(aString, aOffset, aLength, mozilla::fallible_t())) {
|
||||
NS_ABORT_OOM(aLength);
|
||||
aString.AllocFailed(aString.Length() + aLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3973,7 +3973,10 @@ ArrayBufferBuilder::setCapacity(uint32_t aNewCap)
|
|||
{
|
||||
MOZ_ASSERT(!mMapPtr);
|
||||
|
||||
uint8_t *newdata = (uint8_t *) js_realloc(mDataPtr, aNewCap);
|
||||
// To ensure that realloc won't free mDataPtr, use a size of 1
|
||||
// instead of 0.
|
||||
uint8_t* newdata = (uint8_t *) js_realloc(mDataPtr, aNewCap ? aNewCap : 1);
|
||||
|
||||
if (!newdata) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ template<class T> class nsReadingIterator;
|
|||
#include "nsNetUtil.h"
|
||||
#include "TestHarness.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "../nsCSPContext.h"
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
|
||||
#ifndef MOZILLA_INTERNAL_API
|
||||
#undef nsString_h___
|
||||
|
|
|
@ -12,7 +12,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
<div id="testContent"></div>
|
||||
|
||||
<script>
|
||||
var baseUrlHttps = "https://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html";
|
||||
var baseUrlHttps = "https://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html";
|
||||
|
||||
// For tests that require setTimeout, set the maximum polling time to 50 x 100ms = 5 seconds.
|
||||
var MAX_COUNT = 50;
|
||||
|
@ -44,7 +44,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
counter_test1++;
|
||||
return;
|
||||
}
|
||||
if (loc == "http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_child_response") {
|
||||
if (loc == "http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_child_response") {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
@ -63,7 +63,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
|
||||
// Test 2: Navigate secure grandchild iframe to insecure grandchild iframe on a page that has no secure parents
|
||||
var iframe_test2 = document.createElement("iframe");
|
||||
iframe_test2.src = "http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_grandchild.html"
|
||||
iframe_test2.src = "http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_grandchild.html"
|
||||
iframe_test2.onerror = function() {
|
||||
parent.postMessage({"test": "insecurePage_navigate_grandchild", "msg": "got an on error alert when loading or navigating testing iframe"}, "http://mochi.test:8888");
|
||||
};
|
|
@ -9,7 +9,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=841850
|
|||
<title>Tests for Mixed Content Frame Navigation</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?blankTarget" id="blankTarget" target="_blank">Go to http site</a>
|
||||
<a href="http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?blankTarget" id="blankTarget" target="_blank">Go to http site</a>
|
||||
|
||||
<script>
|
||||
var blankTarget = document.getElementById("blankTarget");
|
|
@ -9,7 +9,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
<title>Tests for Mixed Content Frame Navigation</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="https://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_grandchild" id="child"></iframe>
|
||||
<iframe src="https://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_grandchild" id="child"></iframe>
|
||||
|
||||
<script>
|
||||
// For tests that require setTimeout, set the maximum polling time to 50 x 100ms = 5 seconds.
|
||||
|
@ -32,7 +32,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
counter++;
|
||||
return;
|
||||
}
|
||||
if (loc == "http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_grandchild_response") {
|
||||
if (loc == "http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_grandchild_response") {
|
||||
return;
|
||||
}
|
||||
else {
|
|
@ -9,7 +9,7 @@
|
|||
switch (type) {
|
||||
case "insecurePage_navigate_child":
|
||||
document.getElementById("content").innerHTML =
|
||||
'<a href="http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_child_response" id="link">Testing\<\/a>';
|
||||
'<a href="http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_child_response" id="link">Testing\<\/a>';
|
||||
document.getElementById("link").click();
|
||||
break;
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
|||
|
||||
case "insecurePage_navigate_grandchild":
|
||||
document.getElementById("content").innerHTML =
|
||||
'<a href="http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_grandchild_response" id="link">Testing\<\/a>';
|
||||
'<a href="http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_grandchild_response" id="link">Testing\<\/a>';
|
||||
document.getElementById("link").click();
|
||||
break;
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
|||
|
||||
case "securePage_navigate_child":
|
||||
document.getElementById("content").innerHTML =
|
||||
'<a href="http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?securePage_navigate_child_response" id="link">Testing\<\/a>';
|
||||
'<a href="http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?securePage_navigate_child_response" id="link">Testing\<\/a>';
|
||||
document.getElementById("link").click();
|
||||
break;
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
|||
|
||||
case "securePage_navigate_grandchild":
|
||||
document.getElementById("content").innerHTML=
|
||||
'<a href="http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?securePage_navigate_grandchild_response" id="link">Testing\<\/a>';
|
||||
'<a href="http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?securePage_navigate_grandchild_response" id="link">Testing\<\/a>';
|
||||
document.getElementById("link").click();
|
||||
break;
|
||||
|
|
@ -12,7 +12,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
<div id="testContent"></div>
|
||||
|
||||
<script>
|
||||
var baseUrl = "https://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html";
|
||||
var baseUrl = "https://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html";
|
||||
|
||||
// For tests that require setTimeout, set the maximum polling time to 50 x 100ms = 5 seconds.
|
||||
var MAX_COUNT = 50;
|
||||
|
@ -44,7 +44,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
counter_test1++;
|
||||
return;
|
||||
}
|
||||
if (loc == "http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_child_response") {
|
||||
if (loc == "http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?insecurePage_navigate_child_response") {
|
||||
return;
|
||||
} else {
|
||||
if(counter_test1 < MAX_COUNT) {
|
||||
|
@ -62,7 +62,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
|
||||
// Test 2: Open an http page in a new tab from a link click with target=_blank.
|
||||
var iframe_test3 = document.createElement("iframe");
|
||||
iframe_test3.src = "https://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_blankTarget.html";
|
||||
iframe_test3.src = "https://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_blankTarget.html";
|
||||
iframe_test3.onerror = function() {
|
||||
parent.postMessage({"test": "blankTarget", "msg": "got an onerror event when loading or navigating testing iframe"}, "http://mochi.test:8888");
|
||||
};
|
|
@ -10,7 +10,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
</head>
|
||||
<body>
|
||||
|
||||
<iframe src="https://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?securePage_navigate_grandchild" id="child"></iframe>
|
||||
<iframe src="https://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?securePage_navigate_grandchild" id="child"></iframe>
|
||||
<script>
|
||||
// For tests that require setTimeout, set the maximum polling time to 50 x 100ms = 5 seconds.
|
||||
var MAX_COUNT = 50;
|
||||
|
@ -33,7 +33,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
counter++;
|
||||
return;
|
||||
}
|
||||
if (loc == "http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_innermost.html?securePage_navigate_grandchild_response") {
|
||||
if (loc == "http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_innermost.html?securePage_navigate_grandchild_response") {
|
||||
return;
|
||||
}
|
||||
else {
|
|
@ -38,7 +38,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=62178
|
|||
-->
|
||||
|
||||
<script>
|
||||
var baseUrl = "http://example.com/tests/dom/base/test/file_mixed_content_server.sjs";
|
||||
var baseUrl = "http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_server.sjs";
|
||||
|
||||
//For tests that require setTimeout, set the maximum polling time to 100 x 100ms = 10 seconds.
|
||||
var MAX_COUNT = 100;
|
|
@ -112,7 +112,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
|
|||
var webHandler = SpecialPowers.Cc["@mozilla.org/uriloader/web-handler-app;1"].
|
||||
createInstance(SpecialPowers.Ci.nsIWebHandlerApp);
|
||||
webHandler.name = "Web Handler";
|
||||
webHandler.uriTemplate = "http://example.com/tests/dom/base/test/bug803225_test_mailto.html?s=%";
|
||||
webHandler.uriTemplate = "http://example.com/tests/dom/base/test/mixedcontentblocker/bug803225_test_mailto.html?s=%";
|
||||
|
||||
var uri = ioService.newURI("mailto:foo@bar.com", null, null);
|
||||
webHandler.launchWithURI(uri);
|
||||
|
@ -144,7 +144,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
|
|||
|
||||
// Test 8: wss protocol
|
||||
var wss;
|
||||
wss = new WebSocket("wss://example.com/tests/dom/base/test/file_mixed_content_main_bug803225_websocket");
|
||||
wss = new WebSocket("wss://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_main_bug803225_websocket");
|
||||
|
||||
var status_wss = "started";
|
||||
wss.onopen = function(e) {
|
|
@ -0,0 +1,20 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
bug803225_test_mailto.html
|
||||
file_mixed_content_frameNavigation.html
|
||||
file_mixed_content_frameNavigation_blankTarget.html
|
||||
file_mixed_content_frameNavigation_grandchild.html
|
||||
file_mixed_content_frameNavigation_innermost.html
|
||||
file_mixed_content_frameNavigation_secure.html
|
||||
file_mixed_content_frameNavigation_secure_grandchild.html
|
||||
file_mixed_content_main.html
|
||||
file_mixed_content_main_bug803225.html
|
||||
file_mixed_content_main_bug803225_websocket_wsh.py
|
||||
file_mixed_content_server.sjs
|
||||
|
||||
[test_mixed_content_blocker.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
|
||||
[test_mixed_content_blocker_bug803225.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
|
||||
[test_mixed_content_blocker_frameNavigation.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
|
|
@ -62,7 +62,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=62178
|
|||
}
|
||||
|
||||
function reloadFrame() {
|
||||
document.getElementById('framediv').innerHTML = '<iframe id="testHarness" src="https://example.com/tests/dom/base/test/file_mixed_content_main.html"></iframe>';
|
||||
document.getElementById('framediv').innerHTML = '<iframe id="testHarness" src="https://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_main.html"></iframe>';
|
||||
}
|
||||
|
||||
function checkTestsCompleted() {
|
|
@ -64,7 +64,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
|
|||
changePrefs(counter);
|
||||
counter++;
|
||||
log("\nblockDisplay set to "+blockDisplay+", blockActive set to "+blockActive+".");
|
||||
document.getElementById('framediv').innerHTML = '<iframe id="testHarness" src="https://example.com/tests/dom/base/test/file_mixed_content_main_bug803225.html"></iframe>';
|
||||
document.getElementById('framediv').innerHTML = '<iframe id="testHarness" src="https://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_main_bug803225.html"></iframe>';
|
||||
}
|
||||
else {
|
||||
//set the prefs back to what they were set to originally
|
||||
|
@ -141,7 +141,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
|
|||
|
||||
<body>
|
||||
<div id="framediv">
|
||||
<iframe id="testHarness" src="https://example.com/tests/dom/base/test/file_mixed_content_main_bug803225.html"></iframe>
|
||||
<iframe id="testHarness" src="https://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_main_bug803225.html"></iframe>
|
||||
</div>
|
||||
<pre id="log"></pre>
|
||||
</body>
|
|
@ -42,7 +42,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
// If we are here, all the insecure tests have run.
|
||||
// If we haven't changed the iframe to run the secure tests, change it now.
|
||||
if (!secureTestsStarted) {
|
||||
document.getElementById('testing_frame').src = "https://example.com/tests/dom/base/test/file_mixed_content_frameNavigation_secure.html";
|
||||
document.getElementById('testing_frame').src = "https://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation_secure.html";
|
||||
secureTestsStarted = true;
|
||||
}
|
||||
for (var prop in testsToRunSecure) {
|
||||
|
@ -64,7 +64,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
blockActive = SpecialPowers.getBoolPref("security.mixed_content.block_active_content");
|
||||
log("blockActive set to "+blockActive+".");
|
||||
secureTestsStarted = false;
|
||||
document.getElementById('framediv').innerHTML = '<iframe src="http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation.html" id="testing_frame"></iframe>';
|
||||
document.getElementById('framediv').innerHTML = '<iframe src="http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation.html" id="testing_frame"></iframe>';
|
||||
}
|
||||
else {
|
||||
//set the prefs back to what they were set to originally
|
||||
|
@ -119,7 +119,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388
|
|||
|
||||
<body>
|
||||
<div id="framediv">
|
||||
<iframe src="http://example.com/tests/dom/base/test/file_mixed_content_frameNavigation.html" id="testing_frame"></iframe>
|
||||
<iframe src="http://example.com/tests/dom/base/test/mixedcontentblocker/file_mixed_content_frameNavigation.html" id="testing_frame"></iframe>
|
||||
</div>
|
||||
|
||||
<pre id="log"></pre>
|
|
@ -52,7 +52,6 @@ support-files =
|
|||
bug696301-script-1.js
|
||||
bug696301-script-1.js^headers^
|
||||
bug696301-script-2.js
|
||||
bug803225_test_mailto.html
|
||||
bug819051.sjs
|
||||
copypaste.js
|
||||
delayedServerEvents.sjs
|
||||
|
@ -180,16 +179,6 @@ support-files =
|
|||
file_htmlserializer_2_latin1.html
|
||||
file_htmlserializer_ipv6.html
|
||||
file_htmlserializer_ipv6_out.html
|
||||
file_mixed_content_frameNavigation.html
|
||||
file_mixed_content_frameNavigation_blankTarget.html
|
||||
file_mixed_content_frameNavigation_grandchild.html
|
||||
file_mixed_content_frameNavigation_innermost.html
|
||||
file_mixed_content_frameNavigation_secure.html
|
||||
file_mixed_content_frameNavigation_secure_grandchild.html
|
||||
file_mixed_content_main.html
|
||||
file_mixed_content_main_bug803225.html
|
||||
file_mixed_content_main_bug803225_websocket_wsh.py
|
||||
file_mixed_content_server.sjs
|
||||
file_mozfiledataurl_audio.ogg
|
||||
file_mozfiledataurl_doc.html
|
||||
file_mozfiledataurl_img.jpg
|
||||
|
@ -691,12 +680,6 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
|||
[test_meta_viewport4.html]
|
||||
[test_meta_viewport5.html]
|
||||
[test_meta_viewport6.html]
|
||||
[test_mixed_content_blocker.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
|
||||
[test_mixed_content_blocker_bug803225.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
|
||||
[test_mixed_content_blocker_frameNavigation.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
|
||||
[test_mozfiledataurl.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT
|
||||
[test_mozMatchesSelector.html]
|
||||
|
|
|
@ -20,6 +20,7 @@ GeckoCppUnitTests([
|
|||
MOCHITEST_MANIFESTS += [
|
||||
'chrome/mochitest.ini',
|
||||
'csp/mochitest.ini',
|
||||
'mixedcontentblocker/mochitest.ini',
|
||||
'mochitest.ini',
|
||||
'websocket_hybi/mochitest.ini',
|
||||
]
|
||||
|
|
|
@ -9697,10 +9697,11 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
|||
resultVar: See the docstring for CGCallGenerator.
|
||||
|
||||
foundVar: For getters and deleters, the generated code can also set a bool
|
||||
variable, declared by the caller, to indicate whether the given indexed or
|
||||
named property already existed or not. If the caller wants this, it should
|
||||
pass the name of the bool variable as the foundVar keyword argument to the
|
||||
constructor. The caller is responsible for declaring the variable.
|
||||
variable, declared by the caller, if the given indexed or named property
|
||||
already existed. If the caller wants this, it should pass the name of the
|
||||
bool variable as the foundVar keyword argument to the constructor. The
|
||||
caller is responsible for declaring the variable and initializing it to
|
||||
false.
|
||||
"""
|
||||
def __init__(self, descriptor, operation, checkFound=True,
|
||||
argumentMutableValue=None, resultVar=None, foundVar=None):
|
||||
|
@ -9740,7 +9741,7 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
|||
self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
|
||||
elif operation.isGetter() or operation.isDeleter():
|
||||
if foundVar is None:
|
||||
self.cgRoot.prepend(CGGeneric("bool found;\n"))
|
||||
self.cgRoot.prepend(CGGeneric("bool found = false;\n"))
|
||||
|
||||
def getArguments(self):
|
||||
args = [(a, a.identifier.name) for a in self.arguments]
|
||||
|
@ -10217,7 +10218,7 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod):
|
|||
if self.descriptor.supportsNamedProperties():
|
||||
set += fill(
|
||||
"""
|
||||
bool found;
|
||||
bool found = false;
|
||||
$*{presenceChecker}
|
||||
|
||||
if (found) {
|
||||
|
@ -10258,7 +10259,7 @@ class CGDOMJSProxyHandler_delete(ClassMethod):
|
|||
decls += "bool result;\n"
|
||||
if foundVar is None:
|
||||
foundVar = "found"
|
||||
decls += "bool found;\n"
|
||||
decls += "bool found = false;\n"
|
||||
setBp = fill(
|
||||
"""
|
||||
if (${foundVar}) {
|
||||
|
@ -10277,7 +10278,7 @@ class CGDOMJSProxyHandler_delete(ClassMethod):
|
|||
foundDecl = ""
|
||||
if foundVar is None:
|
||||
foundVar = "found"
|
||||
foundDecl = "bool found;\n"
|
||||
foundDecl = "bool found = false;\n"
|
||||
body = fill(
|
||||
"""
|
||||
$*{foundDecl}
|
||||
|
@ -10331,7 +10332,7 @@ class CGDOMJSProxyHandler_delete(ClassMethod):
|
|||
# unconditionally here.
|
||||
delete += fill(
|
||||
"""
|
||||
bool found;
|
||||
bool found = false;
|
||||
$*{namedBody}
|
||||
if (found) {
|
||||
return true;
|
||||
|
@ -10442,7 +10443,7 @@ class CGDOMJSProxyHandler_hasOwn(ClassMethod):
|
|||
"""
|
||||
int32_t index = GetArrayIndexFromId(cx, id);
|
||||
if (IsArrayIndex(index)) {
|
||||
bool found;
|
||||
bool found = false;
|
||||
$*{presenceChecker}
|
||||
|
||||
*bp = found;
|
||||
|
@ -10472,7 +10473,7 @@ class CGDOMJSProxyHandler_hasOwn(ClassMethod):
|
|||
# property names, so no need to check for those here.
|
||||
named = fill(
|
||||
"""
|
||||
bool found;
|
||||
bool found = false;
|
||||
$*{presenceChecker}
|
||||
|
||||
*bp = found;
|
||||
|
|
|
@ -65,6 +65,12 @@ IsValidDtmf(const char aChar) {
|
|||
(aChar >= 'A' && aChar <= 'D');
|
||||
}
|
||||
|
||||
static bool
|
||||
IsSupportedChld(const int aChld) {
|
||||
// We currently only support CHLD=0~3.
|
||||
return (aChld >= 0 && aChld <= 3);
|
||||
}
|
||||
|
||||
class BluetoothHfpManager::GetVolumeTask : public nsISettingsServiceCallback
|
||||
{
|
||||
public:
|
||||
|
@ -1420,6 +1426,13 @@ BluetoothHfpManager::CallHoldNotification(BluetoothHandsfreeCallHoldType aChld)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsSupportedChld((int)aChld)) {
|
||||
// We currently don't support Enhanced Call Control.
|
||||
// AT+CHLD=1x and AT+CHLD=2x will be ignored
|
||||
SendResponse(HFP_AT_RESPONSE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
SendResponse(HFP_AT_RESPONSE_OK);
|
||||
|
||||
nsAutoCString message("CHLD=");
|
||||
|
|
|
@ -62,6 +62,12 @@ IsValidDtmf(const char aChar) {
|
|||
(aChar >= 'A' && aChar <= 'D');
|
||||
}
|
||||
|
||||
static bool
|
||||
IsSupportedChld(const int aChld) {
|
||||
// We currently only support CHLD=0~3.
|
||||
return (aChld >= 0 && aChld <= 3);
|
||||
}
|
||||
|
||||
class BluetoothHfpManager::GetVolumeTask MOZ_FINAL : public nsISettingsServiceCallback
|
||||
{
|
||||
public:
|
||||
|
@ -1411,6 +1417,13 @@ BluetoothHfpManager::CallHoldNotification(BluetoothHandsfreeCallHoldType aChld)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsSupportedChld((int)aChld)) {
|
||||
// We currently don't support Enhanced Call Control.
|
||||
// AT+CHLD=1x and AT+CHLD=2x will be ignored
|
||||
SendResponse(HFP_AT_RESPONSE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
SendResponse(HFP_AT_RESPONSE_OK);
|
||||
|
||||
nsAutoCString message("CHLD=");
|
||||
|
|
|
@ -250,6 +250,7 @@ CanvasImageCache::NotifyDrawImage(Element* aImage,
|
|||
// We are overwriting an existing entry.
|
||||
gImageCache->mTotal -= entry->mData->SizeInBytes();
|
||||
gImageCache->RemoveObject(entry->mData);
|
||||
gImageCache->mSimpleCache.RemoveEntry(*entry->mData->mRequest);
|
||||
}
|
||||
gImageCache->AddObject(entry->mData);
|
||||
|
||||
|
|
|
@ -3678,9 +3678,7 @@ HTMLMediaElement::Buffered() const
|
|||
{
|
||||
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
||||
if (mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) {
|
||||
if (mMediaSource) {
|
||||
mMediaSource->GetBuffered(ranges);
|
||||
} else if (mDecoder) {
|
||||
if (mDecoder) {
|
||||
// If GetBuffered fails we ignore the error result and just return the
|
||||
// time ranges we found up till the error.
|
||||
mDecoder->GetBuffered(ranges);
|
||||
|
|
|
@ -92,6 +92,15 @@ public:
|
|||
static const index_type NoIndex = index_type(-1);
|
||||
|
||||
index_type Find(double aTime);
|
||||
|
||||
bool Contains(double aStart, double aEnd) {
|
||||
index_type target = Find(aStart);
|
||||
if (target == NoIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mRanges[target].mEnd >= aEnd;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# -*- 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/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIContentSecurityPolicy.idl'
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'dom_security'
|
||||
|
|
@ -677,11 +677,22 @@ void MediaDecoder::QueueMetadata(int64_t aPublishTime,
|
|||
}
|
||||
|
||||
bool
|
||||
MediaDecoder::IsDataCachedToEndOfResource()
|
||||
MediaDecoder::IsExpectingMoreData()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
return (mResource &&
|
||||
mResource->IsDataCachedToEndOfResource(mDecoderPosition));
|
||||
|
||||
// If there's no resource, we're probably just getting set up.
|
||||
if (!mResource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we've downloaded anything, we're not waiting for anything.
|
||||
if (mResource->IsDataCachedToEndOfResource(mDecoderPosition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, we should be getting data unless the stream is suspended.
|
||||
return !mResource->IsSuspended();
|
||||
}
|
||||
|
||||
void MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
|
||||
|
@ -899,7 +910,6 @@ NS_IMETHODIMP MediaDecoder::Observe(nsISupports *aSubjet,
|
|||
MediaDecoder::Statistics
|
||||
MediaDecoder::GetStatistics()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread() || OnStateMachineThread());
|
||||
Statistics result;
|
||||
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
|
|
|
@ -804,9 +804,12 @@ public:
|
|||
// the track list. Call on the main thread only.
|
||||
virtual void RemoveMediaTracks() MOZ_OVERRIDE;
|
||||
|
||||
// Returns true if the resource has been loaded. Acquires the monitor.
|
||||
// Call from any thread.
|
||||
virtual bool IsDataCachedToEndOfResource();
|
||||
// Returns true if the this decoder is expecting any more data to arrive
|
||||
// sometime in the not-too-distant future, either from the network or from
|
||||
// an appendBuffer call on a MediaSource element.
|
||||
//
|
||||
// Acquires the monitor. Call from any thread.
|
||||
virtual bool IsExpectingMoreData();
|
||||
|
||||
// Called when the video has completed playing.
|
||||
// Call on the main thread only.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "AbstractMediaDecoder.h"
|
||||
#include "MediaResource.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
|
@ -61,6 +62,7 @@ MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
|
|||
: mAudioCompactor(mAudioQueue)
|
||||
, mDecoder(aDecoder)
|
||||
, mIgnoreAudioOutputFormat(false)
|
||||
, mStartTime(-1)
|
||||
, mAudioDiscontinuity(false)
|
||||
, mVideoDiscontinuity(false)
|
||||
{
|
||||
|
@ -120,11 +122,17 @@ VideoData* MediaDecoderReader::DecodeToFirstVideoData()
|
|||
return (d = VideoQueue().PeekFront()) ? d : nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered,
|
||||
int64_t aStartTime)
|
||||
void
|
||||
MediaDecoderReader::SetStartTime(int64_t aStartTime)
|
||||
{
|
||||
MediaResource* stream = mDecoder->GetResource();
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
mStartTime = aStartTime;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered)
|
||||
{
|
||||
AutoPinned<MediaResource> stream(mDecoder->GetResource());
|
||||
int64_t durationUs = 0;
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
|
|
@ -135,9 +135,7 @@ public:
|
|||
mIgnoreAudioOutputFormat = true;
|
||||
}
|
||||
|
||||
// Populates aBuffered with the time ranges which are buffered. aStartTime
|
||||
// must be the presentation time of the first frame in the media, e.g.
|
||||
// the media time corresponding to playback time/position 0. This function
|
||||
// Populates aBuffered with the time ranges which are buffered. This function
|
||||
// is called on the main, decode, and state machine threads.
|
||||
//
|
||||
// This base implementation in MediaDecoderReader estimates the time ranges
|
||||
|
@ -151,11 +149,15 @@ public:
|
|||
// The OggReader relies on this base implementation not performing I/O,
|
||||
// since in FirefoxOS we can't do I/O on the main thread, where this is
|
||||
// called.
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
|
||||
int64_t aStartTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
|
||||
|
||||
virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio);
|
||||
|
||||
// Wait this number of seconds when buffering, then leave and play
|
||||
// as best as we can if the required amount of data hasn't been
|
||||
// retrieved.
|
||||
virtual uint32_t GetBufferingWait() { return 30; }
|
||||
|
||||
// Returns the number of bytes of memory allocated by structures/frames in
|
||||
// the video queue.
|
||||
size_t SizeOfVideoQueueInBytes() const;
|
||||
|
@ -185,6 +187,7 @@ public:
|
|||
// Indicates if the media is seekable.
|
||||
// ReadMetada should be called before calling this method.
|
||||
virtual bool IsMediaSeekable() = 0;
|
||||
void SetStartTime(int64_t aStartTime);
|
||||
|
||||
MediaTaskQueue* GetTaskQueue() {
|
||||
return mTaskQueue;
|
||||
|
@ -245,6 +248,11 @@ protected:
|
|||
// what we support.
|
||||
bool mIgnoreAudioOutputFormat;
|
||||
|
||||
// The start time of the media, in microseconds. This is the presentation
|
||||
// time of the first frame decoded from the media. This is initialized to -1,
|
||||
// and then set to a value >= by MediaDecoderStateMachine::SetStartTime(),
|
||||
// after which point it never changes.
|
||||
int64_t mStartTime;
|
||||
private:
|
||||
|
||||
nsRefPtr<RequestSampleCallback> mSampleDecodedCallback;
|
||||
|
|
|
@ -84,11 +84,6 @@ extern PRLogModuleInfo* gMediaDecoderLog;
|
|||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
// Wait this number of seconds when buffering, then leave and play
|
||||
// as best as we can if the required amount of data hasn't been
|
||||
// retrieved.
|
||||
static const uint32_t BUFFERING_WAIT_S = 30;
|
||||
|
||||
// If audio queue has less than this many usecs of decoded audio, we won't risk
|
||||
// trying to decode the video, we'll skip decoding video up to the next
|
||||
// keyframe. We may increase this value for an individual decoder if we
|
||||
|
@ -224,7 +219,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
mAmpleVideoFrames =
|
||||
std::max<uint32_t>(Preferences::GetUint("media.video-queue.default-size", 10), 3);
|
||||
|
||||
mBufferingWait = mScheduler->IsRealTime() ? 0 : BUFFERING_WAIT_S;
|
||||
mBufferingWait = mScheduler->IsRealTime() ? 0 : mReader->GetBufferingWait();
|
||||
mLowDataThresholdUsecs = mScheduler->IsRealTime() ? 0 : LOW_DATA_THRESHOLD_USECS;
|
||||
|
||||
mVideoPrerollFrames = mScheduler->IsRealTime() ? 0 : mAmpleVideoFrames / 2;
|
||||
|
@ -821,9 +816,15 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
|||
return;
|
||||
}
|
||||
|
||||
// If the decoder is waiting for data, there's nothing more to do after
|
||||
// clearing the pending request.
|
||||
// If the decoder is waiting for data, we need to make sure that the requests
|
||||
// are cleared, which happened above. Additionally, if we're out of decoded
|
||||
// samples, we need to switch to buffering mode.
|
||||
if (aReason == RequestSampleCallback::WAITING_FOR_DATA) {
|
||||
bool outOfSamples = isAudio ? !AudioQueue().GetSize() : !VideoQueue().GetSize();
|
||||
if (outOfSamples) {
|
||||
StartBuffering();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1296,12 +1297,11 @@ void MediaDecoderStateMachine::SetDuration(int64_t aDuration)
|
|||
return;
|
||||
}
|
||||
|
||||
if (mStartTime != -1) {
|
||||
mEndTime = mStartTime + aDuration;
|
||||
} else {
|
||||
mStartTime = 0;
|
||||
mEndTime = aDuration;
|
||||
if (mStartTime == -1) {
|
||||
SetStartTime(0);
|
||||
}
|
||||
|
||||
mEndTime = mStartTime + aDuration;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::UpdateEstimatedDuration(int64_t aDuration)
|
||||
|
@ -1497,8 +1497,11 @@ void MediaDecoderStateMachine::NotifyDataArrived(const char* aBuffer,
|
|||
// faster than played, mEndTime won't reflect the end of playable data
|
||||
// since we haven't played the frame at the end of buffered data. So update
|
||||
// mEndTime here as new data is downloaded to prevent such a lag.
|
||||
//
|
||||
// Make sure to only do this if we have a start time, otherwise the reader
|
||||
// doesn't know how to compute GetBuffered.
|
||||
nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
|
||||
if (mDecoder->IsInfinite() &&
|
||||
if (mDecoder->IsInfinite() && (mStartTime != -1) &&
|
||||
NS_SUCCEEDED(mDecoder->GetBuffered(buffered)))
|
||||
{
|
||||
uint32_t length = 0;
|
||||
|
@ -1911,28 +1914,29 @@ bool MediaDecoderStateMachine::HasLowUndecodedData()
|
|||
return HasLowUndecodedData(mLowDataThresholdUsecs);
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::HasLowUndecodedData(double aUsecs)
|
||||
bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs)
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
NS_ASSERTION(mState > DECODER_STATE_DECODING_FIRSTFRAME,
|
||||
"Must have loaded first frame for GetBuffered() to work");
|
||||
|
||||
bool reliable;
|
||||
double bytesPerSecond = mDecoder->ComputePlaybackRate(&reliable);
|
||||
if (!reliable) {
|
||||
// Default to assuming we have enough
|
||||
return false;
|
||||
}
|
||||
nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
|
||||
nsresult rv = mReader->GetBuffered(buffered.get());
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
MediaResource* stream = mDecoder->GetResource();
|
||||
int64_t currentPos = stream->Tell();
|
||||
int64_t requiredPos = currentPos + int64_t((aUsecs/1000000.0)*bytesPerSecond);
|
||||
int64_t length = stream->GetLength();
|
||||
if (length >= 0) {
|
||||
requiredPos = std::min(requiredPos, length);
|
||||
int64_t endOfDecodedVideoData = INT64_MAX;
|
||||
if (HasVideo() && !VideoQueue().AtEndOfStream()) {
|
||||
endOfDecodedVideoData = VideoQueue().Peek() ? VideoQueue().Peek()->GetEndTime() : mVideoFrameEndTime;
|
||||
}
|
||||
int64_t endOfDecodedAudioData = INT64_MAX;
|
||||
if (HasAudio() && !AudioQueue().AtEndOfStream()) {
|
||||
endOfDecodedAudioData = AudioQueue().Peek() ? AudioQueue().Peek()->GetEndTime() : GetAudioClock();
|
||||
}
|
||||
int64_t endOfDecodedData = std::min(endOfDecodedVideoData, endOfDecodedAudioData);
|
||||
|
||||
return stream->GetCachedDataEnd(currentPos) < requiredPos;
|
||||
return endOfDecodedData != INT64_MAX &&
|
||||
!buffered->Contains(static_cast<double>(endOfDecodedData) / USECS_PER_S,
|
||||
static_cast<double>(std::min(endOfDecodedData + aUsecs, GetDuration())) / USECS_PER_S);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2567,8 +2571,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
|
||||
(mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS)
|
||||
: HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
|
||||
!mDecoder->IsDataCachedToEndOfResource() &&
|
||||
!resource->IsSuspended())
|
||||
mDecoder->IsExpectingMoreData())
|
||||
{
|
||||
DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
|
||||
mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
|
||||
|
@ -2827,12 +2830,10 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
|||
|
||||
// Check to see if we don't have enough data to play up to the next frame.
|
||||
// If we don't, switch to buffering mode.
|
||||
MediaResource* resource = mDecoder->GetResource();
|
||||
if (mState == DECODER_STATE_DECODING &&
|
||||
mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
|
||||
HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
|
||||
!mDecoder->IsDataCachedToEndOfResource() &&
|
||||
!resource->IsSuspended()) {
|
||||
mDecoder->IsExpectingMoreData()) {
|
||||
if (JustExitedQuickBuffering() || HasLowUndecodedData()) {
|
||||
if (currentFrame) {
|
||||
VideoQueue().PushFront(currentFrame.forget());
|
||||
|
@ -3024,7 +3025,7 @@ MediaDecoderStateMachine::DropAudioUpToSeekTarget(AudioData* aSample)
|
|||
|
||||
void MediaDecoderStateMachine::SetStartTime(int64_t aStartTimeUsecs)
|
||||
{
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
AssertCurrentThreadInMonitor();
|
||||
DECODER_LOG("SetStartTime(%lld)", aStartTimeUsecs);
|
||||
mStartTime = 0;
|
||||
if (aStartTimeUsecs != 0) {
|
||||
|
@ -3038,6 +3039,11 @@ void MediaDecoderStateMachine::SetStartTime(int64_t aStartTimeUsecs)
|
|||
mEndTime = mStartTime + mEndTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Pass along this immutable value to the reader so that it can make
|
||||
// calculations independently of the state machine.
|
||||
mReader->SetStartTime(mStartTime);
|
||||
|
||||
// Set the audio start time to be start of media. If this lies before the
|
||||
// first actual audio frame we have, we'll inject silence during playback
|
||||
// to ensure the audio starts at the correct time.
|
||||
|
@ -3125,15 +3131,6 @@ void MediaDecoderStateMachine::StartBuffering()
|
|||
#endif
|
||||
}
|
||||
|
||||
nsresult MediaDecoderStateMachine::GetBuffered(dom::TimeRanges* aBuffered) {
|
||||
MediaResource* resource = mDecoder->GetResource();
|
||||
NS_ENSURE_TRUE(resource, NS_ERROR_FAILURE);
|
||||
resource->Pin();
|
||||
nsresult res = mReader->GetBuffered(aBuffered, mStartTime);
|
||||
resource->Unpin();
|
||||
return res;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
|
|
@ -269,7 +269,17 @@ public:
|
|||
return mState == DECODER_STATE_SEEKING;
|
||||
}
|
||||
|
||||
nsresult GetBuffered(dom::TimeRanges* aBuffered);
|
||||
nsresult GetBuffered(dom::TimeRanges* aBuffered) {
|
||||
// It's possible for JS to query .buffered before we've determined the start
|
||||
// time from metadata, in which case the reader isn't ready to be asked this
|
||||
// question.
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mStartTime < 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mReader->GetBuffered(aBuffered);
|
||||
}
|
||||
|
||||
void SetPlaybackRate(double aPlaybackRate);
|
||||
void SetPreservesPitch(bool aPreservesPitch);
|
||||
|
@ -443,7 +453,7 @@ protected:
|
|||
bool HasLowUndecodedData();
|
||||
|
||||
// Returns true if we have less than aUsecs of undecoded data available.
|
||||
bool HasLowUndecodedData(double aUsecs);
|
||||
bool HasLowUndecodedData(int64_t aUsecs);
|
||||
|
||||
// Returns the number of unplayed usecs of audio we've got decoded and/or
|
||||
// pushed to the hardware waiting to play. This is how much audio we can
|
||||
|
|
|
@ -718,6 +718,33 @@ protected:
|
|||
bool mIsTransportSeekable;
|
||||
};
|
||||
|
||||
/**
|
||||
* RAII class that handles pinning and unpinning for MediaResource and derived.
|
||||
* This should be used when making calculations that involve potentially-cached
|
||||
* MediaResource data, so that the state of the world can't change out from under
|
||||
* us.
|
||||
*/
|
||||
template<class T>
|
||||
class MOZ_STACK_CLASS AutoPinned {
|
||||
public:
|
||||
explicit AutoPinned(T* aResource MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mResource(aResource) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
MOZ_ASSERT(mResource);
|
||||
mResource->Pin();
|
||||
}
|
||||
|
||||
~AutoPinned() {
|
||||
mResource->Unpin();
|
||||
}
|
||||
|
||||
operator T*() const { return mResource; }
|
||||
T* operator->() const { return mResource; }
|
||||
|
||||
private:
|
||||
T* mResource;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
|
@ -809,13 +809,11 @@ MP4Reader::UpdateIndex()
|
|||
return;
|
||||
}
|
||||
|
||||
MediaResource* resource = mDecoder->GetResource();
|
||||
resource->Pin();
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
nsTArray<MediaByteRange> ranges;
|
||||
if (NS_SUCCEEDED(resource->GetCachedRanges(ranges))) {
|
||||
mDemuxer->UpdateIndex(ranges);
|
||||
}
|
||||
resource->Unpin();
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -830,25 +828,24 @@ MP4Reader::GetEvictionOffset(double aTime)
|
|||
}
|
||||
|
||||
nsresult
|
||||
MP4Reader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
||||
MP4Reader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
if (!mIndexReady) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first");
|
||||
|
||||
MediaResource* resource = mDecoder->GetResource();
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
nsTArray<MediaByteRange> ranges;
|
||||
resource->Pin();
|
||||
nsresult rv = resource->GetCachedRanges(ranges);
|
||||
resource->Unpin();
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsTArray<Interval<Microseconds>> timeRanges;
|
||||
mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges);
|
||||
for (size_t i = 0; i < timeRanges.Length(); i++) {
|
||||
aBuffered->Add((timeRanges[i].start - aStartTime) / 1000000.0,
|
||||
(timeRanges[i].end - aStartTime) / 1000000.0);
|
||||
aBuffered->Add((timeRanges[i].start - mStartTime) / 1000000.0,
|
||||
(timeRanges[i].end - mStartTime) / 1000000.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,7 @@ public:
|
|||
|
||||
virtual int64_t GetEvictionOffset(double aTime) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
|
||||
int64_t aStartTime) MOZ_OVERRIDE;
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE;
|
||||
|
||||
// For Media Resource Management
|
||||
virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;
|
||||
|
|
|
@ -816,8 +816,7 @@ void GStreamerReader::Seek(int64_t aTarget,
|
|||
GetCallback()->OnSeekCompleted(NS_OK);
|
||||
}
|
||||
|
||||
nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered,
|
||||
int64_t aStartTime)
|
||||
nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
if (!mInfo.HasValidMedia()) {
|
||||
return NS_OK;
|
||||
|
@ -826,7 +825,7 @@ nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered,
|
|||
#if GST_VERSION_MAJOR == 0
|
||||
GstFormat format = GST_FORMAT_TIME;
|
||||
#endif
|
||||
MediaResource* resource = mDecoder->GetResource();
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
nsTArray<MediaByteRange> ranges;
|
||||
resource->GetCachedRanges(ranges);
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
int64_t aStartTime,
|
||||
int64_t aEndTime,
|
||||
int64_t aCurrentTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
|
||||
|
||||
virtual void NotifyDataArrived(const char *aBuffer,
|
||||
uint32_t aLength,
|
||||
|
|
|
@ -36,6 +36,12 @@ public:
|
|||
decoder->SetResource(resource);
|
||||
|
||||
reader->Init(nullptr);
|
||||
{
|
||||
// This needs to be done before invoking GetBuffered. This is normally
|
||||
// done by MediaDecoderStateMachine.
|
||||
ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
|
||||
reader->SetStartTime(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Init() {
|
||||
|
@ -72,7 +78,7 @@ TEST(MP4Reader, BufferedRange)
|
|||
b->resource->MockAddBufferedRange(248400, 327455);
|
||||
|
||||
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
|
||||
EXPECT_EQ(1U, ranges->Length());
|
||||
double start = 0;
|
||||
EXPECT_EQ(NS_OK, ranges->Start(0, &start));
|
||||
|
@ -93,7 +99,7 @@ TEST(MP4Reader, BufferedRangeMissingLastByte)
|
|||
b->resource->MockAddBufferedRange(324913, 327455);
|
||||
|
||||
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
|
||||
EXPECT_EQ(1U, ranges->Length());
|
||||
double start = 0;
|
||||
EXPECT_EQ(NS_OK, ranges->Start(0, &start));
|
||||
|
@ -114,7 +120,7 @@ TEST(MP4Reader, BufferedRangeSyncFrame)
|
|||
b->resource->MockAddBufferedRange(146336, 327455);
|
||||
|
||||
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
|
||||
EXPECT_EQ(1U, ranges->Length());
|
||||
double start = 0;
|
||||
EXPECT_EQ(NS_OK, ranges->Start(0, &start));
|
||||
|
@ -172,7 +178,7 @@ TEST(MP4Reader, CompositionOrder)
|
|||
b->resource->MockAddBufferedRange(13220, 13901);
|
||||
|
||||
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
|
||||
EXPECT_EQ(2U, ranges->Length());
|
||||
|
||||
double start = 0;
|
||||
|
@ -222,7 +228,7 @@ TEST(MP4Reader, Normalised)
|
|||
b->resource->MockAddBufferedRange(48, 13901);
|
||||
|
||||
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges, 0));
|
||||
EXPECT_EQ(NS_OK, b->reader->GetBuffered(ranges));
|
||||
EXPECT_EQ(1U, ranges->Length());
|
||||
|
||||
double start = 0;
|
||||
|
|
|
@ -218,6 +218,22 @@ public:
|
|||
aData[7] == 'p';
|
||||
}
|
||||
|
||||
bool IsMediaSegmentPresent(const uint8_t* aData, uint32_t aLength)
|
||||
{
|
||||
ContainerParser::IsMediaSegmentPresent(aData, aLength);
|
||||
if (aLength < 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t chunk_size = BigEndian::readUint32(aData);
|
||||
if (chunk_size < 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return aData[4] == 'm' && aData[5] == 'o' && aData[6] == 'o' &&
|
||||
aData[7] == 'f';
|
||||
}
|
||||
|
||||
bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
|
||||
int64_t& aStart, int64_t& aEnd)
|
||||
{
|
||||
|
|
|
@ -166,7 +166,8 @@ MediaSource::Duration()
|
|||
if (mReadyState == MediaSourceReadyState::Closed) {
|
||||
return UnspecifiedNaN<double>();
|
||||
}
|
||||
return mDuration;
|
||||
MOZ_ASSERT(mDecoder);
|
||||
return mDecoder->GetMediaSourceDuration();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -183,7 +184,7 @@ MediaSource::SetDuration(double aDuration, ErrorResult& aRv)
|
|||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
DurationChange(aDuration, aRv);
|
||||
mDecoder->SetMediaSourceDuration(aDuration);
|
||||
}
|
||||
|
||||
already_AddRefed<SourceBuffer>
|
||||
|
@ -271,7 +272,7 @@ MediaSource::EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, Er
|
|||
mSourceBuffers->Ended();
|
||||
mDecoder->Ended();
|
||||
if (!aError.WasPassed()) {
|
||||
DurationChange(mSourceBuffers->GetHighestBufferedEndTime(), aRv);
|
||||
mDecoder->SetMediaSourceDuration(mSourceBuffers->GetHighestBufferedEndTime());
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
@ -336,7 +337,6 @@ MediaSource::Detach()
|
|||
mDecoder = nullptr;
|
||||
mFirstSourceBufferInitialized = false;
|
||||
SetReadyState(MediaSourceReadyState::Closed);
|
||||
mDuration = UnspecifiedNaN<double>();
|
||||
if (mActiveSourceBuffers) {
|
||||
mActiveSourceBuffers->Clear();
|
||||
}
|
||||
|
@ -345,50 +345,8 @@ MediaSource::Detach()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSource::GetBuffered(TimeRanges* aBuffered)
|
||||
{
|
||||
MOZ_ASSERT(aBuffered->Length() == 0);
|
||||
if (mActiveSourceBuffers->IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
double highestEndTime = 0;
|
||||
|
||||
nsTArray<nsRefPtr<TimeRanges>> activeRanges;
|
||||
for (uint32_t i = 0; i < mActiveSourceBuffers->Length(); ++i) {
|
||||
bool found;
|
||||
SourceBuffer* sourceBuffer = mActiveSourceBuffers->IndexedGetter(i, found);
|
||||
|
||||
ErrorResult dummy;
|
||||
*activeRanges.AppendElement() = sourceBuffer->GetBuffered(dummy);
|
||||
|
||||
highestEndTime = std::max(highestEndTime, activeRanges.LastElement()->GetEndTime());
|
||||
}
|
||||
|
||||
TimeRanges* intersectionRanges = aBuffered;
|
||||
intersectionRanges->Add(0, highestEndTime);
|
||||
|
||||
for (uint32_t i = 0; i < activeRanges.Length(); ++i) {
|
||||
TimeRanges* sourceRanges = activeRanges[i];
|
||||
|
||||
if (mReadyState == MediaSourceReadyState::Ended) {
|
||||
// Set the end time on the last range to highestEndTime by adding a
|
||||
// new range spanning the current end time to highestEndTime, which
|
||||
// Normalize() will then merge with the old last range.
|
||||
sourceRanges->Add(sourceRanges->GetEndTime(), highestEndTime);
|
||||
sourceRanges->Normalize();
|
||||
}
|
||||
|
||||
intersectionRanges->Intersection(sourceRanges);
|
||||
}
|
||||
|
||||
MSE_DEBUG("MediaSource(%p)::GetBuffered ranges=%s", this, DumpTimeRanges(intersectionRanges).get());
|
||||
}
|
||||
|
||||
MediaSource::MediaSource(nsPIDOMWindow* aWindow)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
, mDuration(UnspecifiedNaN<double>())
|
||||
, mDecoder(nullptr)
|
||||
, mPrincipal(nullptr)
|
||||
, mReadyState(MediaSourceReadyState::Closed)
|
||||
|
@ -457,23 +415,19 @@ MediaSource::QueueAsyncSimpleEvent(const char* aName)
|
|||
}
|
||||
|
||||
void
|
||||
MediaSource::DurationChange(double aNewDuration, ErrorResult& aRv)
|
||||
MediaSource::DurationChange(double aOldDuration, double aNewDuration)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("MediaSource(%p)::DurationChange(aNewDuration=%f)", this, aNewDuration);
|
||||
if (mDuration == aNewDuration) {
|
||||
return;
|
||||
}
|
||||
double oldDuration = mDuration;
|
||||
mDuration = aNewDuration;
|
||||
if (aNewDuration < oldDuration) {
|
||||
mSourceBuffers->Remove(aNewDuration, oldDuration, aRv);
|
||||
if (aRv.Failed()) {
|
||||
|
||||
if (aNewDuration < aOldDuration) {
|
||||
ErrorResult rv;
|
||||
mSourceBuffers->Remove(aNewDuration, aOldDuration, rv);
|
||||
if (rv.Failed()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO: If partial audio frames/text cues exist, clamp duration based on mSourceBuffers.
|
||||
// TODO: Update media element's duration and run element's duration change algorithm.
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -74,8 +74,6 @@ public:
|
|||
bool Attach(MediaSourceDecoder* aDecoder);
|
||||
void Detach();
|
||||
|
||||
void GetBuffered(TimeRanges* aBuffered);
|
||||
|
||||
// Set mReadyState to aState and fire the required events at the MediaSource.
|
||||
void SetReadyState(MediaSourceReadyState aState);
|
||||
|
||||
|
@ -122,12 +120,10 @@ private:
|
|||
void DispatchSimpleEvent(const char* aName);
|
||||
void QueueAsyncSimpleEvent(const char* aName);
|
||||
|
||||
void DurationChange(double aNewDuration, ErrorResult& aRv);
|
||||
void DurationChange(double aOldDuration, double aNewDuration);
|
||||
|
||||
void InitializationEvent();
|
||||
|
||||
double mDuration;
|
||||
|
||||
nsRefPtr<SourceBufferList> mSourceBuffers;
|
||||
nsRefPtr<SourceBufferList> mActiveSourceBuffers;
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ class SourceBufferDecoder;
|
|||
|
||||
MediaSourceDecoder::MediaSourceDecoder(dom::HTMLMediaElement* aElement)
|
||||
: mMediaSource(nullptr)
|
||||
, mMediaSourceDuration(UnspecifiedNaN<double>())
|
||||
{
|
||||
Init(aElement);
|
||||
}
|
||||
|
@ -82,7 +83,7 @@ MediaSourceDecoder::GetSeekable(dom::TimeRanges* aSeekable)
|
|||
// Return empty range.
|
||||
} else if (duration > 0 && mozilla::IsInfinite(duration)) {
|
||||
nsRefPtr<dom::TimeRanges> bufferedRanges = new dom::TimeRanges();
|
||||
mMediaSource->GetBuffered(bufferedRanges);
|
||||
mReader->GetBuffered(bufferedRanges);
|
||||
aSeekable->Add(bufferedRanges->GetStartTime(), bufferedRanges->GetEndTime());
|
||||
} else {
|
||||
aSeekable->Add(0, duration);
|
||||
|
@ -164,15 +165,81 @@ MediaSourceDecoder::Ended()
|
|||
mon.NotifyAll();
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceDecoder::IsExpectingMoreData()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
return !mReader->IsEnded();
|
||||
}
|
||||
|
||||
class DurationChangedRunnable : public nsRunnable {
|
||||
public:
|
||||
explicit DurationChangedRunnable(MediaSourceDecoder* aDecoder,
|
||||
double aOldDuration,
|
||||
double aNewDuration)
|
||||
: mDecoder(aDecoder)
|
||||
, mOldDuration(aOldDuration)
|
||||
, mNewDuration(aNewDuration)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
|
||||
mDecoder->DurationChanged(mOldDuration, mNewDuration);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<MediaSourceDecoder> mDecoder;
|
||||
double mOldDuration;
|
||||
double mNewDuration;
|
||||
};
|
||||
|
||||
void
|
||||
MediaSourceDecoder::DurationChanged(double aOldDuration, double aNewDuration)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Run the MediaSource duration changed algorithm
|
||||
if (mMediaSource) {
|
||||
mMediaSource->DurationChange(aOldDuration, aNewDuration);
|
||||
}
|
||||
// Run the MediaElement duration changed algorithm
|
||||
MediaDecoder::DurationChanged();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::SetDecodedDuration(int64_t aDuration)
|
||||
{
|
||||
// Only use the decoded duration if one wasn't already
|
||||
// set.
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
if (!mMediaSource || !IsNaN(mMediaSourceDuration)) {
|
||||
return;
|
||||
}
|
||||
double duration = aDuration;
|
||||
duration /= USECS_PER_S;
|
||||
SetMediaSourceDuration(duration);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::SetMediaSourceDuration(double aDuration)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mMediaSource) {
|
||||
return;
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
double oldDuration = mMediaSourceDuration;
|
||||
mMediaSourceDuration = aDuration;
|
||||
mDecoderStateMachine->SetDuration(aDuration * USECS_PER_S);
|
||||
if (NS_IsMainThread()) {
|
||||
DurationChanged(oldDuration, aDuration);
|
||||
} else {
|
||||
nsRefPtr<nsIRunnable> task =
|
||||
new DurationChangedRunnable(this, oldDuration, aDuration);
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
ErrorResult dummy;
|
||||
mMediaSource->DurationChange(aDuration, dummy);
|
||||
}
|
||||
|
||||
double
|
||||
MediaSourceDecoder::GetMediaSourceDuration()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
return mMediaSourceDuration;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -52,8 +52,12 @@ public:
|
|||
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
|
||||
|
||||
void Ended();
|
||||
bool IsExpectingMoreData() MOZ_OVERRIDE;
|
||||
|
||||
void SetDecodedDuration(int64_t aDuration);
|
||||
void SetMediaSourceDuration(double aDuration);
|
||||
double GetMediaSourceDuration();
|
||||
void DurationChanged(double aOldDuration, double aNewDuration);
|
||||
|
||||
// Called whenever a TrackBuffer has new data appended or a new decoder
|
||||
// initializes. Safe to call from any thread.
|
||||
|
@ -73,6 +77,9 @@ private:
|
|||
// mMediaSource.
|
||||
dom::MediaSource* mMediaSource;
|
||||
nsRefPtr<MediaSourceReader> mReader;
|
||||
|
||||
// Protected by GetReentrantMonitor()
|
||||
double mMediaSourceDuration;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -33,6 +33,15 @@ extern PRLogModuleInfo* GetMediaSourceAPILog();
|
|||
#define MSE_API(...)
|
||||
#endif
|
||||
|
||||
// When a stream hits EOS it needs to decide what other stream to switch to. Due
|
||||
// to inaccuracies is determining buffer end frames (Bug 1065207) and rounding
|
||||
// issues we use a fuzz factor to determine the end time of this stream for
|
||||
// switching to the new stream. This value is based on the end of frame
|
||||
// default value used in Blink, kDefaultBufferDurationInMs.
|
||||
#define EOS_FUZZ_US 125000
|
||||
|
||||
using mozilla::dom::TimeRanges;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
|
||||
|
@ -173,13 +182,43 @@ MediaSourceReader::OnNotDecoded(MediaData::Type aType, RequestSampleCallback::No
|
|||
GetCallback()->OnNotDecoded(aType, aReason);
|
||||
return;
|
||||
}
|
||||
// End of stream. Force switching past this stream to another reader by
|
||||
// switching to the end of the buffered range.
|
||||
MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM);
|
||||
nsRefPtr<MediaDecoderReader> reader = aType == MediaData::AUDIO_DATA ?
|
||||
mAudioReader : mVideoReader;
|
||||
|
||||
// See if we can find a different reader that can pick up where we left off.
|
||||
if (aType == MediaData::AUDIO_DATA && SwitchAudioReader(mLastAudioTime)) {
|
||||
// Find the closest approximation to the end time for this stream.
|
||||
// mLast{Audio,Video}Time differs from the actual end time because of
|
||||
// Bug 1065207 - the duration of a WebM fragment is an estimate not the
|
||||
// actual duration. In the case of audio time an example of where they
|
||||
// differ would be the actual sample duration being small but the
|
||||
// previous sample being large. The buffered end time uses that last
|
||||
// sample duration as an estimate of the end time duration giving an end
|
||||
// time that is greater than mLastAudioTime, which is the actual sample
|
||||
// end time.
|
||||
// Reader switching is based on the buffered end time though so they can be
|
||||
// quite different. By using the EOS_FUZZ_US and the buffered end time we
|
||||
// attempt to account for this difference.
|
||||
int64_t* time = aType == MediaData::AUDIO_DATA ? &mLastAudioTime : &mLastVideoTime;
|
||||
if (reader) {
|
||||
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
||||
reader->GetBuffered(ranges);
|
||||
if (ranges->Length() > 0) {
|
||||
// End time is a double so we convert to nearest by adding 0.5.
|
||||
int64_t end = ranges->GetEndTime() * USECS_PER_S + 0.5;
|
||||
*time = std::max(*time, end);
|
||||
}
|
||||
}
|
||||
|
||||
// See if we can find a different reader that can pick up where we left off. We use the
|
||||
// EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
|
||||
// 1065207 - the duration of a WebM frame is an estimate.
|
||||
if (aType == MediaData::AUDIO_DATA && SwitchAudioReader(*time + EOS_FUZZ_US)) {
|
||||
RequestAudioData();
|
||||
return;
|
||||
}
|
||||
if (aType == MediaData::VIDEO_DATA && SwitchVideoReader(mLastVideoTime)) {
|
||||
if (aType == MediaData::VIDEO_DATA && SwitchVideoReader(*time + EOS_FUZZ_US)) {
|
||||
RequestVideoData(false, 0);
|
||||
return;
|
||||
}
|
||||
|
@ -316,6 +355,15 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType)
|
|||
if (!reader) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// MSE uses a start time of 0 everywhere. Set that immediately on the
|
||||
// subreader to make sure that it's always in a state where we can invoke
|
||||
// GetBuffered on it.
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
|
||||
reader->SetStartTime(0);
|
||||
}
|
||||
|
||||
// Set a callback on the subreader that forwards calls to this reader.
|
||||
// This reader will then forward them onto the state machine via this
|
||||
// reader's callback.
|
||||
|
@ -498,6 +546,46 @@ MediaSourceReader::AttemptSeek()
|
|||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT(aBuffered->Length() == 0);
|
||||
if (mTrackBuffers.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
double highestEndTime = 0;
|
||||
|
||||
nsTArray<nsRefPtr<TimeRanges>> activeRanges;
|
||||
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
||||
nsRefPtr<TimeRanges> r = new TimeRanges();
|
||||
mTrackBuffers[i]->Buffered(r);
|
||||
activeRanges.AppendElement(r);
|
||||
highestEndTime = std::max(highestEndTime, activeRanges.LastElement()->GetEndTime());
|
||||
}
|
||||
|
||||
TimeRanges* intersectionRanges = aBuffered;
|
||||
intersectionRanges->Add(0, highestEndTime);
|
||||
|
||||
for (uint32_t i = 0; i < activeRanges.Length(); ++i) {
|
||||
TimeRanges* sourceRanges = activeRanges[i];
|
||||
|
||||
if (IsEnded()) {
|
||||
// Set the end time on the last range to highestEndTime by adding a
|
||||
// new range spanning the current end time to highestEndTime, which
|
||||
// Normalize() will then merge with the old last range.
|
||||
sourceRanges->Add(sourceRanges->GetEndTime(), highestEndTime);
|
||||
sourceRanges->Normalize();
|
||||
}
|
||||
|
||||
intersectionRanges->Intersection(sourceRanges);
|
||||
}
|
||||
|
||||
MSE_DEBUG("MediaSourceReader(%p)::GetBuffered ranges=%s", this, DumpTimeRanges(intersectionRanges).get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
|
||||
{
|
||||
|
@ -542,13 +630,7 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
|
|||
}
|
||||
|
||||
if (maxDuration != -1) {
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->SetMediaDuration(maxDuration);
|
||||
nsRefPtr<nsIRunnable> task (
|
||||
NS_NewRunnableMethodWithArg<double>(static_cast<MediaSourceDecoder*>(mDecoder),
|
||||
&MediaSourceDecoder::SetMediaSourceDuration,
|
||||
static_cast<double>(maxDuration) / USECS_PER_S));
|
||||
NS_DispatchToMainThread(task);
|
||||
static_cast<MediaSourceDecoder*>(mDecoder)->SetDecodedDuration(maxDuration);
|
||||
}
|
||||
|
||||
*aInfo = mInfo;
|
||||
|
|
|
@ -75,12 +75,21 @@ public:
|
|||
// as chrome/blink and assumes that we always start at t=0.
|
||||
virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio) MOZ_OVERRIDE { return 0; }
|
||||
|
||||
// Buffering waits (in which we decline to present decoded frames because we
|
||||
// "don't have enough") don't really make sense for MSE. The delay is
|
||||
// essentially a streaming heuristic, but JS is supposed to take care of that
|
||||
// in the MSE world. Avoid injecting inexplicable delays.
|
||||
virtual uint32_t GetBufferingWait() { return 0; }
|
||||
|
||||
bool IsMediaSeekable() { return true; }
|
||||
|
||||
nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE;
|
||||
void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
||||
int64_t aCurrentTime) MOZ_OVERRIDE;
|
||||
|
||||
// Acquires the decoder monitor, and is thus callable on any thread.
|
||||
nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE;
|
||||
|
||||
already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
|
||||
|
||||
void AddTrackBuffer(TrackBuffer* aTrackBuffer);
|
||||
|
|
|
@ -225,8 +225,7 @@ SourceBufferDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, in
|
|||
nsresult
|
||||
SourceBufferDecoder::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
// XXX: Need mStartTime (from StateMachine) instead of passing 0.
|
||||
return mReader->GetBuffered(aBuffered, 0);
|
||||
return mReader->GetBuffered(aBuffered);
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
|
|
@ -232,7 +232,6 @@ double
|
|||
TrackBuffer::Buffered(dom::TimeRanges* aRanges)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
double highestEndTime = 0;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
// Returns the highest end time of all of the buffered ranges in the
|
||||
// decoders managed by this TrackBuffer, and returns the union of the
|
||||
// decoders buffered ranges in aRanges.
|
||||
// decoders buffered ranges in aRanges. This may be called on any thread.
|
||||
double Buffered(dom::TimeRanges* aRanges);
|
||||
|
||||
// Mark the current decoder's resource as ended, clear mCurrentDecoder and
|
||||
|
|
|
@ -8,6 +8,7 @@ support-files =
|
|||
[test_MediaSource.html]
|
||||
[test_MediaSource_disabled.html]
|
||||
[test_BufferedSeek.html]
|
||||
[test_BufferingWait.html]
|
||||
[test_FrameSelection.html]
|
||||
[test_HaveMetadataUnbufferedSeek.html]
|
||||
[test_LoadedMetadataFired.html]
|
||||
|
@ -17,4 +18,5 @@ support-files =
|
|||
[test_SeekableBeforeEndOfStreamSplit.html]
|
||||
[test_SplitAppendDelay.html]
|
||||
[test_SplitAppend.html]
|
||||
[test_WaitingOnMissingData.html]
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
|
||||
<title>MSE: Don't get stuck buffering for too long when we have frames to show</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="mediasource.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test"><script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var receivedSourceOpen = false;
|
||||
runWithMSE(function(ms, v) {
|
||||
ms.addEventListener("sourceopen", function() {
|
||||
ok(true, "Receive a sourceopen event");
|
||||
ok(!receivedSourceOpen, "Should only receive one sourceopen for this test");
|
||||
receivedSourceOpen = true;
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
ok(sb, "Create a SourceBuffer");
|
||||
|
||||
function once(target, name, cb) {
|
||||
target.addEventListener(name, function() {
|
||||
target.removeEventListener(name, cb);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
function loadSegment(typedArray) {
|
||||
info(`Loading buffer: [${typedArray.byteOffset}, ${typedArray.byteOffset + typedArray.byteLength})`);
|
||||
return new Promise(function(resolve, reject) {
|
||||
once(sb, 'update', resolve);
|
||||
sb.appendBuffer(typedArray);
|
||||
});
|
||||
}
|
||||
|
||||
function waitUntilTime(targetTime) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
v.addEventListener("waiting", function onwaiting() {
|
||||
info("Got a waiting event at " + v.currentTime);
|
||||
if (v.currentTime >= targetTime) {
|
||||
ok(true, "Reached target time of: " + targetTime);
|
||||
v.removeEventListener("waiting", onwaiting);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fetchWithXHR("seek.webm", function(arrayBuffer) {
|
||||
sb.addEventListener('error', (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
|
||||
loadSegment.bind(null, new Uint8Array(arrayBuffer, 0, 318))().then(
|
||||
loadSegment.bind(null, new Uint8Array(arrayBuffer, 318, 25223-318))).then(
|
||||
loadSegment.bind(null, new Uint8Array(arrayBuffer, 25223, 46712-25223))).then(
|
||||
/* Note - Missing |46712, 67833 - 46712| segment here corresponding to (0.8, 1.2] */
|
||||
/* Note - Missing |67833, 88966 - 67833| segment here corresponding to (1.2, 1.6] */
|
||||
loadSegment.bind(null, new Uint8Array(arrayBuffer, 88966))).then(function() {
|
||||
var promise = waitUntilTime(0.7);
|
||||
info("Playing video. It should play for a bit, then fire 'waiting'");
|
||||
v.play();
|
||||
return promise;
|
||||
}).then(function() {
|
||||
window.firstStop = Date.now();
|
||||
loadSegment(new Uint8Array(arrayBuffer, 46712, 67833 - 46712));
|
||||
return waitUntilTime(1.0);
|
||||
}).then(function() {
|
||||
var waitDuration = (Date.now() - window.firstStop) / 1000;
|
||||
ok(waitDuration < 15, "Should not spend an inordinate amount of time buffering: " + waitDuration);
|
||||
SimpleTest.finish();
|
||||
/* If we allow the rest of the stream to be played, we get stuck at
|
||||
around 2s. See bug 1093133.
|
||||
once(v, 'ended', SimpleTest.finish.bind(SimpleTest));
|
||||
return loadSegment(new Uint8Array(arrayBuffer, 67833, 88966 - 67833));
|
||||
*/
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,72 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
|
||||
<title>MSE: |waiting| event when source data is missing</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="mediasource.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test"><script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var receivedSourceOpen = false;
|
||||
runWithMSE(function(ms, v) {
|
||||
ms.addEventListener("sourceopen", function() {
|
||||
ok(true, "Receive a sourceopen event");
|
||||
ok(!receivedSourceOpen, "Should only receive one sourceopen for this test");
|
||||
receivedSourceOpen = true;
|
||||
var sb = ms.addSourceBuffer("video/webm");
|
||||
ok(sb, "Create a SourceBuffer");
|
||||
|
||||
function once(target, name, cb) {
|
||||
target.addEventListener(name, function() {
|
||||
target.removeEventListener(name, cb);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
function loadSegment(typedArray) {
|
||||
info(`Loading buffer: [${typedArray.byteOffset}, ${typedArray.byteOffset + typedArray.byteLength})`);
|
||||
return new Promise(function(resolve, reject) {
|
||||
once(sb, 'update', resolve);
|
||||
sb.appendBuffer(typedArray);
|
||||
});
|
||||
}
|
||||
|
||||
fetchWithXHR("seek.webm", function(arrayBuffer) {
|
||||
sb.addEventListener('error', (e) => { ok(false, "Got Error: " + e); SimpleTest.finish(); });
|
||||
loadSegment.bind(null, new Uint8Array(arrayBuffer, 0, 318))().then(
|
||||
loadSegment.bind(null, new Uint8Array(arrayBuffer, 318, 25223-318))).then(
|
||||
loadSegment.bind(null, new Uint8Array(arrayBuffer, 25223, 46712-25223))).then(
|
||||
/* Note - Missing |46712, 67833 - 46712| segment here */
|
||||
loadSegment.bind(null, new Uint8Array(arrayBuffer, 67833, 88966 - 67833))).then(
|
||||
loadSegment.bind(null, new Uint8Array(arrayBuffer, 88966))).then(function() {
|
||||
|
||||
v.addEventListener("waiting", function onwaiting() {
|
||||
ok(true, "Got a waiting event at " + v.currentTime);
|
||||
if (v.currentTime > 0.7 && v.currentTime < 1.2) {
|
||||
v.removeEventListener("waiting", onwaiting);
|
||||
todo(v.currentTime >= 0.8, "See bug 1091774");
|
||||
gotWaiting = true;
|
||||
ok(true, "Received waiting event at time " + v.currentTime);
|
||||
loadSegment(new Uint8Array(arrayBuffer, 46712, 67833 - 46712)).then(() => ms.endOfStream());
|
||||
}
|
||||
});
|
||||
|
||||
info("Playing video. It should play for a bit, then fire 'waiting'");
|
||||
v.play();
|
||||
});
|
||||
});
|
||||
});
|
||||
v.addEventListener("ended", function () {
|
||||
ok(Math.abs(v.duration - 4) < 0.1, "Video has correct duration. This fuzz factor is due to bug 1065207");
|
||||
is(v.currentTime, v.duration, "Video has correct current time: " + v.currentTime);
|
||||
ok(gotWaiting, "Received waiting event and playback continued after data added");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1890,15 +1890,16 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
||||
nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first");
|
||||
{
|
||||
mozilla::ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
if (mIsChained)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#ifdef OGG_ESTIMATE_BUFFERED
|
||||
return MediaDecoderReader::GetBuffered(aBuffered, aStartTime);
|
||||
return MediaDecoderReader::GetBuffered(aBuffered);
|
||||
#else
|
||||
// HasAudio and HasVideo are not used here as they take a lock and cause
|
||||
// a deadlock. Accessing mInfo doesn't require a lock - it doesn't change
|
||||
|
@ -1908,7 +1909,7 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
MediaResource* resource = mDecoder->GetResource();
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
nsTArray<MediaByteRange> ranges;
|
||||
nsresult res = resource->GetCachedRanges(ranges);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
@ -1928,7 +1929,7 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
|||
// we special-case (startOffset == 0) so that the first
|
||||
// buffered range always appears to be buffered from the media start
|
||||
// time, rather than from the end-time of the first page.
|
||||
int64_t startTime = (startOffset == 0) ? aStartTime : -1;
|
||||
int64_t startTime = (startOffset == 0) ? mStartTime : -1;
|
||||
|
||||
// Find the start time of the range. Read pages until we find one with a
|
||||
// granulepos which we can convert into a timestamp to use as the time of
|
||||
|
@ -1996,8 +1997,8 @@ nsresult OggReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
|||
// find an end time.
|
||||
int64_t endTime = RangeEndTime(startOffset, endOffset, true);
|
||||
if (endTime != -1) {
|
||||
aBuffered->Add((startTime - aStartTime) / static_cast<double>(USECS_PER_S),
|
||||
(endTime - aStartTime) / static_cast<double>(USECS_PER_S));
|
||||
aBuffered->Add((startTime - mStartTime) / static_cast<double>(USECS_PER_S),
|
||||
(endTime - mStartTime) / static_cast<double>(USECS_PER_S));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags);
|
||||
virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
|
||||
|
||||
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -48,8 +48,7 @@ public:
|
|||
// we returned are not useful for the MediaDecodeStateMachine. Unlike the
|
||||
// ChannelMediaResource, it has a "cache" that can store the whole streaming
|
||||
// data so the |GetBuffered| function can retrieve useful time ranges.
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
|
||||
int64_t aStartTime) MOZ_OVERRIDE {
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,8 +58,7 @@ public:
|
|||
// we returned are not useful for the MediaDecodeStateMachine. Unlike the
|
||||
// ChannelMediaResource, it has a "cache" that can store the whole streaming
|
||||
// data so the |GetBuffered| function can retrieve useful time ranges.
|
||||
virtual nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered,
|
||||
int64_t aStartTime) MOZ_FINAL MOZ_OVERRIDE {
|
||||
virtual nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered) MOZ_FINAL MOZ_OVERRIDE {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -290,7 +290,7 @@ nsresult RawReader::SeekInternal(int64_t aTime)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult RawReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
||||
nsresult RawReader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags);
|
||||
virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
|
||||
|
||||
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -374,7 +374,6 @@ skip-if = toolkit == 'android' || (os == 'win' && !debug) || (os == 'mac' && !de
|
|||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_fastSeek-forwards.html]
|
||||
[test_imagecapture.html]
|
||||
skip-if = toolkit == 'android' # bug 1071217 - crashes on 2.3
|
||||
[test_info_leak.html]
|
||||
[test_invalid_reject.html]
|
||||
[test_invalid_reject_play.html]
|
||||
|
|
|
@ -17,8 +17,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1060896
|
|||
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
function error(event) {
|
||||
var a = event.target;
|
||||
ok(!a.mozHasAudio, "Media must've had no active tracks to play");
|
||||
a.removeEventListener("error", error);
|
||||
a.removeEventListener("ended", ended);
|
||||
removeNodeAndSource(a);
|
||||
manager.finished(a.token);
|
||||
}
|
||||
|
||||
function ended(event) {
|
||||
var a = event.target;
|
||||
a.removeEventListener("error", error);
|
||||
a.removeEventListener("ended", ended);
|
||||
removeNodeAndSource(a);
|
||||
manager.finished(a.token);
|
||||
}
|
||||
|
@ -29,12 +40,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1060896
|
|||
manager.started(token);
|
||||
a.autoplay = true;
|
||||
|
||||
a.addEventListener("ended", ended, false);
|
||||
a.addEventListener("error", error);
|
||||
a.addEventListener("ended", ended);
|
||||
|
||||
a.src = test.name;
|
||||
}
|
||||
|
||||
var videos = gSmallTests.filter(function(x){return /^video/.test(x.type);});
|
||||
var videos = getPlayableVideos(gSmallTests);
|
||||
|
||||
manager.runTests(videos, initTest);
|
||||
|
||||
|
|
|
@ -280,14 +280,15 @@ static double RoundToUsecs(double aSeconds) {
|
|||
return floor(aSeconds * USECS_PER_S) / USECS_PER_S;
|
||||
}
|
||||
|
||||
nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
||||
nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
if (!mInfo.HasAudio()) {
|
||||
return NS_OK;
|
||||
}
|
||||
int64_t startOffset = mDecoder->GetResource()->GetNextCachedData(mWavePCMOffset);
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
int64_t startOffset = resource->GetNextCachedData(mWavePCMOffset);
|
||||
while (startOffset >= 0) {
|
||||
int64_t endOffset = mDecoder->GetResource()->GetCachedDataEnd(startOffset);
|
||||
int64_t endOffset = resource->GetCachedDataEnd(startOffset);
|
||||
// Bytes [startOffset..endOffset] are cached.
|
||||
NS_ASSERTION(startOffset >= mWavePCMOffset, "Integer underflow in GetBuffered");
|
||||
NS_ASSERTION(endOffset >= mWavePCMOffset, "Integer underflow in GetBuffered");
|
||||
|
@ -297,7 +298,7 @@ nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
|||
// the media element.
|
||||
aBuffered->Add(RoundToUsecs(BytesToTime(startOffset - mWavePCMOffset)),
|
||||
RoundToUsecs(BytesToTime(endOffset - mWavePCMOffset)));
|
||||
startOffset = mDecoder->GetResource()->GetNextCachedData(endOffset);
|
||||
startOffset = resource->GetNextCachedData(endOffset);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags);
|
||||
virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
|
||||
|
||||
// To seek in a buffered range, we just have to seek the stream.
|
||||
virtual bool IsSeekableInBufferedRanges() {
|
||||
|
|
|
@ -1092,13 +1092,14 @@ nsresult WebMReader::SeekInternal(int64_t aTarget, int64_t aStartTime)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
||||
nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first");
|
||||
if (aBuffered->Length() != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MediaResource* resource = mDecoder->GetResource();
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
|
||||
// Special case completely cached files. This also handles local files.
|
||||
if (mContext && resource->IsDataCachedToEndOfResource(0)) {
|
||||
|
@ -1121,7 +1122,7 @@ nsresult WebMReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
|||
ranges[index].mEnd,
|
||||
&start, &end);
|
||||
if (rv) {
|
||||
int64_t startOffset = aStartTime * NS_PER_USEC;
|
||||
int64_t startOffset = mStartTime * NS_PER_USEC;
|
||||
NS_ASSERTION(startOffset >= 0 && uint64_t(startOffset) <= start,
|
||||
"startOffset negative or larger than start time");
|
||||
if (!(startOffset >= 0 && uint64_t(startOffset) <= start)) {
|
||||
|
|
|
@ -136,7 +136,7 @@ public:
|
|||
MetadataTags** aTags);
|
||||
virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
||||
int64_t aCurrentTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
|
||||
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength,
|
||||
int64_t aOffset);
|
||||
virtual int64_t GetEvictionOffset(double aTime);
|
||||
|
|
|
@ -22,6 +22,7 @@ interfaces = [
|
|||
'xbl',
|
||||
'xpath',
|
||||
'xul',
|
||||
'security',
|
||||
'storage',
|
||||
'json',
|
||||
'offline',
|
||||
|
@ -73,6 +74,7 @@ DIRS += [
|
|||
'power',
|
||||
'push',
|
||||
'quota',
|
||||
'security',
|
||||
'settings',
|
||||
'storage',
|
||||
'svg',
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# -*- 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.mozilla.dom += [
|
||||
'nsCSPContext.h',
|
||||
'nsCSPService.h',
|
||||
'nsCSPUtils.h',
|
||||
'nsMixedContentBlocker.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsCSPContext.cpp',
|
||||
'nsCSPParser.cpp',
|
||||
'nsCSPService.cpp',
|
||||
'nsCSPUtils.cpp',
|
||||
'nsMixedContentBlocker.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
LOCAL_INCLUDES += [
|
||||
'/caps',
|
||||
'/netwerk/base/src',
|
||||
]
|
|
@ -6,7 +6,7 @@
|
|||
#ifndef nsCSPContext_h___
|
||||
#define nsCSPContext_h___
|
||||
|
||||
#include "nsCSPUtils.h"
|
||||
#include "mozilla/dom/nsCSPUtils.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIChannelEventSink.h"
|
|
@ -29,7 +29,6 @@ using namespace hal;
|
|||
|
||||
#undef near
|
||||
|
||||
// also see sDefaultSensorHint in mobile/android/base/GeckoAppShell.java
|
||||
#define DEFAULT_SENSOR_POLL 100
|
||||
|
||||
static const nsTArray<nsIDOMWindow*>::index_type NoIndex =
|
||||
|
@ -351,12 +350,12 @@ nsDeviceSensors::FireDOMMotionEvent(nsIDOMDocument *domdoc,
|
|||
mLastAcceleration->mZ.SetValue(z);
|
||||
break;
|
||||
case nsIDeviceSensorData::TYPE_ACCELERATION:
|
||||
if (!mLastAccelerationIncluduingGravity) {
|
||||
mLastAccelerationIncluduingGravity.emplace();
|
||||
if (!mLastAccelerationIncludingGravity) {
|
||||
mLastAccelerationIncludingGravity.emplace();
|
||||
}
|
||||
mLastAccelerationIncluduingGravity->mX.SetValue(x);
|
||||
mLastAccelerationIncluduingGravity->mY.SetValue(y);
|
||||
mLastAccelerationIncluduingGravity->mZ.SetValue(z);
|
||||
mLastAccelerationIncludingGravity->mX.SetValue(x);
|
||||
mLastAccelerationIncludingGravity->mY.SetValue(y);
|
||||
mLastAccelerationIncludingGravity->mZ.SetValue(z);
|
||||
break;
|
||||
case nsIDeviceSensorData::TYPE_GYROSCOPE:
|
||||
if (!mLastRotationRate) {
|
||||
|
@ -372,14 +371,14 @@ nsDeviceSensors::FireDOMMotionEvent(nsIDOMDocument *domdoc,
|
|||
if (!mLastAcceleration) {
|
||||
mLastAcceleration.emplace();
|
||||
}
|
||||
if (!mLastAccelerationIncluduingGravity) {
|
||||
mLastAccelerationIncluduingGravity.emplace();
|
||||
if (!mLastAccelerationIncludingGravity) {
|
||||
mLastAccelerationIncludingGravity.emplace();
|
||||
}
|
||||
if (!mLastRotationRate) {
|
||||
mLastRotationRate.emplace();
|
||||
}
|
||||
} else if (!mLastAcceleration ||
|
||||
!mLastAccelerationIncluduingGravity ||
|
||||
!mLastAccelerationIncludingGravity ||
|
||||
!mLastRotationRate) {
|
||||
return;
|
||||
}
|
||||
|
@ -394,7 +393,7 @@ nsDeviceSensors::FireDOMMotionEvent(nsIDOMDocument *domdoc,
|
|||
true,
|
||||
false,
|
||||
*mLastAcceleration,
|
||||
*mLastAccelerationIncluduingGravity,
|
||||
*mLastAccelerationIncludingGravity,
|
||||
*mLastRotationRate,
|
||||
Nullable<double>(DEFAULT_SENSOR_POLL),
|
||||
rv);
|
||||
|
@ -405,7 +404,7 @@ nsDeviceSensors::FireDOMMotionEvent(nsIDOMDocument *domdoc,
|
|||
target->DispatchEvent(event, &defaultActionEnabled);
|
||||
|
||||
mLastRotationRate.reset();
|
||||
mLastAccelerationIncluduingGravity.reset();
|
||||
mLastAccelerationIncludingGravity.reset();
|
||||
mLastAcceleration.reset();
|
||||
mLastDOMMotionEventTime = TimeStamp::Now();
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ private:
|
|||
mozilla::TimeStamp mLastDOMMotionEventTime;
|
||||
bool mIsUserProximityNear;
|
||||
mozilla::Maybe<DeviceAccelerationInit> mLastAcceleration;
|
||||
mozilla::Maybe<DeviceAccelerationInit> mLastAccelerationIncluduingGravity;
|
||||
mozilla::Maybe<DeviceAccelerationInit> mLastAccelerationIncludingGravity;
|
||||
mozilla::Maybe<DeviceRotationRateInit> mLastRotationRate;
|
||||
};
|
||||
|
||||
|
|
|
@ -734,7 +734,7 @@ AsmJSCacheOpenEntryForRead(JS::Handle<JSObject*> aGlobal,
|
|||
aHandle);
|
||||
}
|
||||
|
||||
static bool
|
||||
static JS::AsmJSCacheResult
|
||||
AsmJSCacheOpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
|
||||
bool aInstalled,
|
||||
const char16_t* aBegin,
|
||||
|
@ -745,7 +745,7 @@ AsmJSCacheOpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
|
|||
{
|
||||
nsIPrincipal* principal = GetPrincipalForAsmJSCacheOp();
|
||||
if (!principal) {
|
||||
return false;
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
|
||||
return asmjscache::OpenEntryForWrite(principal, aInstalled, aBegin, aEnd,
|
||||
|
|
|
@ -128,6 +128,18 @@ DrawTargetD2D1::DrawSurface(SourceSurface *aSurface,
|
|||
return;
|
||||
}
|
||||
|
||||
RefPtr<ID2D1Bitmap> bitmap;
|
||||
if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
|
||||
// If this is called with a DataSourceSurface it might do a partial upload
|
||||
// that our DrawBitmap call doesn't support.
|
||||
image->QueryInterface((ID2D1Bitmap**)byRef(bitmap));
|
||||
}
|
||||
|
||||
if (bitmap && aSurfOptions.mSamplingBounds == SamplingBounds::UNBOUNDED) {
|
||||
mDC->DrawBitmap(bitmap, D2DRect(aDest), aOptions.mAlpha, D2DFilter(aSurfOptions.mFilter), D2DRect(aSource));
|
||||
} else {
|
||||
// This has issues ignoring the alpha channel on windows 7 with images marked opaque.
|
||||
MOZ_ASSERT(aSurface->GetFormat() != SurfaceFormat::B8G8R8X8);
|
||||
mDC->CreateImageBrush(image,
|
||||
D2D1::ImageBrushProperties(samplingBounds,
|
||||
D2D1_EXTEND_MODE_CLAMP,
|
||||
|
@ -136,6 +148,7 @@ DrawTargetD2D1::DrawSurface(SourceSurface *aSurface,
|
|||
D2D1::BrushProperties(aOptions.mAlpha, D2DMatrix(transform)),
|
||||
byRef(brush));
|
||||
mDC->FillRectangle(D2DRect(aDest), brush);
|
||||
}
|
||||
|
||||
FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
|
||||
}
|
||||
|
|
|
@ -189,11 +189,9 @@ void Context::makeCurrent(egl::Surface *surface)
|
|||
mHasBeenCurrent = true;
|
||||
}
|
||||
|
||||
// Wrap the existing swapchain resources into GL objects and assign them to the '0' names
|
||||
rx::SwapChain *swapchain = surface->getSwapChain();
|
||||
|
||||
Colorbuffer *colorbufferZero = new Colorbuffer(mRenderer, swapchain);
|
||||
DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(mRenderer, swapchain);
|
||||
// Wrap the existing surface resources into GL objects and assign them to the '0' names
|
||||
Colorbuffer *colorbufferZero = new Colorbuffer(mRenderer, surface);
|
||||
DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(mRenderer, surface);
|
||||
Framebuffer *framebufferZero = new DefaultFramebuffer(mRenderer, colorbufferZero, depthStencilbufferZero);
|
||||
|
||||
setFramebufferZero(framebufferZero);
|
||||
|
|
|
@ -172,9 +172,9 @@ unsigned int RenderbufferStorage::getTextureSerial() const
|
|||
return -1;
|
||||
}
|
||||
|
||||
Colorbuffer::Colorbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain)
|
||||
Colorbuffer::Colorbuffer(rx::Renderer *renderer, egl::Surface *surface)
|
||||
{
|
||||
mRenderTarget = renderer->createRenderTarget(swapChain, false);
|
||||
mRenderTarget = renderer->createRenderTarget(surface, false);
|
||||
|
||||
if (mRenderTarget)
|
||||
{
|
||||
|
@ -213,9 +213,9 @@ rx::RenderTarget *Colorbuffer::getRenderTarget()
|
|||
return mRenderTarget;
|
||||
}
|
||||
|
||||
DepthStencilbuffer::DepthStencilbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain)
|
||||
DepthStencilbuffer::DepthStencilbuffer(rx::Renderer *renderer, egl::Surface *surface)
|
||||
{
|
||||
mDepthStencil = renderer->createRenderTarget(swapChain, true);
|
||||
mDepthStencil = renderer->createRenderTarget(surface, true);
|
||||
if (mDepthStencil)
|
||||
{
|
||||
mWidth = mDepthStencil->getWidth();
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
#include "common/angleutils.h"
|
||||
#include "common/RefCountObject.h"
|
||||
|
||||
namespace egl
|
||||
{
|
||||
class Surface;
|
||||
}
|
||||
|
||||
namespace rx
|
||||
{
|
||||
class Renderer;
|
||||
|
@ -103,7 +108,7 @@ class RenderbufferStorage
|
|||
class Colorbuffer : public RenderbufferStorage
|
||||
{
|
||||
public:
|
||||
Colorbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain);
|
||||
Colorbuffer(rx::Renderer *renderer, egl::Surface *surface);
|
||||
Colorbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples);
|
||||
|
||||
virtual ~Colorbuffer();
|
||||
|
@ -119,7 +124,7 @@ class Colorbuffer : public RenderbufferStorage
|
|||
class DepthStencilbuffer : public RenderbufferStorage
|
||||
{
|
||||
public:
|
||||
DepthStencilbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain);
|
||||
DepthStencilbuffer(rx::Renderer *renderer, egl::Surface *surface);
|
||||
DepthStencilbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLsizei samples);
|
||||
|
||||
~DepthStencilbuffer();
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
namespace egl
|
||||
{
|
||||
class Display;
|
||||
class Surface;
|
||||
}
|
||||
|
||||
namespace gl
|
||||
|
@ -187,7 +188,7 @@ class Renderer
|
|||
GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) = 0;
|
||||
|
||||
// RenderTarget creation
|
||||
virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth) = 0;
|
||||
virtual RenderTarget *createRenderTarget(egl::Surface *eglSurface, bool depth) = 0;
|
||||
virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples) = 0;
|
||||
|
||||
// Shader creation
|
||||
|
|
|
@ -177,7 +177,8 @@ static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11Depth
|
|||
}
|
||||
|
||||
RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource,
|
||||
ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth)
|
||||
ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum internalFormatOverride)
|
||||
{
|
||||
mRenderer = Renderer11::makeRenderer11(renderer);
|
||||
|
||||
|
@ -220,6 +221,10 @@ RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv,
|
|||
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(desc.Format);
|
||||
mInternalFormat = dxgiFormatInfo.internalFormat;
|
||||
mActualFormat = dxgiFormatInfo.internalFormat;
|
||||
|
||||
if (internalFormatOverride) {
|
||||
mInternalFormat = internalFormatOverride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class RenderTarget11 : public RenderTarget
|
|||
{
|
||||
public:
|
||||
// RenderTarget11 takes ownership of any D3D11 resources it is given and will AddRef them
|
||||
RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth);
|
||||
RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormatOverride = 0);
|
||||
RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth);
|
||||
RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples);
|
||||
virtual ~RenderTarget11();
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h"
|
||||
|
||||
#include "libEGL/Display.h"
|
||||
#include "libEGL/Surface.h"
|
||||
|
||||
#include "common/utilities.h"
|
||||
|
||||
|
@ -2169,11 +2170,12 @@ void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView
|
|||
}
|
||||
}
|
||||
|
||||
RenderTarget *Renderer11::createRenderTarget(SwapChain *swapChain, bool depth)
|
||||
RenderTarget *Renderer11::createRenderTarget(egl::Surface *eglSurface, bool depth)
|
||||
{
|
||||
SwapChain *swapChain = eglSurface->getSwapChain();
|
||||
SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain);
|
||||
RenderTarget11 *renderTarget = NULL;
|
||||
|
||||
RenderTarget11 *renderTarget = NULL;
|
||||
if (depth)
|
||||
{
|
||||
// Note: depth stencil may be NULL for 0 sized surfaces
|
||||
|
@ -2188,7 +2190,8 @@ RenderTarget *Renderer11::createRenderTarget(SwapChain *swapChain, bool depth)
|
|||
renderTarget = new RenderTarget11(this, swapChain11->getRenderTarget(),
|
||||
swapChain11->getOffscreenTexture(),
|
||||
swapChain11->getRenderTargetShaderResource(),
|
||||
swapChain11->getWidth(), swapChain11->getHeight(), 1);
|
||||
swapChain11->getWidth(), swapChain11->getHeight(), 1,
|
||||
eglSurface->getFormat());
|
||||
}
|
||||
return renderTarget;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ class Renderer11 : public Renderer
|
|||
GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels);
|
||||
|
||||
// RenderTarget creation
|
||||
virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth);
|
||||
virtual RenderTarget *createRenderTarget(egl::Surface *eglSurface, bool depth);
|
||||
virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples);
|
||||
|
||||
// Shader creation
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче