Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE

This commit is contained in:
Ciure Andrei 2018-12-22 11:53:32 +02:00
Родитель cc534321e8 f5e90a1d62
Коммит de0be877fa
13 изменённых файлов: 200 добавлений и 56 удалений

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

@ -61,42 +61,40 @@ class DecodedStreamGraphListener {
TrackID aVideoTrackID,
MozPromiseHolder<DecodedStream::EndedPromise>&& aVideoEndedHolder,
AbstractThread* aMainThread)
: mMutex("DecodedStreamGraphListener::mMutex"),
mAudioTrackListener(IsTrackIDExplicit(aAudioTrackID)
: mAudioTrackListener(IsTrackIDExplicit(aAudioTrackID)
? MakeRefPtr<DecodedStreamTrackListener>(
this, aStream, aAudioTrackID)
: nullptr),
mAudioTrackID(aAudioTrackID),
mAudioEndedHolder(std::move(aAudioEndedHolder)),
mVideoTrackListener(IsTrackIDExplicit(aVideoTrackID)
? MakeRefPtr<DecodedStreamTrackListener>(
this, aStream, aVideoTrackID)
: nullptr),
mAudioTrackID(aAudioTrackID),
mAudioEndedHolder(std::move(aAudioEndedHolder)),
mVideoTrackID(aVideoTrackID),
mVideoEndedHolder(std::move(aVideoEndedHolder)),
mStream(aStream),
mAbstractMainThread(aMainThread) {
MOZ_ASSERT(NS_IsMainThread());
if (mAudioTrackListener) {
aStream->AddTrackListener(mAudioTrackListener, mAudioTrackID);
mStream->AddTrackListener(mAudioTrackListener, mAudioTrackID);
} else {
mAudioEndedHolder.ResolveIfExists(true, __func__);
}
if (mVideoTrackListener) {
aStream->AddTrackListener(mVideoTrackListener, mVideoTrackID);
mStream->AddTrackListener(mVideoTrackListener, mVideoTrackID);
} else {
mVideoEndedHolder.ResolveIfExists(true, __func__);
}
}
void NotifyOutput(const RefPtr<SourceMediaStream>& aStream, TrackID aTrackID,
StreamTime aCurrentTrackTime) {
void NotifyOutput(TrackID aTrackID, StreamTime aCurrentTrackTime) {
if (aTrackID != mAudioTrackID && mAudioTrackID != TRACK_NONE) {
// Only audio playout drives the clock forward, if present.
return;
}
if (aStream) {
mOnOutput.Notify(aStream->StreamTimeToMicroseconds(aCurrentTrackTime));
}
mOnOutput.Notify(mStream->StreamTimeToMicroseconds(aCurrentTrackTime));
}
TrackID AudioTrackID() const { return mAudioTrackID; }
@ -115,16 +113,21 @@ class DecodedStreamGraphListener {
}
void Forget() {
RefPtr<DecodedStreamGraphListener> self = this;
mAbstractMainThread->Dispatch(
NS_NewRunnableFunction("DecodedStreamGraphListener::Forget", [self]() {
MOZ_ASSERT(NS_IsMainThread());
self->mAudioEndedHolder.ResolveIfExists(false, __func__);
self->mVideoEndedHolder.ResolveIfExists(false, __func__);
}));
MutexAutoLock lock(mMutex);
MOZ_ASSERT(NS_IsMainThread());
if (mAudioTrackListener && !mStream->IsDestroyed()) {
mStream->EndTrack(mAudioTrackID);
mStream->RemoveTrackListener(mAudioTrackListener, mAudioTrackID);
}
mAudioTrackListener = nullptr;
mAudioEndedHolder.ResolveIfExists(false, __func__);
if (mVideoTrackListener && !mStream->IsDestroyed()) {
mStream->EndTrack(mVideoTrackID);
mStream->RemoveTrackListener(mVideoTrackListener, mVideoTrackID);
}
mVideoTrackListener = nullptr;
mVideoEndedHolder.ResolveIfExists(false, __func__);
}
MediaEventSource<int64_t>& OnOutput() { return mOnOutput; }
@ -137,16 +140,15 @@ class DecodedStreamGraphListener {
MediaEventProducer<int64_t> mOnOutput;
Mutex mMutex;
// Members below are protected by mMutex.
RefPtr<DecodedStreamTrackListener> mAudioTrackListener;
RefPtr<DecodedStreamTrackListener> mVideoTrackListener;
// Main thread only.
RefPtr<DecodedStreamTrackListener> mAudioTrackListener;
const TrackID mAudioTrackID;
MozPromiseHolder<DecodedStream::EndedPromise> mAudioEndedHolder;
RefPtr<DecodedStreamTrackListener> mVideoTrackListener;
const TrackID mVideoTrackID;
MozPromiseHolder<DecodedStream::EndedPromise> mVideoEndedHolder;
const RefPtr<SourceMediaStream> mStream;
const RefPtr<AbstractThread> mAbstractMainThread;
};
@ -157,7 +159,7 @@ DecodedStreamTrackListener::DecodedStreamTrackListener(
void DecodedStreamTrackListener::NotifyOutput(MediaStreamGraph* aGraph,
StreamTime aCurrentTrackTime) {
mGraphListener->NotifyOutput(mStream, mTrackID, aCurrentTrackTime);
mGraphListener->NotifyOutput(mTrackID, aCurrentTrackTime);
}
void DecodedStreamTrackListener::NotifyEnded() {
@ -450,7 +452,7 @@ void DecodedStream::Shutdown() {
mWatchManager.Shutdown();
}
void DecodedStream::DestroyData(UniquePtr<DecodedStreamData> aData) {
void DecodedStream::DestroyData(UniquePtr<DecodedStreamData>&& aData) {
AssertOwnerThread();
if (!aData) {
@ -459,11 +461,9 @@ void DecodedStream::DestroyData(UniquePtr<DecodedStreamData> aData) {
mOutputListener.Disconnect();
DecodedStreamData* data = aData.release();
data->Forget();
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("DecodedStream::DestroyData",
[=]() { delete data; });
NS_DispatchToMainThread(r.forget());
NS_DispatchToMainThread(
NS_NewRunnableFunction("DecodedStream::DestroyData",
[data = std::move(aData)]() { data->Forget(); }));
}
void DecodedStream::SetPlaying(bool aPlaying) {

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

@ -76,7 +76,7 @@ class DecodedStream : public MediaSink {
media::TimeUnit FromMicroseconds(int64_t aTime) {
return media::TimeUnit::FromMicroseconds(aTime);
}
void DestroyData(UniquePtr<DecodedStreamData> aData);
void DestroyData(UniquePtr<DecodedStreamData>&& aData);
void SendAudio(double aVolume, bool aIsSameOrigin,
const PrincipalHandle& aPrincipalHandle);
void SendVideo(bool aIsSameOrigin, const PrincipalHandle& aPrincipalHandle);

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

@ -767,6 +767,9 @@ skip-if = toolkit == 'android' # bug 1306916, bug 1329566, android(bug 1232305)
[test_bug1248229.html]
skip-if = android_version == '17' # bug 1306917, 1323778, android(bug 1232305)
tags=capturestream
[test_bug1512958.html]
skip-if = toolkit == 'android' # android(bug 1232305)
tags=msg capturestream
[test_can_play_type.html]
skip-if = (android_version == '23' && debug) || (android_version == '25' && debug) # android(bug 1232305)
[test_can_play_type_mpeg.html]

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

@ -0,0 +1,74 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test that pausing and resuming a captured media element with audio doesn't stall</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>
<audio id="a"></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
function dumpEvent({target, type}) {
info(`${target.name} GOT EVENT ${type} currentTime=${target.currentTime} ` +
`paused=${target.paused} ended=${target.ended} ` +
`readyState=${target.readyState}`);
}
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const a = document.getElementById('a');
const events = ["timeupdate", "seeking", "seeked", "ended", "playing", "pause"];
for (let ev of events) {
a.addEventListener(ev, dumpEvent);
}
(async _ => {
try {
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("Timeouts for shortcutting test-timeout");
const test = getPlayableAudio(gTrackTests.filter(t => t.duration > 2));
if (!test) {
todo(false, "No playable audio");
return;
}
// Start playing and capture
a.src = test.name;
a.name = test.name;
const ac = new AudioContext();
const src = ac.createMediaElementSource(a);
a.play();
do {
await new Promise(r => a.ontimeupdate = r);
} while(a.currentTime == 0)
// Pause to trigger recreating tracks in DecodedStream
a.pause();
await new Promise(r => a.onpause = r);
// Resuming should now work. Bug 1512958 would cause a stall because the
// original track wasn't ended and we'd block on it.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1512958#c5
a.play();
await new Promise(r => a.onplaying = r);
a.currentTime = test.duration - 1;
await Promise.race([
new Promise(res => a.onended = res),
wait(30000).then(_ => Promise.reject(new Error("Timeout"))),
]);
} catch(e) {
ok(false, e);
} finally {
SimpleTest.finish();
}
})();
</script>
</pre>
</body>
</html>

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

@ -11,6 +11,7 @@
#include <cstdint>
#include "mozilla/Attributes.h"
#include "Point.h"
#include "Rect.h"
#include "Types.h"
@ -33,7 +34,7 @@ namespace gfx {
* Do not use this class directly. Subclass it, pass that subclass as the
* Sub parameter, and only use that subclass.
*/
template <class T, class Sub, class Rect>
template <class T, class Sub, class Point, class Rect>
struct BaseRectAbsolute {
protected:
T left, top, right, bottom;
@ -238,17 +239,41 @@ struct BaseRectAbsolute {
left = static_cast<T>(ceil(double(left) / aXScale));
top = static_cast<T>(ceil(double(top) / aYScale));
}
/**
* Translate this rectangle to be inside aRect. If it doesn't fit inside
* aRect then the dimensions that don't fit will be shrunk so that they
* do fit. The resulting rect is returned.
*/
MOZ_MUST_USE Sub MoveInsideAndClamp(const Sub& aRect) const {
T newLeft = std::max(aRect.left, left);
T newTop = std::max(aRect.top, top);
T width = std::min(aRect.Width(), Width());
T height = std::min(aRect.Height(), Height());
Sub rect(newLeft, newTop, newLeft + width, newTop + height);
newLeft = std::min(rect.right, aRect.right) - width;
newTop = std::min(rect.bottom, aRect.bottom) - height;
rect.MoveBy(newLeft - rect.left, newTop - rect.top);
return rect;
}
friend std::ostream& operator<<(
std::ostream& stream,
const BaseRectAbsolute<T, Sub, Point, Rect>& aRect) {
return stream << '(' << aRect.left << ',' << aRect.top << ',' << aRect.right
<< ',' << aRect.bottom << ')';
}
};
template <class Units>
struct IntRectAbsoluteTyped
: public BaseRectAbsolute<int32_t, IntRectAbsoluteTyped<Units>,
IntRectTyped<Units>>,
IntPointTyped<Units>, IntRectTyped<Units>>,
public Units {
static_assert(IsPixel<Units>::value,
"'units' must be a coordinate system tag");
typedef BaseRectAbsolute<int32_t, IntRectAbsoluteTyped<Units>,
IntRectTyped<Units>>
IntPointTyped<Units>, IntRectTyped<Units>>
Super;
typedef IntParam<int32_t> ToInt;
@ -260,11 +285,12 @@ struct IntRectAbsoluteTyped
template <class Units>
struct RectAbsoluteTyped
: public BaseRectAbsolute<Float, RectAbsoluteTyped<Units>,
RectTyped<Units>>,
PointTyped<Units>, RectTyped<Units>>,
public Units {
static_assert(IsPixel<Units>::value,
"'units' must be a coordinate system tag");
typedef BaseRectAbsolute<Float, RectAbsoluteTyped<Units>, RectTyped<Units>>
typedef BaseRectAbsolute<Float, RectAbsoluteTyped<Units>, PointTyped<Units>,
RectTyped<Units>>
Super;
RectAbsoluteTyped() : Super() {}

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

@ -905,9 +905,6 @@ TransactionId LayerTransactionParent::FlushTransactionId(
// frame increases. This is effectively including the RecvUpdate work as
// part of the 'compositing' phase for this metric, but it isn't included in
// COMPOSITE_TIME, and *is* included in CONTENT_FULL_PAINT_TIME.
latencyMs = (aCompositeEnd - mRefreshStartTime).ToMilliseconds();
latencyNorm = latencyMs / mVsyncRate.ToMilliseconds();
fracLatencyNorm = lround(latencyNorm * 100.0);
if (fracLatencyNorm < 200) {
// Success
Telemetry::AccumulateCategorical(

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

@ -1976,10 +1976,6 @@ TransactionId WebRenderBridgeParent::FlushTransactionIdsForEpoch(
// Record CONTENT_FRAME_TIME_REASON.
//
// This uses the refresh start time (CONTENT_FRAME_TIME uses the start of
// display list building), since that includes layout/style time, and 200
// should correlate more closely with missing a vsync.
//
// Also of note is that when the root WebRenderBridgeParent decides to
// skip a composite (due to the Renderer being busy), that won't notify
// child WebRenderBridgeParents. That failure will show up as the
@ -1992,9 +1988,6 @@ TransactionId WebRenderBridgeParent::FlushTransactionIdsForEpoch(
// child pipelines contained within a render, after it finishes, but I
// can't see how to query what child pipeline would have been rendered,
// when we choose to not do it.
latencyMs = (aEndTime - transactionId.mRefreshStartTime).ToMilliseconds();
latencyNorm = latencyMs / mVsyncRate.ToMilliseconds();
fracLatencyNorm = lround(latencyNorm * 100.0);
if (fracLatencyNorm < 200) {
// Success
Telemetry::AccumulateCategorical(

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

@ -9,11 +9,15 @@
#include "mozilla/gfx/RectAbsolute.h"
#include "nsCoord.h"
#include "nsPoint.h"
#include "nsRect.h"
struct nsRectAbsolute
: public mozilla::gfx::BaseRectAbsolute<nscoord, nsRectAbsolute, nsRect> {
typedef mozilla::gfx::BaseRectAbsolute<nscoord, nsRectAbsolute, nsRect> Super;
: public mozilla::gfx::BaseRectAbsolute<nscoord, nsRectAbsolute, nsPoint,
nsRect> {
typedef mozilla::gfx::BaseRectAbsolute<nscoord, nsRectAbsolute, nsPoint,
nsRect>
Super;
nsRectAbsolute() : Super() {}
nsRectAbsolute(nscoord aX1, nscoord aY1, nscoord aX2, nscoord aY2)
@ -40,13 +44,6 @@ struct nsRectAbsolute
return Super::Union(aRect);
}
MOZ_ALWAYS_INLINE void MoveBy(const nsPoint& aPoint) {
left += aPoint.x;
right += aPoint.x;
top += aPoint.y;
bottom += aPoint.y;
}
void Inflate(const nsMargin& aMargin) {
left -= aMargin.left;
top -= aMargin.top;

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

@ -0,0 +1,14 @@
<style>
/*
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
*/
* {
position: sticky;
padding-right: 1px;
left: 2px;
right: 163px;
display: ruby-base;
}
</style>

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

@ -177,3 +177,4 @@ load 1505426-1.html
load 1508811.html
load 1508822.html
load 1509099.html
load 1496194.html

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

@ -599,3 +599,36 @@ TEST(Gfx, gfxRect) {
TestSetWH<gfxRect>();
TestSwap<gfxRect>();
}
static void TestMoveInsideAndClamp(IntRect aSrc, IntRect aTarget,
IntRect aExpected) {
// Test the implementation in BaseRect (x/y/width/height representation)
IntRect result = aSrc.MoveInsideAndClamp(aTarget);
EXPECT_TRUE(result.IsEqualEdges(aExpected))
<< "Source " << aSrc << " Target " << aTarget << " Expected " << aExpected
<< " Actual " << result;
// Also test the implementation in RectAbsolute (left/top/right/bottom
// representation)
IntRectAbsolute absSrc = IntRectAbsolute::FromRect(aSrc);
IntRectAbsolute absTarget = IntRectAbsolute::FromRect(aTarget);
IntRectAbsolute absExpected = IntRectAbsolute::FromRect(aExpected);
IntRectAbsolute absResult = absSrc.MoveInsideAndClamp(absTarget);
EXPECT_TRUE(absResult.IsEqualEdges(absExpected))
<< "AbsSource " << absSrc << " AbsTarget " << absTarget << " AbsExpected "
<< absExpected << " AbsActual " << absResult;
}
TEST(Gfx, MoveInsideAndClamp) {
TestMoveInsideAndClamp(IntRect(0, 0, 10, 10), IntRect(1, -1, 10, 10),
IntRect(1, -1, 10, 10));
TestMoveInsideAndClamp(IntRect(0, 0, 10, 10), IntRect(-1, -1, 12, 5),
IntRect(0, -1, 10, 5));
TestMoveInsideAndClamp(IntRect(0, 0, 10, 10), IntRect(10, 11, 10, 0),
IntRect(10, 11, 10, 0));
TestMoveInsideAndClamp(IntRect(0, 0, 10, 10), IntRect(-10, -1, 10, 0),
IntRect(-10, -1, 10, 0));
TestMoveInsideAndClamp(IntRect(0, 0, 0, 0), IntRect(10, -10, 10, 10),
IntRect(10, 0, 0, 0));
}

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

@ -320,6 +320,12 @@ void StickyScrollContainer::GetScrollRanges(nsIFrame* aFrame,
// Note that this doesn't necessarily solve all problems stemming from
// comparing pre- and post-collapsing margins (TODO: find a proper solution).
*aInner = aInner->Intersect(*aOuter);
if (aInner->IsEmpty()) {
// This might happen if aInner didn't intersect aOuter at all initially,
// in which case aInner is empty and outside aOuter. Make sure it doesn't
// extend outside aOuter.
*aInner = aInner->MoveInsideAndClamp(*aOuter);
}
}
void StickyScrollContainer::PositionContinuations(nsIFrame* aFrame) {

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

@ -1,6 +1,6 @@
lsan-allowed: [js_pod_malloc, js_pod_calloc, js_pod_realloc, js_arena_calloc,js_pod_arena_calloc, maybe_pod_calloc, pod_calloc, make_zeroed_pod_array, js_arena_malloc]
leak-threshold:
if webrender: [tab:10000, geckomediaplugin:20000, default:16000]
if webrender: [tab:10000, gpu: 10000, geckomediaplugin:20000, default:16000]
if os == "mac": [tab:10000, geckomediaplugin:20000, default:2000, rdd:400]
[tab:10000, geckomediaplugin:20000, rdd:400]