/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
void DecodedSurfaceProvider::DropImageReference() { if (!mImage) { return; // Nothing to do.
}
// RasterImage objects need to be destroyed on the main thread. We also need // to destroy them asynchronously, because if our surface cache entry is // destroyed and we were the only thing keeping |mImage| alive, RasterImage's // destructor may call into the surface cache while whatever code caused us to // get evicted is holding the surface cache lock, causing deadlock.
RefPtr<RasterImage> image = mImage;
mImage = nullptr;
SurfaceCache::ReleaseImageOnMainThread(image.forget(), /* aAlwaysProxy = */ true);
}
DrawableFrameRef DecodedSurfaceProvider::DrawableRef(size_t aFrame) {
MOZ_ASSERT(aFrame == 0, "Requesting an animation frame from a DecodedSurfaceProvider?");
// We depend on SurfaceCache::SurfaceAvailable() to provide synchronization // for methods that touch |mSurface|; after SurfaceAvailable() is called, // |mSurface| should be non-null and shouldn't be mutated further until we get // destroyed. That means that the assertions below are very important; we'll // end up with data races if these assumptions are violated. if (Availability().IsPlaceholder()) {
MOZ_ASSERT_UNREACHABLE("Calling DrawableRef() on a placeholder"); return DrawableFrameRef();
}
if (!mSurface) {
MOZ_ASSERT_UNREACHABLE("Calling DrawableRef() when we have no surface"); return DrawableFrameRef();
}
return mSurface->DrawableRef();
}
bool DecodedSurfaceProvider::IsFinished() const { // See DrawableRef() for commentary on these assertions. if (Availability().IsPlaceholder()) {
MOZ_ASSERT_UNREACHABLE("Calling IsFinished() on a placeholder"); returnfalse;
}
if (!mSurface) {
MOZ_ASSERT_UNREACHABLE("Calling IsFinished() when we have no surface"); returnfalse;
}
return mSurface->IsFinished();
}
void DecodedSurfaceProvider::SetLocked(bool aLocked) { // See DrawableRef() for commentary on these assertions. if (Availability().IsPlaceholder()) {
MOZ_ASSERT_UNREACHABLE("Calling SetLocked() on a placeholder"); return;
}
if (!mSurface) {
MOZ_ASSERT_UNREACHABLE("Calling SetLocked() when we have no surface"); return;
}
if (aLocked == IsLocked()) { return; // Nothing to do.
}
// If we're locked, hold a DrawableFrameRef to |mSurface|, which will keep any // volatile buffer it owns in memory.
mLockRef = aLocked ? mSurface->DrawableRef() : DrawableFrameRef();
}
if (!mDecoder || !mImage) {
MOZ_ASSERT_UNREACHABLE("Running after decoding finished?"); return;
}
// Run the decoder.
LexerResult result = mDecoder->Decode(WrapNotNull(this));
// If there's a new surface available, announce it to the surface cache.
CheckForNewSurface();
if (result.is<TerminalState>()) {
FinishDecoding(); return; // We're done.
}
// Notify for the progress we've made so far. if (mDecoder->HasProgress()) {
NotifyProgress(WrapNotNull(mImage), WrapNotNull(mDecoder));
}
MOZ_ASSERT(result.is<Yield>());
if (result == LexerResult(Yield::NEED_MORE_DATA)) { // We can't make any more progress right now. The decoder itself will ensure // that we get reenqueued when more data is available; just return for now. return;
}
// Single-frame images shouldn't yield for any reason except NEED_MORE_DATA.
MOZ_ASSERT_UNREACHABLE("Unexpected yield for single-frame image");
mDecoder->TerminateFailure();
FinishDecoding();
}
if (mSurface) { // Single-frame images should produce no more than one surface, so if we // have one, it should be the same one the decoder is working on.
MOZ_ASSERT(mSurface.get() == mDecoder->GetCurrentFrameRef().get(), "DecodedSurfaceProvider and Decoder have different surfaces?"); return;
}
// We don't have a surface yet; try to get one from the decoder.
mSurface = mDecoder->GetCurrentFrameRef().get(); if (!mSurface) { return; // No surface yet.
}
// We just got a surface for the first time; let the surface cache know.
MOZ_ASSERT(mImage);
SurfaceCache::SurfaceAvailable(WrapNotNull(this));
}
// If we have a new and complete surface, we can try to prune similarly sized // surfaces if the cache supports it. if (mSurface && mSurface->IsFinished()) {
SurfaceCache::PruneImage(ImageKey(mImage));
}
// Destroy our decoder; we don't need it anymore. (And if we don't destroy it, // our surface can never be optimized, because the decoder has a // RawAccessFrameRef to it.)
mDecoder = nullptr;
// We don't need a reference to our image anymore, either, and we don't want // one. We may be stored in the surface cache for a long time after decoding // finishes. If we don't drop our reference to the image, we'll end up // keeping it alive as long as we remain in the surface cache, which could // greatly extend the image's lifetime - in fact, if the image isn't // discardable, it'd result in a leak!
DropImageReference();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.