forked from mirrors/gecko-dev
Merge inbound to m-c. a=merge
This commit is contained in:
commit
175de6b258
2640 changed files with 171341 additions and 95644 deletions
2
CLOBBER
2
CLOBBER
|
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1018324 - Clobber should fix burning tree
|
||||
Bug 1109248 - This needed a CLOBBER on Windows and OSX.
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ ifdef MOZ_NO_DEBUG_RTL
|
|||
DEFINES += -DMOZ_PACKAGE_MSVC_DLLS=1
|
||||
DEFINES += -DMSVC_C_RUNTIME_DLL=$(MSVC_C_RUNTIME_DLL)
|
||||
DEFINES += -DMSVC_CXX_RUNTIME_DLL=$(MSVC_CXX_RUNTIME_DLL)
|
||||
ifdef MSVC_APPCRT_DLL
|
||||
DEFINES += -DMSVC_APPCRT_DLL=$(MSVC_APPCRT_DLL)
|
||||
endif
|
||||
ifdef MSVC_DESKTOPCRT_DLL
|
||||
DEFINES += -DMSVC_DESKTOPCRT_DLL=$(MSVC_DESKTOPCRT_DLL)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@
|
|||
#if MOZ_PACKAGE_MSVC_DLLS
|
||||
@BINPATH@/@MSVC_C_RUNTIME_DLL@
|
||||
@BINPATH@/@MSVC_CXX_RUNTIME_DLL@
|
||||
#ifdef MSVC_APPCRT_DLL
|
||||
@BINPATH@/@MSVC_APPCRT_DLL@
|
||||
#endif
|
||||
#ifdef MSVC_DESKTOPCRT_DLL
|
||||
@BINPATH@/@MSVC_DESKTOPCRT_DLL@
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MOZ_SHARED_MOZGLUE
|
||||
|
|
|
|||
|
|
@ -392,8 +392,9 @@ function promiseSetToolbarVisibility(aToolbar, aVisible, aCallback) {
|
|||
let transitionProperties =
|
||||
window.getComputedStyle(aToolbar).transitionProperty.split(", ");
|
||||
if (isToolbarVisible(aToolbar) != aVisible &&
|
||||
(transitionProperties.includes("max-height") ||
|
||||
transitionProperties.includes("all"))) {
|
||||
transitionProperties.some(
|
||||
prop => prop == "max-height" || prop == "all"
|
||||
)) {
|
||||
// Just because max-height is a transitionable property doesn't mean
|
||||
// a transition will be triggered, but it's more likely.
|
||||
aToolbar.addEventListener("transitionend", listener);
|
||||
|
|
|
|||
|
|
@ -73,6 +73,12 @@ ifdef MOZ_NO_DEBUG_RTL
|
|||
DEFINES += -DMOZ_PACKAGE_MSVC_DLLS=1
|
||||
DEFINES += -DMSVC_C_RUNTIME_DLL=$(MSVC_C_RUNTIME_DLL)
|
||||
DEFINES += -DMSVC_CXX_RUNTIME_DLL=$(MSVC_CXX_RUNTIME_DLL)
|
||||
ifdef MSVC_APPCRT_DLL
|
||||
DEFINES += -DMSVC_APPCRT_DLL=$(MSVC_APPCRT_DLL)
|
||||
endif
|
||||
ifdef MSVC_DESKTOPCRT_DLL
|
||||
DEFINES += -DMSVC_DESKTOPCRT_DLL=$(MSVC_DESKTOPCRT_DLL)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,12 @@
|
|||
#if MOZ_PACKAGE_MSVC_DLLS
|
||||
@BINPATH@/@MSVC_C_RUNTIME_DLL@
|
||||
@BINPATH@/@MSVC_CXX_RUNTIME_DLL@
|
||||
#ifdef MSVC_APPCRT_DLL
|
||||
@BINPATH@/@MSVC_APPCRT_DLL@
|
||||
#endif
|
||||
#ifdef MSVC_DESKTOPCRT_DLL
|
||||
@BINPATH@/@MSVC_DESKTOPCRT_DLL@
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifndef MOZ_NATIVE_ICU
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ gyp_vars = {
|
|||
# use_system_lib* still seems to be in use in trunk/build
|
||||
'use_system_libjpeg': 0,
|
||||
'use_system_libvpx': 0,
|
||||
'build_json': 0,
|
||||
'build_libjpeg': 0,
|
||||
'build_libvpx': 0,
|
||||
'build_libyuv': 0,
|
||||
'build_libvpx': 0,
|
||||
'build_ssl': 0,
|
||||
'libyuv_dir': '/media/libyuv',
|
||||
'yuv_disable_avx2': 0 if CONFIG['HAVE_X86_AVX2'] else 1,
|
||||
# don't use openssl
|
||||
|
|
@ -47,7 +49,7 @@ gyp_vars = {
|
|||
'use_temporal_layers': 0,
|
||||
|
||||
# Creates AEC internal sample dump files in current directory
|
||||
'aec_debug_dump': 1,
|
||||
'aec_debug_dump': 0,
|
||||
|
||||
# Enable and force use of hardware AEC
|
||||
'hardware_aec_ns': 1 if CONFIG['MOZ_WEBRTC_HARDWARE_AEC_NS'] else 0,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ ifdef WIN32_REDIST_DIR
|
|||
REDIST_FILES = \
|
||||
$(MSVC_C_RUNTIME_DLL) \
|
||||
$(MSVC_CXX_RUNTIME_DLL) \
|
||||
$(MSVC_APPCRT_DLL) \
|
||||
$(MSVC_DESKTOPCRT_DLL) \
|
||||
$(NULL)
|
||||
|
||||
libs-preqs = \
|
||||
|
|
|
|||
20
configure.in
20
configure.in
|
|
@ -497,6 +497,24 @@ case "$target" in
|
|||
MSVS_VERSION=2013
|
||||
MSVC_C_RUNTIME_DLL=msvcr120.dll
|
||||
MSVC_CXX_RUNTIME_DLL=msvcp120.dll
|
||||
elif test "$_CC_MAJOR_VERSION" = "19"; then
|
||||
_CC_SUITE=14
|
||||
MSVS_VERSION=2015
|
||||
MSVC_C_RUNTIME_DLL=vcruntime140.dll
|
||||
MSVC_CXX_RUNTIME_DLL=msvcp140.dll
|
||||
MSVC_APPCRT_DLL=appcrt140.dll
|
||||
MSVC_DESKTOPCRT_DLL=desktopcrt140.dll
|
||||
|
||||
# -Wv:18 disables all warnings introduced after VS2013
|
||||
# See http://blogs.msdn.com/b/vcblog/archive/2014/11/12/improvements-to-warnings-in-the-c-compiler.aspx
|
||||
CFLAGS="$CFLAGS -Wv:18"
|
||||
CXXFLAGS="$CXXFLAGS -Wv:18"
|
||||
|
||||
# https://connect.microsoft.com/VisualStudio/feedback/details/888527/warnings-on-dbghelp-h
|
||||
# for dbghelp.h, imagehlp.h, and shobj.h
|
||||
# C4091: 'typedef ': ignored on left of '' when no variable is declared
|
||||
CFLAGS="$CFLAGS -wd4091"
|
||||
CXXFLAGS="$CXXFLAGS -wd4091"
|
||||
else
|
||||
AC_MSG_ERROR([This version (${_CC_MAJOR_VERSION}.${_CC_MINOR_VERSION}.${_CC_BUILD_VERSION}) of the MSVC compiler is unsupported.
|
||||
You must install Visual C++ 2013 Update 3 or newer in order to build.
|
||||
|
|
@ -505,6 +523,8 @@ See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
|
|||
AC_SUBST(MSVS_VERSION)
|
||||
AC_SUBST(MSVC_C_RUNTIME_DLL)
|
||||
AC_SUBST(MSVC_CXX_RUNTIME_DLL)
|
||||
AC_SUBST(MSVC_APPCRT_DLL)
|
||||
AC_SUBST(MSVC_DESKTOPCRT_DLL)
|
||||
|
||||
# Disable SEH on clang-cl because it doesn't implement them yet.
|
||||
if test -z "$CLANG_CL"; then
|
||||
|
|
|
|||
|
|
@ -145,6 +145,13 @@ nsLineBreaker::FlushCurrentWord()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// If the aFlags parameter to AppendText has all these bits set,
|
||||
// then we don't need to worry about finding break opportunities
|
||||
// in the appended text.
|
||||
#define NO_BREAKS_NEEDED_FLAGS (BREAK_SUPPRESS_INITIAL | \
|
||||
BREAK_SUPPRESS_INSIDE | \
|
||||
BREAK_SKIP_SETTING_NO_BREAKS)
|
||||
|
||||
nsresult
|
||||
nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const char16_t* aText, uint32_t aLength,
|
||||
uint32_t aFlags, nsILineBreakSink* aSink)
|
||||
|
|
@ -184,23 +191,25 @@ nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const char16_t* aText,
|
|||
if (!breakState.AppendElements(aLength))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
bool noCapitalizationNeeded = true;
|
||||
nsTArray<bool> capitalizationState;
|
||||
if (aSink && (aFlags & BREAK_NEED_CAPITALIZATION)) {
|
||||
if (!capitalizationState.AppendElements(aLength))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memset(capitalizationState.Elements(), false, aLength*sizeof(bool));
|
||||
noCapitalizationNeeded = false;
|
||||
}
|
||||
|
||||
uint32_t start = offset;
|
||||
bool noBreaksNeeded = !aSink ||
|
||||
(aFlags == (BREAK_SUPPRESS_INITIAL | BREAK_SUPPRESS_INSIDE | BREAK_SKIP_SETTING_NO_BREAKS) &&
|
||||
((aFlags & NO_BREAKS_NEEDED_FLAGS) == NO_BREAKS_NEEDED_FLAGS &&
|
||||
!mBreakHere && !mAfterBreakableSpace);
|
||||
if (noBreaksNeeded) {
|
||||
if (noBreaksNeeded && noCapitalizationNeeded) {
|
||||
// Skip to the space before the last word, since either the break data
|
||||
// here is not needed, or no breaks are set in the sink and there cannot
|
||||
// be any breaks in this chunk; all we need is the context for the next
|
||||
// chunk (if any)
|
||||
// be any breaks in this chunk; and we don't need to do word-initial
|
||||
// capitalization. All we need is the context for the next chunk (if any).
|
||||
offset = aLength;
|
||||
while (offset > start) {
|
||||
--offset;
|
||||
|
|
@ -223,7 +232,7 @@ nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const char16_t* aText,
|
|||
bool isSpace = IsSpace(ch);
|
||||
bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE);
|
||||
|
||||
if (aSink) {
|
||||
if (aSink && !noBreaksNeeded) {
|
||||
breakState[offset] =
|
||||
mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
|
||||
(mWordBreak == nsILineBreaker::kWordBreak_BreakAll) ?
|
||||
|
|
@ -252,7 +261,7 @@ nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const char16_t* aText,
|
|||
breakState.Elements() + wordStart);
|
||||
}
|
||||
}
|
||||
if (aFlags & BREAK_NEED_CAPITALIZATION) {
|
||||
if (!noCapitalizationNeeded) {
|
||||
SetupCapitalization(aText + wordStart, offset - wordStart,
|
||||
capitalizationState.Elements() + wordStart);
|
||||
}
|
||||
|
|
@ -284,10 +293,11 @@ nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const char16_t* aText,
|
|||
}
|
||||
}
|
||||
|
||||
if (!noBreaksNeeded) {
|
||||
// aSink must not be null
|
||||
aSink->SetBreaks(start, offset - start, breakState.Elements() + start);
|
||||
if (aFlags & BREAK_NEED_CAPITALIZATION) {
|
||||
if (aSink) {
|
||||
if (!noBreaksNeeded) {
|
||||
aSink->SetBreaks(start, offset - start, breakState.Elements() + start);
|
||||
}
|
||||
if (!noCapitalizationNeeded) {
|
||||
aSink->SetCapitalization(start, offset - start,
|
||||
capitalizationState.Elements() + start);
|
||||
}
|
||||
|
|
@ -365,7 +375,7 @@ nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const uint8_t* aText, u
|
|||
|
||||
uint32_t start = offset;
|
||||
bool noBreaksNeeded = !aSink ||
|
||||
(aFlags == (BREAK_SUPPRESS_INITIAL | BREAK_SUPPRESS_INSIDE | BREAK_SKIP_SETTING_NO_BREAKS) &&
|
||||
((aFlags & NO_BREAKS_NEEDED_FLAGS) == NO_BREAKS_NEEDED_FLAGS &&
|
||||
!mBreakHere && !mAfterBreakableSpace);
|
||||
if (noBreaksNeeded) {
|
||||
// Skip to the space before the last word, since either the break data
|
||||
|
|
|
|||
|
|
@ -62,6 +62,13 @@ public:
|
|||
return mInternalResponse->GetStatus();
|
||||
}
|
||||
|
||||
bool
|
||||
Ok() const
|
||||
{
|
||||
return mInternalResponse->GetStatus() >= 200 &&
|
||||
mInternalResponse->GetStatus() <= 299;
|
||||
}
|
||||
|
||||
void
|
||||
GetStatusText(nsCString& aStatusText) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -515,6 +515,16 @@ HTMLMediaElement::IsVideo()
|
|||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaSource>
|
||||
HTMLMediaElement::GetMozMediaSourceObject() const
|
||||
{
|
||||
nsRefPtr<MediaSource> source;
|
||||
if (IsMediaSourceURI(mLoadingSrc)) {
|
||||
NS_GetSourceForMediaSourceURI(mLoadingSrc, getter_AddRefs(source));
|
||||
}
|
||||
return source.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMediaStream>
|
||||
HTMLMediaElement::GetMozSrcObject() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -533,6 +533,7 @@ public:
|
|||
mIsCasting = aShow;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaSource> GetMozMediaSourceObject() const;
|
||||
already_AddRefed<DOMMediaStream> GetMozSrcObject() const;
|
||||
|
||||
void SetMozSrcObject(DOMMediaStream& aValue);
|
||||
|
|
|
|||
|
|
@ -337,6 +337,11 @@ nsresult MP3FrameParser::ParseBuffer(const uint8_t* aBuffer,
|
|||
// Found an ID3 header. We don't care about the body of the header, so
|
||||
// just skip past.
|
||||
buffer = ch + mID3Parser.GetHeaderLength() - (ID3_HEADER_LENGTH - 1);
|
||||
|
||||
if (buffer <= ch) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ch = buffer;
|
||||
|
||||
mTotalID3Size += mID3Parser.GetHeaderLength();
|
||||
|
|
|
|||
|
|
@ -1298,7 +1298,9 @@ void MediaDecoder::ApplyStateToStateMachine(PlayState aState)
|
|||
mRequestedSeekTarget.Reset();
|
||||
break;
|
||||
default:
|
||||
/* No action needed */
|
||||
// The state machine checks for things like PAUSED in RunStateMachine.
|
||||
// Make sure to keep it in the loop.
|
||||
ScheduleStateMachineThread();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,5 +23,18 @@ DispatchMediaPromiseRunnable(nsIEventTarget* aEventTarget, nsIRunnable* aRunnabl
|
|||
return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
AssertOnThread(MediaTaskQueue* aQueue)
|
||||
{
|
||||
MOZ_ASSERT(aQueue->IsCurrentThreadIn());
|
||||
}
|
||||
|
||||
void AssertOnThread(nsIEventTarget* aTarget)
|
||||
{
|
||||
nsCOMPtr<nsIThread> targetThread = do_QueryInterface(aTarget);
|
||||
MOZ_ASSERT(targetThread, "Don't know how to deal with threadpools etc here");
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == targetThread);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ namespace detail {
|
|||
nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable);
|
||||
nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable);
|
||||
|
||||
#ifdef DEBUG
|
||||
void AssertOnThread(MediaTaskQueue* aQueue);
|
||||
void AssertOnThread(nsIEventTarget* aTarget);
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/*
|
||||
|
|
@ -81,6 +86,32 @@ public:
|
|||
return p;
|
||||
}
|
||||
|
||||
class Consumer
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Consumer)
|
||||
|
||||
void Disconnect()
|
||||
{
|
||||
AssertOnDispatchThread();
|
||||
MOZ_RELEASE_ASSERT(!mComplete);
|
||||
mDisconnected = true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void AssertOnDispatchThread() = 0;
|
||||
#else
|
||||
void AssertOnDispatchThread() {}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Consumer() : mComplete(false), mDisconnected(false) {}
|
||||
virtual ~Consumer() {}
|
||||
|
||||
bool mComplete;
|
||||
bool mDisconnected;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
|
|
@ -89,7 +120,7 @@ protected:
|
|||
* resolved or rejected, a {Resolve,Reject}Runnable is dispatched, which
|
||||
* invokes the resolve/reject method and then deletes the ThenValue.
|
||||
*/
|
||||
class ThenValueBase
|
||||
class ThenValueBase : public Consumer
|
||||
{
|
||||
public:
|
||||
class ResolveRunnable : public nsRunnable
|
||||
|
|
@ -108,14 +139,12 @@ protected:
|
|||
{
|
||||
PROMISE_LOG("ResolveRunnable::Run() [this=%p]", this);
|
||||
mThenValue->DoResolve(mResolveValue);
|
||||
|
||||
delete mThenValue;
|
||||
mThenValue = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
ThenValueBase* mThenValue;
|
||||
nsRefPtr<ThenValueBase> mThenValue;
|
||||
ResolveValueType mResolveValue;
|
||||
};
|
||||
|
||||
|
|
@ -135,28 +164,20 @@ protected:
|
|||
{
|
||||
PROMISE_LOG("RejectRunnable::Run() [this=%p]", this);
|
||||
mThenValue->DoReject(mRejectValue);
|
||||
|
||||
delete mThenValue;
|
||||
mThenValue = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
ThenValueBase* mThenValue;
|
||||
nsRefPtr<ThenValueBase> mThenValue;
|
||||
RejectValueType mRejectValue;
|
||||
};
|
||||
|
||||
explicit ThenValueBase(const char* aCallSite) : mCallSite(aCallSite)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ThenValueBase);
|
||||
}
|
||||
explicit ThenValueBase(const char* aCallSite) : mCallSite(aCallSite) {}
|
||||
|
||||
virtual void Dispatch(MediaPromise *aPromise) = 0;
|
||||
|
||||
protected:
|
||||
// This may only be deleted by {Resolve,Reject}Runnable::Run.
|
||||
virtual ~ThenValueBase() { MOZ_COUNT_DTOR(ThenValueBase); }
|
||||
|
||||
virtual void DoResolve(ResolveValueType aResolveValue) = 0;
|
||||
virtual void DoReject(RejectValueType aRejectValue) = 0;
|
||||
|
||||
|
|
@ -218,18 +239,48 @@ protected:
|
|||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Can't mark MOZ_OVERRIDE due to bug in clang builders we use for osx b2g desktop. :-(
|
||||
virtual void AssertOnDispatchThread()
|
||||
{
|
||||
detail::AssertOnThread(mResponseTarget);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual void DoResolve(ResolveValueType aResolveValue) MOZ_OVERRIDE
|
||||
{
|
||||
Consumer::mComplete = true;
|
||||
if (Consumer::mDisconnected) {
|
||||
PROMISE_LOG("ThenValue::DoResolve disconnected - bailing out [this=%p]", this);
|
||||
return;
|
||||
}
|
||||
InvokeCallbackMethod(mThisVal.get(), mResolveMethod, aResolveValue);
|
||||
|
||||
// Null these out after invoking the callback so that any references are
|
||||
// released predictably on the target thread. Otherwise, they would be
|
||||
// released on whatever thread last drops its reference to the ThenValue,
|
||||
// which may or may not be ok.
|
||||
mResponseTarget = nullptr;
|
||||
mThisVal = nullptr;
|
||||
}
|
||||
|
||||
virtual void DoReject(RejectValueType aRejectValue) MOZ_OVERRIDE
|
||||
{
|
||||
Consumer::mComplete = true;
|
||||
if (Consumer::mDisconnected) {
|
||||
PROMISE_LOG("ThenValue::DoReject disconnected - bailing out [this=%p]", this);
|
||||
return;
|
||||
}
|
||||
InvokeCallbackMethod(mThisVal.get(), mRejectMethod, aRejectValue);
|
||||
}
|
||||
|
||||
virtual ~ThenValue() {}
|
||||
// Null these out after invoking the callback so that any references are
|
||||
// released predictably on the target thread. Otherwise, they would be
|
||||
// released on whatever thread last drops its reference to the ThenValue,
|
||||
// which may or may not be ok.
|
||||
mResponseTarget = nullptr;
|
||||
mThisVal = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<TargetType> mResponseTarget;
|
||||
|
|
@ -241,23 +292,35 @@ public:
|
|||
|
||||
template<typename TargetType, typename ThisType,
|
||||
typename ResolveMethodType, typename RejectMethodType>
|
||||
void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
|
||||
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
|
||||
already_AddRefed<Consumer> RefableThen(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
|
||||
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_RELEASE_ASSERT(!IsExclusive || !mHaveConsumer);
|
||||
mHaveConsumer = true;
|
||||
ThenValueBase* thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType,
|
||||
RejectMethodType>(aResponseTarget, aThisVal,
|
||||
aResolveMethod, aRejectMethod,
|
||||
aCallSite);
|
||||
nsRefPtr<ThenValueBase> thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType,
|
||||
RejectMethodType>(aResponseTarget, aThisVal,
|
||||
aResolveMethod, aRejectMethod,
|
||||
aCallSite);
|
||||
PROMISE_LOG("%s invoking Then() [this=%p, thenValue=%p, aThisVal=%p, isPending=%d]",
|
||||
aCallSite, this, thenValue, aThisVal, (int) IsPending());
|
||||
aCallSite, this, thenValue.get(), aThisVal, (int) IsPending());
|
||||
if (!IsPending()) {
|
||||
thenValue->Dispatch(this);
|
||||
} else {
|
||||
mThenValues.AppendElement(thenValue);
|
||||
}
|
||||
|
||||
return thenValue.forget();
|
||||
}
|
||||
|
||||
template<typename TargetType, typename ThisType,
|
||||
typename ResolveMethodType, typename RejectMethodType>
|
||||
void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
|
||||
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
|
||||
{
|
||||
nsRefPtr<Consumer> c =
|
||||
RefableThen(aResponseTarget, aCallSite, aThisVal, aResolveMethod, aRejectMethod);
|
||||
return;
|
||||
}
|
||||
|
||||
void ChainTo(already_AddRefed<MediaPromise> aChainedPromise, const char* aCallSite)
|
||||
|
|
@ -331,7 +394,7 @@ protected:
|
|||
Mutex mMutex;
|
||||
Maybe<ResolveValueType> mResolveValue;
|
||||
Maybe<RejectValueType> mRejectValue;
|
||||
nsTArray<ThenValueBase*> mThenValues;
|
||||
nsTArray<nsRefPtr<ThenValueBase>> mThenValues;
|
||||
nsTArray<nsRefPtr<MediaPromise>> mChainedPromises;
|
||||
bool mHaveConsumer;
|
||||
};
|
||||
|
|
@ -425,6 +488,49 @@ private:
|
|||
nsRefPtr<PromiseType> mPromise;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class to encapsulate a MediaPromise::Consumer reference. Use this as the member
|
||||
* variable for a class waiting on a media promise.
|
||||
*/
|
||||
template<typename PromiseType>
|
||||
class MediaPromiseConsumerHolder
|
||||
{
|
||||
public:
|
||||
MediaPromiseConsumerHolder() {}
|
||||
~MediaPromiseConsumerHolder() { MOZ_ASSERT(!mConsumer); }
|
||||
|
||||
void Begin(already_AddRefed<typename PromiseType::Consumer> aConsumer)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!Exists());
|
||||
mConsumer = aConsumer;
|
||||
}
|
||||
|
||||
void Complete()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(Exists());
|
||||
mConsumer = nullptr;
|
||||
}
|
||||
|
||||
// Disconnects and forgets an outstanding promise. The resolve/reject methods
|
||||
// will never be called.
|
||||
void Disconnect() {
|
||||
MOZ_ASSERT(Exists());
|
||||
mConsumer->Disconnect();
|
||||
mConsumer = nullptr;
|
||||
}
|
||||
|
||||
void DisconnectIfExists() {
|
||||
if (Exists()) {
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
bool Exists() { return !!mConsumer; }
|
||||
|
||||
private:
|
||||
nsRefPtr<typename PromiseType::Consumer> mConsumer;
|
||||
};
|
||||
|
||||
#undef PROMISE_LOG
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -2477,12 +2477,9 @@ void
|
|||
SourceMediaStream::EndTrack(TrackID aID)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
// ::EndAllTrackAndFinished() can end these before the sources call this
|
||||
if (!mFinished) {
|
||||
TrackData *track = FindDataForTrack(aID);
|
||||
if (track) {
|
||||
track->mCommands |= TRACK_END;
|
||||
}
|
||||
TrackData *track = FindDataForTrack(aID);
|
||||
if (track) {
|
||||
track->mCommands |= TRACK_END;
|
||||
}
|
||||
if (auto graph = GraphImpl()) {
|
||||
graph->EnsureNextIteration();
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ namespace mozilla {
|
|||
|
||||
GonkAudioDecoderManager::GonkAudioDecoderManager(
|
||||
const mp4_demuxer::AudioDecoderConfig& aConfig)
|
||||
: mAudioChannels(aConfig.channel_count)
|
||||
: GonkDecoderManager()
|
||||
, mAudioChannels(aConfig.channel_count)
|
||||
, mAudioRate(aConfig.samples_per_second)
|
||||
, mAudioProfile(aConfig.aac_profile)
|
||||
, mUseAdts(true)
|
||||
|
|
@ -97,6 +98,31 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
|||
}
|
||||
}
|
||||
|
||||
status_t
|
||||
GonkAudioDecoderManager::SendSampleToOMX(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->data),
|
||||
aSample->size,
|
||||
aSample->composition_timestamp,
|
||||
0);
|
||||
}
|
||||
|
||||
void
|
||||
GonkAudioDecoderManager::PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (aSample && mUseAdts) {
|
||||
int8_t frequency_index =
|
||||
mp4_demuxer::Adts::GetFrequencyIndex(mAudioRate);
|
||||
bool rv = mp4_demuxer::Adts::ConvertSample(mAudioChannels,
|
||||
frequency_index,
|
||||
mAudioProfile,
|
||||
aSample);
|
||||
if (!rv) {
|
||||
GADM_LOG("Failed to apply ADTS header");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
||||
if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) {
|
||||
|
|
@ -210,12 +236,6 @@ GonkAudioDecoderManager::Output(int64_t aStreamOffset,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Flush()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void GonkAudioDecoderManager::ReleaseAudioBuffer() {
|
||||
if (mAudioBuffer) {
|
||||
mDecoder->ReleaseMediaBuffer(mAudioBuffer);
|
||||
|
|
@ -223,36 +243,4 @@ void GonkAudioDecoderManager::ReleaseAudioBuffer() {
|
|||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (mDecoder == nullptr) {
|
||||
GADM_LOG("Decoder is not inited");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (aSample && mUseAdts) {
|
||||
int8_t frequency_index =
|
||||
mp4_demuxer::Adts::GetFrequencyIndex(mAudioRate);
|
||||
bool rv = mp4_demuxer::Adts::ConvertSample(mAudioChannels,
|
||||
frequency_index,
|
||||
mAudioProfile,
|
||||
aSample);
|
||||
if (!rv) {
|
||||
GADM_LOG("Failed to apply ADTS header");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
status_t rv;
|
||||
if (aSample) {
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
|
||||
uint32_t length = aSample->size;
|
||||
rv = mDecoder->Input(data, length, aSample->composition_timestamp, 0);
|
||||
} else {
|
||||
// Inputted data is null, so it is going to notify decoder EOS
|
||||
rv = mDecoder->Input(0, 0, 0ll, 0);
|
||||
}
|
||||
return rv == OK ? NS_OK : NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -28,12 +28,14 @@ public:
|
|||
|
||||
virtual android::sp<MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Flush() MOZ_OVERRIDE;
|
||||
protected:
|
||||
virtual void PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
|
||||
virtual status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
||||
nsresult CreateAudioData(int64_t aStreamOffset,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,86 @@ using namespace android;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
GonkDecoderManager::GonkDecoderManager()
|
||||
: mMonitor("GonkDecoderManager")
|
||||
, mInputEOS(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
|
||||
// To maintain the order of the MP4Sample, it needs to send the queued samples
|
||||
// to OMX first. And then the current input aSample.
|
||||
// If it fails to input sample to OMX, it needs to add current into queue
|
||||
// for next round.
|
||||
uint32_t len = mQueueSample.Length();
|
||||
status_t rv = OK;
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
rv = SendSampleToOMX(mQueueSample.ElementAt(0));
|
||||
if (rv != OK) {
|
||||
break;
|
||||
}
|
||||
mQueueSample.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
// Already reaching EOS, do not add any sample to queue.
|
||||
if (mInputEOS) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// When EOS, aSample will be null and sends this empty MP4Sample to nofity
|
||||
// OMX it reachs EOS.
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> sample;
|
||||
if (!aSample) {
|
||||
sample = new mp4_demuxer::MP4Sample();
|
||||
mInputEOS = true;
|
||||
}
|
||||
|
||||
// If rv is OK, that means mQueueSample is empty, now try to queue current input
|
||||
// aSample.
|
||||
if (rv == OK) {
|
||||
MOZ_ASSERT(!mQueueSample.Length());
|
||||
mp4_demuxer::MP4Sample* tmp;
|
||||
if (aSample) {
|
||||
tmp = aSample;
|
||||
PerformFormatSpecificProcess(aSample);
|
||||
} else {
|
||||
tmp = sample;
|
||||
}
|
||||
rv = SendSampleToOMX(tmp);
|
||||
if (rv == OK) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Current valid sample can't be sent into OMX, adding the clone one into queue
|
||||
// for next round.
|
||||
if (!sample) {
|
||||
sample = new mp4_demuxer::MP4Sample(*aSample);
|
||||
}
|
||||
mQueueSample.AppendElement(sample);
|
||||
|
||||
// In most cases, EAGAIN or ETIMEOUT safe due to OMX can't process the
|
||||
// filled buffer on time. It should be gone When requeuing sample next time.
|
||||
if (rv == -EAGAIN || rv == -ETIMEDOUT) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Flush()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
mQueueSample.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager,
|
||||
MediaTaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
|
|
@ -92,6 +172,11 @@ GonkMediaDataDecoder::ProcessOutput()
|
|||
nsresult rv = NS_ERROR_ABORT;
|
||||
|
||||
while (!mDrainComplete) {
|
||||
// There are samples in queue, try to send them into decoder when EOS.
|
||||
if (mSignaledEOS && mManager->HasQueuedSample()) {
|
||||
GMDD_LOG("ProcessOutput: drain all input samples");
|
||||
rv = mManager->Input(nullptr);
|
||||
}
|
||||
rv = mManager->Output(mLastStreamOffset, output);
|
||||
if (rv == NS_OK) {
|
||||
mCallback->Output(output);
|
||||
|
|
@ -105,7 +190,9 @@ GonkMediaDataDecoder::ProcessOutput()
|
|||
}
|
||||
}
|
||||
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
MOZ_ASSERT_IF(mSignaledEOS, !mManager->HasQueuedSample());
|
||||
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE && !mSignaledEOS) {
|
||||
mCallback->InputExhausted();
|
||||
return;
|
||||
}
|
||||
|
|
@ -161,8 +248,8 @@ GonkMediaDataDecoder::IsWaitingMediaResources() {
|
|||
}
|
||||
|
||||
bool
|
||||
GonkMediaDataDecoder::IsDormantNeeded() {
|
||||
|
||||
GonkMediaDataDecoder::IsDormantNeeded()
|
||||
{
|
||||
return mDecoder.get() ? true : false;
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +260,8 @@ GonkMediaDataDecoder::AllocateMediaResources()
|
|||
}
|
||||
|
||||
void
|
||||
GonkMediaDataDecoder::ReleaseMediaResources() {
|
||||
GonkMediaDataDecoder::ReleaseMediaResources()
|
||||
{
|
||||
mManager->ReleaseMediaResources();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,25 +19,58 @@ namespace mozilla {
|
|||
// Manage the data flow from inputting encoded data and outputting decode data.
|
||||
class GonkDecoderManager {
|
||||
public:
|
||||
GonkDecoderManager();
|
||||
|
||||
virtual ~GonkDecoderManager() {}
|
||||
|
||||
// Creates and initializs the GonkDecoder.
|
||||
// Returns nullptr on failure.
|
||||
virtual android::sp<android::MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) = 0;
|
||||
|
||||
// Add samples into OMX decoder or queue them if decoder is out of input buffer.
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
|
||||
|
||||
// Produces decoded output, it blocks until output can be produced or a timeout
|
||||
// is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
|
||||
// if there's not enough data to produce more output. If this returns a failure
|
||||
// code other than NS_ERROR_NOT_AVAILABLE, an error will be reported to the
|
||||
// MP4Reader.
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) = 0;
|
||||
// The overrided class should follow the same behaviour.
|
||||
virtual nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) = 0;
|
||||
virtual nsresult Flush() = 0;
|
||||
|
||||
virtual void AllocateMediaResources() {};
|
||||
// Flush the queued sample.
|
||||
// It this function is overrided by subclass, this functino should be called
|
||||
// in the overrided function.
|
||||
virtual nsresult Flush();
|
||||
|
||||
virtual void ReleaseMediaResources() {};
|
||||
virtual void AllocateMediaResources() {}
|
||||
|
||||
virtual void ReleaseMediaResources() {}
|
||||
|
||||
bool HasQueuedSample() {
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
return mQueueSample.Length();
|
||||
}
|
||||
|
||||
protected:
|
||||
// It performs special operation to MP4 sample, the real action is depended on
|
||||
// the codec type.
|
||||
virtual void PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) {}
|
||||
|
||||
// It sends MP4Sample to OMX layer. It must be overrided by subclass.
|
||||
virtual android::status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) = 0;
|
||||
|
||||
// It protects mQueueSample.
|
||||
ReentrantMonitor mMonitor;
|
||||
|
||||
// An queue with the MP4 samples which are waiting to be sent into OMX.
|
||||
// If an element is an empty MP4Sample, that menas EOS. There should not
|
||||
// any sample be queued after EOS.
|
||||
nsTArray<nsAutoPtr<mp4_demuxer::MP4Sample>> mQueueSample;
|
||||
|
||||
// True when mQueueSample gets an empty MP4Sample.
|
||||
bool mInputEOS;
|
||||
};
|
||||
|
||||
// Samples are decoded using the GonkDecoder (MediaCodec)
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ enum {
|
|||
};
|
||||
|
||||
GonkVideoDecoderManager::GonkVideoDecoderManager(
|
||||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
: mImageContainer(aImageContainer)
|
||||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
: GonkDecoderManager()
|
||||
, mImageContainer(aImageContainer)
|
||||
, mReaderCallback(nullptr)
|
||||
, mMonitor("GonkVideoDecoderManager")
|
||||
, mColorConverterBufferSize(0)
|
||||
, mNativeWindow(nullptr)
|
||||
, mPendingVideoBuffersLock("GonkVideoDecoderManager::mPendingVideoBuffersLock")
|
||||
|
|
@ -124,7 +124,7 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
|||
void
|
||||
GonkVideoDecoderManager::QueueFrameTimeIn(int64_t aPTS, int64_t aDuration)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
FrameTimeInfo timeInfo = {aPTS, aDuration};
|
||||
mFrameTimeInfo.AppendElement(timeInfo);
|
||||
}
|
||||
|
|
@ -132,7 +132,7 @@ GonkVideoDecoderManager::QueueFrameTimeIn(int64_t aPTS, int64_t aDuration)
|
|||
nsresult
|
||||
GonkVideoDecoderManager::QueueFrameTimeOut(int64_t aPTS, int64_t& aDuration)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
|
||||
// Set default to 1 here.
|
||||
// During seeking, frames could still in MediaCodec and the mFrameTimeInfo could
|
||||
|
|
@ -435,41 +435,41 @@ void GonkVideoDecoderManager::ReleaseVideoBuffer() {
|
|||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
status_t
|
||||
GonkVideoDecoderManager::SendSampleToOMX(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (mDecoder == nullptr) {
|
||||
GVDM_LOG("Decoder is not inited");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
// An empty MP4Sample is going to notify EOS to decoder. It doesn't need
|
||||
// to keep PTS and duration.
|
||||
if (aSample->data && aSample->duration && aSample->composition_timestamp) {
|
||||
QueueFrameTimeIn(aSample->composition_timestamp, aSample->duration);
|
||||
}
|
||||
status_t rv;
|
||||
|
||||
return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->data),
|
||||
aSample->size,
|
||||
aSample->composition_timestamp,
|
||||
0);
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (aSample != nullptr) {
|
||||
// We must prepare samples in AVC Annex B.
|
||||
mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
|
||||
// Forward sample data to the decoder.
|
||||
|
||||
QueueFrameTimeIn(aSample->composition_timestamp, aSample->duration);
|
||||
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
|
||||
uint32_t length = aSample->size;
|
||||
rv = mDecoder->Input(data, length, aSample->composition_timestamp, 0);
|
||||
}
|
||||
else {
|
||||
// Inputted data is null, so it is going to notify decoder EOS
|
||||
rv = mDecoder->Input(nullptr, 0, 0ll, 0);
|
||||
}
|
||||
return (rv == OK) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::Flush()
|
||||
{
|
||||
GonkDecoderManager::Flush();
|
||||
|
||||
status_t err = mDecoder->flush();
|
||||
if (err != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
mFrameTimeInfo.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@ public:
|
|||
|
||||
virtual android::sp<MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
|
||||
|
||||
|
|
@ -58,6 +56,11 @@ public:
|
|||
|
||||
static void RecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
protected:
|
||||
virtual void PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
|
||||
virtual android::status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
struct FrameInfo
|
||||
{
|
||||
|
|
@ -155,12 +158,11 @@ private:
|
|||
android::sp<ALooper> mManagerLooper;
|
||||
FrameInfo mFrameInfo;
|
||||
|
||||
// It protects mFrameTimeInfo.
|
||||
Monitor mMonitor;
|
||||
// Array of FrameTimeInfo whose corresponding frames are sent to OMX.
|
||||
// Ideally, it is a FIFO. Input() adds the entry to the end element and
|
||||
// CreateVideoData() takes the first entry. However, there are exceptions
|
||||
// due to MediaCodec error or seeking.
|
||||
// It is protected by mMonitor.
|
||||
nsTArray<FrameTimeInfo> mFrameTimeInfo;
|
||||
|
||||
// color converter
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@
|
|||
#define PUBLIC_FUNC
|
||||
#endif
|
||||
|
||||
#define BIG_FRAME 10000
|
||||
|
||||
static int g_log_level = 0;
|
||||
|
||||
#define GMPLOG(l, x) do { \
|
||||
|
|
@ -166,7 +168,7 @@ class FakeVideoEncoder : public GMPVideoEncoder {
|
|||
|
||||
// Now return the encoded data back to the parent.
|
||||
GMPVideoFrame* ftmp;
|
||||
GMPErr err = host_->CreateFrame (kGMPEncodedVideoFrame, &ftmp);
|
||||
GMPErr err = host_->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
|
||||
if (err != GMPNoErr) {
|
||||
GMPLOG (GL_ERROR, "Error creating encoded frame");
|
||||
return;
|
||||
|
|
@ -192,13 +194,17 @@ class FakeVideoEncoder : public GMPVideoEncoder {
|
|||
|
||||
eframe.timestamp_ = inputImage->Timestamp();
|
||||
|
||||
err = f->CreateEmptyFrame (sizeof(eframe));
|
||||
err = f->CreateEmptyFrame (sizeof(eframe) +
|
||||
(frame_type == kGMPKeyFrame ? sizeof(uint32_t) + BIG_FRAME : 0));
|
||||
if (err != GMPNoErr) {
|
||||
GMPLOG (GL_ERROR, "Error allocating frame data");
|
||||
f->Destroy();
|
||||
return;
|
||||
}
|
||||
memcpy(f->Buffer(), &eframe, sizeof(eframe));
|
||||
if (frame_type == kGMPKeyFrame) {
|
||||
*((uint32_t*) f->Buffer() + sizeof(eframe)) = BIG_FRAME;
|
||||
}
|
||||
|
||||
f->SetEncodedWidth (inputImage->Width());
|
||||
f->SetEncodedHeight (inputImage->Height());
|
||||
|
|
|
|||
|
|
@ -540,6 +540,12 @@ MediaSource::Dump(const char* aPath)
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
MediaSource::GetMozDebugReaderData(nsAString& aString)
|
||||
{
|
||||
mDecoder->GetMozDebugReaderData(aString);
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
MediaSource::GetParentObject() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -114,6 +114,10 @@ public:
|
|||
void Dump(const char* aPath);
|
||||
#endif
|
||||
|
||||
// Returns a string describing the state of the MediaSource internal
|
||||
// buffered data. Used for debugging purposes.
|
||||
void GetMozDebugReaderData(nsAString& aString);
|
||||
|
||||
private:
|
||||
// MediaSourceDecoder uses DurationChange to set the duration
|
||||
// without hitting the checks in SetDuration.
|
||||
|
|
|
|||
|
|
@ -290,6 +290,12 @@ MediaSourceDecoder::PrepareReaderInitialization()
|
|||
mReader->PrepareInitialization();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::GetMozDebugReaderData(nsAString& aString)
|
||||
{
|
||||
mReader->GetMozDebugReaderData(aString);
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
|
|
|
|||
|
|
@ -79,6 +79,10 @@ public:
|
|||
// reader in this decoders MediaSourceReader.
|
||||
bool IsActiveReader(MediaDecoderReader* aReader);
|
||||
|
||||
// Returns a string describing the state of the MediaSource internal
|
||||
// buffered data. Used for debugging purposes.
|
||||
void GetMozDebugReaderData(nsAString& aString);
|
||||
|
||||
private:
|
||||
void DoSetMediaSourceDuration(double aDuration);
|
||||
void ScheduleDurationChange(double aOldDuration,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "MediaSourceUtils.h"
|
||||
#include "SourceBufferDecoder.h"
|
||||
#include "TrackBuffer.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
#ifdef MOZ_FMP4
|
||||
#include "SharedDecoderManager.h"
|
||||
|
|
@ -50,9 +51,7 @@ MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
|
|||
, mLastVideoTime(0)
|
||||
, mPendingSeekTime(-1)
|
||||
, mWaitingForSeekData(false)
|
||||
, mAudioIsSeeking(false)
|
||||
, mVideoIsSeeking(false)
|
||||
, mTimeThreshold(-1)
|
||||
, mTimeThreshold(0)
|
||||
, mDropAudioBeforeThreshold(false)
|
||||
, mDropVideoBeforeThreshold(false)
|
||||
, mEnded(false)
|
||||
|
|
@ -119,18 +118,20 @@ MediaSourceReader::RequestAudioData()
|
|||
mAudioPromise.Reject(DECODE_ERROR, __func__);
|
||||
return p;
|
||||
}
|
||||
if (mAudioIsSeeking) {
|
||||
if (IsSeeking()) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called mid-seek. Rejecting.", this);
|
||||
mAudioPromise.Reject(CANCELED, __func__);
|
||||
return p;
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(!mAudioSeekRequest.Exists());
|
||||
|
||||
SwitchReaderResult ret = SwitchAudioReader(mLastAudioTime);
|
||||
switch (ret) {
|
||||
case READER_NEW:
|
||||
mAudioReader->Seek(mLastAudioTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::RequestAudioDataComplete,
|
||||
&MediaSourceReader::RequestAudioDataFailed);
|
||||
mAudioSeekRequest.Begin(mAudioReader->Seek(mLastAudioTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteAudioSeekAndDoRequest,
|
||||
&MediaSourceReader::CompleteAudioSeekAndRejectPromise));
|
||||
break;
|
||||
case READER_ERROR:
|
||||
if (mLastAudioTime) {
|
||||
|
|
@ -139,49 +140,42 @@ MediaSourceReader::RequestAudioData()
|
|||
}
|
||||
// Fallback to using current reader
|
||||
default:
|
||||
RequestAudioDataComplete(0);
|
||||
DoAudioRequest();
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::RequestAudioDataComplete(int64_t aTime)
|
||||
void MediaSourceReader::DoAudioRequest()
|
||||
{
|
||||
mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioDecoded,
|
||||
&MediaSourceReader::OnAudioNotDecoded);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::RequestAudioDataFailed(nsresult aResult)
|
||||
{
|
||||
OnAudioNotDecoded(DECODE_ERROR);
|
||||
mAudioRequest.Begin(mAudioReader->RequestAudioData()
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioDecoded,
|
||||
&MediaSourceReader::OnAudioNotDecoded));
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnAudioDecoded(AudioData* aSample)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!IsSeeking());
|
||||
mAudioRequest.Complete();
|
||||
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
|
||||
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
||||
if (mDropAudioBeforeThreshold) {
|
||||
if (aSample->mTime < mTimeThreshold) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnAudioDecoded mTime=%lld < mTimeThreshold=%lld",
|
||||
this, aSample->mTime, mTimeThreshold);
|
||||
mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioDecoded,
|
||||
&MediaSourceReader::OnAudioNotDecoded);
|
||||
mAudioRequest.Begin(mAudioReader->RequestAudioData()
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioDecoded,
|
||||
&MediaSourceReader::OnAudioNotDecoded));
|
||||
return;
|
||||
}
|
||||
mDropAudioBeforeThreshold = false;
|
||||
}
|
||||
|
||||
// Any OnAudioDecoded callbacks received while mAudioIsSeeking must be not
|
||||
// update our last used timestamp, as these are emitted by the reader we're
|
||||
// switching away from.
|
||||
if (!mAudioIsSeeking) {
|
||||
mLastAudioTime = aSample->mTime + aSample->mDuration;
|
||||
}
|
||||
mLastAudioTime = aSample->mTime + aSample->mDuration;
|
||||
|
||||
mAudioPromise.Resolve(aSample, __func__);
|
||||
}
|
||||
|
|
@ -215,6 +209,9 @@ AdjustEndTime(int64_t* aEndTime, MediaDecoderReader* aReader)
|
|||
void
|
||||
MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!IsSeeking());
|
||||
mAudioRequest.Complete();
|
||||
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnAudioNotDecoded aReason=%u IsEnded: %d", this, aReason, IsEnded());
|
||||
if (aReason == DECODE_ERROR || aReason == CANCELED) {
|
||||
mAudioPromise.Reject(aReason, __func__);
|
||||
|
|
@ -232,10 +229,10 @@ MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
|
|||
// EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
|
||||
// 1065207.
|
||||
if (SwitchAudioReader(mLastAudioTime, EOS_FUZZ_US) == READER_NEW) {
|
||||
mAudioReader->Seek(mLastAudioTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::RequestAudioDataComplete,
|
||||
&MediaSourceReader::RequestAudioDataFailed);
|
||||
mAudioSeekRequest.Begin(mAudioReader->Seek(mLastAudioTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteAudioSeekAndDoRequest,
|
||||
&MediaSourceReader::CompleteAudioSeekAndRejectPromise));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -259,18 +256,20 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
|
|||
mDropAudioBeforeThreshold = true;
|
||||
mDropVideoBeforeThreshold = true;
|
||||
}
|
||||
if (mVideoIsSeeking) {
|
||||
if (IsSeeking()) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::RequestVideoData called mid-seek. Rejecting.", this);
|
||||
mVideoPromise.Reject(CANCELED, __func__);
|
||||
return p;
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(!mVideoSeekRequest.Exists());
|
||||
|
||||
SwitchReaderResult ret = SwitchVideoReader(mLastVideoTime);
|
||||
switch (ret) {
|
||||
case READER_NEW:
|
||||
mVideoReader->Seek(mLastVideoTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::RequestVideoDataComplete,
|
||||
&MediaSourceReader::RequestVideoDataFailed);
|
||||
mVideoSeekRequest.Begin(mVideoReader->Seek(mLastVideoTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteVideoSeekAndDoRequest,
|
||||
&MediaSourceReader::CompleteVideoSeekAndRejectPromise));
|
||||
break;
|
||||
case READER_ERROR:
|
||||
if (mLastVideoTime) {
|
||||
|
|
@ -279,9 +278,7 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
|
|||
}
|
||||
// Fallback to using current reader.
|
||||
default:
|
||||
mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
|
||||
DoVideoRequest();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -289,42 +286,34 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
|
|||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::RequestVideoDataComplete(int64_t aTime)
|
||||
MediaSourceReader::DoVideoRequest()
|
||||
{
|
||||
mVideoReader->RequestVideoData(false, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::RequestVideoDataFailed(nsresult aResult)
|
||||
{
|
||||
OnVideoNotDecoded(DECODE_ERROR);
|
||||
mVideoRequest.Begin(mVideoReader->RequestVideoData(mDropVideoBeforeThreshold, mTimeThreshold)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoDecoded,
|
||||
&MediaSourceReader::OnVideoNotDecoded));
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!IsSeeking());
|
||||
mVideoRequest.Complete();
|
||||
|
||||
MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
|
||||
this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
|
||||
if (mDropVideoBeforeThreshold) {
|
||||
if (aSample->mTime < mTimeThreshold) {
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnVideoDecoded mTime=%lld < mTimeThreshold=%lld",
|
||||
this, aSample->mTime, mTimeThreshold);
|
||||
mVideoReader->RequestVideoData(false, 0)->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoDecoded,
|
||||
&MediaSourceReader::OnVideoNotDecoded);
|
||||
DoVideoRequest();
|
||||
return;
|
||||
}
|
||||
mDropVideoBeforeThreshold = false;
|
||||
mTimeThreshold = 0;
|
||||
}
|
||||
|
||||
// Any OnVideoDecoded callbacks received while mVideoIsSeeking must be not
|
||||
// update our last used timestamp, as these are emitted by the reader we're
|
||||
// switching away from.
|
||||
if (!mVideoIsSeeking) {
|
||||
mLastVideoTime = aSample->mTime + aSample->mDuration;
|
||||
}
|
||||
mLastVideoTime = aSample->mTime + aSample->mDuration;
|
||||
|
||||
mVideoPromise.Resolve(aSample, __func__);
|
||||
}
|
||||
|
|
@ -332,6 +321,9 @@ MediaSourceReader::OnVideoDecoded(VideoData* aSample)
|
|||
void
|
||||
MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!IsSeeking());
|
||||
mVideoRequest.Complete();
|
||||
|
||||
MSE_DEBUG("MediaSourceReader(%p)::OnVideoNotDecoded aReason=%u IsEnded: %d", this, aReason, IsEnded());
|
||||
if (aReason == DECODE_ERROR || aReason == CANCELED) {
|
||||
mVideoPromise.Reject(aReason, __func__);
|
||||
|
|
@ -349,10 +341,10 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
|
|||
// EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug
|
||||
// 1065207.
|
||||
if (SwitchVideoReader(mLastVideoTime, EOS_FUZZ_US) == READER_NEW) {
|
||||
mVideoReader->Seek(mLastVideoTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::RequestVideoDataComplete,
|
||||
&MediaSourceReader::RequestVideoDataFailed);
|
||||
mVideoSeekRequest.Begin(mVideoReader->Seek(mLastVideoTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::CompleteVideoSeekAndDoRequest,
|
||||
&MediaSourceReader::CompleteVideoSeekAndRejectPromise));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -675,6 +667,20 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aIgnored /* Used only for ogg whi
|
|||
return p;
|
||||
}
|
||||
|
||||
// Any previous requests we've been waiting on are now unwanted.
|
||||
mAudioRequest.DisconnectIfExists();
|
||||
mVideoRequest.DisconnectIfExists();
|
||||
|
||||
// Additionally, reject any outstanding promises _we_ made that we might have
|
||||
// been waiting on the above to fulfill.
|
||||
mAudioPromise.RejectIfExists(CANCELED, __func__);
|
||||
mVideoPromise.RejectIfExists(CANCELED, __func__);
|
||||
|
||||
// Finally, if we were midway seeking a new reader to find a sample, abandon
|
||||
// that too.
|
||||
mAudioSeekRequest.DisconnectIfExists();
|
||||
mVideoSeekRequest.DisconnectIfExists();
|
||||
|
||||
// Store pending seek target in case the track buffers don't contain
|
||||
// the desired time and we delay doing the seek.
|
||||
mPendingSeekTime = aTime;
|
||||
|
|
@ -693,69 +699,64 @@ MediaSourceReader::CancelSeek()
|
|||
{
|
||||
MOZ_ASSERT(OnDecodeThread());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mWaitingForSeekData) {
|
||||
mSeekPromise.Reject(NS_OK, __func__);
|
||||
mWaitingForSeekData = false;
|
||||
mPendingSeekTime = -1;
|
||||
} else if (mVideoIsSeeking) {
|
||||
// NB: Currently all readers have sync Seeks(), so this is a no-op.
|
||||
mVideoReader->CancelSeek();
|
||||
} else if (mAudioIsSeeking) {
|
||||
// NB: Currently all readers have sync Seeks(), so this is a no-op.
|
||||
mWaitingForSeekData = false;
|
||||
mPendingSeekTime = -1;
|
||||
if (mAudioReader) {
|
||||
mAudioSeekRequest.DisconnectIfExists();
|
||||
mAudioReader->CancelSeek();
|
||||
} else {
|
||||
MOZ_ASSERT(mSeekPromise.IsEmpty());
|
||||
}
|
||||
if (mVideoReader) {
|
||||
mVideoSeekRequest.DisconnectIfExists();
|
||||
mVideoReader->CancelSeek();
|
||||
}
|
||||
mSeekPromise.RejectIfExists(NS_OK, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnVideoSeekCompleted(int64_t aTime)
|
||||
{
|
||||
mPendingSeekTime = aTime;
|
||||
MOZ_ASSERT(mVideoIsSeeking);
|
||||
MOZ_ASSERT(!mAudioIsSeeking);
|
||||
mVideoIsSeeking = false;
|
||||
mVideoSeekRequest.Complete();
|
||||
|
||||
if (mAudioTrack) {
|
||||
mAudioIsSeeking = true;
|
||||
SwitchAudioReader(mPendingSeekTime);
|
||||
mAudioReader->Seek(mPendingSeekTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioSeekCompleted,
|
||||
&MediaSourceReader::OnSeekFailed);
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p", this, mAudioReader.get());
|
||||
return;
|
||||
mPendingSeekTime = aTime;
|
||||
DoAudioSeek();
|
||||
} else {
|
||||
mPendingSeekTime = -1;
|
||||
mSeekPromise.Resolve(aTime, __func__);
|
||||
}
|
||||
mSeekPromise.Resolve(mPendingSeekTime, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnVideoSeekFailed(nsresult aResult)
|
||||
{
|
||||
mVideoSeekRequest.Complete();
|
||||
mPendingSeekTime = -1;
|
||||
mSeekPromise.Reject(aResult, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::DoAudioSeek()
|
||||
{
|
||||
SwitchAudioReader(mPendingSeekTime);
|
||||
mAudioSeekRequest.Begin(mAudioReader->Seek(mPendingSeekTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnAudioSeekCompleted,
|
||||
&MediaSourceReader::OnAudioSeekFailed));
|
||||
MSE_DEBUG("MediaSourceReader(%p)::DoAudioSeek reader=%p", this, mAudioReader.get());
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnAudioSeekCompleted(int64_t aTime)
|
||||
{
|
||||
mPendingSeekTime = aTime;
|
||||
MOZ_ASSERT(mAudioIsSeeking);
|
||||
MOZ_ASSERT(!mVideoIsSeeking);
|
||||
mAudioIsSeeking = false;
|
||||
|
||||
mSeekPromise.Resolve(mPendingSeekTime, __func__);
|
||||
mAudioSeekRequest.Complete();
|
||||
mPendingSeekTime = -1;
|
||||
mSeekPromise.Resolve(aTime, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::OnSeekFailed(nsresult aResult)
|
||||
MediaSourceReader::OnAudioSeekFailed(nsresult aResult)
|
||||
{
|
||||
MOZ_ASSERT(mVideoIsSeeking || mAudioIsSeeking);
|
||||
|
||||
if (mVideoIsSeeking) {
|
||||
MOZ_ASSERT(!mAudioIsSeeking);
|
||||
mVideoIsSeeking = false;
|
||||
}
|
||||
|
||||
if (mAudioIsSeeking) {
|
||||
MOZ_ASSERT(!mVideoIsSeeking);
|
||||
mAudioIsSeeking = false;
|
||||
}
|
||||
|
||||
mAudioSeekRequest.Complete();
|
||||
mPendingSeekTime = -1;
|
||||
mSeekPromise.Reject(aResult, __func__);
|
||||
}
|
||||
|
|
@ -783,18 +784,25 @@ MediaSourceReader::AttemptSeek()
|
|||
mLastVideoTime = mPendingSeekTime;
|
||||
|
||||
if (mVideoTrack) {
|
||||
mVideoIsSeeking = true;
|
||||
SwitchVideoReader(mPendingSeekTime);
|
||||
mVideoReader->Seek(mPendingSeekTime, 0)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoSeekCompleted,
|
||||
&MediaSourceReader::OnSeekFailed);
|
||||
MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p", this, mVideoReader.get());
|
||||
DoVideoSeek();
|
||||
} else if (mAudioTrack) {
|
||||
DoAudioSeek();
|
||||
} else {
|
||||
OnVideoSeekCompleted(mPendingSeekTime);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::DoVideoSeek()
|
||||
{
|
||||
SwitchVideoReader(mPendingSeekTime);
|
||||
mVideoSeekRequest.Begin(mVideoReader->Seek(mPendingSeekTime, 0)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
&MediaSourceReader::OnVideoSeekCompleted,
|
||||
&MediaSourceReader::OnVideoSeekFailed));
|
||||
MSE_DEBUG("MediaSourceReader(%p)::DoVideoSeek reader=%p", this, mVideoReader.get());
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
|
|
@ -849,11 +857,11 @@ MediaSourceReader::MaybeNotifyHaveData()
|
|||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
bool haveAudio = false, haveVideo = false;
|
||||
if (!mAudioIsSeeking && mAudioTrack && HaveData(mLastAudioTime, MediaData::AUDIO_DATA)) {
|
||||
if (!IsSeeking() && mAudioTrack && HaveData(mLastAudioTime, MediaData::AUDIO_DATA)) {
|
||||
haveAudio = true;
|
||||
WaitPromise(MediaData::AUDIO_DATA).ResolveIfExists(MediaData::AUDIO_DATA, __func__);
|
||||
}
|
||||
if (!mVideoIsSeeking && mVideoTrack && HaveData(mLastVideoTime, MediaData::VIDEO_DATA)) {
|
||||
if (!IsSeeking() && mVideoTrack && HaveData(mLastVideoTime, MediaData::VIDEO_DATA)) {
|
||||
haveVideo = true;
|
||||
WaitPromise(MediaData::VIDEO_DATA).ResolveIfExists(MediaData::VIDEO_DATA, __func__);
|
||||
}
|
||||
|
|
@ -968,6 +976,42 @@ MediaSourceReader::SetMediaSourceDuration(double aDuration)
|
|||
mMediaSourceDuration = aDuration;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::GetMozDebugReaderData(nsAString& aString)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
nsAutoCString result;
|
||||
result += nsPrintfCString("Dumping data for reader %p:\n", this);
|
||||
if (mAudioTrack) {
|
||||
result += nsPrintfCString("\tDumping Audio Track Decoders: - mLastAudioTime: %f\n", double(mLastAudioTime) / USECS_PER_S);
|
||||
for (int32_t i = mAudioTrack->Decoders().Length() - 1; i >= 0; --i) {
|
||||
nsRefPtr<MediaDecoderReader> newReader = mAudioTrack->Decoders()[i]->GetReader();
|
||||
|
||||
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
||||
mAudioTrack->Decoders()[i]->GetBuffered(ranges);
|
||||
result += nsPrintfCString("\t\tReader %d: %p ranges=%s active=%s size=%lld\n",
|
||||
i, newReader.get(), DumpTimeRanges(ranges).get(),
|
||||
newReader.get() == mAudioReader.get() ? "true" : "false",
|
||||
mAudioTrack->Decoders()[i]->GetResource()->GetSize());
|
||||
}
|
||||
}
|
||||
|
||||
if (mVideoTrack) {
|
||||
result += nsPrintfCString("\tDumping Video Track Decoders - mLastVideoTime: %f\n", double(mLastVideoTime) / USECS_PER_S);
|
||||
for (int32_t i = mVideoTrack->Decoders().Length() - 1; i >= 0; --i) {
|
||||
nsRefPtr<MediaDecoderReader> newReader = mVideoTrack->Decoders()[i]->GetReader();
|
||||
|
||||
nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
|
||||
mVideoTrack->Decoders()[i]->GetBuffered(ranges);
|
||||
result += nsPrintfCString("\t\tReader %d: %p ranges=%s active=%s size=%lld\n",
|
||||
i, newReader.get(), DumpTimeRanges(ranges).get(),
|
||||
newReader.get() == mVideoReader.get() ? "true" : "false",
|
||||
mVideoTrack->Decoders()[i]->GetResource()->GetSize());
|
||||
}
|
||||
}
|
||||
aString += NS_ConvertUTF8toUTF16(result);
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MediaSourceReader::SetCDMProxy(CDMProxy* aProxy)
|
||||
|
|
|
|||
|
|
@ -61,9 +61,12 @@ public:
|
|||
void OnVideoDecoded(VideoData* aSample);
|
||||
void OnVideoNotDecoded(NotDecodedReason aReason);
|
||||
|
||||
void DoVideoSeek();
|
||||
void DoAudioSeek();
|
||||
void OnVideoSeekCompleted(int64_t aTime);
|
||||
void OnVideoSeekFailed(nsresult aResult);
|
||||
void OnAudioSeekCompleted(int64_t aTime);
|
||||
void OnSeekFailed(nsresult aResult);
|
||||
void OnAudioSeekFailed(nsresult aResult);
|
||||
|
||||
virtual bool IsWaitForDataSupported() MOZ_OVERRIDE { return true; }
|
||||
virtual nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) MOZ_OVERRIDE;
|
||||
|
|
@ -146,6 +149,10 @@ public:
|
|||
// Returns true if aReader is a currently active audio or video
|
||||
bool IsActiveReader(MediaDecoderReader* aReader);
|
||||
|
||||
// Returns a string describing the state of the MediaSource internal
|
||||
// buffered data. Used for debugging purposes.
|
||||
void GetMozDebugReaderData(nsAString& aString);
|
||||
|
||||
private:
|
||||
// Switch the current audio/video reader to the reader that
|
||||
// contains aTarget (or up to aError after target). Both
|
||||
|
|
@ -157,10 +164,34 @@ private:
|
|||
};
|
||||
SwitchReaderResult SwitchAudioReader(int64_t aTarget, int64_t aError = 0);
|
||||
SwitchReaderResult SwitchVideoReader(int64_t aTarget, int64_t aError = 0);
|
||||
void RequestAudioDataComplete(int64_t aTime);
|
||||
void RequestAudioDataFailed(nsresult aResult);
|
||||
void RequestVideoDataComplete(int64_t aTime);
|
||||
void RequestVideoDataFailed(nsresult aResult);
|
||||
|
||||
void DoAudioRequest();
|
||||
void DoVideoRequest();
|
||||
|
||||
void CompleteAudioSeekAndDoRequest()
|
||||
{
|
||||
mAudioSeekRequest.Complete();
|
||||
DoAudioRequest();
|
||||
}
|
||||
|
||||
void CompleteVideoSeekAndDoRequest()
|
||||
{
|
||||
mVideoSeekRequest.Complete();
|
||||
DoVideoRequest();
|
||||
}
|
||||
|
||||
void CompleteAudioSeekAndRejectPromise()
|
||||
{
|
||||
mAudioSeekRequest.Complete();
|
||||
mAudioPromise.Reject(DECODE_ERROR, __func__);
|
||||
}
|
||||
|
||||
void CompleteVideoSeekAndRejectPromise()
|
||||
{
|
||||
mVideoSeekRequest.Complete();
|
||||
mVideoPromise.Reject(DECODE_ERROR, __func__);
|
||||
}
|
||||
|
||||
// Will reject the MediaPromise with END_OF_STREAM if mediasource has ended
|
||||
// or with WAIT_FOR_DATA otherwise.
|
||||
void CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime /* microseconds */);
|
||||
|
|
@ -173,6 +204,7 @@ private:
|
|||
bool HaveData(int64_t aTarget, MediaData::Type aType);
|
||||
|
||||
void AttemptSeek();
|
||||
bool IsSeeking() { return mPendingSeekTime != -1; }
|
||||
|
||||
nsRefPtr<MediaDecoderReader> mAudioReader;
|
||||
nsRefPtr<MediaDecoderReader> mVideoReader;
|
||||
|
|
@ -183,6 +215,9 @@ private:
|
|||
nsRefPtr<TrackBuffer> mAudioTrack;
|
||||
nsRefPtr<TrackBuffer> mVideoTrack;
|
||||
|
||||
MediaPromiseConsumerHolder<AudioDataPromise> mAudioRequest;
|
||||
MediaPromiseConsumerHolder<VideoDataPromise> mVideoRequest;
|
||||
|
||||
MediaPromiseHolder<AudioDataPromise> mAudioPromise;
|
||||
MediaPromiseHolder<VideoDataPromise> mVideoPromise;
|
||||
|
||||
|
|
@ -201,13 +236,14 @@ private:
|
|||
int64_t mLastAudioTime;
|
||||
int64_t mLastVideoTime;
|
||||
|
||||
MediaPromiseConsumerHolder<SeekPromise> mAudioSeekRequest;
|
||||
MediaPromiseConsumerHolder<SeekPromise> mVideoSeekRequest;
|
||||
MediaPromiseHolder<SeekPromise> mSeekPromise;
|
||||
|
||||
// Temporary seek information while we wait for the data
|
||||
// to be added to the track buffer.
|
||||
MediaPromiseHolder<SeekPromise> mSeekPromise;
|
||||
int64_t mPendingSeekTime;
|
||||
bool mWaitingForSeekData;
|
||||
bool mAudioIsSeeking;
|
||||
bool mVideoIsSeeking;
|
||||
|
||||
int64_t mTimeThreshold;
|
||||
bool mDropAudioBeforeThreshold;
|
||||
|
|
|
|||
|
|
@ -181,7 +181,6 @@ MediaEngineDefaultVideoSource::Stop(SourceMediaStream *aSource, TrackID aID)
|
|||
aSource->EndTrack(kTrackCount + i);
|
||||
}
|
||||
}
|
||||
aSource->Finish();
|
||||
|
||||
mState = kStopped;
|
||||
return NS_OK;
|
||||
|
|
@ -438,7 +437,6 @@ MediaEngineDefaultAudioSource::Stop(SourceMediaStream *aSource, TrackID aID)
|
|||
aSource->EndTrack(kTrackCount + kFakeVideoTrackCount+i);
|
||||
}
|
||||
}
|
||||
aSource->Finish();
|
||||
|
||||
mState = kStopped;
|
||||
return NS_OK;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
#include "webrtc/voice_engine/include/voe_volume_control.h"
|
||||
#include "webrtc/voice_engine/include/voe_external_media.h"
|
||||
#include "webrtc/voice_engine/include/voe_audio_processing.h"
|
||||
#include "webrtc/voice_engine/include/voe_call_report.h"
|
||||
|
||||
// Video Engine
|
||||
// conflicts with #include of scoped_ptr.h
|
||||
|
|
@ -69,6 +68,7 @@ public:
|
|||
virtual int DeliverFrame(unsigned char* buffer,
|
||||
int size,
|
||||
uint32_t time_stamp,
|
||||
int64_t ntp_time_ms,
|
||||
int64_t render_time,
|
||||
void *handle) MOZ_OVERRIDE;
|
||||
/**
|
||||
|
|
@ -219,7 +219,6 @@ private:
|
|||
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERender;
|
||||
ScopedCustomReleasePtr<webrtc::VoENetwork> mVoENetwork;
|
||||
ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mVoEProcessing;
|
||||
ScopedCustomReleasePtr<webrtc::VoECallReport> mVoECallReport;
|
||||
|
||||
// mMonitor protects mSources[] access/changes, and transitions of mState
|
||||
// from kStarted to kStopped (which are combined with EndTrack()).
|
||||
|
|
|
|||
|
|
@ -436,11 +436,6 @@ MediaEngineWebRTCAudioSource::Init()
|
|||
return;
|
||||
}
|
||||
|
||||
mVoECallReport = webrtc::VoECallReport::GetInterface(mVoiceEngine);
|
||||
if (!mVoECallReport) {
|
||||
return;
|
||||
}
|
||||
|
||||
mChannel = mVoEBase->CreateChannel();
|
||||
if (mChannel < 0) {
|
||||
return;
|
||||
|
|
@ -569,24 +564,6 @@ MediaEngineWebRTCAudioSource::Process(int channel,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
mSamples += length;
|
||||
if (mSamples > samplingFreq) {
|
||||
mSamples %= samplingFreq; // just in case mSamples >> samplingFreq
|
||||
if (PR_LOG_TEST(GetMediaManagerLog(), PR_LOG_DEBUG)) {
|
||||
webrtc::EchoStatistics echo;
|
||||
|
||||
mVoECallReport->GetEchoMetricSummary(echo);
|
||||
#define DUMP_STATVAL(x) (x).min, (x).max, (x).average
|
||||
LOG(("Echo: ERL: %d/%d/%d, ERLE: %d/%d/%d, RERL: %d/%d/%d, NLP: %d/%d/%d",
|
||||
DUMP_STATVAL(echo.erl),
|
||||
DUMP_STATVAL(echo.erle),
|
||||
DUMP_STATVAL(echo.rerl),
|
||||
DUMP_STATVAL(echo.a_nlp)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
if (mState != kStarted)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ MediaEngineWebRTCVideoSource::FrameSizeChange(
|
|||
// ViEExternalRenderer Callback. Process every incoming frame here.
|
||||
int
|
||||
MediaEngineWebRTCVideoSource::DeliverFrame(
|
||||
unsigned char* buffer, int size, uint32_t time_stamp, int64_t render_time,
|
||||
void *handle)
|
||||
unsigned char* buffer, int size, uint32_t time_stamp,
|
||||
int64_t ntp_time_ms, int64_t render_time, void *handle)
|
||||
{
|
||||
// Check for proper state.
|
||||
if (mState != kStarted) {
|
||||
|
|
@ -87,8 +87,8 @@ MediaEngineWebRTCVideoSource::DeliverFrame(
|
|||
|
||||
#ifdef DEBUG
|
||||
static uint32_t frame_num = 0;
|
||||
LOGFRAME(("frame %d (%dx%d); timestamp %u, render_time %lu", frame_num++,
|
||||
mWidth, mHeight, time_stamp, render_time));
|
||||
LOGFRAME(("frame %d (%dx%d); timestamp %u, ntp_time %lu, render_time %lu", frame_num++,
|
||||
mWidth, mHeight, time_stamp, ntp_time_ms, render_time));
|
||||
#endif
|
||||
|
||||
// we don't touch anything in 'this' until here (except for snapshot,
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@ interface HTMLMediaElement : HTMLElement {
|
|||
|
||||
// Mozilla extensions:
|
||||
partial interface HTMLMediaElement {
|
||||
[ChromeOnly]
|
||||
readonly attribute MediaSource? mozMediaSourceObject;
|
||||
attribute MediaStream? mozSrcObject;
|
||||
attribute boolean mozPreservesPitch;
|
||||
readonly attribute boolean mozAutoplayEnabled;
|
||||
|
|
|
|||
|
|
@ -35,4 +35,6 @@ interface MediaSource : EventTarget {
|
|||
[Throws]
|
||||
void endOfStream(optional MediaSourceEndOfStreamError error);
|
||||
static boolean isTypeSupported(DOMString type);
|
||||
[ChromeOnly]
|
||||
readonly attribute DOMString mozDebugReaderData;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ interface Response {
|
|||
|
||||
readonly attribute USVString url;
|
||||
readonly attribute unsigned short status;
|
||||
readonly attribute boolean ok;
|
||||
readonly attribute ByteString statusText;
|
||||
[SameObject] readonly attribute Headers headers;
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,20 @@ function testRedirect() {
|
|||
}
|
||||
}
|
||||
|
||||
function testOk() {
|
||||
var r1 = new Response("", { status: 200});
|
||||
ok(r1.ok, "Response with status 200 should have ok true");
|
||||
|
||||
var r2 = new Response("", { status: 204});
|
||||
ok(r2.ok, "Response with status 204 should have ok true");
|
||||
|
||||
var r3 = new Response("", { status: 299});
|
||||
ok(r3.ok, "Response with status 299 should have ok true");
|
||||
|
||||
var r4 = new Response("", { status: 302});
|
||||
ok(!r4.ok, "Response with status 302 should have ok false");
|
||||
}
|
||||
|
||||
function testBodyUsed() {
|
||||
var res = new Response("Sample body");
|
||||
ok(!res.bodyUsed, "bodyUsed is initially false.");
|
||||
|
|
@ -138,6 +152,7 @@ onmessage = function() {
|
|||
testDefaultCtor();
|
||||
testClone();
|
||||
testRedirect();
|
||||
testOk();
|
||||
|
||||
Promise.resolve()
|
||||
.then(testBodyCreation)
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ TextureClientD3D11::BorrowDrawTarget()
|
|||
static const GUID sD3D11TextureUsage =
|
||||
{ 0xd89275b0, 0x6c7d, 0x4038, { 0xb5, 0xfa, 0x4d, 0x87, 0x16, 0xd5, 0xcc, 0x4e } };
|
||||
|
||||
/* This class get's it's lifetime tied to a D3D texture
|
||||
/* This class gets its lifetime tied to a D3D texture
|
||||
* and increments memory usage on construction and decrements
|
||||
* on destruction */
|
||||
class TextureMemoryMeasurer : public IUnknown
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ purpose. It is provided "as is" without express or implied warranty.
|
|||
*/
|
||||
#ifndef __TH_CHAR_H__
|
||||
#define __TH_CHAR_H__
|
||||
#include "nscore.h"
|
||||
|
||||
|
||||
typedef unsigned char tis_char;
|
||||
|
|
|
|||
|
|
@ -190,7 +190,10 @@ BackgroundChildImpl::DeallocPFileDescriptorSetChild(
|
|||
BackgroundChildImpl::PVsyncChild*
|
||||
BackgroundChildImpl::AllocPVsyncChild()
|
||||
{
|
||||
return new mozilla::layout::VsyncChild();
|
||||
nsRefPtr<mozilla::layout::VsyncChild> actor = new mozilla::layout::VsyncChild();
|
||||
// There still has one ref-count after return, and it will be released in
|
||||
// DeallocPVsyncChild().
|
||||
return actor.forget().take();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -198,7 +201,9 @@ BackgroundChildImpl::DeallocPVsyncChild(PVsyncChild* aActor)
|
|||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete static_cast<mozilla::layout::VsyncChild*>(aActor);
|
||||
// This actor already has one ref-count. Please check AllocPVsyncChild().
|
||||
nsRefPtr<mozilla::layout::VsyncChild> actor =
|
||||
dont_AddRef(static_cast<mozilla::layout::VsyncChild*>(aActor));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -147,6 +147,9 @@ class AsmJSNumLit
|
|||
static AsmJSNumLit Create(Which w, Value v) {
|
||||
AsmJSNumLit lit;
|
||||
lit.which_ = w;
|
||||
// Force float32 coercion, as the caller may have not done it.
|
||||
if (w == Float)
|
||||
v = Float32Value(v.toNumber());
|
||||
lit.value.scalar_ = v;
|
||||
MOZ_ASSERT(!lit.isSimd());
|
||||
return lit;
|
||||
|
|
|
|||
|
|
@ -419,9 +419,26 @@ case "$target" in
|
|||
|
||||
if test "$_CC_MAJOR_VERSION" = "18"; then
|
||||
_CC_SUITE=12
|
||||
MSVC_C_RUNTIME_DLL=msvcr120.dll
|
||||
MSVC_CXX_RUNTIME_DLL=msvcp120.dll
|
||||
elif test "$_CC_MAJOR_VERSION" = "19"; then
|
||||
_CC_SUITE=14
|
||||
MSVC_C_RUNTIME_DLL=vcruntime140.dll
|
||||
MSVC_CXX_RUNTIME_DLL=msvcp140.dll
|
||||
MSVC_APPCRT_DLL=appcrt140.dll
|
||||
MSVC_DESKTOPCRT_DLL=desktopcrt140.dll
|
||||
|
||||
# -Wv:18 disables all warnings introduced after VS2013
|
||||
# See http://blogs.msdn.com/b/vcblog/archive/2014/11/12/improvements-to-warnings-in-the-c-compiler.aspx
|
||||
CFLAGS="$CFLAGS -Wv:18"
|
||||
CXXFLAGS="$CXXFLAGS -Wv:18"
|
||||
else
|
||||
AC_MSG_ERROR([This version ($CC_VERSION) of the MSVC compiler is unsupported. See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
|
||||
fi
|
||||
AC_SUBST(MSVC_C_RUNTIME_DLL)
|
||||
AC_SUBST(MSVC_CXX_RUNTIME_DLL)
|
||||
AC_SUBST(MSVC_APPCRT_DLL)
|
||||
AC_SUBST(MSVC_DESKTOPCRT_DLL)
|
||||
|
||||
dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool',
|
||||
dnl not something else like "magnetic tape manipulation utility".
|
||||
|
|
|
|||
|
|
@ -382,10 +382,7 @@ class FullParseHandler
|
|||
if (!initialYield)
|
||||
return false;
|
||||
|
||||
initialYield->pn_next = stmtList->pn_head;
|
||||
stmtList->pn_head = initialYield;
|
||||
stmtList->pn_count++;
|
||||
|
||||
stmtList->prepend(initialYield);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -848,6 +848,15 @@ class ParseNode
|
|||
pn_count++;
|
||||
}
|
||||
|
||||
void prepend(ParseNode *pn) {
|
||||
MOZ_ASSERT(pn_arity == PN_LIST);
|
||||
pn->pn_next = pn_head;
|
||||
pn_head = pn;
|
||||
if (pn_tail == &pn_head)
|
||||
pn_tail = &pn->pn_next;
|
||||
pn_count++;
|
||||
}
|
||||
|
||||
void checkListConsistency()
|
||||
#ifndef DEBUG
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -2253,11 +2253,7 @@ Parser<FullParseHandler>::finishFunctionDefinition(ParseNode *pn, FunctionBox *f
|
|||
if (!item)
|
||||
return false;
|
||||
|
||||
item->pn_next = body->pn_head;
|
||||
body->pn_head = item;
|
||||
if (body->pn_tail == &body->pn_head)
|
||||
body->pn_tail = &item->pn_next;
|
||||
++body->pn_count;
|
||||
body->prepend(item);
|
||||
body->pn_xflags |= PNX_DESTRUCT;
|
||||
}
|
||||
|
||||
|
|
|
|||
36
js/src/jit-test/tests/asm.js/bug1126251.js
Normal file
36
js/src/jit-test/tests/asm.js/bug1126251.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
load(libdir + "asm.js");
|
||||
|
||||
var v = asmLink(asmCompile('global', `
|
||||
"use asm";
|
||||
var frd = global.Math.fround;
|
||||
function e() {
|
||||
var x = frd(.1e+71);
|
||||
x = frd(x / x);
|
||||
return +x;
|
||||
}
|
||||
return e;
|
||||
`), this)();
|
||||
|
||||
assertEq(v, NaN);
|
||||
|
||||
if (!isSimdAvailable() || typeof SIMD === 'undefined') {
|
||||
quit(0);
|
||||
}
|
||||
|
||||
var v = asmLink(asmCompile('global', `
|
||||
"use asm";
|
||||
var frd = global.Math.fround;
|
||||
var float32x4 = global.SIMD.float32x4;
|
||||
var splat = float32x4.splat;
|
||||
function e() {
|
||||
var v = float32x4(0,0,0,0);
|
||||
var x = frd(0.);
|
||||
v = splat(.1e+71);
|
||||
x = v.x;
|
||||
x = frd(x / x);
|
||||
return +x;
|
||||
}
|
||||
return e;
|
||||
`), this)();
|
||||
|
||||
assertEq(v, NaN);
|
||||
18
js/src/jit-test/tests/basic/mutable-proto-teleporting.js
Normal file
18
js/src/jit-test/tests/basic/mutable-proto-teleporting.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// The teleporting optimization should work correctly
|
||||
// when we modify an object's proto.
|
||||
|
||||
var A = {x: 1};
|
||||
var B = Object.create(A);
|
||||
|
||||
var C = {};
|
||||
C.__proto__ = B;
|
||||
|
||||
function f() {
|
||||
for (var i=0; i<25; i++) {
|
||||
assertEq(C.x, (i <= 20) ? 1 : 3);
|
||||
if (i === 20) {
|
||||
B.x = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
f();
|
||||
14
js/src/jit-test/tests/basic/teleporting-mutable-proto.js
Normal file
14
js/src/jit-test/tests/basic/teleporting-mutable-proto.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
var A = {x: 3};
|
||||
var B = Object.create(A);
|
||||
var C = Object.create(B);
|
||||
var D = Object.create(C);
|
||||
|
||||
function f() {
|
||||
for (var i=0; i<30; i++) {
|
||||
assertEq(D.x, (i <= 20) ? 3 : 10);
|
||||
if (i === 20) {
|
||||
C.__proto__ = {x: 10};
|
||||
}
|
||||
}
|
||||
}
|
||||
f();
|
||||
9
js/src/jit-test/tests/basic/testBug1126754.js
Normal file
9
js/src/jit-test/tests/basic/testBug1126754.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// |jit-test| error:SyntaxError
|
||||
|
||||
(function() {
|
||||
with ({}) {}
|
||||
function f() {
|
||||
({ *h(){} })
|
||||
}
|
||||
function f
|
||||
})()
|
||||
5
js/src/jit-test/tests/gc/bug-1124653.js
Normal file
5
js/src/jit-test/tests/gc/bug-1124653.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
var o = {};
|
||||
gczeal(14);
|
||||
for (var i = 0; i < 200; i++) {
|
||||
with (o) { }
|
||||
}
|
||||
|
|
@ -352,98 +352,20 @@ class CachePage
|
|||
char validity_map_[kValidityMapSize]; // One byte per line.
|
||||
};
|
||||
|
||||
class Redirection;
|
||||
|
||||
class SimulatorRuntime
|
||||
{
|
||||
friend class AutoLockSimulatorRuntime;
|
||||
|
||||
Redirection *redirection_;
|
||||
|
||||
// ICache checking.
|
||||
struct ICacheHasher {
|
||||
typedef void *Key;
|
||||
typedef void *Lookup;
|
||||
static HashNumber hash(const Lookup &l);
|
||||
static bool match(const Key &k, const Lookup &l);
|
||||
};
|
||||
|
||||
public:
|
||||
typedef HashMap<void *, CachePage *, ICacheHasher, SystemAllocPolicy> ICacheMap;
|
||||
|
||||
protected:
|
||||
ICacheMap icache_;
|
||||
|
||||
// Synchronize access between main thread and compilation threads.
|
||||
PRLock *lock_;
|
||||
mozilla::DebugOnly<PRThread *> lockOwner_;
|
||||
|
||||
public:
|
||||
SimulatorRuntime()
|
||||
: redirection_(nullptr),
|
||||
lock_(nullptr),
|
||||
lockOwner_(nullptr)
|
||||
{}
|
||||
~SimulatorRuntime();
|
||||
bool init() {
|
||||
lock_ = PR_NewLock();
|
||||
if (!lock_)
|
||||
return false;
|
||||
if (!icache_.init())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
ICacheMap &icache() {
|
||||
MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
|
||||
return icache_;
|
||||
}
|
||||
Redirection *redirection() const {
|
||||
MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
|
||||
return redirection_;
|
||||
}
|
||||
void setRedirection(js::jit::Redirection *redirection) {
|
||||
MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
|
||||
redirection_ = redirection;
|
||||
}
|
||||
};
|
||||
|
||||
class AutoLockSimulatorRuntime
|
||||
{
|
||||
protected:
|
||||
SimulatorRuntime *srt_;
|
||||
|
||||
public:
|
||||
AutoLockSimulatorRuntime(SimulatorRuntime *srt)
|
||||
: srt_(srt)
|
||||
{
|
||||
PR_Lock(srt_->lock_);
|
||||
MOZ_ASSERT(!srt_->lockOwner_);
|
||||
#ifdef DEBUG
|
||||
srt_->lockOwner_ = PR_GetCurrentThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
~AutoLockSimulatorRuntime() {
|
||||
MOZ_ASSERT(srt_->lockOwner_ == PR_GetCurrentThread());
|
||||
srt_->lockOwner_ = nullptr;
|
||||
PR_Unlock(srt_->lock_);
|
||||
}
|
||||
};
|
||||
|
||||
bool Simulator::ICacheCheckingEnabled = false;
|
||||
|
||||
int64_t Simulator::StopSimAt = -1L;
|
||||
|
||||
SimulatorRuntime *
|
||||
CreateSimulatorRuntime()
|
||||
Simulator *
|
||||
Simulator::Create()
|
||||
{
|
||||
SimulatorRuntime *srt = js_new<SimulatorRuntime>();
|
||||
if (!srt)
|
||||
Simulator *sim = js_new<Simulator>();
|
||||
if (!sim)
|
||||
return nullptr;
|
||||
|
||||
if (!srt->init()) {
|
||||
js_delete(srt);
|
||||
return nullptr;
|
||||
if (!sim->init()) {
|
||||
js_delete(sim);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getenv("ARM_SIM_ICACHE_CHECKS"))
|
||||
|
|
@ -456,13 +378,13 @@ CreateSimulatorRuntime()
|
|||
Simulator::StopSimAt = stopAt;
|
||||
}
|
||||
|
||||
return srt;
|
||||
return sim;
|
||||
}
|
||||
|
||||
void
|
||||
DestroySimulatorRuntime(SimulatorRuntime *srt)
|
||||
Simulator::Destroy(Simulator *sim)
|
||||
{
|
||||
js_delete(srt);
|
||||
js_delete(sim);
|
||||
}
|
||||
|
||||
// The ArmDebugger class is used by the simulator while debugging simulated ARM
|
||||
|
|
@ -1000,11 +922,11 @@ AllOnOnePage(uintptr_t start, int size)
|
|||
}
|
||||
|
||||
static CachePage *
|
||||
GetCachePage(SimulatorRuntime::ICacheMap &i_cache, void *page)
|
||||
GetCachePage(Simulator::ICacheMap &i_cache, void *page)
|
||||
{
|
||||
MOZ_ASSERT(Simulator::ICacheCheckingEnabled);
|
||||
|
||||
SimulatorRuntime::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
|
||||
Simulator::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
|
||||
if (p)
|
||||
return p->value();
|
||||
|
||||
|
|
@ -1016,7 +938,7 @@ GetCachePage(SimulatorRuntime::ICacheMap &i_cache, void *page)
|
|||
|
||||
// Flush from start up to and not including start + size.
|
||||
static void
|
||||
FlushOnePage(SimulatorRuntime::ICacheMap &i_cache, intptr_t start, int size)
|
||||
FlushOnePage(Simulator::ICacheMap &i_cache, intptr_t start, int size)
|
||||
{
|
||||
MOZ_ASSERT(size <= CachePage::kPageSize);
|
||||
MOZ_ASSERT(AllOnOnePage(start, size - 1));
|
||||
|
|
@ -1031,7 +953,7 @@ FlushOnePage(SimulatorRuntime::ICacheMap &i_cache, intptr_t start, int size)
|
|||
}
|
||||
|
||||
static void
|
||||
FlushICache(SimulatorRuntime::ICacheMap &i_cache, void *start_addr, size_t size)
|
||||
FlushICache(Simulator::ICacheMap &i_cache, void *start_addr, size_t size)
|
||||
{
|
||||
intptr_t start = reinterpret_cast<intptr_t>(start_addr);
|
||||
int intra_line = (start & CachePage::kLineMask);
|
||||
|
|
@ -1052,7 +974,7 @@ FlushICache(SimulatorRuntime::ICacheMap &i_cache, void *start_addr, size_t size)
|
|||
}
|
||||
|
||||
static void
|
||||
CheckICache(SimulatorRuntime::ICacheMap &i_cache, SimInstruction *instr)
|
||||
CheckICache(Simulator::ICacheMap &i_cache, SimInstruction *instr)
|
||||
{
|
||||
intptr_t address = reinterpret_cast<intptr_t>(instr);
|
||||
void *page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
|
||||
|
|
@ -1075,13 +997,13 @@ CheckICache(SimulatorRuntime::ICacheMap &i_cache, SimInstruction *instr)
|
|||
}
|
||||
|
||||
HashNumber
|
||||
SimulatorRuntime::ICacheHasher::hash(const Lookup &l)
|
||||
Simulator::ICacheHasher::hash(const Lookup &l)
|
||||
{
|
||||
return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(l)) >> 2;
|
||||
}
|
||||
|
||||
bool
|
||||
SimulatorRuntime::ICacheHasher::match(const Key &k, const Lookup &l)
|
||||
Simulator::ICacheHasher::match(const Key &k, const Lookup &l)
|
||||
{
|
||||
MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
|
||||
MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
|
||||
|
|
@ -1101,30 +1023,19 @@ Simulator::FlushICache(void *start_addr, size_t size)
|
|||
JitSpewCont(JitSpew_CacheFlush, "[%p %zx]", start_addr, size);
|
||||
if (!Simulator::ICacheCheckingEnabled)
|
||||
return;
|
||||
SimulatorRuntime *srt = TlsPerThreadData.get()->simulatorRuntime();
|
||||
AutoLockSimulatorRuntime alsr(srt);
|
||||
js::jit::FlushICache(srt->icache(), start_addr, size);
|
||||
js::jit::FlushICache(Simulator::Current()->icache(), start_addr, size);
|
||||
}
|
||||
|
||||
Simulator::~Simulator()
|
||||
{
|
||||
js_free(stack_);
|
||||
}
|
||||
|
||||
Simulator::Simulator(SimulatorRuntime *srt)
|
||||
: srt_(srt)
|
||||
Simulator::Simulator()
|
||||
{
|
||||
// Set up simulator support first. Some of this information is needed to
|
||||
// setup the architecture state.
|
||||
|
||||
// Allocate 2MB for the stack. Note that we will only use 1MB, see also
|
||||
// Simulator::stackLimit().
|
||||
static const size_t stackSize = 2 * 1024*1024;
|
||||
stack_ = reinterpret_cast<char*>(js_malloc(stackSize));
|
||||
if (!stack_) {
|
||||
MOZ_ReportAssertionFailure("[unhandlable oom] Simulator stack", __FILE__, __LINE__);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
// Note, allocation and anything that depends on allocated memory is
|
||||
// deferred until init(), in order to handle OOM properly.
|
||||
|
||||
stack_ = nullptr;
|
||||
stackLimit_ = 0;
|
||||
pc_modified_ = false;
|
||||
icount_ = 0L;
|
||||
resume_pc_ = 0;
|
||||
|
|
@ -1161,17 +1072,38 @@ Simulator::Simulator(SimulatorRuntime *srt)
|
|||
underflow_vfp_flag_ = false;
|
||||
inexact_vfp_flag_ = false;
|
||||
|
||||
// The sp is initialized to point to the bottom (high address) of the
|
||||
// allocated stack area. To be safe in potential stack underflows we leave
|
||||
// some buffer below.
|
||||
registers_[sp] = reinterpret_cast<int32_t>(stack_) + stackSize - 64;
|
||||
|
||||
// The lr and pc are initialized to a known bad value that will cause an
|
||||
// access violation if the simulator ever tries to execute it.
|
||||
registers_[pc] = bad_lr;
|
||||
registers_[lr] = bad_lr;
|
||||
|
||||
lastDebuggerInput_ = nullptr;
|
||||
|
||||
redirection_ = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
Simulator::init()
|
||||
{
|
||||
if (!icache_.init())
|
||||
return false;
|
||||
|
||||
// Allocate 2MB for the stack. Note that we will only use 1MB, see below.
|
||||
static const size_t stackSize = 2 * 1024*1024;
|
||||
stack_ = reinterpret_cast<char*>(js_malloc(stackSize));
|
||||
if (!stack_)
|
||||
return false;
|
||||
|
||||
// Leave a safety margin of 1MB to prevent overrunning the stack when
|
||||
// pushing values (total stack size is 2MB).
|
||||
stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
|
||||
|
||||
// The sp is initialized to point to the bottom (high address) of the
|
||||
// allocated stack area. To be safe in potential stack underflows we leave
|
||||
// some buffer below.
|
||||
registers_[sp] = reinterpret_cast<int32_t>(stack_) + stackSize - 64;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// When the generated code calls a VM function (masm.callWithABI) we need to
|
||||
|
|
@ -1182,18 +1114,18 @@ Simulator::Simulator(SimulatorRuntime *srt)
|
|||
// offset from the svc instruction so the simulator knows what to call.
|
||||
class Redirection
|
||||
{
|
||||
friend class SimulatorRuntime;
|
||||
friend class Simulator;
|
||||
|
||||
Redirection(void *nativeFunction, ABIFunctionType type, SimulatorRuntime *srt)
|
||||
Redirection(void *nativeFunction, ABIFunctionType type, Simulator *sim)
|
||||
: nativeFunction_(nativeFunction),
|
||||
swiInstruction_(Assembler::AL | (0xf * (1 << 24)) | kCallRtRedirected),
|
||||
type_(type),
|
||||
next_(nullptr)
|
||||
{
|
||||
next_ = srt->redirection();
|
||||
next_ = sim->redirection();
|
||||
if (Simulator::ICacheCheckingEnabled)
|
||||
FlushICache(srt->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
|
||||
srt->setRedirection(this);
|
||||
FlushICache(sim->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
|
||||
sim->setRedirection(this);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -1202,13 +1134,8 @@ class Redirection
|
|||
ABIFunctionType type() const { return type_; }
|
||||
|
||||
static Redirection *Get(void *nativeFunction, ABIFunctionType type) {
|
||||
PerThreadData *pt = TlsPerThreadData.get();
|
||||
SimulatorRuntime *srt = pt->simulatorRuntime();
|
||||
AutoLockSimulatorRuntime alsr(srt);
|
||||
|
||||
MOZ_ASSERT_IF(pt->simulator(), pt->simulator()->srt_ == srt);
|
||||
|
||||
Redirection *current = srt->redirection();
|
||||
Simulator *sim = Simulator::Current();
|
||||
Redirection *current = sim->redirection();
|
||||
for (; current != nullptr; current = current->next_) {
|
||||
if (current->nativeFunction_ == nativeFunction) {
|
||||
MOZ_ASSERT(current->type() == type);
|
||||
|
|
@ -1222,7 +1149,7 @@ class Redirection
|
|||
__FILE__, __LINE__);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
new(redir) Redirection(nativeFunction, type, srt);
|
||||
new(redir) Redirection(nativeFunction, type, sim);
|
||||
return redir;
|
||||
}
|
||||
|
||||
|
|
@ -1239,23 +1166,22 @@ class Redirection
|
|||
Redirection *next_;
|
||||
};
|
||||
|
||||
/* static */ void *
|
||||
Simulator::RedirectNativeFunction(void *nativeFunction, ABIFunctionType type)
|
||||
{
|
||||
Redirection *redirection = Redirection::Get(nativeFunction, type);
|
||||
return redirection->addressOfSwiInstruction();
|
||||
}
|
||||
|
||||
SimulatorRuntime::~SimulatorRuntime()
|
||||
Simulator::~Simulator()
|
||||
{
|
||||
js_free(stack_);
|
||||
Redirection *r = redirection_;
|
||||
while (r) {
|
||||
Redirection *next = r->next_;
|
||||
js_delete(r);
|
||||
r = next;
|
||||
}
|
||||
if (lock_)
|
||||
PR_DestroyLock(lock_);
|
||||
}
|
||||
|
||||
/* static */ void *
|
||||
Simulator::RedirectNativeFunction(void *nativeFunction, ABIFunctionType type)
|
||||
{
|
||||
Redirection *redirection = Redirection::Get(nativeFunction, type);
|
||||
return redirection->addressOfSwiInstruction();
|
||||
}
|
||||
|
||||
// Sets the register in the architecture state. It will also deal with updating
|
||||
|
|
@ -1630,9 +1556,13 @@ Simulator::writeDW(int32_t addr, int32_t value1, int32_t value2)
|
|||
uintptr_t
|
||||
Simulator::stackLimit() const
|
||||
{
|
||||
// Leave a safety margin of 1MB to prevent overrunning the stack when
|
||||
// pushing values (total stack size is 2MB).
|
||||
return reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
|
||||
return stackLimit_;
|
||||
}
|
||||
|
||||
uintptr_t *
|
||||
Simulator::addressOfStackLimit()
|
||||
{
|
||||
return &stackLimit_;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -4170,10 +4100,8 @@ Simulator::decodeSpecialCondition(SimInstruction *instr)
|
|||
void
|
||||
Simulator::instructionDecode(SimInstruction *instr)
|
||||
{
|
||||
if (Simulator::ICacheCheckingEnabled) {
|
||||
AutoLockSimulatorRuntime alsr(srt_);
|
||||
CheckICache(srt_->icache(), instr);
|
||||
}
|
||||
if (Simulator::ICacheCheckingEnabled)
|
||||
CheckICache(icache(), instr);
|
||||
|
||||
pc_modified_ = false;
|
||||
|
||||
|
|
@ -4441,14 +4369,7 @@ Simulator::call(uint8_t* entry, int argument_count, ...)
|
|||
Simulator *
|
||||
Simulator::Current()
|
||||
{
|
||||
PerThreadData *pt = TlsPerThreadData.get();
|
||||
Simulator *sim = pt->simulator();
|
||||
if (!sim) {
|
||||
sim = js_new<Simulator>(pt->simulatorRuntime());
|
||||
pt->setSimulator(sim);
|
||||
}
|
||||
|
||||
return sim;
|
||||
return TlsPerThreadData.get()->simulator();
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
|
|
@ -4460,46 +4381,14 @@ JSRuntime::simulator() const
|
|||
return simulator_;
|
||||
}
|
||||
|
||||
uintptr_t *
|
||||
JSRuntime::addressOfSimulatorStackLimit()
|
||||
{
|
||||
return simulator_->addressOfStackLimit();
|
||||
}
|
||||
|
||||
js::jit::Simulator *
|
||||
js::PerThreadData::simulator() const
|
||||
{
|
||||
return runtime_->simulator();
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::setSimulator(js::jit::Simulator *sim)
|
||||
{
|
||||
simulator_ = sim;
|
||||
simulatorStackLimit_ = sim->stackLimit();
|
||||
}
|
||||
|
||||
void
|
||||
js::PerThreadData::setSimulator(js::jit::Simulator *sim)
|
||||
{
|
||||
runtime_->setSimulator(sim);
|
||||
}
|
||||
|
||||
uintptr_t *
|
||||
JSRuntime::addressOfSimulatorStackLimit()
|
||||
{
|
||||
return &simulatorStackLimit_;
|
||||
}
|
||||
|
||||
js::jit::SimulatorRuntime *
|
||||
js::PerThreadData::simulatorRuntime() const
|
||||
{
|
||||
return runtime_->simulatorRuntime();
|
||||
}
|
||||
|
||||
js::jit::SimulatorRuntime *
|
||||
JSRuntime::simulatorRuntime() const
|
||||
{
|
||||
return simulatorRuntime_;
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::setSimulatorRuntime(js::jit::SimulatorRuntime *srt)
|
||||
{
|
||||
MOZ_ASSERT(!simulatorRuntime_);
|
||||
simulatorRuntime_ = srt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,8 @@ namespace js {
|
|||
namespace jit {
|
||||
|
||||
class Simulator;
|
||||
class SimulatorRuntime;
|
||||
SimulatorRuntime *CreateSimulatorRuntime();
|
||||
void DestroySimulatorRuntime(SimulatorRuntime *srt);
|
||||
class Redirection;
|
||||
class CachePage;
|
||||
|
||||
// When the SingleStepCallback is called, the simulator is about to execute
|
||||
// sim->get_pc() and the current machine state represents the completed
|
||||
|
|
@ -95,7 +94,13 @@ class Simulator
|
|||
num_q_registers = 16
|
||||
};
|
||||
|
||||
explicit Simulator(SimulatorRuntime *srt);
|
||||
// Returns nullptr on OOM.
|
||||
static Simulator *Create();
|
||||
|
||||
static void Destroy(Simulator *simulator);
|
||||
|
||||
// Constructor/destructor are for internal use only; use the static methods above.
|
||||
Simulator();
|
||||
~Simulator();
|
||||
|
||||
// The currently executing Simulator instance. Potentially there can be one
|
||||
|
|
@ -106,6 +111,8 @@ class Simulator
|
|||
return Simulator::Current()->stackLimit();
|
||||
}
|
||||
|
||||
uintptr_t *addressOfStackLimit();
|
||||
|
||||
// Accessors for register state. Reading the pc value adheres to the ARM
|
||||
// architecture specification and is off by a 8 from the currently executing
|
||||
// instruction.
|
||||
|
|
@ -188,6 +195,8 @@ class Simulator
|
|||
end_sim_pc = -2
|
||||
};
|
||||
|
||||
bool init();
|
||||
|
||||
// Checks if the current instruction should be executed based on its
|
||||
// condition bits.
|
||||
inline bool conditionallyExecute(SimInstruction* instr);
|
||||
|
|
@ -333,6 +342,7 @@ class Simulator
|
|||
|
||||
// Simulator support.
|
||||
char *stack_;
|
||||
uintptr_t stackLimit_;
|
||||
bool pc_modified_;
|
||||
int64_t icount_;
|
||||
|
||||
|
|
@ -350,8 +360,6 @@ class Simulator
|
|||
SingleStepCallback single_step_callback_;
|
||||
void *single_step_callback_arg_;
|
||||
|
||||
SimulatorRuntime *srt_;
|
||||
|
||||
// A stop is watched if its code is less than kNumOfWatchedStops.
|
||||
// Only watched stops support enabling/disabling and the counter feature.
|
||||
static const uint32_t kNumOfWatchedStops = 256;
|
||||
|
|
@ -374,6 +382,35 @@ class Simulator
|
|||
return icount_;
|
||||
}
|
||||
|
||||
private:
|
||||
Redirection *redirection_;
|
||||
|
||||
// ICache checking.
|
||||
struct ICacheHasher {
|
||||
typedef void *Key;
|
||||
typedef void *Lookup;
|
||||
static HashNumber hash(const Lookup &l);
|
||||
static bool match(const Key &k, const Lookup &l);
|
||||
};
|
||||
|
||||
public:
|
||||
typedef HashMap<void *, CachePage *, ICacheHasher, SystemAllocPolicy> ICacheMap;
|
||||
|
||||
protected:
|
||||
ICacheMap icache_;
|
||||
|
||||
public:
|
||||
ICacheMap &icache() {
|
||||
return icache_;
|
||||
}
|
||||
|
||||
Redirection *redirection() const {
|
||||
return redirection_;
|
||||
}
|
||||
|
||||
void setRedirection(js::jit::Redirection *redirection) {
|
||||
redirection_ = redirection;
|
||||
}
|
||||
};
|
||||
|
||||
#define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror) \
|
||||
|
|
|
|||
|
|
@ -486,96 +486,20 @@ class CachePage {
|
|||
char validity_map_[kValidityMapSize]; // One byte per line.
|
||||
};
|
||||
|
||||
class Redirection;
|
||||
|
||||
class SimulatorRuntime
|
||||
{
|
||||
friend class AutoLockSimulatorRuntime;
|
||||
|
||||
Redirection *redirection_;
|
||||
|
||||
// ICache checking.
|
||||
struct ICacheHasher {
|
||||
typedef void *Key;
|
||||
typedef void *Lookup;
|
||||
static HashNumber hash(const Lookup &l);
|
||||
static bool match(const Key &k, const Lookup &l);
|
||||
};
|
||||
|
||||
public:
|
||||
typedef HashMap<void *, CachePage *, ICacheHasher, SystemAllocPolicy> ICacheMap;
|
||||
|
||||
protected:
|
||||
ICacheMap icache_;
|
||||
|
||||
// Synchronize access between main thread and compilation threads.
|
||||
PRLock *lock_;
|
||||
mozilla::DebugOnly<PRThread *> lockOwner_;
|
||||
|
||||
public:
|
||||
SimulatorRuntime()
|
||||
: redirection_(nullptr),
|
||||
lock_(nullptr),
|
||||
lockOwner_(nullptr) {}
|
||||
~SimulatorRuntime();
|
||||
bool init() {
|
||||
lock_ = PR_NewLock();
|
||||
if (!lock_)
|
||||
return false;
|
||||
if (!icache_.init())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
ICacheMap &icache() {
|
||||
MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
|
||||
return icache_;
|
||||
}
|
||||
Redirection *redirection() const {
|
||||
MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
|
||||
return redirection_;
|
||||
}
|
||||
void setRedirection(js::jit::Redirection *redirection) {
|
||||
MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
|
||||
redirection_ = redirection;
|
||||
}
|
||||
};
|
||||
|
||||
class AutoLockSimulatorRuntime
|
||||
{
|
||||
protected:
|
||||
SimulatorRuntime *srt_;
|
||||
|
||||
public:
|
||||
AutoLockSimulatorRuntime(SimulatorRuntime *srt)
|
||||
: srt_(srt) {
|
||||
PR_Lock(srt_->lock_);
|
||||
MOZ_ASSERT(!srt_->lockOwner_);
|
||||
#ifdef DEBUG
|
||||
srt_->lockOwner_ = PR_GetCurrentThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
~AutoLockSimulatorRuntime() {
|
||||
MOZ_ASSERT(srt_->lockOwner_ == PR_GetCurrentThread());
|
||||
srt_->lockOwner_ = nullptr;
|
||||
PR_Unlock(srt_->lock_);
|
||||
}
|
||||
};
|
||||
|
||||
bool Simulator::ICacheCheckingEnabled = false;
|
||||
|
||||
int Simulator::StopSimAt = -1;
|
||||
|
||||
SimulatorRuntime *
|
||||
CreateSimulatorRuntime()
|
||||
Simulator *
|
||||
Simulator::Create()
|
||||
{
|
||||
SimulatorRuntime *srt = js_new<SimulatorRuntime>();
|
||||
if (!srt)
|
||||
Simulator *sim = js_new<Simulator>();
|
||||
if (!sim)
|
||||
return nullptr;
|
||||
|
||||
if (!srt->init()) {
|
||||
js_delete(srt);
|
||||
return nullptr;
|
||||
if (!sim->icache_.init()) {
|
||||
js_delete(sim);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getenv("MIPS_SIM_ICACHE_CHECKS"))
|
||||
|
|
@ -588,13 +512,13 @@ CreateSimulatorRuntime()
|
|||
Simulator::StopSimAt = stopAt;
|
||||
}
|
||||
|
||||
return srt;
|
||||
return sim;
|
||||
}
|
||||
|
||||
void
|
||||
DestroySimulatorRuntime(SimulatorRuntime *srt)
|
||||
Simulator::Destroy(Simulator *sim)
|
||||
{
|
||||
js_delete(srt);
|
||||
js_delete(sim);
|
||||
}
|
||||
|
||||
// The MipsDebugger class is used by the simulator while debugging simulated
|
||||
|
|
@ -1193,9 +1117,9 @@ Simulator::setLastDebuggerInput(char *input)
|
|||
}
|
||||
|
||||
static CachePage *
|
||||
GetCachePage(SimulatorRuntime::ICacheMap &i_cache, void *page)
|
||||
GetCachePage(Simulator::ICacheMap &i_cache, void *page)
|
||||
{
|
||||
SimulatorRuntime::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
|
||||
Simulator::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
|
||||
if (p)
|
||||
return p->value();
|
||||
|
||||
|
|
@ -1207,7 +1131,7 @@ GetCachePage(SimulatorRuntime::ICacheMap &i_cache, void *page)
|
|||
|
||||
// Flush from start up to and not including start + size.
|
||||
static void
|
||||
FlushOnePage(SimulatorRuntime::ICacheMap &i_cache, intptr_t start, int size)
|
||||
FlushOnePage(Simulator::ICacheMap &i_cache, intptr_t start, int size)
|
||||
{
|
||||
MOZ_ASSERT(size <= CachePage::kPageSize);
|
||||
MOZ_ASSERT(AllOnOnePage(start, size - 1));
|
||||
|
|
@ -1221,7 +1145,7 @@ FlushOnePage(SimulatorRuntime::ICacheMap &i_cache, intptr_t start, int size)
|
|||
}
|
||||
|
||||
static void
|
||||
FlushICache(SimulatorRuntime::ICacheMap &i_cache, void *start_addr, size_t size)
|
||||
FlushICache(Simulator::ICacheMap &i_cache, void *start_addr, size_t size)
|
||||
{
|
||||
intptr_t start = reinterpret_cast<intptr_t>(start_addr);
|
||||
int intra_line = (start & CachePage::kLineMask);
|
||||
|
|
@ -1243,7 +1167,7 @@ FlushICache(SimulatorRuntime::ICacheMap &i_cache, void *start_addr, size_t size)
|
|||
}
|
||||
|
||||
static void
|
||||
CheckICache(SimulatorRuntime::ICacheMap &i_cache, SimInstruction *instr)
|
||||
CheckICache(Simulator::ICacheMap &i_cache, SimInstruction *instr)
|
||||
{
|
||||
intptr_t address = reinterpret_cast<intptr_t>(instr);
|
||||
void *page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
|
||||
|
|
@ -1266,13 +1190,13 @@ CheckICache(SimulatorRuntime::ICacheMap &i_cache, SimInstruction *instr)
|
|||
}
|
||||
|
||||
HashNumber
|
||||
SimulatorRuntime::ICacheHasher::hash(const Lookup &l)
|
||||
Simulator::ICacheHasher::hash(const Lookup &l)
|
||||
{
|
||||
return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(l)) >> 2;
|
||||
}
|
||||
|
||||
bool
|
||||
SimulatorRuntime::ICacheHasher::match(const Key &k, const Lookup &l)
|
||||
Simulator::ICacheHasher::match(const Key &k, const Lookup &l)
|
||||
{
|
||||
MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
|
||||
MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
|
||||
|
|
@ -1282,30 +1206,24 @@ SimulatorRuntime::ICacheHasher::match(const Key &k, const Lookup &l)
|
|||
void
|
||||
Simulator::FlushICache(void *start_addr, size_t size)
|
||||
{
|
||||
SimulatorRuntime *srt = TlsPerThreadData.get()->simulatorRuntime();
|
||||
AutoLockSimulatorRuntime alsr(srt);
|
||||
js::jit::FlushICache(srt->icache(), start_addr, size);
|
||||
js::jit::FlushICache(Simulator::Current()->icache(), start_addr, size);
|
||||
}
|
||||
|
||||
Simulator::~Simulator()
|
||||
{
|
||||
js_free(stack_);
|
||||
}
|
||||
|
||||
Simulator::Simulator(SimulatorRuntime *srt)
|
||||
: srt_(srt)
|
||||
Simulator::Simulator()
|
||||
{
|
||||
// Set up simulator support first. Some of this information is needed to
|
||||
// setup the architecture state.
|
||||
|
||||
// Allocate 2MB for the stack. Note that we will only use 1MB, see also
|
||||
// Simulator::stackLimit().
|
||||
// Allocate 2MB for the stack. Note that we will only use 1MB, see below.
|
||||
static const size_t stackSize = 2 * 1024 * 1024;
|
||||
stack_ = static_cast<char*>(js_malloc(stackSize));
|
||||
if (!stack_) {
|
||||
MOZ_ReportAssertionFailure("[unhandlable oom] Simulator stack", __FILE__, __LINE__);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
// Leave a safety margin of 1MB to prevent overrunning the stack when
|
||||
// pushing values (total stack size is 2MB).
|
||||
stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
|
||||
pc_modified_ = false;
|
||||
icount_ = 0;
|
||||
break_count_ = 0;
|
||||
|
|
@ -1336,6 +1254,8 @@ Simulator::Simulator(SimulatorRuntime *srt)
|
|||
exceptions[i] = 0;
|
||||
|
||||
lastDebuggerInput_ = nullptr;
|
||||
|
||||
redirection_ = nullptr;
|
||||
}
|
||||
|
||||
// When the generated code calls an external reference we need to catch that in
|
||||
|
|
@ -1347,18 +1267,18 @@ Simulator::Simulator(SimulatorRuntime *srt)
|
|||
// offset from the swi instruction so the simulator knows what to call.
|
||||
class Redirection
|
||||
{
|
||||
friend class SimulatorRuntime;
|
||||
friend class Simulator;
|
||||
|
||||
Redirection(void* nativeFunction, ABIFunctionType type, SimulatorRuntime *srt)
|
||||
Redirection(void* nativeFunction, ABIFunctionType type, Simulator *sim)
|
||||
: nativeFunction_(nativeFunction),
|
||||
swiInstruction_(kCallRedirInstr),
|
||||
type_(type),
|
||||
next_(nullptr)
|
||||
{
|
||||
next_ = srt->redirection();
|
||||
next_ = sim->redirection();
|
||||
if (Simulator::ICacheCheckingEnabled)
|
||||
FlushICache(srt->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
|
||||
srt->setRedirection(this);
|
||||
FlushICache(sim->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
|
||||
sim->setRedirection(this);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -1367,13 +1287,8 @@ class Redirection
|
|||
ABIFunctionType type() const { return type_; }
|
||||
|
||||
static Redirection *Get(void *nativeFunction, ABIFunctionType type) {
|
||||
PerThreadData *pt = TlsPerThreadData.get();
|
||||
SimulatorRuntime *srt = pt->simulatorRuntime();
|
||||
AutoLockSimulatorRuntime alsr(srt);
|
||||
|
||||
MOZ_ASSERT_IF(pt->simulator(), pt->simulator()->srt_ == srt);
|
||||
|
||||
Redirection *current = srt->redirection();
|
||||
Simulator *sim = Simulator::Current();
|
||||
Redirection *current = sim->redirection();
|
||||
for (; current != nullptr; current = current->next_) {
|
||||
if (current->nativeFunction_ == nativeFunction) {
|
||||
MOZ_ASSERT(current->type() == type);
|
||||
|
|
@ -1387,7 +1302,7 @@ class Redirection
|
|||
__FILE__, __LINE__);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
new(redir) Redirection(nativeFunction, type, srt);
|
||||
new(redir) Redirection(nativeFunction, type, sim);
|
||||
return redir;
|
||||
}
|
||||
|
||||
|
|
@ -1404,6 +1319,17 @@ class Redirection
|
|||
Redirection *next_;
|
||||
};
|
||||
|
||||
Simulator::~Simulator()
|
||||
{
|
||||
js_free(stack_);
|
||||
Redirection *r = redirection_;
|
||||
while (r) {
|
||||
Redirection *next = r->next_;
|
||||
js_delete(r);
|
||||
r = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void *
|
||||
Simulator::RedirectNativeFunction(void *nativeFunction, ABIFunctionType type)
|
||||
{
|
||||
|
|
@ -1411,30 +1337,11 @@ Simulator::RedirectNativeFunction(void *nativeFunction, ABIFunctionType type)
|
|||
return redirection->addressOfSwiInstruction();
|
||||
}
|
||||
|
||||
SimulatorRuntime::~SimulatorRuntime()
|
||||
{
|
||||
Redirection *r = redirection_;
|
||||
while (r) {
|
||||
Redirection *next = r->next_;
|
||||
js_delete(r);
|
||||
r = next;
|
||||
}
|
||||
if (lock_)
|
||||
PR_DestroyLock(lock_);
|
||||
}
|
||||
|
||||
// Get the active Simulator for the current thread.
|
||||
Simulator *
|
||||
Simulator::Current()
|
||||
{
|
||||
PerThreadData *pt = TlsPerThreadData.get();
|
||||
Simulator *sim = pt->simulator();
|
||||
if (!sim) {
|
||||
sim = js_new<Simulator>(pt->simulatorRuntime());
|
||||
pt->setSimulator(sim);
|
||||
}
|
||||
|
||||
return sim;
|
||||
return TlsPerThreadData.get()->simulator();
|
||||
}
|
||||
|
||||
// Sets the register in the architecture state. It will also deal with updating
|
||||
|
|
@ -1808,9 +1715,13 @@ Simulator::writeB(uint32_t addr, int8_t value)
|
|||
uintptr_t
|
||||
Simulator::stackLimit() const
|
||||
{
|
||||
// Leave a safety margin of 1MB to prevent overrunning the stack when
|
||||
// pushing values (total stack size is 2MB).
|
||||
return reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
|
||||
return stackLimit_;
|
||||
}
|
||||
|
||||
uintptr_t *
|
||||
Simulator::addressOfStackLimit()
|
||||
{
|
||||
return &stackLimit_;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -3302,10 +3213,8 @@ Simulator::decodeTypeJump(SimInstruction *instr)
|
|||
void
|
||||
Simulator::instructionDecode(SimInstruction *instr)
|
||||
{
|
||||
if (Simulator::ICacheCheckingEnabled) {
|
||||
AutoLockSimulatorRuntime alsr(srt_);
|
||||
CheckICache(srt_->icache(), instr);
|
||||
}
|
||||
if (Simulator::ICacheCheckingEnabled)
|
||||
CheckICache(icache(), instr);
|
||||
pc_modified_ = false;
|
||||
|
||||
switch (instr->instructionType()) {
|
||||
|
|
@ -3516,40 +3425,9 @@ js::PerThreadData::simulator() const
|
|||
return runtime_->simulator();
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::setSimulator(js::jit::Simulator *sim)
|
||||
{
|
||||
simulator_ = sim;
|
||||
simulatorStackLimit_ = sim->stackLimit();
|
||||
}
|
||||
|
||||
void
|
||||
js::PerThreadData::setSimulator(js::jit::Simulator *sim)
|
||||
{
|
||||
runtime_->setSimulator(sim);
|
||||
}
|
||||
|
||||
uintptr_t *
|
||||
JSRuntime::addressOfSimulatorStackLimit()
|
||||
{
|
||||
return &simulatorStackLimit_;
|
||||
return simulator_->addressOfStackLimit();
|
||||
}
|
||||
|
||||
js::jit::SimulatorRuntime *
|
||||
js::PerThreadData::simulatorRuntime() const
|
||||
{
|
||||
return runtime_->simulatorRuntime();
|
||||
}
|
||||
|
||||
js::jit::SimulatorRuntime *
|
||||
JSRuntime::simulatorRuntime() const
|
||||
{
|
||||
return simulatorRuntime_;
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::setSimulatorRuntime(js::jit::SimulatorRuntime *srt)
|
||||
{
|
||||
MOZ_ASSERT(!simulatorRuntime_);
|
||||
simulatorRuntime_ = srt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@
|
|||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
class SimulatorRuntime;
|
||||
SimulatorRuntime *CreateSimulatorRuntime();
|
||||
void DestroySimulatorRuntime(SimulatorRuntime *srt);
|
||||
class Simulator;
|
||||
class Redirection;
|
||||
class CachePage;
|
||||
|
||||
const intptr_t kPointerAlignment = 4;
|
||||
const intptr_t kPointerAlignmentMask = kPointerAlignment - 1;
|
||||
|
|
@ -137,7 +137,11 @@ class Simulator {
|
|||
kNumFPURegisters
|
||||
};
|
||||
|
||||
explicit Simulator(SimulatorRuntime *srt);
|
||||
static Simulator *Create();
|
||||
static void Destroy(Simulator *simulator);
|
||||
|
||||
// Constructor/destructor are for internal use only; use the static methods above.
|
||||
Simulator();
|
||||
~Simulator();
|
||||
|
||||
// The currently executing Simulator instance. Potentially there can be one
|
||||
|
|
@ -148,6 +152,8 @@ class Simulator {
|
|||
return Simulator::Current()->stackLimit();
|
||||
}
|
||||
|
||||
uintptr_t *addressOfStackLimit();
|
||||
|
||||
// Accessors for register state. Reading the pc value adheres to the MIPS
|
||||
// architecture specification and is off by a 8 from the currently executing
|
||||
// instruction.
|
||||
|
|
@ -315,6 +321,7 @@ class Simulator {
|
|||
|
||||
// Simulator support.
|
||||
char *stack_;
|
||||
uintptr_t stackLimit_;
|
||||
bool pc_modified_;
|
||||
int icount_;
|
||||
int break_count_;
|
||||
|
|
@ -328,8 +335,6 @@ class Simulator {
|
|||
SimInstruction *break_pc_;
|
||||
Instr break_instr_;
|
||||
|
||||
SimulatorRuntime *srt_;
|
||||
|
||||
// A stop is watched if its code is less than kNumOfWatchedStops.
|
||||
// Only watched stops support enabling/disabling and the counter feature.
|
||||
static const uint32_t kNumOfWatchedStops = 256;
|
||||
|
|
@ -347,6 +352,36 @@ class Simulator {
|
|||
char *desc_;
|
||||
};
|
||||
StopCountAndDesc watchedStops_[kNumOfWatchedStops];
|
||||
|
||||
private:
|
||||
Redirection *redirection_;
|
||||
|
||||
// ICache checking.
|
||||
struct ICacheHasher {
|
||||
typedef void *Key;
|
||||
typedef void *Lookup;
|
||||
static HashNumber hash(const Lookup &l);
|
||||
static bool match(const Key &k, const Lookup &l);
|
||||
};
|
||||
|
||||
public:
|
||||
typedef HashMap<void *, CachePage *, ICacheHasher, SystemAllocPolicy> ICacheMap;
|
||||
|
||||
protected:
|
||||
ICacheMap icache_;
|
||||
|
||||
public:
|
||||
ICacheMap &icache() {
|
||||
return icache_;
|
||||
}
|
||||
|
||||
Redirection *redirection() const {
|
||||
return redirection_;
|
||||
}
|
||||
|
||||
void setRedirection(js::jit::Redirection *redirection) {
|
||||
redirection_ = redirection;
|
||||
}
|
||||
};
|
||||
|
||||
#define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror) \
|
||||
|
|
|
|||
|
|
@ -1191,8 +1191,9 @@ ExclusiveContext::stackLimitAddressForJitCode(StackKind kind)
|
|||
{
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
return runtime_->addressOfSimulatorStackLimit();
|
||||
#endif
|
||||
#else
|
||||
return stackLimitAddress(kind);
|
||||
#endif
|
||||
}
|
||||
|
||||
JSVersion
|
||||
|
|
|
|||
|
|
@ -2325,7 +2325,7 @@ struct ArenasToUpdate
|
|||
};
|
||||
ArenasToUpdate(JSRuntime *rt, KindsToUpdate kinds);
|
||||
bool done() { return initialized && arena == nullptr; }
|
||||
ArenaHeader* next();
|
||||
ArenaHeader* next(AutoLockHelperThreadState& lock);
|
||||
ArenaHeader *getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned max);
|
||||
|
||||
private:
|
||||
|
|
@ -2349,7 +2349,7 @@ bool ArenasToUpdate::shouldProcessKind(unsigned kind)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (kind > FINALIZE_OBJECT_LAST || js::gc::IsBackgroundFinalized(AllocKind(kind)))
|
||||
if (js::gc::IsBackgroundFinalized(AllocKind(kind)))
|
||||
return (kinds & BACKGROUND) != 0;
|
||||
else
|
||||
return (kinds & FOREGROUND) != 0;
|
||||
|
|
@ -2362,7 +2362,7 @@ ArenasToUpdate::ArenasToUpdate(JSRuntime *rt, KindsToUpdate kinds)
|
|||
}
|
||||
|
||||
ArenaHeader *
|
||||
ArenasToUpdate::next()
|
||||
ArenasToUpdate::next(AutoLockHelperThreadState& lock)
|
||||
{
|
||||
// Find the next arena to update.
|
||||
//
|
||||
|
|
@ -2407,7 +2407,7 @@ ArenasToUpdate::getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned coun
|
|||
ArenaHeader *tail = nullptr;
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
ArenaHeader *arena = next();
|
||||
ArenaHeader *arena = next(lock);
|
||||
if (!arena)
|
||||
break;
|
||||
|
||||
|
|
@ -2492,31 +2492,46 @@ GCRuntime::updateAllCellPointersParallel(MovingTracer *trc)
|
|||
|
||||
const size_t minTasks = 2;
|
||||
const size_t maxTasks = 8;
|
||||
unsigned taskCount = Min(Max(HelperThreadState().cpuCount / 2, minTasks) + 1,
|
||||
maxTasks);
|
||||
UpdateCellPointersTask updateTasks[maxTasks];
|
||||
size_t targetTaskCount = HelperThreadState().cpuCount / 2;
|
||||
size_t taskCount = Min(Max(targetTaskCount, minTasks), maxTasks);
|
||||
UpdateCellPointersTask bgTasks[maxTasks];
|
||||
UpdateCellPointersTask fgTask;
|
||||
|
||||
ArenasToUpdate fgArenas(rt, ArenasToUpdate::FOREGROUND);
|
||||
ArenasToUpdate bgArenas(rt, ArenasToUpdate::BACKGROUND);
|
||||
AutoLockHelperThreadState lock;
|
||||
unsigned i;
|
||||
for (i = 0; i < taskCount && !bgArenas.done(); ++i) {
|
||||
ArenasToUpdate *source = i == 0 ? &fgArenas : &bgArenas;
|
||||
updateTasks[i].init(rt, source, lock);
|
||||
startTask(updateTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
|
||||
}
|
||||
unsigned tasksStarted = i;
|
||||
|
||||
for (i = 0; i < tasksStarted; ++i)
|
||||
joinTask(updateTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
|
||||
unsigned tasksStarted = 0;
|
||||
{
|
||||
AutoLockHelperThreadState lock;
|
||||
unsigned i;
|
||||
for (i = 0; i < taskCount && !bgArenas.done(); ++i) {
|
||||
bgTasks[i].init(rt, &bgArenas, lock);
|
||||
startTask(bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
|
||||
}
|
||||
tasksStarted = i;
|
||||
|
||||
fgTask.init(rt, &fgArenas, lock);
|
||||
}
|
||||
|
||||
fgTask.runFromMainThread(rt);
|
||||
|
||||
{
|
||||
AutoLockHelperThreadState lock;
|
||||
for (unsigned i = 0; i < tasksStarted; ++i)
|
||||
joinTask(bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::updateAllCellPointersSerial(MovingTracer *trc)
|
||||
{
|
||||
ArenasToUpdate allArenas(rt, ArenasToUpdate::ALL);
|
||||
while (ArenaHeader *arena = allArenas.next())
|
||||
UpdateCellPointers(trc, arena);
|
||||
UpdateCellPointersTask task;
|
||||
{
|
||||
AutoLockHelperThreadState lock;
|
||||
ArenasToUpdate allArenas(rt, ArenasToUpdate::ALL);
|
||||
task.init(rt, &allArenas, lock);
|
||||
}
|
||||
task.runFromMainThread(rt);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -4386,6 +4386,9 @@ JSObject::splicePrototype(JSContext *cx, const Class *clasp, Handle<TaggedProto>
|
|||
/* Inner objects may not appear on prototype chains. */
|
||||
MOZ_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject);
|
||||
|
||||
if (proto.isObject() && !proto.toObject()->setDelegate(cx))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Force type instantiation when splicing lazy types. This may fail,
|
||||
* in which case inference will be disabled for the compartment.
|
||||
|
|
|
|||
|
|
@ -2704,25 +2704,24 @@ bool
|
|||
js::SetClassAndProto(JSContext *cx, HandleObject obj,
|
||||
const Class *clasp, Handle<js::TaggedProto> proto)
|
||||
{
|
||||
/*
|
||||
* Regenerate shapes for all of the scopes along the old prototype chain,
|
||||
* in case any entries were filled by looking up through obj. Stop when a
|
||||
* non-native object is found, prototype lookups will not be cached across
|
||||
* these.
|
||||
*
|
||||
* How this shape change is done is very delicate; the change can be made
|
||||
* either by marking the object's prototype as uncacheable (such that the
|
||||
* property cache and JIT'ed ICs cannot assume the shape determines the
|
||||
* prototype) or by just generating a new shape for the object. Choosing
|
||||
* the former is bad if the object is on the prototype chain of other
|
||||
* objects, as the uncacheable prototype can inhibit iterator caches on
|
||||
* those objects and slow down prototype accesses. Choosing the latter is
|
||||
* bad if there are many similar objects to this one which will have their
|
||||
* prototype mutated, as the generateOwnShape forces the object into
|
||||
* dictionary mode and similar property lineages will be repeatedly cloned.
|
||||
*
|
||||
* :XXX: bug 707717 make this code less brittle.
|
||||
*/
|
||||
// Regenerate the object's shape. If the object is a proto (isDelegate()),
|
||||
// we also need to regenerate shapes for all of the objects along the old
|
||||
// prototype chain, in case any entries were filled by looking up through
|
||||
// obj. Stop when a non-native object is found, prototype lookups will not
|
||||
// be cached across these.
|
||||
//
|
||||
// How this shape change is done is very delicate; the change can be made
|
||||
// either by marking the object's prototype as uncacheable (such that the
|
||||
// JIT'ed ICs cannot assume the shape determines the prototype) or by just
|
||||
// generating a new shape for the object. Choosing the former is bad if the
|
||||
// object is on the prototype chain of other objects, as the uncacheable
|
||||
// prototype can inhibit iterator caches on those objects and slow down
|
||||
// prototype accesses. Choosing the latter is bad if there are many similar
|
||||
// objects to this one which will have their prototype mutated, as the
|
||||
// generateOwnShape forces the object into dictionary mode and similar
|
||||
// property lineages will be repeatedly cloned.
|
||||
//
|
||||
// :XXX: bug 707717 make this code less brittle.
|
||||
RootedObject oldproto(cx, obj);
|
||||
while (oldproto && oldproto->isNative()) {
|
||||
if (oldproto->hasSingletonType()) {
|
||||
|
|
@ -2732,9 +2731,18 @@ js::SetClassAndProto(JSContext *cx, HandleObject obj,
|
|||
if (!oldproto->setUncacheableProto(cx))
|
||||
return false;
|
||||
}
|
||||
if (!obj->isDelegate()) {
|
||||
// If |obj| is not a proto of another object, we don't need to
|
||||
// reshape the whole proto chain.
|
||||
MOZ_ASSERT(obj == oldproto);
|
||||
break;
|
||||
}
|
||||
oldproto = oldproto->getProto();
|
||||
}
|
||||
|
||||
if (proto.isObject() && !proto.toObject()->setDelegate(cx))
|
||||
return false;
|
||||
|
||||
if (obj->hasSingletonType()) {
|
||||
/*
|
||||
* Just splice the prototype, but mark the properties as unknown for
|
||||
|
|
|
|||
|
|
@ -365,7 +365,9 @@ class JSObject : public js::gc::Cell
|
|||
|
||||
JSObject *getProto() const {
|
||||
MOZ_ASSERT(!uninlinedIsProxy());
|
||||
return getTaggedProto().toObjectOrNull();
|
||||
JSObject *proto = getTaggedProto().toObjectOrNull();
|
||||
MOZ_ASSERT_IF(proto && proto->isNative(), proto->isDelegate());
|
||||
return proto;
|
||||
}
|
||||
|
||||
// Normal objects and a subset of proxies have uninteresting [[Prototype]].
|
||||
|
|
|
|||
|
|
@ -158,8 +158,6 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
|
|||
gcInitialized(false),
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
simulator_(nullptr),
|
||||
simulatorStackLimit_(0),
|
||||
simulatorRuntime_(nullptr),
|
||||
#endif
|
||||
scriptAndCountsVector(nullptr),
|
||||
NaNValue(DoubleNaNValue()),
|
||||
|
|
@ -318,8 +316,8 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
|
|||
dateTimeInfo.updateTimeZoneAdjustment();
|
||||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
simulatorRuntime_ = js::jit::CreateSimulatorRuntime();
|
||||
if (!simulatorRuntime_)
|
||||
simulator_ = js::jit::Simulator::Create();
|
||||
if (!simulator_)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
|
|
@ -435,8 +433,7 @@ JSRuntime::~JSRuntime()
|
|||
gc.nursery.disable();
|
||||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
js::jit::DestroySimulatorRuntime(simulatorRuntime_);
|
||||
js_delete(simulator_);
|
||||
js::jit::Simulator::Destroy(simulator_);
|
||||
#endif
|
||||
|
||||
DebugOnly<size_t> oldCount = liveRuntimesCount--;
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ class JitRuntime;
|
|||
class JitActivation;
|
||||
struct PcScriptCache;
|
||||
class Simulator;
|
||||
class SimulatorRuntime;
|
||||
struct AutoFlushICache;
|
||||
class CompileRuntime;
|
||||
}
|
||||
|
|
@ -562,8 +561,6 @@ class PerThreadData : public PerThreadDataFriendFields
|
|||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
js::jit::Simulator *simulator() const;
|
||||
void setSimulator(js::jit::Simulator *sim);
|
||||
js::jit::SimulatorRuntime *simulatorRuntime() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
@ -959,8 +956,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
js::jit::Simulator *simulator_;
|
||||
uintptr_t simulatorStackLimit_;
|
||||
js::jit::SimulatorRuntime *simulatorRuntime_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
|
@ -970,10 +965,7 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
js::jit::Simulator *simulator() const;
|
||||
void setSimulator(js::jit::Simulator *sim);
|
||||
uintptr_t *addressOfSimulatorStackLimit();
|
||||
js::jit::SimulatorRuntime *simulatorRuntime() const;
|
||||
void setSimulatorRuntime(js::jit::SimulatorRuntime *srt);
|
||||
#endif
|
||||
|
||||
/* Strong references on scripts held for PCCount profiling API. */
|
||||
|
|
|
|||
|
|
@ -458,7 +458,8 @@ TouchCaret::IsDisplayable()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!nsLayoutUtils::IsRectVisibleInScrollFrames(focusFrame, focusRect)) {
|
||||
if (mState != TOUCHCARET_TOUCHDRAG_ACTIVE &&
|
||||
!nsLayoutUtils::IsRectVisibleInScrollFrames(focusFrame, focusRect)) {
|
||||
TOUCHCARET_LOG("Caret does not show in the scrollable frame!");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -314,6 +314,8 @@ private:
|
|||
public:
|
||||
explicit RefreshDriverVsyncObserver(VsyncRefreshDriverTimer* aVsyncRefreshDriverTimer)
|
||||
: mVsyncRefreshDriverTimer(aVsyncRefreshDriverTimer)
|
||||
, mRefreshTickLock("RefreshTickLock")
|
||||
, mProcessedVsync(true)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
|
@ -321,6 +323,19 @@ private:
|
|||
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) MOZ_OVERRIDE
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
// Compress vsync notifications such that only 1 may run at a time
|
||||
// This is so that we don't flood the refresh driver with vsync messages
|
||||
// if the main thread is blocked for long periods of time
|
||||
{ // scope lock
|
||||
MonitorAutoLock lock(mRefreshTickLock);
|
||||
mRecentVsync = aVsyncTimestamp;
|
||||
if (!mProcessedVsync) {
|
||||
return true;
|
||||
}
|
||||
mProcessedVsync = false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> vsyncEvent =
|
||||
NS_NewRunnableMethodWithArg<TimeStamp>(this,
|
||||
&RefreshDriverVsyncObserver::TickRefreshDriver,
|
||||
|
|
@ -346,6 +361,12 @@ private:
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
MonitorAutoLock lock(mRefreshTickLock);
|
||||
aVsyncTimestamp = mRecentVsync;
|
||||
mProcessedVsync = true;
|
||||
}
|
||||
|
||||
// We might have a problem that we call ~VsyncRefreshDriverTimer() before
|
||||
// the scheduled TickRefreshDriver() runs. Check mVsyncRefreshDriverTimer
|
||||
// before use.
|
||||
|
|
@ -358,6 +379,9 @@ private:
|
|||
// be always available before Shutdown(). We can just use the raw pointer
|
||||
// here.
|
||||
VsyncRefreshDriverTimer* mVsyncRefreshDriverTimer;
|
||||
Monitor mRefreshTickLock;
|
||||
TimeStamp mRecentVsync;
|
||||
bool mProcessedVsync;
|
||||
}; // RefreshDriverVsyncObserver
|
||||
|
||||
virtual ~VsyncRefreshDriverTimer()
|
||||
|
|
@ -416,9 +440,13 @@ private:
|
|||
Tick(vsyncJsNow, aTimeStamp);
|
||||
}
|
||||
|
||||
nsRefPtr<RefreshTimerVsyncDispatcher> mVsyncDispatcher;
|
||||
nsRefPtr<RefreshDriverVsyncObserver> mVsyncObserver;
|
||||
VsyncChild* mVsyncChild;
|
||||
// Used for parent process.
|
||||
nsRefPtr<RefreshTimerVsyncDispatcher> mVsyncDispatcher;
|
||||
// Used for child process.
|
||||
// The mVsyncChild will be always available before VsncChild::ActorDestroy().
|
||||
// After ActorDestroy(), StartTimer() and StopTimer() calls will be non-op.
|
||||
nsRefPtr<VsyncChild> mVsyncChild;
|
||||
}; // VsyncRefreshDriverTimer
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ async protocol PVsync
|
|||
|
||||
child:
|
||||
// Send vsync event from chrome to content process.
|
||||
async Notify(TimeStamp aVsyncTimestamp);
|
||||
async Notify(TimeStamp aVsyncTimestamp) compress;
|
||||
|
||||
parent:
|
||||
// Content process use these messages to acquire the vsync event.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ namespace layout {
|
|||
|
||||
VsyncChild::VsyncChild()
|
||||
: mObservingVsync(false)
|
||||
, mIsShutdown(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
|
@ -26,9 +27,9 @@ bool
|
|||
VsyncChild::SendObserve()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mObservingVsync) {
|
||||
PVsyncChild::SendObserve();
|
||||
if (!mObservingVsync && !mIsShutdown) {
|
||||
mObservingVsync = true;
|
||||
PVsyncChild::SendObserve();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -37,9 +38,9 @@ bool
|
|||
VsyncChild::SendUnobserve()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mObservingVsync) {
|
||||
PVsyncChild::SendUnobserve();
|
||||
if (mObservingVsync && !mIsShutdown) {
|
||||
mObservingVsync = false;
|
||||
PVsyncChild::SendUnobserve();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -48,6 +49,8 @@ void
|
|||
VsyncChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
mIsShutdown = true;
|
||||
mObserver = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +58,7 @@ bool
|
|||
VsyncChild::RecvNotify(const TimeStamp& aVsyncTimestamp)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
if (mObservingVsync && mObserver) {
|
||||
mObserver->NotifyVsync(aVsyncTimestamp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#define mozilla_layout_ipc_VsyncChild_h
|
||||
|
||||
#include "mozilla/layout/PVsyncChild.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsRefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
|
@ -25,6 +26,8 @@ namespace layout {
|
|||
// PVsyncParent actor dies.
|
||||
class VsyncChild MOZ_FINAL : public PVsyncChild
|
||||
{
|
||||
NS_INLINE_DECL_REFCOUNTING(VsyncChild)
|
||||
|
||||
friend class mozilla::ipc::BackgroundChildImpl;
|
||||
|
||||
public:
|
||||
|
|
@ -44,6 +47,7 @@ private:
|
|||
virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) MOZ_OVERRIDE;
|
||||
|
||||
bool mObservingVsync;
|
||||
bool mIsShutdown;
|
||||
|
||||
// The content side vsync observer.
|
||||
nsRefPtr<VsyncObserver> mObserver;
|
||||
|
|
|
|||
21
layout/reftests/bugs/1127107-1-ref.html
Normal file
21
layout/reftests/bugs/1127107-1-ref.html
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
div.test {
|
||||
/* Author expects this to prevent wrapping, and may add
|
||||
"overflow:hidden;text-overflow:ellipsis" for nice effect: */
|
||||
white-space: nowrap;
|
||||
|
||||
width: 200px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="test">
|
||||
Does this text wrap? Does this text wrap? Does this text wrap?
|
||||
Does this text wrap?
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
28
layout/reftests/bugs/1127107-1a-nowrap.html
Normal file
28
layout/reftests/bugs/1127107-1a-nowrap.html
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
div.test {
|
||||
/* Author expects this to prevent wrapping, and may add
|
||||
"overflow:hidden;text-overflow:ellipsis" for nice effect: */
|
||||
white-space: nowrap;
|
||||
|
||||
/* BUT these (combined) seem to allow wrapping: */
|
||||
-moz-hyphens: auto;
|
||||
-ms-hyphens: auto;
|
||||
-webkit-hyphens: auto;
|
||||
hyphens: auto;
|
||||
word-break: break-all;
|
||||
|
||||
width: 200px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="test">
|
||||
Does this text wrap? Does this text wrap? Does this text wrap?
|
||||
Does this text wrap?
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
25
layout/reftests/bugs/1127107-1b-pre.html
Normal file
25
layout/reftests/bugs/1127107-1b-pre.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
div.test {
|
||||
/* Author expects this to prevent wrapping, and may add
|
||||
"overflow:hidden;text-overflow:ellipsis" for nice effect: */
|
||||
white-space: pre;
|
||||
|
||||
/* BUT these (combined) seem to allow wrapping: */
|
||||
-moz-hyphens: auto;
|
||||
-ms-hyphens: auto;
|
||||
-webkit-hyphens: auto;
|
||||
hyphens: auto;
|
||||
word-break: break-all;
|
||||
|
||||
width: 200px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="test">Does this text wrap? Does this text wrap? Does this text wrap? Does this text wrap?</div>
|
||||
</body>
|
||||
</html>
|
||||
21
layout/reftests/bugs/1127107-2-capitalize-ref.html
Normal file
21
layout/reftests/bugs/1127107-2-capitalize-ref.html
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
div.test {
|
||||
/* Author expects this to prevent wrapping, and may add
|
||||
"overflow:hidden;text-overflow:ellipsis" for nice effect: */
|
||||
white-space: nowrap;
|
||||
|
||||
width: 200px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="test">
|
||||
Does This Text Wrap? Does This Text Wrap? Does This Text Wrap?
|
||||
Does This Text Wrap?
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
25
layout/reftests/bugs/1127107-2-capitalize.html
Normal file
25
layout/reftests/bugs/1127107-2-capitalize.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
div.test {
|
||||
/* Author expects this to prevent wrapping, and may add
|
||||
"overflow:hidden;text-overflow:ellipsis" for nice effect: */
|
||||
white-space: nowrap;
|
||||
|
||||
/* BUT these (combined) seem to allow wrapping: */
|
||||
text-transform: capitalize;
|
||||
word-break: break-all;
|
||||
|
||||
width: 200px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="test">
|
||||
Does this text wrap? Does this text wrap? Does this text wrap?
|
||||
Does this text wrap?
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1858,3 +1858,6 @@ fuzzy-if(d2d,36,304) HTTP(..) == 1116480-1-fakeitalic-overflow.html 1116480-1-fa
|
|||
== 1119117-1b.html 1119117-1-ref.html
|
||||
== 1120431-1.html 1120431-1-ref.html
|
||||
== 1120431-2.html 1120431-2-ref.html
|
||||
== 1127107-1a-nowrap.html 1127107-1-ref.html
|
||||
== 1127107-1b-pre.html 1127107-1-ref.html
|
||||
== 1127107-2-capitalize.html 1127107-2-capitalize-ref.html
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<p>'ab' should be paried with 'xy':</p>
|
||||
|
||||
<p><rbc>ab</rbc><rt>xy</rt></p>
|
||||
<p><rb>ab</rb><rtc>xy</rtc></p>
|
||||
<p><rb>ab</rb><rtc style="letter-spacing: 1px">xy</rtc></p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@
|
|||
<!-- pseudo ruby base -->
|
||||
<p><rbc>a<rb class="remove"></rb>b</rbc><rt>xy</rt></p>
|
||||
<!-- pseudo ruby text -->
|
||||
<p><rb>ab</rb><rtc>x<rt class="remove"></rt>y</rtc></p>
|
||||
<!-- letter-spacing is added here to avoid fuzzy on Windows. See bug 1111891 -->
|
||||
<p><rb>ab</rb><rtc style="letter-spacing: 1px">x<rt class="remove"></rt>y</rtc></p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ fails == autohiding-3.html autohiding-3-ref.html # bug 1107701
|
|||
== dynamic-insertion-3.html dynamic-insertion-3-ref.html
|
||||
== dynamic-removal-1.html dynamic-removal-1-ref.html
|
||||
== dynamic-removal-2.html dynamic-removal-2-ref.html
|
||||
fuzzy-if(winWidget,35,1) == dynamic-removal-3.html dynamic-removal-3-ref.html # bug 1111891
|
||||
== dynamic-removal-3.html dynamic-removal-3-ref.html
|
||||
== float-handling.html float-handling-ref.html
|
||||
== inlinize-blocks-1.html inlinize-blocks-1-ref.html
|
||||
== inlinize-blocks-2.html inlinize-blocks-2-ref.html
|
||||
|
|
|
|||
8
layout/reftests/svg/mask-transformed-child-01-ref.svg
Normal file
8
layout/reftests/svg/mask-transformed-child-01-ref.svg
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="50" y="75" width="100" height="50" fill="blue"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 227 B |
11
layout/reftests/svg/mask-transformed-child-01.svg
Normal file
11
layout/reftests/svg/mask-transformed-child-01.svg
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
|
||||
<rect x="0.25" y="0" width="0.5" height="1" fill="white" transform="rotate(90,0.5,0.5)"/>
|
||||
</mask>
|
||||
<rect x="50" y="50" width="100" height="100" fill="blue" mask="url(#mask)"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 436 B |
|
|
@ -209,6 +209,7 @@ pref(svg.marker-improvements.enabled,true) == marker-orientation-02.svg marker-o
|
|||
== mask-containing-masked-content-01.svg pass.svg
|
||||
== mask-transformed-01.svg mask-transformed-01-ref.svg
|
||||
== mask-transformed-02.svg pass.svg
|
||||
== mask-transformed-child-01.svg mask-transformed-child-01-ref.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d,1,6400) == mask-type-01.svg mask-type-01-ref.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d,1,6400) == mask-type-02.svg mask-type-01-ref.svg
|
||||
pref(layout.css.masking.enabled,true) fuzzy-if(d2d,1,6400) == mask-type-03.svg mask-type-01-ref.svg
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(gfxContext* aContext,
|
|||
m = static_cast<nsSVGElement*>(kid->GetContent())->
|
||||
PrependLocalTransformsTo(m);
|
||||
}
|
||||
nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, mMatrixForChildren);
|
||||
nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m);
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ else:
|
|||
'silk/fixed',
|
||||
]
|
||||
SOURCES += silk_sources_fixed
|
||||
# for webrtc
|
||||
SOURCES += opus_sources_float
|
||||
|
||||
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_AS']:
|
||||
SOURCES += celt_sources_arm
|
||||
|
|
|
|||
|
|
@ -257,7 +257,10 @@ status_t SampleTable::setSampleToChunkParams(
|
|||
return ERROR_IO;
|
||||
}
|
||||
|
||||
CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec.
|
||||
if (!U32_AT(buffer)) {
|
||||
ALOGE("error reading sample to chunk table");
|
||||
return ERROR_MALFORMED; // chunk index is 1 based in the spec.
|
||||
}
|
||||
|
||||
// We want the chunk index to be 0-based.
|
||||
mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ webrtc_non_unified_sources = [
|
|||
'trunk/webrtc/modules/audio_coding/codecs/g722/g722_encode.c', # Because of name clash in the saturate function
|
||||
'trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c', # Because of name clash in the kDampFilter variable
|
||||
'trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c', # Because of name clash in the kDampFilter variable
|
||||
'trunk/webrtc/modules/audio_coding/neteq4/audio_vector.cc', # Because of explicit template specializations
|
||||
'trunk/webrtc/modules/audio_coding/neteq/audio_vector.cc', # Because of explicit template specializations
|
||||
'trunk/webrtc/modules/audio_device/linux/audio_device_pulse_linux.cc', # Because of LATE()
|
||||
'trunk/webrtc/modules/audio_device/linux/audio_mixer_manager_pulse_linux.cc',# Because of LATE()
|
||||
'trunk/webrtc/modules/audio_device/opensl/opensles_input.cc', # Because of name clash in the kOption variable
|
||||
|
|
|
|||
|
|
@ -51,10 +51,6 @@
|
|||
'../../../dom/media',
|
||||
'../../../media/mtransport',
|
||||
'../trunk',
|
||||
'../trunk/webrtc',
|
||||
'../trunk/webrtc/video_engine/include',
|
||||
'../trunk/webrtc/voice_engine/include',
|
||||
'../trunk/webrtc/modules/interface',
|
||||
'../../libyuv/include',
|
||||
'../../mtransport/third_party/nrappkit/src/util/libekr',
|
||||
],
|
||||
|
|
@ -209,7 +205,6 @@
|
|||
],
|
||||
'include_dirs': [
|
||||
# hack on hack to re-add it after SrtpFlow removes it
|
||||
'../../webrtc/trunk/webrtc',
|
||||
'../../../dom/media/omx',
|
||||
'../../../gfx/layers/client',
|
||||
],
|
||||
|
|
@ -250,6 +245,7 @@
|
|||
'defines': [
|
||||
'OS_LINUX',
|
||||
'SIP_OS_LINUX',
|
||||
'WEBRTC_POSIX',
|
||||
'_GNU_SOURCE',
|
||||
'LINUX',
|
||||
'GIPS_VER=3510',
|
||||
|
|
@ -286,6 +282,7 @@
|
|||
],
|
||||
'defines': [
|
||||
# avoiding pointless ifdef churn
|
||||
'WEBRTC_POSIX',
|
||||
'SIP_OS_OSX',
|
||||
'OSX',
|
||||
'SECLIB_OPENSSL',
|
||||
|
|
@ -298,6 +295,7 @@
|
|||
'include_dirs': [
|
||||
],
|
||||
'defines': [
|
||||
'WEBRTC_POSIX',
|
||||
'OS_MACOSX',
|
||||
'SIP_OS_OSX',
|
||||
'OSX',
|
||||
|
|
|
|||
|
|
@ -544,9 +544,9 @@ WebrtcAudioConduit::EnableAudioLevelExtension(bool enabled, uint8_t id)
|
|||
{
|
||||
CSFLogDebug(logTag, "%s %d %d ", __FUNCTION__, enabled, id);
|
||||
|
||||
if (mPtrVoERTP_RTCP->SetRTPAudioLevelIndicationStatus(mChannel, enabled, id) == -1)
|
||||
if (mPtrVoERTP_RTCP->SetSendAudioLevelIndicationStatus(mChannel, enabled, id) == -1)
|
||||
{
|
||||
CSFLogError(logTag, "%s SetRTPAudioLevelIndicationStatus Failed", __FUNCTION__);
|
||||
CSFLogError(logTag, "%s SetSendAudioLevelIndicationStatus Failed", __FUNCTION__);
|
||||
return kMediaConduitUnknownError;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -234,7 +234,8 @@ public:
|
|||
* return: Concrete VideoSessionConduitObject or nullptr in the case
|
||||
* of failure
|
||||
*/
|
||||
static RefPtr<VideoSessionConduit> Create(VideoSessionConduit *aOther);
|
||||
static RefPtr<VideoSessionConduit> Create(VideoSessionConduit *aOther,
|
||||
bool receiving);
|
||||
|
||||
enum FrameRequestType
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,13 +42,15 @@ const unsigned int WebrtcVideoConduit::CODEC_PLNAME_SIZE = 32;
|
|||
/**
|
||||
* Factory Method for VideoConduit
|
||||
*/
|
||||
mozilla::RefPtr<VideoSessionConduit> VideoSessionConduit::Create(VideoSessionConduit *aOther)
|
||||
mozilla::RefPtr<VideoSessionConduit>
|
||||
VideoSessionConduit::Create(VideoSessionConduit *aOther,
|
||||
bool receiving)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
CSFLogDebug(logTag, "%s ", __FUNCTION__);
|
||||
|
||||
WebrtcVideoConduit* obj = new WebrtcVideoConduit();
|
||||
if(obj->Init(static_cast<WebrtcVideoConduit*>(aOther)) != kMediaConduitNoError)
|
||||
if(obj->Init(static_cast<WebrtcVideoConduit*>(aOther), receiving) != kMediaConduitNoError)
|
||||
{
|
||||
CSFLogError(logTag, "%s VideoConduit Init Failed ", __FUNCTION__);
|
||||
delete obj;
|
||||
|
|
@ -284,7 +286,9 @@ bool WebrtcVideoConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
|
|||
/**
|
||||
* Performs initialization of the MANDATORY components of the Video Engine
|
||||
*/
|
||||
MediaConduitErrorCode WebrtcVideoConduit::Init(WebrtcVideoConduit *other)
|
||||
MediaConduitErrorCode
|
||||
WebrtcVideoConduit::Init(WebrtcVideoConduit *other,
|
||||
bool receiving)
|
||||
{
|
||||
CSFLogDebug(logTag, "%s this=%p other=%p", __FUNCTION__, this, other);
|
||||
|
||||
|
|
@ -332,7 +336,6 @@ MediaConduitErrorCode WebrtcVideoConduit::Init(WebrtcVideoConduit *other)
|
|||
MOZ_ASSERT(other->mVideoEngine);
|
||||
mVideoEngine = other->mVideoEngine;
|
||||
} else {
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// get the JVM
|
||||
JavaVM *jvm = jsjni_GetVM();
|
||||
|
|
@ -344,7 +347,8 @@ MediaConduitErrorCode WebrtcVideoConduit::Init(WebrtcVideoConduit *other)
|
|||
#endif
|
||||
|
||||
// Per WebRTC APIs below function calls return nullptr on failure
|
||||
if( !(mVideoEngine = webrtc::VideoEngine::Create()) )
|
||||
mVideoEngine = webrtc::VideoEngine::Create();
|
||||
if(!mVideoEngine)
|
||||
{
|
||||
CSFLogError(logTag, "%s Unable to create video engine ", __FUNCTION__);
|
||||
return kMediaConduitSessionNotInited;
|
||||
|
|
@ -445,14 +449,6 @@ MediaConduitErrorCode WebrtcVideoConduit::Init(WebrtcVideoConduit *other)
|
|||
__FUNCTION__,mPtrViEBase->LastError());
|
||||
return kMediaConduitCaptureError;
|
||||
}
|
||||
|
||||
if(mPtrViERender->AddRenderer(mChannel,
|
||||
webrtc::kVideoI420,
|
||||
(webrtc::ExternalRenderer*) this) == -1)
|
||||
{
|
||||
CSFLogError(logTag, "%s Failed to added external renderer ", __FUNCTION__);
|
||||
return kMediaConduitInvalidRenderer;
|
||||
}
|
||||
// Set up some parameters, per juberti. Set MTU.
|
||||
if(mPtrViENetwork->SetMTU(mChannel, 1200) != 0)
|
||||
{
|
||||
|
|
@ -469,6 +465,15 @@ MediaConduitErrorCode WebrtcVideoConduit::Init(WebrtcVideoConduit *other)
|
|||
}
|
||||
}
|
||||
|
||||
if (receiving) {
|
||||
if (mPtrViERender->AddRenderer(mChannel,
|
||||
webrtc::kVideoI420,
|
||||
(webrtc::ExternalRenderer*) this) == -1) {
|
||||
CSFLogError(logTag, "%s Failed to added external renderer ", __FUNCTION__);
|
||||
return kMediaConduitInvalidRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
CSFLogError(logTag, "%s Initialization Done", __FUNCTION__);
|
||||
return kMediaConduitNoError;
|
||||
}
|
||||
|
|
@ -1238,6 +1243,7 @@ int
|
|||
WebrtcVideoConduit::DeliverFrame(unsigned char* buffer,
|
||||
int buffer_size,
|
||||
uint32_t time_stamp,
|
||||
int64_t ntp_time_ms,
|
||||
int64_t render_time,
|
||||
void *handle)
|
||||
{
|
||||
|
|
@ -1318,7 +1324,8 @@ WebrtcVideoConduit::CodecConfigToWebRTCCodec(const VideoCodecConfig* codecInfo,
|
|||
#ifdef MOZ_WEBRTC_OMX
|
||||
cinst.resolution_divisor = 16;
|
||||
#endif
|
||||
cinst.codecSpecific.H264.profile = codecInfo->mProfile;
|
||||
// cinst.codecSpecific.H264.profile = ?
|
||||
cinst.codecSpecific.H264.profile_byte = codecInfo->mProfile;
|
||||
cinst.codecSpecific.H264.constraints = codecInfo->mConstraints;
|
||||
cinst.codecSpecific.H264.level = codecInfo->mLevel;
|
||||
cinst.codecSpecific.H264.packetizationMode = codecInfo->mPacketizationMode;
|
||||
|
|
|
|||
|
|
@ -182,8 +182,8 @@ public:
|
|||
*/
|
||||
virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int) MOZ_OVERRIDE;
|
||||
|
||||
virtual int DeliverFrame(unsigned char*,int, uint32_t , int64_t,
|
||||
void *handle) MOZ_OVERRIDE;
|
||||
virtual int DeliverFrame(unsigned char*, int, uint32_t , int64_t,
|
||||
int64_t, void *handle) MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Does DeliverFrame() support a null buffer and non-null handle
|
||||
|
|
@ -226,7 +226,8 @@ public:
|
|||
WebrtcVideoConduit();
|
||||
virtual ~WebrtcVideoConduit();
|
||||
|
||||
MediaConduitErrorCode Init(WebrtcVideoConduit *other);
|
||||
MediaConduitErrorCode Init(WebrtcVideoConduit *other,
|
||||
bool receiving);
|
||||
|
||||
int GetChannel() { return mChannel; }
|
||||
webrtc::VideoEngine* GetVideoEngine() { return mVideoEngine; }
|
||||
|
|
|
|||
|
|
@ -446,6 +446,11 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
|||
return;
|
||||
}
|
||||
|
||||
struct nal_entry {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
};
|
||||
nsTArray<nal_entry> nals;
|
||||
uint32_t size;
|
||||
// make sure we don't read past the end of the buffer getting the size
|
||||
while (buffer+size_bytes < end) {
|
||||
|
|
@ -484,13 +489,9 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
|||
buffer+size - end));
|
||||
return;
|
||||
}
|
||||
webrtc::EncodedImage unit(buffer, size, size);
|
||||
unit._frameType = ft;
|
||||
unit._timeStamp = timestamp;
|
||||
unit._completeFrame = true;
|
||||
|
||||
mCallback->Encoded(unit, nullptr, nullptr);
|
||||
|
||||
// XXX optimize by making buffer an offset
|
||||
nal_entry nal = {((uint32_t) (buffer-aEncodedFrame->Buffer())), (uint32_t) size};
|
||||
nals.AppendElement(nal);
|
||||
buffer += size;
|
||||
// on last one, buffer == end normally
|
||||
}
|
||||
|
|
@ -498,6 +499,24 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
|||
// At most 3 bytes can be left over, depending on buffertype
|
||||
LOGD(("GMP plugin returned %td extra bytes", end - buffer));
|
||||
}
|
||||
|
||||
size_t num_nals = nals.Length();
|
||||
if (num_nals > 0) {
|
||||
webrtc::RTPFragmentationHeader fragmentation;
|
||||
fragmentation.VerifyAndAllocateFragmentationHeader(num_nals);
|
||||
for (size_t i = 0; i < num_nals; i++) {
|
||||
fragmentation.fragmentationOffset[i] = nals[i].offset;
|
||||
fragmentation.fragmentationLength[i] = nals[i].size;
|
||||
}
|
||||
|
||||
webrtc::EncodedImage unit(aEncodedFrame->Buffer(), size, size);
|
||||
unit._frameType = ft;
|
||||
unit._timeStamp = timestamp;
|
||||
unit._completeFrame = true;
|
||||
|
||||
mCallback->Encoded(unit, nullptr, &fragmentation);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
using namespace android;
|
||||
|
||||
// WebRTC
|
||||
#include "common_video/interface/texture_video_frame.h"
|
||||
#include "video_engine/include/vie_external_codec.h"
|
||||
#include "webrtc/common_video/interface/texture_video_frame.h"
|
||||
#include "webrtc/video_engine/include/vie_external_codec.h"
|
||||
#include "runnable_utils.h"
|
||||
|
||||
// Gecko
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
// Original author: ekr@rtfm.com
|
||||
|
||||
#include "logging.h"
|
||||
#include "MediaPipeline.h"
|
||||
|
||||
#ifndef USE_FAKE_MEDIA_STREAMS
|
||||
|
|
@ -45,8 +44,7 @@
|
|||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
|
||||
#include "logging.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
|
|
|||
|
|
@ -608,7 +608,7 @@ MediaPipelineFactory::CreateVideoConduit(const JsepTrackPair& aTrackPair,
|
|||
// The two sides of a send/receive pair of conduits each keep a raw
|
||||
// pointer to the other, and are responsible for cleanly shutting down.
|
||||
RefPtr<VideoSessionConduit> conduit = VideoSessionConduit::Create(
|
||||
static_cast<VideoSessionConduit*>(peerConduit.get()));
|
||||
static_cast<VideoSessionConduit*>(peerConduit.get()), receiving);
|
||||
|
||||
if (!conduit) {
|
||||
MOZ_MTLOG(ML_ERROR, "Could not create video conduit");
|
||||
|
|
|
|||
|
|
@ -318,9 +318,6 @@ nsresult PeerConnectionMedia::UpdateMediaPipelines(
|
|||
return rv;
|
||||
}
|
||||
|
||||
// TODO(bug 1099318): We are forced to do receive then transmit, because of
|
||||
// a bug in the VideoConduit code. This will need to be fixed for
|
||||
// renegotiation.
|
||||
if (pair->mReceiving) {
|
||||
rv = factory.CreateMediaPipeline(*pair, *pair->mReceiving);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
|||
|
|
@ -595,6 +595,7 @@ class TransportConduitTest : public ::testing::Test
|
|||
WrapRunnableNMRet(
|
||||
&mozilla::VideoSessionConduit::Create,
|
||||
nullptr,
|
||||
false,
|
||||
&mVideoSession));
|
||||
if( !mVideoSession )
|
||||
ASSERT_NE(mVideoSession, (void*)nullptr);
|
||||
|
|
@ -604,6 +605,7 @@ class TransportConduitTest : public ::testing::Test
|
|||
WrapRunnableNMRet(
|
||||
&mozilla::VideoSessionConduit::Create,
|
||||
nullptr,
|
||||
true,
|
||||
&mVideoSession2));
|
||||
if( !mVideoSession2 )
|
||||
ASSERT_NE(mVideoSession2,(void*)nullptr);
|
||||
|
|
@ -695,6 +697,7 @@ class TransportConduitTest : public ::testing::Test
|
|||
WrapRunnableNMRet(
|
||||
&mozilla::VideoSessionConduit::Create,
|
||||
nullptr,
|
||||
true,
|
||||
&videoSession));
|
||||
if( !videoSession )
|
||||
ASSERT_NE(videoSession, (void*)nullptr);
|
||||
|
|
@ -807,6 +810,7 @@ class TransportConduitTest : public ::testing::Test
|
|||
WrapRunnableNMRet(
|
||||
&mozilla::VideoSessionConduit::Create,
|
||||
nullptr,
|
||||
false,
|
||||
&mVideoSession));
|
||||
if( !mVideoSession )
|
||||
ASSERT_NE(mVideoSession, (void*)nullptr);
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
# This file is generated by gyp; do not edit.
|
||||
|
||||
export builddir_name ?= trunk/base/out
|
||||
.PHONY: all
|
||||
all:
|
||||
$(MAKE) -C .. base
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
# Below are normally provided by Chromium's base.gyp and required for
|
||||
# libjingle.gyp.
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'base',
|
||||
'type': 'none',
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'..',
|
||||
],
|
||||
},
|
||||
'conditions': [
|
||||
['OS == "linux"', {
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
# We need rt for clock_gettime() used in libjingle.
|
||||
'-lrt',
|
||||
],
|
||||
},
|
||||
}],
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# This file is generated by gyp; do not edit.
|
||||
|
||||
TOOLSET := target
|
||||
TARGET := base
|
||||
### Rules for final target.
|
||||
$(obj).target/base/base.stamp: TOOLSET := $(TOOLSET)
|
||||
$(obj).target/base/base.stamp: FORCE_DO_CMD
|
||||
$(call do_cmd,touch)
|
||||
|
||||
all_deps += $(obj).target/base/base.stamp
|
||||
# Add target alias
|
||||
.PHONY: base
|
||||
base: $(obj).target/base/base.stamp
|
||||
|
||||
# Add target alias to "all" target.
|
||||
.PHONY: all
|
||||
all: base
|
||||
|
||||
|
|
@ -35,8 +35,10 @@
|
|||
'dependencies': [
|
||||
'webrtc/modules/modules.gyp:audio_device',
|
||||
'webrtc/modules/modules.gyp:video_capture_module',
|
||||
# 'webrtc/modules/modules.gyp:video_render_module',
|
||||
'webrtc/modules/modules.gyp:video_capture_module_internal_impl',
|
||||
'webrtc/modules/modules.gyp:video_render_module_impl',
|
||||
# 'webrtc/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||
# 'webrtc/system_wrappers/source/system_wrappers.gyp:metrics_default',
|
||||
'webrtc/video_engine/video_engine.gyp:video_engine_core',
|
||||
'webrtc/voice_engine/voice_engine.gyp:voice_engine',
|
||||
],
|
||||
|
|
|
|||
245
media/webrtc/trunk/webrtc/BUILD.gn
Normal file
245
media/webrtc/trunk/webrtc/BUILD.gn
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
# TODO(kjellander): Rebase this to webrtc/build/common.gypi changes after r6330.
|
||||
|
||||
import("//build/config/arm.gni")
|
||||
import("//build/config/crypto.gni")
|
||||
import("//build/config/linux/pkg_config.gni")
|
||||
import("build/webrtc.gni")
|
||||
|
||||
# Contains the defines and includes in common.gypi that are duplicated both as
|
||||
# target_defaults and direct_dependent_settings.
|
||||
config("common_inherited_config") {
|
||||
defines = []
|
||||
if (build_with_mozilla) {
|
||||
defines += [ "WEBRTC_MOZILLA_BUILD" ]
|
||||
}
|
||||
if (build_with_chromium) {
|
||||
defines = [
|
||||
"WEBRTC_CHROMIUM_BUILD",
|
||||
]
|
||||
include_dirs = [
|
||||
# overrides must be included first as that is the mechanism for
|
||||
# selecting the override headers in Chromium.
|
||||
"overrides",
|
||||
# Allow includes to be prefixed with webrtc/ in case it is not an
|
||||
# immediate subdirectory of the top-level.
|
||||
"..",
|
||||
]
|
||||
}
|
||||
if (is_posix) {
|
||||
defines += [ "WEBRTC_POSIX" ]
|
||||
}
|
||||
if (is_ios) {
|
||||
defines += [
|
||||
"WEBRTC_MAC",
|
||||
"WEBRTC_IOS",
|
||||
]
|
||||
}
|
||||
if (is_linux) {
|
||||
defines += [ "WEBRTC_LINUX" ]
|
||||
}
|
||||
if (is_mac) {
|
||||
defines += [ "WEBRTC_MAC" ]
|
||||
}
|
||||
if (is_win) {
|
||||
defines += [ "WEBRTC_WIN" ]
|
||||
}
|
||||
if (is_android) {
|
||||
defines += [
|
||||
"WEBRTC_LINUX",
|
||||
"WEBRTC_ANDROID",
|
||||
]
|
||||
if (rtc_enable_android_opensl) {
|
||||
defines += [ "WEBRTC_ANDROID_OPENSLES" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rtc_have_dbus_glib) {
|
||||
pkg_config("dbus-glib") {
|
||||
packages = [ "dbus-glib-1" ]
|
||||
}
|
||||
}
|
||||
|
||||
config("common_config") {
|
||||
cflags = []
|
||||
cflags_cc = []
|
||||
if (rtc_restrict_logging) {
|
||||
defines = [ "WEBRTC_RESTRICT_LOGGING" ]
|
||||
}
|
||||
|
||||
if (rtc_have_dbus_glib) {
|
||||
defines += [ "HAVE_DBUS_GLIB" ]
|
||||
# TODO(kjellander): Investigate this, it seems like include <dbus/dbus.h>
|
||||
# is still not found even if the execution of
|
||||
# build/config/linux/pkg-config.py dbus-glib-1 returns correct include
|
||||
# dirs on Linux.
|
||||
all_dependent_configs = [ "dbus-glib" ]
|
||||
}
|
||||
|
||||
if (rtc_enable_video) {
|
||||
defines += [ "WEBRTC_MODULE_UTILITY_VIDEO" ]
|
||||
}
|
||||
|
||||
if (build_with_chromium) {
|
||||
defines += [ "LOGGING_INSIDE_WEBRTC" ]
|
||||
} else {
|
||||
if (is_posix) {
|
||||
# -Wextra is currently disabled in Chromium"s common.gypi. Enable
|
||||
# for targets that can handle it. For Android/arm64 right now
|
||||
# there will be an "enumeral and non-enumeral type in conditional
|
||||
# expression" warning in android_tools/ndk_experimental"s version
|
||||
# of stlport.
|
||||
# See: https://code.google.com/p/chromium/issues/detail?id=379699
|
||||
if (cpu_arch != "arm64" || !is_android) {
|
||||
cflags = [
|
||||
"-Wextra",
|
||||
# We need to repeat some flags from Chromium"s common.gypi
|
||||
# here that get overridden by -Wextra.
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-missing-field-initializers",
|
||||
"-Wno-strict-overflow",
|
||||
]
|
||||
cflags_cc = [
|
||||
"-Wnon-virtual-dtor",
|
||||
# This is enabled for clang; enable for gcc as well.
|
||||
"-Woverloaded-virtual",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (is_clang) {
|
||||
cflags += [ "-Wthread-safety" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (cpu_arch == "arm64") {
|
||||
defines += [ "WEBRTC_ARCH_ARM" ]
|
||||
}
|
||||
|
||||
if (cpu_arch == "arm") {
|
||||
defines += [ "WEBRTC_ARCH_ARM" ]
|
||||
if (arm_version == 7) {
|
||||
defines += [ "WEBRTC_ARCH_ARM_V7" ]
|
||||
if (arm_use_neon) {
|
||||
defines += [ "WEBRTC_ARCH_ARM_NEON" ]
|
||||
} else {
|
||||
defines += [ "WEBRTC_DETECT_ARM_NEON" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cpu_arch == "mipsel") {
|
||||
defines += [ "MIPS32_LE" ]
|
||||
if (mips_fpu) {
|
||||
defines += [ "MIPS_FPU_LE" ]
|
||||
cflags += [ "-mhard-float" ]
|
||||
} else {
|
||||
cflags += [ "-msoft-float" ]
|
||||
}
|
||||
if (mips_arch_variant == "mips32r2") {
|
||||
defines += [ "MIPS32_R2_LE" ]
|
||||
cflags += [ "-mips32r2" ]
|
||||
cflags_cc += [ "-mips32r2" ]
|
||||
}
|
||||
if (mips_dsp_rev == 1) {
|
||||
defines += [ "MIPS_DSP_R1_LE" ]
|
||||
cflags += [ "-mdsp" ]
|
||||
cflags_cc += [ "-mdsp" ]
|
||||
} else if (mips_dsp_rev == 2) {
|
||||
defines += [
|
||||
"MIPS_DSP_R1_LE",
|
||||
"MIPS_DSP_R2_LE",
|
||||
]
|
||||
cflags += [ "-mdspr2" ]
|
||||
cflags_cc += [ "-mdspr2" ]
|
||||
}
|
||||
}
|
||||
|
||||
# TODO(kjellander): Handle warnings on Windows where WebRTC differ from the
|
||||
# default warnings set in build/config/compiler/BUILD.gn.
|
||||
|
||||
if (is_android && is_clang) {
|
||||
# The Android NDK doesn"t provide optimized versions of these
|
||||
# functions. Ensure they are disabled for all compilers.
|
||||
cflags += [
|
||||
"-fno-builtin-cos",
|
||||
"-fno-builtin-sin",
|
||||
"-fno-builtin-cosf",
|
||||
"-fno-builtin-sinf",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
static_library("webrtc") {
|
||||
sources = [
|
||||
"call.h",
|
||||
"config.h",
|
||||
"experiments.h",
|
||||
"frame_callback.h",
|
||||
"transport.h",
|
||||
]
|
||||
|
||||
configs += [ ":common_config" ]
|
||||
public_configs = [ ":common_inherited_config"]
|
||||
|
||||
deps = [
|
||||
":webrtc_common",
|
||||
"base:webrtc_base",
|
||||
"common_audio",
|
||||
"common_video",
|
||||
"modules/audio_coding",
|
||||
"modules/audio_conference_mixer",
|
||||
"modules/audio_device",
|
||||
"modules/audio_processing",
|
||||
"modules/bitrate_controller",
|
||||
"modules/desktop_capture",
|
||||
"modules/media_file",
|
||||
"modules/rtp_rtcp",
|
||||
"modules/utility",
|
||||
"modules/video_capture",
|
||||
"modules/video_coding",
|
||||
"modules/video_processing",
|
||||
"modules/video_render",
|
||||
"system_wrappers",
|
||||
"tools",
|
||||
"video",
|
||||
"video_engine",
|
||||
"voice_engine",
|
||||
]
|
||||
}
|
||||
|
||||
if (!build_with_chromium) {
|
||||
executable("webrtc_tests") {
|
||||
testonly = true
|
||||
deps = [
|
||||
":webrtc",
|
||||
"modules/video_render:video_render_internal_impl",
|
||||
"modules/video_capture:video_capture_internal_impl",
|
||||
"test",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
source_set("webrtc_common") {
|
||||
sources = [
|
||||
"config.h",
|
||||
"config.cc",
|
||||
]
|
||||
|
||||
if (is_clang) {
|
||||
# Suppress warnings from Chrome's Clang plugins.
|
||||
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
|
||||
configs -= [ "//build/config/clang:find_bad_constructs" ]
|
||||
}
|
||||
|
||||
configs += [ ":common_config" ]
|
||||
public_configs = [ ":common_inherited_config" ]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue