Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(684)

Unified Diff: third_party/WebKit/Source/core/loader/ImageLoader.cpp

Issue 1833303002: [Not committed] Make image load completion async and remove EventSender from ImageLoader (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@Loader_asyncImageLoadEvent_1
Patch Set: Rebase. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/loader/ImageLoader.cpp
diff --git a/third_party/WebKit/Source/core/loader/ImageLoader.cpp b/third_party/WebKit/Source/core/loader/ImageLoader.cpp
index 73e2f1916e24f1d0e1af09c5b445cbf6158a5b25..9df7ede1a445b78dde02cdef5b0b94e25b5fa52e 100644
--- a/third_party/WebKit/Source/core/loader/ImageLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/ImageLoader.cpp
@@ -30,7 +30,6 @@
#include "core/dom/Element.h"
#include "core/dom/IncrementLoadEventDelayCount.h"
#include "core/events/Event.h"
-#include "core/events/EventSender.h"
#include "core/fetch/FetchRequest.h"
#include "core/fetch/MemoryCache.h"
#include "core/fetch/ResourceFetcher.h"
@@ -48,22 +47,13 @@
#include "platform/Logging.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "platform/weborigin/SecurityPolicy.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebTaskRunner.h"
+#include "public/platform/WebTraceLocation.h"
#include "public/platform/WebURLRequest.h"
namespace blink {
-static ImageEventSender& loadEventSender()
-{
- DEFINE_STATIC_LOCAL(ImageEventSender, sender, (ImageEventSender::create(EventTypeNames::load)));
- return sender;
-}
-
-static ImageEventSender& errorEventSender()
-{
- DEFINE_STATIC_LOCAL(ImageEventSender, sender, (ImageEventSender::create(EventTypeNames::error)));
- return sender;
-}
-
static inline bool pageIsBeingDismissed(Document* document)
{
return document->pageDismissalEventBeingDispatched() != Document::NoDismissal;
@@ -149,8 +139,9 @@ private:
ImageLoader::ImageLoader(Element* element)
: m_element(element)
, m_derefElementTimer(this, &ImageLoader::timerFired)
+ , m_finishTask(CancellableTaskFactory::create(this, &ImageLoader::finish))
+ , m_dispatchErrorEventTask(CancellableTaskFactory::create(this, &ImageLoader::dispatchErrorEvent))
, m_hasPendingLoadEvent(false)
- , m_hasPendingErrorEvent(false)
, m_imageComplete(true)
, m_loadingImageDocument(false)
, m_elementIsProtected(false)
@@ -169,30 +160,39 @@ ImageLoader::~ImageLoader()
#endif
}
+void ImageLoader::cancelPendingFinish()
+{
+ if (m_loadDelayCounterForFinish) {
+ m_finishTask->cancel();
+ m_loadDelayCounterForFinish.clear();
+ }
+ m_hasPendingLoadEvent = false;
+}
+
+void ImageLoader::cancelPendingErrorEvent()
+{
+ if (m_loadDelayCounterForError) {
+ m_dispatchErrorEventTask->cancel();
+ m_loadDelayCounterForError.clear();
+ }
+}
+
void ImageLoader::dispose()
{
- WTF_LOG(Timers, "~ImageLoader %p; m_hasPendingLoadEvent=%d, m_hasPendingErrorEvent=%d",
- this, m_hasPendingLoadEvent, m_hasPendingErrorEvent);
+ WTF_LOG(Timers, "~ImageLoader %p; m_hasPendingLoadEvent=%d, hasPendingErrorEvent=%d",
+ this, m_hasPendingLoadEvent, hasPendingError());
#if !ENABLE(OILPAN)
- if (m_pendingTask)
- m_pendingTask->clearLoader();
+ if (m_pendingMicrotask)
+ m_pendingMicrotask->clearLoader();
#endif
if (m_image) {
m_image->removeObserver(this);
m_image = nullptr;
}
-
-#if !ENABLE(OILPAN)
- ASSERT(m_hasPendingLoadEvent || !loadEventSender().hasPendingEvents(this));
- if (m_hasPendingLoadEvent)
- loadEventSender().cancelEvent(this);
-
- ASSERT(m_hasPendingErrorEvent || !errorEventSender().hasPendingEvents(this));
- if (m_hasPendingErrorEvent)
- errorEventSender().cancelEvent(this);
-#endif
+ cancelPendingFinish();
+ cancelPendingErrorEvent();
}
DEFINE_TRACE(ImageLoader)
@@ -216,14 +216,8 @@ void ImageLoader::setImageWithoutConsideringPendingLoadEvent(ImageResource* newI
ImageResource* oldImage = m_image.get();
if (newImage != oldImage) {
m_image = newImage;
- if (m_hasPendingLoadEvent) {
- loadEventSender().cancelEvent(this);
- m_hasPendingLoadEvent = false;
- }
- if (m_hasPendingErrorEvent) {
- errorEventSender().cancelEvent(this);
- m_hasPendingErrorEvent = false;
- }
+ cancelPendingFinish();
+ cancelPendingErrorEvent();
m_imageComplete = true;
if (newImage) {
newImage->addObserver(this);
@@ -250,10 +244,10 @@ static void configureRequest(FetchRequest& request, ImageLoader::BypassMainWorld
request.setResourceWidth(toHTMLImageElement(element).getResourceWidth());
}
-inline void ImageLoader::dispatchErrorEvent()
+inline void ImageLoader::scheduleErrorEvent()
{
- m_hasPendingErrorEvent = true;
- errorEventSender().dispatchEventSoon(this);
+ m_loadDelayCounterForError = IncrementLoadEventDelayCount::create(m_element->document());
+ Platform::current()->currentThread()->getWebTaskRunner()->postTask(BLINK_FROM_HERE, m_dispatchErrorEventTask->cancelAndCreate());
}
inline void ImageLoader::crossSiteOrCSPViolationOccurred(AtomicString imageSourceURL)
@@ -269,9 +263,9 @@ inline void ImageLoader::clearFailedLoadURL()
inline void ImageLoader::enqueueImageLoadingMicroTask(UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
{
OwnPtr<Task> task = Task::create(this, updateBehavior, referrerPolicy);
- m_pendingTask = task->createWeakPtr();
+ m_pendingMicrotask = task->createWeakPtr();
Microtask::enqueueMicrotask(task.release());
- m_loadDelayCounter = IncrementLoadEventDelayCount::create(m_element->document());
+ m_loadDelayCounterForMicrotask = IncrementLoadEventDelayCount::create(m_element->document());
}
void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
@@ -283,11 +277,11 @@ void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up
//
// We don't need to call clearLoader here: Either we were called from the
// task, or our caller updateFromElement cleared the task's loader (and set
- // m_pendingTask to null).
- m_pendingTask.clear();
+ // m_pendingMicrotask to null).
+ m_pendingMicrotask.clear();
// Make sure to only decrement the count when we exit this function
OwnPtr<IncrementLoadEventDelayCount> loadDelayCounter;
- loadDelayCounter.swap(m_loadDelayCounter);
+ loadDelayCounter.swap(m_loadDelayCounterForMicrotask);
Document& document = m_element->document();
if (!document.isActive())
@@ -332,14 +326,14 @@ void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up
if (!newImage && !pageIsBeingDismissed(&document)) {
crossSiteOrCSPViolationOccurred(imageSourceURL);
- dispatchErrorEvent();
+ scheduleErrorEvent();
} else {
clearFailedLoadURL();
}
} else {
if (!imageSourceURL.isNull()) {
// Fire an error event if the url string is not empty, but the KURL is.
- dispatchErrorEvent();
+ scheduleErrorEvent();
}
noImageResourceToLoad();
}
@@ -348,19 +342,14 @@ void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up
if (updateBehavior == UpdateSizeChanged && m_element->layoutObject() && m_element->layoutObject()->isImage() && newImage == oldImage) {
toLayoutImage(m_element->layoutObject())->intrinsicSizeChanged();
} else {
- if (m_hasPendingLoadEvent) {
- loadEventSender().cancelEvent(this);
- m_hasPendingLoadEvent = false;
- }
+ cancelPendingFinish();
// Cancel error events that belong to the previous load, which is now cancelled by changing the src attribute.
- // If newImage is null and m_hasPendingErrorEvent is true, we know the error event has been just posted by
+ // If newImage is null and hasPendingError() is true, we know the error event has been just posted by
// this load and we should not cancel the event.
// FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two.
- if (m_hasPendingErrorEvent && newImage) {
- errorEventSender().cancelEvent(this);
- m_hasPendingErrorEvent = false;
- }
+ if (newImage)
+ cancelPendingErrorEvent();
m_image = newImage;
m_hasPendingLoadEvent = newImage;
@@ -398,9 +387,9 @@ void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior, Re
// If we have a pending task, we have to clear it -- either we're
// now loading immediately, or we need to reset the task's state.
- if (m_pendingTask) {
- m_pendingTask->clearLoader();
- m_pendingTask.clear();
+ if (m_pendingMicrotask) {
+ m_pendingMicrotask->clearLoader();
+ m_pendingMicrotask.clear();
}
KURL url = imageSourceToKURL(imageSourceURL);
@@ -416,6 +405,8 @@ void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior, Re
image->removeObserver(this);
}
m_image = nullptr;
+ cancelPendingFinish();
+ cancelPendingErrorEvent();
}
// Don't load images for inactive documents. We don't want to slow down the
@@ -465,45 +456,56 @@ void ImageLoader::imageNotifyFinished(ImageResource* resource)
ASSERT(m_failedLoadURL.isEmpty());
ASSERT(resource == m_image.get());
+ m_loadDelayCounterForFinish = IncrementLoadEventDelayCount::create(m_element->document());
+ Platform::current()->currentThread()->getWebTaskRunner()->postTask(BLINK_FROM_HERE, m_finishTask->cancelAndCreate());
+}
+
+void ImageLoader::finish()
+{
m_imageComplete = true;
+ ImageResource* imageResource = m_image.get();
+ ASSERT(imageResource);
- // Update ImageAnimationPolicy for m_image.
- if (m_image)
- m_image->updateImageAnimationPolicy();
+ // Update ImageAnimationPolicy for |imageResource|.
+ if (imageResource)
+ imageResource->updateImageAnimationPolicy();
updateLayoutObject();
- if (m_image && m_image->getImage() && m_image->getImage()->isSVGImage())
- toSVGImage(m_image->getImage())->updateUseCounters(element()->document());
+ if (imageResource && imageResource->getImage() && imageResource->getImage()->isSVGImage())
+ toSVGImage(imageResource->getImage())->updateUseCounters(element()->document());
- if (!m_hasPendingLoadEvent)
- return;
+ finishInternal(imageResource);
- if (resource->errorOccurred()) {
- loadEventSender().cancelEvent(this);
+ // Dispatches image's load/error event.
+ if (m_hasPendingLoadEvent) {
m_hasPendingLoadEvent = false;
- if (resource->resourceError().isAccessCheck())
- crossSiteOrCSPViolationOccurred(AtomicString(resource->resourceError().failingURL()));
+ if (imageResource->errorOccurred()) {
+ if (imageResource->resourceError().isAccessCheck())
+ crossSiteOrCSPViolationOccurred(AtomicString(imageResource->resourceError().failingURL()));
+
+ // The error event should not fire if the image data update is a result of environment change.
+ // https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element:the-img-element-55
+ if (!m_suppressErrorEvents)
+ dispatchErrorEventWithoutUpdatedHasPendingEvent();
+ } else if (!imageResource->wasCanceled()) {
+ if (element()->document().frame())
+ dispatchLoadEvent();
+ }
+ }
- // The error event should not fire if the image data update is a result of environment change.
- // https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element:the-img-element-55
- if (!m_suppressErrorEvents)
- dispatchErrorEvent();
+ // Dispatches document's load event if applicable.
+ // Calling checkCompleted() and document load event synchronously here has
+ // no problem regarding reentrancy because ImageLoader::finish() is
+ // always executed as a CancellableTask and not called by others.
+ m_loadDelayCounterForFinish.clear();
+ if (element()->document().frame())
+ element()->document().frame()->loader().checkCompleted();
- // Only consider updating the protection ref-count of the Element immediately before returning
- // from this function as doing so might result in the destruction of this ImageLoader.
- updatedHasPendingEvent();
- return;
- }
- if (resource->wasCanceled()) {
- m_hasPendingLoadEvent = false;
- // Only consider updating the protection ref-count of the Element immediately before returning
- // from this function as doing so might result in the destruction of this ImageLoader.
- updatedHasPendingEvent();
- return;
- }
- loadEventSender().dispatchEventSoon(this);
+ // Only consider updating the protection ref-count of the Element immediately before returning
+ // from this function as doing so might result in the destruction of this ImageLoader.
+ updatedHasPendingEvent();
}
LayoutImageResource* ImageLoader::layoutImageResource()
@@ -549,7 +551,7 @@ void ImageLoader::updatedHasPendingEvent()
// destroyed by DOM manipulation or garbage collection.
// If such an Element wishes for the load to stop when removed from the DOM it needs to stop the ImageLoader explicitly.
bool wasProtected = m_elementIsProtected;
- m_elementIsProtected = m_hasPendingLoadEvent || m_hasPendingErrorEvent;
+ m_elementIsProtected = m_hasPendingLoadEvent || hasPendingError();
if (wasProtected == m_elementIsProtected)
return;
@@ -569,40 +571,16 @@ void ImageLoader::timerFired(Timer<ImageLoader>*)
m_keepAlive.clear();
}
-void ImageLoader::dispatchPendingEvent(ImageEventSender* eventSender)
+void ImageLoader::dispatchErrorEventWithoutUpdatedHasPendingEvent()
{
- WTF_LOG(Timers, "ImageLoader::dispatchPendingEvent %p", this);
- ASSERT(eventSender == &loadEventSender() || eventSender == &errorEventSender());
- const AtomicString& eventType = eventSender->eventType();
- if (eventType == EventTypeNames::load)
- dispatchPendingLoadEvent();
- if (eventType == EventTypeNames::error)
- dispatchPendingErrorEvent();
-}
-
-void ImageLoader::dispatchPendingLoadEvent()
-{
- if (!m_hasPendingLoadEvent)
- return;
- if (!m_image)
- return;
- m_hasPendingLoadEvent = false;
if (element()->document().frame())
- dispatchLoadEvent();
-
- // Only consider updating the protection ref-count of the Element immediately before returning
- // from this function as doing so might result in the destruction of this ImageLoader.
- updatedHasPendingEvent();
+ element()->dispatchEvent(Event::create(EventTypeNames::error));
+ m_loadDelayCounterForError.clear();
}
-void ImageLoader::dispatchPendingErrorEvent()
+void ImageLoader::dispatchErrorEvent()
{
- if (!m_hasPendingErrorEvent)
- return;
- m_hasPendingErrorEvent = false;
-
- if (element()->document().frame())
- element()->dispatchEvent(Event::create(EventTypeNames::error));
+ dispatchErrorEventWithoutUpdatedHasPendingEvent();
// Only consider updating the protection ref-count of the Element immediately before returning
// from this function as doing so might result in the destruction of this ImageLoader.
@@ -618,20 +596,14 @@ bool ImageLoader::getImageAnimationPolicy(ImageAnimationPolicy& policy)
return true;
}
-void ImageLoader::dispatchPendingLoadEvents()
-{
- loadEventSender().dispatchPendingEvents();
-}
-
-void ImageLoader::dispatchPendingErrorEvents()
-{
- errorEventSender().dispatchPendingEvents();
-}
-
void ImageLoader::elementDidMoveToNewDocument()
{
- if (m_loadDelayCounter)
- m_loadDelayCounter->documentChanged(m_element->document());
+ if (m_loadDelayCounterForMicrotask)
+ m_loadDelayCounterForMicrotask->documentChanged(m_element->document());
+ if (m_loadDelayCounterForFinish)
+ m_loadDelayCounterForFinish->documentChanged(m_element->document());
+ if (m_loadDelayCounterForError)
+ m_loadDelayCounterForError->documentChanged(m_element->document());
clearFailedLoadURL();
setImage(0);
}
« no previous file with comments | « third_party/WebKit/Source/core/loader/ImageLoader.h ('k') | third_party/WebKit/Source/web/tests/sim/SimRequest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698