merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-11-12 16:02:10 +01:00
Родитель 32bdd95f97 de08411809
Коммит b3c105d5da
204 изменённых файлов: 1850 добавлений и 1158 удалений

Просмотреть файл

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

28
dom/security/moz.build Normal file
Просмотреть файл

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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше