merge mozilla-central to autoland. r=merge a=merge

This commit is contained in:
Sebastian Hengst 2017-03-26 20:58:51 +02:00
Родитель a8d1b9bde0 fcf7f0e64e
Коммит e475487dec
5 изменённых файлов: 116 добавлений и 57 удалений

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

@ -87,7 +87,11 @@ nsresult
GetOriginFromPrincipal(nsIPrincipal* aPrincipal, nsACString& aOrigin)
{
nsresult rv = aPrincipal->GetOriginNoSuffix(aOrigin);
NS_ENSURE_SUCCESS(rv, rv);
// The principal may belong to the about:blank content viewer, so this can be
// expected to fail.
if (NS_FAILED(rv)) {
return rv;
}
nsAutoCString suffix;
rv = aPrincipal->GetOriginSuffix(suffix);

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

@ -26,36 +26,80 @@ namespace image {
///////////////////////////////////////////////////////////////////////////////
void
AnimationState::NotifyDecodeComplete()
AnimationState::UpdateState(bool aAnimationFinished,
RasterImage *aImage,
const gfx::IntSize& aSize)
{
// If we weren't discarded before the decode finished then mark ourselves as
// currently decoded.
if (!mDiscarded) {
mIsCurrentlyDecoded = true;
LookupResult result =
SurfaceCache::Lookup(ImageKey(aImage),
RasterSurfaceKey(aSize,
DefaultSurfaceFlags(),
PlaybackType::eAnimated));
UpdateStateInternal(result, aAnimationFinished);
}
void
AnimationState::UpdateStateInternal(LookupResult& aResult,
bool aAnimationFinished)
{
// Update mDiscarded and mIsCurrentlyDecoded.
if (aResult.Type() == MatchType::NOT_FOUND) {
// no frames, we've either been discarded, or never been decoded before.
mDiscarded = mHasBeenDecoded;
mIsCurrentlyDecoded = false;
} else if (aResult.Type() == MatchType::PENDING) {
// no frames yet, but a decoder is or will be working on it.
mDiscarded = false;
mIsCurrentlyDecoded = false;
} else {
MOZ_ASSERT(aResult.Type() == MatchType::EXACT);
mDiscarded = false;
// If mHasBeenDecoded is true then we know the true total frame count and
// we can use it to determine if we have all the frames now so we know if
// we are currently fully decoded.
// If mHasBeenDecoded is false then we'll get another UpdateState call
// when the decode finishes.
if (mHasBeenDecoded) {
Maybe<uint32_t> frameCount = FrameCount();
MOZ_ASSERT(frameCount.isSome());
aResult.Surface().Seek(*frameCount - 1);
if (aResult.Surface() && aResult.Surface()->IsFinished()) {
mIsCurrentlyDecoded = true;
} else {
mIsCurrentlyDecoded = false;
}
}
}
// Update the value of mCompositedFrameInvalid.
if (mIsCurrentlyDecoded || aAnimationFinished) {
// Animated images that have finished their animation (ie because it is a
// finite length animation) don't have RequestRefresh called on them, and so
// mCompositedFrameInvalid would never get cleared. We clear it here (and
// also in RasterImage::Decode when we create a decoder for an image that
// has finished animated so it can display sooner than waiting until the
// decode completes). This is safe to do for images that aren't finished
// animating because before we paint the refresh driver will call into us
// to advance to the correct frame, and that will succeed because we have
// all the frames.
// decode completes). We also do it if we are fully decoded. This is safe
// to do for images that aren't finished animating because before we paint
// the refresh driver will call into us to advance to the correct frame,
// and that will succeed because we have all the frames.
mCompositedFrameInvalid = false;
} else if (aResult.Type() == MatchType::NOT_FOUND ||
aResult.Type() == MatchType::PENDING) {
if (mHasBeenDecoded) {
MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable());
mCompositedFrameInvalid = true;
}
}
mHasBeenDecoded = true;
// Otherwise don't change the value of mCompositedFrameInvalid, it will be
// updated by RequestRefresh.
}
void
AnimationState::SetDiscarded(bool aDiscarded)
AnimationState::NotifyDecodeComplete()
{
if (aDiscarded) {
MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable());
mIsCurrentlyDecoded = false;
mCompositedFrameInvalid = true;
}
mDiscarded = aDiscarded;
mHasBeenDecoded = true;
}
void
@ -307,7 +351,9 @@ FrameAnimator::AdvanceFrame(AnimationState& aState,
}
RefreshResult
FrameAnimator::RequestRefresh(AnimationState& aState, const TimeStamp& aTime)
FrameAnimator::RequestRefresh(AnimationState& aState,
const TimeStamp& aTime,
bool aAnimationFinished)
{
// By default, an empty RefreshResult.
RefreshResult ret;
@ -326,12 +372,8 @@ FrameAnimator::RequestRefresh(AnimationState& aState, const TimeStamp& aTime)
DefaultSurfaceFlags(),
PlaybackType::eAnimated));
if (!result) {
if (result.Type() == MatchType::NOT_FOUND) {
// No surface, and nothing pending, must have been discarded but
// we haven't been notified yet.
aState.SetDiscarded(true);
}
aState.UpdateStateInternal(result, aAnimationFinished);
if (aState.IsDiscarded() || !result) {
return ret;
}

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

@ -39,6 +39,19 @@ public:
, mDiscarded(false)
{ }
/**
* Call this whenever a decode completes, a decode starts, or the image is
* discarded. It will update the internal state. Specifically mDiscarded,
* mCompositedFrameInvalid, and mIsCurrentlyDecoded.
*/
void UpdateState(bool aAnimationFinished,
RasterImage *aImage,
const gfx::IntSize& aSize);
private:
void UpdateStateInternal(LookupResult& aResult,
bool aAnimationFinished);
public:
/**
* Call when a decode of this image has been completed.
*/
@ -49,12 +62,6 @@ public:
*/
bool GetHasBeenDecoded() { return mHasBeenDecoded; }
/**
* Call this with true when this image is discarded. Call this with false
* when a decoder is created to decode the image.
*/
void SetDiscarded(bool aDiscarded);
/**
* Returns true if this image has been discarded and a decoded has not yet
* been created to redecode it.
@ -276,7 +283,9 @@ public:
* Returns the result of that blending, including whether the current frame
* changed and what the resulting dirty rectangle is.
*/
RefreshResult RequestRefresh(AnimationState& aState, const TimeStamp& aTime);
RefreshResult RequestRefresh(AnimationState& aState,
const TimeStamp& aTime,
bool aAnimationFinished);
/**
* Get the full frame for the current frame of the animation (it may or may

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

@ -173,7 +173,7 @@ RasterImage::RequestRefresh(const TimeStamp& aTime)
RefreshResult res;
if (mAnimationState) {
MOZ_ASSERT(mFrameAnimator);
res = mFrameAnimator->RequestRefresh(*mAnimationState, aTime);
res = mFrameAnimator->RequestRefresh(*mAnimationState, aTime, mAnimationFinished);
}
if (res.mFrameAdvanced) {
@ -450,7 +450,7 @@ RasterImage::OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey)
if (animatedFramesDiscarded && NS_IsMainThread()) {
MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable());
mAnimationState->SetDiscarded(true);
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
// We don't need OnSurfaceDiscardedInternal to handle the animated frames
// being discarded because we just did.
animatedFramesDiscarded = false;
@ -471,7 +471,7 @@ RasterImage::OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded)
if (aAnimatedFramesDiscarded && mAnimationState) {
MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable());
mAnimationState->SetDiscarded(true);
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
}
if (mProgressTracker) {
@ -1081,7 +1081,7 @@ RasterImage::Discard()
SurfaceCache::RemoveImage(ImageKey(this));
if (mAnimationState) {
mAnimationState->SetDiscarded(true);
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
}
// Notify that we discarded.
@ -1253,10 +1253,10 @@ RasterImage::Decode(const IntSize& aSize,
task = DecoderFactory::CreateAnimationDecoder(mDecoderType, WrapNotNull(this),
mSourceBuffer, mSize,
decoderFlags, surfaceFlags);
mAnimationState->SetDiscarded(false);
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
// If the animation is finished we can draw right away because we just draw
// the final frame all the time from now on. See comment in
// AnimationState::NotifyDecodeComplete.
// AnimationState::UpdateState.
if (mAnimationFinished) {
mAnimationState->SetCompositedFrameInvalid(false);
}
@ -1717,6 +1717,7 @@ RasterImage::NotifyDecodeComplete(const DecoderFinalStatus& aStatus,
// We've finished a full decode of all animation frames and our AnimationState
// has been notified about them all, so let it know not to expect anymore.
mAnimationState->NotifyDecodeComplete();
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
}
// Do some telemetry if this isn't a metadata decode.

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

@ -131,6 +131,20 @@ NewPromiseAllDataHolder(JSContext* cx, HandleObject resultPromise, HandleValue v
return dataHolder;
}
/**
* Wrapper for GetAndClearException that handles cases where no exception is
* pending, but an error occurred. This can be the case if an OOM was
* encountered while throwing the error.
*/
static bool
MaybeGetAndClearException(JSContext* cx, MutableHandleValue rval)
{
if (!cx->isExceptionPending())
return false;
return GetAndClearException(cx, rval);
}
static MOZ_MUST_USE bool RunResolutionFunction(JSContext *cx, HandleObject resolutionFun,
HandleValue result, ResolutionMode mode,
HandleObject promiseObj);
@ -142,13 +156,9 @@ static MOZ_MUST_USE bool RunResolutionFunction(JSContext *cx, HandleObject resol
static bool
AbruptRejectPromise(JSContext *cx, CallArgs& args, HandleObject promiseObj, HandleObject reject)
{
// Not much we can do about uncatchable exceptions, so just bail.
if (!cx->isExceptionPending())
return false;
// Step 1.a.
RootedValue reason(cx);
if (!GetAndClearException(cx, &reason))
if (!MaybeGetAndClearException(cx, &reason))
return false;
if (!RunResolutionFunction(cx, reject, reason, RejectMode, promiseObj))
@ -351,7 +361,8 @@ ResolvePromiseInternal(JSContext* cx, HandleObject promise, HandleValue resoluti
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF);
RootedValue selfResolutionError(cx);
MOZ_ALWAYS_TRUE(GetAndClearException(cx, &selfResolutionError));
if (!MaybeGetAndClearException(cx, &selfResolutionError))
return false;
// Step 6.b.
return RejectMaybeWrappedPromise(cx, promise, selfResolutionError);
@ -364,7 +375,7 @@ ResolvePromiseInternal(JSContext* cx, HandleObject promise, HandleValue resoluti
// Step 9.
if (!status) {
RootedValue error(cx);
if (!GetAndClearException(cx, &error))
if (!MaybeGetAndClearException(cx, &error))
return false;
return RejectMaybeWrappedPromise(cx, promise, error);
@ -899,9 +910,7 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
args2[0].set(argument);
if (!Call(cx, handlerVal, UndefinedHandleValue, args2, &handlerResult)) {
resolutionMode = RejectMode;
// Not much we can do about uncatchable exceptions, so just bail
// for those.
if (!cx->isExceptionPending() || !GetAndClearException(cx, &handlerResult))
if (!MaybeGetAndClearException(cx, &handlerResult))
return false;
}
}
@ -978,7 +987,7 @@ PromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp)
if (Call(cx, then, thenable, args2, &rval))
return true;
if (!GetAndClearException(cx, &rval))
if (!MaybeGetAndClearException(cx, &rval))
return false;
FixedInvokeArgs<1> rejectArgs(cx);
@ -1321,9 +1330,7 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
// Step 10.
if (!success) {
RootedValue exceptionVal(cx);
// Not much we can do about uncatchable exceptions, so just bail
// for those.
if (!cx->isExceptionPending() || !GetAndClearException(cx, &exceptionVal))
if (!MaybeGetAndClearException(cx, &exceptionVal))
return nullptr;
FixedInvokeArgs<1> args(cx);
@ -2125,13 +2132,9 @@ js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal)
MOZ_MUST_USE bool
js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise)
{
// Not much we can do about uncatchable exceptions, so just bail.
if (!cx->isExceptionPending())
return false;
// Step 3.f.
RootedValue exc(cx);
if (!GetAndClearException(cx, &exc))
if (!MaybeGetAndClearException(cx, &exc))
return false;
if (!RejectMaybeWrappedPromise(cx, resultPromise, exc))