Merge latest green b2g-inbound changeset and mozilla-central; a=merge

This commit is contained in:
Ed Morley 2014-08-05 15:47:28 +01:00
commit 66c14d6e52
185 changed files with 4588 additions and 1441 deletions

View File

@ -48,8 +48,6 @@
<menuitem value="ar" label="&font.langGroup.arabic;"/>
<menuitem value="x-armn" label="&font.langGroup.armenian;"/>
<menuitem value="x-beng" label="&font.langGroup.bengali;"/>
<menuitem value="x-baltic" label="&font.langGroup.baltic;"/>
<menuitem value="x-central-euro" label="&font.langGroup.latin2;"/>
<menuitem value="zh-CN" label="&font.langGroup.simpl-chinese;"/>
<menuitem value="zh-HK" label="&font.langGroup.trad-chinese-hk;"/>
<menuitem value="zh-TW" label="&font.langGroup.trad-chinese;"/>
@ -65,6 +63,7 @@
<menuitem value="x-knda" label="&font.langGroup.kannada;"/>
<menuitem value="x-khmr" label="&font.langGroup.khmer;"/>
<menuitem value="ko" label="&font.langGroup.korean;"/>
<menuitem value="x-western" label="&font.langGroup.latin;"/>
<menuitem value="x-mlym" label="&font.langGroup.malayalam;"/>
<menuitem value="x-orya" label="&font.langGroup.oriya;"/>
<menuitem value="x-sinh" label="&font.langGroup.sinhala;"/>
@ -72,10 +71,8 @@
<menuitem value="x-telu" label="&font.langGroup.telugu;"/>
<menuitem value="th" label="&font.langGroup.thai;"/>
<menuitem value="x-tibt" label="&font.langGroup.tibetan;"/>
<menuitem value="tr" label="&font.langGroup.turkish;"/>
<menuitem value="x-cans" label="&font.langGroup.canadian;"/>
<menuitem value="x-western" label="&font.langGroup.latin1;"/>
<menuitem value="x-unicode" label="&font.langGroup.unicode;"/>
<menuitem value="x-unicode" label="&font.langGroup.other;"/>
</menupopup>
</menulist>
</caption>

View File

@ -21,18 +21,17 @@
<!ENTITY monospace.label "Monospace:">
<!ENTITY monospace.accesskey "M">
<!ENTITY font.langGroup.latin1 "Western">
<!ENTITY font.langGroup.latin2 "Central European">
<!-- LOCALIZATION NOTE (font.langGroup.latin) :
Translate "Latin" as the name of Latin (Roman) script, not as the name of the Latin language. -->
<!ENTITY font.langGroup.latin "Latin">
<!ENTITY font.langGroup.japanese "Japanese">
<!ENTITY font.langGroup.trad-chinese "Traditional Chinese (Taiwan)">
<!ENTITY font.langGroup.simpl-chinese "Simplified Chinese">
<!ENTITY font.langGroup.trad-chinese-hk "Traditional Chinese (Hong Kong)">
<!ENTITY font.langGroup.korean "Korean">
<!ENTITY font.langGroup.cyrillic "Cyrillic">
<!ENTITY font.langGroup.baltic "Baltic">
<!ENTITY font.langGroup.el "Greek">
<!ENTITY font.langGroup.turkish "Turkish">
<!ENTITY font.langGroup.unicode "Other Languages">
<!ENTITY font.langGroup.other "Other Writing Systems">
<!ENTITY font.langGroup.thai "Thai">
<!ENTITY font.langGroup.hebrew "Hebrew">
<!ENTITY font.langGroup.arabic "Arabic">

View File

@ -3843,6 +3843,7 @@ MOZ_PAY=
MOZ_AUDIO_CHANNEL_MANAGER=
NSS_NO_LIBPKIX=
MOZ_CONTENT_SANDBOX=
MOZ_GMP_SANDBOX=
JSGC_USE_EXACT_ROOTING=1
JSGC_GENERATIONAL=
@ -6394,6 +6395,28 @@ fi
AC_SUBST(MOZ_CONTENT_SANDBOX)
dnl ========================================================
dnl = Gecko Media Plugin sandboxing
dnl ========================================================
case $OS_TARGET in
WINNT)
MOZ_GMP_SANDBOX=1
;;
Linux)
case $CPU_ARCH in
x86_64|x86)
MOZ_GMP_SANDBOX=1
;;
esac
;;
esac
if test -n "$MOZ_GMP_SANDBOX"; then
AC_DEFINE(MOZ_GMP_SANDBOX)
fi
AC_SUBST(MOZ_GMP_SANDBOX)
dnl ========================================================
dnl =
dnl = Module specific options

View File

@ -2170,6 +2170,13 @@ public:
*/
static bool IsContentInsertionPoint(const nsIContent* aContent);
/**
* Returns whether the children of the provided content are
* nodes that are distributed to Shadow DOM insertion points.
*/
static bool HasDistributedChildren(nsIContent* aContent);
/**
* Returns whether a given header is forbidden for an XHR or fetch
* request.

View File

@ -152,21 +152,23 @@ nsIContent::FindFirstNonChromeOnlyAccessContent() const
nsIContent*
nsIContent::GetFlattenedTreeParent() const
{
nsIContent* parent = nullptr;
nsIContent* parent = GetParent();
nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
if (destInsertionPoints && !destInsertionPoints->IsEmpty()) {
// This node was distributed into an insertion point. The last node in
// the list of destination insertion insertion points is where this node
// appears in the composed tree (see Shadow DOM spec).
nsIContent* lastInsertionPoint = destInsertionPoints->LastElement();
parent = lastInsertionPoint->GetParent();
if (nsContentUtils::HasDistributedChildren(parent)) {
// This node is distributed to insertion points, thus we
// need to consult the destination insertion points list to
// figure out where this node was inserted in the flattened tree.
// It may be the case that |parent| distributes its children
// but the child does not match any insertion points, thus
// the flattened tree parent is nullptr.
nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ?
destInsertionPoints->LastElement()->GetParent() : nullptr;
} else if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
parent = GetXBLInsertionParent();
}
if (!parent) {
parent = GetParent();
nsIContent* insertionParent = GetXBLInsertionParent();
if (insertionParent) {
parent = insertionParent;
}
}
// Shadow roots never shows up in the flattened tree. Return the host

View File

@ -40,6 +40,7 @@
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TextDecoder.h"
#include "mozilla/dom/TouchEvent.h"
@ -6874,6 +6875,45 @@ nsContentUtils::IsContentInsertionPoint(const nsIContent* aContent)
return false;
}
// static
bool
nsContentUtils::HasDistributedChildren(nsIContent* aContent)
{
if (!aContent) {
return false;
}
if (aContent->GetShadowRoot()) {
// Children of a shadow root host are distributed
// to content insertion points in the shadow root.
return true;
}
ShadowRoot* shadow = ShadowRoot::FromNode(aContent);
if (shadow) {
// Children of a shadow root are distributed to
// the shadow insertion point of the younger shadow root.
return shadow->GetYoungerShadow();
}
HTMLShadowElement* shadowEl = HTMLShadowElement::FromContent(aContent);
if (shadowEl && shadowEl->IsInsertionPoint()) {
// Children of a shadow insertion points are distributed
// to the insertion points in the older shadow root.
return shadow->GetOlderShadow();
}
HTMLContentElement* contentEl = HTMLContentElement::FromContent(aContent);
if (contentEl && contentEl->IsInsertionPoint()) {
// Children of a content insertion point are distributed to the
// content insertion point if the content insertion point does
// not match any nodes (fallback content).
return contentEl->MatchedNodes().IsEmpty();
}
return false;
}
// static
bool
nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader)

View File

@ -2028,7 +2028,6 @@ GK_ATOM(zh_tw, "zh-tw")
GK_ATOM(x_cyrillic, "x-cyrillic")
GK_ATOM(he, "he")
GK_ATOM(ar, "ar")
GK_ATOM(x_baltic, "x-baltic")
GK_ATOM(x_devanagari, "x-devanagari")
GK_ATOM(x_tamil, "x-tamil")
GK_ATOM(x_armn, "x-armn")
@ -2048,7 +2047,6 @@ GK_ATOM(x_tibt, "x-tibt")
// used in gfxGDIFontList.h
GK_ATOM(ko_xxx, "ko-xxx")
GK_ATOM(x_central_euro, "x-central-euro")
GK_ATOM(x_symbol, "x-symbol")
// additional languages that have special case transformations

View File

@ -21,6 +21,8 @@ class HTMLContentElement MOZ_FINAL : public nsGenericHTMLElement
public:
HTMLContentElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLContentElement, content)
// nsISupports
NS_DECL_ISUPPORTS_INHERITED

View File

@ -17,6 +17,8 @@ class HTMLShadowElement MOZ_FINAL : public nsGenericHTMLElement,
public:
HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLShadowElement, shadow)
// nsISupports
NS_DECL_ISUPPORTS_INHERITED

View File

@ -105,6 +105,7 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
, mVideo("MP4 video decoder data", Preferences::GetUint("media.mp4-video-decode-ahead", 2))
, mLastReportedNumDecodedFrames(0)
, mLayersBackendType(layers::LayersBackend::LAYERS_NONE)
, mTimeRangesMonitor("MP4Reader::TimeRanges")
, mDemuxerInitialized(false)
, mIsEncrypted(false)
{
@ -705,20 +706,30 @@ MP4Reader::Seek(int64_t aTime,
return NS_OK;
}
nsresult
MP4Reader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
void
MP4Reader::NotifyDataArrived(const char* aBuffer, uint32_t aLength,
int64_t aOffset)
{
nsTArray<MediaByteRange> ranges;
if (NS_FAILED(mDecoder->GetResource()->GetCachedRanges(ranges))) {
return NS_ERROR_FAILURE;
return;
}
nsTArray<Interval<Microseconds>> timeRanges;
mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges);
for (size_t i = 0; i < timeRanges.Length(); i++) {
aBuffered->Add((timeRanges[i].start - aStartTime) / 1000000.0,
(timeRanges[i].end - aStartTime) / 1000000.0);
MonitorAutoLock mon(mTimeRangesMonitor);
mTimeRanges = timeRanges;
}
nsresult
MP4Reader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
{
MonitorAutoLock mon(mTimeRangesMonitor);
for (size_t i = 0; i < mTimeRanges.Length(); i++) {
aBuffered->Add((mTimeRanges[i].start - aStartTime) / 1000000.0,
(mTimeRanges[i].end - aStartTime) / 1000000.0);
}
return NS_OK;

View File

@ -53,6 +53,9 @@ public:
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength,
int64_t aOffset) MOZ_OVERRIDE;
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
int64_t aStartTime) MOZ_OVERRIDE;
@ -165,6 +168,8 @@ private:
layers::LayersBackend mLayersBackendType;
nsTArray<nsTArray<uint8_t>> mInitDataEncountered;
Monitor mTimeRangesMonitor;
nsTArray<mp4_demuxer::Interval<Microseconds>> mTimeRanges;
// True if we've read the streams' metadata.
bool mDemuxerInitialized;

View File

@ -93,9 +93,6 @@ PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
if (!pdm) {
return nullptr;
}
} else {
NS_WARNING("CDM that decodes not yet supported!");
return nullptr;
}
return new EMEDecoderModule(aProxy,

View File

@ -0,0 +1,319 @@
/* -*- 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 "EMEAACDecoder.h"
#include "mp4_demuxer/DecoderData.h"
#include "mozilla/EMELog.h"
#include "gmp-audio-host.h"
#include "gmp-audio-decode.h"
#include "gmp-audio-samples.h"
#include "GMPAudioHost.h"
#include "GMPAudioDecoderProxy.h"
#include "mozilla/CDMProxy.h"
#include "nsServiceManagerUtils.h"
#include "prsystem.h"
namespace mozilla {
EMEAACDecoder::EMEAACDecoder(CDMProxy* aProxy,
const AudioDecoderConfig& aConfig,
MediaTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback)
: mAudioRate(0)
, mAudioBytesPerSample(0)
, mAudioChannels(0)
, mMustRecaptureAudioPosition(true)
, mAudioFrameSum(0)
, mAudioFrameOffset(0)
, mStreamOffset(0)
, mProxy(aProxy)
, mGMP(nullptr)
, mConfig(aConfig)
, mTaskQueue(aTaskQueue)
, mCallback(aCallback)
, mMonitor("EMEAACDecoder")
, mFlushComplete(false)
{
}
EMEAACDecoder::~EMEAACDecoder()
{
}
nsresult
EMEAACDecoder::Init()
{
// Note: this runs on the decode task queue.
MOZ_ASSERT((mConfig.bits_per_sample / 8) == 2); // Demuxer guarantees this.
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
MOZ_ASSERT(mMPS);
nsresult rv = mMPS->GetThread(getter_AddRefs(mGMPThread));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<InitTask> task(new InitTask(this));
rv = mGMPThread->Dispatch(task, NS_DISPATCH_SYNC);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(task->mResult, task->mResult);
return NS_OK;
}
nsresult
EMEAACDecoder::Input(MP4Sample* aSample)
{
MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
nsRefPtr<nsIRunnable> task(new DeliverSample(this, aSample));
nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
EMEAACDecoder::Flush()
{
MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
{
MonitorAutoLock mon(mMonitor);
mFlushComplete = false;
}
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethod(this, &EMEAACDecoder::GmpFlush);
nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
{
MonitorAutoLock mon(mMonitor);
while (!mFlushComplete) {
mon.Wait();
}
}
return NS_OK;
}
nsresult
EMEAACDecoder::Drain()
{
MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethod(this, &EMEAACDecoder::GmpDrain);
nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
EMEAACDecoder::Shutdown()
{
MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethod(this, &EMEAACDecoder::GmpShutdown);
nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_SYNC);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
void
EMEAACDecoder::Decoded(const nsTArray<int16_t>& aPCM,
uint64_t aTimeStamp)
{
MOZ_ASSERT(IsOnGMPThread());
size_t numFrames = aPCM.Length() / mAudioChannels;
nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[aPCM.Length()]);
for (size_t i = 0; i < aPCM.Length(); ++i) {
audioData[i] = AudioSampleToFloat(aPCM[i]);
}
if (mMustRecaptureAudioPosition) {
mAudioFrameSum = 0;
auto timestamp = UsecsToFrames(aTimeStamp, mAudioRate);
if (!timestamp.isValid()) {
NS_WARNING("Invalid timestamp");
mCallback->Error();
return;
}
mAudioFrameOffset = timestamp.value();
MOZ_ASSERT(mAudioFrameOffset >= 0);
mMustRecaptureAudioPosition = false;
}
auto timestamp = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate);
if (!timestamp.isValid()) {
NS_WARNING("Invalid timestamp on audio samples");
mCallback->Error();
return;
}
mAudioFrameSum += numFrames;
auto duration = FramesToUsecs(numFrames, mAudioRate);
if (!duration.isValid()) {
NS_WARNING("Invalid duration on audio samples");
mCallback->Error();
return;
}
nsAutoPtr<AudioData> audio(new AudioData(mStreamOffset,
timestamp.value(),
duration.value(),
numFrames,
audioData.forget(),
mAudioChannels));
#ifdef LOG_SAMPLE_DECODE
LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
timestamp, duration, currentLength);
#endif
mCallback->Output(audio.forget());
}
void
EMEAACDecoder::InputDataExhausted()
{
MOZ_ASSERT(IsOnGMPThread());
mCallback->InputExhausted();
}
void
EMEAACDecoder::DrainComplete()
{
MOZ_ASSERT(IsOnGMPThread());
mCallback->DrainComplete();
}
void
EMEAACDecoder::ResetComplete()
{
MOZ_ASSERT(IsOnGMPThread());
mMustRecaptureAudioPosition = true;
{
MonitorAutoLock mon(mMonitor);
mFlushComplete = true;
mon.NotifyAll();
}
}
void
EMEAACDecoder::Error(GMPErr aErr)
{
MOZ_ASSERT(IsOnGMPThread());
mCallback->Error();
GmpShutdown();
}
void
EMEAACDecoder::Terminated()
{
MOZ_ASSERT(IsOnGMPThread());
GmpShutdown();
}
nsresult
EMEAACDecoder::GmpInit()
{
MOZ_ASSERT(IsOnGMPThread());
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("aac"));
tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
nsresult rv = mMPS->GetGMPAudioDecoder(&tags,
mProxy->GetOrigin(),
&mGMP);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(mGMP);
mAudioRate = mConfig.samples_per_second;
mAudioBytesPerSample = mConfig.bits_per_sample / 8;
mAudioChannels = mConfig.channel_count;
nsTArray<uint8_t> extraData;
extraData.AppendElements(&mConfig.audio_specific_config[0],
mConfig.audio_specific_config.length());
mGMP->InitDecode(kGMPAudioCodecAAC,
mAudioChannels,
mConfig.bits_per_sample,
mAudioRate,
extraData,
this);
return NS_OK;
}
nsresult
EMEAACDecoder::GmpInput(MP4Sample* aSample)
{
MOZ_ASSERT(IsOnGMPThread());
nsAutoPtr<MP4Sample> sample(aSample);
if (!mGMP) {
mCallback->Error();
return NS_ERROR_FAILURE;
}
if (sample->crypto.valid) {
CDMCaps::AutoLock caps(mProxy->Capabilites());
MOZ_ASSERT(caps.CanDecryptAndDecodeAudio());
const auto& keyid = sample->crypto.key;
if (!caps.IsKeyUsable(keyid)) {
// DeliverSample assumes responsibility for deleting aSample.
nsRefPtr<nsIRunnable> task(new DeliverSample(this, sample.forget()));
caps.CallWhenKeyUsable(keyid, task, mGMPThread);
return NS_OK;
}
}
gmp::GMPAudioSamplesImpl samples(sample);
mGMP->Decode(samples);
mStreamOffset = sample->byte_offset;
return NS_OK;
}
void
EMEAACDecoder::GmpFlush()
{
MOZ_ASSERT(IsOnGMPThread());
if (!mGMP || NS_FAILED(mGMP->Reset())) {
// Abort the flush...
MonitorAutoLock mon(mMonitor);
mFlushComplete = true;
mon.NotifyAll();
}
}
void
EMEAACDecoder::GmpDrain()
{
MOZ_ASSERT(IsOnGMPThread());
if (!mGMP || NS_FAILED(mGMP->Drain())) {
mCallback->DrainComplete();
}
}
void
EMEAACDecoder::GmpShutdown()
{
MOZ_ASSERT(IsOnGMPThread());
if (!mGMP) {
return;
}
mGMP->Close();
mGMP = nullptr;
}
} // namespace mozilla

View File

@ -0,0 +1,115 @@
/* -*- 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/. */
#ifndef EMEAACDecoder_h_
#define EMEAACDecoder_h_
#include "PlatformDecoderModule.h"
#include "mp4_demuxer/DecoderData.h"
#include "mozIGeckoMediaPluginService.h"
#include "nsServiceManagerUtils.h"
#include "GMPAudioHost.h"
#include "GMPAudioDecoderProxy.h"
namespace mozilla {
class EMEAACDecoder : public MediaDataDecoder
, public GMPAudioDecoderProxyCallback
{
typedef mp4_demuxer::MP4Sample MP4Sample;
typedef mp4_demuxer::AudioDecoderConfig AudioDecoderConfig;
public:
EMEAACDecoder(CDMProxy* aProxy,
const AudioDecoderConfig& aConfig,
MediaTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback);
~EMEAACDecoder();
// MediaDataDecoder implementation.
virtual nsresult Init() MOZ_OVERRIDE;
virtual nsresult Input(MP4Sample* aSample) MOZ_OVERRIDE;
virtual nsresult Flush() MOZ_OVERRIDE;
virtual nsresult Drain() MOZ_OVERRIDE;
virtual nsresult Shutdown() MOZ_OVERRIDE;
// GMPAudioDecoderProxyCallback implementation.
virtual void Decoded(const nsTArray<int16_t>& aPCM,
uint64_t aTimeStamp) MOZ_OVERRIDE;
virtual void InputDataExhausted() MOZ_OVERRIDE;
virtual void DrainComplete() MOZ_OVERRIDE;
virtual void ResetComplete() MOZ_OVERRIDE;
virtual void Error(GMPErr aErr) MOZ_OVERRIDE;
virtual void Terminated() MOZ_OVERRIDE;
private:
class DeliverSample : public nsRunnable {
public:
DeliverSample(EMEAACDecoder* aDecoder,
mp4_demuxer::MP4Sample* aSample)
: mDecoder(aDecoder)
, mSample(aSample)
{}
NS_IMETHOD Run() {
mDecoder->GmpInput(mSample.forget());
return NS_OK;
}
private:
nsRefPtr<EMEAACDecoder> mDecoder;
nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
};
class InitTask : public nsRunnable {
public:
InitTask(EMEAACDecoder* aDecoder)
: mDecoder(aDecoder)
{}
NS_IMETHOD Run() {
mResult = mDecoder->GmpInit();
return NS_OK;
}
nsresult mResult;
EMEAACDecoder* mDecoder;
};
nsresult GmpInit();
nsresult GmpInput(MP4Sample* aSample);
void GmpFlush();
void GmpDrain();
void GmpShutdown();
#ifdef DEBUG
bool IsOnGMPThread() {
return NS_GetCurrentThread() == mGMPThread;
}
#endif
uint32_t mAudioRate;
uint32_t mAudioBytesPerSample;
uint32_t mAudioChannels;
bool mMustRecaptureAudioPosition;
int64_t mAudioFrameSum;
int64_t mAudioFrameOffset;
int64_t mStreamOffset;
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
nsCOMPtr<nsIThread> mGMPThread;
nsRefPtr<CDMProxy> mProxy;
GMPAudioDecoderProxy* mGMP;
const mp4_demuxer::AudioDecoderConfig& mConfig;
nsRefPtr<MediaTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;
Monitor mMonitor;
bool mFlushComplete;
};
} // namespace mozilla
#endif

View File

@ -18,6 +18,8 @@
#include "MediaTaskQueue.h"
#include "SharedThreadPool.h"
#include "mozilla/EMELog.h"
#include "EMEH264Decoder.h"
#include "EMEAACDecoder.h"
#include <string>
namespace mozilla {
@ -199,8 +201,13 @@ EMEDecoderModule::CreateH264Decoder(const VideoDecoderConfig& aConfig,
MediaDataDecoderCallback* aCallback)
{
if (mCDMDecodesVideo) {
NS_WARNING("Support for CDM that decodes video not yet supported");
return nullptr;
nsRefPtr<MediaDataDecoder> decoder(new EMEH264Decoder(mProxy,
aConfig,
aLayersBackend,
aImageContainer,
aVideoTaskQueue,
aCallback));
return decoder.forget();
}
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateH264Decoder(aConfig,
@ -225,8 +232,11 @@ EMEDecoderModule::CreateAACDecoder(const AudioDecoderConfig& aConfig,
MediaDataDecoderCallback* aCallback)
{
if (mCDMDecodesAudio) {
NS_WARNING("Support for CDM that decodes audio not yet supported");
return nullptr;
nsRefPtr<MediaDataDecoder> decoder(new EMEAACDecoder(mProxy,
aConfig,
aAudioTaskQueue,
aCallback));
return decoder.forget();
}
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateAACDecoder(aConfig,

View File

@ -0,0 +1,360 @@
/* -*- 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 "EMEH264Decoder.h"
#include "gmp-video-host.h"
#include "gmp-video-decode.h"
#include "gmp-video-frame-i420.h"
#include "gmp-video-frame-encoded.h"
#include "GMPVideoEncodedFrameImpl.h"
#include "mp4_demuxer/AnnexB.h"
#include "mozilla/CDMProxy.h"
#include "nsServiceManagerUtils.h"
#include "prsystem.h"
#include "gfx2DGlue.h"
namespace mozilla {
EMEH264Decoder::EMEH264Decoder(CDMProxy* aProxy,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer,
MediaTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback)
: mProxy(aProxy)
, mGMP(nullptr)
, mHost(nullptr)
, mConfig(aConfig)
, mImageContainer(aImageContainer)
, mTaskQueue(aTaskQueue)
, mCallback(aCallback)
, mLastStreamOffset(0)
, mMonitor("EMEH264Decoder")
, mFlushComplete(false)
{
}
EMEH264Decoder::~EMEH264Decoder() {
}
nsresult
EMEH264Decoder::Init()
{
// Note: this runs on the decode task queue.
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
MOZ_ASSERT(mMPS);
nsresult rv = mMPS->GetThread(getter_AddRefs(mGMPThread));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<InitTask> task(new InitTask(this));
rv = mGMPThread->Dispatch(task, NS_DISPATCH_SYNC);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(task->mResult, task->mResult);
return NS_OK;
}
nsresult
EMEH264Decoder::Input(MP4Sample* aSample)
{
MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
nsRefPtr<nsIRunnable> task(new DeliverSample(this, aSample));
nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
EMEH264Decoder::Flush()
{
MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
{
MonitorAutoLock mon(mMonitor);
mFlushComplete = false;
}
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethod(this, &EMEH264Decoder::GmpFlush);
nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
{
MonitorAutoLock mon(mMonitor);
while (!mFlushComplete) {
mon.Wait();
}
}
return NS_OK;
}
nsresult
EMEH264Decoder::Drain()
{
MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethod(this, &EMEH264Decoder::GmpDrain);
nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
EMEH264Decoder::Shutdown()
{
MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethod(this, &EMEH264Decoder::GmpShutdown);
nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_SYNC);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
void
EMEH264Decoder::Decoded(GMPVideoi420Frame* aDecodedFrame)
{
MOZ_ASSERT(IsOnGMPThread());
VideoData::YCbCrBuffer b;
auto height = aDecodedFrame->Height();
auto width = aDecodedFrame->Width();
// Y (Y') plane
b.mPlanes[0].mData = aDecodedFrame->Buffer(kGMPYPlane);
b.mPlanes[0].mStride = aDecodedFrame->Stride(kGMPYPlane);
b.mPlanes[0].mHeight = height;
b.mPlanes[0].mWidth = width;
b.mPlanes[0].mOffset = 0;
b.mPlanes[0].mSkip = 0;
// U plane (Cb)
b.mPlanes[1].mData = aDecodedFrame->Buffer(kGMPUPlane);
b.mPlanes[1].mStride = aDecodedFrame->Stride(kGMPUPlane);
b.mPlanes[1].mHeight = height / 2;
b.mPlanes[1].mWidth = width / 2;
b.mPlanes[1].mOffset = 0;
b.mPlanes[1].mSkip = 0;
// V plane (Cr)
b.mPlanes[2].mData = aDecodedFrame->Buffer(kGMPVPlane);
b.mPlanes[2].mStride = aDecodedFrame->Stride(kGMPVPlane);
b.mPlanes[2].mHeight = height / 2;
b.mPlanes[2].mWidth = width / 2;
b.mPlanes[2].mOffset = 0;
b.mPlanes[2].mSkip = 0;
VideoData *v = VideoData::Create(mVideoInfo,
mImageContainer,
mLastStreamOffset,
aDecodedFrame->Timestamp(),
aDecodedFrame->Duration(),
b,
false,
-1,
ToIntRect(mPictureRegion));
aDecodedFrame->Destroy();
mCallback->Output(v);
}
void
EMEH264Decoder::ReceivedDecodedReferenceFrame(const uint64_t aPictureId)
{
// Ignore.
}
void
EMEH264Decoder::ReceivedDecodedFrame(const uint64_t aPictureId)
{
// Ignore.
}
void
EMEH264Decoder::InputDataExhausted()
{
MOZ_ASSERT(IsOnGMPThread());
mCallback->InputExhausted();
}
void
EMEH264Decoder::DrainComplete()
{
MOZ_ASSERT(IsOnGMPThread());
mCallback->DrainComplete();
}
void
EMEH264Decoder::ResetComplete()
{
MOZ_ASSERT(IsOnGMPThread());
{
MonitorAutoLock mon(mMonitor);
mFlushComplete = true;
mon.NotifyAll();
}
}
void
EMEH264Decoder::Error(GMPErr aErr)
{
MOZ_ASSERT(IsOnGMPThread());
mCallback->Error();
GmpShutdown();
}
void
EMEH264Decoder::Terminated()
{
MOZ_ASSERT(IsOnGMPThread());
NS_WARNING("H.264 GMP decoder terminated.");
GmpShutdown();
}
nsresult
EMEH264Decoder::GmpInit()
{
MOZ_ASSERT(IsOnGMPThread());
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
nsresult rv = mMPS->GetGMPVideoDecoder(&tags,
mProxy->GetOrigin(),
&mHost,
&mGMP);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(mHost && mGMP);
GMPVideoCodec codec;
memset(&codec, 0, sizeof(codec));
codec.mGMPApiVersion = kGMPVersion33;
codec.mCodecType = kGMPVideoCodecH264;
codec.mWidth = mConfig.display_width;
codec.mHeight = mConfig.display_height;
nsTArray<uint8_t> codecSpecific;
codecSpecific.AppendElement(0); // mPacketizationMode.
codecSpecific.AppendElements(mConfig.extra_data.begin(),
mConfig.extra_data.length());
rv = mGMP->InitDecode(codec,
codecSpecific,
this,
PR_GetNumberOfProcessors());
NS_ENSURE_SUCCESS(rv, rv);
mVideoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
mVideoInfo.mHasVideo = true;
mPictureRegion = nsIntRect(0, 0, mConfig.display_width, mConfig.display_height);
return NS_OK;
}
nsresult
EMEH264Decoder::GmpInput(MP4Sample* aSample)
{
MOZ_ASSERT(IsOnGMPThread());
nsAutoPtr<MP4Sample> sample(aSample);
if (!mGMP) {
mCallback->Error();
return NS_ERROR_FAILURE;
}
if (sample->crypto.valid) {
CDMCaps::AutoLock caps(mProxy->Capabilites());
MOZ_ASSERT(caps.CanDecryptAndDecodeVideo());
const auto& keyid = sample->crypto.key;
if (!caps.IsKeyUsable(keyid)) {
nsRefPtr<nsIRunnable> task(new DeliverSample(this, sample.forget()));
caps.CallWhenKeyUsable(keyid, task, mGMPThread);
return NS_OK;
}
}
mLastStreamOffset = sample->byte_offset;
GMPVideoFrame* ftmp = nullptr;
GMPErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
if (GMP_FAILED(err)) {
mCallback->Error();
return NS_ERROR_FAILURE;
}
gmp::GMPVideoEncodedFrameImpl* frame = static_cast<gmp::GMPVideoEncodedFrameImpl*>(ftmp);
err = frame->CreateEmptyFrame(sample->size);
if (GMP_FAILED(err)) {
mCallback->Error();
return NS_ERROR_FAILURE;
}
memcpy(frame->Buffer(), sample->data, frame->Size());
frame->SetEncodedWidth(mConfig.display_width);
frame->SetEncodedHeight(mConfig.display_height);
frame->SetTimeStamp(sample->composition_timestamp);
frame->SetCompleteFrame(true);
frame->SetDuration(sample->duration);
if (sample->crypto.valid) {
frame->InitCrypto(sample->crypto);
}
frame->SetFrameType(sample->is_sync_point ? kGMPKeyFrame : kGMPDeltaFrame);
frame->SetBufferType(GMP_BufferLength32);
nsTArray<uint8_t> info; // No codec specific per-frame info to pass.
nsresult rv = mGMP->Decode(frame, false, info, 0);
if (NS_FAILED(rv)) {
mCallback->Error();
return rv;
}
return NS_OK;
}
void
EMEH264Decoder::GmpFlush()
{
MOZ_ASSERT(IsOnGMPThread());
if (!mGMP || NS_FAILED(mGMP->Reset())) {
// Abort the flush...
MonitorAutoLock mon(mMonitor);
mFlushComplete = true;
mon.NotifyAll();
}
}
void
EMEH264Decoder::GmpDrain()
{
MOZ_ASSERT(IsOnGMPThread());
if (!mGMP || NS_FAILED(mGMP->Drain())) {
mCallback->DrainComplete();
}
}
void
EMEH264Decoder::GmpShutdown()
{
MOZ_ASSERT(IsOnGMPThread());
if (!mGMP) {
return;
}
mGMP->Close();
mGMP = nullptr;
}
} // namespace mozilla

View File

@ -0,0 +1,114 @@
/* -*- 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/. */
#ifndef EMEH264Decoder_h_
#define EMEH264Decoder_h_
#include "PlatformDecoderModule.h"
#include "mp4_demuxer/DecoderData.h"
#include "ImageContainer.h"
#include "GMPVideoDecoderProxy.h"
#include "mozIGeckoMediaPluginService.h"
namespace mozilla {
class CDMProxy;
class MediaTaskQueue;
class EMEH264Decoder : public MediaDataDecoder
, public GMPVideoDecoderCallbackProxy
{
typedef mp4_demuxer::MP4Sample MP4Sample;
public:
EMEH264Decoder(CDMProxy* aProxy,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer,
MediaTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback);
~EMEH264Decoder();
// MediaDataDecoder
virtual nsresult Init() MOZ_OVERRIDE;
virtual nsresult Input(MP4Sample* aSample) MOZ_OVERRIDE;
virtual nsresult Flush() MOZ_OVERRIDE;
virtual nsresult Drain() MOZ_OVERRIDE;
virtual nsresult Shutdown() MOZ_OVERRIDE;
// GMPVideoDecoderProxyCallback
virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) MOZ_OVERRIDE;
virtual void ReceivedDecodedReferenceFrame(const uint64_t aPictureId) MOZ_OVERRIDE;
virtual void ReceivedDecodedFrame(const uint64_t aPictureId) MOZ_OVERRIDE;
virtual void InputDataExhausted() MOZ_OVERRIDE;
virtual void DrainComplete() MOZ_OVERRIDE;
virtual void ResetComplete() MOZ_OVERRIDE;
virtual void Error(GMPErr aErr) MOZ_OVERRIDE;
virtual void Terminated() MOZ_OVERRIDE;
private:
nsresult GmpInit();
nsresult GmpInput(MP4Sample* aSample);
void GmpFlush();
void GmpDrain();
void GmpShutdown();
#ifdef DEBUG
bool IsOnGMPThread() {
return NS_GetCurrentThread() == mGMPThread;
}
#endif
class DeliverSample : public nsRunnable {
public:
DeliverSample(EMEH264Decoder* aDecoder,
mp4_demuxer::MP4Sample* aSample)
: mDecoder(aDecoder)
, mSample(aSample)
{}
NS_IMETHOD Run() {
mDecoder->GmpInput(mSample.forget());
return NS_OK;
}
private:
nsRefPtr<EMEH264Decoder> mDecoder;
nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
};
class InitTask : public nsRunnable {
public:
InitTask(EMEH264Decoder* aDecoder)
: mDecoder(aDecoder)
{}
NS_IMETHOD Run() {
mResult = mDecoder->GmpInit();
return NS_OK;
}
nsresult mResult;
EMEH264Decoder* mDecoder;
};
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
nsCOMPtr<nsIThread> mGMPThread;
nsRefPtr<CDMProxy> mProxy;
GMPVideoDecoderProxy* mGMP;
GMPVideoHost* mHost;
VideoInfo mVideoInfo;
nsIntRect mPictureRegion;
const mp4_demuxer::VideoDecoderConfig& mConfig;
nsRefPtr<layers::ImageContainer> mImageContainer;
nsRefPtr<MediaTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;
int64_t mLastStreamOffset;
Monitor mMonitor;
bool mFlushComplete;
};
}
#endif // EMEH264Decoder_h_

View File

@ -5,7 +5,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS += [
'eme/EMEAACDecoder.h',
'eme/EMEDecoderModule.h',
'eme/EMEH264Decoder.h',
'MP4Decoder.h',
'MP4Reader.h',
'PlatformDecoderModule.h',
@ -13,7 +15,9 @@ EXPORTS += [
UNIFIED_SOURCES += [
'BlankDecoderModule.cpp',
'eme/EMEAACDecoder.cpp',
'eme/EMEDecoderModule.cpp',
'eme/EMEH264Decoder.cpp',
'PlatformDecoderModule.cpp',
]
@ -58,6 +62,12 @@ if CONFIG['MOZ_APPLEMEDIA']:
'-framework AudioToolbox',
]
include('/ipc/chromium/chromium-config.mozbuild')
LOCAL_INCLUDES += [
'../base',
]
FINAL_LIBRARY = 'xul'
FAIL_ON_WARNINGS = True

View File

@ -27,6 +27,8 @@ using mozilla::dom::CrashReporterChild;
#if defined(XP_WIN)
#define TARGET_SANDBOX_EXPORTS
#include "mozilla/sandboxTarget.h"
#elif defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
#include "mozilla/Sandbox.h"
#endif
namespace mozilla {
@ -99,6 +101,13 @@ GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
nsAutoCString nativePath;
libFile->GetNativePath(nativePath);
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
// Enable sandboxing here -- we know the plugin file's path, but
// this process's execution hasn't been affected by its content yet.
mozilla::SetMediaPluginSandbox(nativePath.get());
#endif
mLib = PR_LoadLibrary(nativePath.get());
if (!mLib) {
return false;
@ -110,7 +119,7 @@ GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
}
auto platformAPI = new GMPPlatformAPI();
InitPlatformAPI(*platformAPI);
InitPlatformAPI(*platformAPI, this);
if (initFunc(platformAPI) != GMPNoErr) {
return false;
@ -301,6 +310,33 @@ GMPChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
return true;
}
PGMPTimerChild*
GMPChild::AllocPGMPTimerChild()
{
return new GMPTimerChild(this);
}
bool
GMPChild::DeallocPGMPTimerChild(PGMPTimerChild* aActor)
{
MOZ_ASSERT(mTimerChild == static_cast<GMPTimerChild*>(aActor));
mTimerChild = nullptr;
return true;
}
GMPTimerChild*
GMPChild::GetGMPTimers()
{
if (!mTimerChild) {
PGMPTimerChild* sc = SendPGMPTimerConstructor();
if (!sc) {
return nullptr;
}
mTimerChild = static_cast<GMPTimerChild*>(sc);
}
return mTimerChild;
}
bool
GMPChild::RecvCrashPluginNow()
{

View File

@ -8,6 +8,7 @@
#include "mozilla/gmp/PGMPChild.h"
#include "GMPSharedMemManager.h"
#include "GMPTimerChild.h"
#include "gmp-entrypoints.h"
#include "prlink.h"
@ -28,6 +29,9 @@ public:
bool LoadPluginLibrary(const std::string& aPluginPath);
MessageLoop* GMPMessageLoop();
// Main thread only.
GMPTimerChild* GetGMPTimers();
// GMPSharedMem
virtual void CheckThread() MOZ_OVERRIDE;
@ -51,11 +55,16 @@ private:
virtual bool DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor) MOZ_OVERRIDE;
virtual bool RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor) MOZ_OVERRIDE;
virtual PGMPTimerChild* AllocPGMPTimerChild() MOZ_OVERRIDE;
virtual bool DeallocPGMPTimerChild(PGMPTimerChild* aActor) MOZ_OVERRIDE;
virtual bool RecvCrashPluginNow() MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual void ProcessingError(Result aWhat) MOZ_OVERRIDE;
nsRefPtr<GMPTimerChild> mTimerChild;
PRLibrary* mLib;
GMPGetAPIFunc mGetAPIFunc;
MessageLoop* mGMPMessageLoop;

View File

@ -149,8 +149,13 @@ GMPDecryptorChild::Decrypted(GMPBuffer* aBuffer, GMPErr aResult)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
if (!aBuffer) {
NS_WARNING("GMPDecryptorCallback passed bull GMPBuffer");
return;
}
auto buffer = static_cast<GMPBufferImpl*>(aBuffer);
SendDecrypted(buffer->mId, aResult, buffer->mData);
delete buffer;
}
void
@ -307,6 +312,8 @@ GMPDecryptorChild::RecvDecrypt(const uint32_t& aId,
GMPEncryptedBufferDataImpl metadata(aMetadata);
// Note: the GMPBufferImpl created here is deleted when the GMP passes
// it back in the Decrypted() callback above.
mSession->Decrypt(new GMPBufferImpl(aId, aBuffer), &metadata);
return true;
}

View File

@ -120,7 +120,7 @@ private:
#ifdef DEBUG
GMPChild* mPlugin;
#endif
#endif
};
} // namespace gmp

View File

@ -16,6 +16,7 @@
#include "mozIGeckoMediaPluginService.h"
#include "mozilla/unused.h"
#include "nsIObserverService.h"
#include "GMPTimerParent.h"
#include "runnable_utils.h"
#include "mozilla/dom/CrashReporterParent.h"
@ -92,7 +93,7 @@ GMPParent::Init(GeckoMediaPluginService *aService, nsIFile* aPluginDir)
if (NS_FAILED(rv)) {
return rv;
}
LOGD(("%s::%s: %p for %s", __CLASS__, __FUNCTION__, this,
LOGD(("%s::%s: %p for %s", __CLASS__, __FUNCTION__, this,
NS_LossyConvertUTF16toASCII(leafname).get()));
MOZ_ASSERT(leafname.Length() > 4);
@ -328,7 +329,6 @@ GMPParent::State() const
return mState;
}
#ifdef DEBUG
// Not changing to use mService since we'll be removing it
nsIThread*
GMPParent::GMPThread()
@ -350,7 +350,6 @@ GMPParent::GMPThread()
return mGMPThread;
}
#endif
bool
GMPParent::SupportsAPI(const nsCString& aAPI, const nsCString& aTag)
@ -618,6 +617,28 @@ GMPParent::DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor)
return true;
}
bool
GMPParent::RecvPGMPTimerConstructor(PGMPTimerParent* actor)
{
return true;
}
PGMPTimerParent*
GMPParent::AllocPGMPTimerParent()
{
GMPTimerParent* p = new GMPTimerParent(GMPThread());
NS_ADDREF(p); // Released in DeallocPGMPTimerParent.
return p;
}
bool
GMPParent::DeallocPGMPTimerParent(PGMPTimerParent* aActor)
{
GMPTimerParent* p = static_cast<GMPTimerParent*>(aActor);
NS_RELEASE(p);
return true;
}
nsresult
ParseNextRecord(nsILineInputStream* aLineInputStream,
const nsCString& aPrefix,

View File

@ -12,6 +12,7 @@
#include "GMPDecryptorParent.h"
#include "GMPVideoDecoderParent.h"
#include "GMPVideoEncoderParent.h"
#include "GMPTimerParent.h"
#include "mozilla/gmp/PGMPParent.h"
#include "nsCOMPtr.h"
#include "nscore.h"
@ -95,9 +96,7 @@ public:
void AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder);
GMPState State() const;
#ifdef DEBUG
nsIThread* GMPThread();
#endif
// A GMP can either be a single instance shared across all origins (like
// in the OpenH264 case), or we can require a new plugin instance for every
@ -143,7 +142,7 @@ private:
virtual PGMPVideoDecoderParent* AllocPGMPVideoDecoderParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) MOZ_OVERRIDE;
virtual PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) MOZ_OVERRIDE;
@ -153,6 +152,10 @@ private:
virtual PGMPAudioDecoderParent* AllocPGMPAudioDecoderParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) MOZ_OVERRIDE;
virtual bool RecvPGMPTimerConstructor(PGMPTimerParent* actor) MOZ_OVERRIDE;
virtual PGMPTimerParent* AllocPGMPTimerParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPTimerParent(PGMPTimerParent* aActor) MOZ_OVERRIDE;
GMPState mState;
nsCOMPtr<nsIFile> mDirectory; // plugin directory on disk
nsString mName; // base name of plugin on disk, UTF-16 because used for paths
@ -168,9 +171,7 @@ private:
nsTArray<nsRefPtr<GMPVideoEncoderParent>> mVideoEncoders;
nsTArray<nsRefPtr<GMPDecryptorParent>> mDecryptors;
nsTArray<nsRefPtr<GMPAudioDecoderParent>> mAudioDecoders;
#ifdef DEBUG
nsCOMPtr<nsIThread> mGMPThread;
#endif
// Origin the plugin is assigned to, or empty if the the plugin is not
// assigned to an origin.
nsAutoString mOrigin;

View File

@ -4,13 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPPlatform.h"
#include "GMPTimerChild.h"
#include "mozilla/Monitor.h"
#include "nsAutoPtr.h"
#include "GMPChild.h"
#include <ctime>
namespace mozilla {
namespace gmp {
static MessageLoop* sMainLoop = nullptr;
static GMPChild* sChild = nullptr;
// We just need a refcounted wrapper for GMPTask objects.
class Runnable MOZ_FINAL
@ -141,12 +145,30 @@ CreateMutex(GMPMutex** aMutex)
return GMPNoErr;
}
GMPErr
SetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS)
{
GMPTimerChild* timers = sChild->GetGMPTimers();
NS_ENSURE_TRUE(timers, GMPGenericErr);
return timers->SetTimer(aTask, aTimeoutMS);
}
GMPErr
GetClock(GMPTimestamp* aOutTime)
{
*aOutTime = time(0) * 1000;
return GMPNoErr;
}
void
InitPlatformAPI(GMPPlatformAPI& aPlatformAPI)
InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
{
if (!sMainLoop) {
sMainLoop = MessageLoop::current();
}
if (!sChild) {
sChild = aChild;
}
aPlatformAPI.version = 0;
aPlatformAPI.createthread = &CreateThread;
@ -154,18 +176,20 @@ InitPlatformAPI(GMPPlatformAPI& aPlatformAPI)
aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
aPlatformAPI.createmutex = &CreateMutex;
aPlatformAPI.createrecord = nullptr;
aPlatformAPI.settimer = nullptr;
aPlatformAPI.getcurrenttime = nullptr;
aPlatformAPI.settimer = &SetTimerOnMainThread;
aPlatformAPI.getcurrenttime = &GetClock;
}
GMPThreadImpl::GMPThreadImpl()
: mMutex("GMPThreadImpl"),
mThread("GMPThread")
{
MOZ_COUNT_CTOR(GMPThread);
}
GMPThreadImpl::~GMPThreadImpl()
{
MOZ_COUNT_DTOR(GMPThread);
}
void
@ -189,19 +213,30 @@ GMPThreadImpl::Post(GMPTask* aTask)
void
GMPThreadImpl::Join()
{
MutexAutoLock lock(mMutex);
if (mThread.IsRunning()) {
mThread.Stop();
{
MutexAutoLock lock(mMutex);
if (mThread.IsRunning()) {
mThread.Stop();
}
}
delete this;
}
GMPMutexImpl::GMPMutexImpl()
: mMutex("gmp-mutex")
{
MOZ_COUNT_CTOR(GMPMutexImpl);
}
GMPMutexImpl::~GMPMutexImpl()
{
MOZ_COUNT_DTOR(GMPMutexImpl);
}
void
GMPMutexImpl::Destroy()
{
delete this;
}
void

View File

@ -15,7 +15,9 @@ namespace gmp {
class GMPChild;
void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI);
void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild);
GMPErr RunOnMainThread(GMPTask* aTask);
class GMPThreadImpl : public GMPThread
{
@ -41,6 +43,7 @@ public:
// GMPMutex
virtual void Acquire() MOZ_OVERRIDE;
virtual void Release() MOZ_OVERRIDE;
virtual void Destroy() MOZ_OVERRIDE;
private:
Mutex mMutex;

View File

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "GMPTimerChild.h"
#include "GMPPlatform.h"
#include "GMPChild.h"
#define MAX_NUM_TIMERS 1000
namespace mozilla {
namespace gmp {
GMPTimerChild::GMPTimerChild(GMPChild* aPlugin)
: mTimerCount(1)
, mPlugin(aPlugin)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
}
GMPTimerChild::~GMPTimerChild()
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
}
GMPErr
GMPTimerChild::SetTimer(GMPTask* aTask, int64_t aTimeoutMS)
{
if (!aTask) {
NS_WARNING("Tried to set timer with null task!");
return GMPGenericErr;
}
if (mPlugin->GMPMessageLoop() != MessageLoop::current()) {
NS_WARNING("Tried to set GMP timer on non-main thread.");
return GMPGenericErr;
}
if (mTimers.Count() > MAX_NUM_TIMERS) {
return GMPQuotaExceededErr;
}
uint32_t timerId = mTimerCount;
mTimers.Put(timerId, aTask);
mTimerCount++;
if (!SendSetTimer(timerId, aTimeoutMS)) {
return GMPGenericErr;
}
return GMPNoErr;
}
bool
GMPTimerChild::RecvTimerExpired(const uint32_t& aTimerId)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
GMPTask* task = mTimers.Get(aTimerId);
mTimers.Remove(aTimerId);
if (task) {
RunOnMainThread(task);
}
return true;
}
} // namespace gmp
} // namespace mozilla

View File

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 GMPTimerChild_h_
#define GMPTimerChild_h_
#include "mozilla/gmp/PGMPTimerChild.h"
#include "mozilla/Monitor.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "gmp-errors.h"
#include "gmp-platform.h"
namespace mozilla {
namespace gmp {
class GMPChild;
class GMPTimerChild : public PGMPTimerChild
{
public:
NS_INLINE_DECL_REFCOUNTING(GMPTimerChild)
GMPTimerChild(GMPChild* aPlugin);
GMPErr SetTimer(GMPTask* aTask, int64_t aTimeoutMS);
protected:
// GMPTimerChild
virtual bool RecvTimerExpired(const uint32_t& aTimerId) MOZ_OVERRIDE;
private:
~GMPTimerChild();
nsDataHashtable<nsUint32HashKey, GMPTask*> mTimers;
uint32_t mTimerCount;
GMPChild* mPlugin;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPTimerChild_h_

View File

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "GMPTimerParent.h"
#include "nsComponentManagerUtils.h"
#include "mozilla/unused.h"
namespace mozilla {
namespace gmp {
GMPTimerParent::GMPTimerParent(nsIThread* aGMPThread)
: mGMPThread(aGMPThread)
{
}
bool
GMPTimerParent::RecvSetTimer(const uint32_t& aTimerId,
const uint32_t& aTimeoutMs)
{
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
nsresult rv;
nsAutoPtr<Context> ctx(new Context());
ctx->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
NS_ENSURE_SUCCESS(rv, true);
ctx->mId = aTimerId;
rv = ctx->mTimer->SetTarget(mGMPThread);
NS_ENSURE_SUCCESS(rv, true);
ctx->mParent = this;
rv = ctx->mTimer->InitWithFuncCallback(&GMPTimerParent::GMPTimerExpired,
ctx,
aTimeoutMs,
nsITimer::TYPE_ONE_SHOT);
NS_ENSURE_SUCCESS(rv, true);
mTimers.PutEntry(ctx.forget());
return true;
}
/*static */
PLDHashOperator
GMPTimerParent::CancelTimers(nsPtrHashKey<Context>* aContext, void* aClosure)
{
auto context = aContext->GetKey();
context->mTimer->Cancel();
delete context;
return PL_DHASH_NEXT;
}
void
GMPTimerParent::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
mTimers.EnumerateEntries(GMPTimerParent::CancelTimers, nullptr);
mTimers.Clear();
}
/* static */
void
GMPTimerParent::GMPTimerExpired(nsITimer *aTimer, void *aClosure)
{
MOZ_ASSERT(aClosure);
nsAutoPtr<Context> ctx(static_cast<Context*>(aClosure));
MOZ_ASSERT(ctx->mParent);
if (ctx->mParent) {
ctx->mParent->TimerExpired(ctx);
}
}
void
GMPTimerParent::TimerExpired(Context* aContext)
{
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
uint32_t id = aContext->mId;
mTimers.RemoveEntry(aContext);
if (id) {
unused << SendTimerExpired(id);
}
}
} // namespace gmp
} // namespace mozilla

View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 GMPTimerParent_h_
#define GMPTimerParent_h_
#include "mozilla/gmp/PGMPTimerParent.h"
#include "nsITimer.h"
#include "nsCOMPtr.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "nsAutoPtr.h"
#include "mozilla/Monitor.h"
#include "nsIThread.h"
namespace mozilla {
namespace gmp {
class GMPTimerParent : public PGMPTimerParent {
public:
NS_INLINE_DECL_REFCOUNTING(GMPTimerParent)
GMPTimerParent(nsIThread* aGMPThread);
protected:
virtual bool RecvSetTimer(const uint32_t& aTimerId,
const uint32_t& aTimeoutMs) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
private:
~GMPTimerParent() {}
static void GMPTimerExpired(nsITimer *aTimer, void *aClosure);
struct Context {
Context() {
MOZ_COUNT_CTOR(Context);
}
~Context() {
MOZ_COUNT_DTOR(Context);
}
nsCOMPtr<nsITimer> mTimer;
nsRefPtr<GMPTimerParent> mParent; // Note: live timers keep the GMPTimerParent alive.
uint32_t mId;
};
static PLDHashOperator
CancelTimers(nsPtrHashKey<Context>* aContext, void* aClosure);
void TimerExpired(Context* aContext);
nsTHashtable<nsPtrHashKey<Context>> mTimers;
nsCOMPtr<nsIThread> mGMPThread;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPTimerParent_h_

View File

@ -8,6 +8,7 @@ include protocol PGMPVideoEncoder;
include protocol PCrashReporter;
include protocol PGMPDecryptor;
include protocol PGMPAudioDecoder;
include protocol PGMPTimer;
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
@ -21,9 +22,11 @@ intr protocol PGMP
manages PGMPVideoDecoder;
manages PGMPVideoEncoder;
manages PCrashReporter;
manages PGMPTimer;
parent:
async PCrashReporter(NativeThreadId tid);
async PGMPTimer();
child:
async PGMPAudioDecoder();

View File

@ -0,0 +1,22 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 protocol PGMP;
namespace mozilla {
namespace gmp {
async protocol PGMPTimer
{
manager PGMP;
child:
TimerExpired(uint32_t aTimerId);
parent:
SetTimer(uint32_t aTimerId, uint32_t aTimeoutMs);
__delete__();
};
} // namespace gmp
} // namespace mozilla

View File

@ -257,6 +257,9 @@ public:
// same GMPBuffer object and return it to Gecko by calling Decrypted(),
// with the GMPNoErr successcode. If decryption fails, call Decrypted()
// with a failure code, and an error event will fire on the media element.
// Note: When Decrypted() is called and aBuffer is passed back, aBuffer
// is deleted. Don't forget to call Decrypted(), as otherwise aBuffer's
// memory will leak!
virtual void Decrypt(GMPBuffer* aBuffer,
GMPEncryptedBufferMetadata* aMetadata) = 0;

View File

@ -41,7 +41,7 @@
class GMPTask {
public:
virtual void Destroy() = 0;
virtual void Destroy() = 0; // Deletes object.
virtual ~GMPTask() {}
virtual void Run() = 0;
};
@ -50,7 +50,7 @@ class GMPThread {
public:
virtual ~GMPThread() {}
virtual void Post(GMPTask* aTask) = 0;
virtual void Join() = 0;
virtual void Join() = 0; // Deletes object after join completes.
};
class GMPMutex {
@ -58,6 +58,7 @@ public:
virtual ~GMPMutex() {}
virtual void Acquire() = 0;
virtual void Release() = 0;
virtual void Destroy() = 0; // Deletes object.
};
// Time is defined as the number of milliseconds since the
@ -72,6 +73,8 @@ typedef GMPErr (*GMPCreateRecordPtr)(const char* aRecordName,
uint32_t aRecordNameSize,
GMPRecord** aOutRecord,
GMPRecordClient* aClient);
// Call on main thread only.
typedef GMPErr (*GMPSetTimerOnMainThreadPtr)(GMPTask* aTask, int64_t aTimeoutMS);
typedef GMPErr (*GMPGetCurrentTimePtr)(GMPTimestamp* aOutTime);

View File

@ -46,6 +46,8 @@ EXPORTS += [
'GMPProcessParent.h',
'GMPService.h',
'GMPSharedMemManager.h',
'GMPTimerChild.h',
'GMPTimerParent.h',
'GMPVideoDecoderChild.h',
'GMPVideoDecoderParent.h',
'GMPVideoDecoderProxy.h',
@ -72,6 +74,8 @@ UNIFIED_SOURCES += [
'GMPProcessParent.cpp',
'GMPService.cpp',
'GMPSharedMemManager.cpp',
'GMPTimerChild.cpp',
'GMPTimerParent.cpp',
'GMPVideoDecoderChild.cpp',
'GMPVideoDecoderParent.cpp',
'GMPVideoEncodedFrameImpl.cpp',
@ -87,6 +91,7 @@ IPDL_SOURCES += [
'PGMP.ipdl',
'PGMPAudioDecoder.ipdl',
'PGMPDecryptor.ipdl',
'PGMPTimer.ipdl',
'PGMPVideoDecoder.ipdl',
'PGMPVideoEncoder.ipdl',
]

View File

@ -21,6 +21,7 @@
#include "nsThreadUtils.h"
#include "prlog.h"
#include "SubBufferDecoder.h"
#include "mozilla/Preferences.h"
struct JSContext;
class JSObject;
@ -166,8 +167,19 @@ public:
}
uint32_t chunk_size = BigEndian::readUint32(aData);
return chunk_size > 8 && aData[4] == 'f' && aData[5] == 't' &&
aData[6] == 'y' && aData[7] == 'p';
if (chunk_size < 8) {
return false;
}
if (Preferences::GetBool("media.mediasource.allow_init_moov", false)) {
if (aData[4] == 'm' && aData[5] == 'o' && aData[6] == 'o' &&
aData[7] == 'v') {
return true;
}
}
return aData[4] == 'f' && aData[5] == 't' && aData[6] == 'y' &&
aData[7] == 'p';
}
};

View File

@ -48,9 +48,7 @@ function startTest() {
function checkTrackRemoved() {
if (isPlaying) {
is(audioOnremovetrack, 1, 'Calls of onremovetrack on audioTracks should be 1.');
is(element.audioTracks.length, 0, 'The length of audioTracks should be 0.');
is(videoOnremovetrack, 1, 'Calls of onremovetrack on videoTracks should be 1.');
is(element.videoTracks.length, 0, 'The length of videoTracks should be 0.');
}
}

View File

@ -358,6 +358,8 @@ DOMInterfaces = {
'URL': 'documentURIFromJS'
}
},
# Note: we still need the worker descriptor here because
# XMLHttpRequest.send() uses it.
{
'nativeType': 'JSObject',
'workers': True,
@ -827,14 +829,10 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::HTMLCanvasPrintState',
},
'MozChannel': [
{
'MozChannel': {
'nativeType': 'nsIChannel',
'notflattened': True
},
{
'workers': True,
}],
'MozCellBroadcast': {
'nativeType': 'mozilla::dom::CellBroadcast',

View File

@ -78,9 +78,7 @@ def idlTypeNeedsCycleCollection(type):
def wantsAddProperty(desc):
return (desc.concrete and
desc.wrapperCache and
not desc.interface.getExtendedAttribute("Global"))
return (desc.concrete and desc.wrapperCache and not desc.isGlobal())
# We'll want to insert the indent at the beginnings of lines, but we
@ -372,7 +370,7 @@ class CGDOMJSClass(CGThing):
JS_NULL_CLASS_EXT,
JS_NULL_OBJECT_OPS
"""
if self.descriptor.interface.getExtendedAttribute("Global"):
if self.descriptor.isGlobal():
classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
traceHook = "JS_GlobalObjectTraceHook"
reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
@ -415,7 +413,7 @@ JS_NULL_OBJECT_OPS
newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME
classFlags += " | JSCLASS_NEW_RESOLVE"
enumerateHook = ENUMERATE_HOOK_NAME
elif self.descriptor.interface.getExtendedAttribute("Global"):
elif self.descriptor.isGlobal():
newResolveHook = "(JSResolveOp) mozilla::dom::ResolveGlobal"
classFlags += " | JSCLASS_NEW_RESOLVE"
enumerateHook = "mozilla::dom::EnumerateGlobal"
@ -1521,7 +1519,7 @@ def finalizeHook(descriptor, hookName, freeOp):
finalize += "ClearWrapper(self, self);\n"
if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
if descriptor.interface.getExtendedAttribute("Global"):
if descriptor.isGlobal():
finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), obj);\n" % freeOp
finalize += ("AddForDeferredFinalization<%s, %s >(self);\n" %
(descriptor.nativeType, DeferredFinalizeSmartPtr(descriptor)))
@ -2034,6 +2032,11 @@ def methodLength(method):
return min(overloadLength(arguments) for retType, arguments in signatures)
def isMaybeExposedIn(member, descriptor):
# All we can say for sure is that if this is a worker descriptor
# and member is only exposed in windows, then it's not exposed.
return not descriptor.workers or member.exposureSet != set(["Window"])
class MethodDefiner(PropertyDefiner):
"""
A class for defining methods on a prototype object.
@ -2051,7 +2054,8 @@ class MethodDefiner(PropertyDefiner):
methods = [m for m in descriptor.interface.members if
m.isMethod() and m.isStatic() == static and
MemberIsUnforgeable(m, descriptor) == unforgeable and
not m.isIdentifierLess()]
not m.isIdentifierLess() and
isMaybeExposedIn(m, descriptor)]
else:
methods = []
self.chrome = []
@ -2265,7 +2269,8 @@ class AttrDefiner(PropertyDefiner):
if descriptor.interface.hasInterfacePrototypeObject() or static:
attributes = [m for m in descriptor.interface.members if
m.isAttr() and m.isStatic() == static and
MemberIsUnforgeable(m, descriptor) == unforgeable]
MemberIsUnforgeable(m, descriptor) == unforgeable and
isMaybeExposedIn(m, descriptor)]
else:
attributes = []
self.chrome = [m for m in attributes if isChromeOnly(m)]
@ -2348,7 +2353,8 @@ class ConstDefiner(PropertyDefiner):
def __init__(self, descriptor, name):
PropertyDefiner.__init__(self, descriptor, name)
self.name = name
constants = [m for m in descriptor.interface.members if m.isConst()]
constants = [m for m in descriptor.interface.members if m.isConst() and
isMaybeExposedIn(m, descriptor)]
self.chrome = [m for m in constants if isChromeOnly(m)]
self.regular = [m for m in constants if not isChromeOnly(m)]
@ -2599,7 +2605,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
interfaceClass = "nullptr"
interfaceCache = "nullptr"
isGlobal = self.descriptor.interface.getExtendedAttribute("Global") is not None
isGlobal = self.descriptor.isGlobal() is not None
if not isGlobal and self.properties.hasNonChromeOnly():
properties = "&sNativeProperties"
elif self.properties.hasNonChromeOnly():
@ -7323,7 +7329,7 @@ class CGNewResolveHook(CGAbstractBindingMethod):
"""))
def definition_body(self):
if self.descriptor.interface.getExtendedAttribute("Global"):
if self.descriptor.isGlobal():
# Resolve standard classes
prefix = dedent("""
if (!ResolveGlobal(cx, obj, id, objp)) {
@ -7372,7 +7378,7 @@ class CGEnumerateHook(CGAbstractBindingMethod):
"""))
def definition_body(self):
if self.descriptor.interface.getExtendedAttribute("Global"):
if self.descriptor.isGlobal():
# Enumerate standard classes
prefix = dedent("""
if (!EnumerateGlobal(cx, obj)) {
@ -10471,6 +10477,8 @@ class CGDescriptor(CGThing):
for m in descriptor.interface.members:
if m.isMethod() and m.identifier.name == 'queryInterface':
continue
if not isMaybeExposedIn(m, descriptor):
continue
if m.isMethod() and m == descriptor.operations['Jsonifier']:
hasJsonifier = True
hasMethod = descriptor.needsSpecialGenericOps()
@ -10626,9 +10634,7 @@ class CGDescriptor(CGThing):
if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.getNavigatorProperty()) and
not descriptor.interface.isExternal() and
descriptor.isExposedConditionally() and
# Workers stuff is never conditional
not descriptor.workers):
descriptor.isExposedConditionally()):
cgThings.append(CGConstructorEnabled(descriptor))
if (descriptor.interface.hasMembersInSlots() and
@ -10666,7 +10672,7 @@ class CGDescriptor(CGThing):
if descriptor.interface.hasMembersInSlots():
cgThings.append(CGUpdateMemberSlotsMethod(descriptor))
if descriptor.interface.getExtendedAttribute("Global"):
if descriptor.isGlobal():
assert descriptor.wrapperCache
cgThings.append(CGWrapGlobalMethod(descriptor, properties))
elif descriptor.wrapperCache:
@ -11325,6 +11331,48 @@ class CGDictionary(CGThing):
return all(isTypeCopyConstructible(m.type) for m in dictionary.members)
class CGRegisterWorkerBindings(CGAbstractMethod):
def __init__(self, config):
CGAbstractMethod.__init__(self, None, 'RegisterWorkerBindings', 'bool',
[Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aObj')])
self.config = config
def definition_body(self):
# We have to be a bit careful: Some of the interfaces we want to expose
# in workers only have one descriptor, while others have both a worker
# and a non-worker descriptor. When both are present we want the worker
# descriptor, but otherwise we want whatever descriptor we've got.
descriptors = self.config.getDescriptors(hasInterfaceObject=True,
isExposedInAllWorkers=True,
register=True,
skipGen=False,
workers=True)
workerDescriptorIfaceNames = set(d.interface.identifier.name for
d in descriptors)
descriptors.extend(
filter(
lambda d: d.interface.identifier.name not in workerDescriptorIfaceNames,
self.config.getDescriptors(hasInterfaceObject=True,
isExposedInAllWorkers=True,
register=True,
skipGen=False,
workers=False)))
conditions = []
for desc in descriptors:
bindingNS = toBindingNamespace(desc.name)
condition = "!%s::GetConstructorObject(aCx, aObj)" % bindingNS
if desc.isExposedConditionally():
condition = (
"%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
+ condition)
conditions.append(condition)
lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
condition in conditions]
lines.append(CGGeneric("return true;\n"))
return CGList(lines, "\n").define()
class CGRegisterProtos(CGAbstractMethod):
def __init__(self, config):
CGAbstractMethod.__init__(self, None, 'Register', 'void',
@ -13716,6 +13764,33 @@ class GlobalGenRoots():
# Done.
return curr
@staticmethod
def RegisterWorkerBindings(config):
# TODO - Generate the methods we want
curr = CGRegisterWorkerBindings(config)
# Wrap all of that in our namespaces.
curr = CGNamespace.build(['mozilla', 'dom'],
CGWrapper(curr, post='\n'))
curr = CGWrapper(curr, post='\n')
# Add the includes
defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
for desc in config.getDescriptors(hasInterfaceObject=True,
register=True,
isExposedInAllWorkers=True,
skipGen=False)]
curr = CGHeaders([], [], [], [], [], defineIncludes,
'RegisterWorkerBindings', curr)
# Add include guards.
curr = CGIncludeGuard('RegisterWorkerBindings', curr)
# Done.
return curr
@staticmethod
def UnionTypes(config):

View File

@ -138,6 +138,8 @@ class Configuration:
getter = lambda x: x.interface.isJSImplemented()
elif key == 'isNavigatorProperty':
getter = lambda x: x.interface.getNavigatorProperty() != None
elif key == 'isExposedInAllWorkers':
getter = lambda x: not x.interface.isExternal() and "Worker" in x.interface._exposureGlobalNames
else:
# Have to watch out: just closing over "key" is not enough,
# since we're about to mutate its value
@ -563,6 +565,14 @@ class Descriptor(DescriptorProvider):
"""
return self.hasXPConnectImpls or self.interface.isOnGlobalProtoChain()
def isGlobal(self):
"""
Returns true if this is the primary interface for a global object
of some sort.
"""
return (self.interface.getExtendedAttribute("Global") or
self.interface.getExtendedAttribute("PrimaryGlobal"))
# Some utility methods
def getTypesFromDescriptor(descriptor):
"""

View File

@ -131,6 +131,7 @@ class WebIDLCodegenManager(LoggingMixin):
'GeneratedAtomList.h',
'PrototypeList.h',
'RegisterBindings.h',
'RegisterWorkerBindings.h',
'UnionConversions.h',
'UnionTypes.h',
}
@ -138,6 +139,7 @@ class WebIDLCodegenManager(LoggingMixin):
# Global parser derived definition files.
GLOBAL_DEFINE_FILES = {
'RegisterBindings.cpp',
'RegisterWorkerBindings.cpp',
'UnionTypes.cpp',
'PrototypeList.cpp',
}

View File

@ -9,6 +9,7 @@ import re
import os
import traceback
import math
from collections import defaultdict
# Machinery
@ -219,6 +220,12 @@ class IDLScope(IDLObject):
self._name = None
self._dict = {}
self.globalNames = set()
# A mapping from global name to the set of global interfaces
# that have that global name.
self.globalNameMapping = defaultdict(set)
self.primaryGlobalAttr = None
self.primaryGlobalName = None
def __str__(self):
return self.QName()
@ -482,24 +489,85 @@ class IDLExternalInterface(IDLObjectWithIdentifier):
def _getDependentObjects(self):
return set()
class IDLPartialInterface(IDLObject):
def __init__(self, location, name, members, nonPartialInterface):
assert isinstance(name, IDLUnresolvedIdentifier)
IDLObject.__init__(self, location)
self.identifier = name
self.members = members
# propagatedExtendedAttrs are the ones that should get
# propagated to our non-partial interface.
self.propagatedExtendedAttrs = []
self._nonPartialInterface = nonPartialInterface
self._finished = False
nonPartialInterface.addPartialInterface(self)
def addExtendedAttributes(self, attrs):
for attr in attrs:
identifier = attr.identifier()
if identifier in ["Constructor", "NamedConstructor"]:
self.propagatedExtendedAttrs.append(attr)
elif identifier == "Exposed":
# This just gets propagated to all our members.
for member in self.members:
if len(member._exposureGlobalNames) != 0:
raise WebIDLError("[Exposed] specified on both a "
"partial interface member and on the "
"partial interface itself",
[member.location, attr.location])
member.addExtendedAttributes([attr])
else:
raise WebIDLError("Unknown extended attribute %s on partial "
"interface" % identifier,
[attr.location])
def finish(self, scope):
if self._finished:
return
self._finished = True
# Need to make sure our non-partial interface gets finished so it can
# report cases when we only have partial interfaces.
self._nonPartialInterface.finish(scope)
def validate(self):
pass
def convertExposedAttrToGlobalNameSet(exposedAttr, targetSet):
assert len(targetSet) == 0
if exposedAttr.hasValue():
targetSet.add(exposedAttr.value())
else:
assert exposedAttr.hasArgs()
targetSet.update(exposedAttr.args())
def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
for name in nameSet:
exposureSet.update(globalScope.globalNameMapping[name])
class IDLInterface(IDLObjectWithScope):
def __init__(self, location, parentScope, name, parent, members,
isPartial):
isKnownNonPartial):
assert isinstance(parentScope, IDLScope)
assert isinstance(name, IDLUnresolvedIdentifier)
assert not isPartial or not parent
assert isKnownNonPartial or not parent
assert isKnownNonPartial or len(members) == 0
self.parent = None
self._callback = False
self._finished = False
self.members = []
self._partialInterfaces = []
self._extendedAttrDict = {}
# namedConstructors needs deterministic ordering because bindings code
# outputs the constructs in the order that namedConstructors enumerates
# them.
self.namedConstructors = list()
self.implementedInterfaces = set()
self._consequential = False
self._isPartial = True
self._isKnownNonPartial = False
# self.interfacesBasedOnSelf is the set of interfaces that inherit from
# self or have self as a consequential interface, including self itself.
# Used for distinguishability checking.
@ -514,14 +582,16 @@ class IDLInterface(IDLObjectWithScope):
self.totalMembersInSlots = 0
# Tracking of the number of own own members we have in slots
self._ownMembersInSlots = 0
# _exposureGlobalNames are the global names listed in our [Exposed]
# extended attribute. exposureSet is the exposure set as defined in the
# Web IDL spec: it contains interface names.
self._exposureGlobalNames = set()
self.exposureSet = set()
IDLObjectWithScope.__init__(self, location, parentScope, name)
if not isPartial:
if isKnownNonPartial:
self.setNonPartial(location, parent, members)
else:
# Just remember our members for now
self.members = members
def __str__(self):
return "Interface '%s'" % self.identifier.name
@ -553,11 +623,42 @@ class IDLInterface(IDLObjectWithScope):
self._finished = True
if self._isPartial:
if not self._isKnownNonPartial:
raise WebIDLError("Interface %s does not have a non-partial "
"declaration" % self.identifier.name,
[self.location])
# Verify that our [Exposed] value, if any, makes sense.
for globalName in self._exposureGlobalNames:
if globalName not in scope.globalNames:
raise WebIDLError("Unknown [Exposed] value %s" % globalName,
[self.location])
if len(self._exposureGlobalNames) == 0:
self._exposureGlobalNames.add(scope.primaryGlobalName)
globalNameSetToExposureSet(scope, self._exposureGlobalNames,
self.exposureSet)
# Now go ahead and merge in our partial interfaces.
for partial in self._partialInterfaces:
partial.finish(scope)
self.addExtendedAttributes(partial.propagatedExtendedAttrs)
self.members.extend(partial.members)
# Now that we've merged in our partial interfaces, set the
# _exposureGlobalNames on any members that don't have it set yet. Note
# that any partial interfaces that had [Exposed] set have already set up
# _exposureGlobalNames on all the members coming from them, so this is
# just implementing the "members default to interface that defined them"
# and "partial interfaces default to interface they're a partial for"
# rules from the spec.
for m in self.members:
# If m, or the partial interface m came from, had [Exposed]
# specified, it already has a nonempty exposure global names set.
if len(m._exposureGlobalNames) == 0:
m._exposureGlobalNames.update(self._exposureGlobalNames)
assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder)
parent = self.parent.finish(scope) if self.parent else None
if parent and isinstance(parent, IDLExternalInterface):
@ -595,8 +696,10 @@ class IDLInterface(IDLObjectWithScope):
self.totalMembersInSlots = self.parent.totalMembersInSlots
# Interfaces with [Global] must not have anything inherit from them
if self.parent.getExtendedAttribute("Global"):
# Interfaces with [Global] or [PrimaryGlobal] must not
# have anything inherit from them
if (self.parent.getExtendedAttribute("Global") or
self.parent.getExtendedAttribute("PrimaryGlobal")):
# Note: This is not a self.parent.isOnGlobalProtoChain() check
# because ancestors of a [Global] interface can have other
# descendants.
@ -604,6 +707,14 @@ class IDLInterface(IDLObjectWithScope):
"inheriting from it",
[self.location, self.parent.location])
# Make sure that we're not exposed in places where our parent is not
if not self.exposureSet.issubset(self.parent.exposureSet):
raise WebIDLError("Interface %s is exposed in globals where its "
"parent interface %s is not exposed." %
(self.identifier.name,
self.parent.identifier.name),
[self.location, self.parent.location])
# Callbacks must not inherit from non-callbacks or inherit from
# anything that has consequential interfaces.
# XXXbz Can non-callbacks inherit from callbacks? Spec issue pending.
@ -649,6 +760,14 @@ class IDLInterface(IDLObjectWithScope):
for member in self.members:
member.finish(scope)
# Now that we've finished our members, which has updated their exposure
# sets, make sure they aren't exposed in places where we are not.
for member in self.members:
if not member.exposureSet.issubset(self.exposureSet):
raise WebIDLError("Interface member has larger exposure set "
"than the interface itself",
[member.location, self.location])
ctor = self.ctor()
if ctor is not None:
ctor.finish(scope)
@ -669,6 +788,12 @@ class IDLInterface(IDLObjectWithScope):
key=lambda x: x.identifier.name):
# Flag the interface as being someone's consequential interface
iface.setIsConsequentialInterfaceOf(self)
# Verify that we're not exposed somewhere where iface is not exposed
if not self.exposureSet.issubset(iface.exposureSet):
raise WebIDLError("Interface %s is exposed in globals where its "
"consequential interface %s is not exposed." %
(self.identifier.name, iface.identifier.name),
[self.location, iface.location])
additionalMembers = iface.originalMembers;
for additionalMember in additionalMembers:
for member in self.members:
@ -891,6 +1016,12 @@ class IDLInterface(IDLObjectWithScope):
attr = fowardAttr
putForwards = attr.getExtendedAttribute("PutForwards")
if (self.getExtendedAttribute("Pref") and
self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
raise WebIDLError("[Pref] used on an member that is not %s-only" %
self.parentScope.primaryGlobalName,
[self.location])
def isInterface(self):
return True
@ -948,7 +1079,6 @@ class IDLInterface(IDLObjectWithScope):
return not self.isCallback() and self.getUserData('hasConcreteDescendant', False)
def addExtendedAttributes(self, attrs):
self._extendedAttrDict = {}
for attr in attrs:
identifier = attr.identifier()
@ -1049,9 +1179,29 @@ class IDLInterface(IDLObjectWithScope):
"an interface with inherited interfaces",
[attr.location, self.location])
elif identifier == "Global":
if attr.hasValue():
self.globalNames = [ attr.value() ]
elif attr.hasArgs():
self.globalNames = attr.args()
else:
self.globalNames = [ self.identifier.name ]
self.parentScope.globalNames.update(self.globalNames)
for globalName in self.globalNames:
self.parentScope.globalNameMapping[globalName].add(self.identifier.name)
self._isOnGlobalProtoChain = True
elif identifier == "PrimaryGlobal":
if not attr.noArguments():
raise WebIDLError("[Global] must take no arguments",
raise WebIDLError("[PrimaryGlobal] must take no arguments",
[attr.location])
if self.parentScope.primaryGlobalAttr is not None:
raise WebIDLError(
"[PrimaryGlobal] specified twice",
[attr.location,
self.parentScope.primaryGlobalAttr.location])
self.parentScope.primaryGlobalAttr = attr
self.parentScope.primaryGlobalName = self.identifier.name
self.parentScope.globalNames.add(self.identifier.name)
self.parentScope.globalNameMapping[self.identifier.name].add(self.identifier.name)
self._isOnGlobalProtoChain = True
elif (identifier == "NeedNewResolve" or
identifier == "OverrideBuiltins" or
@ -1063,6 +1213,9 @@ class IDLInterface(IDLObjectWithScope):
if not attr.noArguments():
raise WebIDLError("[%s] must take no arguments" % identifier,
[attr.location])
elif identifier == "Exposed":
convertExposedAttrToGlobalNameSet(attr,
self._exposureGlobalNames)
elif (identifier == "Pref" or
identifier == "JSImplementation" or
identifier == "HeaderFile" or
@ -1139,11 +1292,11 @@ class IDLInterface(IDLObjectWithScope):
def setNonPartial(self, location, parent, members):
assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
if not self._isPartial:
if self._isKnownNonPartial:
raise WebIDLError("Two non-partial definitions for the "
"same interface",
[location, self.location])
self._isPartial = False
self._isKnownNonPartial = True
# Now make it look like we were parsed at this new location, since
# that's the place where the interface is "really" defined
self.location = location
@ -1152,6 +1305,10 @@ class IDLInterface(IDLObjectWithScope):
# Put the new members at the beginning
self.members = members + self.members
def addPartialInterface(self, partial):
assert self.identifier.name == partial.identifier.name
self._partialInterfaces.append(partial)
def getJSImplementation(self):
classId = self.getExtendedAttribute("JSImplementation")
if not classId:
@ -1535,6 +1692,9 @@ class IDLType(IDLObject):
raise TypeError("Can't tell whether a generic type is or is not "
"distinguishable from other things")
def isExposedInAllOf(self, exposureSet):
return True
class IDLUnresolvedType(IDLType):
"""
Unresolved types are interface types
@ -1842,6 +2002,9 @@ class IDLMozMapType(IDLType):
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isDate() or other.isNonCallbackInterface() or other.isSequence())
def isExposedInAllOf(self, exposureSet):
return self.inner.unroll().isExposedInAllOf(exposureSet)
def _getDependentObjects(self):
return self.inner._getDependentObjects()
@ -1952,6 +2115,14 @@ class IDLUnionType(IDLType):
return False
return True
def isExposedInAllOf(self, exposureSet):
# We could have different member types in different globals. Just make sure that each thing in exposureSet has one of our member types exposed in it.
for globalName in exposureSet:
if not any(t.unroll().isExposedInAllOf(set([globalName])) for t
in self.flatMemberTypes):
return False
return True
def _getDependentObjects(self):
return set(self.memberTypes)
@ -2291,6 +2462,20 @@ class IDLWrapperType(IDLType):
assert other.isObject()
return False
def isExposedInAllOf(self, exposureSet):
if not self.isInterface():
return True
iface = self.inner
if iface.isExternal():
# Let's say true, though ideally we'd only do this when
# exposureSet contains the primary global's name.
return True
if (iface.identifier.name == "Promise" and
# Check the internal type
not self._promiseInnerType.unroll().isExposedInAllOf(exposureSet)):
return False
return iface.exposureSet.issuperset(exposureSet)
def _getDependentObjects(self):
# NB: The codegen for an interface type depends on
# a) That the identifier is in fact an interface (as opposed to
@ -2805,6 +2990,11 @@ class IDLInterfaceMember(IDLObjectWithIdentifier):
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
self.tag = tag
self._extendedAttrDict = {}
# _exposureGlobalNames are the global names listed in our [Exposed]
# extended attribute. exposureSet is the exposure set as defined in the
# Web IDL spec: it contains interface names.
self._exposureGlobalNames = set()
self.exposureSet = set()
def isMethod(self):
return self.tag == IDLInterfaceMember.Tags.Method
@ -2827,6 +3017,22 @@ class IDLInterfaceMember(IDLObjectWithIdentifier):
def getExtendedAttribute(self, name):
return self._extendedAttrDict.get(name, None)
def finish(self, scope):
for globalName in self._exposureGlobalNames:
if globalName not in scope.globalNames:
raise WebIDLError("Unknown [Exposed] value %s" % globalName,
[self.location])
globalNameSetToExposureSet(scope, self._exposureGlobalNames,
self.exposureSet)
self._scope = scope
def validate(self):
if (self.getExtendedAttribute("Pref") and
self.exposureSet != set([self._scope.primaryGlobalName])):
raise WebIDLError("[Pref] used on an interface member that is not "
"%s-only" % self._scope.primaryGlobalName,
[self.location])
class IDLConst(IDLInterfaceMember):
def __init__(self, location, identifier, type, value):
IDLInterfaceMember.__init__(self, location, identifier,
@ -2847,6 +3053,8 @@ class IDLConst(IDLInterfaceMember):
return "'%s' const '%s'" % (self.type, self.identifier)
def finish(self, scope):
IDLInterfaceMember.finish(self, scope)
if not self.type.isComplete():
type = self.type.complete(scope)
if not type.isPrimitive() and not type.isString():
@ -2865,7 +3073,23 @@ class IDLConst(IDLInterfaceMember):
self.value = coercedValue
def validate(self):
pass
IDLInterfaceMember.validate(self)
def handleExtendedAttribute(self, attr):
identifier = attr.identifier()
if identifier == "Exposed":
convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
elif (identifier == "Pref" or
identifier == "ChromeOnly" or
identifier == "Func" or
identifier == "AvailableIn" or
identifier == "CheckPermissions"):
# Known attributes that we don't need to do anything with here
pass
else:
raise WebIDLError("Unknown extended attribute %s on constant" % identifier,
[attr.location])
IDLInterfaceMember.handleExtendedAttribute(self, attr)
def _getDependentObjects(self):
return set([self.type, self.value])
@ -2903,6 +3127,8 @@ class IDLAttribute(IDLInterfaceMember):
return "'%s' attribute '%s'" % (self.type, self.identifier)
def finish(self, scope):
IDLInterfaceMember.finish(self, scope)
if not self.type.isComplete():
t = self.type.complete(scope)
@ -2961,6 +3187,8 @@ class IDLAttribute(IDLInterfaceMember):
[self.location])
def validate(self):
IDLInterfaceMember.validate(self)
if ((self.getExtendedAttribute("Cached") or
self.getExtendedAttribute("StoreInSlot")) and
not self.getExtendedAttribute("Constant") and
@ -2976,6 +3204,10 @@ class IDLAttribute(IDLInterfaceMember):
"sequence-valued, dictionary-valued, and "
"MozMap-valued attributes",
[self.location])
if not self.type.unroll().isExposedInAllOf(self.exposureSet):
raise WebIDLError("Attribute returns a type that is not exposed "
"everywhere where the attribute is exposed",
[self.location])
def handleExtendedAttribute(self, attr):
identifier = attr.identifier()
@ -3078,6 +3310,8 @@ class IDLAttribute(IDLInterfaceMember):
raise WebIDLError("[LenientThis] is not allowed in combination "
"with [%s]" % identifier,
[attr.location, self.location])
elif identifier == "Exposed":
convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
elif (identifier == "Pref" or
identifier == "SetterThrows" or
identifier == "Pure" or
@ -3494,6 +3728,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
self._overloads]
def finish(self, scope):
IDLInterfaceMember.finish(self, scope)
if self.getExtendedAttribute("FeatureDetectible"):
if not (self.getExtendedAttribute("Func") or
self.getExtendedAttribute("AvailableIn") or
@ -3577,6 +3813,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
if len(self.signaturesForArgCount(i)) != 0 ]
def validate(self):
IDLInterfaceMember.validate(self)
# Make sure our overloads are properly distinguishable and don't have
# different argument types before the distinguishing args.
for argCount in self.allowedArgCounts:
@ -3596,6 +3834,12 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
distinguishingIndex),
[self.location, overload.location])
for overload in self._overloads:
if not overload.returnType.unroll().isExposedInAllOf(self.exposureSet):
raise WebIDLError("Overload returns a type that is not exposed "
"everywhere where the method is exposed",
[overload.location])
def overloadsForArgCount(self, argc):
return [overload for overload in self._overloads if
len(overload.arguments) == argc or
@ -3674,6 +3918,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
raise WebIDLError("[LenientFloat] used on an operation with no "
"restricted float type arguments",
[attr.location, self.location])
elif identifier == "Exposed":
convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
elif (identifier == "Pure" or
identifier == "CrossOriginCallable" or
identifier == "WebGLHandlesContextLoss" or
@ -3920,6 +4166,45 @@ class Tokenizer(object):
lextab='webidllex',
reflags=re.DOTALL)
class SqueakyCleanLogger(object):
errorWhitelist = [
# Web IDL defines the WHITESPACE token, but doesn't actually
# use it ... so far.
"Token 'WHITESPACE' defined, but not used",
# And that means we have an unused token
"There is 1 unused token",
# Web IDL defines a OtherOrComma rule that's only used in
# ExtendedAttributeInner, which we don't use yet.
"Rule 'OtherOrComma' defined, but not used",
# And an unused rule
"There is 1 unused rule",
# And the OtherOrComma grammar symbol is unreachable.
"Symbol 'OtherOrComma' is unreachable",
# Which means the Other symbol is unreachable.
"Symbol 'Other' is unreachable",
]
def __init__(self):
self.errors = []
def debug(self, msg, *args, **kwargs):
pass
info = debug
def warning(self, msg, *args, **kwargs):
if msg == "%s:%d: Rule '%s' defined, but not used":
# Munge things so we don't have to hardcode filenames and
# line numbers in our whitelist.
whitelistmsg = "Rule '%s' defined, but not used"
whitelistargs = args[2:]
else:
whitelistmsg = msg
whitelistargs = args
if (whitelistmsg % whitelistargs) not in SqueakyCleanLogger.errorWhitelist:
self.errors.append(msg % args)
error = warning
def reportGrammarErrors(self):
if self.errors:
raise WebIDLError("\n".join(self.errors), [])
class Parser(Tokenizer):
def getLocation(self, p, i):
return Location(self.lexer, p.lineno(i), p.lexpos(i), self._filename)
@ -3995,10 +4280,11 @@ class Parser(Tokenizer):
parent = p[3]
try:
if self.globalScope()._lookupIdentifier(identifier):
p[0] = self.globalScope()._lookupIdentifier(identifier)
existingObj = self.globalScope()._lookupIdentifier(identifier)
if existingObj:
p[0] = existingObj
if not isinstance(p[0], IDLInterface):
raise WebIDLError("Partial interface has the same name as "
raise WebIDLError("Interface has the same name as "
"non-interface object",
[location, p[0].location])
p[0].setNonPartial(location, parent, members)
@ -4009,7 +4295,7 @@ class Parser(Tokenizer):
pass
p[0] = IDLInterface(location, self.globalScope(), identifier, parent,
members, isPartial=False)
members, isKnownNonPartial=True)
def p_InterfaceForwardDecl(self, p):
"""
@ -4042,26 +4328,26 @@ class Parser(Tokenizer):
identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
members = p[5]
nonPartialInterface = None
try:
if self.globalScope()._lookupIdentifier(identifier):
p[0] = self.globalScope()._lookupIdentifier(identifier)
if not isinstance(p[0], IDLInterface):
nonPartialInterface = self.globalScope()._lookupIdentifier(identifier)
if nonPartialInterface:
if not isinstance(nonPartialInterface, IDLInterface):
raise WebIDLError("Partial interface has the same name as "
"non-interface object",
[location, p[0].location])
# Just throw our members into the existing IDLInterface. If we
# have extended attributes, those will get added to it
# automatically.
p[0].members.extend(members)
return
[location, nonPartialInterface.location])
except Exception, ex:
if isinstance(ex, WebIDLError):
raise ex
pass
p[0] = IDLInterface(location, self.globalScope(), identifier, None,
members, isPartial=True)
pass
if not nonPartialInterface:
nonPartialInterface = IDLInterface(location, self.globalScope(),
identifier, None,
[], isKnownNonPartial=False)
partialInterface = IDLPartialInterface(location, identifier, members,
nonPartialInterface)
p[0] = partialInterface
def p_Inheritance(self, p):
"""
@ -4726,6 +5012,7 @@ class Parser(Tokenizer):
| ExtendedAttributeArgList
| ExtendedAttributeIdent
| ExtendedAttributeNamedArgList
| ExtendedAttributeIdentList
"""
p[0] = IDLExtendedAttribute(self.getLocation(p, 1), p[1])
@ -5200,6 +5487,34 @@ class Parser(Tokenizer):
"""
p[0] = (p[1], p[3], p[5])
def p_ExtendedAttributeIdentList(self, p):
"""
ExtendedAttributeIdentList : IDENTIFIER EQUALS LPAREN IdentifierList RPAREN
"""
p[0] = (p[1], p[4])
def p_IdentifierList(self, p):
"""
IdentifierList : IDENTIFIER Identifiers
"""
idents = list(p[2])
idents.insert(0, p[1])
p[0] = idents
def p_IdentifiersList(self, p):
"""
Identifiers : COMMA IDENTIFIER Identifiers
"""
idents = list(p[3])
idents.insert(0, p[2])
p[0] = idents
def p_IdentifiersEmpty(self, p):
"""
Identifiers :
"""
p[0] = []
def p_error(self, p):
if not p:
raise WebIDLError("Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) or both",
@ -5209,10 +5524,12 @@ class Parser(Tokenizer):
def __init__(self, outputdir='', lexer=None):
Tokenizer.__init__(self, outputdir, lexer)
logger = SqueakyCleanLogger()
self.parser = yacc.yacc(module=self,
outputdir=outputdir,
tabmodule='webidlyacc',
errorlog=yacc.NullLogger()
errorlog=logger
# Pickling the grammar is a speedup in
# some cases (older Python?) but a
# significant slowdown in others.
@ -5220,7 +5537,13 @@ class Parser(Tokenizer):
# becomes a speedup again.
# , picklefile='WebIDLGrammar.pkl'
)
logger.reportGrammarErrors()
self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None)
# To make our test harness work, pretend like we have a primary global already. Note that we _don't_ set _globalScope.primaryGlobalAttr, so we'll still be able to detect multiple PrimaryGlobal extended attributes.
self._globalScope.primaryGlobalName = "FakeTestPrimaryGlobal"
self._globalScope.globalNames.add("FakeTestPrimaryGlobal")
self._globalScope.globalNameMapping["FakeTestPrimaryGlobal"].add("FakeTestPrimaryGlobal")
self._installBuiltins(self._globalScope)
self._productions = []

View File

@ -0,0 +1,222 @@
import WebIDL
def WebIDLTest(parser, harness):
parser.parse("""
[PrimaryGlobal] interface Foo {};
[Global=(Bar1,Bar2)] interface Bar {};
[Global=Baz2] interface Baz {};
[Exposed=(Foo,Bar1)]
interface Iface {
void method1();
[Exposed=Bar1]
readonly attribute any attr;
};
[Exposed=Foo]
partial interface Iface {
void method2();
};
""")
results = parser.finish()
harness.check(len(results), 5, "Should know about five things");
iface = results[3]
harness.ok(isinstance(iface, WebIDL.IDLInterface),
"Should have an interface here");
members = iface.members
harness.check(len(members), 3, "Should have three members")
harness.ok(members[0].exposureSet == set(["Foo", "Bar"]),
"method1 should have the right exposure set")
harness.ok(members[0]._exposureGlobalNames == set(["Foo", "Bar1"]),
"method1 should have the right exposure global names")
harness.ok(members[1].exposureSet == set(["Bar"]),
"attr should have the right exposure set")
harness.ok(members[1]._exposureGlobalNames == set(["Bar1"]),
"attr should have the right exposure global names")
harness.ok(members[2].exposureSet == set(["Foo"]),
"method2 should have the right exposure set")
harness.ok(members[2]._exposureGlobalNames == set(["Foo"]),
"method2 should have the right exposure global names")
harness.ok(iface.exposureSet == set(["Foo", "Bar"]),
"Iface should have the right exposure set")
harness.ok(iface._exposureGlobalNames == set(["Foo", "Bar1"]),
"Iface should have the right exposure global names")
parser = parser.reset()
parser.parse("""
[PrimaryGlobal] interface Foo {};
[Global=(Bar1,Bar2)] interface Bar {};
[Global=Baz2] interface Baz {};
interface Iface2 {
void method3();
};
""")
results = parser.finish()
harness.check(len(results), 4, "Should know about four things");
iface = results[3]
harness.ok(isinstance(iface, WebIDL.IDLInterface),
"Should have an interface here");
members = iface.members
harness.check(len(members), 1, "Should have one member")
harness.ok(members[0].exposureSet == set(["Foo"]),
"method3 should have the right exposure set")
harness.ok(members[0]._exposureGlobalNames == set(["Foo"]),
"method3 should have the right exposure global names")
harness.ok(iface.exposureSet == set(["Foo"]),
"Iface2 should have the right exposure set")
harness.ok(iface._exposureGlobalNames == set(["Foo"]),
"Iface2 should have the right exposure global names")
parser = parser.reset()
parser.parse("""
[PrimaryGlobal] interface Foo {};
[Global=(Bar1,Bar2)] interface Bar {};
[Global=Baz2] interface Baz {};
[Exposed=Foo]
interface Iface3 {
void method4();
};
[Exposed=(Foo,Bar1)]
interface Mixin {
void method5();
};
Iface3 implements Mixin;
""")
results = parser.finish()
harness.check(len(results), 6, "Should know about six things");
iface = results[3]
harness.ok(isinstance(iface, WebIDL.IDLInterface),
"Should have an interface here");
members = iface.members
harness.check(len(members), 2, "Should have two members")
harness.ok(members[0].exposureSet == set(["Foo"]),
"method4 should have the right exposure set")
harness.ok(members[0]._exposureGlobalNames == set(["Foo"]),
"method4 should have the right exposure global names")
harness.ok(members[1].exposureSet == set(["Foo", "Bar"]),
"method5 should have the right exposure set")
harness.ok(members[1]._exposureGlobalNames == set(["Foo", "Bar1"]),
"method5 should have the right exposure global names")
parser = parser.reset()
threw = False
try:
parser.parse("""
[Exposed=Foo]
interface Bar {
};
""")
results = parser.finish()
except Exception,x:
threw = True
harness.ok(threw, "Should have thrown on invalid Exposed value on interface.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Bar {
[Exposed=Foo]
readonly attribute bool attr;
};
""")
results = parser.finish()
except Exception,x:
threw = True
harness.ok(threw, "Should have thrown on invalid Exposed value on attribute.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Bar {
[Exposed=Foo]
void operation();
};
""")
results = parser.finish()
except Exception,x:
threw = True
harness.ok(threw, "Should have thrown on invalid Exposed value on operation.")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Bar {
[Exposed=Foo]
const long constant = 5;
};
""")
results = parser.finish()
except Exception,x:
threw = True
harness.ok(threw, "Should have thrown on invalid Exposed value on constant.")
parser = parser.reset()
threw = False
try:
parser.parse("""
[Global] interface Foo {};
[Global] interface Bar {};
[Exposed=Foo]
interface Baz {
[Exposed=Bar]
void method();
};
""")
results = parser.finish()
except Exception,x:
threw = True
harness.ok(threw, "Should have thrown on member exposed where its interface is not.")
parser = parser.reset()
threw = False
try:
parser.parse("""
[Global] interface Foo {};
[Global] interface Bar {};
[Exposed=Foo]
interface Baz {
void method();
};
[Exposed=Bar]
interface Mixin {};
Baz implements Mixin;
""")
results = parser.finish()
except Exception,x:
threw = True
harness.ok(threw, "Should have thrown on LHS of implements being exposed where RHS is not.")

View File

@ -201,8 +201,8 @@ def WebIDLTest(parser, harness):
};
""");
results = parser.finish();
harness.check(len(results), 1,
"Should have one result with partial interface")
harness.check(len(results), 2,
"Should have two results with partial interface")
iface = results[0]
harness.check(len(iface.members), 3,
"Should have three members with partial interface")
@ -231,9 +231,9 @@ def WebIDLTest(parser, harness):
};
""");
results = parser.finish();
harness.check(len(results), 1,
"Should have one result with reversed partial interface")
iface = results[0]
harness.check(len(results), 2,
"Should have two results with reversed partial interface")
iface = results[1]
harness.check(len(iface.members), 3,
"Should have three members with reversed partial interface")
harness.check(iface.members[0].identifier.name, "x",

View File

@ -580,10 +580,6 @@ WebGLContext::CopyTexSubImage2D(GLenum target,
if (yoffset + height > texHeight || yoffset + height < 0)
return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
GLenum webGLFormat = imageInfo.WebGLFormat();
if (IsGLDepthFormat(webGLFormat) || IsGLDepthStencilFormat(webGLFormat))
return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
@ -597,6 +593,7 @@ WebGLContext::CopyTexSubImage2D(GLenum target,
ClearBackbufferIfNeeded();
}
GLenum webGLFormat = imageInfo.WebGLFormat();
bool texFormatRequiresAlpha = FormatHasAlpha(webGLFormat);
bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
: bool(gl->GetPixelFormat().alpha > 0);

View File

@ -527,6 +527,31 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
return true;
}
/* WEBGL_depth_texture added formats */
if (format == LOCAL_GL_DEPTH_COMPONENT ||
format == LOCAL_GL_DEPTH_STENCIL)
{
if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
InfoFrom(func), EnumName(format));
return false;
}
// If WEBGL_depth_texture is enabled, then it is not allowed to be used with the
// texSubImage, copyTexImage, or copyTexSubImage methods
if (func == WebGLTexImageFunc::TexSubImage ||
func == WebGLTexImageFunc::CopyTexImage ||
func == WebGLTexImageFunc::CopyTexSubImage)
{
ErrorInvalidOperation("%s: format %s is not supported", InfoFrom(func), EnumName(format));
return false;
}
return true;
}
// Needs to be below the depth_texture check because an invalid operation
// error needs to be generated instead of invalid enum.
/* Only core formats are valid for CopyTex(Sub)?Image */
// TODO: Revisit this once color_buffer_(half_)?float lands
if (IsCopyFunc(func)) {
@ -534,17 +559,6 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
return false;
}
/* WEBGL_depth_texture added formats */
if (format == LOCAL_GL_DEPTH_COMPONENT ||
format == LOCAL_GL_DEPTH_STENCIL)
{
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
if (!validFormat)
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
InfoFrom(func), WebGLContext::EnumName(format));
return validFormat;
}
/* EXT_sRGB added formats */
if (format == LOCAL_GL_SRGB ||
format == LOCAL_GL_SRGB_ALPHA)

View File

@ -14,29 +14,29 @@ HZ-GB-2312=zh-CN
IBM866=x-cyrillic
ISO-2022-JP=ja
ISO-8859-3=x-western
ISO-8859-4=x-baltic
ISO-8859-4=x-western
ISO-8859-5=x-cyrillic
ISO-8859-6=ar
ISO-8859-7=el
ISO-8859-8=he
ISO-8859-8-I=he
ISO-8859-10=x-western
ISO-8859-13=x-baltic
ISO-8859-13=x-western
ISO-8859-14=x-western
ISO-8859-15=x-western
ISO-8859-16=x-central-euro
ISO-8859-2=x-central-euro
ISO-8859-16=x-western
ISO-8859-2=x-western
KOI8-R=x-cyrillic
KOI8-U=x-cyrillic
Shift_JIS=ja
windows-1250=x-central-euro
windows-1250=x-western
windows-1251=x-cyrillic
windows-1252=x-western
windows-1253=el
windows-1254=tr
windows-1254=x-western
windows-1255=he
windows-1256=ar
windows-1257=x-baltic
windows-1257=x-western
windows-1258=x-western
windows-874=th
x-mac-cyrillic=x-cyrillic

View File

@ -6,6 +6,7 @@
#include "FMRadioService.h"
#include "mozilla/Hal.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsIAudioManager.h"
#include "AudioManager.h"
#include "nsDOMClassInfo.h"
@ -832,6 +833,7 @@ FMRadioService::Singleton()
if (!sFMRadioService) {
sFMRadioService = new FMRadioService();
ClearOnShutdown(&sFMRadioService);
}
return sFMRadioService;

View File

@ -918,7 +918,7 @@ ContentChild::RecvSetProcessSandbox()
// at some point; see bug 880808.
#if defined(MOZ_CONTENT_SANDBOX)
#if defined(XP_LINUX)
SetCurrentProcessSandbox();
SetContentProcessSandbox();
#elif defined(XP_WIN)
mozilla::SandboxTarget::Instance()->StartSandbox();
#endif

View File

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window,Worker)]
interface AbstractWorker {
attribute EventHandler onerror;
};

View File

@ -4,7 +4,8 @@
* 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/. */
[ChromeOnly]
[ChromeOnly,
Exposed=(Window,Worker)]
interface Console {
void log(any... data);
void info(any... data);

View File

@ -15,7 +15,8 @@
interface StackFrame;
[NoInterfaceObject]
[NoInterfaceObject,
Exposed=(Window,Worker)]
interface ExceptionMembers
{
// A custom message set by the thrower. LenientThis so it can be
@ -72,7 +73,8 @@ Exception implements ExceptionMembers;
// XXXkhuey this is an 'exception', not an interface, but we don't have any
// parser or codegen mechanisms for dealing with exceptions.
[ExceptionClass]
[ExceptionClass,
Exposed=(Window, Worker)]
interface DOMException {
const unsigned short INDEX_SIZE_ERR = 1;
const unsigned short DOMSTRING_SIZE_ERR = 2; // historical

View File

@ -12,7 +12,8 @@ typedef (DOMString or unsigned long) DataStoreKey;
// JS codes implemented by the DataStoreImpl WebIDL.
[Func="Navigator::HasDataStoreSupport",
ChromeConstructor]
ChromeConstructor,
Exposed=(Window,Worker)]
interface DataStore : EventTarget {
// Returns the label of the DataSource.
[GetterThrows]
@ -65,8 +66,9 @@ partial interface DataStore {
// which currently plays a role of C++ proxy directing to the
// JS codes implemented by the DataStoreCursorImpl WebIDL.
[Pref="dom.datastore.enabled",
ChromeConstructor]
[Func="Navigator::HasDataStoreSupport",
ChromeConstructor,
Exposed=(Window,Worker)]
interface DataStoreCursor {
// the DataStore
[GetterThrows]

View File

@ -12,7 +12,8 @@
* this document.
*/
[Global, Func="mozilla::dom::workers::DedicatedWorkerGlobalScope::Visible"]
[Global=(Worker,DedicatedWorker),
Exposed=DedicatedWorker]
interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
[Throws]
void postMessage(any message, optional sequence<any> transfer);

View File

@ -10,7 +10,8 @@
* liability, trademark and document use rules apply.
*/
[Constructor(DOMString type, optional EventInit eventInitDict)]
[Constructor(DOMString type, optional EventInit eventInitDict),
Exposed=(Window,Worker)]
interface Event {
[Pure]
readonly attribute DOMString type;

View File

@ -10,6 +10,7 @@
* liability, trademark and document use rules apply.
*/
[Exposed=(Window,Worker)]
interface EventTarget {
/* Passing null for wantsUntrusted means "default behavior", which
differs in content and chrome. In content that default boolean

View File

@ -12,7 +12,8 @@
interface Blob;
[Constructor]
[Constructor,
Exposed=Worker]
interface FileReaderSync {
// Synchronously return strings

View File

@ -19,7 +19,7 @@ enum HeadersGuardEnum {
};
[Constructor(optional HeadersInit init),
// FIXME: Exposed=Window,Worker,
Exposed=(Window,Worker),
Func="mozilla::dom::Headers::PrefEnabled"]
interface Headers {
[Throws] void append(ByteString name, ByteString value);

View File

@ -11,7 +11,8 @@
*/
[Constructor(unsigned long sw, unsigned long sh),
Constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh)]
Constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh),
Exposed=(Window,Worker)]
interface ImageData {
[Constant]
readonly attribute unsigned long width;

View File

@ -10,7 +10,11 @@
// While not explicitly restricted to ServiceWorkerGlobalScope, it probably
// should be. https://github.com/slightlyoff/ServiceWorker/issues/254
[Constructor(DOMString type, optional InstallEventInit eventInitDict),
Func="mozilla::dom::workers::ServiceWorkerEventsVisible"]
Func="mozilla::dom::workers::ServiceWorkerEventsVisible",
// XXXbz I have no idea where this should be exposed. The spec makes
// no sense. But since it returns a ServiceWorker and that's only
// exposed in Window, let's say Window.
Exposed=Window]
interface InstallEvent : InstallPhaseEvent {
// The currently active worker for this scope when this worker is asked to
// install itself.

View File

@ -10,7 +10,8 @@
// While not explicitly restricted to ServiceWorkerGlobalScope, it probably
// should be. https://github.com/slightlyoff/ServiceWorker/issues/254
[Constructor(DOMString type, optional EventInit eventInitDict),
Func="mozilla::dom::workers::ServiceWorkerEventsVisible"]
Func="mozilla::dom::workers::ServiceWorkerEventsVisible",
Exposed=(ServiceWorker,Window)]
interface InstallPhaseEvent : Event {
// https://github.com/slightlyoff/ServiceWorker/issues/261
void waitUntil(Promise<any> p);

View File

@ -7,10 +7,14 @@
interface nsISupports;
interface IID;
[NoInterfaceObject]
[NoInterfaceObject,
// Need Exposed here, because this is a mixin onto things like Event
// that are exposed in workers.
Exposed=(Window,Worker)]
interface LegacyQueryInterface {
// Legacy QueryInterface, only exposed to chrome or XBL code on the
// main thread.
[Exposed=Window]
nsISupports queryInterface(IID iid);
};

View File

@ -9,7 +9,8 @@
interface WindowProxy;
[Constructor(DOMString type, optional MessageEventInit eventInitDict)]
[Constructor(DOMString type, optional MessageEventInit eventInitDict),
Exposed=(Window,Worker)]
interface MessageEvent : Event {
/**
* Custom data associated with this event.

View File

@ -7,6 +7,7 @@
* http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging
*/
[Exposed=(Window,Worker)]
interface MessagePort : EventTarget {
[Throws]
void postMessage(any message, optional sequence<Transferable> transferable);

View File

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[NoInterfaceObject, ArrayClass]
[NoInterfaceObject, ArrayClass, Exposed=(Window,Worker)]
interface MessagePortList {
readonly attribute unsigned long length;
getter MessagePort? item(unsigned long index);

View File

@ -30,7 +30,7 @@ Navigator implements NavigatorContentUtils;
Navigator implements NavigatorStorageUtils;
Navigator implements NavigatorFeatures;
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window,Worker)]
interface NavigatorID {
// WebKit/Blink/Trident/Presto support this (hardcoded "Mozilla").
[Constant]
@ -53,10 +53,11 @@ interface NavigatorID {
[NoInterfaceObject]
interface NavigatorLanguage {
readonly attribute DOMString? language;
[Pure, Cached, Frozen] readonly attribute sequence<DOMString> languages;
[Pure, Cached, Frozen]
readonly attribute sequence<DOMString> languages;
};
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window,Worker)]
interface NavigatorOnLine {
readonly attribute boolean onLine;
};
@ -120,7 +121,8 @@ interface NavigatorBattery {
Navigator implements NavigatorBattery;
// https://wiki.mozilla.org/WebAPI/DataStore
[NoInterfaceObject]
[NoInterfaceObject,
Exposed=(Window,Worker)]
interface NavigatorDataStore {
[Throws, NewObject, Func="Navigator::HasDataStoreSupport"]
Promise<sequence<DataStore>> getDataStores(DOMString name,

View File

@ -16,7 +16,8 @@ callback PromiseInit = void (object resolve, object reject);
callback AnyCallback = any (any value);
// REMOVE THE RELEVANT ENTRY FROM test_interfaces.html WHEN THIS IS IMPLEMENTED IN JS.
[Constructor(PromiseInit init)]
[Constructor(PromiseInit init),
Exposed=(Window,Worker)]
// Need to escape "Promise" so it's treated as an identifier.
interface _Promise {
// TODO bug 875289 - static Promise fulfill(any value);

View File

@ -10,7 +10,10 @@
// Still unclear what should be subclassed.
// https://github.com/slightlyoff/ServiceWorker/issues/189
[Pref="dom.serviceWorkers.enabled"]
[Pref="dom.serviceWorkers.enabled",
// XXXbz I have no idea where this should be exposed. The spec makes
// no sense. But since it's got a pref, let's say window.
Exposed=Window]
interface ServiceWorker : EventTarget {
readonly attribute DOMString scope;
readonly attribute DOMString url;

View File

@ -37,15 +37,14 @@ interface ServiceWorkerContainer {
};
// Testing only.
[ChromeOnly, Pref="dom.serviceWorkers.testing.enabled"]
partial interface ServiceWorkerContainer {
[Throws]
[Throws,Pref="dom.serviceWorkers.testing.enabled"]
Promise<any> clearAllServiceWorkerData();
[Throws]
[Throws,Pref="dom.serviceWorkers.testing.enabled"]
DOMString getScopeForUrl(DOMString url);
[Throws]
[Throws,Pref="dom.serviceWorkers.testing.enabled"]
DOMString getControllingWorkerScriptURLForPath(DOMString path);
};

View File

@ -10,10 +10,8 @@
* this document.
*/
// The Pref controls exposure in general, the Func restricts it to inside the
// ServiceWorkerGlobalScope (itself).
[Global, Func="mozilla::dom::workers::ServiceWorkerGlobalScope::Visible",
Pref="dom.serviceWorkers.enabled"]
[Global=(Worker,ServiceWorker),
Exposed=ServiceWorker]
interface ServiceWorkerGlobalScope : WorkerGlobalScope {
// FIXME(nsm): Bug 982725
// readonly attribute CacheList caches;

View File

@ -12,7 +12,8 @@
* this document.
*/
[Global, Func="mozilla::dom::workers::SharedWorkerGlobalScope::Visible"]
[Global=(Worker,SharedWorker),
Exposed=SharedWorker]
interface SharedWorkerGlobalScope : WorkerGlobalScope {
readonly attribute DOMString name;
attribute EventHandler onconnect;

View File

@ -10,7 +10,8 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
[Constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options)]
[Constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options),
Exposed=(Window,Worker)]
interface TextDecoder {
[Constant]
readonly attribute DOMString encoding;

View File

@ -10,7 +10,8 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
[Constructor(optional DOMString utfLabel = "utf-8")]
[Constructor(optional DOMString utfLabel = "utf-8"),
Exposed=(Window,Worker)]
interface TextEncoder {
[Constant]
readonly attribute DOMString encoding;

View File

@ -14,7 +14,8 @@
// [Constructor(DOMString url, optional (URL or DOMString) base = "about:blank")]
[Constructor(DOMString url, URL base),
Constructor(DOMString url, optional DOMString base = "about:blank")]
Constructor(DOMString url, optional DOMString base = "about:blank"),
Exposed=(Window,Worker)]
interface URL {
};
URL implements URLUtils;

View File

@ -14,7 +14,8 @@
*/
[Constructor(optional DOMString init = ""),
Constructor(URLSearchParams init)]
Constructor(URLSearchParams init),
Exposed=(Window,Worker)]
interface URLSearchParams {
void append(DOMString name, DOMString value);
void delete(DOMString name);

View File

@ -13,7 +13,8 @@
* http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
*/
[NoInterfaceObject]
[NoInterfaceObject,
Exposed=(Window, Worker)]
interface URLUtilsNoSearchParams {
// Bug 824857: no support for stringifier attributes yet.
// stringifier attribute DOMString href;
@ -47,7 +48,8 @@ interface URLUtilsNoSearchParams {
stringifier;
};
[NoInterfaceObject]
[NoInterfaceObject,
Exposed=(Window, Worker)]
interface URLUtils : URLUtilsNoSearchParams
{
attribute URLSearchParams searchParams;

View File

@ -13,7 +13,8 @@
* http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
*/
[NoInterfaceObject]
[NoInterfaceObject,
Exposed=(Window, Worker)]
interface URLUtilsReadOnly {
stringifier;
readonly attribute DOMString href;

View File

@ -24,7 +24,7 @@ interface nsIDOMCrypto;
typedef any Transferable;
// http://www.whatwg.org/specs/web-apps/current-work/
[Global, NeedNewResolve]
[PrimaryGlobal, NeedNewResolve]
/*sealed*/ interface Window : EventTarget {
// the current browsing context
[Unforgeable, Throws,
@ -90,7 +90,7 @@ Window implements GlobalEventHandlers;
Window implements WindowEventHandlers;
// http://www.whatwg.org/specs/web-apps/current-work/
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window,Worker)]
interface WindowTimers {
[Throws] long setTimeout(Function handler, optional long timeout = 0, any... arguments);
[Throws] long setTimeout(DOMString handler, optional long timeout = 0, any... unused);
@ -102,7 +102,7 @@ interface WindowTimers {
Window implements WindowTimers;
// http://www.whatwg.org/specs/web-apps/current-work/
[NoInterfaceObject]
[NoInterfaceObject, Exposed=(Window,Worker)]
interface WindowBase64 {
[Throws] DOMString btoa(DOMString btoa);
[Throws] DOMString atob(DOMString atob);

View File

@ -13,7 +13,8 @@
*/
[Constructor(DOMString scriptURL),
Func="mozilla::dom::workers::WorkerPrivate::WorkerAvailable"]
Func="mozilla::dom::workers::WorkerPrivate::WorkerAvailable",
Exposed=(Window,Worker)]
interface Worker : EventTarget {
void terminate();
@ -26,6 +27,7 @@ interface Worker : EventTarget {
Worker implements AbstractWorker;
[Constructor(DOMString scriptURL),
Func="mozilla::dom::workers::ChromeWorkerPrivate::WorkerAvailable"]
Func="mozilla::dom::workers::ChromeWorkerPrivate::WorkerAvailable",
Exposed=(Window,Worker)]
interface ChromeWorker : Worker {
};

View File

@ -12,6 +12,7 @@
* this document.
*/
[Exposed=Worker]
interface WorkerGlobalScope : EventTarget {
readonly attribute WorkerGlobalScope self;

View File

@ -12,5 +12,6 @@
* this document.
*/
[Exposed=Worker]
interface WorkerLocation { };
WorkerLocation implements URLUtilsReadOnly;

View File

@ -2,6 +2,8 @@
* 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/. */
[Exposed=Worker]
interface WorkerNavigator {
};

View File

@ -54,7 +54,8 @@ dictionary MozXMLHttpRequestParameters
// things like this:
// c = new(window.ActiveXObject || XMLHttpRequest)("Microsoft.XMLHTTP")
// To handle that, we need a constructor that takes a string.
Constructor(DOMString ignored)]
Constructor(DOMString ignored),
Exposed=(Window,Worker)]
interface XMLHttpRequest : XMLHttpRequestEventTarget {
// event handler
attribute EventHandler onreadystatechange;
@ -129,7 +130,7 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget {
[Throws]
readonly attribute DOMString? responseText;
[Throws=MainThread]
[Throws, Exposed=Window]
readonly attribute Document? responseXML;
// Mozilla-specific stuff
@ -137,7 +138,7 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget {
[ChromeOnly, SetterThrows=Workers]
attribute boolean mozBackgroundRequest;
[ChromeOnly]
[ChromeOnly, Exposed=Window]
readonly attribute MozChannel? channel;
[Throws]

View File

@ -10,7 +10,8 @@
* liability, trademark and document use rules apply.
*/
[NoInterfaceObject]
[NoInterfaceObject,
Exposed=(Window,Worker)]
interface XMLHttpRequestEventTarget : EventTarget {
// event handlers
[SetterThrows=Workers, GetterThrows=Workers]

View File

@ -10,6 +10,7 @@
* liability, trademark and document use rules apply.
*/
[Exposed=(Window,Worker)]
interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {
};

View File

@ -10,28 +10,7 @@
#include "jsapi.h"
#include "js/OldDebugAPI.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ConsoleBinding.h"
#include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/dom/EventBinding.h"
#include "mozilla/dom/EventHandlerBinding.h"
#include "mozilla/dom/EventTargetBinding.h"
#include "mozilla/dom/FileReaderSyncBinding.h"
#include "mozilla/dom/HeadersBinding.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/ImageDataBinding.h"
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/PromiseBinding.h"
#include "mozilla/dom/TextDecoderBinding.h"
#include "mozilla/dom/TextEncoderBinding.h"
#include "mozilla/dom/XMLHttpRequestBinding.h"
#include "mozilla/dom/XMLHttpRequestUploadBinding.h"
#include "mozilla/dom/URLBinding.h"
#include "mozilla/dom/URLSearchParamsBinding.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/dom/WorkerLocationBinding.h"
#include "mozilla/dom/WorkerNavigatorBinding.h"
#include "mozilla/dom/RegisterWorkerBindings.h"
#include "mozilla/OSFileConstants.h"
USING_WORKERS_NAMESPACE
@ -40,15 +19,13 @@ using namespace mozilla::dom;
bool
WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
{
JS::Rooted<JSObject*> eventTargetProto(aCx,
EventTargetBinding::GetProtoObject(aCx, aGlobal));
if (!eventTargetProto) {
// Init Web IDL bindings
if (!RegisterWorkerBindings(aCx, aGlobal)) {
return false;
}
if (IsChromeWorker()) {
if (!ChromeWorkerBinding::GetConstructorObject(aCx, aGlobal) ||
!DefineChromeWorkerFunctions(aCx, aGlobal) ||
if (!DefineChromeWorkerFunctions(aCx, aGlobal) ||
!DefineOSFileConstants(aCx, aGlobal)) {
return false;
}
@ -59,29 +36,6 @@ WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
return false;
}
// Init other paris-bindings.
if (!ConsoleBinding::GetConstructorObject(aCx, aGlobal) ||
!DOMExceptionBinding::GetConstructorObject(aCx, aGlobal) ||
!EventBinding::GetConstructorObject(aCx, aGlobal) ||
!FileReaderSyncBinding_workers::GetConstructorObject(aCx, aGlobal) ||
(HeadersBinding::ConstructorEnabled(aCx, aGlobal) &&
!HeadersBinding::GetConstructorObject(aCx, aGlobal)) ||
!ImageDataBinding::GetConstructorObject(aCx, aGlobal) ||
!MessageEventBinding::GetConstructorObject(aCx, aGlobal) ||
!MessagePortBinding::GetConstructorObject(aCx, aGlobal) ||
!PromiseBinding::GetConstructorObject(aCx, aGlobal) ||
!TextDecoderBinding::GetConstructorObject(aCx, aGlobal) ||
!TextEncoderBinding::GetConstructorObject(aCx, aGlobal) ||
!XMLHttpRequestBinding_workers::GetConstructorObject(aCx, aGlobal) ||
!XMLHttpRequestUploadBinding_workers::GetConstructorObject(aCx, aGlobal) ||
!URLBinding_workers::GetConstructorObject(aCx, aGlobal) ||
!URLSearchParamsBinding::GetConstructorObject(aCx, aGlobal) ||
!WorkerBinding::GetConstructorObject(aCx, aGlobal) ||
!WorkerLocationBinding_workers::GetConstructorObject(aCx, aGlobal) ||
!WorkerNavigatorBinding_workers::GetConstructorObject(aCx, aGlobal)) {
return false;
}
if (!JS_DefineProfilingFunctions(aCx, aGlobal)) {
return false;
}

View File

@ -3580,11 +3580,17 @@ ChromeWorkerPrivate::Constructor(const GlobalObject& aGlobal,
// static
bool
ChromeWorkerPrivate::WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */)
ChromeWorkerPrivate::WorkerAvailable(JSContext* aCx, JSObject* /* unused */)
{
// Chrome is always allowed to use workers, and content is never allowed to
// use ChromeWorker, so all we have to check is the caller.
return nsContentUtils::ThreadsafeIsCallerChrome();
// Chrome is always allowed to use workers, and content is never
// allowed to use ChromeWorker, so all we have to check is the
// caller. However, chrome workers apparently might not have a
// system principal, so we have to check for them manually.
if (NS_IsMainThread()) {
return nsContentUtils::IsCallerChrome();
}
return GetWorkerPrivateFromContext(aCx)->IsChromeWorker();
}
// static

View File

@ -1191,7 +1191,7 @@ public:
ErrorResult& rv);
static bool
WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */);
WorkerAvailable(JSContext* aCx, JSObject* /* unused */);
private:
ChromeWorkerPrivate() MOZ_DELETE;

View File

@ -281,14 +281,6 @@ DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPri
{
}
/* static */ bool
DedicatedWorkerGlobalScope::Visible(JSContext* aCx, JSObject* aObj)
{
DedicatedWorkerGlobalScope* self = nullptr;
nsresult rv = UNWRAP_WORKER_OBJECT(DedicatedWorkerGlobalScope, aObj, self);
return NS_SUCCEEDED(rv) && self;
}
JSObject*
DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx)
{
@ -320,14 +312,6 @@ SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
{
}
/* static */ bool
SharedWorkerGlobalScope::Visible(JSContext* aCx, JSObject* aObj)
{
SharedWorkerGlobalScope* self = nullptr;
nsresult rv = UNWRAP_WORKER_OBJECT(SharedWorkerGlobalScope, aObj, self);
return NS_SUCCEEDED(rv) && self;
}
JSObject*
SharedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx)
{
@ -349,14 +333,6 @@ ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate
{
}
/* static */ bool
ServiceWorkerGlobalScope::Visible(JSContext* aCx, JSObject* aObj)
{
ServiceWorkerGlobalScope* self = nullptr;
nsresult rv = UNWRAP_WORKER_OBJECT(ServiceWorkerGlobalScope, aObj, self);
return NS_SUCCEEDED(rv) && self;
}
JSObject*
ServiceWorkerGlobalScope::WrapGlobalObject(JSContext* aCx)
{

View File

@ -124,9 +124,6 @@ class DedicatedWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope
public:
DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate);
static bool
Visible(JSContext* aCx, JSObject* aObj);
virtual JSObject*
WrapGlobalObject(JSContext* aCx) MOZ_OVERRIDE;
@ -148,9 +145,6 @@ public:
SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
const nsCString& aName);
static bool
Visible(JSContext* aCx, JSObject* aObj);
virtual JSObject*
WrapGlobalObject(JSContext* aCx) MOZ_OVERRIDE;
@ -170,9 +164,6 @@ class ServiceWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope
public:
ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, const nsACString& aScope);
static bool
Visible(JSContext* aCx, JSObject* aObj);
virtual JSObject*
WrapGlobalObject(JSContext* aCx) MOZ_OVERRIDE;

View File

@ -220,18 +220,6 @@ public:
void
GetResponseText(nsAString& aResponseText, ErrorResult& aRv);
JSObject*
GetResponseXML() const
{
return nullptr;
}
JSObject*
GetChannel() const
{
return nullptr;
}
void
GetInterface(JSContext* cx, JS::Handle<JSObject*> aIID,
JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv)

View File

@ -30,10 +30,7 @@ var ecmaGlobals =
"Float32Array",
"Float64Array",
"Function",
// NB: We haven't bothered to resolve constants like Infinity and NaN on
// Xrayed windows (which are seen from the XBL scope). We could support
// this if needed with some refactoring.
{name: "Infinity"},
"Infinity",
"Int16Array",
"Int32Array",
"Int8Array",
@ -43,7 +40,7 @@ var ecmaGlobals =
"JSON",
"Map",
"Math",
{name: "NaN"},
"NaN",
"Number",
"Object",
"Proxy",
@ -74,10 +71,12 @@ var interfaceNamesInGlobalScope =
[
// IMPORTANT: Do not change this list without review from a DOM peer!
"Blob",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Console",
// IMPORTANT: Do not change this list without review from a DOM peer!
"DedicatedWorkerGlobalScope",
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "DataStore", b2g: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "DataStoreCursor", b2g: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
"DOMException",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -143,6 +143,7 @@ static const char *sExtensionNames[] = {
"GL_OES_compressed_ETC1_RGB8_texture",
"GL_EXT_draw_range_elements",
"GL_EXT_shader_texture_lod",
"GL_NV_fence",
nullptr
};
@ -1075,6 +1076,26 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
}
if (IsExtensionSupported(NV_fence)) {
SymLoadStruct extSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGenFences, { "GenFencesNV", nullptr } },
{ (PRFuncPtr*) &mSymbols.fDeleteFences, { "DeleteFencesNV", nullptr } },
{ (PRFuncPtr*) &mSymbols.fSetFence, { "SetFenceNV", nullptr } },
{ (PRFuncPtr*) &mSymbols.fTestFence, { "TestFenceNV", nullptr } },
{ (PRFuncPtr*) &mSymbols.fFinishFence, { "FinishFenceNV", nullptr } },
{ (PRFuncPtr*) &mSymbols.fIsFence, { "IsFenceNV", nullptr } },
{ (PRFuncPtr*) &mSymbols.fGetFenceiv, { "GetFenceivNV", nullptr } },
END_SYMBOLS
};
if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
NS_ERROR("GL supports NV_fence without supplying its functions.");
MarkExtensionUnsupported(NV_fence);
ClearSymbols(extSymbols);
}
}
// Load developer symbols, don't fail if we can't find them.
SymLoadStruct auxSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },

View File

@ -412,6 +412,7 @@ public:
OES_compressed_ETC1_RGB8_texture,
EXT_draw_range_elements,
EXT_shader_texture_lod,
NV_fence,
Extensions_Max,
Extensions_End
};
@ -2501,6 +2502,67 @@ public:
return ret;
}
// -----------------------------------------------------------------------------
// Extension NV_fence
public:
void fGenFences(GLsizei n, GLuint* fences)
{
ASSERT_SYMBOL_PRESENT(fGenFences);
BEFORE_GL_CALL;
mSymbols.fGenFences(n, fences);
AFTER_GL_CALL;
}
void fDeleteFences(GLsizei n, const GLuint* fences)
{
ASSERT_SYMBOL_PRESENT(fDeleteFences);
BEFORE_GL_CALL;
mSymbols.fDeleteFences(n, fences);
AFTER_GL_CALL;
}
void fSetFence(GLuint fence, GLenum condition)
{
ASSERT_SYMBOL_PRESENT(fSetFence);
BEFORE_GL_CALL;
mSymbols.fSetFence(fence, condition);
AFTER_GL_CALL;
}
realGLboolean fTestFence(GLuint fence)
{
ASSERT_SYMBOL_PRESENT(fTestFence);
BEFORE_GL_CALL;
realGLboolean ret = mSymbols.fTestFence(fence);
AFTER_GL_CALL;
return ret;
}
void fFinishFence(GLuint fence)
{
ASSERT_SYMBOL_PRESENT(fFinishFence);
BEFORE_GL_CALL;
mSymbols.fFinishFence(fence);
AFTER_GL_CALL;
}
realGLboolean fIsFence(GLuint fence)
{
ASSERT_SYMBOL_PRESENT(fIsFence);
BEFORE_GL_CALL;
realGLboolean ret = mSymbols.fIsFence(fence);
AFTER_GL_CALL;
return ret;
}
void fGetFenceiv(GLuint fence, GLenum pname, GLint* params)
{
ASSERT_SYMBOL_PRESENT(fGetFenceiv);
BEFORE_GL_CALL;
mSymbols.fGetFenceiv(fence, pname, params);
AFTER_GL_CALL;
}
// -----------------------------------------------------------------------------
// Constructor

View File

@ -497,6 +497,22 @@ struct GLContextSymbols
// draw_range_elements
typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTS) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices);
PFNGLDRAWRANGEELEMENTS fDrawRangeElements;
// NV_fence
typedef void (GLAPIENTRY * pfnGenFencesT) (GLsizei n, GLuint* fences);
pfnGenFencesT fGenFences;
typedef void (GLAPIENTRY * pfnDeleteFencesT) (GLsizei n, const GLuint* fences);
pfnDeleteFencesT fDeleteFences;
typedef void (GLAPIENTRY * pfnSetFenceT) (GLuint fence, GLenum condition);
pfnSetFenceT fSetFence;
typedef realGLboolean (GLAPIENTRY * pfnTestFenceT) (GLuint fence);
pfnTestFenceT fTestFence;
typedef void (GLAPIENTRY * pfnFinishFenceT) (GLuint fence);
pfnFinishFenceT fFinishFence;
typedef realGLboolean (GLAPIENTRY * pfnIsFenceT) (GLuint fence);
pfnIsFenceT fIsFence;
typedef void (GLAPIENTRY * pfnGetFenceivT) (GLuint fence, GLenum pname, GLint* params);
pfnGetFenceivT fGetFenceiv;
};
}

View File

@ -80,6 +80,7 @@ protected:
public:
virtual void Fence() = 0;
virtual bool WaitSync() = 0;
virtual bool PollSync() = 0;
// This function waits until the buffer is no longer being used.
// To optimize the performance, some implementaions recycle SharedSurfaces

View File

@ -51,20 +51,12 @@ SharedSurface_ANGLEShareHandle::UnlockProdImpl()
{
}
void
SharedSurface_ANGLEShareHandle::Fence()
{
mGL->fFinish();
}
bool
SharedSurface_ANGLEShareHandle::WaitSync()
{
// Since we glFinish in Fence(), we're always going to be resolved here.
return true;
}
static void
FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs,
int redBits, int greenBits,

View File

@ -64,7 +64,8 @@ public:
virtual void UnlockProdImpl() MOZ_OVERRIDE;
virtual void Fence() MOZ_OVERRIDE;
virtual bool WaitSync() MOZ_OVERRIDE;
virtual bool WaitSync() MOZ_OVERRIDE { return true; } // Fence is glFinish.
virtual bool PollSync() MOZ_OVERRIDE { return true; }
// Implementation-specific functions below:
HANDLE GetShareHandle() {

View File

@ -162,6 +162,30 @@ SharedSurface_EGLImage::WaitSync()
return true;
}
bool
SharedSurface_EGLImage::PollSync()
{
MutexAutoLock lock(mMutex);
if (!mSync) {
// We must not be needed.
return true;
}
MOZ_ASSERT(mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync));
EGLint status = 0;
MOZ_ALWAYS_TRUE( mEGL->fGetSyncAttrib(mEGL->Display(),
mSync,
LOCAL_EGL_SYNC_STATUS_KHR,
&status) );
if (status != LOCAL_EGL_SIGNALED_KHR) {
return false;
}
MOZ_ALWAYS_TRUE( mEGL->fDestroySync(mEGL->Display(), mSync) );
mSync = 0;
return true;
}
EGLDisplay
SharedSurface_EGLImage::Display() const

View File

@ -64,9 +64,9 @@ public:
virtual void LockProdImpl() MOZ_OVERRIDE {}
virtual void UnlockProdImpl() MOZ_OVERRIDE {}
virtual void Fence() MOZ_OVERRIDE;
virtual bool WaitSync() MOZ_OVERRIDE;
virtual bool PollSync() MOZ_OVERRIDE;
virtual GLuint ProdTexture() MOZ_OVERRIDE {
return mProdTex;

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