merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-10-28 15:53:31 +01:00
Родитель 51b468217d 70fc2808f1
Коммит f52809d2cb
95 изменённых файлов: 1370 добавлений и 901 удалений

Просмотреть файл

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 946065 needs a CLOBBER
Backout of bug 1087560 needed a CLOBBER

Просмотреть файл

@ -1082,8 +1082,9 @@ nsSHistory::GloballyEvictContentViewers()
nsTArray<TransactionAndDistance> transactions;
nsSHistory *shist = static_cast<nsSHistory*>(PR_LIST_HEAD(&gSHistoryList));
while (shist != &gSHistoryList) {
PRCList* listEntry = PR_LIST_HEAD(&gSHistoryList);
while (listEntry != &gSHistoryList) {
nsSHistory* shist = static_cast<nsSHistory*>(listEntry);
// Maintain a list of the transactions which have viewers and belong to
// this particular shist object. We'll add this list to the global list,
@ -1142,7 +1143,7 @@ nsSHistory::GloballyEvictContentViewers()
// We've found all the transactions belonging to shist which have viewers.
// Add those transactions to our global list and move on.
transactions.AppendElements(shTransactions);
shist = static_cast<nsSHistory*>(PR_NEXT_LINK(shist));
listEntry = PR_NEXT_LINK(shist);
}
// We now have collected all cached content viewers. First check that we

Просмотреть файл

@ -2551,6 +2551,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
js::SetProxyExtra(obj, 0, js::PrivateValue(nullptr));
js::SetProxyExtra(outerObject, 0, js::PrivateValue(nullptr));
outerObject = xpc::TransplantObject(cx, obj, outerObject);
if (!outerObject) {

Просмотреть файл

@ -174,6 +174,24 @@ UnwrapDOMObject(JSObject* obj)
return static_cast<T*>(val.toPrivate());
}
template <class T>
inline T*
UnwrapPossiblyNotInitializedDOMObject(JSObject* obj)
{
// This is used by the OjectMoved JSClass hook which can be called before
// JS_NewObject has returned and so before we have a chance to set
// DOM_OBJECT_SLOT to anything useful.
MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
"Don't pass non-DOM objects to this function");
JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
if (val.isUndefined()) {
return nullptr;
}
return static_cast<T*>(val.toPrivate());
}
inline const DOMJSClass*
GetDOMClass(const js::Class* clasp)
{

Просмотреть файл

@ -1528,7 +1528,7 @@ class CGAbstractClassHook(CGAbstractStaticMethod):
args)
def definition_body_prologue(self):
return ("%s* self = UnwrapDOMObject<%s>(obj);\n" %
return ("%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n" %
(self.descriptor.nativeType, self.descriptor.nativeType))
def definition_body(self):

Просмотреть файл

@ -669,6 +669,12 @@ CreateOffscreen(GLContext* gl,
if (!baseCaps.alpha)
baseCaps.premultAlpha = true;
if (gl->IsANGLE()) {
// We can't use no-alpha formats on ANGLE yet because of:
// https://code.google.com/p/angleproject/issues/detail?id=764
baseCaps.alpha = true;
}
// we should really have this behind a
// |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
// for now it's just behind a pref for testing/evaluation.
@ -903,17 +909,24 @@ WebGLContext::SetDimensions(int32_t sWidth, int32_t sHeight)
// increment the generation number
++mGeneration;
MakeContextCurrent();
gl->fViewport(0, 0, mWidth, mHeight);
mViewportWidth = mWidth;
mViewportHeight = mHeight;
// Update our internal stuff:
if (gl->WorkAroundDriverBugs()) {
if (!mOptions.alpha && gl->Caps().alpha) {
mNeedsFakeNoAlpha = true;
}
}
// Update mOptions.
mOptions.depth = gl->Caps().depth;
mOptions.stencil = gl->Caps().stencil;
mOptions.antialias = gl->Caps().antialias;
MakeContextCurrent();
gl->fViewport(0, 0, mWidth, mHeight);
mViewportWidth = mWidth;
mViewportHeight = mHeight;
// Make sure that we clear this out, otherwise
// we'll end up displaying random memory
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
@ -929,18 +942,13 @@ WebGLContext::SetDimensions(int32_t sWidth, int32_t sHeight)
mShouldPresent = true;
MOZ_ASSERT(gl->Caps().color);
MOZ_ASSERT(gl->Caps().alpha == mOptions.alpha);
MOZ_ASSERT_IF(!mNeedsFakeNoAlpha, gl->Caps().alpha == mOptions.alpha);
MOZ_ASSERT_IF(mNeedsFakeNoAlpha, !mOptions.alpha && gl->Caps().alpha);
MOZ_ASSERT(gl->Caps().depth == mOptions.depth);
MOZ_ASSERT(gl->Caps().stencil == mOptions.stencil);
MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias);
MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
if (!mOptions.alpha) {
mNeedsFakeNoAlpha = true;
}
}
AssertCachedBindings();
AssertCachedState();
@ -1252,12 +1260,10 @@ WebGLContext::GetContextAttributes(Nullable<dom::WebGLContextAttributes> &retval
dom::WebGLContextAttributes& result = retval.SetValue();
const PixelBufferFormat& format = gl->GetPixelFormat();
result.mAlpha.Construct(format.alpha > 0);
result.mDepth = format.depth > 0;
result.mStencil = format.stencil > 0;
result.mAntialias = format.samples > 1;
result.mAlpha.Construct(mOptions.alpha);
result.mDepth = mOptions.depth;
result.mStencil = mOptions.stencil;
result.mAntialias = mOptions.antialias;
result.mPremultipliedAlpha = mOptions.premultipliedAlpha;
result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer;
}
@ -1845,7 +1851,6 @@ bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
////////////////////////////////////////////////////////////////////////////////
WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
: mWebGL(webgl)
, mNeedsChange(NeedsChange(webgl))

Просмотреть файл

@ -2104,6 +2104,58 @@ WebGLContext::PixelStorei(GLenum pname, GLint param)
}
}
// `width` in pixels.
// `stride` in bytes.
static bool
SetFullAlpha(void* data, GLenum format, GLenum type, size_t width,
size_t height, size_t stride)
{
if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
// Just memset the rows.
for (size_t j = 0; j < height; ++j) {
uint8_t* row = static_cast<uint8_t*>(data) + j*stride;
memset(row, 0xff, width);
row += stride;
}
return true;
}
if (format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE) {
for (size_t j = 0; j < height; ++j) {
uint8_t* row = static_cast<uint8_t*>(data) + j*stride;
uint8_t* pAlpha = row + 3;
uint8_t* pAlphaEnd = pAlpha + 4*width;
while (pAlpha != pAlphaEnd) {
*pAlpha = 0xff;
pAlpha += 4;
}
}
return true;
}
if (format == LOCAL_GL_RGBA && type == LOCAL_GL_FLOAT) {
for (size_t j = 0; j < height; ++j) {
uint8_t* rowBytes = static_cast<uint8_t*>(data) + j*stride;
float* row = reinterpret_cast<float*>(rowBytes);
float* pAlpha = row + 3;
float* pAlphaEnd = pAlpha + 4*width;
while (pAlpha != pAlphaEnd) {
*pAlpha = 1.0f;
pAlpha += 4;
}
}
return true;
}
MOZ_ASSERT(false, "Unhandled case, how'd we get here?");
return false;
}
void
WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
GLsizei height, GLenum format,
@ -2347,61 +2399,25 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
// if we're reading alpha, we may need to do fixup. Note that we don't allow
// GL_ALPHA to readpixels currently, but we had the code written for it already.
if (format == LOCAL_GL_ALPHA ||
format == LOCAL_GL_RGBA)
{
bool needAlphaFixup;
if (mBoundFramebuffer) {
needAlphaFixup = !mBoundFramebuffer->ColorAttachment(0).HasAlpha();
} else {
needAlphaFixup = gl->GetPixelFormat().alpha == 0;
}
if (needAlphaFixup) {
if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
// this is easy; it's an 0xff memset per row
uint8_t *row = static_cast<uint8_t*>(data);
for (GLint j = 0; j < height; ++j) {
memset(row, 0xff, checked_plainRowSize.value());
row += checked_alignedRowSize.value();
}
} else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE) {
// this is harder, we need to just set the alpha byte here
uint8_t *row = static_cast<uint8_t*>(data);
for (GLint j = 0; j < height; ++j) {
uint8_t *rowp = row;
#if MOZ_LITTLE_ENDIAN
// offset to get the alpha byte; we're always going to
// move by 4 bytes
rowp += 3;
#endif
uint8_t *endrowp = rowp + 4 * width;
while (rowp != endrowp) {
*rowp = 0xff;
rowp += 4;
}
const bool formatHasAlpha = format == LOCAL_GL_ALPHA ||
format == LOCAL_GL_RGBA;
if (!formatHasAlpha)
return;
row += checked_alignedRowSize.value();
}
} else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_FLOAT) {
float* row = static_cast<float*>(data);
bool needAlphaFilled;
if (mBoundFramebuffer) {
needAlphaFilled = !mBoundFramebuffer->ColorAttachment(0).HasAlpha();
} else {
needAlphaFilled = !mOptions.alpha;
}
for (GLint j = 0; j < height; ++j) {
float* pAlpha = row + 3;
float* pAlphaEnd = pAlpha + 4*width;
if (!needAlphaFilled)
return;
while (pAlpha != pAlphaEnd) {
*pAlpha = 1.0f;
pAlpha += 4;
}
row += checked_alignedRowSize.value();
}
} else {
NS_WARNING("Unhandled case, how'd we get here?");
return rv.Throw(NS_ERROR_FAILURE);
}
}
size_t stride = checked_alignedRowSize.value(); // In bytes!
if (!SetFullAlpha(data, format, type, width, height, stride)) {
return rv.Throw(NS_ERROR_FAILURE);
}
}

Просмотреть файл

@ -312,12 +312,18 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
case LOCAL_GL_RED_BITS:
case LOCAL_GL_GREEN_BITS:
case LOCAL_GL_BLUE_BITS:
case LOCAL_GL_ALPHA_BITS:
case LOCAL_GL_DEPTH_BITS: {
GLint i = 0;
gl->fGetIntegerv(pname, &i);
return JS::Int32Value(i);
}
case LOCAL_GL_ALPHA_BITS: {
GLint i = 0;
if (!mNeedsFakeNoAlpha) {
gl->fGetIntegerv(pname, &i);
}
return JS::Int32Value(i);
}
case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT: {
if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
GLint i = 0;

Просмотреть файл

@ -1100,7 +1100,7 @@ WebGLContext::ValidateCopyTexImage(GLenum format,
MOZ_ASSERT(IsCopyFunc(func));
// Default framebuffer format
GLenum fboFormat = bool(gl->GetPixelFormat().alpha > 0) ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
GLenum fboFormat = mOptions.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {

Просмотреть файл

@ -54,8 +54,9 @@ if (!window.todo) {
}
if (!window.SimpleTest) {
window.SimpleTest = {
waitForExplicitFinish: function(){},
finish: function(){},
requestLongerTimeout: function(){},
waitForExplicitFinish: function(){},
};
}
@ -243,6 +244,13 @@ function OnTestComplete() {
SimpleTest.waitForExplicitFinish();
var isAndroid2_3 = (DriverInfo.getOS() == DriverInfo.OS.ANDROID &&
DriverInfo.getOSVersion() < OS_VERSION_ANDROID_ICS);
if (isAndroid2_3) {
var timeoutLengthMultiplier = 2.0;
SimpleTest.requestLongerTimeout(timeoutLengthMultiplier);
}
do {
var arg = location.search.substr(1);
if (arg == 'dump') {

Просмотреть файл

@ -1792,7 +1792,11 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
if (!window) {
return nullptr;
}
#ifdef MOZ_EME
if (ContainsRestrictedContent()) {
return nullptr;
}
#endif
OutputMediaStream* out = mOutputStreams.AppendElement();
#ifdef DEBUG
// Estimate hints based on the type of the media element
@ -3997,10 +4001,21 @@ HTMLMediaElement::GetMediaKeys() const
return mMediaKeys;
}
bool
HTMLMediaElement::ContainsRestrictedContent()
{
return GetMediaKeys() != nullptr;
}
already_AddRefed<Promise>
HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
ErrorResult& aRv)
{
if (MozAudioCaptured()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
nsCOMPtr<nsIGlobalObject> global =
do_QueryInterface(OwnerDoc()->GetInnerWindow());
if (!global) {
@ -4035,6 +4050,8 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
if (mDecoder) {
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
}
// Update the same-origin status.
NotifyDecoderPrincipalChanged();
}
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();

Просмотреть файл

@ -550,6 +550,7 @@ public:
// in the URL bar of the browser window.
already_AddRefed<nsIPrincipal> GetTopLevelPrincipal();
bool ContainsRestrictedContent();
#endif // MOZ_EME
bool MozAutoplayEnabled() const

Просмотреть файл

@ -1411,6 +1411,13 @@ ContentParent::ShutDownProcess(bool aCloseWithError)
// sequence.
mCalledClose = true;
Close();
#ifdef MOZ_NUWA_PROCESS
// Kill Nuwa process forcibly to break its IPC channels and finalize
// corresponding parents.
if (IsNuwaProcess()) {
KillHard();
}
#endif
}
if (aCloseWithError && !mCalledCloseWithError) {
@ -2931,17 +2938,13 @@ ContentParent::KillHard()
if (!KillProcess(OtherProcess(), 1, false)) {
NS_WARNING("failed to kill subprocess!");
}
mSubprocess->SetAlreadyDead();
if (mSubprocess) {
mSubprocess->SetAlreadyDead();
}
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(&ProcessWatcher::EnsureProcessTerminated,
OtherProcess(), /*force=*/true));
//We do clean-up here
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
NewRunnableMethod(this, &ContentParent::ShutDownProcess,
/* closeWithError */ true),
3000);
// We've now closed the OtherProcess() handle, so must set it to null to
// prevent our dtor closing it twice.
SetOtherProcess(0);

Просмотреть файл

@ -165,7 +165,7 @@ static_assert(QUICK_BUFFERING_LOW_DATA_USECS <= AMPLE_AUDIO_USECS,
static const int64_t ESTIMATED_DURATION_FUZZ_FACTOR_USECS = USECS_PER_S / 2;
static TimeDuration UsecsToDuration(int64_t aUsecs) {
return TimeDuration::FromMilliseconds(static_cast<double>(aUsecs) / USECS_PER_MS);
return TimeDuration::FromMicroseconds(aUsecs);
}
static int64_t DurationToUsecs(TimeDuration aDuration) {
@ -2569,6 +2569,7 @@ void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
if (container) {
container->SetCurrentFrame(ThebesIntSize(aData->mDisplay), aData->mImage,
aTarget);
MOZ_ASSERT(container->GetFrameDelay() >= 0 || mScheduler->IsRealTime());
}
}
@ -2655,6 +2656,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
}
int64_t clock_time = GetClock();
TimeStamp nowTime = TimeStamp::Now();
// Skip frames up to the frame at the playback position, and figure out
// the time remaining until it's time to display the next frame.
int64_t remainingTime = AUDIO_DURATION_USECS;
@ -2721,8 +2723,8 @@ void MediaDecoderStateMachine::AdvanceFrame()
if (currentFrame) {
// Decode one frame and display it.
TimeStamp presTime = mPlayStartTime - UsecsToDuration(mPlayDuration) +
UsecsToDuration(currentFrame->mTime - mStartTime);
int64_t delta = currentFrame->mTime - clock_time;
TimeStamp presTime = nowTime + TimeDuration::FromMicroseconds(delta / mPlaybackRate);
NS_ASSERTION(currentFrame->mTime >= mStartTime, "Should have positive frame time");
// Filter out invalid frames by checking the frame time. FrameTime could be
// zero if it's a initial frame.
@ -2768,7 +2770,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
// ready state. Post an update to do so.
UpdateReadyState();
ScheduleStateMachine(remainingTime);
ScheduleStateMachine(remainingTime / mPlaybackRate);
}
nsresult

Просмотреть файл

@ -38,7 +38,7 @@ AppleATDecoder::AppleATDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
, mFlushed(false)
{
MOZ_COUNT_CTOR(AppleATDecoder);
LOG("Creating Apple AudioToolbox Audio decoder");
LOG("Creating Apple AudioToolbox decoder");
LOG("Audio Decoder configuration: %s %d Hz %d channels %d bits per channel",
mConfig.mime_type,
mConfig.samples_per_second,
@ -92,7 +92,7 @@ AppleATDecoder::Init()
NS_ERROR("Non recognised format");
return NS_ERROR_FAILURE;
}
LOG("Initializing Apple AudioToolbox Audio decoder");
LOG("Initializing Apple AudioToolbox decoder");
OSStatus rv = AudioFileStreamOpen(this,
_MetadataCallback,
_SampleCallback,
@ -315,10 +315,10 @@ AppleATDecoder::SampleCallback(uint32_t aNumBytes,
void
AppleATDecoder::SetupDecoder()
{
AudioStreamBasicDescription inputFormat;
LOG("Setting up Apple AudioToolbox decoder.");
mHaveOutput = false;
AudioStreamBasicDescription inputFormat;
nsresult rv = AppleUtils::GetRichestDecodableFormat(mStream, inputFormat);
if (NS_FAILED(rv)) {
mCallback->Error();

Просмотреть файл

@ -1201,7 +1201,10 @@ GeckoMediaPluginService::ClearStorage()
return;
}
if (NS_FAILED(path->Remove(true))) {
bool exists = false;
if (NS_SUCCEEDED(path->Exists(&exists)) &&
exists &&
NS_FAILED(path->Remove(true))) {
NS_WARNING("Failed to delete GMP storage directory");
}
NS_DispatchToMainThread(new StorageClearedTask(), NS_DISPATCH_NORMAL);

Просмотреть файл

@ -84,6 +84,18 @@ public:
mTaskQueue = aTaskQueue;
}
void BreakCycles()
{
if (mReader) {
mReader->BreakCycles();
mReader = nullptr;
}
mTaskQueue = nullptr;
#ifdef MOZ_EME
mCDMProxy = nullptr;
#endif
}
#ifdef MOZ_EME
virtual nsresult SetCDMProxy(CDMProxy* aProxy)
{

Просмотреть файл

@ -391,7 +391,7 @@ TrackBuffer::BreakCycles()
MOZ_ASSERT(NS_IsMainThread());
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
mDecoders[i]->GetReader()->BreakCycles();
mDecoders[i]->BreakCycles();
}
mDecoders.Clear();

178
dom/media/test/eme.js Normal file
Просмотреть файл

@ -0,0 +1,178 @@
const KEYSYSTEM_TYPE = "org.w3.clearkey";
function bail(message)
{
return function(err) {
ok(false, message);
if (err) {
info(err);
}
SimpleTest.finish();
}
}
function ArrayBufferToString(arr)
{
var str = '';
var view = new Uint8Array(arr);
for (var i = 0; i < view.length; i++) {
str += String.fromCharCode(view[i]);
}
return str;
}
function StringToArrayBuffer(str)
{
var arr = new ArrayBuffer(str.length);
var view = new Uint8Array(arr);
for (var i = 0; i < str.length; i++) {
view[i] = str.charCodeAt(i);
}
return arr;
}
function Base64ToHex(str)
{
var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
var res = "";
for (var i = 0; i < bin.length; i++) {
res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
}
return res;
}
function HexToBase64(hex)
{
var bin = "";
for (var i = 0; i < hex.length; i += 2) {
bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
}
return window.btoa(bin).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
}
function UpdateSessionFunc(test) {
return function(ev) {
var msgStr = ArrayBufferToString(ev.message);
var msg = JSON.parse(msgStr);
info("got message from CDM: " + msgStr);
is(msg.type, test.sessionType, "Key session type should match");
ok(msg.kids, "message event should contain key ID array");
var outKeys = [];
for (var i = 0; i < msg.kids.length; i++) {
var id64 = msg.kids[i];
var idHex = Base64ToHex(msg.kids[i]).toLowerCase();
var key = test.keys[idHex];
if (key) {
info("found key " + key + " for key id " + idHex);
outKeys.push({
"kty":"oct",
"alg":"A128KW",
"kid":id64,
"k":HexToBase64(key)
});
} else {
bail("Couldn't find key for key id " + idHex);
}
}
var update = JSON.stringify({
"keys" : outKeys,
"type" : msg.type
});
info("sending update message to CDM: " + update);
ev.target.update(StringToArrayBuffer(update)).then(function() {
info("MediaKeySession update ok!");
}, bail("MediaKeySession update failed"));
}
}
function PlayFragmented(test, elem)
{
return new Promise(function(resolve, reject) {
var ms = new MediaSource();
elem.src = URL.createObjectURL(ms);
var sb;
var curFragment = 0;
function addNextFragment() {
if (curFragment >= test.fragments.length) {
ms.endOfStream();
resolve();
return;
}
var fragmentFile = test.fragments[curFragment++];
var req = new XMLHttpRequest();
req.open("GET", fragmentFile);
req.responseType = "arraybuffer";
req.addEventListener("load", function() {
sb.appendBuffer(new Uint8Array(req.response));
});
info("fetching resource " + fragmentFile);
req.send(null);
}
ms.addEventListener("sourceopen", function () {
sb = ms.addSourceBuffer(test.type);
sb.addEventListener("updateend", addNextFragment);
addNextFragment();
})
});
}
// Returns a promise that is resovled when the media element is ready to have
// its play() function called; when it's loaded MSE fragments, or once the load
// has started for non-MSE video.
function LoadTest(test, elem)
{
if (test.fragments) {
return PlayFragmented(test, elem);
}
// This file isn't fragmented; set the media source normally.
return new Promise(function(resolve, reject) {
elem.src = test.name;
resolve();
});
}
function SetupEME(test, token, params)
{
var v = document.createElement("video");
var onSetKeysFail = (params && params.onSetKeysFail)
? params.onSetKeysFail
: bail(token + " Failed to set MediaKeys on <video> element");
v.addEventListener("encrypted", function(ev) {
info(token + " got encrypted event");
MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
info(token + " created MediaKeys object ok");
mediaKeys.sessions = [];
return v.setMediaKeys(mediaKeys);
}, bail("failed to create MediaKeys object")).then(function() {
info(token + " set MediaKeys on <video> element ok");
var session = v.mediaKeys.createSession(test.sessionType);
if (params && params.onsessioncreated) {
params.onsessioncreated(session);
}
session.addEventListener("message", UpdateSessionFunc(test));
session.generateRequest(ev.initDataType, ev.initData).then(function() {
}, bail(token + " Failed to initialise MediaKeySession"));
}, onSetKeysFail);
});
return v;
}

Просмотреть файл

@ -140,6 +140,7 @@ support-files =
dirac.ogg^headers^
dynamic_redirect.sjs
dynamic_resource.sjs
eme.js
gizmo-frag-cenc1.m4s
gizmo-frag-cenc2.m4s
gizmo-frag-cencinit.mp4
@ -360,7 +361,11 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
[test_defaultMuted.html]
[test_delay_load.html]
skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984
[test_encryptedMediaExtensions.html]
[test_eme_canvas_blocked.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_playback.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_stream_capture_blocked.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_error_in_video_document.html]
skip-if = toolkit == 'android' # bug 608634

Просмотреть файл

@ -0,0 +1,67 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test Encrypted Media Extensions</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="eme.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var manager = new MediaTestManager;
function startTest(test, token)
{
manager.started(token);
var sessions = [];
var v = SetupEME(test, token);
v.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
v.addEventListener("canplay", function(ev) {
var video = ev.target;
var canvas = document.createElement("canvas");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");
var threwError = false;
try {
ctx.drawImage(video, 0, 0);
} catch (ex) {
threwError = true;
}
ok(threwError, token + " - Should throw an error when trying to draw EME video to canvas.");
manager.finished(token);
});
v.addEventListener("error", bail(token + " got error event"));
LoadTest(test, v);
}
function beginTest() {
manager.runTests(gEMETests, startTest);
}
var prefs = [
[ "media.mediasource.enabled", true ],
[ "media.mediasource.ignore_codecs", true ],
];
if (/Linux/.test(navigator.userAgent) ||
!document.createElement('video').canPlayType("video/mp4")) {
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
prefs.push([ "media.fragmented-mp4.exposed", true ]);
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,128 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test Encrypted Media Extensions</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="eme.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var manager = new MediaTestManager;
function KeysChangeFunc(session, keys, token) {
session.keyIdsReceived = [];
for (var keyid in keys) {
info("Set " + keyid + " to false in session.keyIdsReceived");
session.keyIdsReceived[keyid] = false;
}
return function(ev) {
var session = ev.target;
session.gotKeysChanged = true;
session.getUsableKeyIds().then(function(keyIds) {
for (var k = 0; k < keyIds.length; k++) {
var kid = Base64ToHex(window.btoa(ArrayBufferToString(keyIds[k])));
ok(kid in session.keyIdsReceived, token + " session.keyIdsReceived contained " + kid + " as expected.");
session.keyIdsReceived[kid] = true;
}
}, bail("Failed to get keyIds"));
}
}
function startTest(test, token)
{
manager.started(token);
var sessions = [];
var v = SetupEME(test, token,
{
onsessioncreated: function(session) {
sessions.push(session);
session.addEventListener("keyschange", KeysChangeFunc(session, test.keys, token), false);
}
}
);
var gotEncrypted = false;
var gotPlaying = false;
v.addEventListener("encrypted", function(ev) {
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
token + " MediaKeys should support this keysystem");
gotEncrypted = true;
});
v.addEventListener("playing", function () { gotPlaying = true; });
v.addEventListener("ended", function(ev) {
ok(true, token + " got ended event");
manager.finished(token);
ok(gotEncrypted, token + " encrypted event should have fired");
ok(gotPlaying, token + " playing event should have fired");
ok(Math.abs(test.duration - v.duration) < 0.1,
token + " Duration of video should be corrrect");
ok(Math.abs(test.duration - v.currentTime) < 0.1,
token + " Current time should be same as duration");
// Verify all sessions had all keys went sent the to the CDM usable, and thus
// that we received keyschange event(s).
is(sessions.length, 1, "should have 1 session");
for (var i = 0; i < sessions.length; i++) {
var session = sessions[i];
ok(session.gotKeysChanged, token + " should have received at least one keychange event");
for (var kid in session.keyIdsReceived) {
ok(session.keyIdsReceived[kid], token + " key with id " + kid + " was usable as expected");
}
}
});
v.addEventListener("error", bail(token + " got error event"));
LoadTest(test, v).then(function(){v.play();}, bail(token + " failed to load"));
}
function testIsTypeSupported()
{
var t = MediaKeys.isTypeSupported;
const clearkey = "org.w3.clearkey";
ok(!t("bogus", "bogon", "video/bogus"), "Invalid type.");
ok(t(clearkey), "ClearKey supported.");
ok(!t(clearkey, "bogus"), "ClearKey bogus initDataType not supported.");
ok(t(clearkey, "cenc"), "ClearKey/cenc should be supported.");
ok(!t(clearkey, "cenc", "bogus"), "ClearKey/cenc bogus content type should be supported.");
ok(t(clearkey, "cenc", 'video/mp4'), "ClearKey/cenc video/mp4 supported.");
ok(t(clearkey, "cenc", 'video/mp4; codecs="avc1.4d4015,mp4a.40.2"'), "ClearKey/cenc H.264/AAC supported.");
ok(t(clearkey, "cenc", 'audio/mp4'), "ClearKey/cenc audio/mp4 supported.");
ok(t(clearkey, "cenc", 'audio/mp4; codecs="mp4a.40.2"'), "ClearKey/cenc AAC LC supported.");
}
function beginTest() {
testIsTypeSupported();
manager.runTests(gEMETests, startTest);
}
var prefs = [
[ "media.mediasource.enabled", true ],
[ "media.mediasource.ignore_codecs", true ],
];
if (/Linux/.test(navigator.userAgent) ||
!document.createElement('video').canPlayType("video/mp4")) {
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
prefs.push([ "media.fragmented-mp4.exposed", true ]);
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,102 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test Encrypted Media Extensions</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="eme.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var manager = new MediaTestManager;
function startTest(test, token)
{
// Three cases:
// 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
// 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
// 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
// Case 1. setting MediaKeys on an element captured by MediaElementSource should fail.
var case1token = token + "_case1";
var setKeysFailed = function() {
ok(true, case1token + " setMediaKeys failed as expected.");
manager.finished(case1token);
};
var v1 = SetupEME(test, case1token, { onSetKeysFail: setKeysFailed });
var context = new AudioContext();
var node = context.createMediaElementSource(v1);
v1.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
v1.addEventListener("error", bail(case1token + " got error event"));
v1.addEventListener("canplay", function(ev) {
ok(false, case1token + " should never reach canplay, as setMediaKeys should fail");
});
manager.started(case1token);
LoadTest(test, v1);
// Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail.
var case2token = token + "_case2";
var v2 = SetupEME(test, case2token);
v2.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
v2.addEventListener("error", bail(case2token + " got error event"));
v2.addEventListener("canplay", function(ev) {
ok(true, case2token + " should reach canplay");
var threw = false;
try {
var context = new AudioContext();
var node = context.createMediaElementSource(v2);
} catch (e) {
threw = true;
}
ok(threw, "Should throw an error creating a MediaElementSource on an EME video.");
manager.finished(case2token);
});
manager.started(case2token);
LoadTest(test, v2);
// Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
var case3token = token + "_case3";
var v3 = SetupEME(test, case3token);
v3.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
v3.addEventListener("error", bail(case3token + " got error event"));
v3.addEventListener("canplay", function(ev) {
ok(true, case3token + " should reach canplay");
var threw = false;
try {
var stream = v3.mozCaptureStreamUntilEnded();
} catch (e) {
threw = true;
}
ok(threw, "Should throw an error calling mozCaptureStreamUntilEnded an EME video.");
manager.finished(case3token);
});
manager.started(case3token);
LoadTest(test, v3);
}
function beginTest() {
manager.runTests(gEMETests, startTest);
}
var prefs = [
[ "media.mediasource.enabled", true ],
[ "media.mediasource.ignore_codecs", true ],
];
if (/Linux/.test(navigator.userAgent) ||
!document.createElement('video').canPlayType("video/mp4")) {
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
prefs.push([ "media.fragmented-mp4.exposed", true ]);
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,278 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test Encrypted Media Extensions</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var manager = new MediaTestManager;
const KEYSYSTEM_TYPE = "org.w3.clearkey";
function bail(message)
{
return function(err) {
ok(false, message);
if (err) {
info(err);
}
SimpleTest.finish();
}
}
function ArrayBufferToString(arr)
{
var str = '';
var view = new Uint8Array(arr);
for (var i = 0; i < view.length; i++) {
str += String.fromCharCode(view[i]);
}
return str;
}
function StringToArrayBuffer(str)
{
var arr = new ArrayBuffer(str.length);
var view = new Uint8Array(arr);
for (var i = 0; i < str.length; i++) {
view[i] = str.charCodeAt(i);
}
return arr;
}
function Base64ToHex(str)
{
var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
var res = "";
for (var i = 0; i < bin.length; i++) {
res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
}
return res;
}
function HexToBase64(hex)
{
var bin = "";
for (var i = 0; i < hex.length; i += 2) {
bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
}
return window.btoa(bin).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
}
function UpdateSessionFunc(test) {
return function(ev) {
var msgStr = ArrayBufferToString(ev.message);
var msg = JSON.parse(msgStr);
info("got message from CDM: " + msgStr);
is(msg.type, test.sessionType, "Key session type should match");
ok(msg.kids, "message event should contain key ID array");
var outKeys = [];
for (var i = 0; i < msg.kids.length; i++) {
var id64 = msg.kids[i];
var idHex = Base64ToHex(msg.kids[i]).toLowerCase();
var key = test.keys[idHex];
if (key) {
info("found key " + key + " for key id " + idHex);
outKeys.push({
"kty":"oct",
"alg":"A128KW",
"kid":id64,
"k":HexToBase64(key)
});
} else {
bail("Couldn't find key for key id " + idHex);
}
}
var update = JSON.stringify({
"keys" : outKeys,
"type" : msg.type
});
info("sending update message to CDM: " + update);
ev.target.update(StringToArrayBuffer(update)).then(function() {
info("MediaKeySession update ok!");
}, bail("MediaKeySession update failed"));
}
}
function PlayFragmented(test, elem)
{
var ms = new MediaSource();
elem.src = URL.createObjectURL(ms);
var sb;
var curFragment = 0;
function addNextFragment() {
if (curFragment >= test.fragments.length) {
ms.endOfStream();
elem.play();
return;
}
var fragmentFile = test.fragments[curFragment++];
var req = new XMLHttpRequest();
req.open("GET", fragmentFile);
req.responseType = "arraybuffer";
req.addEventListener("load", function() {
sb.appendBuffer(new Uint8Array(req.response));
});
info("fetching resource " + fragmentFile);
req.send(null);
}
ms.addEventListener("sourceopen", function () {
sb = ms.addSourceBuffer(test.type);
sb.addEventListener("updateend", addNextFragment);
addNextFragment();
});
}
function PlayTest(test, elem)
{
if (test.fragments) {
PlayFragmented(test, elem);
return;
}
// This file isn't fragmented; set the media source normally.
elem.src = test.name;
elem.play();
}
function KeysChangeFunc(session, keys) {
session.keyIdsReceived = [];
for (var keyid in keys) {
info("Set " + keyid + " to false in session.keyIdsReceived");
session.keyIdsReceived[keyid] = false;
}
return function(ev) {
var session = ev.target;
session.gotKeysChanged = true;
session.getUsableKeyIds().then(function(keyIds) {
for (var k = 0; k < keyIds.length; k++) {
var kid = Base64ToHex(window.btoa(ArrayBufferToString(keyIds[k])));
ok(kid in session.keyIdsReceived, "session.keyIdsReceived contained " + kid + " as expected.");
session.keyIdsReceived[kid] = true;
}
}, bail("Failed to get keyIds"));
}
}
function startTest(test, token)
{
manager.started(test._token);
var v = document.createElement("video");
var gotEncrypted = false;
var gotPlaying = false;
v.addEventListener("encrypted", function(ev) {
gotEncrypted = true;
info(token + " got encrypted event");
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
token + " MediaKeys should support this keysystem");
MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
info(token + " created MediaKeys object ok");
mediaKeys.sessions = [];
return v.setMediaKeys(mediaKeys);
}, bail("failed to create MediaKeys object")).then(function() {
info(token + " set MediaKeys on <video> element ok");
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
"MediaKeys should still support keysystem after CDM created...");
var session = v.mediaKeys.createSession(test.sessionType);
v.mediaKeys.sessions.push(session);
session.addEventListener("keyschange", KeysChangeFunc(session, test.keys), false);
session.addEventListener("message", UpdateSessionFunc(test));
session.generateRequest(ev.initDataType, ev.initData).then(function() {
}, bail(token + " Failed to initialise MediaKeySession"));
}, bail(token + " Failed to set MediaKeys on <video> element"));
});
v.addEventListener("playing", function () { gotPlaying = true; });
v.addEventListener("ended", function(ev) {
ok(true, token + " got ended event");
manager.finished(test._token);
ok(gotEncrypted, token + " encrypted event should have fired");
ok(gotPlaying, token + " playing event should have fired");
ok(Math.abs(test.duration - v.duration) < 0.1,
token + " Duration of video should be corrrect");
ok(Math.abs(test.duration - v.currentTime) < 0.1,
token + " Current time should be same as duration");
// Verify all sessions had all keys went sent the to the CDM usable, and thus
// that we received keyschange event(s).
var sessions = v.mediaKeys.sessions;
is(sessions.length, 1, "should have 1 session");
for (var i = 0; i < sessions.length; i++) {
var session = sessions[i];
ok(session.gotKeysChanged, "Should have received at least one keychange event");
for (var kid in session.keyIdsReceived) {
ok(session.keyIdsReceived[kid], "key with id " + kid + " was usable as expected");
}
}
});
v.addEventListener("error", bail(token + " got error event"));
PlayTest(test, v);
}
function testIsTypeSupported()
{
var t = MediaKeys.isTypeSupported;
const clearkey = "org.w3.clearkey";
ok(!t("bogus", "bogon", "video/bogus"), "Invalid type.");
ok(t(clearkey), "ClearKey supported.");
ok(!t(clearkey, "bogus"), "ClearKey bogus initDataType not supported.");
ok(t(clearkey, "cenc"), "ClearKey/cenc should be supported.");
ok(!t(clearkey, "cenc", "bogus"), "ClearKey/cenc bogus content type should be supported.");
ok(t(clearkey, "cenc", 'video/mp4'), "ClearKey/cenc video/mp4 supported.");
ok(t(clearkey, "cenc", 'video/mp4; codecs="avc1.4d4015,mp4a.40.2"'), "ClearKey/cenc H.264/AAC supported.");
ok(t(clearkey, "cenc", 'audio/mp4'), "ClearKey/cenc audio/mp4 supported.");
ok(t(clearkey, "cenc", 'audio/mp4; codecs="mp4a.40.2"'), "ClearKey/cenc AAC LC supported.");
}
function beginTest() {
testIsTypeSupported();
manager.runTests(gEMETests, startTest);
}
var prefs = [
[ "media.mediasource.enabled", true ],
[ "media.mediasource.ignore_codecs", true ],
];
if (/Linux/.test(navigator.userAgent) ||
!document.createElement('video').canPlayType("video/mp4")) {
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
prefs.push([ "media.fragmented-mp4.exposed", true ]);
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1303,6 +1303,8 @@ DataChannelTest.prototype = Object.create(PeerConnectionTest.prototype, {
is(channel.readyState, "open", peer + " dataChannels[0] switched to state: 'open'");
dcOpened = true;
onSuccess();
} else {
info("dataChannelConnected() called, but data channel was open already");
}
}
@ -2606,11 +2608,12 @@ PeerConnectionWrapper.prototype = {
* Callback to execute when the data channel has been opened
*/
registerDataChannelOpenEvents : function (onDataChannelOpened) {
info(this + ": Register callbacks for 'ondatachannel' and 'onopen'");
info(this + ": Register callback for 'ondatachannel'");
this.ondatachannel = function (targetChannel) {
targetChannel.onopen = onDataChannelOpened;
this.dataChannels.push(targetChannel);
info(this + ": 'ondatachannel' fired, registering 'onopen' callback");
targetChannel.onopen = onDataChannelOpened;
};
},

Просмотреть файл

@ -285,6 +285,12 @@ AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement,
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
#ifdef MOZ_EME
if (aMediaElement.ContainsRestrictedContent()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
#endif
nsRefPtr<DOMMediaStream> stream = aMediaElement.MozCaptureStream(aRv);
if (aRv.Failed()) {
return nullptr;

Просмотреть файл

@ -591,7 +591,8 @@ bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint le
case GL_RGBA:
if (colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_RGBA8_OES)
colorbufferFormat != GL_RGBA8_OES &&
colorbufferFormat != GL_BGRA8_EXT)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;

Просмотреть файл

@ -5187,8 +5187,6 @@
#define LOCAL_EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133
#define LOCAL_EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131
#define LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
#define LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2)
#define LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3)
#define LOCAL_EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
#define LOCAL_EGL_DEPTH_ENCODING_NONE_NV 0
#define LOCAL_EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3

Просмотреть файл

@ -1812,6 +1812,15 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
}
}
if (WorkAroundDriverBugs() &&
IsANGLE() &&
formats.color_rbFormat == LOCAL_GL_RGBA8)
{
formats.color_texInternalFormat = LOCAL_GL_BGRA;
formats.color_texFormat = LOCAL_GL_BGRA;
formats.color_rbFormat = LOCAL_GL_BGRA8_EXT;
}
uint32_t msaaLevel = gfxPrefs::MSAALevel();
GLsizei samples = msaaLevel * msaaLevel;
samples = std::min(samples, mMaxSamples);

Просмотреть файл

@ -55,4 +55,8 @@
#define LOCAL_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
#define LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2)
#define LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3)
#endif

Просмотреть файл

@ -99,6 +99,19 @@ LoadLibraryForEGLOnWindows(const nsAString& filename)
}
#endif // XP_WIN
static EGLDisplay
GetAndInitDisplay(GLLibraryEGL& egl, void* displayType)
{
EGLDisplay display = egl.fGetDisplay(displayType);
if (display == EGL_NO_DISPLAY)
return EGL_NO_DISPLAY;
if (!egl.fInitialize(display, nullptr, nullptr))
return EGL_NO_DISPLAY;
return display;
}
bool
GLLibraryEGL::EnsureInitialized()
{
@ -185,6 +198,7 @@ GLLibraryEGL::EnsureInitialized()
GLLibraryLoader::SymLoadStruct earlySymbols[] = {
SYMBOL(GetDisplay),
SYMBOL(Terminate),
SYMBOL(GetCurrentSurface),
SYMBOL(GetCurrentContext),
SYMBOL(MakeCurrent),
@ -232,37 +246,43 @@ GLLibraryEGL::EnsureInitialized()
"Couldn't find eglQueryStringImplementationANDROID");
#endif
mEGLDisplay = nullptr;
mEGLDisplay = GetAndInitDisplay(*this, EGL_DEFAULT_DISPLAY);
#ifdef XP_WIN
// XXX we have no way of knowing if this is ANGLE, or if we're just using
// a native EGL on windows. We don't really do the latter right now, so
// let's assume it is ANGLE, and try our special types.
// D3D11 ANGLE only works with OMTC; there's a bug in the non-OMTC layer
// manager, and it's pointless to try to fix it. We also don't try D3D11
// ANGLE if the layer manager is prefering D3D9 (hrm, do we care?)
if (gfxPrefs::LayersOffMainThreadCompositionEnabled() &&
!gfxPrefs::LayersPreferD3D9())
const char* vendor = (char*)fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR);
if (vendor && (strstr(vendor, "TransGaming") != 0 ||
strstr(vendor, "Google Inc.") != 0))
{
if (gfxPrefs::WebGLANGLEForceD3D11()) {
mEGLDisplay = fGetDisplay(LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
} else if (gfxPrefs::WebGLANGLETryD3D11()) {
mEGLDisplay = fGetDisplay(LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE);
}
}
#endif
if (!mEGLDisplay)
mEGLDisplay = fGetDisplay(EGL_DEFAULT_DISPLAY);
if (!fInitialize(mEGLDisplay, nullptr, nullptr))
return false;
const char *vendor = (const char*) fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR);
if (vendor && (strstr(vendor, "TransGaming") != 0 || strstr(vendor, "Google Inc.") != 0)) {
mIsANGLE = true;
}
if (mIsANGLE) {
EGLDisplay newDisplay = EGL_NO_DISPLAY;
// D3D11 ANGLE only works with OMTC; there's a bug in the non-OMTC layer
// manager, and it's pointless to try to fix it. We also don't try
// D3D11 ANGLE if the layer manager is prefering D3D9 (hrm, do we care?)
if (gfxPrefs::LayersOffMainThreadCompositionEnabled() &&
!gfxPrefs::LayersPreferD3D9())
{
if (gfxPrefs::WebGLANGLEForceD3D11()) {
newDisplay = GetAndInitDisplay(*this,
LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
} else if (gfxPrefs::WebGLANGLETryD3D11()) {
newDisplay = GetAndInitDisplay(*this,
LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE);
}
}
if (newDisplay != EGL_NO_DISPLAY) {
DebugOnly<EGLBoolean> success = fTerminate(mEGLDisplay);
MOZ_ASSERT(success == LOCAL_EGL_TRUE);
mEGLDisplay = newDisplay;
vendor = (char*)fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR);
}
}
InitExtensions();
GLLibraryLoader::PlatformLookupFunction lookupFunction =

Просмотреть файл

@ -104,7 +104,7 @@ namespace gl {
class GLLibraryEGL
{
public:
GLLibraryEGL()
GLLibraryEGL()
: mInitialized(false),
mEGLLibrary(nullptr),
mIsANGLE(false)
@ -154,6 +154,14 @@ public:
return disp;
}
EGLBoolean fTerminate(EGLDisplay display)
{
BEFORE_GL_CALL;
EGLBoolean ret = mSymbols.fTerminate(display);
AFTER_GL_CALL;
return ret;
}
EGLSurface fGetCurrentSurface(EGLint id)
{
BEFORE_GL_CALL;
@ -469,6 +477,8 @@ public:
struct {
typedef EGLDisplay (GLAPIENTRY * pfnGetDisplay)(void *display_id);
pfnGetDisplay fGetDisplay;
typedef EGLBoolean (GLAPIENTRY * pfnTerminate)(EGLDisplay dpy);
pfnTerminate fTerminate;
typedef EGLSurface (GLAPIENTRY * pfnGetCurrentSurface)(EGLint);
pfnGetCurrentSurface fGetCurrentSurface;
typedef EGLContext (GLAPIENTRY * pfnGetCurrentContext)(void);

Просмотреть файл

@ -289,7 +289,9 @@ ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps)
EGLConfig config = EGL_NO_CONFIG;
for (int i = 0; i < foundConfigs; i++) {
EGLConfig cur = configs[i];
if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
caps.alpha) ||
!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
caps.depth) ||
!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE,
caps.stencil))
@ -297,16 +299,6 @@ ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps)
continue;
}
// We can't enforce alpha on ANGLE yet because of:
// https://code.google.com/p/angleproject/issues/detail?id=764
if (!gl->IsANGLE()) {
if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
caps.alpha))
{
continue;
}
}
config = cur;
break;
}

Просмотреть файл

@ -48,6 +48,8 @@ SharedSurface_Basic::Create(GLContext* gl,
break;
case LOCAL_GL_RGBA:
case LOCAL_GL_RGBA8:
case LOCAL_GL_BGRA:
case LOCAL_GL_BGRA8_EXT:
format = SurfaceFormat::B8G8R8A8;
break;
default:

Просмотреть файл

@ -193,5 +193,175 @@ Compositor::DrawDiagnosticsInternal(DiagnosticFlags aFlags,
aTransform);
}
} // namespace
} // namespace
static float
WrapTexCoord(float v)
{
// fmodf gives negative results for negative numbers;
// that is, fmodf(0.75, 1.0) == 0.75, but
// fmodf(-0.75, 1.0) == -0.75. For the negative case,
// the result we need is 0.25, so we add 1.0f.
if (v < 0.0f) {
return 1.0f + fmodf(v, 1.0f);
}
return fmodf(v, 1.0f);
}
static void
SetRects(size_t n,
decomposedRectArrayT* aLayerRects,
decomposedRectArrayT* aTextureRects,
float x0, float y0, float x1, float y1,
float tx0, float ty0, float tx1, float ty1,
bool flip_y)
{
if (flip_y) {
std::swap(ty0, ty1);
}
(*aLayerRects)[n] = gfx::Rect(x0, y0, x1 - x0, y1 - y0);
(*aTextureRects)[n] = gfx::Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
}
#ifdef DEBUG
static inline bool
FuzzyEqual(float a, float b)
{
return fabs(a - b) < 0.0001f;
}
static inline bool
FuzzyLTE(float a, float b)
{
return a <= b + 0.0001f;
}
#endif
size_t
DecomposeIntoNoRepeatRects(const gfx::Rect& aRect,
const gfx::Rect& aTexCoordRect,
decomposedRectArrayT* aLayerRects,
decomposedRectArrayT* aTextureRects)
{
gfx::Rect texCoordRect = aTexCoordRect;
// If the texture should be flipped, it will have negative height. Detect that
// here and compensate for it. We will flip each rect as we emit it.
bool flipped = false;
if (texCoordRect.height < 0) {
flipped = true;
texCoordRect.y += texCoordRect.height;
texCoordRect.height = -texCoordRect.height;
}
// Wrap the texture coordinates so they are within [0,1] and cap width/height
// at 1. We rely on this below.
texCoordRect = gfx::Rect(gfx::Point(WrapTexCoord(texCoordRect.x),
WrapTexCoord(texCoordRect.y)),
gfx::Size(std::min(texCoordRect.width, 1.0f),
std::min(texCoordRect.height, 1.0f)));
NS_ASSERTION(texCoordRect.x >= 0.0f && texCoordRect.x <= 1.0f &&
texCoordRect.y >= 0.0f && texCoordRect.y <= 1.0f &&
texCoordRect.width >= 0.0f && texCoordRect.width <= 1.0f &&
texCoordRect.height >= 0.0f && texCoordRect.height <= 1.0f &&
texCoordRect.XMost() >= 0.0f && texCoordRect.XMost() <= 2.0f &&
texCoordRect.YMost() >= 0.0f && texCoordRect.YMost() <= 2.0f,
"We just wrapped the texture coordinates, didn't we?");
// Get the top left and bottom right points of the rectangle. Note that
// tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2].
gfx::Point tl = texCoordRect.TopLeft();
gfx::Point br = texCoordRect.BottomRight();
NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f &&
tl.y >= 0.0f && tl.y <= 1.0f &&
br.x >= tl.x && br.x <= 2.0f &&
br.y >= tl.y && br.y <= 2.0f &&
FuzzyLTE(br.x - tl.x, 1.0f) &&
FuzzyLTE(br.y - tl.y, 1.0f),
"Somehow generated invalid texture coordinates");
// Then check if we wrap in either the x or y axis.
bool xwrap = br.x > 1.0f;
bool ywrap = br.y > 1.0f;
// If xwrap is false, the texture will be sampled from tl.x .. br.x.
// If xwrap is true, then it will be split into tl.x .. 1.0, and
// 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination
// rectangle is also split appropriately, according to the calculated
// xmid/ymid values.
if (!xwrap && !ywrap) {
SetRects(0, aLayerRects, aTextureRects,
aRect.x, aRect.y, aRect.XMost(), aRect.YMost(),
tl.x, tl.y, br.x, br.y,
flipped);
return 1;
}
// If we are dealing with wrapping br.x and br.y are greater than 1.0 so
// wrap them here as well.
br = gfx::Point(xwrap ? WrapTexCoord(br.x) : br.x,
ywrap ? WrapTexCoord(br.y) : br.y);
// If we wrap around along the x axis, we will draw first from
// tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above).
// The same applies for the Y axis. The midpoints we calculate here are
// only valid if we actually wrap around.
GLfloat xmid = aRect.x + (1.0f - tl.x) / texCoordRect.width * aRect.width;
GLfloat ymid = aRect.y + (1.0f - tl.y) / texCoordRect.height * aRect.height;
NS_ASSERTION(!xwrap ||
(xmid > aRect.x &&
xmid < aRect.XMost() &&
FuzzyEqual((xmid - aRect.x) + (aRect.XMost() - xmid), aRect.width)),
"xmid should be within [x,XMost()] and the wrapped rect should have the same width");
NS_ASSERTION(!ywrap ||
(ymid > aRect.y &&
ymid < aRect.YMost() &&
FuzzyEqual((ymid - aRect.y) + (aRect.YMost() - ymid), aRect.height)),
"ymid should be within [y,YMost()] and the wrapped rect should have the same height");
if (!xwrap && ywrap) {
SetRects(0, aLayerRects, aTextureRects,
aRect.x, aRect.y, aRect.XMost(), ymid,
tl.x, tl.y, br.x, 1.0f,
flipped);
SetRects(1, aLayerRects, aTextureRects,
aRect.x, ymid, aRect.XMost(), aRect.YMost(),
tl.x, 0.0f, br.x, br.y,
flipped);
return 2;
}
if (xwrap && !ywrap) {
SetRects(0, aLayerRects, aTextureRects,
aRect.x, aRect.y, xmid, aRect.YMost(),
tl.x, tl.y, 1.0f, br.y,
flipped);
SetRects(1, aLayerRects, aTextureRects,
xmid, aRect.y, aRect.XMost(), aRect.YMost(),
0.0f, tl.y, br.x, br.y,
flipped);
return 2;
}
SetRects(0, aLayerRects, aTextureRects,
aRect.x, aRect.y, xmid, ymid,
tl.x, tl.y, 1.0f, 1.0f,
flipped);
SetRects(1, aLayerRects, aTextureRects,
xmid, aRect.y, aRect.XMost(), ymid,
0.0f, tl.y, br.x, 1.0f,
flipped);
SetRects(2, aLayerRects, aTextureRects,
aRect.x, ymid, xmid, aRect.YMost(),
tl.x, 0.0f, 1.0f, br.y,
flipped);
SetRects(3, aLayerRects, aTextureRects,
xmid, ymid, aRect.XMost(), aRect.YMost(),
0.0f, 0.0f, br.x, br.y,
flipped);
return 4;
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -540,6 +540,13 @@ private:
};
// Returns the number of rects. (Up to 4)
typedef gfx::Rect decomposedRectArrayT[4];
size_t DecomposeIntoNoRepeatRects(const gfx::Rect& aRect,
const gfx::Rect& aTexCoordRect,
decomposedRectArrayT* aLayerRects,
decomposedRectArrayT* aTextureRects);
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -210,7 +210,6 @@ CompositorD3D11::Initialize()
}
CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT);
samplerDesc.AddressU = samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
hr = mDevice->CreateSamplerState(&samplerDesc, byRef(mAttachments->mLinearSamplerState));
if (FAILED(hr)) {
return false;
@ -574,7 +573,6 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
IntPoint origin = mCurrentRT->GetOrigin();
mVSConstants.renderTargetOffset[0] = origin.x;
mVSConstants.renderTargetOffset[1] = origin.y;
mVSConstants.layerQuad = aRect;
mPSConstants.layerOpacity[0] = aOpacity;
@ -627,6 +625,7 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
mContext->VSSetShader(mAttachments->mVSQuadShader[maskType], nullptr, 0);
const Rect* pTexCoordRect = nullptr;
switch (aEffectChain.mPrimaryEffect->mType) {
case EffectTypes::SOLID_COLOR: {
@ -646,7 +645,7 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
TexturedEffect* texturedEffect =
static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
mVSConstants.textureCoords = texturedEffect->mTextureCoords;
pTexCoordRect = &texturedEffect->mTextureCoords;
TextureSourceD3D11* source = texturedEffect->mTexture->AsSourceD3D11();
@ -682,7 +681,7 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
SetSamplerForFilter(Filter::LINEAR);
mVSConstants.textureCoords = ycbcrEffect->mTextureCoords;
pTexCoordRect = &ycbcrEffect->mTextureCoords;
const int Y = 0, Cb = 1, Cr = 2;
TextureSource* source = ycbcrEffect->mTexture;
@ -749,7 +748,8 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
SetSamplerForFilter(effectComponentAlpha->mFilter);
mVSConstants.textureCoords = effectComponentAlpha->mTextureCoords;
pTexCoordRect = &effectComponentAlpha->mTextureCoords;
RefPtr<ID3D11ShaderResourceView> views[2];
HRESULT hr;
@ -774,12 +774,34 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
NS_WARNING("Unknown shader type");
return;
}
if (!UpdateConstantBuffers()) {
NS_WARNING("Failed to update shader constant buffers");
return;
if (pTexCoordRect) {
Rect layerRects[4];
Rect textureRects[4];
size_t rects = DecomposeIntoNoRepeatRects(aRect,
*pTexCoordRect,
&layerRects,
&textureRects);
for (size_t i = 0; i < rects; i++) {
mVSConstants.layerQuad = layerRects[i];
mVSConstants.textureCoords = textureRects[i];
if (!UpdateConstantBuffers()) {
NS_WARNING("Failed to update shader constant buffers");
break;
}
mContext->Draw(4, 0);
}
} else {
mVSConstants.layerQuad = aRect;
if (!UpdateConstantBuffers()) {
NS_WARNING("Failed to update shader constant buffers");
} else {
mContext->Draw(4, 0);
}
}
mContext->Draw(4, 0);
if (restoreBlendMode) {
mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
}
@ -860,7 +882,7 @@ CompositorD3D11::EndFrame()
PaintToTarget();
}
}
mCurrentRT = nullptr;
}

Просмотреть файл

@ -383,171 +383,6 @@ CompositorOGL::Initialize()
return true;
}
static GLfloat
WrapTexCoord(GLfloat v)
{
// fmodf gives negative results for negative numbers;
// that is, fmodf(0.75, 1.0) == 0.75, but
// fmodf(-0.75, 1.0) == -0.75. For the negative case,
// the result we need is 0.25, so we add 1.0f.
if (v < 0.0f) {
return 1.0f + fmodf(v, 1.0f);
}
return fmodf(v, 1.0f);
}
static void
SetRects(int n,
Rect* aLayerRects,
Rect* aTextureRects,
GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
bool flip_y /* = false */)
{
if (flip_y) {
std::swap(ty0, ty1);
}
aLayerRects[n] = Rect(x0, y0, x1 - x0, y1 - y0);
aTextureRects[n] = Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
}
#ifdef DEBUG
static inline bool
FuzzyEqual(float a, float b)
{
return fabs(a - b) < 0.0001f;
}
#endif
static int
DecomposeIntoNoRepeatRects(const Rect& aRect,
const Rect& aTexCoordRect,
Rect* aLayerRects,
Rect* aTextureRects)
{
Rect texCoordRect = aTexCoordRect;
// If the texture should be flipped, it will have negative height. Detect that
// here and compensate for it. We will flip each rect as we emit it.
bool flipped = false;
if (texCoordRect.height < 0) {
flipped = true;
texCoordRect.y += texCoordRect.height;
texCoordRect.height = -texCoordRect.height;
}
// Wrap the texture coordinates so they are within [0,1] and cap width/height
// at 1. We rely on this below.
texCoordRect = Rect(Point(WrapTexCoord(texCoordRect.x),
WrapTexCoord(texCoordRect.y)),
Size(std::min(texCoordRect.width, 1.0f),
std::min(texCoordRect.height, 1.0f)));
NS_ASSERTION(texCoordRect.x >= 0.0f && texCoordRect.x <= 1.0f &&
texCoordRect.y >= 0.0f && texCoordRect.y <= 1.0f &&
texCoordRect.width >= 0.0f && texCoordRect.width <= 1.0f &&
texCoordRect.height >= 0.0f && texCoordRect.height <= 1.0f &&
texCoordRect.XMost() >= 0.0f && texCoordRect.XMost() <= 2.0f &&
texCoordRect.YMost() >= 0.0f && texCoordRect.YMost() <= 2.0f,
"We just wrapped the texture coordinates, didn't we?");
// Get the top left and bottom right points of the rectangle. Note that
// tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2].
Point tl = texCoordRect.TopLeft();
Point br = texCoordRect.BottomRight();
NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f &&
tl.y >= 0.0f && tl.y <= 1.0f &&
br.x >= tl.x && br.x <= 2.0f &&
br.y >= tl.y && br.y <= 2.0f &&
br.x - tl.x <= 1.0f &&
br.y - tl.y <= 1.0f,
"Somehow generated invalid texture coordinates");
// Then check if we wrap in either the x or y axis.
bool xwrap = br.x > 1.0f;
bool ywrap = br.y > 1.0f;
// If xwrap is false, the texture will be sampled from tl.x .. br.x.
// If xwrap is true, then it will be split into tl.x .. 1.0, and
// 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination
// rectangle is also split appropriately, according to the calculated
// xmid/ymid values.
if (!xwrap && !ywrap) {
SetRects(0, aLayerRects, aTextureRects,
aRect.x, aRect.y, aRect.XMost(), aRect.YMost(),
tl.x, tl.y, br.x, br.y,
flipped);
return 1;
}
// If we are dealing with wrapping br.x and br.y are greater than 1.0 so
// wrap them here as well.
br = Point(xwrap ? WrapTexCoord(br.x) : br.x,
ywrap ? WrapTexCoord(br.y) : br.y);
// If we wrap around along the x axis, we will draw first from
// tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above).
// The same applies for the Y axis. The midpoints we calculate here are
// only valid if we actually wrap around.
GLfloat xmid = aRect.x + (1.0f - tl.x) / texCoordRect.width * aRect.width;
GLfloat ymid = aRect.y + (1.0f - tl.y) / texCoordRect.height * aRect.height;
NS_ASSERTION(!xwrap ||
(xmid > aRect.x &&
xmid < aRect.XMost() &&
FuzzyEqual((xmid - aRect.x) + (aRect.XMost() - xmid), aRect.width)),
"xmid should be within [x,XMost()] and the wrapped rect should have the same width");
NS_ASSERTION(!ywrap ||
(ymid > aRect.y &&
ymid < aRect.YMost() &&
FuzzyEqual((ymid - aRect.y) + (aRect.YMost() - ymid), aRect.height)),
"ymid should be within [y,YMost()] and the wrapped rect should have the same height");
if (!xwrap && ywrap) {
SetRects(0, aLayerRects, aTextureRects,
aRect.x, aRect.y, aRect.XMost(), ymid,
tl.x, tl.y, br.x, 1.0f,
flipped);
SetRects(1, aLayerRects, aTextureRects,
aRect.x, ymid, aRect.XMost(), aRect.YMost(),
tl.x, 0.0f, br.x, br.y,
flipped);
return 2;
}
if (xwrap && !ywrap) {
SetRects(0, aLayerRects, aTextureRects,
aRect.x, aRect.y, xmid, aRect.YMost(),
tl.x, tl.y, 1.0f, br.y,
flipped);
SetRects(1, aLayerRects, aTextureRects,
xmid, aRect.y, aRect.XMost(), aRect.YMost(),
0.0f, tl.y, br.x, br.y,
flipped);
return 2;
}
SetRects(0, aLayerRects, aTextureRects,
aRect.x, aRect.y, xmid, ymid,
tl.x, tl.y, 1.0f, 1.0f,
flipped);
SetRects(1, aLayerRects, aTextureRects,
xmid, aRect.y, aRect.XMost(), ymid,
0.0f, tl.y, br.x, 1.0f,
flipped);
SetRects(2, aLayerRects, aTextureRects,
aRect.x, ymid, xmid, aRect.YMost(),
tl.x, 0.0f, 1.0f, br.y,
flipped);
SetRects(3, aLayerRects, aTextureRects,
xmid, ymid, aRect.XMost(), aRect.YMost(),
0.0f, 0.0f, br.x, br.y,
flipped);
return 4;
}
// |aRect| is the rectangle we want to draw to. We will draw it with
// up to 4 draw commands if necessary to avoid wrapping.
// |aTexCoordRect| is the rectangle from the texture that we want to
@ -562,10 +397,10 @@ CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
{
Rect layerRects[4];
Rect textureRects[4];
int rects = DecomposeIntoNoRepeatRects(aRect,
aTexCoordRect,
layerRects,
textureRects);
size_t rects = DecomposeIntoNoRepeatRects(aRect,
aTexCoordRect,
&layerRects,
&textureRects);
BindAndDrawQuads(aProg, rects, layerRects, textureRects);
}

Просмотреть файл

@ -392,7 +392,9 @@ gfxWindowsPlatform::UpdateRenderMode()
}
ID3D11Device *device = GetD3D11Device();
if (isVistaOrHigher && !safeMode && tryD2D && device &&
if (isVistaOrHigher && !safeMode && tryD2D &&
device &&
device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_0 &&
DoesD3D11DeviceSupportResourceSharing(device)) {
VerifyD2DDevice(d2dForceEnabled);

Просмотреть файл

@ -351,7 +351,11 @@ struct ClassExtension
*
* There may exist weak pointers to an object that are not traced through
* when the normal trace APIs are used, for example objects in the wrapper
* cache. This hook allows these pointers to be updated.
* cache. This hook allows these pointers to be updated.
*
* Note that this hook can be called before JS_NewObject() returns if a GC
* is triggered during construction of the object. This can happen for
* global objects for example.
*/
JSObjectMovedOp objectMovedOp;
};

Просмотреть файл

@ -64,6 +64,7 @@ var ignoreClasses = {
"PRIOMethods": true,
"XPCOMFunctions" : true, // I'm a little unsure of this one
"_MD_IOVector" : true,
"malloc_table_t": true, // replace_malloc
};
// Ignore calls through TYPE.FIELD, where TYPE is the class or struct name containing

Просмотреть файл

@ -160,6 +160,7 @@ EmitCheck(ExclusiveContext *cx, BytecodeEmitter *bce, ptrdiff_t delta)
ptrdiff_t offset = bce->code().length();
// Start it off moderately large to avoid repeated resizings early on.
// ~98% of cases fit within 1024 bytes.
if (bce->code().capacity() == 0 && !bce->code().reserve(1024))
return -1;
@ -2225,8 +2226,6 @@ EmitFinishIteratorResult(ExclusiveContext *cx, BytecodeEmitter *bce, bool done)
return false;
if (!EmitIndex32(cx, JSOP_INITPROP, done_id, bce))
return false;
if (Emit1(cx, bce, JSOP_ENDINIT) < 0)
return false;
return true;
}
@ -3387,8 +3386,6 @@ EmitDestructuringOpsArrayHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Pars
return false;
if (Emit1(cx, bce, JSOP_POP) < 0) // ... OBJ? ARRAY
return false;
if (Emit1(cx, bce, JSOP_ENDINIT) < 0)
return false;
needToPopIterator = false;
} else {
if (Emit1(cx, bce, JSOP_DUP) < 0) // ... OBJ? ITER ITER
@ -6421,9 +6418,6 @@ EmitObject(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
}
}
if (Emit1(cx, bce, JSOP_ENDINIT) < 0)
return false;
if (obj) {
/*
* The object survived and has a predictable shape: update the original
@ -6466,8 +6460,7 @@ EmitArrayComp(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return false;
bce->arrayCompDepth = saveDepth;
/* Emit the usual op needed for decompilation. */
return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
return true;
}
/**
@ -6555,9 +6548,7 @@ EmitArray(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, uint32_t co
if (Emit1(cx, bce, JSOP_POP) < 0) // ARRAY
return false;
}
/* Emit an op to finish the array and aid in decompilation. */
return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
return true;
}
static bool
@ -7082,7 +7073,8 @@ static int
AllocSrcNote(ExclusiveContext *cx, SrcNotesVector &notes)
{
// Start it off moderately large to avoid repeated resizings early on.
if (notes.capacity() == 0 && !notes.reserve(1024))
// ~99% of cases fit within 256 bytes.
if (notes.capacity() == 0 && !notes.reserve(256))
return -1;
jssrcnote dummy = 0;

Просмотреть файл

@ -26,6 +26,8 @@
namespace js {
class AutoLockGC;
namespace gc {
typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
@ -64,6 +66,24 @@ class ChunkPool
};
};
// Performs extra allocation off the main thread so that when memory is
// required on the main thread it will already be available and waiting.
class BackgroundAllocTask : public GCParallelTask
{
// Guarded by the GC lock.
JSRuntime *runtime;
ChunkPool &chunkPool_;
const bool enabled_;
public:
BackgroundAllocTask(JSRuntime *rt, ChunkPool &pool);
bool enabled() const { return enabled_; }
protected:
virtual void run() MOZ_OVERRIDE;
};
/*
* Encapsulates all of the GC tunables. These are effectively constant and
* should only be modified by setParameter.
@ -257,7 +277,7 @@ class GCRuntime
void minorGC(JS::gcreason::Reason reason);
void minorGC(JSContext *cx, JS::gcreason::Reason reason);
void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) { minorGC(reason); }
void gcIfNeeded(JSContext *cx);
bool gcIfNeeded(JSContext *cx = nullptr);
void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
void gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0);
void gcFinalSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
@ -301,8 +321,14 @@ class GCRuntime
js::gc::State state() { return incrementalState; }
bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
void waitBackgroundSweepOrAllocEnd() { helperState.waitBackgroundSweepOrAllocEnd(); }
void startBackgroundAllocationIfIdle() { helperState.startBackgroundAllocationIfIdle(); }
void waitBackgroundSweepOrAllocEnd() {
helperState.waitBackgroundSweepEnd();
allocTask.cancel(GCParallelTask::CancelAndWait);
}
#ifdef JSGC_GENERATIONAL
void requestMinorGC(JS::gcreason::Reason reason);
#endif
#ifdef DEBUG
@ -414,7 +440,7 @@ class GCRuntime
bool areGrayBitsValid() { return grayBitsValid; }
void setGrayBitsInvalid() { grayBitsValid = false; }
bool isGcNeeded() { return isNeeded; }
bool isGcNeeded() { return minorGCRequested || majorGCRequested; }
double computeHeapGrowthFactor(size_t lastBytes);
size_t computeTriggerBytes(double growthFactor, size_t lastBytes);
@ -451,7 +477,8 @@ class GCRuntime
private:
// For ArenaLists::allocateFromArena()
friend class ArenaLists;
Chunk *pickChunk(Zone *zone, AutoMaybeStartBackgroundAllocation &maybeStartBGAlloc);
Chunk *pickChunk(const AutoLockGC &lock, Zone *zone,
AutoMaybeStartBackgroundAllocation &maybeStartBGAlloc);
inline void arenaAllocatedDuringGC(JS::Zone *zone, ArenaHeader *arena);
template <AllowGC allowGC>
@ -469,10 +496,13 @@ class GCRuntime
void prepareToFreeChunk(ChunkInfo &info);
void releaseChunk(Chunk *chunk);
inline bool wantBackgroundAllocation() const;
friend class BackgroundAllocTask;
friend class AutoMaybeStartBackgroundAllocation;
inline bool wantBackgroundAllocation(const AutoLockGC &lock) const;
void startBackgroundAllocTaskIfIdle();
bool initZeal();
void requestInterrupt(JS::gcreason::Reason reason);
void requestMajorGC(JS::gcreason::Reason reason);
void collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
JS::gcreason::Reason reason);
bool gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
@ -605,12 +635,13 @@ class GCRuntime
*/
bool grayBitsValid;
/*
* These flags must be kept separate so that a thread requesting a
* compartment GC doesn't cancel another thread's concurrent request for a
* full GC.
*/
volatile uintptr_t isNeeded;
volatile uintptr_t majorGCRequested;
JS::gcreason::Reason majorGCTriggerReason;
#ifdef JSGC_GENERATIONAL
bool minorGCRequested;
JS::gcreason::Reason minorGCTriggerReason;
#endif
/* Incremented at the start of every major GC. */
uint64_t majorGCNumber;
@ -633,9 +664,6 @@ class GCRuntime
/* The invocation kind of the current GC, taken from the first slice. */
JSGCInvocationKind invocationKind;
/* The reason that an interrupt-triggered GC should be called. */
JS::gcreason::Reason triggerReason;
/*
* If this is 0, all cross-compartment proxies must be registered in the
* wrapper map. This checking must be disabled temporarily while creating
@ -840,6 +868,7 @@ class GCRuntime
PRLock *lock;
mozilla::DebugOnly<PRThread *> lockOwner;
BackgroundAllocTask allocTask;
GCHelperState helperState;
/*

Просмотреть файл

@ -766,7 +766,8 @@ Statistics::beginSlice(const ZoneGCStats &zoneStats, JS::gcreason::Reason reason
beginGC();
SliceData data(reason, PRMJ_Now(), GetPageFaultCount());
(void) slices.append(data); /* Ignore any OOMs here. */
if (!slices.append(data))
CrashAtUnhandlableOOM("Failed to allocate statistics slice.");
if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback)
(*cb)(JS_TELEMETRY_GC_REASON, reason);

Просмотреть файл

@ -303,7 +303,7 @@ void
StoreBuffer::setAboutToOverflow()
{
aboutToOverflow_ = true;
runtime_->requestInterrupt(JSRuntime::RequestInterruptMainThread);
runtime_->gc.requestMinorGC(JS::gcreason::FULL_STORE_BUFFER);
}
bool

Просмотреть файл

@ -1854,12 +1854,6 @@ BaselineCompiler::emit_JSOP_INITPROP()
return emitOpIC(compiler.getStub(&stubSpace_));
}
bool
BaselineCompiler::emit_JSOP_ENDINIT()
{
return true;
}
typedef bool (*NewbornArrayPushFn)(JSContext *, HandleObject, const Value &);
static const VMFunction NewbornArrayPushInfo = FunctionInfo<NewbornArrayPushFn>(NewbornArrayPush);

Просмотреть файл

@ -104,7 +104,6 @@ namespace jit {
_(JSOP_INITPROP) \
_(JSOP_INITPROP_GETTER) \
_(JSOP_INITPROP_SETTER) \
_(JSOP_ENDINIT) \
_(JSOP_ARRAYPUSH) \
_(JSOP_GETELEM) \
_(JSOP_SETELEM) \

Просмотреть файл

@ -1639,9 +1639,6 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_INITELEM_SETTER:
return jsop_initelem_getter_setter();
case JSOP_ENDINIT:
return true;
case JSOP_FUNCALL:
return jsop_funcall(GET_ARGC(pc));

Просмотреть файл

@ -1069,18 +1069,29 @@ GCRuntime::moveChunkToFreePool(Chunk *chunk)
}
inline bool
GCRuntime::wantBackgroundAllocation() const
GCRuntime::wantBackgroundAllocation(const AutoLockGC &lock) const
{
/*
* To minimize memory waste we do not want to run the background chunk
* allocation if we have empty chunks or when the runtime needs just few
* of them.
*/
return helperState.canBackgroundAllocate() &&
// To minimize memory waste, we do not want to run the background chunk
// allocation if we already have some empty chunks or when the runtime has
// a small heap size (and therefore likely has a small growth rate).
return allocTask.enabled() &&
emptyChunks.count() < tunables.minEmptyChunkCount() &&
chunkSet.count() >= 4;
}
void
GCRuntime::startBackgroundAllocTaskIfIdle()
{
AutoLockHelperThreadState helperLock;
if (allocTask.isRunning())
return;
// Join the previous invocation of the task. This will return immediately
// if the thread has never been started.
allocTask.joinWithLockHeld();
allocTask.startWithLockHeld();
}
class js::gc::AutoMaybeStartBackgroundAllocation
{
private:
@ -1099,17 +1110,14 @@ class js::gc::AutoMaybeStartBackgroundAllocation
}
~AutoMaybeStartBackgroundAllocation() {
if (runtime && !runtime->currentThreadOwnsInterruptLock()) {
AutoLockHelperThreadState helperLock;
AutoLockGC lock(runtime);
runtime->gc.startBackgroundAllocationIfIdle();
}
if (runtime && !runtime->currentThreadOwnsInterruptLock())
runtime->gc.startBackgroundAllocTaskIfIdle();
}
};
/* The caller must hold the GC lock. */
Chunk *
GCRuntime::pickChunk(Zone *zone, AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation)
GCRuntime::pickChunk(const AutoLockGC &lock, Zone *zone,
AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation)
{
Chunk **listHeadp = getAvailableChunkList(zone);
Chunk *chunk = *listHeadp;
@ -1127,7 +1135,7 @@ GCRuntime::pickChunk(Zone *zone, AutoMaybeStartBackgroundAllocation &maybeStartB
MOZ_ASSERT(chunk->unused());
MOZ_ASSERT(!chunkSet.has(chunk));
if (wantBackgroundAllocation())
if (wantBackgroundAllocation(lock))
maybeStartBackgroundAllocation.tryToStartBackgroundAllocation(rt);
chunkAllocationSinceLastGC = true;
@ -1173,13 +1181,17 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
decommitThreshold(32 * 1024 * 1024),
cleanUpEverything(false),
grayBitsValid(false),
isNeeded(0),
majorGCRequested(0),
majorGCTriggerReason(JS::gcreason::NO_REASON),
#ifdef JSGC_GENERATIONAL
minorGCRequested(false),
minorGCTriggerReason(JS::gcreason::NO_REASON),
#endif
majorGCNumber(0),
jitReleaseNumber(0),
number(0),
startNumber(0),
isFull(false),
triggerReason(JS::gcreason::NO_REASON),
#ifdef DEBUG
disableStrictProxyCheckingCount(0),
#endif
@ -1229,6 +1241,7 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
#endif
lock(nullptr),
lockOwner(nullptr),
allocTask(rt, emptyChunks),
helperState(rt)
{
setGCMode(JSGC_MODE_GLOBAL);
@ -1970,7 +1983,7 @@ ArenaLists::allocateFromArena(JS::Zone *zone, AllocKind thingKind,
if (maybeLock.isNothing())
maybeLock.emplace(rt);
Chunk *chunk = rt->gc.pickChunk(zone, maybeStartBGAlloc);
Chunk *chunk = rt->gc.pickChunk(maybeLock.ref(), zone, maybeStartBGAlloc);
if (!chunk)
return nullptr;
@ -2937,13 +2950,25 @@ js::MarkCompartmentActive(InterpreterFrame *fp)
}
void
GCRuntime::requestInterrupt(JS::gcreason::Reason reason)
GCRuntime::requestMajorGC(JS::gcreason::Reason reason)
{
if (isNeeded)
if (majorGCRequested)
return;
isNeeded = true;
triggerReason = reason;
majorGCRequested = true;
majorGCTriggerReason = reason;
rt->requestInterrupt(JSRuntime::RequestInterruptMainThread);
}
void
GCRuntime::requestMinorGC(JS::gcreason::Reason reason)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
if (minorGCRequested)
return;
minorGCRequested = true;
minorGCTriggerReason = reason;
rt->requestInterrupt(JSRuntime::RequestInterruptMainThread);
}
@ -2972,7 +2997,7 @@ GCRuntime::triggerGC(JS::gcreason::Reason reason)
return false;
JS::PrepareForFullGC(rt);
requestInterrupt(reason);
requestMajorGC(reason);
return true;
}
@ -3014,7 +3039,7 @@ GCRuntime::triggerZoneGC(Zone *zone, JS::gcreason::Reason reason)
}
PrepareZoneForGC(zone);
requestInterrupt(reason);
requestMajorGC(reason);
return true;
}
@ -3031,10 +3056,8 @@ GCRuntime::maybeGC(Zone *zone)
}
#endif
if (isNeeded) {
gcSlice(GC_NORMAL, JS::gcreason::MAYBEGC);
if (gcIfNeeded())
return true;
}
double factor = schedulingState.inHighFrequencyGCMode() ? 0.85 : 0.9;
if (zone->usage.gcBytes() > 1024 * 1024 &&
@ -3269,12 +3292,8 @@ GCHelperState::init()
if (!(done = PR_NewCondVar(rt->gc.lock)))
return false;
if (CanUseExtraThreads()) {
backgroundAllocation = (GetCPUCount() >= 2);
if (CanUseExtraThreads())
HelperThreadState().ensureInitialized();
} else {
backgroundAllocation = false;
}
return true;
}
@ -3358,28 +3377,6 @@ GCHelperState::work()
break;
}
case ALLOCATING: {
AutoTraceLog logAllocation(logger, TraceLogger::GCAllocation);
do {
Chunk *chunk;
{
AutoUnlockGC unlock(rt);
chunk = Chunk::allocate(rt);
}
/* OOM stops the background allocation. */
if (!chunk)
break;
MOZ_ASSERT(chunk->info.numArenasFreeCommitted == 0);
rt->gc.emptyChunks.put(chunk);
} while (state() == ALLOCATING && rt->gc.wantBackgroundAllocation());
MOZ_ASSERT(state() == ALLOCATING || state() == CANCEL_ALLOCATION);
break;
}
case CANCEL_ALLOCATION:
break;
}
setState(IDLE);
@ -3388,6 +3385,32 @@ GCHelperState::work()
PR_NotifyAllCondVar(done);
}
BackgroundAllocTask::BackgroundAllocTask(JSRuntime *rt, ChunkPool &pool)
: runtime(rt),
chunkPool_(pool),
enabled_(CanUseExtraThreads() && GetCPUCount() >= 2)
{
}
/* virtual */ void
BackgroundAllocTask::run()
{
TraceLogger *logger = TraceLoggerForCurrentThread();
AutoTraceLog logAllocation(logger, TraceLogger::GCAllocation);
AutoLockGC lock(runtime);
while (!cancel_ && runtime->gc.wantBackgroundAllocation(lock)) {
Chunk *chunk;
{
AutoUnlockGC unlock(runtime);
chunk = Chunk::allocate(runtime);
if (!chunk)
break;
}
chunkPool_.put(chunk);
}
}
void
GCHelperState::startBackgroundSweep(bool shouldShrink)
{
@ -3416,13 +3439,8 @@ GCHelperState::startBackgroundShrink()
case SWEEPING:
shrinkFlag = true;
break;
case ALLOCATING:
case CANCEL_ALLOCATION:
/*
* If we have started background allocation there is nothing to
* shrink.
*/
break;
default:
MOZ_CRASH("Invalid GC helper thread state.");
}
}
@ -3436,26 +3454,6 @@ GCHelperState::waitBackgroundSweepEnd()
rt->gc.assertBackgroundSweepingFinished();
}
void
GCHelperState::waitBackgroundSweepOrAllocEnd()
{
AutoLockGC lock(rt);
if (state() == ALLOCATING)
setState(CANCEL_ALLOCATION);
while (state() == SWEEPING || state() == CANCEL_ALLOCATION)
waitForBackgroundThread();
if (rt->gc.incrementalState == NO_INCREMENTAL)
rt->gc.assertBackgroundSweepingFinished();
}
/* Must be called with the GC lock taken. */
inline void
GCHelperState::startBackgroundAllocationIfIdle()
{
if (state_ == IDLE)
startBackgroundThread(ALLOCATING);
}
/* Must be called with the GC lock taken. */
void
GCHelperState::doSweep()
@ -5814,7 +5812,7 @@ GCRuntime::gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
AutoTraceSession session(rt, MajorCollecting);
isNeeded = false;
majorGCRequested = false;
interFrameGC = true;
number++;
@ -5828,15 +5826,20 @@ GCRuntime::gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
// Assert if this is a GC unsafe region.
JS::AutoAssertOnGC::VerifyIsSafeToGC(rt);
/*
* As we about to purge caches and clear the mark bits we must wait for
* any background finalization to finish. We must also wait for the
* background allocation to finish so we can avoid taking the GC lock
* when manipulating the chunks during the GC.
*/
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
waitBackgroundSweepOrAllocEnd();
// As we are about to purge caches and clear the mark bits, wait for
// background finalization to finish. It cannot run between slices
// so we only need to wait on the first slice.
if (incrementalState == NO_INCREMENTAL)
waitBackgroundSweepEnd();
// We must also wait for background allocation to finish so we can
// avoid taking the GC lock when manipulating the chunks during the GC.
// The background alloc task can run between slices, so we must wait
// for it at the start of every slice.
allocTask.cancel(GCParallelTask::CancelAndWait);
}
State prevState = incrementalState;
@ -6145,6 +6148,7 @@ void
GCRuntime::minorGC(JS::gcreason::Reason reason)
{
#ifdef JSGC_GENERATIONAL
minorGCRequested = false;
TraceLogger *logger = TraceLoggerForMainThread(rt);
AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC);
nursery.collect(rt, reason, nullptr);
@ -6158,6 +6162,7 @@ GCRuntime::minorGC(JSContext *cx, JS::gcreason::Reason reason)
// Alternate to the runtime-taking form above which allows marking type
// objects as needing pretenuring.
#ifdef JSGC_GENERATIONAL
minorGCRequested = false;
TraceLogger *logger = TraceLoggerForMainThread(rt);
AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC);
Nursery::TypeObjectList pretenureTypes;
@ -6196,20 +6201,26 @@ GCRuntime::enableGenerationalGC()
#endif
}
void
GCRuntime::gcIfNeeded(JSContext *cx)
bool
GCRuntime::gcIfNeeded(JSContext *cx /* = nullptr */)
{
// This method returns whether a major GC was performed.
#ifdef JSGC_GENERATIONAL
/*
* In case of store buffer overflow perform minor GC first so that the
* correct reason is seen in the logs.
*/
if (storeBuffer.isAboutToOverflow())
minorGC(cx, JS::gcreason::FULL_STORE_BUFFER);
if (minorGCRequested) {
if (cx)
minorGC(cx, minorGCTriggerReason);
else
minorGC(minorGCTriggerReason);
}
#endif
if (isNeeded)
gcSlice(GC_NORMAL, rt->gc.triggerReason, 0);
if (majorGCRequested) {
gcSlice(GC_NORMAL, rt->gc.majorGCTriggerReason);
return true;
}
return false;
}
AutoFinishGC::AutoFinishGC(JSRuntime *rt)

Просмотреть файл

@ -1005,9 +1005,7 @@ class GCHelperState
{
enum State {
IDLE,
SWEEPING,
ALLOCATING,
CANCEL_ALLOCATION
SWEEPING
};
// Associated runtime.
@ -1033,8 +1031,6 @@ class GCHelperState
bool sweepFlag;
bool shrinkFlag;
bool backgroundAllocation;
friend class js::gc::ArenaLists;
static void freeElementsAndArray(void **array, void **end) {
@ -1054,8 +1050,7 @@ class GCHelperState
state_(IDLE),
thread(nullptr),
sweepFlag(false),
shrinkFlag(false),
backgroundAllocation(true)
shrinkFlag(false)
{ }
bool init();
@ -1072,20 +1067,6 @@ class GCHelperState
/* Must be called without the GC lock taken. */
void waitBackgroundSweepEnd();
/* Must be called without the GC lock taken. */
void waitBackgroundSweepOrAllocEnd();
/* Must be called with the GC lock taken. */
void startBackgroundAllocationIfIdle();
bool canBackgroundAllocate() const {
return backgroundAllocation;
}
void disableBackgroundAllocation() {
backgroundAllocation = false;
}
bool onBackgroundThread();
/*
@ -1118,11 +1099,15 @@ class GCParallelTask
uint64_t duration_;
protected:
// A flag to signal a request for early completion of the off-thread task.
mozilla::Atomic<bool> cancel_;
virtual void run() = 0;
public:
GCParallelTask() : state(NotStarted), duration_(0) {}
// Time spent in the most recent invocation of this task.
int64_t duration() const { return duration_; }
// The simple interface to a parallel task works exactly like pthreads.
@ -1137,6 +1122,17 @@ class GCParallelTask
// Instead of dispatching to a helper, run the task on the main thread.
void runFromMainThread(JSRuntime *rt);
// Dispatch a cancelation request.
enum CancelMode { CancelNoWait, CancelAndWait};
void cancel(CancelMode mode = CancelNoWait) {
cancel_ = true;
if (mode == CancelAndWait)
join();
}
// Check if a task is actively running.
bool isRunning() const;
// This should be friended to HelperThread, but cannot be because it
// would introduce several circular dependencies.
public:

Просмотреть файл

@ -804,6 +804,10 @@ js_DumpPC(JSContext *cx)
if (!sprinter.init())
return false;
ScriptFrameIter iter(cx);
if (iter.done()) {
fprintf(stdout, "Empty stack.\n");
return true;
}
RootedScript script(cx, iter.script());
bool ok = js_DisassembleAtPC(cx, script, true, iter.pc(), false, &sprinter);
fprintf(stdout, "%s", sprinter.string());

Просмотреть файл

@ -26,17 +26,7 @@ typedef enum JSOp {
FOR_EACH_OPCODE(ENUMERATE_OPCODE)
#undef ENUMERATE_OPCODE
JSOP_LIMIT,
/*
* These pseudo-ops help js_DecompileValueGenerator decompile JSOP_SETPROP,
* JSOP_SETELEM, and comprehension-tails, respectively. They are never
* stored in bytecode, so they don't preempt valid opcodes.
*/
JSOP_GETPROP2 = JSOP_LIMIT,
JSOP_GETELEM2 = JSOP_LIMIT + 1,
JSOP_FORLOCAL = JSOP_LIMIT + 2,
JSOP_FAKE_LIMIT = JSOP_FORLOCAL
JSOP_LIMIT
} JSOp;
/*

Просмотреть файл

@ -352,23 +352,10 @@ static inline void
WeakMapPostWriteBarrier(JSRuntime *rt, ObjectValueMap *weakMap, JSObject *key)
{
#ifdef JSGC_GENERATIONAL
/*
* Strip the barriers from the type before inserting into the store buffer.
* This will automatically ensure that barriers do not fire during GC.
*
* Some compilers complain about instantiating the WeakMap class for
* unbarriered type arguments, so we cast to a HashMap instead. Because of
* WeakMap's multiple inheritace, We need to do this in two stages, first to
* the HashMap base class and then to the unbarriered version.
*/
ObjectValueMap::Base *baseHashMap = static_cast<ObjectValueMap::Base *>(weakMap);
typedef HashMap<JSObject *, Value> UnbarrieredMap;
UnbarrieredMap *unbarrieredMap = reinterpret_cast<UnbarrieredMap *>(baseHashMap);
typedef HashKeyRef<UnbarrieredMap, JSObject *> Ref;
// Strip the barriers from the type before inserting into the store buffer.
// This will automatically ensure that barriers do not fire during GC.
if (key && IsInsideNursery(key))
rt->gc.storeBuffer.putGeneric(Ref((unbarrieredMap), key));
rt->gc.storeBuffer.putGeneric(UnbarrieredRef(weakMap, key));
#endif
}

Просмотреть файл

@ -12,6 +12,7 @@
#include "jsobj.h"
#include "gc/Marking.h"
#include "gc/StoreBuffer.h"
#include "js/HashTable.h"
namespace js {
@ -279,6 +280,28 @@ protected:
}
};
/*
* At times, you will need to ignore barriers when accessing WeakMap entries.
* Localize the templatized casting craziness here.
*/
template <class Key, class Value>
static inline gc::HashKeyRef<HashMap<Key, Value, DefaultHasher<Key>, RuntimeAllocPolicy>, Key>
UnbarrieredRef(WeakMap<PreBarriered<Key>, RelocatablePtr<Value>> *map, Key key)
{
/*
* Some compilers complain about instantiating the WeakMap class for
* unbarriered type arguments, so we cast to a HashMap instead. Because of
* WeakMap's multiple inheritance, we need to do this in two stages, first
* to the HashMap base class and then to the unbarriered version.
*/
typedef typename WeakMap<PreBarriered<Key>, RelocatablePtr<Value>>::Base BaseMap;
auto baseMap = static_cast<BaseMap*>(map);
typedef HashMap<Key, Value, DefaultHasher<Key>, RuntimeAllocPolicy> UnbarrieredMap;
typedef gc::HashKeyRef<UnbarrieredMap, Key> UnbarrieredKeyRef;
return UnbarrieredKeyRef(reinterpret_cast<UnbarrieredMap*>(baseMap), key);
}
/* WeakMap methods exposed so they can be installed in the self-hosting global. */
extern JSObject *

Просмотреть файл

@ -22,22 +22,22 @@ if (typeof findReferences == "function") {
function g() { return 42; }
function s(v) { }
var p = Object.defineProperty({}, 'a', { get:g, set:s });
assertEq(referencesVia(p, 'shape; base; getter', g), true);
assertEq(referencesVia(p, 'shape; base; setter', s), true);
assertEq(referencesVia(p, 'shape; getter', g), true);
assertEq(referencesVia(p, 'shape; setter', s), true);
// If there are multiple objects with the same shape referring to a getter
// or setter, findReferences should get all of them, even though the shape
// gets 'marked' the first time we visit it.
var q = Object.defineProperty({}, 'a', { get:g, set:s });
assertEq(referencesVia(p, 'shape; base; getter', g), true);
assertEq(referencesVia(q, 'shape; base; getter', g), true);
assertEq(referencesVia(p, 'shape; getter', g), true);
assertEq(referencesVia(q, 'shape; getter', g), true);
// If we extend each object's shape chain, both should still be able to
// reach the getter, even though the two shapes are each traversed twice.
p.b = 9;
q.b = 9;
assertEq(referencesVia(p, 'shape; parent; base; getter', g), true);
assertEq(referencesVia(q, 'shape; parent; base; getter', g), true);
assertEq(referencesVia(p, 'shape; parent; getter', g), true);
assertEq(referencesVia(q, 'shape; parent; getter', g), true);
// These are really just ordinary own property references.
assertEq(referencesVia(C, 'prototype', Object.getPrototypeOf(o)), true);

Просмотреть файл

@ -240,6 +240,11 @@ GlobalObject::create(JSContext *cx, const Class *clasp)
Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
// Initialize the private slot to null if present, as GC can call class
// hooks before the caller gets to set this to a non-garbage value.
if (clasp->flags & JSCLASS_HAS_PRIVATE)
global->setPrivate(nullptr);
cx->compartment()->initGlobal(*global);
if (!global->setQualifiedVarObj(cx))

Просмотреть файл

@ -189,8 +189,8 @@ ParseTask::ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal, JSC
JS::OffThreadCompileCallback callback, void *callbackData)
: cx(cx), options(initCx), chars(chars), length(length),
alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
exclusiveContextGlobal(initCx, exclusiveContextGlobal), optionsElement(initCx),
optionsIntroductionScript(initCx), callback(callback), callbackData(callbackData),
exclusiveContextGlobal(initCx, exclusiveContextGlobal),
callback(callback), callbackData(callbackData),
script(nullptr), errors(cx), overRecursed(false)
{
}
@ -761,6 +761,7 @@ js::GCParallelTask::joinWithLockHeld()
while (state != Finished)
HelperThreadState().wait(GlobalHelperThreadState::CONSUMER);
state = NotStarted;
cancel_ = false;
}
void
@ -796,6 +797,13 @@ js::GCParallelTask::runFromHelperThread()
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
}
bool
js::GCParallelTask::isRunning() const
{
MOZ_ASSERT(HelperThreadState().isLocked());
return state == Dispatched;
}
void
HelperThread::handleGCParallelWorkload()
{

Просмотреть файл

@ -457,14 +457,6 @@ struct ParseTask
// Rooted pointer to the global object used by 'cx'.
PersistentRootedObject exclusiveContextGlobal;
// Saved GC-managed CompileOptions fields that will populate slots in
// the ScriptSourceObject. We create the ScriptSourceObject in the
// compilation's temporary compartment, so storing these values there
// at that point would create cross-compartment references. Instead we
// hold them here, and install them after merging the compartments.
PersistentRootedObject optionsElement;
PersistentRootedScript optionsIntroductionScript;
// Callback invoked off the main thread when the parse finishes.
JS::OffThreadCompileCallback callback;
void *callbackData;

Просмотреть файл

@ -570,19 +570,19 @@ InitArrayElemOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, uint32_t
MOZ_ASSERT(obj->is<ArrayObject>());
/*
* If val is a hole, do not call JSObject::defineElement. In this case,
* if the current op is the last element initialiser, set the array length
* to one greater than id.
* If val is a hole, do not call JSObject::defineElement.
*
* If val is a hole and current op is JSOP_INITELEM_INC, always call
* Furthermore, if the current op is JSOP_INITELEM_INC, always call
* SetLengthProperty even if it is not the last element initialiser,
* because it may be followed by JSOP_SPREAD, which will not set the array
* length if nothing is spreaded.
* length if nothing is spread.
*
* Alternatively, if the current op is JSOP_INITELEM_ARRAY, the length will
* have already been set by the earlier JSOP_NEWARRAY; JSOP_INITELEM_ARRAY
* cannot follow JSOP_SPREAD.
*/
if (val.isMagic(JS_ELEMENTS_HOLE)) {
JSOp next = JSOp(*GetNextPc(pc));
if ((op == JSOP_INITELEM_ARRAY && next == JSOP_ENDINIT) || op == JSOP_INITELEM_INC) {
if (op == JSOP_INITELEM_INC) {
if (!SetLengthProperty(cx, obj, index + 1))
return false;
}

Просмотреть файл

@ -1611,6 +1611,7 @@ CASE(JSOP_UNUSED51)
CASE(JSOP_UNUSED52)
CASE(JSOP_UNUSED57)
CASE(JSOP_UNUSED83)
CASE(JSOP_UNUSED92)
CASE(JSOP_UNUSED103)
CASE(JSOP_UNUSED104)
CASE(JSOP_UNUSED105)
@ -3120,14 +3121,6 @@ CASE(JSOP_NEWOBJECT)
}
END_CASE(JSOP_NEWOBJECT)
CASE(JSOP_ENDINIT)
{
/* FIXME remove JSOP_ENDINIT bug 588522 */
MOZ_ASSERT(REGS.stackDepth() >= 1);
MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
}
END_CASE(JSOP_ENDINIT)
CASE(JSOP_MUTATEPROTO)
{
MOZ_ASSERT(REGS.stackDepth() >= 2);

Просмотреть файл

@ -770,17 +770,9 @@
* Stack: => obj
*/ \
macro(JSOP_NEWOBJECT, 91, "newobject", NULL, 5, 0, 1, JOF_OBJECT) \
/*
* A no-operation bytecode.
*
* Indicates the end of object/array initialization, and used for
* Type-Inference, decompile, etc.
* Category: Literals
* Type: Object
* Operands:
* Stack: =>
*/ \
macro(JSOP_ENDINIT, 92, "endinit", NULL, 1, 0, 0, JOF_BYTE) \
\
macro(JSOP_UNUSED92, 92, "unused92", NULL, 1, 0, 0, JOF_BYTE) \
\
/*
* Initialize a named property in an object literal, like '{a: x}'.
*

Просмотреть файл

@ -1846,23 +1846,8 @@ DebugScopes::proxiedScopesPostWriteBarrier(JSRuntime *rt, ObjectWeakMap *map,
const PreBarrieredObject &key)
{
#ifdef JSGC_GENERATIONAL
/*
* Strip the barriers from the type before inserting into the store buffer.
* This will automatically ensure that barriers do not fire during GC.
*
* Some compilers complain about instantiating the WeakMap class for
* unbarriered type arguments, so we cast to a HashMap instead. Because of
* WeakMap's multiple inheritace, We need to do this in two stages, first to
* the HashMap base class and then to the unbarriered version.
*/
ObjectWeakMap::Base *baseHashMap = static_cast<ObjectWeakMap::Base *>(map);
typedef HashMap<JSObject *, JSObject *> UnbarrieredMap;
UnbarrieredMap *unbarrieredMap = reinterpret_cast<UnbarrieredMap *>(baseHashMap);
typedef gc::HashKeyRef<UnbarrieredMap, JSObject *> Ref;
if (key && IsInsideNursery(key))
rt->gc.storeBuffer.putGeneric(Ref(unbarrieredMap, key.get()));
rt->gc.storeBuffer.putGeneric(UnbarrieredRef(map, key.get()));
#endif
}

Просмотреть файл

@ -28,7 +28,7 @@ namespace js {
*
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 186);
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 187);
class XDRBuffer {
public:

Просмотреть файл

@ -6092,6 +6092,12 @@ nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement,
NS_WARN_IF_FALSE((aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) == 0, "We can't support non-premultiplied alpha for video!");
#ifdef MOZ_EME
if (aElement->ContainsRestrictedContent()) {
return result;
}
#endif
uint16_t readyState;
if (NS_SUCCEEDED(aElement->GetReadyState(&readyState)) &&
(readyState == nsIDOMHTMLMediaElement::HAVE_NOTHING ||

Просмотреть файл

@ -2463,6 +2463,22 @@ MaxZIndexInList(nsDisplayList* aList, nsDisplayListBuilder* aBuilder)
return maxZIndex;
}
// Finds the max z-index of the items in aList that meet the following conditions
// 1) have z-index auto or z-index >= 0.
// 2) aFrame is a proper ancestor of the item's frame.
// Returns -1 if there is no such item.
static int32_t
MaxZIndexInListOfItemsContainedInFrame(nsDisplayList* aList, nsIFrame* aFrame)
{
int32_t maxZIndex = -1;
for (nsDisplayItem* item = aList->GetBottom(); item; item = item->GetAbove()) {
if (nsLayoutUtils::IsProperAncestorFrame(aFrame, item->Frame())) {
maxZIndex = std::max(maxZIndex, item->ZIndex());
}
}
return maxZIndex;
}
static void
AppendToTop(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists,
nsDisplayList* aSource, nsIFrame* aSourceFrame, bool aOwnLayer,
@ -2997,10 +3013,10 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// metadata about this scroll box to the compositor process.
nsDisplayScrollInfoLayer* layerItem = new (aBuilder) nsDisplayScrollInfoLayer(
aBuilder, mScrolledFrame, mOuter);
nsDisplayList* positionedDescendants = scrolledContent.PositionedDescendants();
if (BuildScrollContainerLayers()) {
// We process display items from bottom to top, so if we need to flatten after
// the scroll layer items have been processed we need to be on the top.
nsDisplayList* positionedDescendants = scrolledContent.PositionedDescendants();
if (!positionedDescendants->IsEmpty()) {
layerItem->SetOverrideZIndex(MaxZIndexInList(positionedDescendants, aBuilder));
positionedDescendants->AppendNewToTop(layerItem);
@ -3008,7 +3024,14 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
aLists.Outlines()->AppendNewToTop(layerItem);
}
} else {
scrolledContent.BorderBackground()->AppendNewToBottom(layerItem);
int32_t zindex =
MaxZIndexInListOfItemsContainedInFrame(positionedDescendants, mOuter);
if (zindex >= 0) {
layerItem->SetOverrideZIndex(zindex);
positionedDescendants->AppendNewToTop(layerItem);
} else {
scrolledContent.Outlines()->AppendNewToTop(layerItem);
}
}
}
// Now display overlay scrollbars and the resizer, if we have one.

Просмотреть файл

@ -79,8 +79,7 @@ private:
};
ClearKeyDecryptionManager::ClearKeyDecryptionManager(GMPDecryptorHost* aHost)
: mHost(aHost)
ClearKeyDecryptionManager::ClearKeyDecryptionManager()
{
CK_LOGD("ClearKeyDecryptionManager ctor");
}
@ -132,7 +131,7 @@ ClearKeyDecryptionManager::CreateSession(uint32_t aPromiseId,
string sessionId = GetNewSessionId();
assert(mSessions.find(sessionId) == mSessions.end());
ClearKeySession* session = new ClearKeySession(sessionId, mHost, mCallback);
ClearKeySession* session = new ClearKeySession(sessionId, mCallback);
session->Init(aPromiseId, aInitData, aInitDataSize);
mSessions[sessionId] = session;

Просмотреть файл

@ -19,7 +19,7 @@ class ClearKeyDecryptor;
class ClearKeyDecryptionManager MOZ_FINAL : public GMPDecryptor
{
public:
explicit ClearKeyDecryptionManager(GMPDecryptorHost* aHost);
ClearKeyDecryptionManager();
~ClearKeyDecryptionManager();
virtual void Init(GMPDecryptorCallback* aCallback) MOZ_OVERRIDE;
@ -60,7 +60,6 @@ public:
private:
GMPDecryptorCallback* mCallback;
GMPDecryptorHost* mHost;
std::map<KeyId, ClearKeyDecryptor*> mDecryptors;
std::map<std::string, ClearKeySession*> mSessions;

Просмотреть файл

@ -12,10 +12,8 @@
using namespace mozilla;
ClearKeySession::ClearKeySession(const std::string& aSessionId,
GMPDecryptorHost* aHost,
GMPDecryptorCallback* aCallback)
: mSessionId(aSessionId)
, mHost(aHost)
, mCallback(aCallback)
{
CK_LOGD("ClearKeySession ctor %p", this);

Просмотреть файл

@ -21,7 +21,7 @@ class ClearKeySession
{
public:
ClearKeySession(const std::string& aSessionId,
GMPDecryptorHost* aHost, GMPDecryptorCallback *aCallback);
GMPDecryptorCallback* aCallback);
~ClearKeySession();
@ -34,7 +34,6 @@ private:
std::vector<KeyId> mKeyIds;
GMPDecryptorCallback* mCallback;
GMPDecryptorHost* mHost;
};
#endif // __ClearKeySession_h__

Просмотреть файл

@ -10,6 +10,8 @@
#include <vector>
#include "ClearKeyUtils.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Endian.h"
#include "mozilla/NullPtr.h"
#include "openaes/oaes_lib.h"
@ -95,7 +97,7 @@ EncodeBase64Web(vector<uint8_t> aBinary, string& aEncoded)
auto out = aEncoded.begin();
auto data = aBinary.begin();
for (int i = 0; i < aEncoded.length(); i++) {
for (string::size_type i = 0; i < aEncoded.length(); i++) {
if (shift) {
out[i] = (*data << (6 - shift)) & sMask;
data++;
@ -106,7 +108,12 @@ EncodeBase64Web(vector<uint8_t> aBinary, string& aEncoded)
out[i] += (*data >> (shift + 2)) & sMask;
shift = (shift + 2) % 8;
out[i] = sAlphabet[out[i]];
// Cast idx to size_t before using it as an array-index,
// to pacify clang 'Wchar-subscripts' warning:
size_t idx = static_cast<size_t>(out[i]);
MOZ_ASSERT(idx < MOZ_ARRAY_LENGTH(sAlphabet),
"out of bounds index for 'sAlphabet'");
out[i] = sAlphabet[idx];
}
return true;

Просмотреть файл

@ -35,7 +35,7 @@ GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginAPI)
return GMPNotImplementedErr;
}
*aPluginAPI = new ClearKeyDecryptionManager(static_cast<GMPDecryptorHost*>(aHostAPI));
*aPluginAPI = new ClearKeyDecryptionManager();
return GMPNoErr;
}

Просмотреть файл

@ -736,7 +736,7 @@ int WebRtcAec_GetDelayMetricsCore(AecCore* self, int* median, int* std) {
// Calculate the L1 norm, with median value as central moment.
for (i = 0; i < kHistorySizeBlocks; i++) {
l1_norm += (float)(fabs(i - my_median) * self->delay_histogram[i]);
l1_norm += (float)abs(i - my_median) * self->delay_histogram[i];
}
*std = (int)(l1_norm / (float)num_delay_values + 0.5f) * kMsPerBlock;

Просмотреть файл

@ -289,7 +289,7 @@ int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc_t *stt, const int16_t *in_far,
int16_t nrSamples)
{
// Check for valid pointer
if (&stt->vadFarend == NULL)
if (stt == NULL)
{
return -1;
}

Просмотреть файл

@ -249,10 +249,10 @@ void OveruseDetector::UpdateKalman(int64_t t_delta,
const double residual = t_ts_delta - slope_*h[0] - offset_;
const bool stable_state =
(BWE_MIN(num_of_deltas_, 60) * fabsf(offset_) < threshold_);
(BWE_MIN(num_of_deltas_, 60) * fabs(offset_) < threshold_);
// We try to filter out very late frames. For instance periodic key
// frames doesn't fit the Gaussian model well.
if (fabsf(residual) < 3 * sqrt(var_noise_)) {
if (fabs(residual) < 3 * sqrt(var_noise_)) {
UpdateNoiseEstimate(residual, min_frame_period, stable_state);
} else {
UpdateNoiseEstimate(3 * sqrt(var_noise_), min_frame_period, stable_state);
@ -358,7 +358,7 @@ BandwidthUsage OveruseDetector::Detect(double ts_delta) {
return kBwNormal;
}
const double T = BWE_MIN(num_of_deltas_, 60) * offset_;
if (fabsf(T) > threshold_) {
if (fabs(T) > threshold_) {
if (offset_ > 0) {
if (time_over_using_ == -1) {
// Initialize the timer. Assume that we've been

Просмотреть файл

@ -162,7 +162,7 @@ VCMJitterEstimator::UpdateEstimate(int64_t frameDelayMS, uint32_t frameSizeBytes
// deviation is probably due to an incorrect line slope.
double deviation = DeviationFromExpectedDelay(frameDelayMS, deltaFS);
if (abs(deviation) < _numStdDevDelayOutlier * sqrt(_varNoise) ||
if (fabs(deviation) < _numStdDevDelayOutlier * sqrt(_varNoise) ||
frameSizeBytes > _avgFrameSize + _numStdDevFrameSizeOutlier * sqrt(_varFrameSize))
{
// Update the variance of the deviation from the
@ -257,7 +257,7 @@ VCMJitterEstimator::KalmanEstimateChannel(int64_t frameDelayMS,
{
return;
}
double sigma = (300.0 * exp(-abs(static_cast<double>(deltaFSBytes)) /
double sigma = (300.0 * exp(-fabs(static_cast<double>(deltaFSBytes)) /
(1e0 * _maxFrameSize)) + 1) * sqrt(_varNoise);
if (sigma < 1.0)
{

Просмотреть файл

@ -159,12 +159,12 @@ VCMEncodedFrame* VCMReceiver::FrameForDecoding(
// Assume that render timing errors are due to changes in the video stream.
if (next_render_time_ms < 0) {
timing_error = true;
} else if (abs(next_render_time_ms - now_ms) > max_video_delay_ms_) {
} else if (std::abs(next_render_time_ms - now_ms) > max_video_delay_ms_) {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
VCMId(vcm_id_, receiver_id_),
"This frame is out of our delay bounds, resetting jitter "
"buffer: %d > %d",
static_cast<int>(abs(next_render_time_ms - now_ms)),
static_cast<int>(std::abs(next_render_time_ms - now_ms)),
max_video_delay_ms_);
timing_error = true;
} else if (static_cast<int>(timing_->TargetVideoDelay()) >

Просмотреть файл

@ -114,7 +114,7 @@ bool
VCMRttFilter::JumpDetection(uint32_t rttMs)
{
double diffFromAvg = _avgRtt - rttMs;
if (abs(diffFromAvg) > _jumpStdDevs * sqrt(_varRtt))
if (fabs(diffFromAvg) > _jumpStdDevs * sqrt(_varRtt))
{
int diffSign = (diffFromAvg >= 0) ? 1 : -1;
int jumpCountSign = (_jumpCount >= 0) ? 1 : -1;

Просмотреть файл

@ -52,7 +52,7 @@ struct Vp8StreamInfo {
MATCHER_P(MatchesVp8StreamInfo, expected, "") {
bool res = true;
for (int tl = 0; tl < kMaxNumberOfTemporalLayers; ++tl) {
if (abs(expected.framerate_fps[tl] - arg.framerate_fps[tl]) > 0.5) {
if (fabs(expected.framerate_fps[tl] - arg.framerate_fps[tl]) > 0.5) {
*result_listener << " framerate_fps[" << tl
<< "] = " << arg.framerate_fps[tl] << " (expected "
<< expected.framerate_fps[tl] << ") ";

Просмотреть файл

@ -184,7 +184,7 @@ class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer {
// estimated as being synchronized. We don't want to trigger on those.
if (time_since_creation < kStartupTimeMs)
return;
if (abs(latest_audio_ntp - latest_video_ntp) < kInSyncThresholdMs) {
if (std::abs(latest_audio_ntp - latest_video_ntp) < kInSyncThresholdMs) {
if (first_time_in_sync_ == -1) {
first_time_in_sync_ = now_ms;
webrtc::test::PrintResult("sync_convergence_time",

Просмотреть файл

@ -20,6 +20,7 @@ from manifestparser import TestManifest
from marionette import Marionette
from mixins.b2g import B2GTestResultMixin, get_b2g_pid, get_dm
from mozhttpd import MozHttpd
from mozlog.structured.structuredlog import get_default_logger
from moztest.adapters.unit import StructuredTestRunner, StructuredTestResult
from moztest.results import TestResultCollection, TestResult, relevant_line
@ -222,7 +223,8 @@ class MarionetteTextTestRunner(StructuredTestRunner):
marionette=self.marionette,
b2g_pid=self.b2g_pid,
logger=self.logger,
logcat_stdout=self.logcat_stdout)
logcat_stdout=self.logcat_stdout,
result_callbacks=self.result_callbacks)
def run(self, test):
"Run the given test case or test suite."
@ -450,7 +452,8 @@ class BaseMarionetteTestRunner(object):
device_serial=None, symbols_path=None, timeout=None,
shuffle=False, shuffle_seed=random.randint(0, sys.maxint),
sdcard=None, this_chunk=1, total_chunks=1, sources=None,
server_root=None, gecko_log=None, **kwargs):
server_root=None, gecko_log=None, result_callbacks=None,
**kwargs):
self.address = address
self.emulator = emulator
self.emulator_binary = emulator_binary
@ -490,6 +493,22 @@ class BaseMarionetteTestRunner(object):
self.mixin_run_tests = []
self.manifest_skipped_tests = []
self.tests = []
self.result_callbacks = result_callbacks if result_callbacks is not None else []
def gather_debug(test, status):
rv = {}
marionette = test._marionette_weakref()
try:
marionette.set_context(marionette.CONTEXT_CHROME)
rv['screenshot'] = marionette.screenshot()
marionette.set_context(marionette.CONTEXT_CONTENT)
rv['source'] = marionette.page_source
except:
logger = get_default_logger()
logger.warning('Failed to gather test failure debug.', exc_info=True)
return rv
self.result_callbacks.append(gather_debug)
if testvars:
if not os.path.exists(testvars):
@ -789,7 +808,8 @@ class BaseMarionetteTestRunner(object):
runner = self.textrunnerclass(logger=self.logger,
marionette=self.marionette,
capabilities=self.capabilities,
logcat_stdout=self.logcat_stdout)
logcat_stdout=self.logcat_stdout,
result_callbacks=self.result_callbacks)
results = runner.run(suite)
self.results.append(results)

Просмотреть файл

@ -124,7 +124,7 @@ class HTMLFormatter(base.BaseFormatter):
# use base64 to avoid that some browser (such as Firefox, Opera)
# treats '#' as the start of another link if the data URL contains.
# use 'charset=utf-8' to show special characters like Chinese.
href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(content)
href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(content.encode('utf-8'))
links_html.append(html.a(
name.title(),
class_=name,

Просмотреть файл

@ -10,6 +10,3 @@
[Test appending an empty ArrayBuffer.]
expected: FAIL
[Test SourceBuffer.appendBuffer() triggering an 'ended' to 'open' transition.]
disabled:
if not debug and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): Unstable

Просмотреть файл

@ -1,3 +1,15 @@
[mediasource-buffered.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
expected: TIMEOUT
[Demuxed content with different lengths]
expected: FAIL
[Muxed tracks with different lengths]
expected: FAIL
[Demuxed content with an empty buffered range on one SourceBuffer]
expected: FAIL
[Muxed content empty buffered ranges.]
expected: FAIL

Просмотреть файл

@ -1,3 +0,0 @@
[mediasource-config-change-webm-a-bitrate.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467

Просмотреть файл

@ -1,3 +0,0 @@
[mediasource-config-change-webm-av-audio-bitrate.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467

Просмотреть файл

@ -1,3 +0,0 @@
[mediasource-config-change-webm-av-video-bitrate.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467

Просмотреть файл

@ -1,6 +1,5 @@
[mediasource-config-change-webm-v-bitrate.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
[Tests webm video-only bitrate changes.]
expected: FAIL

Просмотреть файл

@ -1,3 +1,15 @@
[mediasource-duration.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
expected: TIMEOUT
[Test seek starts on duration truncation below currentTime]
expected: TIMEOUT
[Test appendBuffer completes previous seek to truncated duration]
disabled: TIMEOUT or FAIL https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
[Test endOfStream completes previous seek to truncated duration]
expected: TIMEOUT
[Test setting same duration multiple times does not fire duplicate durationchange]
expected: FAIL

Просмотреть файл

@ -1,3 +1,6 @@
[mediasource-play-then-seek-back.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
expected: TIMEOUT
[Test playing then seeking back.]
expected: TIMEOUT

Просмотреть файл

@ -1,3 +1,6 @@
[mediasource-redundant-seek.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
expected: TIMEOUT
[Test redundant fully prebuffered seek]
expected: TIMEOUT

Просмотреть файл

@ -1,3 +1,9 @@
[mediasource-seek-beyond-duration.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
expected: TIMEOUT
[Test seeking beyond updated media duration.]
expected: TIMEOUT
[Test seeking beyond media duration.]
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467

Просмотреть файл

@ -1,3 +1,9 @@
[mediasource-seek-during-pending-seek.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
expected: TIMEOUT
[Test seeking to a new location before transitioning beyond HAVE_METADATA.]
expected: TIMEOUT
[Test seeking to a new location during a pending seek.]
expected: TIMEOUT

Просмотреть файл

@ -1,3 +1,6 @@
[mediasource-sourcebuffer-mode.html]
type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1066467
expected: TIMEOUT
[Test setting SourceBuffer.mode and SourceBuffer.timestampOffset while parsing media segment.]
expected: FAIL

Просмотреть файл

@ -264,7 +264,10 @@ class TickSample {
lr(NULL),
#endif
context(NULL),
isSamplingCurrentThread(false) {}
isSamplingCurrentThread(false),
threadProfile(nullptr),
rssMemory(0),
ussMemory(0) {}
void PopulateContext(void* aContext);

Просмотреть файл

@ -180,6 +180,8 @@
#include "npapi.h"
#include <d3d11.h>
#if !defined(SM_CONVERTIBLESLATEMODE)
#define SM_CONVERTIBLESLATEMODE 0x2003
#endif
@ -6735,7 +6737,9 @@ nsWindow::GetPreferredCompositorBackends(nsTArray<LayersBackend>& aHints)
}
ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
if (device && !DoesD3D11DeviceSupportResourceSharing(device)) {
if (device &&
device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_0 &&
!DoesD3D11DeviceSupportResourceSharing(device)) {
// bug 1083071 - bad things - fall back to basic layers
// This should not happen aside from driver bugs, and in particular
// should not happen on our test machines, so let's NS_ERROR to ensure