зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-central to autoland. r=merge a=merge
This commit is contained in:
Коммит
e475487dec
|
@ -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))
|
||||
|
|
Загрузка…
Ссылка в новой задаче