mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-16 05:45:33 +00:00
Merge m-c to b2g-inbound.
This commit is contained in:
commit
3364547f5d
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
toolkit/library
|
||||
dom
|
||||
ipc
|
||||
security/sandbox
|
||||
ipc
|
||||
netwerk/build
|
||||
netwerk
|
||||
|
62
configure.in
62
configure.in
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
289
content/media/directshow/AudioSinkFilter.cpp
Normal file
289
content/media/directshow/AudioSinkFilter.cpp
Normal 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
|
||||
|
94
content/media/directshow/AudioSinkFilter.h
Normal file
94
content/media/directshow/AudioSinkFilter.h
Normal 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_
|
200
content/media/directshow/AudioSinkInputPin.cpp
Normal file
200
content/media/directshow/AudioSinkInputPin.cpp
Normal 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
|
||||
|
75
content/media/directshow/AudioSinkInputPin.h
Normal file
75
content/media/directshow/AudioSinkInputPin.h
Normal 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_
|
61
content/media/directshow/DirectShowDecoder.cpp
Normal file
61
content/media/directshow/DirectShowDecoder.cpp
Normal 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
|
||||
|
45
content/media/directshow/DirectShowDecoder.h
Normal file
45
content/media/directshow/DirectShowDecoder.h
Normal 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
|
366
content/media/directshow/DirectShowReader.cpp
Normal file
366
content/media/directshow/DirectShowReader.cpp
Normal 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
|
113
content/media/directshow/DirectShowReader.h
Normal file
113
content/media/directshow/DirectShowReader.h
Normal 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
|
309
content/media/directshow/DirectShowUtils.cpp
Normal file
309
content/media/directshow/DirectShowUtils.cpp
Normal 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
|
115
content/media/directshow/DirectShowUtils.h
Normal file
115
content/media/directshow/DirectShowUtils.h
Normal 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
|
23
content/media/directshow/Makefile.in
Normal file
23
content/media/directshow/Makefile.in
Normal 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
|
163
content/media/directshow/SampleSink.cpp
Normal file
163
content/media/directshow/SampleSink.cpp
Normal 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
|
||||
|
67
content/media/directshow/SampleSink.h
Normal file
67
content/media/directshow/SampleSink.h
Normal 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_
|
638
content/media/directshow/SourceFilter.cpp
Normal file
638
content/media/directshow/SourceFilter.cpp
Normal 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
|
71
content/media/directshow/SourceFilter.h
Normal file
71
content/media/directshow/SourceFilter.h
Normal 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
|
35
content/media/directshow/moz.build
Normal file
35
content/media/directshow/moz.build
Normal 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',
|
||||
]
|
@ -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']
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "gfxPoint.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsMemory.h"
|
||||
#include "prtypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -668,8 +668,6 @@ public:
|
||||
return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nullptr;
|
||||
}
|
||||
|
||||
static bool HasIndexedDBSupport();
|
||||
|
||||
static WindowByIdTable* GetWindowsTable() {
|
||||
return sWindowsById;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
5874
gfx/gl/GLConsts.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
3353
gfx/gl/GLDefs.h
3353
gfx/gl/GLDefs.h
File diff suppressed because it is too large
Load Diff
212
gfx/gl/GLParseRegistryXML.py
Executable file
212
gfx/gl/GLParseRegistryXML.py
Executable 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')
|
@ -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
|
||||
|
@ -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
83
gfx/gl/GLTypes.h
Normal 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
|
@ -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',
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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 ========================================================
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
8
js/src/jit-test/tests/ion/try-catch-5.js
Normal file
8
js/src/jit-test/tests/ion/try-catch-5.js
Normal file
@ -0,0 +1,8 @@
|
||||
function x() {
|
||||
try {
|
||||
do {
|
||||
var { q , gen } = t;
|
||||
} while(false);
|
||||
} catch (e) {}
|
||||
}
|
||||
x();
|
@ -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
|
||||
|
@ -255,6 +255,8 @@ struct BaselineScript
|
||||
static size_t offsetOfFlags() {
|
||||
return offsetof(BaselineScript, flags_);
|
||||
}
|
||||
|
||||
static void writeBarrierPre(Zone *zone, BaselineScript *script);
|
||||
};
|
||||
|
||||
inline bool
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ®Exps();
|
||||
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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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, ®s, 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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -528,12 +528,6 @@ RegExpStatics::checkInvariants()
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
inline RegExpStatics *
|
||||
ExclusiveContext::regExpStatics()
|
||||
{
|
||||
return global()->getRegExpStatics();
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_RegExpStatics_h */
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -833,11 +833,12 @@ Activation::~Activation()
|
||||
cx_->mainThread().activation_ = prev_;
|
||||
}
|
||||
|
||||
InterpreterActivation::InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs ®s)
|
||||
InterpreterActivation::InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs ®s,
|
||||
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_);
|
||||
}
|
||||
|
@ -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 ®s_;
|
||||
int *const switchMask_; // For debugger interrupts, see js::Interpret.
|
||||
|
||||
#ifdef DEBUG
|
||||
size_t oldFrameCount_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
inline InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs ®s);
|
||||
inline InterpreterActivation(JSContext *cx, StackFrame *entry, FrameRegs ®s,
|
||||
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 ®s() 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.
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user