Merge m-c to b2g-inbound.

This commit is contained in:
Ryan VanderMeulen 2013-08-13 15:38:58 -04:00
commit 3364547f5d
152 changed files with 10235 additions and 8996 deletions

View File

@ -257,7 +257,6 @@ pref("layers.async-pan-zoom.enabled", true);
pref("notification.feature.enabled", true);
// IndexedDB
pref("indexedDB.feature.enabled", true);
pref("dom.indexedDB.warningQuota", 5);
// prevent video elements from preloading too much data

View File

@ -205,12 +205,12 @@ ifeq ($(OS_ARCH),WINNT)
cat $< $(srcdir)/../installer/windows/nsis/updater_append.ini | \
sed -e "s/^InfoText=/Info=/" -e "s/^TitleText=/Title=/" | \
sed -e "s/%MOZ_APP_DISPLAYNAME%/$(MOZ_APP_DISPLAYNAME)/" > \
$(DIST)/bin/updater.ini
$(FINAL_TARGET)/../updater.ini
else
cat $< | \
sed -e "s/^InfoText=/Info=/" -e "s/^TitleText=/Title=/" | \
sed -e "s/%MOZ_APP_DISPLAYNAME%/$(MOZ_APP_DISPLAYNAME)/" > \
$(DIST)/bin/updater.ini
$(FINAL_TARGET)/../updater.ini
endif
endif

View File

@ -1,7 +1,4 @@
toolkit/library
dom
ipc
security/sandbox
ipc
netwerk/build
netwerk

View File

@ -1255,11 +1255,6 @@ if test "$GNU_CC"; then
fi
fi
WARNINGS_AS_ERRORS='-Werror'
# Don't treat -Wuninitialized as error b/c it has lots of false positives.
WARNINGS_AS_ERRORS="$WARNINGS_AS_ERRORS -Wno-error=uninitialized"
# Don't treat -Wdeprecated-declarations as error b/c we don't want our
# builds held hostage when a platform-specific API is suddenly deprecated.
WARNINGS_AS_ERRORS="$WARNINGS_AS_ERRORS -Wno-error=deprecated-declarations"
DSO_CFLAGS=''
DSO_PIC_CFLAGS='-fPIC'
ASFLAGS="$ASFLAGS -fPIC"
@ -4151,6 +4146,7 @@ MOZ_SAMPLE_TYPE_S16=
MOZ_OPUS=1
MOZ_WEBM=1
MOZ_DASH=
MOZ_DIRECTSHOW=
MOZ_WMF=
MOZ_WEBRTC=1
MOZ_PEERCONNECTION=
@ -4212,8 +4208,6 @@ MOZ_TIME_MANAGER=
MOZ_PAY=
MOZ_AUDIO_CHANNEL_MANAGER=
NSS_NO_LIBPKIX=
MOZ_CONTENT_SANDBOX=
MOZ_CONTENT_SANDBOX_REPORTER=
case "$target_os" in
mingw*)
@ -5432,6 +5426,24 @@ if test -n "$MOZ_WEBM"; then
MOZ_VP8=1
fi;
dnl ========================================================
dnl = DirectShow support
dnl ========================================================
if test "$OS_ARCH" = "WINNT"; then
dnl Enable DirectShow support by default.
MOZ_DIRECTSHOW=1
fi
MOZ_ARG_DISABLE_BOOL(directshow,
[ --disable-directshow Disable support for DirectShow],
MOZ_DIRECTSHOW=,
MOZ_DIRECTSHOW=1)
if test -n "$MOZ_DIRECTSHOW"; then
AC_DEFINE(MOZ_DIRECTSHOW)
MOZ_CUBEB=1
fi;
dnl ========================================================
dnl = Windows Media Foundation support
dnl ========================================================
@ -6479,32 +6491,6 @@ if test -n "$NSS_NO_LIBPKIX"; then
fi
AC_SUBST(NSS_NO_LIBPKIX)
dnl ========================================================
dnl = Content process sandboxing
dnl ========================================================
if test -n "$gonkdir"; then
MOZ_CONTENT_SANDBOX=1
fi
MOZ_ARG_ENABLE_BOOL(content-sandbox,
[ --enable-content-sandbox Enable sandboxing support for content-processes],
MOZ_CONTENT_SANDBOX=1)
if test -n "$MOZ_CONTENT_SANDBOX"; then
AC_DEFINE(MOZ_CONTENT_SANDBOX)
fi
AC_SUBST(MOZ_CONTENT_SANDBOX)
MOZ_ARG_ENABLE_BOOL(content-sandbox-reporter,
[ --enable-content-sandbox-reporter Enable syscall reporter to troubleshoot syscalls denied by the content-processes sandbox],
MOZ_CONTENT_SANDBOX_REPORTER=1)
if test -n "$MOZ_CONTENT_SANDBOX_REPORTER"; then
AC_DEFINE(MOZ_CONTENT_SANDBOX_REPORTER)
fi
AC_SUBST(MOZ_CONTENT_SANDBOX_REPORTER)
dnl ========================================================
dnl =
@ -7007,6 +6993,15 @@ MOZ_ARG_ENABLE_BOOL(warnings-as-errors,
MOZ_ENABLE_WARNINGS_AS_ERRORS=)
if test -z "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
WARNINGS_AS_ERRORS=''
elif test "$GNU_CC"; then
# Prevent the following GCC warnings from being treated as errors:
# -Wuninitialized - too many false positives
# -Wdeprecated-declarations - we don't want our builds held hostage when a
# platform-specific API becomes deprecated.
MOZ_C_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_c_has_noerror_uninitialized)
MOZ_CXX_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_cxx_has_noerror_uninitialized)
MOZ_C_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_c_has_noerror_deprecated_declarations)
MOZ_CXX_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_cxx_has_noerror_deprecated_declarations)
fi
dnl ========================================================
@ -8916,6 +8911,7 @@ AC_SUBST(MOZ_OPUS)
AC_SUBST(MOZ_WEBM)
AC_SUBST(MOZ_DASH)
AC_SUBST(MOZ_WMF)
AC_SUBST(MOZ_DIRECTSHOW)
AC_SUBST(MOZ_MEDIA_PLUGINS)
AC_SUBST(MOZ_OMX_PLUGIN)
AC_SUBST(MOZ_VP8_ERROR_CONCEALMENT)

View File

@ -338,6 +338,8 @@ public:
(HasValidDir() || IsHTML(nsGkAtoms::bdi)));
}
Directionality GetComputedDirectionality() const;
protected:
/**
* Method to get the _intrinsic_ content state of this element. This is the

View File

@ -3419,6 +3419,18 @@ Element::SetBoolAttr(nsIAtom* aAttr, bool aValue)
return UnsetAttr(kNameSpaceID_None, aAttr, true);
}
Directionality
Element::GetComputedDirectionality() const
{
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
return frame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR
? eDir_LTR : eDir_RTL;
}
return GetDirectionality();
}
float
Element::FontSizeInflation()
{

View File

@ -2839,17 +2839,6 @@ SelectTextFieldOnFocus()
return gSelectTextFieldOnFocus == 1;
}
static bool
IsLTR(Element* aElement)
{
nsIFrame* frame = aElement->GetPrimaryFrame();
if (frame) {
return frame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR;
}
// at least for HTML, directionality is exclusively LTR or RTL
return aElement->GetDirectionality() == eDir_LTR;
}
bool
HTMLInputElement::ShouldPreventDOMActivateDispatch(EventTarget* aOriginalTarget)
{
@ -3180,10 +3169,12 @@ HTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
Decimal newValue;
switch (keyEvent->keyCode) {
case NS_VK_LEFT:
newValue = value + (IsLTR(this) ? -step : step);
newValue = value + (GetComputedDirectionality() == eDir_RTL
? step : -step);
break;
case NS_VK_RIGHT:
newValue = value + (IsLTR(this) ? step : -step);
newValue = value + (GetComputedDirectionality() == eDir_RTL
? -step : step);
break;
case NS_VK_UP:
// Even for horizontal range, "up" means "increase"

View File

@ -52,6 +52,10 @@
#include "WMFDecoder.h"
#include "WMFReader.h"
#endif
#ifdef MOZ_DIRECTSHOW
#include "DirectShowDecoder.h"
#include "DirectShowReader.h"
#endif
namespace mozilla
{
@ -276,6 +280,14 @@ IsWMFSupportedType(const nsACString& aType)
}
#endif
#ifdef MOZ_DIRECTSHOW
static bool
IsDirectShowSupportedType(const nsACString& aType)
{
return DirectShowDecoder::GetSupportedCodecs(aType, nullptr);
}
#endif
/* static */
bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType)
{
@ -354,6 +366,11 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
result = CANPLAY_MAYBE;
}
#endif
#ifdef MOZ_DIRECTSHOW
if (DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), &codecList)) {
result = CANPLAY_MAYBE;
}
#endif
#ifdef MOZ_MEDIA_PLUGINS
if (MediaDecoder::IsMediaPluginsEnabled() &&
GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList))
@ -444,6 +461,13 @@ DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
decoder = new DASHDecoder();
}
#endif
#ifdef MOZ_DIRECTSHOW
// Note: DirectShow decoder must come before WMFDecoder, else the pref
// "media.directshow.preferred" won't be honored.
if (IsDirectShowSupportedType(aType)) {
decoder = new DirectShowDecoder();
}
#endif
#ifdef MOZ_WMF
if (IsWMFSupportedType(aType)) {
decoder = new WMFDecoder();
@ -497,6 +521,13 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
decoderReader = new WebMReader(aDecoder);
} else
#endif
#ifdef MOZ_DIRECTSHOW
// Note: DirectShowReader is preferred for MP3, but if it's disabled we
// fallback to the WMFReader.
if (IsDirectShowSupportedType(aType)) {
decoderReader = new DirectShowReader(aDecoder);
} else
#endif
#ifdef MOZ_WMF
if (IsWMFSupportedType(aType)) {
decoderReader = new WMFReader(aDecoder);
@ -537,6 +568,9 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
#ifdef MOZ_WMF
(IsWMFSupportedType(aType) &&
Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true)) ||
#endif
#ifdef MOZ_DIRECTSHOW
IsDirectShowSupportedType(aType) ||
#endif
false;
}

View File

@ -18,11 +18,15 @@ include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
INCLUDES += \
LOCAL_INCLUDES += \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/layout/generic \
-I$(topsrcdir)/layout/xul/base/src \
$(NULL)
ifdef MOZ_DIRECTSHOW
LOCAL_INCLUDES += -I$(topsrcdir)/media/webrtc/trunk/webrtc/modules/video_capture/windows/
endif
CFLAGS += $(GSTREAMER_CFLAGS)
CXXFLAGS += $(GSTREAMER_CFLAGS)

View File

@ -470,6 +470,8 @@ VideoData* MediaDecoderReader::FindStartTime(int64_t& aOutStartTime)
nsresult MediaDecoderReader::DecodeToTarget(int64_t aTarget)
{
LOG(PR_LOG_DEBUG, ("MediaDecoderReader::DecodeToTarget(%lld) Begin", aTarget));
// Decode forward to the target frame. Start with video, if we have it.
if (HasVideo()) {
bool eof = false;
@ -591,6 +593,9 @@ nsresult MediaDecoderReader::DecodeToTarget(int64_t aTarget)
break;
}
}
LOG(PR_LOG_DEBUG, ("MediaDecoderReader::DecodeToTarget(%lld) End", aTarget));
return NS_OK;
}

View File

@ -0,0 +1,289 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SampleSink.h"
#include "AudioSinkFilter.h"
#include "AudioSinkInputPin.h"
#include "VideoUtils.h"
#include "prlog.h"
#include <initguid.h>
#include <wmsdkidl.h>
#define DELETE_RESET(p) { delete (p) ; (p) = NULL ;}
DEFINE_GUID(CLSID_MozAudioSinkFilter, 0x1872d8c8, 0xea8d, 0x4c34, 0xae, 0x96, 0x69, 0xde,
0xf1, 0x33, 0x7b, 0x33);
using namespace mozilla::media;
namespace mozilla {
#ifdef PR_LOGGING
PRLogModuleInfo* GetDirectShowLog();
#define LOG(...) PR_LOG(GetDirectShowLog(), PR_LOG_DEBUG, (__VA_ARGS__))
#else
#define LOG(...)
#endif
AudioSinkFilter::AudioSinkFilter(const wchar_t* aObjectName, HRESULT* aOutResult)
: BaseFilter(aObjectName, CLSID_MozAudioSinkFilter),
mFilterCritSec("AudioSinkFilter::mFilterCritSec")
{
(*aOutResult) = S_OK;
mInputPin = new AudioSinkInputPin(L"AudioSinkInputPin",
this,
&mFilterCritSec,
aOutResult);
}
AudioSinkFilter::~AudioSinkFilter()
{
}
int
AudioSinkFilter::GetPinCount()
{
return 1;
}
BasePin*
AudioSinkFilter::GetPin(int aIndex)
{
CriticalSectionAutoEnter lockFilter(mFilterCritSec);
return (aIndex == 0) ? static_cast<BasePin*>(mInputPin) : nullptr;
}
HRESULT
AudioSinkFilter::Pause()
{
CriticalSectionAutoEnter lockFilter(mFilterCritSec);
if (mState == State_Stopped) {
// Change the state, THEN activate the input pin.
mState = State_Paused;
if (mInputPin && mInputPin->IsConnected()) {
mInputPin->Active();
}
} else if (mState == State_Running) {
mState = State_Paused;
}
return S_OK;
}
HRESULT
AudioSinkFilter::Stop()
{
CriticalSectionAutoEnter lockFilter(mFilterCritSec);
mState = State_Stopped;
if (mInputPin) {
mInputPin->Inactive();
}
GetSampleSink()->Flush();
return S_OK;
}
HRESULT
AudioSinkFilter::Run(REFERENCE_TIME tStart)
{
LOG("AudioSinkFilter::Run(%lld) [%4.2lf]",
RefTimeToUsecs(tStart),
double(RefTimeToUsecs(tStart)) / USECS_PER_S);
return media::BaseFilter::Run(tStart);
}
HRESULT
AudioSinkFilter::GetClassID( OUT CLSID * pCLSID )
{
(* pCLSID) = CLSID_MozAudioSinkFilter;
return S_OK;
}
HRESULT
AudioSinkFilter::QueryInterface(REFIID aIId, void **aInterface)
{
if (aIId == IID_IMediaSeeking) {
*aInterface = static_cast<IMediaSeeking*>(this);
AddRef();
return S_OK;
}
return mozilla::media::BaseFilter::QueryInterface(aIId, aInterface);
}
ULONG
AudioSinkFilter::AddRef()
{
return ::InterlockedIncrement(&mRefCnt);
}
ULONG
AudioSinkFilter::Release()
{
unsigned long newRefCnt = ::InterlockedDecrement(&mRefCnt);
if (!newRefCnt) {
delete this;
}
return newRefCnt;
}
SampleSink*
AudioSinkFilter::GetSampleSink()
{
return mInputPin->GetSampleSink();
}
// IMediaSeeking implementation.
//
// Calls to IMediaSeeking are forwarded to the output pin that the
// AudioSinkInputPin is connected to, i.e. upstream towards the parser and
// source filters, which actually implement seeking.
#define ENSURE_CONNECTED_PIN_SEEKING \
if (!mInputPin) { \
return E_NOTIMPL; \
} \
RefPtr<IMediaSeeking> pinSeeking = mInputPin->GetConnectedPinSeeking(); \
if (!pinSeeking) { \
return E_NOTIMPL; \
}
HRESULT
AudioSinkFilter::GetCapabilities(DWORD* aCapabilities)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->GetCapabilities(aCapabilities);
}
HRESULT
AudioSinkFilter::CheckCapabilities(DWORD* aCapabilities)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->CheckCapabilities(aCapabilities);
}
HRESULT
AudioSinkFilter::IsFormatSupported(const GUID* aFormat)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->IsFormatSupported(aFormat);
}
HRESULT
AudioSinkFilter::QueryPreferredFormat(GUID* aFormat)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->QueryPreferredFormat(aFormat);
}
HRESULT
AudioSinkFilter::GetTimeFormat(GUID* aFormat)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->GetTimeFormat(aFormat);
}
HRESULT
AudioSinkFilter::IsUsingTimeFormat(const GUID* aFormat)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->IsUsingTimeFormat(aFormat);
}
HRESULT
AudioSinkFilter::SetTimeFormat(const GUID* aFormat)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->SetTimeFormat(aFormat);
}
HRESULT
AudioSinkFilter::GetDuration(LONGLONG* aDuration)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->GetDuration(aDuration);
}
HRESULT
AudioSinkFilter::GetStopPosition(LONGLONG* aStop)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->GetStopPosition(aStop);
}
HRESULT
AudioSinkFilter::GetCurrentPosition(LONGLONG* aCurrent)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->GetCurrentPosition(aCurrent);
}
HRESULT
AudioSinkFilter::ConvertTimeFormat(LONGLONG* aTarget,
const GUID* aTargetFormat,
LONGLONG aSource,
const GUID* aSourceFormat)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->ConvertTimeFormat(aTarget,
aTargetFormat,
aSource,
aSourceFormat);
}
HRESULT
AudioSinkFilter::SetPositions(LONGLONG* aCurrent,
DWORD aCurrentFlags,
LONGLONG* aStop,
DWORD aStopFlags)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->SetPositions(aCurrent,
aCurrentFlags,
aStop,
aStopFlags);
}
HRESULT
AudioSinkFilter::GetPositions(LONGLONG* aCurrent,
LONGLONG* aStop)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->GetPositions(aCurrent, aStop);
}
HRESULT
AudioSinkFilter::GetAvailable(LONGLONG* aEarliest,
LONGLONG* aLatest)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->GetAvailable(aEarliest, aLatest);
}
HRESULT
AudioSinkFilter::SetRate(double aRate)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->SetRate(aRate);
}
HRESULT
AudioSinkFilter::GetRate(double* aRate)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->GetRate(aRate);
}
HRESULT
AudioSinkFilter::GetPreroll(LONGLONG* aPreroll)
{
ENSURE_CONNECTED_PIN_SEEKING
return pinSeeking->GetPreroll(aPreroll);
}
} // namespace mozilla

View File

@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(AudioSinkFilter_h_)
#define AudioSinkFilter_h_
#include "BaseFilter.h"
#include "DirectShowUtils.h"
#include "nsAutoPtr.h"
#include "mozilla/RefPtr.h"
namespace mozilla {
class AudioSinkInputPin;
class SampleSink;
// Filter that acts as the end of the graph. Audio samples input into
// this filter block the calling thread, and the calling thread is
// unblocked when the decode thread extracts the sample. The samples
// input into this filter are stored in the SampleSink, where the blocking
// is implemented. The input pin owns the SampleSink.
class AudioSinkFilter: public mozilla::media::BaseFilter,
public IMediaSeeking
{
public:
AudioSinkFilter(const wchar_t* aObjectName, HRESULT* aOutResult);
virtual ~AudioSinkFilter();
// Gets the input pin's sample sink.
SampleSink* GetSampleSink();
// IUnknown implementation.
STDMETHODIMP QueryInterface(REFIID aIId, void **aInterface);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// --------------------------------------------------------------------
// CBaseFilter methods
int GetPinCount ();
mozilla::media::BasePin* GetPin ( IN int Index);
STDMETHODIMP Pause ();
STDMETHODIMP Stop ();
STDMETHODIMP GetClassID ( OUT CLSID * pCLSID);
STDMETHODIMP Run(REFERENCE_TIME tStart);
// IMediaSeeking Methods...
// We defer to SourceFilter, but we must expose the interface on
// the output pins. Seeking commands come upstream from the renderers,
// but they must be actioned at the source filters.
STDMETHODIMP GetCapabilities(DWORD* aCapabilities);
STDMETHODIMP CheckCapabilities(DWORD* aCapabilities);
STDMETHODIMP IsFormatSupported(const GUID* aFormat);
STDMETHODIMP QueryPreferredFormat(GUID* aFormat);
STDMETHODIMP GetTimeFormat(GUID* aFormat);
STDMETHODIMP IsUsingTimeFormat(const GUID* aFormat);
STDMETHODIMP SetTimeFormat(const GUID* aFormat);
STDMETHODIMP GetDuration(LONGLONG* pDuration);
STDMETHODIMP GetStopPosition(LONGLONG* pStop);
STDMETHODIMP GetCurrentPosition(LONGLONG* aCurrent);
STDMETHODIMP ConvertTimeFormat(LONGLONG* aTarget,
const GUID* aTargetFormat,
LONGLONG aSource,
const GUID* aSourceFormat);
STDMETHODIMP SetPositions(LONGLONG* aCurrent,
DWORD aCurrentFlags,
LONGLONG* aStop,
DWORD aStopFlags);
STDMETHODIMP GetPositions(LONGLONG* aCurrent,
LONGLONG* aStop);
STDMETHODIMP GetAvailable(LONGLONG* aEarliest,
LONGLONG* aLatest);
STDMETHODIMP SetRate(double aRate);
STDMETHODIMP GetRate(double* aRate);
STDMETHODIMP GetPreroll(LONGLONG* aPreroll);
// --------------------------------------------------------------------
// class factory calls this
static IUnknown * CreateInstance (IN LPUNKNOWN punk, OUT HRESULT * phr);
private:
CriticalSection mFilterCritSec;
// Note: The input pin defers its refcounting to the sink filter, so when
// the input pin is addrefed, what actually happens is the sink filter is
// addrefed.
nsAutoPtr<AudioSinkInputPin> mInputPin;
};
} // namespace mozilla
#endif // AudioSinkFilter_h_

View File

@ -0,0 +1,200 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioSinkInputPin.h"
#include "AudioSinkFilter.h"
#include "SampleSink.h"
#include "prlog.h"
#include <initguid.h>
#include <wmsdkidl.h>
using namespace mozilla::media;
namespace mozilla {
#ifdef PR_LOGGING
PRLogModuleInfo* GetDirectShowLog();
#define LOG(...) PR_LOG(GetDirectShowLog(), PR_LOG_DEBUG, (__VA_ARGS__))
#else
#define LOG(...)
#endif
AudioSinkInputPin::AudioSinkInputPin(wchar_t* aObjectName,
AudioSinkFilter* aFilter,
mozilla::CriticalSection* aLock,
HRESULT* aOutResult)
: BaseInputPin(aObjectName, aFilter, aLock, aOutResult, aObjectName),
mSegmentStartTime(0)
{
MOZ_COUNT_CTOR(AudioSinkInputPin);
mSampleSink = new SampleSink();
}
AudioSinkInputPin::~AudioSinkInputPin()
{
MOZ_COUNT_DTOR(AudioSinkInputPin);
}
HRESULT
AudioSinkInputPin::GetMediaType(int aPosition, MediaType* aOutMediaType)
{
NS_ENSURE_TRUE(aPosition >= 0, E_INVALIDARG);
NS_ENSURE_TRUE(aOutMediaType, E_POINTER);
if (aPosition > 0) {
return S_FALSE;
}
// Note: We set output as PCM, as IEEE_FLOAT only works when using the
// MP3 decoder as an MFT, and we can't do that while using DirectShow.
aOutMediaType->SetType(&MEDIATYPE_Audio);
aOutMediaType->SetSubtype(&MEDIASUBTYPE_PCM);
aOutMediaType->SetType(&FORMAT_WaveFormatEx);
aOutMediaType->SetTemporalCompression(FALSE);
return S_OK;
}
HRESULT
AudioSinkInputPin::CheckMediaType(const MediaType* aMediaType)
{
if (!aMediaType) {
return E_INVALIDARG;
}
GUID majorType = *aMediaType->Type();
if (majorType != MEDIATYPE_Audio && majorType != WMMEDIATYPE_Audio) {
return E_INVALIDARG;
}
if (*aMediaType->Subtype() != MEDIASUBTYPE_PCM) {
return E_INVALIDARG;
}
if (*aMediaType->FormatType() != FORMAT_WaveFormatEx) {
return E_INVALIDARG;
}
// We accept the media type, stash its layout format!
WAVEFORMATEX* wfx = (WAVEFORMATEX*)(aMediaType->pbFormat);
GetSampleSink()->SetAudioFormat(wfx);
return S_OK;
}
AudioSinkFilter*
AudioSinkInputPin::GetAudioSinkFilter()
{
return reinterpret_cast<AudioSinkFilter*>(mFilter);
}
SampleSink*
AudioSinkInputPin::GetSampleSink()
{
return mSampleSink;
}
HRESULT
AudioSinkInputPin::SetAbsoluteMediaTime(IMediaSample* aSample)
{
HRESULT hr;
REFERENCE_TIME start = 0, end = 0;
hr = aSample->GetTime(&start, &end);
NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
{
CriticalSectionAutoEnter lock(*mLock);
start += mSegmentStartTime;
end += mSegmentStartTime;
}
hr = aSample->SetMediaTime(&start, &end);
NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
return S_OK;
}
HRESULT
AudioSinkInputPin::Receive(IMediaSample* aSample )
{
HRESULT hr;
NS_ENSURE_TRUE(aSample, E_POINTER);
hr = BaseInputPin::Receive(aSample);
if (SUCCEEDED(hr) && hr != S_FALSE) { // S_FALSE == flushing
// Set the timestamp of the sample after being adjusted for
// seeking/segments in the "media time" attribute. When we seek,
// DirectShow starts a new "segment", and starts labeling samples
// from time=0 again, so we need to correct for this to get the
// actual timestamps after seeking.
hr = SetAbsoluteMediaTime(aSample);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = GetSampleSink()->Receive(aSample);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
}
return S_OK;
}
TemporaryRef<IMediaSeeking>
AudioSinkInputPin::GetConnectedPinSeeking()
{
RefPtr<IPin> peer = GetConnected();
if (!peer)
return nullptr;
RefPtr<IMediaSeeking> seeking;
peer->QueryInterface(static_cast<IMediaSeeking**>(byRef(seeking)));
return seeking;
}
HRESULT
AudioSinkInputPin::BeginFlush()
{
HRESULT hr = media::BaseInputPin::BeginFlush();
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
GetSampleSink()->Flush();
return S_OK;
}
HRESULT
AudioSinkInputPin::EndFlush()
{
HRESULT hr = media::BaseInputPin::EndFlush();
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Reset the EOS flag, so that if we're called after a seek we still work.
GetSampleSink()->Reset();
return S_OK;
}
HRESULT
AudioSinkInputPin::EndOfStream(void)
{
HRESULT hr = media::BaseInputPin::EndOfStream();
if (FAILED(hr) || hr == S_FALSE) {
// Pin is stil flushing.
return hr;
}
GetSampleSink()->SetEOS();
return S_OK;
}
HRESULT
AudioSinkInputPin::NewSegment(REFERENCE_TIME tStart,
REFERENCE_TIME tStop,
double dRate)
{
CriticalSectionAutoEnter lock(*mLock);
// Record the start time of the new segment, so that we can store the
// correct absolute timestamp in the "media time" each incoming sample.
mSegmentStartTime = tStart;
return S_OK;
}
} // namespace mozilla

View File

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(AudioSinkInputPin_h_)
#define AudioSinkInputPin_h_
#include "BaseInputPin.h"
#include "DirectShowUtils.h"
#include "mozilla/RefPtr.h"
#include "nsAutoPtr.h"
namespace mozilla {
namespace media {
class MediaType;
}
class AudioSinkFilter;
class SampleSink;
// Input pin for capturing audio output of a DirectShow filter graph.
// This is the input pin for the AudioSinkFilter.
class AudioSinkInputPin: public mozilla::media::BaseInputPin
{
public:
AudioSinkInputPin(wchar_t* aObjectName,
AudioSinkFilter* aFilter,
mozilla::CriticalSection* aLock,
HRESULT* aOutResult);
virtual ~AudioSinkInputPin();
HRESULT GetMediaType (IN int iPos, OUT mozilla::media::MediaType * pmt);
HRESULT CheckMediaType (IN const mozilla::media::MediaType * pmt);
STDMETHODIMP Receive (IN IMediaSample *);
STDMETHODIMP BeginFlush() MOZ_OVERRIDE;
STDMETHODIMP EndFlush() MOZ_OVERRIDE;
// Called when we start decoding a new segment, that happens directly after
// a seek. This captures the segment's start time. Samples decoded by the
// MP3 decoder have their timestamps offset from the segment start time.
// Storing the segment start time enables us to set each sample's MediaTime
// as an offset in the stream relative to the start of the stream, rather
// than the start of the segment, i.e. its absolute time in the stream.
STDMETHODIMP NewSegment(REFERENCE_TIME tStart,
REFERENCE_TIME tStop,
double dRate) MOZ_OVERRIDE;
STDMETHODIMP EndOfStream() MOZ_OVERRIDE;
// Returns the IMediaSeeking interface of the connected output pin.
// We forward seeking requests upstream from the sink to the source
// filters.
TemporaryRef<IMediaSeeking> GetConnectedPinSeeking();
SampleSink* GetSampleSink();
private:
AudioSinkFilter* GetAudioSinkFilter();
// Sets the media time on the media sample, relative to the segment
// start time.
HRESULT SetAbsoluteMediaTime(IMediaSample* aSample);
nsAutoPtr<SampleSink> mSampleSink;
// Synchronized by the filter lock; BaseInputPin::mLock.
REFERENCE_TIME mSegmentStartTime;
};
} // namespace mozilla
#endif // AudioSinkInputPin_h_

View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DirectShowDecoder.h"
#include "DirectShowReader.h"
#include "MediaDecoderStateMachine.h"
#include "mozilla/Preferences.h"
namespace mozilla {
MediaDecoderStateMachine* DirectShowDecoder::CreateStateMachine()
{
return new MediaDecoderStateMachine(this, new DirectShowReader(this));
}
/* static */
bool
DirectShowDecoder::GetSupportedCodecs(const nsACString& aType,
char const *const ** aCodecList)
{
if (!IsEnabled()) {
return false;
}
static char const *const mp3AudioCodecs[] = {
"mp3",
nullptr
};
if (aType.EqualsASCII("audio/mpeg") ||
aType.EqualsASCII("audio/mp3")) {
if (aCodecList) {
*aCodecList = mp3AudioCodecs;
}
return true;
}
return false;
}
/* static */
bool
DirectShowDecoder::IsEnabled()
{
return Preferences::GetBool("media.directshow.enabled");
}
DirectShowDecoder::DirectShowDecoder()
{
MOZ_COUNT_CTOR(DirectShowDecoder);
}
DirectShowDecoder::~DirectShowDecoder()
{
MOZ_COUNT_DTOR(DirectShowDecoder);
}
} // namespace mozilla

View File

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(DirectShowDecoder_h_)
#define DirectShowDecoder_h_
#include "MediaDecoder.h"
namespace mozilla {
// Decoder that uses DirectShow to playback MP3 files only.
class DirectShowDecoder : public MediaDecoder
{
public:
DirectShowDecoder();
virtual ~DirectShowDecoder();
MediaDecoder* Clone() MOZ_OVERRIDE {
if (!IsEnabled()) {
return nullptr;
}
return new DirectShowDecoder();
}
MediaDecoderStateMachine* CreateStateMachine() MOZ_OVERRIDE;
// Returns true if aType is a MIME type that we render with the
// DirectShow backend. If aCodecList is non null,
// it is filled with a (static const) null-terminated list of strings
// denoting the codecs we'll playback. Note that playback is strictly
// limited to MP3 only.
static bool GetSupportedCodecs(const nsACString& aType,
char const *const ** aCodecList);
// Returns true if the DirectShow backend is preffed on.
static bool IsEnabled();
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,366 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DirectShowReader.h"
#include "MediaDecoderReader.h"
#include "mozilla/RefPtr.h"
#include "dshow.h"
#include "AudioSinkFilter.h"
#include "SourceFilter.h"
#include "DirectShowUtils.h"
#include "SampleSink.h"
namespace mozilla {
#ifdef PR_LOGGING
PRLogModuleInfo*
GetDirectShowLog() {
static PRLogModuleInfo* log = nullptr;
if (!log) {
log = PR_NewLogModule("DirectShowDecoder");
}
return log;
}
#define LOG(...) PR_LOG(GetDirectShowLog(), PR_LOG_DEBUG, (__VA_ARGS__))
#else
#define LOG(...)
#endif
DirectShowReader::DirectShowReader(AbstractMediaDecoder* aDecoder)
: MediaDecoderReader(aDecoder),
#ifdef DEBUG
mRotRegister(0),
#endif
mNumChannels(0),
mAudioRate(0),
mBytesPerSample(0)
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
MOZ_COUNT_CTOR(DirectShowReader);
}
DirectShowReader::~DirectShowReader()
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
MOZ_COUNT_DTOR(DirectShowReader);
#ifdef DEBUG
if (mRotRegister) {
RemoveGraphFromRunningObjectTable(mRotRegister);
}
#endif
}
nsresult
DirectShowReader::Init(MediaDecoderReader* aCloneDonor)
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
return NS_OK;
}
// Windows XP's MP3 decoder filter. This is available on XP only, on Vista
// and later we can use the DMO Wrapper filter and MP3 decoder DMO.
static const GUID CLSID_MPEG_LAYER_3_DECODER_FILTER =
{ 0x38BE3000, 0xDBF4, 0x11D0, 0x86, 0x0E, 0x00, 0xA0, 0x24, 0xCF, 0xEF, 0x6D };
nsresult
DirectShowReader::ReadMetadata(VideoInfo* aInfo,
MetadataTags** aTags)
{
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
HRESULT hr;
nsresult rv;
// Create the filter graph, reference it by the GraphBuilder interface,
// to make graph building more convenient.
hr = CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
reinterpret_cast<void**>(static_cast<IGraphBuilder**>(byRef(mGraph))));
NS_ENSURE_TRUE(SUCCEEDED(hr) && mGraph, NS_ERROR_FAILURE);
#ifdef DEBUG
// Add the graph to the Running Object Table so that we can connect
// to this graph with GraphEdit/GraphStudio. Note: on Vista and up you must
// also regsvr32 proppage.dll from the Windows SDK.
// See: http://msdn.microsoft.com/en-us/library/ms787252(VS.85).aspx
hr = AddGraphToRunningObjectTable(mGraph, &mRotRegister);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
#endif
// Extract the interface pointers we'll need from the filter graph.
hr = mGraph->QueryInterface(static_cast<IMediaControl**>(byRef(mControl)));
NS_ENSURE_TRUE(SUCCEEDED(hr) && mControl, NS_ERROR_FAILURE);
hr = mGraph->QueryInterface(static_cast<IMediaSeeking**>(byRef(mMediaSeeking)));
NS_ENSURE_TRUE(SUCCEEDED(hr) && mMediaSeeking, NS_ERROR_FAILURE);
// Build the graph. Create the filters we need, and connect them. We
// build the entire graph ourselves to prevent other decoders installed
// on the system being created and used.
// Our source filters, wraps the MediaResource.
mSourceFilter = new SourceFilter(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio);
NS_ENSURE_TRUE(mSourceFilter, NS_ERROR_FAILURE);
rv = mSourceFilter->Init(mDecoder->GetResource());
NS_ENSURE_SUCCESS(rv, rv);
hr = mGraph->AddFilter(mSourceFilter, L"MozillaDirectShowSource");
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
// The MPEG demuxer.
RefPtr<IBaseFilter> demuxer;
hr = CreateAndAddFilter(mGraph,
CLSID_MPEG1Splitter,
L"MPEG1Splitter",
byRef(demuxer));
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
// Platform MP3 decoder.
RefPtr<IBaseFilter> decoder;
// Firstly try to create the MP3 decoder filter that ships with WinXP
// directly. This filter doesn't normally exist on later versions of
// Windows.
hr = CreateAndAddFilter(mGraph,
CLSID_MPEG_LAYER_3_DECODER_FILTER,
L"MPEG Layer 3 Decoder",
byRef(decoder));
if (FAILED(hr)) {
// Failed to create MP3 decoder filter. Try to instantiate
// the MP3 decoder DMO.
hr = AddMP3DMOWrapperFilter(mGraph, byRef(decoder));
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
}
// Sink, captures audio samples and inserts them into our pipeline.
static const wchar_t* AudioSinkFilterName = L"MozAudioSinkFilter";
mAudioSinkFilter = new AudioSinkFilter(AudioSinkFilterName, &hr);
NS_ENSURE_TRUE(mAudioSinkFilter && SUCCEEDED(hr), NS_ERROR_FAILURE);
hr = mGraph->AddFilter(mAudioSinkFilter, AudioSinkFilterName);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
// Join the filters.
hr = ConnectFilters(mGraph, mSourceFilter, demuxer);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
hr = ConnectFilters(mGraph, demuxer, decoder);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
hr = ConnectFilters(mGraph, decoder, mAudioSinkFilter);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
WAVEFORMATEX format;
mAudioSinkFilter->GetSampleSink()->GetAudioFormat(&format);
NS_ENSURE_TRUE(format.wFormatTag == WAVE_FORMAT_PCM, NS_ERROR_FAILURE);
mInfo.mAudioChannels = mNumChannels = format.nChannels;
mInfo.mAudioRate = mAudioRate = format.nSamplesPerSec;
mBytesPerSample = format.wBitsPerSample / 8;
mInfo.mHasAudio = true;
mInfo.mHasVideo = false;
*aInfo = mInfo;
*aTags = nullptr;
// Begin decoding!
hr = mControl->Run();
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
DWORD seekCaps = 0;
hr = mMediaSeeking->GetCapabilities(&seekCaps);
bool canSeek = ((AM_SEEKING_CanSeekAbsolute & seekCaps) == AM_SEEKING_CanSeekAbsolute);
if (!canSeek) {
mDecoder->SetMediaSeekable(false);
}
int64_t duration = 0;
hr = mMediaSeeking->GetDuration(&duration);
if (SUCCEEDED(hr)) {
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecoder->SetMediaDuration(RefTimeToUsecs(duration));
}
LOG("Successfully initialized DirectShow MP3 decoder.");
LOG("Channels=%u Hz=%u duration=%lld bytesPerSample=%d",
mInfo.mAudioChannels,
mInfo.mAudioRate,
RefTimeToUsecs(duration),
mBytesPerSample);
return NS_OK;
}
inline float
UnsignedByteToAudioSample(uint8_t aValue)
{
return aValue * (2.0f / UINT8_MAX) - 1.0f;
}
bool
DirectShowReader::Finish(HRESULT aStatus)
{
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
LOG("DirectShowReader::Finish(0x%x)", aStatus);
mAudioQueue.Finish();
// Notify the filter graph of end of stream.
RefPtr<IMediaEventSink> eventSink;
HRESULT hr = mGraph->QueryInterface(static_cast<IMediaEventSink**>(byRef(eventSink)));
if (SUCCEEDED(hr) && eventSink) {
eventSink->Notify(EC_COMPLETE, aStatus, NULL);
}
return false;
}
bool
DirectShowReader::DecodeAudioData()
{
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
HRESULT hr;
SampleSink* sink = mAudioSinkFilter->GetSampleSink();
if (sink->AtEOS()) {
// End of stream.
return Finish(S_OK);
}
// Get the next chunk of audio samples. This blocks until the sample
// arrives, or an error occurs (like the stream is shutdown).
RefPtr<IMediaSample> sample;
hr = sink->Extract(sample);
if (FAILED(hr) || hr == S_FALSE) {
return Finish(hr);
}
int64_t start = 0, end = 0;
sample->GetMediaTime(&start, &end);
LOG("DirectShowReader::DecodeAudioData [%4.2lf-%4.2lf]",
RefTimeToSeconds(start),
RefTimeToSeconds(end));
LONG length = sample->GetActualDataLength();
LONG numSamples = length / mBytesPerSample;
LONG numFrames = length / mBytesPerSample / mNumChannels;
BYTE* data = nullptr;
hr = sample->GetPointer(&data);
NS_ENSURE_TRUE(SUCCEEDED(hr), Finish(hr));
nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[numSamples]);
AudioDataValue* dst = buffer.get();
if (mBytesPerSample == 1) {
uint8_t* src = reinterpret_cast<uint8_t*>(data);
for (int32_t i = 0; i < numSamples; ++i) {
dst[i] = UnsignedByteToAudioSample(src[i]);
}
} else if (mBytesPerSample == 2) {
int16_t* src = reinterpret_cast<int16_t*>(data);
for (int32_t i = 0; i < numSamples; ++i) {
dst[i] = AudioSampleToFloat(src[i]);
}
}
mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(),
RefTimeToUsecs(start),
RefTimeToUsecs(end - start),
numFrames,
buffer.forget(),
mNumChannels));
uint32_t bytesConsumed = mSourceFilter->GetAndResetBytesConsumedCount();
if (bytesConsumed > 0) {
mDecoder->NotifyBytesConsumed(bytesConsumed);
}
return true;
}
bool
DirectShowReader::DecodeVideoFrame(bool &aKeyframeSkip,
int64_t aTimeThreshold)
{
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
return false;
}
bool
DirectShowReader::HasAudio()
{
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
return true;
}
bool
DirectShowReader::HasVideo()
{
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
return false;
}
nsresult
DirectShowReader::Seek(int64_t aTargetUs,
int64_t aStartTime,
int64_t aEndTime,
int64_t aCurrentTime)
{
HRESULT hr;
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");\
LOG("DirectShowReader::Seek() target=%lld", aTargetUs);
hr = mControl->Pause();
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
nsresult rv = ResetDecode();
NS_ENSURE_SUCCESS(rv, rv);
LONGLONG seekPosition = UsecsToRefTime(aTargetUs);
hr = mMediaSeeking->SetPositions(&seekPosition,
AM_SEEKING_AbsolutePositioning,
nullptr,
AM_SEEKING_NoPositioning);
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
hr = mControl->Run();
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
return DecodeToTarget(aTargetUs);
}
nsresult
DirectShowReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered,
int64_t aStartTime)
{
MediaResource* stream = mDecoder->GetResource();
int64_t durationUs = 0;
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
durationUs = mDecoder->GetMediaDuration();
}
GetEstimatedBufferedTimeRanges(stream, durationUs, aBuffered);
return NS_OK;
}
void
DirectShowReader::OnDecodeThreadStart()
{
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
NS_ENSURE_TRUE_VOID(SUCCEEDED(hr));
}
void
DirectShowReader::OnDecodeThreadFinish()
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
CoUninitialize();
}
} // namespace mozilla

View File

@ -0,0 +1,113 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(DirectShowReader_h_)
#define DirectShowReader_h_
#include "Windows.h" // HRESULT, DWORD
#include "MediaDecoderReader.h"
#include "mozilla/RefPtr.h"
class IGraphBuilder;
class IMediaControl;
class IMediaSeeking;
class IMediaEventEx;
namespace mozilla {
class AudioSinkFilter;
class SourceFilter;
namespace dom {
class TimeRanges;
}
// Decoder backend for decoding MP3 using DirectShow. DirectShow operates as
// a filter graph. The basic design of the DirectShowReader is that we have
// a SourceFilter that wraps the MediaResource that connects to the
// MP3 decoder filter. The MP3 decoder filter "pulls" data as it requires it
// downstream on its own thread. When the MP3 decoder has produced a block of
// decoded samples, its thread calls downstream into our AudioSinkFilter,
// passing the decoded buffer in. The AudioSinkFilter inserts the samples into
// a SampleSink object. The SampleSink blocks the MP3 decoder's thread until
// the decode thread calls DecodeAudioData(), whereupon the SampleSink
// releases the decoded samples to the decode thread, and unblocks the MP3
// decoder's thread. The MP3 decoder can then request more data from the
// SourceFilter, and decode more data. If the decode thread calls
// DecodeAudioData() and there's no decoded samples waiting to be extracted
// in the SampleSink, the SampleSink blocks the decode thread until the MP3
// decoder produces a decoded sample.
class DirectShowReader : public MediaDecoderReader
{
public:
DirectShowReader(AbstractMediaDecoder* aDecoder);
virtual ~DirectShowReader();
nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE;
bool DecodeAudioData() MOZ_OVERRIDE;
bool DecodeVideoFrame(bool &aKeyframeSkip,
int64_t aTimeThreshold) MOZ_OVERRIDE;
bool HasAudio() MOZ_OVERRIDE;
bool HasVideo() MOZ_OVERRIDE;
nsresult ReadMetadata(VideoInfo* aInfo,
MetadataTags** aTags) MOZ_OVERRIDE;
nsresult Seek(int64_t aTime,
int64_t aStartTime,
int64_t aEndTime,
int64_t aCurrentTime) MOZ_OVERRIDE;
nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered,
int64_t aStartTime) MOZ_OVERRIDE;
void OnDecodeThreadStart() MOZ_OVERRIDE;
void OnDecodeThreadFinish() MOZ_OVERRIDE;
private:
// Calls mAudioQueue.Finish(), and notifies the filter graph that playback
// is complete. aStatus is the code to send to the filter graph.
// Always returns false, so that we can just "return Finish()" from
// DecodeAudioData().
bool Finish(HRESULT aStatus);
// DirectShow filter graph, and associated playback and seeking
// control interfaces.
RefPtr<IGraphBuilder> mGraph;
RefPtr<IMediaControl> mControl;
RefPtr<IMediaSeeking> mMediaSeeking;
// Wraps the MediaResource, and feeds undecoded data into the filter graph.
RefPtr<SourceFilter> mSourceFilter;
// Sits at the end of the graph, removing decoded samples from the graph.
// The graph will block while this is blocked, i.e. it will pause decoding.
RefPtr<AudioSinkFilter> mAudioSinkFilter;
#ifdef DEBUG
// Used to add/remove the filter graph to the Running Object Table. You can
// connect GraphEdit/GraphStudio to the graph to observe and/or debug its
// topology and state.
DWORD mRotRegister;
#endif
// Number of channels in the audio stream.
uint32_t mNumChannels;
// Samples per second in the audio stream.
uint32_t mAudioRate;
// Number of bytes per sample. Can be either 1 or 2.
uint32_t mBytesPerSample;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,309 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "dshow.h"
#include "Dmodshow.h"
#include "Wmcodecdsp.h"
#include "Dmoreg.h"
#include "DirectShowUtils.h"
#include "nsAutoPtr.h"
#include "mozilla/RefPtr.h"
#include "nsMemory.h"
namespace mozilla {
#if defined(PR_LOGGING)
// Create a table which maps GUIDs to a string representation of the GUID.
// This is useful for debugging purposes, for logging the GUIDs of media types.
// This is only available when logging is enabled, i.e. not in release builds.
struct GuidToName {
const char* name;
const GUID guid;
};
#pragma push_macro("OUR_GUID_ENTRY")
#undef OUR_GUID_ENTRY
#define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
{ #name, {l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8} },
static const GuidToName GuidToNameTable[] = {
#include <uuids.h>
};
#pragma pop_macro("OUR_GUID_ENTRY")
const char*
GetDirectShowGuidName(const GUID& aGuid)
{
size_t len = NS_ARRAY_LENGTH(GuidToNameTable);
for (unsigned i = 0; i < len; i++) {
if (IsEqualGUID(aGuid, GuidToNameTable[i].guid)) {
return GuidToNameTable[i].name;
}
}
return "Unknown";
}
#endif // PR_LOGGING
void
RemoveGraphFromRunningObjectTable(DWORD aRotRegister)
{
nsRefPtr<IRunningObjectTable> runningObjectTable;
if (SUCCEEDED(GetRunningObjectTable(0, getter_AddRefs(runningObjectTable)))) {
runningObjectTable->Revoke(aRotRegister);
}
}
HRESULT
AddGraphToRunningObjectTable(IUnknown *aUnkGraph, DWORD *aOutRotRegister)
{
HRESULT hr;
nsRefPtr<IMoniker> moniker;
nsRefPtr<IRunningObjectTable> runningObjectTable;
hr = GetRunningObjectTable(0, getter_AddRefs(runningObjectTable));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
const size_t STRING_LENGTH = 256;
WCHAR wsz[STRING_LENGTH];
StringCchPrintfW(wsz,
STRING_LENGTH,
L"FilterGraph %08x pid %08x",
(DWORD_PTR)aUnkGraph,
GetCurrentProcessId());
hr = CreateItemMoniker(L"!", wsz, getter_AddRefs(moniker));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = runningObjectTable->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE,
aUnkGraph,
moniker,
aOutRotRegister);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
return S_OK;
}
const char*
GetGraphNotifyString(long evCode)
{
#define CASE(x) case x: return #x
switch(evCode) {
CASE(EC_ACTIVATE); // A video window is being activated or deactivated.
CASE(EC_BANDWIDTHCHANGE); // Not supported.
CASE(EC_BUFFERING_DATA); // The graph is buffering data, or has stopped buffering data.
CASE(EC_BUILT); // Send by the Video Control when a graph has been built. Not forwarded to applications.
CASE(EC_CLOCK_CHANGED); // The reference clock has changed.
CASE(EC_CLOCK_UNSET); // The clock provider was disconnected.
CASE(EC_CODECAPI_EVENT); // Sent by an encoder to signal an encoding event.
CASE(EC_COMPLETE); // All data from a particular stream has been rendered.
CASE(EC_CONTENTPROPERTY_CHANGED); // Not supported.
CASE(EC_DEVICE_LOST); // A Plug and Play device was removed or has become available again.
CASE(EC_DISPLAY_CHANGED); // The display mode has changed.
CASE(EC_END_OF_SEGMENT); // The end of a segment has been reached.
CASE(EC_EOS_SOON); // Not supported.
CASE(EC_ERROR_STILLPLAYING); // An asynchronous command to run the graph has failed.
CASE(EC_ERRORABORT); // An operation was aborted because of an error.
CASE(EC_ERRORABORTEX); // An operation was aborted because of an error.
CASE(EC_EXTDEVICE_MODE_CHANGE); // Not supported.
CASE(EC_FILE_CLOSED); // The source file was closed because of an unexpected event.
CASE(EC_FULLSCREEN_LOST); // The video renderer is switching out of full-screen mode.
CASE(EC_GRAPH_CHANGED); // The filter graph has changed.
CASE(EC_LENGTH_CHANGED); // The length of a source has changed.
CASE(EC_LOADSTATUS); // Notifies the application of progress when opening a network file.
CASE(EC_MARKER_HIT); // Not supported.
CASE(EC_NEED_RESTART); // A filter is requesting that the graph be restarted.
CASE(EC_NEW_PIN); // Not supported.
CASE(EC_NOTIFY_WINDOW); // Notifies a filter of the video renderer's window.
CASE(EC_OLE_EVENT); // A filter is passing a text string to the application.
CASE(EC_OPENING_FILE); // The graph is opening a file, or has finished opening a file.
CASE(EC_PALETTE_CHANGED); // The video palette has changed.
CASE(EC_PAUSED); // A pause request has completed.
CASE(EC_PLEASE_REOPEN); // The source file has changed.
CASE(EC_PREPROCESS_COMPLETE); // Sent by the WM ASF Writer filter when it completes the pre-processing for multipass encoding.
CASE(EC_PROCESSING_LATENCY); // Indicates the amount of time that a component is taking to process each sample.
CASE(EC_QUALITY_CHANGE); // The graph is dropping samples, for quality control.
//CASE(EC_RENDER_FINISHED); // Not supported.
CASE(EC_REPAINT); // A video renderer requires a repaint.
CASE(EC_SAMPLE_LATENCY); // Specifies how far behind schedule a component is for processing samples.
//CASE(EC_SAMPLE_NEEDED); // Requests a new input sample from the Enhanced Video Renderer (EVR) filter.
CASE(EC_SCRUB_TIME); // Specifies the time stamp for the most recent frame step.
CASE(EC_SEGMENT_STARTED); // A new segment has started.
CASE(EC_SHUTTING_DOWN); // The filter graph is shutting down, prior to being destroyed.
CASE(EC_SNDDEV_IN_ERROR); // A device error has occurred in an audio capture filter.
CASE(EC_SNDDEV_OUT_ERROR); // A device error has occurred in an audio renderer filter.
CASE(EC_STARVATION); // A filter is not receiving enough data.
CASE(EC_STATE_CHANGE); // The filter graph has changed state.
CASE(EC_STATUS); // Contains two arbitrary status strings.
CASE(EC_STEP_COMPLETE); // A filter performing frame stepping has stepped the specified number of frames.
CASE(EC_STREAM_CONTROL_STARTED); // A stream-control start command has taken effect.
CASE(EC_STREAM_CONTROL_STOPPED); // A stream-control stop command has taken effect.
CASE(EC_STREAM_ERROR_STILLPLAYING); // An error has occurred in a stream. The stream is still playing.
CASE(EC_STREAM_ERROR_STOPPED); // A stream has stopped because of an error.
CASE(EC_TIMECODE_AVAILABLE); // Not supported.
CASE(EC_UNBUILT); // Send by the Video Control when a graph has been torn down. Not forwarded to applications.
CASE(EC_USERABORT); // The user has terminated playback.
CASE(EC_VIDEO_SIZE_CHANGED); // The native video size has changed.
CASE(EC_VIDEOFRAMEREADY); // A video frame is ready for display.
CASE(EC_VMR_RECONNECTION_FAILED); // Sent by the VMR-7 and the VMR-9 when it was unable to accept a dynamic format change request from the upstream decoder.
CASE(EC_VMR_RENDERDEVICE_SET); // Sent when the VMR has selected its rendering mechanism.
CASE(EC_VMR_SURFACE_FLIPPED); // Sent when the VMR-7's allocator presenter has called the DirectDraw Flip method on the surface being presented.
CASE(EC_WINDOW_DESTROYED); // The video renderer was destroyed or removed from the graph.
CASE(EC_WMT_EVENT); // Sent by the WM ASF Reader filter when it reads ASF files protected by digital rights management (DRM).
CASE(EC_WMT_INDEX_EVENT); // Sent when an application uses the WM ASF Writer to index Windows Media Video files.
CASE(S_OK); // Success.
CASE(VFW_S_AUDIO_NOT_RENDERED); // Partial success; the audio was not rendered.
CASE(VFW_S_DUPLICATE_NAME); // Success; the Filter Graph Manager modified a filter name to avoid duplication.
CASE(VFW_S_PARTIAL_RENDER); // Partial success; some of the streams in this movie are in an unsupported format.
CASE(VFW_S_VIDEO_NOT_RENDERED); // Partial success; the video was not rendered.
CASE(E_ABORT); // Operation aborted.
CASE(E_OUTOFMEMORY); // Insufficient memory.
CASE(E_POINTER); // NULL pointer argument.
CASE(VFW_E_CANNOT_CONNECT); // No combination of intermediate filters could be found to make the connection.
CASE(VFW_E_CANNOT_RENDER); // No combination of filters could be found to render the stream.
CASE(VFW_E_NO_ACCEPTABLE_TYPES); // There is no common media type between these pins.
CASE(VFW_E_NOT_IN_GRAPH);
default:
return "Unknown Code";
};
#undef CASE
}
HRESULT
CreateAndAddFilter(IGraphBuilder* aGraph,
REFGUID aFilterClsId,
LPCWSTR aFilterName,
IBaseFilter **aOutFilter)
{
NS_ENSURE_TRUE(aGraph, E_POINTER);
NS_ENSURE_TRUE(aOutFilter, E_POINTER);
HRESULT hr;
nsRefPtr<IBaseFilter> filter;
hr = CoCreateInstance(aFilterClsId,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
getter_AddRefs(filter));
if (FAILED(hr)) {
// Object probably not available on this system.
return hr;
}
hr = aGraph->AddFilter(filter, aFilterName);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
filter.forget(aOutFilter);
return S_OK;
}
HRESULT
AddMP3DMOWrapperFilter(IGraphBuilder* aGraph,
IBaseFilter **aOutFilter)
{
NS_ENSURE_TRUE(aGraph, E_POINTER);
NS_ENSURE_TRUE(aOutFilter, E_POINTER);
HRESULT hr;
// Create the wrapper filter.
nsRefPtr<IBaseFilter> filter;
hr = CoCreateInstance(CLSID_DMOWrapperFilter,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
getter_AddRefs(filter));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
// Query for IDMOWrapperFilter.
nsRefPtr<IDMOWrapperFilter> dmoWrapper;
hr = filter->QueryInterface(IID_IDMOWrapperFilter,
getter_AddRefs(dmoWrapper));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = dmoWrapper->Init(CLSID_CMP3DecMediaObject, DMOCATEGORY_AUDIO_DECODER);
if (FAILED(hr)) {
// Can't instantiate MP3 DMO. It doesn't exist on Windows XP, we're
// probably hitting that. Don't log warning to console, this is an
// expected error.
return hr;
}
// Add the wrapper filter to graph.
hr = aGraph->AddFilter(filter, L"MP3 Decoder DMO");
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
filter.forget(aOutFilter);
return S_OK;
}
// Match a pin by pin direction and connection state.
HRESULT
MatchUnconnectedPin(IPin* aPin,
PIN_DIRECTION aPinDir,
bool *aOutMatches)
{
NS_ENSURE_TRUE(aPin, E_POINTER);
NS_ENSURE_TRUE(aOutMatches, E_POINTER);
// Ensure the pin is unconnected.
RefPtr<IPin> peer;
HRESULT hr = aPin->ConnectedTo(byRef(peer));
if (hr != VFW_E_NOT_CONNECTED) {
*aOutMatches = false;
return hr;
}
// Ensure the pin is of the specified direction.
PIN_DIRECTION pinDir;
hr = aPin->QueryDirection(&pinDir);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
*aOutMatches = (pinDir == aPinDir);
return S_OK;
}
// Return the first unconnected input pin or output pin.
TemporaryRef<IPin>
GetUnconnectedPin(IBaseFilter* aFilter, PIN_DIRECTION aPinDir)
{
RefPtr<IEnumPins> enumPins;
HRESULT hr = aFilter->EnumPins(byRef(enumPins));
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
// Test each pin to see if it matches the direction we're looking for.
RefPtr<IPin> pin;
while (S_OK == enumPins->Next(1, byRef(pin), NULL)) {
bool matches = FALSE;
if (SUCCEEDED(MatchUnconnectedPin(pin, aPinDir, &matches)) &&
matches) {
return pin;
}
}
return nullptr;
}
HRESULT
ConnectFilters(IGraphBuilder* aGraph,
IBaseFilter* aOutputFilter,
IBaseFilter* aInputFilter)
{
RefPtr<IPin> output = GetUnconnectedPin(aOutputFilter, PINDIR_OUTPUT);
NS_ENSURE_TRUE(output, E_FAIL);
RefPtr<IPin> input = GetUnconnectedPin(aInputFilter, PINDIR_INPUT);
NS_ENSURE_TRUE(output, E_FAIL);
return aGraph->Connect(output, input);
}
} // namespace mozilla

View File

@ -0,0 +1,115 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _DirectShowUtils_h_
#define _DirectShowUtils_h_
#include <stdint.h>
#include "dshow.h"
#include "DShowTools.h"
#include "prlog.h"
namespace mozilla {
// Win32 "Event" wrapper. Must be paired with a CriticalSection to create a
// Java-style "monitor".
class Signal {
public:
Signal(CriticalSection* aLock)
: mLock(aLock)
{
CriticalSectionAutoEnter lock(*mLock);
mEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
~Signal() {
CriticalSectionAutoEnter lock(*mLock);
CloseHandle(mEvent);
}
// Lock must be held.
void Notify() {
SetEvent(mEvent);
}
// Lock must be held. Check the wait condition before waiting!
HRESULT Wait() {
mLock->Leave();
DWORD result = WaitForSingleObject(mEvent, INFINITE);
mLock->Enter();
return result == WAIT_OBJECT_0 ? S_OK : E_FAIL;
}
private:
CriticalSection* mLock;
HANDLE mEvent;
};
HRESULT
AddGraphToRunningObjectTable(IUnknown *aUnkGraph, DWORD *aOutRotRegister);
void
RemoveGraphFromRunningObjectTable(DWORD aRotRegister);
const char*
GetGraphNotifyString(long evCode);
// Creates a filter and adds it to a graph.
HRESULT
CreateAndAddFilter(IGraphBuilder* aGraph,
REFGUID aFilterClsId,
LPCWSTR aFilterName,
IBaseFilter **aOutFilter);
HRESULT
AddMP3DMOWrapperFilter(IGraphBuilder* aGraph,
IBaseFilter **aOutFilter);
// Connects the output pin on aOutputFilter to an input pin on
// aInputFilter, in aGraph.
HRESULT
ConnectFilters(IGraphBuilder* aGraph,
IBaseFilter* aOutputFilter,
IBaseFilter* aInputFilter);
HRESULT
MatchUnconnectedPin(IPin* aPin,
PIN_DIRECTION aPinDir,
bool *aOutMatches);
// Converts from microseconds to DirectShow "Reference Time"
// (hundreds of nanoseconds).
inline int64_t
UsecsToRefTime(const int64_t aUsecs)
{
return aUsecs * 10;
}
// Converts from DirectShow "Reference Time" (hundreds of nanoseconds)
// to microseconds.
inline int64_t
RefTimeToUsecs(const int64_t hRefTime)
{
return hRefTime / 10;
}
// Converts from DirectShow "Reference Time" (hundreds of nanoseconds)
// to seconds.
inline double
RefTimeToSeconds(const REFERENCE_TIME aRefTime)
{
return double(aRefTime) / 10000000;
}
#if defined(PR_LOGGING)
const char*
GetDirectShowGuidName(const GUID& aGuid);
#endif
} // namespace mozilla
#endif

View File

@ -0,0 +1,23 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
FAIL_ON_WARNINGS := 1
LIBRARY_NAME = gkcondirectshow_s
LIBXUL_LIBRARY = 1
LOCAL_INCLUDES += -I$(topsrcdir)/media/webrtc/trunk/webrtc/modules/video_capture/windows/
ifeq ($(OS_ARCH),WINNT)
OS_CXXFLAGS += -DNOMINMAX
endif
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SampleSink.h"
#include "AudioSinkFilter.h"
#include "AudioSinkInputPin.h"
#include "VideoUtils.h"
#include "prlog.h"
using namespace mozilla::media;
namespace mozilla {
#ifdef PR_LOGGING
PRLogModuleInfo* GetDirectShowLog();
#define LOG(...) PR_LOG(GetDirectShowLog(), PR_LOG_DEBUG, (__VA_ARGS__))
#else
#define LOG(...)
#endif
SampleSink::SampleSink()
: mMonitor("SampleSink"),
mIsFlushing(false),
mAtEOS(false)
{
MOZ_COUNT_CTOR(SampleSink);
}
SampleSink::~SampleSink()
{
MOZ_COUNT_DTOR(SampleSink);
}
void
SampleSink::SetAudioFormat(const WAVEFORMATEX* aInFormat)
{
NS_ENSURE_TRUE(aInFormat, );
ReentrantMonitorAutoEnter mon(mMonitor);
memcpy(&mAudioFormat, aInFormat, sizeof(WAVEFORMATEX));
}
void
SampleSink::GetAudioFormat(WAVEFORMATEX* aOutFormat)
{
MOZ_ASSERT(aOutFormat);
ReentrantMonitorAutoEnter mon(mMonitor);
memcpy(aOutFormat, &mAudioFormat, sizeof(WAVEFORMATEX));
}
HRESULT
SampleSink::Receive(IMediaSample* aSample)
{
ReentrantMonitorAutoEnter mon(mMonitor);
while (true) {
if (mIsFlushing) {
return S_FALSE;
}
if (!mSample) {
break;
}
if (mAtEOS) {
return E_UNEXPECTED;
}
// Wait until the consumer thread consumes the sample.
mon.Wait();
}
#ifdef PR_LOGGING
REFERENCE_TIME start = 0, end = 0;
HRESULT hr = aSample->GetMediaTime(&start, &end);
LOG("SampleSink::Receive() [%4.2lf-%4.2lf]",
(double)RefTimeToUsecs(start) / USECS_PER_S,
(double)RefTimeToUsecs(end) / USECS_PER_S);
#endif
mSample = aSample;
// Notify the signal, to awaken the consumer thread in WaitForSample()
// if necessary.
mon.NotifyAll();
return S_OK;
}
HRESULT
SampleSink::Extract(RefPtr<IMediaSample>& aOutSample)
{
ReentrantMonitorAutoEnter mon(mMonitor);
// Loop until we have a sample, or we should abort.
while (true) {
if (mIsFlushing) {
return S_FALSE;
}
if (mSample) {
break;
}
if (mAtEOS) {
// Order is important here, if we have a sample, we should return it
// before reporting EOS.
return E_UNEXPECTED;
}
// Wait until the producer thread gives us a sample.
mon.Wait();
}
aOutSample = mSample;
#ifdef PR_LOGGING
int64_t start = 0, end = 0;
mSample->GetMediaTime(&start, &end);
LOG("SampleSink::Extract() [%4.2lf-%4.2lf]",
(double)RefTimeToUsecs(start) / USECS_PER_S,
(double)RefTimeToUsecs(end) / USECS_PER_S);
#endif
mSample = nullptr;
// Notify the signal, to awaken the producer thread in Receive()
// if necessary.
mon.NotifyAll();
return S_OK;
}
void
SampleSink::Flush()
{
LOG("SampleSink::Flush()");
ReentrantMonitorAutoEnter mon(mMonitor);
mIsFlushing = true;
mSample = nullptr;
mon.NotifyAll();
}
void
SampleSink::Reset()
{
LOG("SampleSink::Reset()");
ReentrantMonitorAutoEnter mon(mMonitor);
mIsFlushing = false;
mAtEOS = false;
}
void
SampleSink::SetEOS()
{
LOG("SampleSink::SetEOS()");
ReentrantMonitorAutoEnter mon(mMonitor);
mAtEOS = true;
// Notify to unblock any threads waiting for samples in
// Extract() or Receive(). Now that we're at EOS, no more samples
// will come!
mon.NotifyAll();
}
bool
SampleSink::AtEOS()
{
ReentrantMonitorAutoEnter mon(mMonitor);
return mAtEOS && !mSample;
}
} // namespace mozilla

View File

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(SampleSink_h_)
#define SampleSink_h_
#include "BaseFilter.h"
#include "DirectShowUtils.h"
#include "nsAutoPtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/ReentrantMonitor.h"
namespace mozilla {
class SampleSink {
public:
SampleSink();
virtual ~SampleSink();
// Sets the audio format of the incoming samples. The upstream filter
// calls this. This makes a copy.
void SetAudioFormat(const WAVEFORMATEX* aInFormat);
// Copies the format of incoming audio samples into into *aOutFormat.
void GetAudioFormat(WAVEFORMATEX* aOutFormat);
// Called when a sample is delivered by the DirectShow graph to the sink.
// The decode thread retrieves the sample by calling WaitForSample().
// Blocks if there's already a sample waiting to be consumed by the decode
// thread.
HRESULT Receive(IMediaSample* aSample);
// Retrieves a sample from the sample queue, blocking until one becomes
// available, or until an error occurs. Returns S_FALSE on EOS.
HRESULT Extract(RefPtr<IMediaSample>& aOutSample);
// Unblocks any threads waiting in GetSample().
// Clears mSample, which unblocks upstream stream.
void Flush();
// Opens up the sink to receive more samples in PutSample().
// Clears EOS flag.
void Reset();
// Marks that we've reacehd the end of stream.
void SetEOS();
// Returns whether we're at end of stream.
bool AtEOS();
private:
// All data in this class is syncronized by mMonitor.
ReentrantMonitor mMonitor;
RefPtr<IMediaSample> mSample;
// Format of the audio stream we're receiving.
WAVEFORMATEX mAudioFormat;
bool mIsFlushing;
bool mAtEOS;
};
} // namespace mozilla
#endif // SampleSink_h_

View File

@ -0,0 +1,638 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SourceFilter.h"
#include "MediaResource.h"
#include "mozilla/RefPtr.h"
#include "DirectShowUtils.h"
using namespace mozilla::media;
namespace mozilla {
// Define to trace what's on...
//#define DEBUG_SOURCE_TRACE 1
#if defined(PR_LOGGING) && defined (DEBUG_SOURCE_TRACE)
PRLogModuleInfo* GetDirectShowLog();
#define LOG(...) PR_LOG(GetDirectShowLog(), PR_LOG_DEBUG, (__VA_ARGS__))
#else
#define LOG(...)
#endif
static HRESULT
DoGetInterface(IUnknown* aUnknown, void** aInterface)
{
if (!aInterface)
return E_POINTER;
*aInterface = aUnknown;
aUnknown->AddRef();
return S_OK;
}
// Stores details of IAsyncReader::Request().
class ReadRequest {
public:
ReadRequest(IMediaSample* aSample,
DWORD_PTR aDwUser,
uint32_t aOffset,
uint32_t aCount)
: mSample(aSample),
mDwUser(aDwUser),
mOffset(aOffset),
mCount(aCount)
{
MOZ_COUNT_CTOR(ReadRequest);
}
~ReadRequest() {
MOZ_COUNT_DTOR(ReadRequest);
}
RefPtr<IMediaSample> mSample;
DWORD_PTR mDwUser;
uint32_t mOffset;
uint32_t mCount;
};
// Output pin for SourceFilter, which implements IAsyncReader, to
// allow downstream filters to pull/read data from it. Downstream pins
// register to read data using Request(), and asynchronously wait for the
// reads to complete using WaitForNext(). They may also synchronously read
// using SyncRead(). This class is a delegate (tear off) of
// SourceFilter.
//
// Implements:
// * IAsyncReader
// * IPin
// * IQualityControl
// * IUnknown
//
class DECLSPEC_UUID("18e5cfb2-1015-440c-a65c-e63853235894")
OutputPin : public IAsyncReader,
public BasePin
{
public:
OutputPin(MediaResource* aMediaResource,
SourceFilter* aParent,
CriticalSection& aFilterLock);
virtual ~OutputPin();
// IUnknown
// Defer to ref counting to BasePin, which defers to owning nsBaseFilter.
STDMETHODIMP_(ULONG) AddRef() MOZ_OVERRIDE { return BasePin::AddRef(); }
STDMETHODIMP_(ULONG) Release() MOZ_OVERRIDE { return BasePin::Release(); }
STDMETHODIMP QueryInterface(REFIID iid, void** ppv) MOZ_OVERRIDE;
// BasePin Overrides.
// Determines if the pin accepts a specific media type.
HRESULT CheckMediaType(const MediaType* aMediaType) MOZ_OVERRIDE;
// Retrieves a preferred media type, by index value.
HRESULT GetMediaType(int aPosition, MediaType* aMediaType) MOZ_OVERRIDE;
// Releases the pin from a connection.
HRESULT BreakConnect(void) MOZ_OVERRIDE;
// Determines whether a pin connection is suitable.
HRESULT CheckConnect(IPin* aPin) MOZ_OVERRIDE;
// IAsyncReader overrides
// The RequestAllocator method requests an allocator during the
// pin connection.
STDMETHODIMP RequestAllocator(IMemAllocator* aPreferred,
ALLOCATOR_PROPERTIES* aProps,
IMemAllocator** aActual) MOZ_OVERRIDE;
// The Request method queues an asynchronous request for data. Downstream
// will call WaitForNext() when they want to retrieve the result.
STDMETHODIMP Request(IMediaSample* aSample, DWORD_PTR aUserData) MOZ_OVERRIDE;
// The WaitForNext method waits for the next pending read request
// to complete. This method fails if the graph is flushing.
// Defers to SyncRead/5.
STDMETHODIMP WaitForNext(DWORD aTimeout,
IMediaSample** aSamples,
DWORD_PTR* aUserData) MOZ_OVERRIDE;
// The SyncReadAligned method performs a synchronous read. The method
// blocks until the request is completed. Defers to SyncRead/5. This
// method does not fail if the graph is flushing.
STDMETHODIMP SyncReadAligned(IMediaSample* aSample) MOZ_OVERRIDE;
// The SyncRead method performs a synchronous read. The method blocks
// until the request is completed. Defers to SyncRead/5. This
// method does not fail if the graph is flushing.
STDMETHODIMP SyncRead(LONGLONG aPosition, LONG aLength, BYTE* aBuffer) MOZ_OVERRIDE;
// The Length method retrieves the total length of the stream.
STDMETHODIMP Length(LONGLONG* aTotal, LONGLONG* aAvailable) MOZ_OVERRIDE;
// IPin Overrides
STDMETHODIMP BeginFlush(void) MOZ_OVERRIDE;
STDMETHODIMP EndFlush(void) MOZ_OVERRIDE;
uint32_t GetAndResetBytesConsumedCount();
private:
// Protects thread-shared data/structures (mFlushCount, mPendingReads).
// WaitForNext() also waits on this monitor
CriticalSection& mPinLock;
// Signal used with mPinLock to implement WaitForNext().
Signal mSignal;
// The filter that owns us. Weak reference, as we're a delegate (tear off).
SourceFilter* mParentSource;
// MediaResource from which we read data.
RefPtr<MediaResource> mResource;
// Counter, inc'd in BeginFlush(), dec'd in EndFlush(). Calls to this can
// come from multiple threads and can interleave, hence the counter.
int32_t mFlushCount;
// Number of bytes that have been read from the output pin since the last
// time GetAndResetBytesConsumedCount() was called.
uint32_t mBytesConsumed;
// Deque of ReadRequest* for reads that are yet to be serviced.
// nsReadRequest's are stored on the heap, popper must delete them.
nsDeque mPendingReads;
// Flags if the downstream pin has QI'd for IAsyncReader. We refuse
// connection if they don't query, as it means they're assuming that we're
// a push filter, and we're not.
bool mQueriedForAsyncReader;
};
OutputPin::OutputPin(MediaResource* aResource,
SourceFilter* aParent,
CriticalSection& aFilterLock)
: BasePin(static_cast<BaseFilter*>(aParent),
&aFilterLock,
L"MozillaOutputPin",
PINDIR_OUTPUT),
mPinLock(aFilterLock),
mSignal(&mPinLock),
mParentSource(aParent),
mResource(aResource),
mFlushCount(0),
mBytesConsumed(0),
mQueriedForAsyncReader(false)
{
MOZ_COUNT_CTOR(OutputPin);
LOG("OutputPin::OutputPin()");
mResource->Seek(nsISeekableStream::NS_SEEK_SET, 0);
}
OutputPin::~OutputPin()
{
MOZ_COUNT_DTOR(OutputPin);
LOG("OutputPin::~OutputPin()");
}
HRESULT
OutputPin::BreakConnect()
{
mQueriedForAsyncReader = false;
return BasePin::BreakConnect();
}
STDMETHODIMP
OutputPin::QueryInterface(REFIID aIId, void** aInterface)
{
if (aIId == IID_IAsyncReader) {
mQueriedForAsyncReader = true;
return DoGetInterface(static_cast<IAsyncReader*>(this), aInterface);
}
if (aIId == __uuidof(OutputPin)) {
AddRef();
*aInterface = this;
return S_OK;
}
return BasePin::QueryInterface(aIId, aInterface);
}
HRESULT
OutputPin::CheckConnect(IPin* aPin)
{
// Our connection is only suitable if the downstream pin knows
// that we're asynchronous (i.e. it queried for IAsyncReader).
return mQueriedForAsyncReader ? S_OK : S_FALSE;
}
HRESULT
OutputPin::CheckMediaType(const MediaType* aMediaType)
{
const MediaType *myMediaType = mParentSource->GetMediaType();
if (IsEqualGUID(aMediaType->majortype, myMediaType->majortype) &&
IsEqualGUID(aMediaType->subtype, myMediaType->subtype) &&
IsEqualGUID(aMediaType->formattype, myMediaType->formattype))
{
LOG("OutputPin::CheckMediaType() Match: major=%s minor=%s TC=%d FSS=%d SS=%u",
GetDirectShowGuidName(aMediaType->majortype),
GetDirectShowGuidName(aMediaType->subtype),
aMediaType->TemporalCompression(),
aMediaType->bFixedSizeSamples,
aMediaType->SampleSize());
return S_OK;
}
LOG("OutputPin::CheckMediaType() Failed to match: major=%s minor=%s TC=%d FSS=%d SS=%u",
GetDirectShowGuidName(aMediaType->majortype),
GetDirectShowGuidName(aMediaType->subtype),
aMediaType->TemporalCompression(),
aMediaType->bFixedSizeSamples,
aMediaType->SampleSize());
return S_FALSE;
}
HRESULT
OutputPin::GetMediaType(int aPosition, MediaType* aMediaType)
{
if (!aMediaType)
return E_POINTER;
if (aPosition == 0) {
aMediaType->Assign(mParentSource->GetMediaType());
return S_OK;
}
return VFW_S_NO_MORE_ITEMS;
}
static inline bool
IsPowerOf2(int32_t x) {
return ((-x & x) != x);
}
STDMETHODIMP
OutputPin::RequestAllocator(IMemAllocator* aPreferred,
ALLOCATOR_PROPERTIES* aProps,
IMemAllocator** aActual)
{
// Require the downstream pin to suggest what they want...
if (!aPreferred) return E_POINTER;
if (!aProps) return E_POINTER;
if (!aActual) return E_POINTER;
// We only care about alignment - our allocator will reject anything
// which isn't power-of-2 aligned, so so try a 4-byte aligned allocator.
ALLOCATOR_PROPERTIES props;
memcpy(&props, aProps, sizeof(ALLOCATOR_PROPERTIES));
if (aProps->cbAlign == 0 || IsPowerOf2(aProps->cbAlign)) {
props.cbAlign = 4;
}
// Limit allocator's number of buffers. We know that the media will most
// likely be bound by network speed, not by decoding speed. We also
// store the incoming data in a Gecko stream, if we don't limit buffers
// here we'll end up duplicating a lot of storage. We must have enough
// space for audio key frames to fit in the first batch of buffers however,
// else pausing may fail for some downstream decoders.
if (props.cBuffers > BaseFilter::sMaxNumBuffers) {
props.cBuffers = BaseFilter::sMaxNumBuffers;
}
// The allocator properties that are actually used. We don't store
// this, we need it for SetProperties() below to succeed.
ALLOCATOR_PROPERTIES actualProps;
HRESULT hr;
if (aPreferred) {
// Play nice and prefer the downstream pin's preferred allocator.
hr = aPreferred->SetProperties(&props, &actualProps);
if (SUCCEEDED(hr)) {
aPreferred->AddRef();
*aActual = aPreferred;
return S_OK;
}
}
// Else downstream hasn't requested a specific allocator, so create one...
// Just create a default allocator. It's highly unlikely that we'll use
// this anyway, as most parsers insist on using their own allocators.
nsRefPtr<IMemAllocator> allocator;
hr = CoCreateInstance(CLSID_MemoryAllocator,
0,
CLSCTX_INPROC_SERVER,
IID_IMemAllocator,
getter_AddRefs(allocator));
if(FAILED(hr) || (allocator == NULL)) {
NS_WARNING("Can't create our own DirectShow allocator.");
return hr;
}
// See if we can make it suitable
hr = allocator->SetProperties(&props, &actualProps);
if (SUCCEEDED(hr)) {
// We need to release our refcount on pAlloc, and addref
// it to pass a refcount to the caller - this is a net nothing.
allocator.forget(aActual);
return S_OK;
}
NS_WARNING("Failed to pick an allocator");
return hr;
}
STDMETHODIMP
OutputPin::Request(IMediaSample* aSample, DWORD_PTR aDwUser)
{
if (!aSample) return E_FAIL;
CriticalSectionAutoEnter lock(*mLock);
NS_ASSERTION(!mFlushCount, __FUNCTION__"() while flushing");
if (mFlushCount)
return VFW_E_WRONG_STATE;
REFERENCE_TIME refStart = 0, refEnd = 0;
if (FAILED(aSample->GetTime(&refStart, &refEnd))) {
NS_WARNING("Sample incorrectly timestamped");
return VFW_E_SAMPLE_TIME_NOT_SET;
}
// Convert reference time to bytes.
uint32_t start = (uint32_t)(refStart / 10000000);
uint32_t end = (uint32_t)(refEnd / 10000000);
uint32_t numBytes = end - start;
ReadRequest* request = new ReadRequest(aSample,
aDwUser,
start,
numBytes);
// Memory for |request| is free when it's popped from the completed
// reads list.
// Push this onto the queue of reads to be serviced.
mPendingReads.Push(request);
// Notify any threads blocked in WaitForNext() which are waiting for mPendingReads
// to become non-empty.
mSignal.Notify();
return S_OK;
}
STDMETHODIMP
OutputPin::WaitForNext(DWORD aTimeout,
IMediaSample** aOutSample,
DWORD_PTR* aOutDwUser)
{
NS_ASSERTION(aTimeout == 0 || aTimeout == INFINITE,
"Oops, we don't handle this!");
*aOutSample = NULL;
*aOutDwUser = 0;
LONGLONG offset = 0;
LONG count = 0;
BYTE* buf = nullptr;
{
CriticalSectionAutoEnter lock(*mLock);
// Wait until there's a pending read to service.
while (aTimeout && mPendingReads.GetSize() == 0 && !mFlushCount) {
// Note: No need to guard against shutdown-during-wait here, as
// typically the thread doing the pull will have already called
// Request(), so we won't Wait() here anyway. SyncRead() will fail
// on shutdown.
mSignal.Wait();
}
nsAutoPtr<ReadRequest> request = reinterpret_cast<ReadRequest*>(mPendingReads.PopFront());
if (!request)
return VFW_E_WRONG_STATE;
*aOutSample = request->mSample;
*aOutDwUser = request->mDwUser;
offset = request->mOffset;
count = request->mCount;
buf = nullptr;
request->mSample->GetPointer(&buf);
NS_ASSERTION(buf != nullptr, "Invalid buffer!");
if (mFlushCount) {
return VFW_E_TIMEOUT;
}
}
return SyncRead(offset, count, buf);
}
STDMETHODIMP
OutputPin::SyncReadAligned(IMediaSample* aSample)
{
{
// Ignore reads while flushing.
CriticalSectionAutoEnter lock(*mLock);
if (mFlushCount) {
return S_FALSE;
}
}
if (!aSample)
return E_FAIL;
REFERENCE_TIME lStart = 0, lEnd = 0;
if (FAILED(aSample->GetTime(&lStart, &lEnd))) {
NS_WARNING("Sample incorrectly timestamped");
return VFW_E_SAMPLE_TIME_NOT_SET;
}
// Convert reference time to bytes.
int32_t start = (int32_t)(lStart / 10000000);
int32_t end = (int32_t)(lEnd / 10000000);
int32_t numBytes = end - start;
// If the range extends off the end of stream, truncate to the end of stream
// as per IAsyncReader specificiation.
int64_t streamLength = mResource->GetLength();
if (streamLength != -1) {
// We know the exact length of the stream, fail if the requested offset
// is beyond it.
if (start > streamLength) {
return VFW_E_BADALIGN;
}
// If the end of the chunk to read is off the end of the stream,
// truncate it to the end of the stream.
if ((start + numBytes) > streamLength) {
numBytes = (uint32_t)(streamLength - start);
}
}
BYTE* buf=0;
aSample->GetPointer(&buf);
return SyncRead(start, numBytes, buf);
}
STDMETHODIMP
OutputPin::SyncRead(LONGLONG aPosition,
LONG aLength,
BYTE* aBuffer)
{
MOZ_ASSERT(!NS_IsMainThread());
NS_ENSURE_TRUE(aPosition >= 0, E_FAIL);
NS_ENSURE_TRUE(aLength > 0, E_FAIL);
NS_ENSURE_TRUE(aBuffer, E_POINTER);
LOG("OutputPin::SyncRead(%lld, %d)", aPosition, aLength);
{
// Ignore reads while flushing.
CriticalSectionAutoEnter lock(*mLock);
if (mFlushCount) {
return S_FALSE;
}
}
// Read in a loop to ensure we fill the buffer, when possible.
LONG totalBytesRead = 0;
while (totalBytesRead < aLength) {
BYTE* readBuffer = aBuffer + totalBytesRead;
uint32_t bytesRead = 0;
LONG length = aLength - totalBytesRead;
nsresult rv = mResource->ReadAt(aPosition + totalBytesRead,
reinterpret_cast<char*>(readBuffer),
length,
&bytesRead);
if (NS_FAILED(rv)) {
return E_FAIL;
}
totalBytesRead += bytesRead;
if (bytesRead == 0) {
break;
}
}
if (totalBytesRead > 0) {
CriticalSectionAutoEnter lock(*mLock);
mBytesConsumed += totalBytesRead;
}
return (totalBytesRead == aLength) ? S_OK : S_FALSE;
}
STDMETHODIMP
OutputPin::Length(LONGLONG* aTotal, LONGLONG* aAvailable)
{
HRESULT hr = S_OK;
int64_t length = mResource->GetLength();
if (length == -1) {
hr = VFW_S_ESTIMATED;
// Don't have a length. Just lie, it seems to work...
*aTotal = INT32_MAX;
} else {
*aTotal = length;
}
if (aAvailable) {
*aAvailable = mResource->GetCachedDataEnd(mResource->Tell());
}
LOG("OutputPin::Length() len=%lld avail=%lld", *aTotal, *aAvailable);
return hr;
}
STDMETHODIMP
OutputPin::BeginFlush()
{
CriticalSectionAutoEnter lock(*mLock);
mFlushCount++;
mSignal.Notify();
return S_OK;
}
STDMETHODIMP
OutputPin::EndFlush(void)
{
CriticalSectionAutoEnter lock(*mLock);
mFlushCount--;
return S_OK;
}
uint32_t
OutputPin::GetAndResetBytesConsumedCount()
{
CriticalSectionAutoEnter lock(*mLock);
uint32_t bytesConsumed = mBytesConsumed;
mBytesConsumed = 0;
return bytesConsumed;
}
SourceFilter::SourceFilter(const GUID& aMajorType,
const GUID& aSubType)
: BaseFilter(L"MozillaDirectShowSource", __uuidof(SourceFilter))
{
MOZ_COUNT_CTOR(SourceFilter);
mMediaType.majortype = aMajorType;
mMediaType.subtype = aSubType;
LOG("SourceFilter Constructor(%s, %s)",
GetDirectShowGuidName(aMajorType),
GetDirectShowGuidName(aSubType));
}
SourceFilter::~SourceFilter()
{
MOZ_COUNT_DTOR(SourceFilter);
LOG("SourceFilter Destructor()");
}
BasePin*
SourceFilter::GetPin(int n)
{
if (n == 0) {
NS_ASSERTION(mOutputPin != 0, "GetPin with no pin!");
return static_cast<BasePin*>(mOutputPin);
} else {
return NULL;
}
}
// Get's the media type we're supplying.
const MediaType*
SourceFilter::GetMediaType() const
{
return &mMediaType;
}
nsresult
SourceFilter::Init(MediaResource* aResource)
{
LOG("SourceFilter::Init()");
mOutputPin = new OutputPin(aResource,
this,
mLock);
NS_ENSURE_TRUE(mOutputPin != nullptr, NS_ERROR_FAILURE);
return NS_OK;
}
uint32_t
SourceFilter::GetAndResetBytesConsumedCount()
{
return mOutputPin->GetAndResetBytesConsumedCount();
}
} // namespace mozilla

View File

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(nsDirectShowSource_h___)
#define nsDirectShowSource_h___
#include "BaseFilter.h"
#include "BasePin.h"
#include "MediaType.h"
#include "nsDeque.h"
#include "nsAutoPtr.h"
#include "DirectShowUtils.h"
#include "mozilla/RefPtr.h"
namespace mozilla {
class MediaResource;
class ReadRequest;
class OutputPin;
// SourceFilter is an asynchronous DirectShow source filter which
// reads from an MediaResource, and supplies data via a pull model downstream
// using OutputPin. It us used to supply a generic byte stream into
// DirectShow.
//
// Implements:
// * IBaseFilter
// * IMediaFilter
// * IPersist
// * IUnknown
//
class DECLSPEC_UUID("5c2a7ad0-ba82-4659-9178-c4719a2765d6")
SourceFilter : public media::BaseFilter
{
public:
// Constructs source filter to deliver given media type.
SourceFilter(const GUID& aMajorType, const GUID& aSubType);
~SourceFilter();
nsresult Init(MediaResource *aResource);
// BaseFilter overrides.
// Only one output - the byte stream.
int GetPinCount() MOZ_OVERRIDE { return 1; }
media::BasePin* GetPin(int n) MOZ_OVERRIDE;
// Get's the media type we're supplying.
const media::MediaType* GetMediaType() const;
uint32_t GetAndResetBytesConsumedCount();
protected:
// Our async pull output pin.
nsAutoPtr<OutputPin> mOutputPin;
// Type of byte stream we output.
media::MediaType mMediaType;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,35 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'content'
EXPORTS += [
'AudioSinkFilter.h',
'AudioSinkInputPin.h',
'DirectShowDecoder.h',
'DirectShowReader.h',
'DirectShowUtils.h',
]
CPP_SOURCES += [
'AudioSinkFilter.cpp',
'AudioSinkInputPin.cpp',
'DirectShowDecoder.cpp',
'DirectShowReader.cpp',
'DirectShowUtils.cpp',
'SampleSink.cpp',
'SourceFilter.cpp',
]
# If WebRTC isn't being built, we need to compile the DirectShow base classes so that
# they're available at link time.
if not CONFIG['MOZ_WEBRTC_IN_LIBXUL']:
CPP_SOURCES += [
TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseFilter.cpp',
TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseInputPin.cpp',
TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BasePin.cpp',
TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/MediaType.cpp',
]

View File

@ -28,6 +28,9 @@ if CONFIG['MOZ_GSTREAMER']:
if CONFIG['MOZ_DASH']:
PARALLEL_DIRS += ['dash']
if CONFIG['MOZ_DIRECTSHOW']:
PARALLEL_DIRS += ['directshow']
if CONFIG['MOZ_MEDIA_PLUGINS']:
PARALLEL_DIRS += ['plugins']

View File

@ -26,13 +26,11 @@ function IsWindowsVistaOrLater() {
return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.0;
}
function IsWindows7() {
var re = /Windows NT (\d.\d)/;
var winver = navigator.userAgent.match(re);
return winver && winver.length == 2 && parseFloat(winver[1]) == 6.1;
function IsWindows() {
return navigator.userAgent.match(/Windows/) != null;
}
function getMediaPref(name) {
function getPref(name) {
var pref = false;
try {
pref = SpecialPowers.getBoolPref(name);
@ -40,20 +38,18 @@ function getMediaPref(name) {
return pref;
}
var haveMp4 = (getMediaPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
getMediaPref("media.omx.enabled") ||
getMediaPref("media.gstreamer.enabled");
// TODO: Add "getMediaPref("media.plugins.enabled")" once MP4 works on Gingerbread.
var haveMp4 = (getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
getPref("media.omx.enabled") ||
getPref("media.gstreamer.enabled");
// TODO: Add "getPref("media.plugins.enabled")" once MP4 works on Gingerbread.
check_mp4(document.getElementById('v'), haveMp4);
if (!IsWindows7()) {
// Don't check MP3 support on Windows 7. MP3 is disabled on Win7SP0 (bug 852915),
// and there's no easy way from JS to distinguish which service pack is installed
// on a users system, so we just won't test it. We'll get MP3 support on Win7SP0
// via DirectShow once bug 861693 lands.
check_mp3(document.getElementById('v'), haveMp4);
}
var haveMp3 = getPref("media.directshow.enabled") ||
(getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
getPref("media.omx.enabled") ||
getPref("media.gstreamer.enabled");
check_mp3(document.getElementById('v'), haveMp3);
mediaTestCleanup();
</script>

View File

@ -121,8 +121,8 @@ var tests = [
numberOfChannels: 2,
duration: 0.6936,
length: 33294,
fuzzTolerance: 12,
fuzzToleranceMobile: 15826
fuzzTolerance: 38,
fuzzToleranceMobile: 15906
},
// An ogg file with two different channels, 44.1khz
{
@ -133,8 +133,8 @@ var tests = [
numberOfChannels: 2,
duration: 0.6932,
length: 33274,
fuzzTolerance: 16,
fuzzToleranceMobile: 16713
fuzzTolerance: 39,
fuzzToleranceMobile: 16798
},
// An ogg file with two different channels, 48khz
{

View File

@ -12,6 +12,10 @@
#include "mozilla/Preferences.h"
#include "WinUtils.h"
#ifdef MOZ_DIRECTSHOW
#include "DirectShowDecoder.h"
#endif
using namespace mozilla::widget;
namespace mozilla {
@ -26,7 +30,14 @@ bool
WMFDecoder::IsMP3Supported()
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
if (!MediaDecoder::IsWMFEnabled()) {
#ifdef MOZ_DIRECTSHOW
if (DirectShowDecoder::IsEnabled()) {
// DirectShowDecoder is enabled, we use that in preference to the WMF
// backend.
return false;
}
#endif
if (!MediaDecoder::IsWMFEnabled()) {
return false;
}
if (WinUtils::GetWindowsVersion() != WinUtils::WIN7_VERSION) {

View File

@ -11,8 +11,8 @@
namespace mozilla {
// Decoder that uses Windows Media Foundation to playback H.264/AAC in MP4
// and M4A files, and MP3 files. Playback is strictly limited to only those
// codecs.
// and M4A files, and MP3 files if the DirectShow backend is disabled.
// Playback is strictly limited to only those codecs.
class WMFDecoder : public MediaDecoder
{
public:

View File

@ -20,8 +20,8 @@ namespace dom {
class TimeRanges;
}
// Decoder backend for reading H.264/AAC in MP4/M4A and MP3 audio files,
// using Windows Media Foundation.
// Decoder backend for reading H.264/AAC in MP4/M4A, and MP3 files using
// Windows Media Foundation.
class WMFReader : public MediaDecoderReader
{
public:

View File

@ -9,6 +9,7 @@
#include "gfxPoint.h"
#include "nsDebug.h"
#include "nsMemory.h"
#include "prtypes.h"
namespace mozilla {

View File

@ -9,6 +9,7 @@
#include "nsServiceManagerUtils.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsIPluginHost.h"
#include "nsIDocShell.h"
#include "nsContentUtils.h"
#include "imgLoader.h"
@ -50,7 +51,15 @@ nsWebNavigationInfo::IsTypeSupported(const nsACString& aType,
if (*aIsTypeSupported) {
return rv;
}
// If this request is for a docShell that isn't going to allow plugins,
// there's no need to try and find a plugin to handle it.
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aWebNav));
bool allowed;
if (docShell && NS_SUCCEEDED(docShell->GetAllowPlugins(&allowed)) && !allowed) {
return NS_OK;
}
// Try reloading plugins in case they've changed.
nsCOMPtr<nsIPluginHost> pluginHost =
do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);

View File

@ -1195,7 +1195,7 @@ nsDOMClassInfo::Init()
AutoSafeJSContext cx;
DOM_CLASSINFO_MAP_BEGIN(Window, nsIDOMWindow)
DOM_CLASSINFO_WINDOW_MAP_ENTRIES(nsGlobalWindow::HasIndexedDBSupport())
DOM_CLASSINFO_WINDOW_MAP_ENTRIES(true)
#ifdef MOZ_WEBSPEECH
DOM_CLASSINFO_MAP_ENTRY(nsISpeechSynthesisGetter)
#endif
@ -1390,7 +1390,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ModalContentWindow, nsIDOMWindow)
DOM_CLASSINFO_WINDOW_MAP_ENTRIES(nsGlobalWindow::HasIndexedDBSupport())
DOM_CLASSINFO_WINDOW_MAP_ENTRIES(true)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMModalContentWindow)
#ifdef MOZ_WEBSPEECH
DOM_CLASSINFO_MAP_ENTRY(nsISpeechSynthesisGetter)

View File

@ -11436,13 +11436,6 @@ nsGlobalWindow::DisableTimeChangeNotifications()
nsSystemTimeChangeObserver::RemoveWindowListener(this);
}
// static
bool
nsGlobalWindow::HasIndexedDBSupport()
{
return Preferences::GetBool("indexedDB.feature.enabled", true);
}
static size_t
SizeOfEventTargetObjectsEntryExcludingThisFun(
nsPtrHashKey<nsDOMEventTargetHelper> *aEntry,

View File

@ -668,8 +668,6 @@ public:
return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nullptr;
}
static bool HasIndexedDBSupport();
static WindowByIdTable* GetWindowsTable() {
return sWindowsById;
}

View File

@ -30,9 +30,6 @@
#include "mozilla/layers/PCompositorChild.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/Preferences.h"
#ifdef MOZ_CONTENT_SANDBOX
#include "mozilla/Sandbox.h"
#endif
#include "mozilla/unused.h"
#include "nsIMemoryReporter.h"
@ -549,13 +546,6 @@ ContentChild::RecvSetProcessPrivileges(const ChildPrivileges& aPrivs)
aPrivs;
// If this fails, we die.
SetCurrentProcessPrivileges(privs);
#ifdef MOZ_CONTENT_SANDBOX
// SetCurrentProcessSandbox should be moved close to process initialization
// time if/when possible. SetCurrentProcessPrivileges should probably be
// moved as well. Right now this is set ONLY if we receive the
// RecvSetProcessPrivileges message. See bug 880808.
SetCurrentProcessSandbox();
#endif
return true;
}

View File

@ -172,7 +172,7 @@ nsPluginInstanceOwner::GetImageContainer()
data.mShareType = mozilla::gl::GLContext::SameProcess;
data.mInverted = mInstance->Inverted();
gfxRect r = GetPluginRect();
LayoutDeviceRect r = GetPluginRect();
data.mSize = gfxIntSize(r.width, r.height);
SharedTextureImage* pluginImage = static_cast<SharedTextureImage*>(img.get());
@ -182,8 +182,8 @@ nsPluginInstanceOwner::GetImageContainer()
float xResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetXResolution();
float yResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetYResolution();
r.Scale(xResolution, yResolution);
mInstance->NotifySize(nsIntSize(r.width, r.height));
ScreenSize screenSize = (r * LayoutDeviceToScreenScale(xResolution, yResolution)).Size();
mInstance->NotifySize(nsIntSize(screenSize.width, screenSize.height));
return container.forget();
#endif
@ -1620,16 +1620,15 @@ GetOffsetRootContent(nsIFrame* aFrame)
return offset;
}
gfxRect nsPluginInstanceOwner::GetPluginRect()
LayoutDeviceRect nsPluginInstanceOwner::GetPluginRect()
{
// Get the offset of the content relative to the page
nsRect bounds = mObjectFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mObjectFrame);
nsIntRect intBounds = bounds.ToNearestPixels(mObjectFrame->PresContext()->AppUnitsPerDevPixel());
return gfxRect(intBounds);
LayoutDeviceIntRect rect = LayoutDeviceIntRect::FromAppUnitsToNearest(bounds, mObjectFrame->PresContext()->AppUnitsPerDevPixel());
return LayoutDeviceRect(rect);
}
bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect /* = gfxRect(0, 0, 0, 0) */)
bool nsPluginInstanceOwner::AddPluginView(const LayoutDeviceRect& aRect /* = LayoutDeviceRect(0, 0, 0, 0) */)
{
if (!mJavaView) {
mJavaView = mInstance->GetJavaSurface();

View File

@ -260,8 +260,8 @@ private:
void FixUpURLS(const nsString &name, nsAString &value);
#ifdef MOZ_WIDGET_ANDROID
gfxRect GetPluginRect();
bool AddPluginView(const gfxRect& aRect = gfxRect(0, 0, 0, 0));
mozilla::LayoutDeviceRect GetPluginRect();
bool AddPluginView(const mozilla::LayoutDeviceRect& aRect = mozilla::LayoutDeviceRect(0, 0, 0, 0));
void RemovePluginView();
bool mFullScreen;

5874
gfx/gl/GLConsts.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1994,7 +1994,7 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
do {
// calculate portion of the tile that is going to be painted to
nsIntRect dstSubRect;
nsIntRect dstTextureRect = aDst->GetTileRect();
nsIntRect dstTextureRect = ThebesIntRect(aDst->GetTileRect());
dstSubRect.IntersectRect(aDstRect, dstTextureRect);
// this tile is not part of the destination rectangle aDstRect
@ -2016,7 +2016,7 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
do {
// calculate portion of the source tile that is in the source rect
nsIntRect srcSubRect;
nsIntRect srcTextureRect = aSrc->GetTileRect();
nsIntRect srcTextureRect = ThebesIntRect(aSrc->GetTileRect());
srcSubRect.IntersectRect(aSrcRect, srcTextureRect);
// this tile is not part of the source rect

File diff suppressed because it is too large Load Diff

212
gfx/gl/GLParseRegistryXML.py Executable file
View File

@ -0,0 +1,212 @@
#!/usr/bin/env python
# coding=utf8
################################################################################
# TUTORIAL
# This script will generate GLConsts.h
#
# Step 1:
# Download the last gl.xml, egl.xml, glx.xml and wgl.xml from
# http://www.opengl.org/registry/#specfiles into a directory of your choice
#
# Step 2:
# Execute this script ./GLParseRegistryXML.py [your dir containing XML files]
#
# Step 3:
# Do not add the downloaded XML in the patch
#
# Step 4:
# Enjoy =)
#
################################################################################
# includes
import os
import sys
import xml.etree.ElementTree
################################################################################
# export management
class GLConstHeader:
def __init__(self, f):
self.f = f
def write(self, arg):
if isinstance(arg, list):
self.f.write('\n'.join(arg) + '\n')
elif isinstance(arg, (int, long)):
self.f.write('\n' * arg)
else:
self.f.write(str(arg) + '\n')
def formatFileBegin(self):
self.write([
'/* This Source Code Form is subject to the terms of the Mozilla Public',
' * License, v. 2.0. If a copy of the MPL was not distributed with this',
' * file, You can obtain one at http://mozilla.org/MPL/2.0/. */',
'',
'#if !defined(GLCONSTS_H_)',
'#define GLCONSTS_H_',
'',
'/**',
' * GENERATED FILE, DO NOT MODIFY DIRECTLY.',
' * THIS IS A GENERATED FILE DIRECTLY FROM THE OFFCIAL OPENGL REGISTRY',
' * XML AVAILABLE AT http://www.opengl.org/registry/#specfiles.',
' *',
' * To generate this file, see tutorial in GLParseRegistry.py',
' */',
''
])
def formatLibBegin(self, lib):
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
self.write('// ' + lib)
def formatLibConstant(self, lib, name, value):
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
# name is the name of the const (example: MAX_TEXTURE_SIZE)
# value is the value of the const (example: 0xABCD)
define = '#define LOCAL_' + lib + '_' + name
whitespace = max(60 - len(define), 0)
self.write(define + ' ' * whitespace + ' ' + value)
def formatLibEnd(self, lib):
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
self.write(2)
def formatFileEnd(self):
self.write([
'',
'#endif // GLCONSTS_H_'
])
################################################################################
# underground code
def getScriptDir():
return os.path.dirname(__file__) + '/'
def getXMLDir():
if len(sys.argv) == 1:
return './'
dirPath = sys.argv[1]
if dirPath[-1] != '/':
dirPath += '/'
return dirPath
class GLConst:
def __init__(self, lib, name, value, type):
self.lib = lib
self.name = name
self.value = value
self.type = type
class GLDatabase:
LIBS = ['GL', 'EGL', 'GLX', 'WGL']
def __init__(self):
self.consts = {}
self.libs = set(GLDatabase.LIBS)
self.vendors = set(['EXT', 'ATI'])
# there is no vendor="EXT" and vendor="ATI" in gl.xml,
# so we manualy declare them
def loadXML(self, path):
xmlPath = getXMLDir() + path
if not os.path.isfile(xmlPath):
print 'missing file "' + xmlPath + '"'
return False
tree = xml.etree.ElementTree.parse(xmlPath)
root = tree.getroot()
for enums in root.iter('enums'):
vendor = enums.get('vendor')
if not vendor:
# there some standart enums that do have the vendor attribute,
# so we fake them as ARB's enums
vendor = 'ARB'
if vendor not in self.vendors:
# we map this new vendor in the vendors set.
self.vendors.add(vendor)
namespaceType = enums.get('type')
for enum in enums:
if enum.tag != 'enum':
# this is not an enum => we skip it
continue
lib = enum.get('name').split('_')[0]
if lib not in self.libs:
# unknown library => we skip it
continue
name = enum.get('name')[len(lib) + 1:]
value = enum.get('value')
type = enum.get('type')
if not type:
# if no type specified, we get the namespace's default type
type = namespaceType
self.consts[lib + '_' + name] = GLConst(lib, name, value, type)
return True
def exportConsts(self, path):
with open(getScriptDir() + path,'w') as f:
headerFile = GLConstHeader(f)
headerFile.formatFileBegin()
constNames = self.consts.keys()
constNames.sort()
for lib in GLDatabase.LIBS:
headerFile.formatLibBegin(lib)
for constName in constNames:
const = self.consts[constName]
if const.lib != lib:
continue
headerFile.formatLibConstant(lib, const.name, const.value)
headerFile.formatLibEnd(lib)
headerFile.formatFileEnd()
glDatabase = GLDatabase()
success = glDatabase.loadXML('gl.xml')
success = success and glDatabase.loadXML('egl.xml')
success = success and glDatabase.loadXML('glx.xml')
success = success and glDatabase.loadXML('wgl.xml')
if success:
glDatabase.exportConsts('GLConsts.h')

View File

@ -23,6 +23,17 @@ TextureImage::Create(GLContext* gl,
return gl->CreateTextureImage(size, contentType, wrapMode, flags);
}
// Moz2D equivalent...
already_AddRefed<TextureImage>
TextureImage::Create(GLContext* gl,
const gfx::IntSize& size,
TextureImage::ContentType contentType,
GLenum wrapMode,
TextureImage::Flags flags)
{
return Create(gl, ThebesIntSize(size), contentType, wrapMode, flags);
}
bool
TextureImage::UpdateFromDataSource(gfx::DataSourceSurface *aSurface,
const nsIntRegion* aDestRegion,
@ -42,6 +53,14 @@ TextureImage::UpdateFromDataSource(gfx::DataSourceSurface *aSurface,
return DirectUpdate(thebesSurf, destRegion, thebesSrcPoint);
}
gfx::IntRect TextureImage::GetTileRect() {
return gfx::IntRect(gfx::IntPoint(0,0), ToIntSize(mSize));
}
gfx::IntRect TextureImage::GetSrcTileRect() {
return GetTileRect();
}
BasicTextureImage::~BasicTextureImage()
{
GLContext *ctx = mGLContext;
@ -208,6 +227,49 @@ BasicTextureImage::Resize(const nsIntSize& aSize)
mSize = aSize;
}
// Moz2D equivalents...
void TextureImage::Resize(const gfx::IntSize& aSize) {
Resize(ThebesIntSize(aSize));
}
gfx::IntSize TextureImage::GetSize() const {
return ToIntSize(mSize);
}
TextureImage::TextureImage(const gfx::IntSize& aSize,
GLenum aWrapMode, ContentType aContentType,
Flags aFlags)
: mSize(ThebesIntSize(aSize))
, mWrapMode(aWrapMode)
, mContentType(aContentType)
, mFilter(gfxPattern::FILTER_GOOD)
, mFlags(aFlags)
{}
BasicTextureImage::BasicTextureImage(GLuint aTexture,
const gfx::IntSize& aSize,
GLenum aWrapMode,
ContentType aContentType,
GLContext* aContext,
TextureImage::Flags aFlags,
TextureImage::ImageFormat aImageFormat)
: TextureImage(ThebesIntSize(aSize), aWrapMode, aContentType, aFlags, aImageFormat)
, mTexture(aTexture)
, mTextureState(Created)
, mGLContext(aContext)
, mUpdateOffset(0, 0)
{}
already_AddRefed<TextureImage>
CreateBasicTextureImage(GLContext* aGL,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags)
{
return CreateBasicTextureImage(aGL, ThebesIntSize(aSize), aContentType, aWrapMode, aFlags);
}
TiledTextureImage::TiledTextureImage(GLContext* aGL,
nsIntSize aSize,
TextureImage::ContentType aContentType,
@ -257,7 +319,7 @@ TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion,
int oldCurrentImage = mCurrentImage;
BeginTileIteration();
do {
nsIntRect tileRect = GetSrcTileRect();
nsIntRect tileRect = ThebesIntRect(GetSrcTileRect());
int xPos = tileRect.x;
int yPos = tileRect.y;
@ -313,7 +375,8 @@ TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
nsIntRect imageRect = nsIntRect(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
ThebesIntSize(mImages[i]->GetSize()));
if (aForRegion.Intersects(imageRect)) {
// Make a copy of the region
@ -355,7 +418,9 @@ TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
nsIntRegion imageRegion = nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
nsIntRegion imageRegion =
nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos),
ThebesIntSize(mImages[i]->GetSize())));
// a single Image can handle this update request
if (imageRegion.Contains(aRegion)) {
@ -410,7 +475,8 @@ TiledTextureImage::EndUpdate()
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize());
nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos),
ThebesIntSize(mImages[i]->GetSize()));
nsIntRegion subregion;
subregion.And(mUpdateRegion, imageRect);
@ -460,25 +526,25 @@ void TiledTextureImage::SetIterationCallback(TileIterationCallback aCallback,
mIterationCallbackData = aCallbackData;
}
nsIntRect TiledTextureImage::GetTileRect()
gfx::IntRect TiledTextureImage::GetTileRect()
{
if (!GetTileCount()) {
return nsIntRect();
return gfx::IntRect();
}
nsIntRect rect = mImages[mCurrentImage]->GetTileRect();
gfx::IntRect rect = mImages[mCurrentImage]->GetTileRect();
unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
rect.MoveBy(xPos, yPos);
return rect;
}
nsIntRect TiledTextureImage::GetSrcTileRect()
gfx::IntRect TiledTextureImage::GetSrcTileRect()
{
nsIntRect rect = GetTileRect();
gfx::IntRect rect = GetTileRect();
unsigned int srcY = mFlags & NeedsYFlip
? mSize.height - rect.height - rect.y
: rect.y;
return nsIntRect(rect.x, srcY, rect.width, rect.height);
return gfx::IntRect(rect.x, srcY, rect.width, rect.height);
}
void

View File

@ -67,6 +67,13 @@ public:
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags = TextureImage::NoFlags);
// Moz2D equivalent...
static already_AddRefed<TextureImage> Create(
GLContext* gl,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags = TextureImage::NoFlags);
virtual ~TextureImage() {}
@ -133,9 +140,7 @@ public:
void* aCallbackData) {
}
virtual nsIntRect GetTileRect() {
return nsIntRect(nsIntPoint(0,0), mSize);
}
virtual gfx::IntRect GetTileRect();
virtual GLuint GetTextureID() = 0;
@ -157,6 +162,8 @@ public:
BeginUpdate(r);
EndUpdate();
}
// Moz2D equivalent...
void Resize(const gfx::IntSize& aSize);
/**
* Mark this texture as having valid contents. Call this after modifying
@ -229,7 +236,8 @@ public:
virtual already_AddRefed<gfxASurface> GetBackingSurface()
{ return nullptr; }
const nsIntSize& GetSize() const { return mSize; }
gfx::IntSize GetSize() const;
ContentType GetContentType() const { return mContentType; }
ImageFormat GetImageFormat() const { return mImageFormat; }
virtual bool InUpdate() const = 0;
@ -264,9 +272,12 @@ protected:
, mFlags(aFlags)
{}
virtual nsIntRect GetSrcTileRect() {
return nsIntRect(nsIntPoint(0,0), mSize);
}
// Moz2D equivalent...
TextureImage(const gfx::IntSize& aSize,
GLenum aWrapMode, ContentType aContentType,
Flags aFlags = NoFlags);
virtual gfx::IntRect GetSrcTileRect();
nsIntSize mSize;
GLenum mWrapMode;
@ -306,6 +317,14 @@ public:
, mUpdateOffset(0, 0)
{}
BasicTextureImage(GLuint aTexture,
const gfx::IntSize& aSize,
GLenum aWrapMode,
ContentType aContentType,
GLContext* aContext,
TextureImage::Flags aFlags = TextureImage::NoFlags,
TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown);
virtual void BindTexture(GLenum aTextureUnit);
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
@ -369,7 +388,7 @@ public:
virtual bool NextTile();
virtual void SetIterationCallback(TileIterationCallback aCallback,
void* aCallbackData);
virtual nsIntRect GetTileRect();
virtual gfx::IntRect GetTileRect();
virtual GLuint GetTextureID() {
return mImages[mCurrentImage]->GetTextureID();
}
@ -379,7 +398,7 @@ public:
virtual void ApplyFilter();
protected:
virtual nsIntRect GetSrcTileRect();
virtual gfx::IntRect GetSrcTileRect();
unsigned int mCurrentImage;
TileIterationCallback mIterationCallback;
@ -411,6 +430,13 @@ CreateBasicTextureImage(GLContext* aGL,
TextureImage::Flags aFlags,
TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown);
already_AddRefed<TextureImage>
CreateBasicTextureImage(GLContext* aGL,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags);
} // namespace gl
} // namespace mozilla

83
gfx/gl/GLTypes.h Normal file
View File

@ -0,0 +1,83 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(GLTYPES_H_)
#define GLTYPES_H_
#if !defined(__gltypes_h_) && !defined(__gl_h_)
#define __gltypes_h_
#define __gl_h_
#include <stddef.h>
#include <stdint.h>
typedef unsigned int GLenum;
typedef unsigned int GLbitfield;
typedef unsigned int GLuint;
typedef int GLint;
typedef int GLsizei;
typedef char realGLboolean;
typedef signed char GLbyte;
typedef short GLshort;
typedef unsigned char GLubyte;
typedef unsigned short GLushort;
typedef float GLfloat;
typedef float GLclampf;
#ifndef GLdouble_defined
typedef double GLdouble;
#endif
typedef double GLclampd;
typedef void GLvoid;
typedef char GLchar;
#ifndef __gl2_h_
typedef intptr_t GLsizeiptr;
typedef intptr_t GLintptr;
#endif
#endif /* #if !defined(__gltypes_h_) && !defined(__gl_h_) */
#include <stdint.h>
// ARB_sync
typedef struct __GLsync* GLsync;
typedef int64_t GLint64;
typedef uint64_t GLuint64;
// OES_EGL_image (GLES)
typedef void* GLeglImage;
// EGL types
typedef void* EGLImage;
typedef int EGLint;
typedef unsigned int EGLBoolean;
typedef unsigned int EGLenum;
typedef void *EGLConfig;
typedef void *EGLContext;
typedef void *EGLDisplay;
typedef void *EGLSurface;
typedef void *EGLClientBuffer;
typedef void *EGLCastToRelevantPtr;
typedef void *EGLImage;
typedef void *EGLSync;
typedef uint64_t EGLTime;
#define EGL_NO_CONTEXT ((EGLContext)0)
#define EGL_NO_DISPLAY ((EGLDisplay)0)
#define EGL_NO_SURFACE ((EGLSurface)0)
#define EGL_NO_CONFIG ((EGLConfig)nullptr)
#define EGL_NO_SYNC ((EGLSync)0)
#define EGL_NO_IMAGE ((EGLImage)0)
#ifndef GLAPIENTRY
# ifdef WIN32
# define GLAPIENTRY APIENTRY
# define GLAPI
# else
# define GLAPIENTRY
# define GLAPI
# endif
#endif
#endif

View File

@ -37,6 +37,7 @@ if CONFIG['MOZ_GL_PROVIDER']:
EXPORTS += [
'ForceDiscreteGPUHelperCGL.h',
'GLConsts.h',
'GLContext.h',
'GLContextProvider.h',
'GLContextProviderImpl.h',
@ -47,6 +48,7 @@ EXPORTS += [
'GLLibraryLoader.h',
'GLScreenBuffer.h',
'GLTextureImage.h',
'GLTypes.h',
'SharedSurface.h',
'SharedSurfaceEGL.h',
'SharedSurfaceGL.h',

View File

@ -178,10 +178,9 @@ TextureImageTextureSourceOGL::GetSize() const
{
if (mTexImage) {
if (mIterating) {
nsIntRect rect = mTexImage->GetTileRect();
return gfx::IntSize(rect.width, rect.height);
return mTexImage->GetTileRect().Size();
}
return gfx::IntSize(mTexImage->GetSize().width, mTexImage->GetSize().height);
return mTexImage->GetSize();
}
NS_WARNING("Trying to query the size of an empty TextureSource.");
return gfx::IntSize(0, 0);
@ -194,6 +193,11 @@ TextureImageTextureSourceOGL::GetFormat() const
return mTexImage->GetTextureFormat();
}
nsIntRect TextureImageTextureSourceOGL::GetTileRect()
{
return ThebesIntRect(mTexImage->GetTileRect());
}
void
TextureImageTextureSourceOGL::BindTexture(GLenum aTextureUnit)
{
@ -358,14 +362,18 @@ TextureImageDeprecatedTextureHostOGL::GetSize() const
{
if (mTexture) {
if (mIterating) {
nsIntRect rect = mTexture->GetTileRect();
return gfx::IntSize(rect.width, rect.height);
return mTexture->GetTileRect().Size();
}
return gfx::IntSize(mTexture->GetSize().width, mTexture->GetSize().height);
return mTexture->GetSize();
}
return gfx::IntSize(0, 0);
}
nsIntRect TextureImageDeprecatedTextureHostOGL::GetTileRect()
{
return ThebesIntRect(mTexture->GetTileRect());
}
void
TextureImageDeprecatedTextureHostOGL::SetCompositor(Compositor* aCompositor)
{

View File

@ -157,10 +157,7 @@ public:
mIterating = false;
}
virtual nsIntRect GetTileRect() MOZ_OVERRIDE
{
return mTexImage->GetTileRect();
}
virtual nsIntRect GetTileRect() MOZ_OVERRIDE;
virtual size_t GetTileCount() MOZ_OVERRIDE
{
@ -397,10 +394,7 @@ public:
mIterating = false;
}
nsIntRect GetTileRect() MOZ_OVERRIDE
{
return mTexture->GetTileRect();
}
nsIntRect GetTileRect() MOZ_OVERRIDE;
size_t GetTileCount() MOZ_OVERRIDE
{

View File

@ -14,6 +14,7 @@
#include "ThebesLayerOGL.h"
#include "gfxUtils.h"
#include "gfxTeeSurface.h"
#include "gfx2DGlue.h"
#include "gfxPlatform.h"
#include "base/message_loop.h"
@ -91,7 +92,7 @@ public:
nsIntSize GetSize() {
if (mTexImage)
return mTexImage->GetSize();
return ThebesIntSize(mTexImage->GetSize());
return nsIntSize(0, 0);
}
@ -204,7 +205,7 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
region.MoveBy(-origin); // translate into TexImage space, buffer origin might not be at texture (0,0)
// Figure out the intersecting draw region
nsIntSize texSize = mTexImage->GetSize();
nsIntSize texSize = ThebesIntSize(mTexImage->GetSize());
nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height);
textureRect.MoveBy(region.GetBounds().TopLeft());
nsIntRegion subregion;
@ -236,10 +237,10 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
bool usingTiles = (mTexImage->GetTileCount() > 1);
do {
if (mTexImageOnWhite) {
NS_ASSERTION(mTexImageOnWhite->GetTileRect() == mTexImage->GetTileRect(), "component alpha textures should be the same size.");
NS_ASSERTION(ThebesIntRect(mTexImageOnWhite->GetTileRect()) == ThebesIntRect(mTexImage->GetTileRect()), "component alpha textures should be the same size.");
}
nsIntRect tileRect = mTexImage->GetTileRect();
nsIntRect tileRect = ThebesIntRect(mTexImage->GetTileRect());
// Bind textures.
TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);

View File

@ -32,6 +32,11 @@ inline Rect ToRect(const gfxRect &aRect)
Float(aRect.width), Float(aRect.height));
}
inline IntRect ToIntRect(const nsIntRect &aRect)
{
return IntRect(aRect.x, aRect.y, aRect.width, aRect.height);
}
inline Color ToColor(const gfxRGBA &aRGBA)
{
return Color(Float(aRGBA.r), Float(aRGBA.g),
@ -123,6 +128,11 @@ inline gfxRect ThebesRect(const Rect &aRect)
return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height);
}
inline nsIntRect ThebesIntRect(const IntRect &aRect)
{
return nsIntRect(aRect.x, aRect.y, aRect.width, aRect.height);
}
inline gfxRGBA ThebesRGBA(const Color &aColor)
{
return gfxRGBA(aColor.r, aColor.g, aColor.b, aColor.a);

View File

@ -51,6 +51,7 @@
#include "nsDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsISimpleEnumerator.h"
#include "nsIMemory.h"
#include "mozilla/Preferences.h"
#include "mozilla/scache/StartupCache.h"

View File

@ -6,6 +6,7 @@
#include "nsGBKConvUtil.h"
#include "gbku.h"
#include "nsCRT.h"
#include "nsDebug.h"
#define MAX_GBK_LENGTH 24066 /* (0xfe-0x80)*(0xfe-0x3f) */
//--------------------------------------------------------------------
// nsGBKConvUtil

View File

@ -44,16 +44,6 @@ namespace js {}
#define JS_ALWAYS_TRUE(expr) MOZ_ALWAYS_TRUE(expr)
#define JS_ALWAYS_FALSE(expr) MOZ_ALWAYS_FALSE(expr)
#ifdef DEBUG
# ifdef JS_THREADSAFE
# define JS_THREADSAFE_ASSERT(expr) JS_ASSERT(expr)
# else
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
# endif
#else
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
#endif
#if defined(DEBUG)
# define JS_DIAGNOSTICS_ASSERT(expr) MOZ_ASSERT(expr)
#elif defined(JS_CRASH_DIAGNOSTICS)

View File

@ -206,7 +206,7 @@ static bool
CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
{
if (args.length() == 0) {
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics();
Rooted<JSAtom*> empty(cx, cx->runtime()->emptyString);
RegExpObject *reobj = builder.build(empty, res->getFlags());
if (!reobj)
@ -295,7 +295,7 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
if (!js::RegExpShared::checkSyntax(cx, NULL, escapedSourceStr))
return false;
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpObject *reobj = builder.build(escapedSourceStr, RegExpFlag(flags | res->getFlags()));
if (!reobj)
return false;
@ -397,7 +397,7 @@ static const JSFunctionSpec regexp_methods[] = {
static bool \
name(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) \
{ \
RegExpStatics *res = cx->regExpStatics(); \
RegExpStatics *res = cx->global()->getRegExpStatics(); \
code; \
}
@ -423,7 +423,7 @@ DEFINE_STATIC_GETTER(static_paren9_getter, return res->createParen(cx, 9,
static bool \
name(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)\
{ \
RegExpStatics *res = cx->regExpStatics(); \
RegExpStatics *res = cx->global()->getRegExpStatics(); \
code; \
return true; \
}
@ -538,7 +538,9 @@ js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string,
if (!reobj->getShared(cx, &re))
return RegExpRunStatus_Error;
RegExpStatics *res = (staticsUpdate == UpdateRegExpStatics) ? cx->regExpStatics() : NULL;
RegExpStatics *res = (staticsUpdate == UpdateRegExpStatics)
? cx->global()->getRegExpStatics()
: NULL;
/* Step 3. */
Rooted<JSLinearString*> input(cx, string->ensureLinear(cx));

View File

@ -1066,11 +1066,6 @@ if test "$GNU_CC"; then
fi
fi
WARNINGS_AS_ERRORS='-Werror'
# Don't treat -Wuninitialized as error b/c it has lots of false positives.
WARNINGS_AS_ERRORS="$WARNINGS_AS_ERRORS -Wno-error=uninitialized"
# Don't treat -Wdeprecated-declarations as error b/c we don't want our
# builds held hostage when a platform-specific API is suddenly deprecated.
WARNINGS_AS_ERRORS="$WARNINGS_AS_ERRORS -Wno-error=deprecated-declarations"
DSO_CFLAGS=''
DSO_PIC_CFLAGS='-fPIC'
ASFLAGS="$ASFLAGS -fPIC"
@ -3265,6 +3260,15 @@ MOZ_ARG_DISABLE_BOOL(warnings-as-errors,
MOZ_ENABLE_WARNINGS_AS_ERRORS=)
if test -z "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
WARNINGS_AS_ERRORS=''
elif test "$GNU_CC"; then
# Prevent the following GCC warnings from being treated as errors:
# -Wuninitialized - too many false positives
# -Wdeprecated-declarations - we don't want our builds held hostage when a
# platform-specific API becomes deprecated.
MOZ_C_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_c_has_noerror_uninitialized)
MOZ_CXX_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_cxx_has_noerror_uninitialized)
MOZ_C_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_c_has_noerror_deprecated_declarations)
MOZ_CXX_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_cxx_has_noerror_deprecated_declarations)
fi
dnl ========================================================

View File

@ -6225,7 +6225,7 @@ Parser<ParseHandler>::newRegExp()
RegExpFlag flags = tokenStream.currentToken().regExpFlags();
Rooted<RegExpObject*> reobj(context);
if (RegExpStatics *res = context->regExpStatics())
if (RegExpStatics *res = context->global()->getRegExpStatics())
reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream);
else
reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream);

View File

@ -182,7 +182,7 @@ HeapValue::set(Zone *zone, const Value &v)
#ifdef DEBUG
if (value.isMarkable()) {
JS_ASSERT(ZoneOfValue(value) == zone ||
ZoneOfValue(value) == zone->runtimeFromMainThread()->atomsCompartment->zone());
zone->runtimeFromAnyThread()->isAtomsZone(ZoneOfValue(value)));
}
#endif

View File

@ -145,12 +145,10 @@ CheckMarkedThing(JSTracer *trc, T *thing)
JS_ASSERT(MapTypeToTraceKind<T>::kind == GetGCThingTraceKind(thing));
JS_ASSERT_IF(rt->gcStrictCompartmentChecking,
thing->zone()->isCollecting() ||
thing->zone() == rt->atomsCompartment->zone());
thing->zone()->isCollecting() || rt->isAtomsZone(thing->zone()));
JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && AsGCMarker(trc)->getMarkColor() == GRAY,
thing->zone()->isGCMarkingGray() ||
thing->zone() == rt->atomsCompartment->zone());
thing->zone()->isGCMarkingGray() || rt->isAtomsZone(thing->zone()));
/*
* Try to assert that the thing is allocated. This is complicated by the
@ -742,7 +740,7 @@ gc::IsCellAboutToBeFinalized(Cell **thingp)
#define JS_COMPARTMENT_ASSERT_STR(rt, thing) \
JS_ASSERT((thing)->zone()->isGCMarking() || \
(thing)->zone() == (rt)->atomsCompartment->zone());
(rt)->isAtomsZone((thing)->zone()));
static void
PushMarkStack(GCMarker *gcmarker, JSObject *thing)
@ -1411,8 +1409,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
if (v.isString()) {
JSString *str = v.toString();
JS_COMPARTMENT_ASSERT_STR(runtime, str);
JS_ASSERT(str->zone() == runtime->atomsCompartment->zone() ||
str->zone() == obj->zone());
JS_ASSERT(runtime->isAtomsZone(str->zone()) || str->zone() == obj->zone());
if (str->markIfUnmarked())
ScanString(this, str);
} else if (v.isObject()) {

View File

@ -688,7 +688,7 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots)
}
if (!trc->runtime->isHeapMinorCollecting() &&
(!IS_GC_MARKING_TRACER(trc) || rt->atomsCompartment->zone()->isCollecting()))
(!IS_GC_MARKING_TRACER(trc) || rt->atomsCompartment()->zone()->isCollecting()))
{
MarkAtoms(trc);
#ifdef JS_ION

View File

@ -68,7 +68,7 @@ CheckStackRoot(JSRuntime *rt, uintptr_t *w, Rooter *begin, Rooter *end)
return;
/* Don't check atoms as these will never be subject to generational collection. */
if (static_cast<Cell *>(thing)->tenuredZone() == rt->atomsCompartment->zone())
if (rt->isAtomsZone(static_cast<Cell *>(thing)->tenuredZone()))
return;
/*

View File

@ -0,0 +1,8 @@
function x() {
try {
do {
var { q , gen } = t;
} while(false);
} catch (e) {}
}
x();

View File

@ -400,6 +400,16 @@ BaselineScript::trace(JSTracer *trc)
}
}
/* static */
void
BaselineScript::writeBarrierPre(Zone *zone, BaselineScript *script)
{
#ifdef JSGC_INCREMENTAL
if (zone->needsBarrier())
script->trace(zone->barrierTracer());
#endif
}
void
BaselineScript::Trace(JSTracer *trc, BaselineScript *script)
{
@ -843,8 +853,9 @@ ion::FinishDiscardBaselineScript(FreeOp *fop, JSScript *script)
return;
}
BaselineScript::Destroy(fop, script->baselineScript());
BaselineScript *baseline = script->baselineScript();
script->setBaselineScript(NULL);
BaselineScript::Destroy(fop, baseline);
}
void

View File

@ -255,6 +255,8 @@ struct BaselineScript
static size_t offsetOfFlags() {
return offsetof(BaselineScript, flags_);
}
static void writeBarrierPre(Zone *zone, BaselineScript *script);
};
inline bool

View File

@ -29,6 +29,7 @@
#include "vm/ForkJoin.h"
#include "jsboolinlines.h"
#include "jsscriptinlines.h"
#include "jit/shared/CodeGenerator-shared-inl.h"
#include "vm/Interpreter-inl.h"

View File

@ -52,6 +52,7 @@
#include "jscompartmentinlines.h"
#include "jsgcinlines.h"
#include "jsinferinlines.h"
#include "jsscriptinlines.h"
#include "vm/Shape-inl.h"
@ -282,7 +283,7 @@ IonRuntime::debugTrapHandler(JSContext *cx)
// IonRuntime code stubs are shared across compartments and have to
// be allocated in the atoms compartment.
AutoLockForExclusiveAccess lock(cx);
AutoCompartment ac(cx, cx->runtime()->atomsCompartment);
AutoCompartment ac(cx, cx->runtime()->atomsCompartment());
debugTrapHandler_ = generateDebugTrapHandler(cx);
}
return debugTrapHandler_;
@ -385,7 +386,7 @@ FinishAllOffThreadCompilations(IonCompartment *ion)
IonRuntime::Mark(JSTracer *trc)
{
JS_ASSERT(!trc->runtime->isHeapMinorCollecting());
Zone *zone = trc->runtime->atomsCompartment->zone();
Zone *zone = trc->runtime->atomsCompartment()->zone();
for (gc::CellIterUnderGC i(zone, gc::FINALIZE_IONCODE); !i.done(); i.next()) {
IonCode *code = i.get<IonCode>();
MarkIonCodeRoot(trc, &code, "wrapper");
@ -713,6 +714,15 @@ IonScript::trace(JSTracer *trc)
gc::MarkScriptUnbarriered(trc, &callTargetList()[i], "callTarget");
}
/* static */ void
IonScript::writeBarrierPre(Zone *zone, IonScript *ionScript)
{
#ifdef JSGC_INCREMENTAL
if (zone->needsBarrier())
ionScript->trace(zone->barrierTracer());
#endif
}
void
IonScript::copySnapshots(const SnapshotWriter *writer)
{
@ -2190,18 +2200,9 @@ ion::Invalidate(types::TypeCompartment &types, FreeOp *fop,
JSScript *script = co.script;
IonScript *ionScript = GetIonScript(script, executionMode);
Zone *zone = script->zone();
if (zone->needsBarrier()) {
// We're about to remove edges from the JSScript to gcthings
// embedded in the IonScript. Perform one final trace of the
// IonScript for the incremental GC, as it must know about
// those edges.
IonScript::Trace(zone->barrierTracer(), ionScript);
}
SetIonScript(script, executionMode, NULL);
ionScript->detachDependentAsmJSModules(fop);
ionScript->decref(fop);
SetIonScript(script, executionMode, NULL);
co.invalidate();
// Wait for the scripts to get warm again before doing another
@ -2259,6 +2260,13 @@ ion::Invalidate(JSContext *cx, JSScript *script, bool resetUses)
static void
FinishInvalidationOf(FreeOp *fop, JSScript *script, IonScript *ionScript, bool parallel)
{
// In all cases, NULL out script->ion or script->parallelIon to avoid
// re-entry.
if (parallel)
script->setParallelIonScript(NULL);
else
script->setIonScript(NULL);
// If this script has Ion code on the stack, invalidation() will return
// true. In this case we have to wait until destroying it.
if (!ionScript->invalidated()) {
@ -2267,13 +2275,6 @@ FinishInvalidationOf(FreeOp *fop, JSScript *script, IonScript *ionScript, bool p
ion::IonScript::Destroy(fop, ionScript);
}
// In all cases, NULL out script->ion or script->parallelIon to avoid
// re-entry.
if (parallel)
script->setParallelIonScript(NULL);
else
script->setIonScript(NULL);
}
void

View File

@ -537,6 +537,8 @@ struct IonScript
void resetOsrPcMismatchCounter() {
osrPcMismatchCounter_ = 0;
}
static void writeBarrierPre(Zone *zone, IonScript *ionScript);
};
// Execution information for a basic block which may persist after the

View File

@ -988,15 +988,19 @@ CanEmitBitAndAtUses(MInstruction *ins)
if (ins->getOperand(0)->type() != MIRType_Int32 || ins->getOperand(1)->type() != MIRType_Int32)
return false;
MUseDefIterator iter(ins);
if (!iter)
MUseIterator iter(ins->usesBegin());
if (iter == ins->usesEnd())
return false;
if (!iter.def()->isTest())
MNode *node = iter->consumer();
if (!node->isDefinition())
return false;
if (!node->toDefinition()->isTest())
return false;
iter++;
return !iter;
return iter == ins->usesEnd();
}
bool

View File

@ -143,6 +143,9 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
mir = mir->toPassArg()->getArgument();
JS_ASSERT(!mir->isPassArg());
if (mir->isBox())
mir = mir->toBox()->getOperand(0);
MIRType type = mir->isUnused()
? MIRType_Undefined
: mir->type();

View File

@ -82,9 +82,17 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
ins = ins->toPassArg()->getArgument();
JS_ASSERT(!ins->isPassArg());
if (ins->isBox())
ins = ins->toBox()->getOperand(0);
// Guards should never be eliminated.
JS_ASSERT_IF(ins->isUnused(), !ins->isGuard());
// Snapshot operands other than constants should never be
// emitted-at-uses. Try-catch support depends on there being no
// code between an instruction and the LOsiPoint that follows it.
JS_ASSERT_IF(!ins->isConstant(), !ins->isEmittedAtUses());
// The register allocation will fill these fields in with actual
// register/stack assignments. During code generation, we can restore
// interpreter state with the given information. Note that for
@ -97,8 +105,6 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
*type = LConstantIndex::Bogus();
*payload = use(ins, LUse::KEEPALIVE);
} else {
if (!ensureDefined(ins))
return NULL;
*type = useType(ins, LUse::KEEPALIVE);
*payload = usePayload(ins, LUse::KEEPALIVE);
}
@ -129,6 +135,18 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
if (def->isPassArg())
def = def->toPassArg()->getArgument();
JS_ASSERT(!def->isPassArg());
if (def->isBox())
def = def->toBox()->getOperand(0);
// Guards should never be eliminated.
JS_ASSERT_IF(def->isUnused(), !def->isGuard());
// Snapshot operands other than constants should never be
// emitted-at-uses. Try-catch support depends on there being no
// code between an instruction and the LOsiPoint that follows it.
JS_ASSERT_IF(!def->isConstant(), !def->isEmittedAtUses());
LAllocation *a = snapshot->getEntry(i);

View File

@ -1340,7 +1340,7 @@ JS_PUBLIC_API(bool)
JS_InitStandardClasses(JSContext *cx, JSObject *objArg)
{
RootedObject obj(cx, objArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
@ -2911,7 +2911,7 @@ JS_NewGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals,
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
JS_ASSERT(!cx->isExceptionPending());
JSRuntime *rt = cx->runtime();
@ -2966,7 +2966,7 @@ JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *protoArg, JSObject *pare
{
RootedObject proto(cx, protoArg);
RootedObject parent(cx, parentArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, proto, parent);
@ -2996,7 +2996,7 @@ JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *protoArg,
{
RootedObject proto(cx, protoArg);
RootedObject parent(cx, parentArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, proto, parent);
@ -4249,7 +4249,7 @@ JS_NewArrayObject(JSContext *cx, int length, jsval *vector)
{
AutoArrayRooter tvr(cx, length, vector);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
@ -4347,7 +4347,7 @@ JS_NewFunction(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
JSObject *parentArg, const char *name)
{
RootedObject parent(cx, parentArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
@ -4370,7 +4370,7 @@ JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flag
{
RootedObject parent(cx, parentArg);
JS_ASSERT(JSID_IS_STRING(id));
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, parent);
@ -4519,7 +4519,7 @@ js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp)
JS_PUBLIC_API(bool)
JS_DefineFunctions(JSContext *cx, JSObject *objArg, const JSFunctionSpec *fs)
{
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, objArg);
@ -4619,7 +4619,7 @@ JS_DefineFunction(JSContext *cx, JSObject *objArg, const char *name, JSNative ca
unsigned nargs, unsigned attrs)
{
RootedObject obj(cx, objArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
@ -4636,7 +4636,7 @@ JS_DefineUCFunction(JSContext *cx, JSObject *objArg,
unsigned nargs, unsigned attrs)
{
RootedObject obj(cx, objArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
@ -4653,7 +4653,7 @@ JS_DefineFunctionById(JSContext *cx, JSObject *objArg, jsid id_, JSNative call,
{
RootedObject obj(cx, objArg);
RootedId id(cx, id_);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
@ -4797,7 +4797,7 @@ JSScript *
JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options,
const jschar *chars, size_t length)
{
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
@ -4950,7 +4950,7 @@ JS::CompileFunction(JSContext *cx, HandleObject obj, CompileOptions options,
const char *name, unsigned nargs, const char **argnames,
const jschar *chars, size_t length)
{
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
@ -5051,7 +5051,7 @@ JS_CompileFunction(JSContext *cx, JSObject *objArg, const char *name,
JS_PUBLIC_API(JSString *)
JS_DecompileScript(JSContext *cx, JSScript *scriptArg, const char *name, unsigned indent)
{
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
@ -5068,7 +5068,7 @@ JS_DecompileScript(JSContext *cx, JSScript *scriptArg, const char *name, unsigne
JS_PUBLIC_API(JSString *)
JS_DecompileFunction(JSContext *cx, JSFunction *funArg, unsigned indent)
{
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, funArg);
@ -5079,7 +5079,7 @@ JS_DecompileFunction(JSContext *cx, JSFunction *funArg, unsigned indent)
JS_PUBLIC_API(JSString *)
JS_DecompileFunctionBody(JSContext *cx, JSFunction *funArg, unsigned indent)
{
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, funArg);
@ -5093,7 +5093,7 @@ JS_ExecuteScript(JSContext *cx, JSObject *objArg, JSScript *scriptArg, jsval *rv
RootedObject obj(cx, objArg);
RootedScript script(cx, scriptArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
@ -5134,7 +5134,7 @@ extern JS_PUBLIC_API(bool)
JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options,
const jschar *chars, size_t length, jsval *rval)
{
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
@ -5308,7 +5308,7 @@ JS_CallFunction(JSContext *cx, JSObject *objArg, JSFunction *fun, unsigned argc,
jsval *rval)
{
RootedObject obj(cx, objArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
@ -5326,7 +5326,7 @@ JS_CallFunctionName(JSContext *cx, JSObject *objArg, const char *name, unsigned
jsval *rval)
{
RootedObject obj(cx, objArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, JSValueArray(argv, argc));
@ -5353,7 +5353,7 @@ JS_CallFunctionValue(JSContext *cx, JSObject *objArg, jsval fval, unsigned argc,
jsval *rval)
{
RootedObject obj(cx, objArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));

View File

@ -117,13 +117,14 @@ const char js_yield_str[] = "yield";
bool
js::InitAtoms(JSRuntime *rt)
{
return rt->atoms.init(JS_STRING_HASH_COUNT);
AutoLockForExclusiveAccess lock(rt);
return rt->atoms().init(JS_STRING_HASH_COUNT);
}
void
js::FinishAtoms(JSRuntime *rt)
{
AtomSet &atoms = rt->atoms;
AtomSet &atoms = rt->atoms();
if (!atoms.initialized()) {
/*
* We are called with uninitialized state when JS_NewRuntime fails and
@ -181,7 +182,7 @@ void
js::MarkAtoms(JSTracer *trc)
{
JSRuntime *rt = trc->runtime;
for (AtomSet::Range r = rt->atoms.all(); !r.empty(); r.popFront()) {
for (AtomSet::Range r = rt->atoms().all(); !r.empty(); r.popFront()) {
AtomStateEntry entry = r.front();
if (!entry.isTagged())
continue;
@ -195,7 +196,7 @@ js::MarkAtoms(JSTracer *trc)
void
js::SweepAtoms(JSRuntime *rt)
{
for (AtomSet::Enum e(rt->atoms); !e.empty(); e.popFront()) {
for (AtomSet::Enum e(rt->atoms()); !e.empty(); e.popFront()) {
AtomStateEntry entry = e.front();
JSAtom *atom = entry.asPtr();
bool isDying = IsStringAboutToBeFinalized(&atom);
@ -215,7 +216,9 @@ AtomIsInterned(JSContext *cx, JSAtom *atom)
if (StaticStrings::isStatic(atom))
return true;
AtomSet::Ptr p = cx->runtime()->atoms.lookup(atom);
AutoLockForExclusiveAccess lock(cx);
AtomSet::Ptr p = cx->runtime()->atoms().lookup(atom);
if (!p)
return false;

View File

@ -330,41 +330,39 @@ class ExclusiveContext : public ThreadSafeContext
// If required, pause this thread until notified to continue by the main thread.
inline void maybePause() const;
inline bool typeInferenceEnabled() const;
// Threads with an ExclusiveContext may freely access any data in their
// compartment and zone.
JSCompartment *compartment() const {
JS_ASSERT_IF(runtime_->isAtomsCompartment(compartment_),
runtime_->currentThreadHasExclusiveAccess());
return compartment_;
}
JS::Zone *zone() const {
JS_ASSERT_IF(!compartment(), !zone_);
JS_ASSERT_IF(compartment(), js::GetCompartmentZone(compartment()) == zone_);
return zone_;
}
// Per compartment data that can be accessed freely from an ExclusiveContext.
inline RegExpCompartment &regExps();
inline RegExpStatics *regExpStatics();
inline PropertyTree &propertyTree();
inline BaseShapeSet &baseShapes();
inline InitialShapeSet &initialShapes();
inline DtoaCache &dtoaCache();
// Zone local methods that can be used freely from an ExclusiveContext.
inline bool typeInferenceEnabled() const;
types::TypeObject *getNewType(Class *clasp, TaggedProto proto, JSFunction *fun = NULL);
// Current global. This is only safe to use within the scope of the
// AutoCompartment from which it's called.
inline js::Handle<js::GlobalObject*> global() const;
// Methods to access runtime wide data that must be protected by locks.
// Methods to access runtime data that must be protected by locks.
frontend::ParseMapPool &parseMapPool() {
JS_ASSERT(runtime_->currentThreadHasExclusiveAccess());
return runtime_->parseMapPool;
return runtime_->parseMapPool();
}
AtomSet &atoms() {
JS_ASSERT(runtime_->currentThreadHasExclusiveAccess());
return runtime_->atoms;
return runtime_->atoms();
}
JSCompartment *atomsCompartment() {
JS_ASSERT(runtime_->currentThreadHasExclusiveAccess());
return runtime_->atomsCompartment;
return runtime_->atomsCompartment();
}
ScriptDataTable &scriptDataTable() {
JS_ASSERT(runtime_->currentThreadHasExclusiveAccess());
return runtime_->scriptDataTable;
return runtime_->scriptDataTable();
}
};
@ -383,13 +381,6 @@ struct JSContext : public js::ExclusiveContext,
~JSContext();
JSRuntime *runtime() const { return runtime_; }
JSCompartment *compartment() const { return compartment_; }
inline JS::Zone *zone() const {
JS_ASSERT_IF(!compartment(), !zone_);
JS_ASSERT_IF(compartment(), js::GetCompartmentZone(compartment()) == zone_);
return zone_;
}
js::PerThreadData &mainThread() const { return runtime()->mainThread; }
friend class js::ExclusiveContext;

View File

@ -45,16 +45,16 @@ class CompartmentChecker
MOZ_CRASH();
}
/* Note: should only be used when neither c1 nor c2 may be the default compartment. */
/* Note: should only be used when neither c1 nor c2 may be the atoms compartment. */
static void check(JSCompartment *c1, JSCompartment *c2) {
JS_ASSERT(c1 != c1->runtimeFromMainThread()->atomsCompartment);
JS_ASSERT(c2 != c2->runtimeFromMainThread()->atomsCompartment);
JS_ASSERT(!c1->runtimeFromMainThread()->isAtomsCompartment(c1));
JS_ASSERT(!c2->runtimeFromMainThread()->isAtomsCompartment(c2));
if (c1 != c2)
fail(c1, c2);
}
void check(JSCompartment *c) {
if (c && c != compartment->runtimeFromMainThread()->atomsCompartment) {
if (c && !compartment->runtimeFromMainThread()->isAtomsCompartment(c)) {
if (!compartment)
compartment = c;
else if (c != compartment)
@ -338,36 +338,6 @@ GetNativeStackLimit(ExclusiveContext *cx)
return cx->perThreadData->nativeStackLimit;
}
inline RegExpCompartment &
ExclusiveContext::regExps()
{
return compartment_->regExps;
}
inline PropertyTree&
ExclusiveContext::propertyTree()
{
return compartment_->propertyTree;
}
inline BaseShapeSet &
ExclusiveContext::baseShapes()
{
return compartment_->baseShapes;
}
inline InitialShapeSet &
ExclusiveContext::initialShapes()
{
return compartment_->initialShapes;
}
inline DtoaCache &
ExclusiveContext::dtoaCache()
{
return compartment_->dtoaCache;
}
inline void
ExclusiveContext::maybePause() const
{
@ -505,7 +475,7 @@ inline void
js::ExclusiveContext::setCompartment(JSCompartment *comp)
{
// ExclusiveContexts can only be in the atoms zone or in exclusive zones.
JS_ASSERT_IF(!isJSContext() && comp != runtime_->atomsCompartment,
JS_ASSERT_IF(!isJSContext() && !runtime_->isAtomsCompartment(comp),
comp->zone()->usedByExclusiveThread);
// Normal JSContexts cannot enter exclusive zones.
@ -513,12 +483,12 @@ js::ExclusiveContext::setCompartment(JSCompartment *comp)
!comp->zone()->usedByExclusiveThread);
// Only one thread can be in the atoms compartment at a time.
JS_ASSERT_IF(comp == runtime_->atomsCompartment,
JS_ASSERT_IF(runtime_->isAtomsCompartment(comp),
runtime_->currentThreadHasExclusiveAccess());
// Make sure that the atoms compartment has its own zone.
JS_ASSERT_IF(comp && comp != runtime_->atomsCompartment,
comp->zone() != runtime_->atomsCompartment->zone());
JS_ASSERT_IF(comp && !runtime_->isAtomsCompartment(comp),
!runtime_->isAtomsZone(comp->zone()));
// Both the current and the new compartment should be properly marked as
// entered at this point.

View File

@ -128,9 +128,10 @@ JSRuntime::createIonRuntime(JSContext *cx)
js_delete(ionRuntime_);
ionRuntime_ = NULL;
if (cx->runtime()->atomsCompartment->ionCompartment_) {
js_delete(cx->runtime()->atomsCompartment->ionCompartment_);
cx->runtime()->atomsCompartment->ionCompartment_ = NULL;
JSCompartment *comp = cx->runtime()->atomsCompartment();
if (comp->ionCompartment_) {
js_delete(comp->ionCompartment_);
comp->ionCompartment_ = NULL;
}
return NULL;
@ -200,7 +201,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleValue vp, HandleObject existingA
JSRuntime *rt = runtimeFromMainThread();
JS_ASSERT(cx->compartment() == this);
JS_ASSERT(this != rt->atomsCompartment);
JS_ASSERT(!rt->isAtomsCompartment(this));
JS_ASSERT_IF(existingArg, existingArg->compartment() == cx->compartment());
JS_ASSERT_IF(existingArg, vp.isObject());
JS_ASSERT_IF(existingArg, IsDeadProxyObject(existingArg));
@ -224,7 +225,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleValue vp, HandleObject existingA
/* If the string is an atom, we don't have to copy. */
if (str->isAtom()) {
JS_ASSERT(str->zone() == cx->runtime()->atomsCompartment->zone());
JS_ASSERT(cx->runtime()->isAtomsZone(str->zone()));
return true;
}
}

View File

@ -394,6 +394,12 @@ struct JSCompartment
#endif
};
inline bool
JSRuntime::isAtomsZone(JS::Zone *zone)
{
return zone == atomsCompartment_->zone();
}
// For use when changing the debug mode flag on one or more compartments.
// Do not run scripts in any compartment that is scheduled for GC using this
// object. See comment in updateForDebugMode.

View File

@ -267,8 +267,12 @@ JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
{
rt->debugHooks.interruptHook = hook;
rt->debugHooks.interruptHookData = closure;
for (InterpreterFrames *f = rt->interpreterFrames; f; f = f->older)
f->enableInterruptsUnconditionally();
for (ActivationIterator iter(rt); !iter.done(); ++iter) {
if (iter.activation()->isInterpreter())
iter.activation()->asInterpreter()->enableInterruptsUnconditionally();
}
return true;
}

View File

@ -277,7 +277,7 @@ JS_FRIEND_API(bool)
JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *objArg, const JSFunctionSpecWithHelp *fs)
{
RootedObject obj(cx, objArg);
JS_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
@ -338,7 +338,7 @@ js::IsSystemZone(Zone *zone)
JS_FRIEND_API(bool)
js::IsAtomsCompartment(JSCompartment *comp)
{
return comp == comp->runtimeFromAnyThread()->atomsCompartment;
return comp->runtimeFromAnyThread()->isAtomsCompartment(comp);
}
JS_FRIEND_API(bool)
@ -431,7 +431,7 @@ js::DefineFunctionWithReserved(JSContext *cx, JSObject *objArg, const char *name
unsigned nargs, unsigned attrs)
{
RootedObject obj(cx, objArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
JSAtom *atom = Atomize(cx, name, strlen(name));
@ -446,7 +446,7 @@ js::NewFunctionWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsi
JSObject *parentArg, const char *name)
{
RootedObject parent(cx, parentArg);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
CHECK_REQUEST(cx);
assertSameCompartment(cx, parent);
@ -469,7 +469,7 @@ js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs,
{
RootedObject parent(cx, parentArg);
JS_ASSERT(JSID_IS_STRING(id));
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
CHECK_REQUEST(cx);
assertSameCompartment(cx, parent);

View File

@ -1012,7 +1012,6 @@ js_FinishGC(JSRuntime *rt)
}
rt->zones.clear();
rt->atomsCompartment = NULL;
rt->gcSystemAvailableChunkListHead = NULL;
rt->gcUserAvailableChunkListHead = NULL;
@ -1961,7 +1960,7 @@ js::TriggerZoneGC(Zone *zone, JS::gcreason::Reason reason)
return;
}
if (zone == rt->atomsCompartment->zone()) {
if (rt->isAtomsZone(zone)) {
/* We can't do a zone GC of the atoms compartment. */
TriggerGC(rt, reason);
return;
@ -2525,7 +2524,7 @@ SweepCompartments(FreeOp *fop, Zone *zone, bool keepAtleastOne, bool lastGC)
bool foundOne = false;
while (read < end) {
JSCompartment *comp = *read++;
JS_ASSERT(comp != rt->atomsCompartment);
JS_ASSERT(!rt->isAtomsCompartment(comp));
/*
* Don't delete the last compartment if all the ones before it were
@ -2558,7 +2557,7 @@ SweepZones(FreeOp *fop, bool lastGC)
Zone **end = rt->zones.end();
Zone **write = read;
JS_ASSERT(rt->zones.length() >= 1);
JS_ASSERT(rt->zones[0] == rt->atomsCompartment->zone());
JS_ASSERT(rt->isAtomsZone(rt->zones[0]));
while (read < end) {
Zone *zone = *read++;
@ -2597,7 +2596,7 @@ PurgeRuntime(JSRuntime *rt)
for (ThreadDataIter iter(rt); !iter.done(); iter.next())
activeCompilations |= iter->activeCompilations;
if (!activeCompilations)
rt->parseMapPool.purgeAll();
rt->parseMapPool().purgeAll();
}
static bool
@ -2658,7 +2657,7 @@ CheckCompartment(CompartmentCheckTracer *trc, JSCompartment *thingCompartment,
Cell *thing, JSGCTraceKind kind)
{
JS_ASSERT(thingCompartment == trc->compartment ||
thingCompartment == trc->runtime->atomsCompartment ||
trc->runtime->isAtomsCompartment(thingCompartment) ||
(trc->srcKind == JSTRACE_OBJECT &&
InCrossCompartmentMap((JSObject *)trc->src, thing, kind)));
}
@ -2689,7 +2688,7 @@ CheckCompartmentCallback(JSTracer *trcArg, void **thingp, JSGCTraceKind kind)
CheckCompartment(trc, comp, thing, kind);
} else {
JS_ASSERT(thing->tenuredZone() == trc->zone ||
thing->tenuredZone() == trc->runtime->atomsCompartment->zone());
trc->runtime->isAtomsZone(thing->tenuredZone()));
}
}
@ -2738,7 +2737,7 @@ BeginMarkPhase(JSRuntime *rt)
/* Set up which zones will be collected. */
if (zone->isGCScheduled()) {
if (zone != rt->atomsCompartment->zone()) {
if (!rt->isAtomsZone(zone)) {
any = true;
zone->setGCState(Zone::Mark);
}
@ -2768,7 +2767,7 @@ BeginMarkPhase(JSRuntime *rt)
* atoms. Otherwise, the non-collected zones could contain pointers
* to atoms that we would miss.
*/
Zone *atomsZone = rt->atomsCompartment->zone();
Zone *atomsZone = rt->atomsCompartment()->zone();
bool keepAtoms = false;
for (ThreadDataIter iter(rt); !iter.done(); iter.next())
@ -3302,8 +3301,8 @@ Zone::findOutgoingEdges(ComponentFinder<JS::Zone> &finder)
* compartment, and these aren't in the cross compartment map.
*/
JSRuntime *rt = runtimeFromMainThread();
if (rt->atomsCompartment->zone()->isGCMarking())
finder.addEdgeTo(rt->atomsCompartment->zone());
if (rt->atomsCompartment()->zone()->isGCMarking())
finder.addEdgeTo(rt->atomsCompartment()->zone());
for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next())
comp->findOutgoingEdges(finder);
@ -3649,7 +3648,7 @@ BeginSweepingZoneGroup(JSRuntime *rt)
/* Purge the ArenaLists before sweeping. */
zone->allocator.arenas.purge();
if (zone == rt->atomsCompartment->zone())
if (rt->isAtomsZone(zone))
sweepingAtoms = true;
}

View File

@ -394,7 +394,7 @@ NewGCThing(ThreadSafeContext *cx, AllocKind kind, size_t thingSize, InitialHeap
if (cx->isJSContext()) {
JSContext *ncx = cx->asJSContext();
JS_ASSERT_IF(ncx->compartment() == ncx->runtime()->atomsCompartment,
JS_ASSERT_IF(ncx->runtime()->isAtomsCompartment(ncx->compartment()),
kind == FINALIZE_STRING ||
kind == FINALIZE_SHORT_STRING ||
kind == FINALIZE_IONCODE);

View File

@ -550,8 +550,11 @@ js::Int32ToString(ThreadSafeContext *cx, int32_t si)
JS_ASSERT_IF(si == INT32_MIN, ui == uint32_t(INT32_MAX) + 1);
}
if (cx->isExclusiveContext()) {
if (JSFlatString *str = cx->asExclusiveContext()->dtoaCache().lookup(10, si))
JSCompartment *comp = cx->isExclusiveContext()
? cx->asExclusiveContext()->compartment()
: NULL;
if (comp) {
if (JSFlatString *str = comp->dtoaCache.lookup(10, si))
return str;
}
@ -570,8 +573,8 @@ js::Int32ToString(ThreadSafeContext *cx, int32_t si)
jschar *dst = str->init(end - start);
PodCopy(dst, start.get(), end - start + 1);
if (cx->isExclusiveContext())
cx->asExclusiveContext()->dtoaCache().cache(10, si, str);
if (comp)
comp->dtoaCache.cache(10, si, str);
return str;
}
@ -1275,6 +1278,10 @@ js_NumberToStringWithBase(ThreadSafeContext *cx, double d, int base)
if (base < 2 || base > 36)
return NULL;
JSCompartment *comp = cx->isExclusiveContext()
? cx->asExclusiveContext()->compartment()
: NULL;
int32_t i;
if (mozilla::DoubleIsInt32(d, &i)) {
if (base == 10 && StaticStrings::hasInt(i))
@ -1287,16 +1294,16 @@ js_NumberToStringWithBase(ThreadSafeContext *cx, double d, int base)
return cx->staticStrings().getUnit(c);
}
if (cx->isExclusiveContext()) {
if (JSFlatString *str = cx->asExclusiveContext()->dtoaCache().lookup(base, d))
if (comp) {
if (JSFlatString *str = comp->dtoaCache.lookup(base, d))
return str;
}
numStr = IntToCString(&cbuf, i, base);
JS_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
} else {
if (cx->isExclusiveContext()) {
if (JSFlatString *str = cx->asExclusiveContext()->dtoaCache().lookup(base, d))
if (comp) {
if (JSFlatString *str = comp->dtoaCache.lookup(base, d))
return str;
}
@ -1313,8 +1320,8 @@ js_NumberToStringWithBase(ThreadSafeContext *cx, double d, int base)
JSFlatString *s = js_NewStringCopyZ<allowGC>(cx, numStr);
if (cx->isExclusiveContext())
cx->asExclusiveContext()->dtoaCache().cache(base, d, s);
if (comp)
comp->dtoaCache.cache(base, d, s);
return s;
}

View File

@ -1186,7 +1186,7 @@ JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it)
if (!JSID_IS_EMPTY(child.propid))
MarkTypePropertyConfigured(cx, obj, child.propid);
last = cx->propertyTree().getChild(cx, last, obj->numFixedSlots(), child);
last = cx->compartment()->propertyTree.getChild(cx, last, obj->numFixedSlots(), child);
if (!last)
return false;
}

View File

@ -864,9 +864,10 @@ JSScript::initScriptCounts(JSContext *cx)
JS_ASSERT(size_t(cursor - base) == bytes);
/* Enable interrupts in any interpreter frames running on this script. */
InterpreterFrames *frames;
for (frames = cx->runtime()->interpreterFrames; frames; frames = frames->older)
frames->enableInterruptsIfRunning(this);
for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
if (iter.activation()->isInterpreter())
iter.activation()->asInterpreter()->enableInterruptsIfRunning(this);
}
return true;
}
@ -1590,7 +1591,7 @@ void
js::SweepScriptData(JSRuntime *rt)
{
JS_ASSERT(rt->gcIsFull);
ScriptDataTable &table = rt->scriptDataTable;
ScriptDataTable &table = rt->scriptDataTable();
bool keepAtoms = false;
for (ThreadDataIter iter(rt); !iter.done(); iter.next())
@ -1610,7 +1611,7 @@ js::SweepScriptData(JSRuntime *rt)
void
js::FreeScriptData(JSRuntime *rt)
{
ScriptDataTable &table = rt->scriptDataTable;
ScriptDataTable &table = rt->scriptDataTable();
if (!table.initialized())
return;
@ -2611,9 +2612,10 @@ JSScript::ensureHasDebugScript(JSContext *cx)
* interrupts enabled. The interrupts must stay enabled until the
* debug state is destroyed.
*/
InterpreterFrames *frames;
for (frames = cx->runtime()->interpreterFrames; frames; frames = frames->older)
frames->enableInterruptsIfRunning(this);
for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
if (iter.activation()->isInterpreter())
iter.activation()->asInterpreter()->enableInterruptsIfRunning(this);
}
return true;
}

View File

@ -700,10 +700,7 @@ class JSScript : public js::gc::Cell
js::ion::IonScript *const *addressOfIonScript() const {
return &ion;
}
void setIonScript(js::ion::IonScript *ionScript) {
ion = ionScript;
updateBaselineOrIonRaw();
}
inline void setIonScript(js::ion::IonScript *ionScript);
bool hasBaselineScript() const {
return baseline && baseline != BASELINE_DISABLED_SCRIPT;
@ -715,10 +712,7 @@ class JSScript : public js::gc::Cell
JS_ASSERT(hasBaselineScript());
return baseline;
}
void setBaselineScript(js::ion::BaselineScript *baselineScript) {
baseline = baselineScript;
updateBaselineOrIonRaw();
}
inline void setBaselineScript(js::ion::BaselineScript *baselineScript);
void updateBaselineOrIonRaw();
@ -741,9 +735,7 @@ class JSScript : public js::gc::Cell
js::ion::IonScript *maybeParallelIonScript() const {
return parallelIon;
}
void setParallelIonScript(js::ion::IonScript *ionScript) {
parallelIon = ionScript;
}
inline void setParallelIonScript(js::ion::IonScript *ionScript);
static size_t offsetOfBaselineScript() {
return offsetof(JSScript, baseline);

View File

@ -10,6 +10,7 @@
#include "jsscript.h"
#include "jit/AsmJSLink.h"
#include "jit/BaselineJIT.h"
#include "vm/ScopeObject.h"
#include "jscompartmentinlines.h"
@ -154,4 +155,29 @@ JSScript::setOriginalFunctionObject(JSObject *fun) {
enclosingScopeOrOriginalFunction_ = fun;
}
inline void
JSScript::setIonScript(js::ion::IonScript *ionScript) {
if (hasIonScript())
js::ion::IonScript::writeBarrierPre(tenuredZone(), ion);
ion = ionScript;
updateBaselineOrIonRaw();
}
inline void
JSScript::setParallelIonScript(js::ion::IonScript *ionScript) {
if (hasParallelIonScript())
js::ion::IonScript::writeBarrierPre(tenuredZone(), parallelIon);
parallelIon = ionScript;
}
inline void
JSScript::setBaselineScript(js::ion::BaselineScript *baselineScript) {
#ifdef JS_ION
if (hasBaselineScript())
js::ion::BaselineScript::writeBarrierPre(tenuredZone(), baseline);
#endif
baseline = baselineScript;
updateBaselineOrIonRaw();
}
#endif /* jsscriptinlines_h */

View File

@ -1926,7 +1926,7 @@ js::str_match(JSContext *cx, unsigned argc, Value *vp)
if (!g.normalizeRegExp(cx, false, 1, args))
return false;
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics();
Rooted<JSLinearString*> linearStr(cx, str->ensureLinear(cx));
if (!linearStr)
return false;
@ -1964,7 +1964,7 @@ js::str_search(JSContext *cx, unsigned argc, Value *vp)
const jschar *chars = linearStr->chars();
size_t length = linearStr->length();
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics();
/* Per ECMAv5 15.5.4.12 (5) The last index property is ignored and left unchanged. */
size_t i = 0;
@ -2627,13 +2627,13 @@ str_replace_regexp_remove(JSContext *cx, CallArgs args, HandleString str, RegExp
/* If unmatched, return the input string. */
if (!lastIndex) {
if (startIndex > 0)
cx->regExpStatics()->updateLazily(cx, stableStr, &re, lazyIndex);
cx->global()->getRegExpStatics()->updateLazily(cx, stableStr, &re, lazyIndex);
args.rval().setString(str);
return true;
}
/* The last successful match updates the RegExpStatics. */
cx->regExpStatics()->updateLazily(cx, stableStr, &re, lazyIndex);
cx->global()->getRegExpStatics()->updateLazily(cx, stableStr, &re, lazyIndex);
/* Include any remaining part of the string. */
if (lastIndex < charsLen) {
@ -2664,7 +2664,7 @@ str_replace_regexp(JSContext *cx, CallArgs args, ReplaceData &rdata)
rdata.leftIndex = 0;
rdata.calledBack = false;
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpShared &re = rdata.g.regExp();
/* Optimize removal. */
@ -3015,7 +3015,7 @@ SplitHelper(JSContext *cx, Handle<JSLinearString*> str, uint32_t limit, const Ma
/* Step 13(c)(iii)(6-7). */
if (Matcher::returnsCaptures) {
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics();
const MatchPairs &matches = res->getMatches();
for (size_t i = 0; i < matches.parenCount(); i++) {
/* Steps 13(c)(iii)(7)(a-c). */
@ -3196,7 +3196,7 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp)
SplitStringMatcher matcher(cx, sepstr);
aobj = SplitHelper(cx, linearStr, limit, matcher, type);
} else {
SplitRegExpMatcher matcher(*re, cx->regExpStatics());
SplitRegExpMatcher matcher(*re, cx->global()->getRegExpStatics());
aobj = SplitHelper(cx, linearStr, limit, matcher, type);
}
if (!aobj)

View File

@ -601,10 +601,12 @@ WorkerThread::threadLoop()
}
AutoPauseWorkersForGC::AutoPauseWorkersForGC(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: runtime(rt), needsUnpause(false)
: runtime(rt), needsUnpause(false), oldExclusiveThreadsPaused(rt->exclusiveThreadsPaused)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
rt->exclusiveThreadsPaused = true;
if (!runtime->workerThreadState)
return;
@ -634,6 +636,8 @@ AutoPauseWorkersForGC::AutoPauseWorkersForGC(JSRuntime *rt MOZ_GUARD_OBJECT_NOTI
AutoPauseWorkersForGC::~AutoPauseWorkersForGC()
{
runtime->exclusiveThreadsPaused = oldExclusiveThreadsPaused;
if (!needsUnpause)
return;

View File

@ -292,6 +292,7 @@ class AutoPauseWorkersForGC
#ifdef JS_WORKER_THREADS
JSRuntime *runtime;
bool needsUnpause;
mozilla::DebugOnly<bool> oldExclusiveThreadsPaused;
#endif
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER

View File

@ -177,7 +177,7 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
{
Rooted<GlobalObject*> self(cx, this);
JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
JS_ASSERT(isNative());
cx->setDefaultCompartmentObjectIfUnset(self);

View File

@ -975,30 +975,6 @@ TryNoteIter::settle()
goto error; \
JS_END_MACRO
template<typename T>
class GenericInterruptEnabler : public InterpreterFrames::InterruptEnablerBase {
public:
GenericInterruptEnabler(T *variable, T value) : variable(variable), value(value) { }
void enable() const { *variable = value; }
private:
T *variable;
T value;
};
inline InterpreterFrames::InterpreterFrames(JSContext *cx, FrameRegs *regs,
const InterruptEnablerBase &enabler)
: context(cx), regs(regs), enabler(enabler)
{
older = cx->runtime()->interpreterFrames;
cx->runtime()->interpreterFrames = this;
}
inline InterpreterFrames::~InterpreterFrames()
{
context->runtime()->interpreterFrames = older;
}
/*
* Ensure that the interpreter switch can close call-bytecode cases in the
* same way as non-call bytecodes.
@ -1287,10 +1263,19 @@ Interpret(JSContext *cx, RunState &state)
#define CHECK_PCCOUNT_INTERRUPTS() JS_ASSERT_IF(script->hasScriptCounts, switchMask == -1)
/*
* When Debugger puts a script in single-step mode, all js::Interpret
* invocations that might be presently running that script must have
* interrupts enabled. It's not practical to simply check
* script->stepModeEnabled() at each point some callee could have changed
* it, because there are so many places js::Interpret could possibly cause
* JavaScript to run: each place an object might be coerced to a primitive
* or a number, for example. So instead, we expose a simple mechanism to
* let Debugger tweak the affected js::Interpret frames when an onStep
* handler is added: setting switchMask to -1 will enable interrupts.
*/
register int switchMask = 0;
int switchOp;
typedef GenericInterruptEnabler<int> InterruptEnabler;
InterruptEnabler interrupts(&switchMask, -1);
# define DO_OP() goto do_op
@ -1345,7 +1330,7 @@ Interpret(JSContext *cx, RunState &state)
JS_BEGIN_MACRO \
script = (s); \
if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts) \
interrupts.enable(); \
switchMask = -1; /* Enable interrupts. */ \
JS_END_MACRO
FrameRegs regs;
@ -1364,13 +1349,7 @@ Interpret(JSContext *cx, RunState &state)
JS_ASSERT_IF(entryFrame->isEvalFrame(), state.script()->isActiveEval);
InterpreterActivation activation(cx, entryFrame, regs);
/*
* Help Debugger find frames running scripts that it has put in
* single-step mode.
*/
InterpreterFrames interpreterFrame(cx, &regs, interrupts);
InterpreterActivation activation(cx, entryFrame, regs, &switchMask);
/* Copy in hot values that change infrequently. */
JSRuntime *const rt = cx->runtime();
@ -1450,7 +1429,7 @@ Interpret(JSContext *cx, RunState &state)
len = 0;
if (rt->profilingScripts || cx->runtime()->debugHooks.interruptHook)
interrupts.enable();
switchMask = -1; /* Enable interrupts. */
goto advanceAndDoOp;

View File

@ -315,54 +315,6 @@ TypeOfValue(JSContext *cx, const Value &v);
extern bool
HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp);
/*
* A linked list of the |FrameRegs regs;| variables belonging to all
* js::Interpret C++ frames on this thread's stack.
*
* Note that this is *not* a list of all JS frames running under the
* interpreter; that would include inlined frames, whose FrameRegs are
* saved in various pieces in various places. Rather, this lists each
* js::Interpret call's live 'regs'; when control returns to that call, it
* will resume execution with this 'regs' instance.
*
* When Debugger puts a script in single-step mode, all js::Interpret
* invocations that might be presently running that script must have
* interrupts enabled. It's not practical to simply check
* script->stepModeEnabled() at each point some callee could have changed
* it, because there are so many places js::Interpret could possibly cause
* JavaScript to run: each place an object might be coerced to a primitive
* or a number, for example. So instead, we simply expose a list of the
* 'regs' those frames are using, and let Debugger tweak the affected
* js::Interpret frames when an onStep handler is established.
*
* Elements of this list are allocated within the js::Interpret stack
* frames themselves; the list is headed by this thread's js::ThreadData.
*/
class InterpreterFrames {
public:
class InterruptEnablerBase {
public:
virtual void enable() const = 0;
};
InterpreterFrames(JSContext *cx, FrameRegs *regs, const InterruptEnablerBase &enabler);
~InterpreterFrames();
/* If this js::Interpret frame is running |script|, enable interrupts. */
void enableInterruptsIfRunning(JSScript *script) {
if (regs->fp()->script() == script)
enabler.enable();
}
void enableInterruptsUnconditionally() { enabler.enable(); }
InterpreterFrames *older;
private:
JSContext *context;
FrameRegs *regs;
const InterruptEnablerBase &enabler;
};
/* Unwind block and scope chains to match the given depth. */
extern void
UnwindScope(JSContext *cx, AbstractFramePtr frame, uint32_t stackDepth);

View File

@ -264,7 +264,7 @@ RegExpObject::createShared(ExclusiveContext *cx, RegExpGuard *g)
Rooted<RegExpObject*> self(cx, this);
JS_ASSERT(!maybeShared());
if (!cx->regExps().get(cx, getSource(), getFlags(), g))
if (!cx->compartment()->regExps.get(cx, getSource(), getFlags(), g))
return false;
self->setShared(cx, **g);

View File

@ -528,12 +528,6 @@ RegExpStatics::checkInvariants()
#endif /* DEBUG */
}
inline RegExpStatics *
ExclusiveContext::regExpStatics()
{
return global()->getRegExpStatics();
}
} /* namespace js */
#endif /* vm_RegExpStatics_h */

View File

@ -108,9 +108,9 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
exclusiveAccessLock(NULL),
exclusiveAccessOwner(NULL),
mainThreadHasExclusiveAccess(false),
exclusiveThreadsPaused(false),
numExclusiveThreads(0),
#endif
atomsCompartment(NULL),
systemZone(NULL),
numCompartments(0),
localeCallbacks(NULL),
@ -127,7 +127,6 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
selfHostingGlobal_(NULL),
nativeStackBase(0),
nativeStackQuota(0),
interpreterFrames(NULL),
cxCallback(NULL),
destroyCompartmentCallback(NULL),
compartmentNameCallback(NULL),
@ -254,6 +253,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
#endif
mathCache_(NULL),
trustedPrincipals_(NULL),
atomsCompartment_(NULL),
wrapObjectCallback(TransparentObjectWrapper),
sameCompartmentWrapObjectCallback(NULL),
preWrapObjectCallback(NULL),
@ -353,7 +353,7 @@ JSRuntime::init(uint32_t maxbytes)
atomsZone->setGCLastBytes(8192, GC_NORMAL);
atomsZone.forget();
this->atomsCompartment = atomsCompartment.forget();
this->atomsCompartment_ = atomsCompartment.forget();
if (!InitAtoms(this))
return false;
@ -363,7 +363,7 @@ JSRuntime::init(uint32_t maxbytes)
dateTimeInfo.updateTimeZoneAdjustment();
if (!scriptDataTable.init())
if (!scriptDataTable_.init())
return false;
if (!threadPool.init())
@ -401,6 +401,9 @@ JSRuntime::~JSRuntime()
JS_ASSERT(!exclusiveAccessOwner);
if (exclusiveAccessLock)
PR_DestroyLock(exclusiveAccessLock);
JS_ASSERT(!numExclusiveThreads);
exclusiveThreadsPaused = true; // Avoid bogus asserts during teardown.
#endif
/*
@ -431,6 +434,8 @@ JSRuntime::~JSRuntime()
FinishAtoms(this);
js_FinishGC(this);
atomsCompartment_ = NULL;
#ifdef JS_THREADSAFE
if (gcLock)
PR_DestroyLock(gcLock);
@ -518,7 +523,7 @@ JSRuntime::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSi
rtSizes->object = mallocSizeOf(this);
rtSizes->atomsTable = atoms.sizeOfExcludingThis(mallocSizeOf);
rtSizes->atomsTable = atoms().sizeOfExcludingThis(mallocSizeOf);
rtSizes->contexts = 0;
for (ContextIter acx(this); !acx.done(); acx.next())
@ -540,8 +545,8 @@ JSRuntime::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSi
rtSizes->mathCache = mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
rtSizes->scriptData = scriptDataTable.sizeOfExcludingThis(mallocSizeOf);
for (ScriptDataTable::Range r = scriptDataTable.all(); !r.empty(); r.popFront())
rtSizes->scriptData = scriptDataTable().sizeOfExcludingThis(mallocSizeOf);
for (ScriptDataTable::Range r = scriptDataTable().all(); !r.empty(); r.popFront())
rtSizes->scriptData += mallocSizeOf(r.front());
}

View File

@ -76,7 +76,6 @@ typedef Rooted<JSLinearString*> RootedLinearString;
class Activation;
class ActivationIterator;
class AsmJSActivation;
class InterpreterFrames;
class MathCache;
class WorkerThreadState;
@ -663,6 +662,7 @@ class MarkingValidator;
typedef Vector<JS::Zone *, 1, SystemAllocPolicy> ZoneVector;
class AutoLockForExclusiveAccess;
class AutoPauseWorkersForGC;
} // namespace js
@ -758,11 +758,13 @@ struct JSRuntime : public JS::shadow::Runtime,
PRLock *exclusiveAccessLock;
mozilla::DebugOnly<PRThread *> exclusiveAccessOwner;
mozilla::DebugOnly<bool> mainThreadHasExclusiveAccess;
mozilla::DebugOnly<bool> exclusiveThreadsPaused;
/* Number of non-main threads with an ExclusiveContext. */
size_t numExclusiveThreads;
friend class js::AutoLockForExclusiveAccess;
friend class js::AutoPauseWorkersForGC;
public:
#endif // JS_THREADSAFE
@ -770,6 +772,7 @@ struct JSRuntime : public JS::shadow::Runtime,
bool currentThreadHasExclusiveAccess() {
#if defined(JS_THREADSAFE) && defined(DEBUG)
return (!numExclusiveThreads && mainThreadHasExclusiveAccess) ||
exclusiveThreadsPaused ||
exclusiveAccessOwner == PR_GetCurrentThread();
#else
return true;
@ -784,9 +787,6 @@ struct JSRuntime : public JS::shadow::Runtime,
#endif
}
/* Default compartment. */
JSCompartment *atomsCompartment;
/* Embedders can use this zone however they wish. */
JS::Zone *systemZone;
@ -917,12 +917,6 @@ struct JSRuntime : public JS::shadow::Runtime,
/* The native stack size limit that runtime should not exceed. */
size_t nativeStackQuota;
/*
* Frames currently running in js::Interpret. See InterpreterFrames for
* details.
*/
js::InterpreterFrames *interpreterFrames;
/* Context create/destroy callback. */
JSContextCallback cxCallback;
void *cxCallbackData;
@ -1370,8 +1364,15 @@ struct JSRuntime : public JS::shadow::Runtime,
js::ConservativeGCData conservativeGC;
/* Pool of maps used during parse/emit. */
js::frontend::ParseMapPool parseMapPool;
// Pool of maps used during parse/emit. This may be modified by threads
// with an ExclusiveContext and requires a lock.
private:
js::frontend::ParseMapPool parseMapPool_;
public:
js::frontend::ParseMapPool &parseMapPool() {
JS_ASSERT(currentThreadHasExclusiveAccess());
return parseMapPool_;
}
private:
JSPrincipals *trustedPrincipals_;
@ -1379,8 +1380,29 @@ struct JSRuntime : public JS::shadow::Runtime,
void setTrustedPrincipals(JSPrincipals *p) { trustedPrincipals_ = p; }
JSPrincipals *trustedPrincipals() const { return trustedPrincipals_; }
/* Set of all currently-living atoms. */
js::AtomSet atoms;
// Set of all currently-living atoms, and the compartment in which they
// reside. The atoms compartment is additionally used to hold runtime
// wide Ion code stubs. These may be modified by threads with an
// ExclusiveContext and require a lock.
private:
js::AtomSet atoms_;
JSCompartment *atomsCompartment_;
public:
js::AtomSet &atoms() {
JS_ASSERT(currentThreadHasExclusiveAccess());
return atoms_;
}
JSCompartment *atomsCompartment() {
JS_ASSERT(currentThreadHasExclusiveAccess());
return atomsCompartment_;
}
bool isAtomsCompartment(JSCompartment *comp) {
return comp == atomsCompartment_;
}
// The atoms compartment is the only one in its zone.
inline bool isAtomsZone(JS::Zone *zone);
union {
/*
@ -1400,7 +1422,16 @@ struct JSRuntime : public JS::shadow::Runtime,
JSPreWrapCallback preWrapObjectCallback;
js::PreserveWrapperCallback preserveWrapperCallback;
js::ScriptDataTable scriptDataTable;
// Table of bytecode and other data that may be shared across scripts
// within the runtime. This may be modified by threads with an
// ExclusiveContext and requires a lock.
private:
js::ScriptDataTable scriptDataTable_;
public:
js::ScriptDataTable &scriptDataTable() {
JS_ASSERT(currentThreadHasExclusiveAccess());
return scriptDataTable_;
}
#ifdef DEBUG
size_t noGCOrAllocationCheck;

View File

@ -275,7 +275,7 @@ Shape::getChildBinding(ExclusiveContext *cx, const StackShape &child)
gc::AllocKind kind = gc::GetGCObjectKind(slots);
uint32_t nfixed = gc::GetGCKindSlots(kind);
return cx->propertyTree().getChild(cx, this, nfixed, child);
return cx->compartment()->propertyTree.getChild(cx, this, nfixed, child);
}
/* static */ Shape *
@ -302,7 +302,8 @@ Shape::replaceLastProperty(ExclusiveContext *cx, const StackBaseShape &base,
child.base = nbase;
}
return cx->propertyTree().getChild(cx, shape->parent, shape->numFixedSlots(), child);
return cx->compartment()->propertyTree.getChild(cx, shape->parent,
shape->numFixedSlots(), child);
}
/*
@ -349,7 +350,7 @@ JSObject::getChildProperty(ExclusiveContext *cx,
}
shape->initDictionaryShape(child, obj->numFixedSlots(), &obj->shape_);
} else {
shape = cx->propertyTree().getChild(cx, parent, obj->numFixedSlots(), child);
shape = cx->compartment()->propertyTree.getChild(cx, parent, obj->numFixedSlots(), child);
if (!shape)
return NULL;
//JS_ASSERT(shape->parent == parent);
@ -1240,7 +1241,7 @@ StackBaseShape::AutoRooter::trace(JSTracer *trc)
/* static */ UnownedBaseShape*
BaseShape::getUnowned(ExclusiveContext *cx, const StackBaseShape &base)
{
BaseShapeSet &table = cx->baseShapes();
BaseShapeSet &table = cx->compartment()->baseShapes;
if (!table.initialized() && !table.init())
return NULL;
@ -1337,7 +1338,7 @@ EmptyShape::getInitialShape(ExclusiveContext *cx, Class *clasp, TaggedProto prot
JS_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
JS_ASSERT_IF(parent, cx->isInsideCurrentCompartment(parent));
InitialShapeSet &table = cx->initialShapes();
InitialShapeSet &table = cx->compartment()->initialShapes;
if (!table.initialized() && !table.init())
return NULL;
@ -1359,7 +1360,7 @@ EmptyShape::getInitialShape(ExclusiveContext *cx, Class *clasp, TaggedProto prot
if (!nbase)
return NULL;
Shape *shape = cx->propertyTree().newShape(cx);
Shape *shape = cx->compartment()->propertyTree.newShape(cx);
if (!shape)
return NULL;
new (shape) EmptyShape(nbase, nfixed);
@ -1409,7 +1410,7 @@ EmptyShape::insertInitialShape(ExclusiveContext *cx, HandleShape shape, HandleOb
shape->getObjectParent(), shape->getObjectMetadata(),
shape->numFixedSlots(), shape->getObjectFlags());
InitialShapeSet::Ptr p = cx->initialShapes().lookup(lookup);
InitialShapeSet::Ptr p = cx->compartment()->initialShapes.lookup(lookup);
JS_ASSERT(p);
InitialShapeEntry &entry = const_cast<InitialShapeEntry &>(*p);

View File

@ -833,11 +833,12 @@ Activation::~Activation()
cx_->mainThread().activation_ = prev_;
}
InterpreterActivation::InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs)
InterpreterActivation::InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs,
int *const switchMask)
: Activation(cx, Interpreter),
entry_(entry),
current_(entry),
regs_(regs)
regs_(regs),
switchMask_(switchMask)
#ifdef DEBUG
, oldFrameCount_(cx_->runtime()->interpreterStack().frameCount_)
#endif
@ -846,8 +847,8 @@ InterpreterActivation::InterpreterActivation(JSContext *cx, StackFrame *entry, F
InterpreterActivation::~InterpreterActivation()
{
// Pop all inline frames.
while (current_ != entry_)
popInlineFrame(current_);
while (regs_.fp() != entry_)
popInlineFrame(regs_.fp());
JS_ASSERT(oldFrameCount_ == cx_->runtime()->interpreterStack().frameCount_);
JS_ASSERT_IF(oldFrameCount_ == 0, cx_->runtime()->interpreterStack().allocator_.used() == 0);
@ -860,18 +861,15 @@ InterpreterActivation::pushInlineFrame(const CallArgs &args, HandleScript script
if (!cx_->runtime()->interpreterStack().pushInlineFrame(cx_, regs_, args, script, initial))
return false;
JS_ASSERT(regs_.fp()->script()->compartment() == compartment_);
current_ = regs_.fp();
return true;
}
inline void
InterpreterActivation::popInlineFrame(StackFrame *frame)
{
JS_ASSERT(current_ == frame);
JS_ASSERT(current_ != entry_);
current_ = frame->prev();
JS_ASSERT(current_);
(void)frame; // Quell compiler warning.
JS_ASSERT(regs_.fp() == frame);
JS_ASSERT(regs_.fp() != entry_);
cx_->runtime()->interpreterStack().popInlineFrame(regs_);
}

View File

@ -1226,15 +1226,16 @@ class InterpreterActivation : public Activation
friend class js::InterpreterFrameIterator;
StackFrame *const entry_; // Entry frame for this activation.
StackFrame *current_; // The most recent frame.
FrameRegs &regs_;
int *const switchMask_; // For debugger interrupts, see js::Interpret.
#ifdef DEBUG
size_t oldFrameCount_;
#endif
public:
inline InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs);
inline InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs &regs,
int *const switchMask);
inline ~InterpreterActivation();
inline bool pushInlineFrame(const CallArgs &args, HandleScript script,
@ -1242,12 +1243,20 @@ class InterpreterActivation : public Activation
inline void popInlineFrame(StackFrame *frame);
StackFrame *current() const {
JS_ASSERT(current_);
return current_;
return regs_.fp();
}
FrameRegs &regs() const {
return regs_;
}
// If this js::Interpret frame is running |script|, enable interrupts.
void enableInterruptsIfRunning(JSScript *script) {
if (regs_.fp()->script() == script)
enableInterruptsUnconditionally();
}
void enableInterruptsUnconditionally() {
*switchMask_ = -1;
}
};
// Iterates over a runtime's activation list.

View File

@ -627,7 +627,7 @@ bool
StaticStrings::init(JSContext *cx)
{
AutoLockForExclusiveAccess lock(cx);
AutoCompartment ac(cx, cx->runtime()->atomsCompartment);
AutoCompartment ac(cx, cx->runtime()->atomsCompartment());
for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++) {
jschar buffer[] = { jschar(i), '\0' };

Some files were not shown because too many files have changed in this diff Show More