/* -*- 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/. */
staticvoid CheckProgressConsistency(Progress aOldProgress,
Progress aNewProgress, bool aIsMultipart) { // Check preconditions for every progress bit.
// Error's do not get propagated from the tracker for each image part to the // tracker for the multipart image because we don't want one bad part to // prevent the remaining parts from showing. So we need to consider whether // this is a tracker for a multipart image for these assertions to work.
if (aNewProgress & FLAG_SIZE_AVAILABLE) { // No preconditions.
} if (aNewProgress & FLAG_DECODE_COMPLETE) {
MOZ_ASSERT(aNewProgress & FLAG_SIZE_AVAILABLE);
MOZ_ASSERT(aIsMultipart ||
aNewProgress & (FLAG_FRAME_COMPLETE | FLAG_HAS_ERROR));
} if (aNewProgress & FLAG_FRAME_COMPLETE) {
MOZ_ASSERT(aNewProgress & FLAG_SIZE_AVAILABLE);
} if (aNewProgress & FLAG_LOAD_COMPLETE) {
MOZ_ASSERT(aIsMultipart ||
aNewProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
} if (aNewProgress & FLAG_IS_ANIMATED) { // No preconditions; like FLAG_HAS_TRANSPARENCY, we should normally never // discover this *after* FLAG_SIZE_AVAILABLE, but unfortunately some corrupt // GIFs may fool us.
} if (aNewProgress & FLAG_HAS_TRANSPARENCY) { // XXX We'd like to assert that transparency is only set during metadata // decode but we don't have any way to assert that until bug 1254892 is // fixed.
} if (aNewProgress & FLAG_LAST_PART_COMPLETE) {
MOZ_ASSERT(aNewProgress & FLAG_LOAD_COMPLETE);
} if (aNewProgress & FLAG_HAS_ERROR) { // No preconditions.
}
}
uint32_t ProgressTracker::GetImageStatus() const {
uint32_t status = imgIRequest::STATUS_NONE;
// Translate our current state to a set of imgIRequest::STATE_* flags. if (mProgress & FLAG_SIZE_AVAILABLE) {
status |= imgIRequest::STATUS_SIZE_AVAILABLE;
} if (mProgress & FLAG_DECODE_COMPLETE) {
status |= imgIRequest::STATUS_DECODE_COMPLETE;
} if (mProgress & FLAG_FRAME_COMPLETE) {
status |= imgIRequest::STATUS_FRAME_COMPLETE;
} if (mProgress & FLAG_LOAD_COMPLETE) {
status |= imgIRequest::STATUS_LOAD_COMPLETE;
} if (mProgress & FLAG_IS_ANIMATED) {
status |= imgIRequest::STATUS_IS_ANIMATED;
} if (mProgress & FLAG_HAS_TRANSPARENCY) {
status |= imgIRequest::STATUS_HAS_TRANSPARENCY;
} if (mProgress & FLAG_HAS_ERROR) {
status |= imgIRequest::STATUS_ERROR;
}
return status;
}
// A helper class to allow us to call SyncNotify asynchronously. class AsyncNotifyRunnable : public Runnable { public:
AsyncNotifyRunnable(ProgressTracker* aTracker, IProgressObserver* aObserver)
: Runnable("ProgressTracker::AsyncNotifyRunnable"), mTracker(aTracker) {
MOZ_ASSERT(NS_IsMainThread(), "Should be created on the main thread");
MOZ_ASSERT(aTracker, "aTracker should not be null");
MOZ_ASSERT(aObserver, "aObserver should not be null");
mObservers.AppendElement(aObserver);
}
NS_IMETHOD Run() override {
MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
MOZ_ASSERT(mTracker, "mTracker should not be null"); for (uint32_t i = 0; i < mObservers.Length(); ++i) {
mObservers[i]->ClearPendingNotify();
mTracker->SyncNotify(mObservers[i]);
}
// If we have an existing runnable that we can use, we just append this // observer to its list of observers to be notified. This ensures we don't // unnecessarily delay onload. if (mRunnable) {
mRunnable->AddObserver(aObserver);
} elseif (!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) { // Avoid dispatch if we are late in shutdown.
RefPtr<AsyncNotifyRunnable> ev = new AsyncNotifyRunnable(this, aObserver);
mRunnable = ProgressTracker::RenderBlockingRunnable::Create(ev.forget());
SchedulerGroup::Dispatch(do_AddRef(mRunnable));
}
}
// A helper class to allow us to call SyncNotify asynchronously for a given, // fixed, state. class AsyncNotifyCurrentStateRunnable : public Runnable { public:
AsyncNotifyCurrentStateRunnable(ProgressTracker* aProgressTracker,
IProgressObserver* aObserver)
: Runnable("image::AsyncNotifyCurrentStateRunnable"),
mProgressTracker(aProgressTracker),
mObserver(aObserver) {
MOZ_ASSERT(NS_IsMainThread(), "Should be created on the main thread");
MOZ_ASSERT(mProgressTracker, "mProgressTracker should not be null");
MOZ_ASSERT(mObserver, "mObserver should not be null");
mImage = mProgressTracker->GetImage();
}
NS_IMETHOD Run() override {
MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
mObserver->ClearPendingNotify();
// Avoid dispatch if we are late in shutdown. if (!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
nsCOMPtr<nsIRunnable> ev = new AsyncNotifyCurrentStateRunnable(this, aObserver);
SchedulerGroup::Dispatch(ev.forget());
}
}
/** * ImageObserverNotifier is a helper type that abstracts over the difference * between sending notifications to all of the observers in an ObserverTable, * and sending them to a single observer. This allows the same notification code * to be used for both cases.
*/ template <typename T> struct ImageObserverNotifier;
if (aHasImage) { // OnFrameUpdate // If there's any content in this frame at all (always true for // vector images, true for raster images that have decoded at // least one frame) then send OnFrameUpdate. if (!aDirtyRect.IsEmpty()) {
notify([&](IProgressObserver* aObs) {
aObs->Notify(I::FRAME_UPDATE, &aDirtyRect);
});
}
if (aProgress & FLAG_DECODE_COMPLETE) {
MOZ_ASSERT(aHasImage, "Stopped decoding without ever having an image?");
notify([](IProgressObserver* aObs) { aObs->Notify(I::DECODE_COMPLETE); });
}
nsIntRect rect; if (image) {
int32_t width, height; if (NS_FAILED(image->GetWidth(&width)) ||
NS_FAILED(image->GetHeight(&height))) { // Either the image has no intrinsic size, or it has an error.
rect = GetMaxSizedIntRect();
} else {
rect.SizeTo(width, height);
}
}
void ProgressTracker::EmulateRequestFinished(IProgressObserver* aObserver) {
MOZ_ASSERT(NS_IsMainThread(), "SyncNotifyState and mObservers are not threadsafe");
RefPtr<IProgressObserver> kungFuDeathGrip(aObserver);
if (!(mProgress & FLAG_LOAD_COMPLETE)) {
aObserver->OnLoadComplete(true);
}
}
// Remove the observer from the list. bool removed = mObservers.Write(
[observer](ObserverTable* aTable) { return aTable->Remove(observer); });
// Observers can get confused if they don't get all the proper teardown // notifications. Part ways on good terms. if (removed && !aObserver->NotificationsDeferred()) {
EmulateRequestFinished(aObserver);
}
// Make sure we don't give callbacks to an observer that isn't interested in // them any more. if (aObserver->NotificationsDeferred() && mRunnable) {
mRunnable->RemoveObserver(aObserver);
aObserver->ClearPendingNotify();
}
void ProgressTracker::OnImageAvailable() {
MOZ_ASSERT(NS_IsMainThread()); // Notify any imgRequestProxys that are observing us that we have an Image.
mObservers.Read([](const ObserverTable* aTable) {
ImageObserverNotifier<const ObserverTable*> notify(
aTable, /* aIgnoreDeferral = */ true);
notify([](IProgressObserver* aObs) { aObs->SetHasImage(); });
});
}
// Some kind of problem has happened with image decoding. // Report the URI to net:failed-to-process-uri-conent observers.
RefPtr<Image> image = GetImage(); if (image) { // Should be on main thread, so ok to create a new nsIURI.
nsCOMPtr<nsIURI> uri = image->GetURI(); if (uri) {
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); if (os) {
os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
}
}
}
}
} // namespace image
} // namespace mozilla
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
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.