Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-01-30 12:22:33 -05:00
commit 175de6b258
2640 changed files with 171341 additions and 95644 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -62,6 +62,13 @@ public:
return mInternalResponse->GetStatus();
}
bool
Ok() const
{
return mInternalResponse->GetStatus() >= 200 &&
mInternalResponse->GetStatus() <= 299;
}
void
GetStatusText(nsCString& aStatusText) const
{

View file

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

View file

@ -533,6 +533,7 @@ public:
mIsCasting = aShow;
}
already_AddRefed<MediaSource> GetMozMediaSourceObject() const;
already_AddRefed<DOMMediaStream> GetMozSrcObject() const;
void SetMozSrcObject(DOMMediaStream& aValue);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -540,6 +540,12 @@ MediaSource::Dump(const char* aPath)
}
#endif
void
MediaSource::GetMozDebugReaderData(nsAString& aString)
{
mDecoder->GetMozDebugReaderData(aString);
}
nsPIDOMWindow*
MediaSource::GetParentObject() const
{

View file

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

View file

@ -290,6 +290,12 @@ MediaSourceDecoder::PrepareReaderInitialization()
mReader->PrepareInitialization();
}
void
MediaSourceDecoder::GetMozDebugReaderData(nsAString& aString)
{
mReader->GetMozDebugReaderData(aString);
}
#ifdef MOZ_EME
nsresult
MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -35,4 +35,6 @@ interface MediaSource : EventTarget {
[Throws]
void endOfStream(optional MediaSourceEndOfStreamError error);
static boolean isTypeSupported(DOMString type);
[ChromeOnly]
readonly attribute DOMString mozDebugReaderData;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

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

View file

@ -0,0 +1,9 @@
// |jit-test| error:SyntaxError
(function() {
with ({}) {}
function f() {
({ *h(){} })
}
function f
})()

View file

@ -0,0 +1,5 @@
var o = {};
gczeal(14);
for (var i = 0; i < 200; i++) {
with (o) { }
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

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

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

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

View file

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

View file

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

View file

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

View file

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

View 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

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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