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

Side by Side 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 Apple Inc. All rights reserv ed. 4 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 Apple Inc. All rights reserv ed.
5 * 5 *
6 * This library is free software; you can redistribute it and/or 6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public 7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either 8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version. 9 * version 2 of the License, or (at your option) any later version.
10 * 10 *
(...skipping 12 matching lines...) Expand all
23 23
24 #include "bindings/core/v8/Microtask.h" 24 #include "bindings/core/v8/Microtask.h"
25 #include "bindings/core/v8/ScriptController.h" 25 #include "bindings/core/v8/ScriptController.h"
26 #include "bindings/core/v8/ScriptState.h" 26 #include "bindings/core/v8/ScriptState.h"
27 #include "bindings/core/v8/V8Binding.h" 27 #include "bindings/core/v8/V8Binding.h"
28 #include "bindings/core/v8/V8PerIsolateData.h" 28 #include "bindings/core/v8/V8PerIsolateData.h"
29 #include "core/dom/Document.h" 29 #include "core/dom/Document.h"
30 #include "core/dom/Element.h" 30 #include "core/dom/Element.h"
31 #include "core/dom/IncrementLoadEventDelayCount.h" 31 #include "core/dom/IncrementLoadEventDelayCount.h"
32 #include "core/events/Event.h" 32 #include "core/events/Event.h"
33 #include "core/events/EventSender.h"
34 #include "core/fetch/FetchRequest.h" 33 #include "core/fetch/FetchRequest.h"
35 #include "core/fetch/MemoryCache.h" 34 #include "core/fetch/MemoryCache.h"
36 #include "core/fetch/ResourceFetcher.h" 35 #include "core/fetch/ResourceFetcher.h"
37 #include "core/frame/LocalFrame.h" 36 #include "core/frame/LocalFrame.h"
38 #include "core/frame/Settings.h" 37 #include "core/frame/Settings.h"
39 #include "core/frame/UseCounter.h" 38 #include "core/frame/UseCounter.h"
40 #include "core/html/CrossOriginAttribute.h" 39 #include "core/html/CrossOriginAttribute.h"
41 #include "core/html/HTMLImageElement.h" 40 #include "core/html/HTMLImageElement.h"
42 #include "core/html/parser/HTMLParserIdioms.h" 41 #include "core/html/parser/HTMLParserIdioms.h"
43 #include "core/inspector/InspectorInstrumentation.h" 42 #include "core/inspector/InspectorInstrumentation.h"
44 #include "core/layout/LayoutImage.h" 43 #include "core/layout/LayoutImage.h"
45 #include "core/layout/LayoutVideo.h" 44 #include "core/layout/LayoutVideo.h"
46 #include "core/layout/svg/LayoutSVGImage.h" 45 #include "core/layout/svg/LayoutSVGImage.h"
47 #include "core/svg/graphics/SVGImage.h" 46 #include "core/svg/graphics/SVGImage.h"
48 #include "platform/Logging.h" 47 #include "platform/Logging.h"
49 #include "platform/weborigin/SecurityOrigin.h" 48 #include "platform/weborigin/SecurityOrigin.h"
50 #include "platform/weborigin/SecurityPolicy.h" 49 #include "platform/weborigin/SecurityPolicy.h"
50 #include "public/platform/Platform.h"
51 #include "public/platform/WebTaskRunner.h"
52 #include "public/platform/WebTraceLocation.h"
51 #include "public/platform/WebURLRequest.h" 53 #include "public/platform/WebURLRequest.h"
52 54
53 namespace blink { 55 namespace blink {
54 56
55 static ImageEventSender& loadEventSender()
56 {
57 DEFINE_STATIC_LOCAL(ImageEventSender, sender, (ImageEventSender::create(Even tTypeNames::load)));
58 return sender;
59 }
60
61 static ImageEventSender& errorEventSender()
62 {
63 DEFINE_STATIC_LOCAL(ImageEventSender, sender, (ImageEventSender::create(Even tTypeNames::error)));
64 return sender;
65 }
66
67 static inline bool pageIsBeingDismissed(Document* document) 57 static inline bool pageIsBeingDismissed(Document* document)
68 { 58 {
69 return document->pageDismissalEventBeingDispatched() != Document::NoDismissa l; 59 return document->pageDismissalEventBeingDispatched() != Document::NoDismissa l;
70 } 60 }
71 61
72 static ImageLoader::BypassMainWorldBehavior shouldBypassMainWorldCSP(ImageLoader * loader) 62 static ImageLoader::BypassMainWorldBehavior shouldBypassMainWorldCSP(ImageLoader * loader)
73 { 63 {
74 ASSERT(loader); 64 ASSERT(loader);
75 ASSERT(loader->element()); 65 ASSERT(loader->element());
76 if (loader->element()->document().frame() && loader->element()->document().f rame()->script().shouldBypassMainWorldCSP()) 66 if (loader->element()->document().frame() && loader->element()->document().f rame()->script().shouldBypassMainWorldCSP())
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 UpdateFromElementBehavior m_updateBehavior; 132 UpdateFromElementBehavior m_updateBehavior;
143 RefPtr<ScriptState> m_scriptState; 133 RefPtr<ScriptState> m_scriptState;
144 WeakPtrFactory<Task> m_weakFactory; 134 WeakPtrFactory<Task> m_weakFactory;
145 ReferrerPolicy m_referrerPolicy; 135 ReferrerPolicy m_referrerPolicy;
146 int m_operationId; 136 int m_operationId;
147 }; 137 };
148 138
149 ImageLoader::ImageLoader(Element* element) 139 ImageLoader::ImageLoader(Element* element)
150 : m_element(element) 140 : m_element(element)
151 , m_derefElementTimer(this, &ImageLoader::timerFired) 141 , m_derefElementTimer(this, &ImageLoader::timerFired)
142 , m_finishTask(CancellableTaskFactory::create(this, &ImageLoader::finish))
143 , m_dispatchErrorEventTask(CancellableTaskFactory::create(this, &ImageLoader ::dispatchErrorEvent))
152 , m_hasPendingLoadEvent(false) 144 , m_hasPendingLoadEvent(false)
153 , m_hasPendingErrorEvent(false)
154 , m_imageComplete(true) 145 , m_imageComplete(true)
155 , m_loadingImageDocument(false) 146 , m_loadingImageDocument(false)
156 , m_elementIsProtected(false) 147 , m_elementIsProtected(false)
157 , m_suppressErrorEvents(false) 148 , m_suppressErrorEvents(false)
158 { 149 {
159 WTF_LOG(Timers, "new ImageLoader %p", this); 150 WTF_LOG(Timers, "new ImageLoader %p", this);
160 #if ENABLE(OILPAN) 151 #if ENABLE(OILPAN)
161 ThreadState::current()->registerPreFinalizer(this); 152 ThreadState::current()->registerPreFinalizer(this);
162 #endif 153 #endif
163 } 154 }
164 155
165 ImageLoader::~ImageLoader() 156 ImageLoader::~ImageLoader()
166 { 157 {
167 #if !ENABLE(OILPAN) 158 #if !ENABLE(OILPAN)
168 dispose(); 159 dispose();
169 #endif 160 #endif
170 } 161 }
171 162
163 void ImageLoader::cancelPendingFinish()
164 {
165 if (m_loadDelayCounterForFinish) {
166 m_finishTask->cancel();
167 m_loadDelayCounterForFinish.clear();
168 }
169 m_hasPendingLoadEvent = false;
170 }
171
172 void ImageLoader::cancelPendingErrorEvent()
173 {
174 if (m_loadDelayCounterForError) {
175 m_dispatchErrorEventTask->cancel();
176 m_loadDelayCounterForError.clear();
177 }
178 }
179
172 void ImageLoader::dispose() 180 void ImageLoader::dispose()
173 { 181 {
174 WTF_LOG(Timers, "~ImageLoader %p; m_hasPendingLoadEvent=%d, m_hasPendingErro rEvent=%d", 182 WTF_LOG(Timers, "~ImageLoader %p; m_hasPendingLoadEvent=%d, hasPendingErrorE vent=%d",
175 this, m_hasPendingLoadEvent, m_hasPendingErrorEvent); 183 this, m_hasPendingLoadEvent, hasPendingError());
176 184
177 #if !ENABLE(OILPAN) 185 #if !ENABLE(OILPAN)
178 if (m_pendingTask) 186 if (m_pendingMicrotask)
179 m_pendingTask->clearLoader(); 187 m_pendingMicrotask->clearLoader();
180 #endif 188 #endif
181 189
182 if (m_image) { 190 if (m_image) {
183 m_image->removeObserver(this); 191 m_image->removeObserver(this);
184 m_image = nullptr; 192 m_image = nullptr;
185 } 193 }
186 194 cancelPendingFinish();
187 #if !ENABLE(OILPAN) 195 cancelPendingErrorEvent();
188 ASSERT(m_hasPendingLoadEvent || !loadEventSender().hasPendingEvents(this));
189 if (m_hasPendingLoadEvent)
190 loadEventSender().cancelEvent(this);
191
192 ASSERT(m_hasPendingErrorEvent || !errorEventSender().hasPendingEvents(this)) ;
193 if (m_hasPendingErrorEvent)
194 errorEventSender().cancelEvent(this);
195 #endif
196 } 196 }
197 197
198 DEFINE_TRACE(ImageLoader) 198 DEFINE_TRACE(ImageLoader)
199 { 199 {
200 visitor->trace(m_image); 200 visitor->trace(m_image);
201 visitor->trace(m_element); 201 visitor->trace(m_element);
202 } 202 }
203 203
204 void ImageLoader::setImage(ImageResource* newImage) 204 void ImageLoader::setImage(ImageResource* newImage)
205 { 205 {
206 setImageWithoutConsideringPendingLoadEvent(newImage); 206 setImageWithoutConsideringPendingLoadEvent(newImage);
207 207
208 // Only consider updating the protection ref-count of the Element immediatel y before returning 208 // Only consider updating the protection ref-count of the Element immediatel y before returning
209 // from this function as doing so might result in the destruction of this Im ageLoader. 209 // from this function as doing so might result in the destruction of this Im ageLoader.
210 updatedHasPendingEvent(); 210 updatedHasPendingEvent();
211 } 211 }
212 212
213 void ImageLoader::setImageWithoutConsideringPendingLoadEvent(ImageResource* newI mage) 213 void ImageLoader::setImageWithoutConsideringPendingLoadEvent(ImageResource* newI mage)
214 { 214 {
215 ASSERT(m_failedLoadURL.isEmpty()); 215 ASSERT(m_failedLoadURL.isEmpty());
216 ImageResource* oldImage = m_image.get(); 216 ImageResource* oldImage = m_image.get();
217 if (newImage != oldImage) { 217 if (newImage != oldImage) {
218 m_image = newImage; 218 m_image = newImage;
219 if (m_hasPendingLoadEvent) { 219 cancelPendingFinish();
220 loadEventSender().cancelEvent(this); 220 cancelPendingErrorEvent();
221 m_hasPendingLoadEvent = false;
222 }
223 if (m_hasPendingErrorEvent) {
224 errorEventSender().cancelEvent(this);
225 m_hasPendingErrorEvent = false;
226 }
227 m_imageComplete = true; 221 m_imageComplete = true;
228 if (newImage) { 222 if (newImage) {
229 newImage->addObserver(this); 223 newImage->addObserver(this);
230 } 224 }
231 if (oldImage) { 225 if (oldImage) {
232 oldImage->removeObserver(this); 226 oldImage->removeObserver(this);
233 } 227 }
234 } 228 }
235 229
236 if (LayoutImageResource* imageResource = layoutImageResource()) 230 if (LayoutImageResource* imageResource = layoutImageResource())
237 imageResource->resetAnimation(); 231 imageResource->resetAnimation();
238 } 232 }
239 233
240 static void configureRequest(FetchRequest& request, ImageLoader::BypassMainWorld Behavior bypassBehavior, Element& element, const ClientHintsPreferences& clientH intsPreferences) 234 static void configureRequest(FetchRequest& request, ImageLoader::BypassMainWorld Behavior bypassBehavior, Element& element, const ClientHintsPreferences& clientH intsPreferences)
241 { 235 {
242 if (bypassBehavior == ImageLoader::BypassMainWorldCSP) 236 if (bypassBehavior == ImageLoader::BypassMainWorldCSP)
243 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy); 237 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy);
244 238
245 CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue(element.fa stGetAttribute(HTMLNames::crossoriginAttr)); 239 CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue(element.fa stGetAttribute(HTMLNames::crossoriginAttr));
246 if (crossOrigin != CrossOriginAttributeNotSet) 240 if (crossOrigin != CrossOriginAttributeNotSet)
247 request.setCrossOriginAccessControl(element.document().getSecurityOrigin (), crossOrigin); 241 request.setCrossOriginAccessControl(element.document().getSecurityOrigin (), crossOrigin);
248 242
249 if (clientHintsPreferences.shouldSendResourceWidth() && isHTMLImageElement(e lement)) 243 if (clientHintsPreferences.shouldSendResourceWidth() && isHTMLImageElement(e lement))
250 request.setResourceWidth(toHTMLImageElement(element).getResourceWidth()) ; 244 request.setResourceWidth(toHTMLImageElement(element).getResourceWidth()) ;
251 } 245 }
252 246
253 inline void ImageLoader::dispatchErrorEvent() 247 inline void ImageLoader::scheduleErrorEvent()
254 { 248 {
255 m_hasPendingErrorEvent = true; 249 m_loadDelayCounterForError = IncrementLoadEventDelayCount::create(m_element- >document());
256 errorEventSender().dispatchEventSoon(this); 250 Platform::current()->currentThread()->getWebTaskRunner()->postTask(BLINK_FRO M_HERE, m_dispatchErrorEventTask->cancelAndCreate());
257 } 251 }
258 252
259 inline void ImageLoader::crossSiteOrCSPViolationOccurred(AtomicString imageSourc eURL) 253 inline void ImageLoader::crossSiteOrCSPViolationOccurred(AtomicString imageSourc eURL)
260 { 254 {
261 m_failedLoadURL = imageSourceURL; 255 m_failedLoadURL = imageSourceURL;
262 } 256 }
263 257
264 inline void ImageLoader::clearFailedLoadURL() 258 inline void ImageLoader::clearFailedLoadURL()
265 { 259 {
266 m_failedLoadURL = AtomicString(); 260 m_failedLoadURL = AtomicString();
267 } 261 }
268 262
269 inline void ImageLoader::enqueueImageLoadingMicroTask(UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy) 263 inline void ImageLoader::enqueueImageLoadingMicroTask(UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
270 { 264 {
271 OwnPtr<Task> task = Task::create(this, updateBehavior, referrerPolicy); 265 OwnPtr<Task> task = Task::create(this, updateBehavior, referrerPolicy);
272 m_pendingTask = task->createWeakPtr(); 266 m_pendingMicrotask = task->createWeakPtr();
273 Microtask::enqueueMicrotask(task.release()); 267 Microtask::enqueueMicrotask(task.release());
274 m_loadDelayCounter = IncrementLoadEventDelayCount::create(m_element->documen t()); 268 m_loadDelayCounterForMicrotask = IncrementLoadEventDelayCount::create(m_elem ent->document());
275 } 269 }
276 270
277 void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up dateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy) 271 void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up dateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
278 { 272 {
279 // FIXME: According to 273 // FIXME: According to
280 // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-cont ent.html#the-img-element:the-img-element-55 274 // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-cont ent.html#the-img-element:the-img-element-55
281 // When "update image" is called due to environment changes and the load fai ls, onerror should not be called. 275 // When "update image" is called due to environment changes and the load fai ls, onerror should not be called.
282 // That is currently not the case. 276 // That is currently not the case.
283 // 277 //
284 // We don't need to call clearLoader here: Either we were called from the 278 // We don't need to call clearLoader here: Either we were called from the
285 // task, or our caller updateFromElement cleared the task's loader (and set 279 // task, or our caller updateFromElement cleared the task's loader (and set
286 // m_pendingTask to null). 280 // m_pendingMicrotask to null).
287 m_pendingTask.clear(); 281 m_pendingMicrotask.clear();
288 // Make sure to only decrement the count when we exit this function 282 // Make sure to only decrement the count when we exit this function
289 OwnPtr<IncrementLoadEventDelayCount> loadDelayCounter; 283 OwnPtr<IncrementLoadEventDelayCount> loadDelayCounter;
290 loadDelayCounter.swap(m_loadDelayCounter); 284 loadDelayCounter.swap(m_loadDelayCounterForMicrotask);
291 285
292 Document& document = m_element->document(); 286 Document& document = m_element->document();
293 if (!document.isActive()) 287 if (!document.isActive())
294 return; 288 return;
295 289
296 AtomicString imageSourceURL = m_element->imageSourceURL(); 290 AtomicString imageSourceURL = m_element->imageSourceURL();
297 KURL url = imageSourceToKURL(imageSourceURL); 291 KURL url = imageSourceToKURL(imageSourceURL);
298 RawPtr<ImageResource> newImage = nullptr; 292 RawPtr<ImageResource> newImage = nullptr;
299 RawPtr<Element> protectElement(m_element.get()); 293 RawPtr<Element> protectElement(m_element.get());
300 if (!url.isNull()) { 294 if (!url.isNull()) {
(...skipping 24 matching lines...) Expand all
325 request.setDefer(FetchRequest::DeferredByClient); 319 request.setDefer(FetchRequest::DeferredByClient);
326 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy); 320 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy);
327 } 321 }
328 322
329 newImage = ImageResource::fetch(request, document.fetcher()); 323 newImage = ImageResource::fetch(request, document.fetcher());
330 if (m_loadingImageDocument && newImage) 324 if (m_loadingImageDocument && newImage)
331 newImage->setStatus(Resource::Pending); 325 newImage->setStatus(Resource::Pending);
332 326
333 if (!newImage && !pageIsBeingDismissed(&document)) { 327 if (!newImage && !pageIsBeingDismissed(&document)) {
334 crossSiteOrCSPViolationOccurred(imageSourceURL); 328 crossSiteOrCSPViolationOccurred(imageSourceURL);
335 dispatchErrorEvent(); 329 scheduleErrorEvent();
336 } else { 330 } else {
337 clearFailedLoadURL(); 331 clearFailedLoadURL();
338 } 332 }
339 } else { 333 } else {
340 if (!imageSourceURL.isNull()) { 334 if (!imageSourceURL.isNull()) {
341 // Fire an error event if the url string is not empty, but the KURL is. 335 // Fire an error event if the url string is not empty, but the KURL is.
342 dispatchErrorEvent(); 336 scheduleErrorEvent();
343 } 337 }
344 noImageResourceToLoad(); 338 noImageResourceToLoad();
345 } 339 }
346 340
347 RawPtr<ImageResource> oldImage = m_image.get(); 341 RawPtr<ImageResource> oldImage = m_image.get();
348 if (updateBehavior == UpdateSizeChanged && m_element->layoutObject() && m_el ement->layoutObject()->isImage() && newImage == oldImage) { 342 if (updateBehavior == UpdateSizeChanged && m_element->layoutObject() && m_el ement->layoutObject()->isImage() && newImage == oldImage) {
349 toLayoutImage(m_element->layoutObject())->intrinsicSizeChanged(); 343 toLayoutImage(m_element->layoutObject())->intrinsicSizeChanged();
350 } else { 344 } else {
351 if (m_hasPendingLoadEvent) { 345 cancelPendingFinish();
352 loadEventSender().cancelEvent(this);
353 m_hasPendingLoadEvent = false;
354 }
355 346
356 // Cancel error events that belong to the previous load, which is now ca ncelled by changing the src attribute. 347 // Cancel error events that belong to the previous load, which is now ca ncelled by changing the src attribute.
357 // If newImage is null and m_hasPendingErrorEvent is true, we know the e rror event has been just posted by 348 // If newImage is null and hasPendingError() is true, we know the error event has been just posted by
358 // this load and we should not cancel the event. 349 // this load and we should not cancel the event.
359 // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two. 350 // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two.
360 if (m_hasPendingErrorEvent && newImage) { 351 if (newImage)
361 errorEventSender().cancelEvent(this); 352 cancelPendingErrorEvent();
362 m_hasPendingErrorEvent = false;
363 }
364 353
365 m_image = newImage; 354 m_image = newImage;
366 m_hasPendingLoadEvent = newImage; 355 m_hasPendingLoadEvent = newImage;
367 m_imageComplete = !newImage; 356 m_imageComplete = !newImage;
368 357
369 updateLayoutObject(); 358 updateLayoutObject();
370 // If newImage exists and is cached, addObserver() will result in the lo ad event 359 // If newImage exists and is cached, addObserver() will result in the lo ad event
371 // being queued to fire. Ensure this happens after beforeload is dispatc hed. 360 // being queued to fire. Ensure this happens after beforeload is dispatc hed.
372 if (newImage) { 361 if (newImage) {
373 newImage->addObserver(this); 362 newImage->addObserver(this);
(...skipping 17 matching lines...) Expand all
391 m_suppressErrorEvents = (updateBehavior == UpdateSizeChanged); 380 m_suppressErrorEvents = (updateBehavior == UpdateSizeChanged);
392 381
393 if (updateBehavior == UpdateIgnorePreviousError) 382 if (updateBehavior == UpdateIgnorePreviousError)
394 clearFailedLoadURL(); 383 clearFailedLoadURL();
395 384
396 if (!m_failedLoadURL.isEmpty() && imageSourceURL == m_failedLoadURL) 385 if (!m_failedLoadURL.isEmpty() && imageSourceURL == m_failedLoadURL)
397 return; 386 return;
398 387
399 // If we have a pending task, we have to clear it -- either we're 388 // If we have a pending task, we have to clear it -- either we're
400 // now loading immediately, or we need to reset the task's state. 389 // now loading immediately, or we need to reset the task's state.
401 if (m_pendingTask) { 390 if (m_pendingMicrotask) {
402 m_pendingTask->clearLoader(); 391 m_pendingMicrotask->clearLoader();
403 m_pendingTask.clear(); 392 m_pendingMicrotask.clear();
404 } 393 }
405 394
406 KURL url = imageSourceToKURL(imageSourceURL); 395 KURL url = imageSourceToKURL(imageSourceURL);
407 if (shouldLoadImmediately(url)) { 396 if (shouldLoadImmediately(url)) {
408 doUpdateFromElement(DoNotBypassMainWorldCSP, updateBehavior, referrerPol icy); 397 doUpdateFromElement(DoNotBypassMainWorldCSP, updateBehavior, referrerPol icy);
409 return; 398 return;
410 } 399 }
411 // Allow the idiom "img.src=''; img.src='.." to clear down the image before 400 // Allow the idiom "img.src=''; img.src='.." to clear down the image before
412 // an asynchronous load completes. 401 // an asynchronous load completes.
413 if (imageSourceURL.isEmpty()) { 402 if (imageSourceURL.isEmpty()) {
414 ImageResource* image = m_image.get(); 403 ImageResource* image = m_image.get();
415 if (image) { 404 if (image) {
416 image->removeObserver(this); 405 image->removeObserver(this);
417 } 406 }
418 m_image = nullptr; 407 m_image = nullptr;
408 cancelPendingFinish();
409 cancelPendingErrorEvent();
419 } 410 }
420 411
421 // Don't load images for inactive documents. We don't want to slow down the 412 // Don't load images for inactive documents. We don't want to slow down the
422 // raw HTML parsing case by loading images we don't intend to display. 413 // raw HTML parsing case by loading images we don't intend to display.
423 Document& document = m_element->document(); 414 Document& document = m_element->document();
424 if (document.isActive()) 415 if (document.isActive())
425 enqueueImageLoadingMicroTask(updateBehavior, referrerPolicy); 416 enqueueImageLoadingMicroTask(updateBehavior, referrerPolicy);
426 } 417 }
427 418
428 KURL ImageLoader::imageSourceToKURL(AtomicString imageSourceURL) const 419 KURL ImageLoader::imageSourceToKURL(AtomicString imageSourceURL) const
(...skipping 29 matching lines...) Expand all
458 } 449 }
459 450
460 void ImageLoader::imageNotifyFinished(ImageResource* resource) 451 void ImageLoader::imageNotifyFinished(ImageResource* resource)
461 { 452 {
462 WTF_LOG(Timers, "ImageLoader::imageNotifyFinished %p; m_hasPendingLoadEvent= %d", 453 WTF_LOG(Timers, "ImageLoader::imageNotifyFinished %p; m_hasPendingLoadEvent= %d",
463 this, m_hasPendingLoadEvent); 454 this, m_hasPendingLoadEvent);
464 455
465 ASSERT(m_failedLoadURL.isEmpty()); 456 ASSERT(m_failedLoadURL.isEmpty());
466 ASSERT(resource == m_image.get()); 457 ASSERT(resource == m_image.get());
467 458
459 m_loadDelayCounterForFinish = IncrementLoadEventDelayCount::create(m_element ->document());
460 Platform::current()->currentThread()->getWebTaskRunner()->postTask(BLINK_FRO M_HERE, m_finishTask->cancelAndCreate());
461 }
462
463 void ImageLoader::finish()
464 {
468 m_imageComplete = true; 465 m_imageComplete = true;
466 ImageResource* imageResource = m_image.get();
467 ASSERT(imageResource);
469 468
470 // Update ImageAnimationPolicy for m_image. 469 // Update ImageAnimationPolicy for |imageResource|.
471 if (m_image) 470 if (imageResource)
472 m_image->updateImageAnimationPolicy(); 471 imageResource->updateImageAnimationPolicy();
473 472
474 updateLayoutObject(); 473 updateLayoutObject();
475 474
476 if (m_image && m_image->getImage() && m_image->getImage()->isSVGImage()) 475 if (imageResource && imageResource->getImage() && imageResource->getImage()- >isSVGImage())
477 toSVGImage(m_image->getImage())->updateUseCounters(element()->document() ); 476 toSVGImage(imageResource->getImage())->updateUseCounters(element()->docu ment());
478 477
479 if (!m_hasPendingLoadEvent) 478 finishInternal(imageResource);
480 return;
481 479
482 if (resource->errorOccurred()) { 480 // Dispatches image's load/error event.
483 loadEventSender().cancelEvent(this); 481 if (m_hasPendingLoadEvent) {
484 m_hasPendingLoadEvent = false; 482 m_hasPendingLoadEvent = false;
485 483
486 if (resource->resourceError().isAccessCheck()) 484 if (imageResource->errorOccurred()) {
487 crossSiteOrCSPViolationOccurred(AtomicString(resource->resourceError ().failingURL())); 485 if (imageResource->resourceError().isAccessCheck())
486 crossSiteOrCSPViolationOccurred(AtomicString(imageResource->reso urceError().failingURL()));
488 487
489 // The error event should not fire if the image data update is a result of environment change. 488 // The error event should not fire if the image data update is a res ult of environment change.
490 // https://html.spec.whatwg.org/multipage/embedded-content.html#the-img- element:the-img-element-55 489 // https://html.spec.whatwg.org/multipage/embedded-content.html#the- img-element:the-img-element-55
491 if (!m_suppressErrorEvents) 490 if (!m_suppressErrorEvents)
492 dispatchErrorEvent(); 491 dispatchErrorEventWithoutUpdatedHasPendingEvent();
492 } else if (!imageResource->wasCanceled()) {
493 if (element()->document().frame())
494 dispatchLoadEvent();
495 }
496 }
493 497
494 // Only consider updating the protection ref-count of the Element immedi ately before returning 498 // Dispatches document's load event if applicable.
495 // from this function as doing so might result in the destruction of thi s ImageLoader. 499 // Calling checkCompleted() and document load event synchronously here has
496 updatedHasPendingEvent(); 500 // no problem regarding reentrancy because ImageLoader::finish() is
497 return; 501 // always executed as a CancellableTask and not called by others.
498 } 502 m_loadDelayCounterForFinish.clear();
499 if (resource->wasCanceled()) { 503 if (element()->document().frame())
500 m_hasPendingLoadEvent = false; 504 element()->document().frame()->loader().checkCompleted();
501 // Only consider updating the protection ref-count of the Element immedi ately before returning 505
502 // from this function as doing so might result in the destruction of thi s ImageLoader. 506 // Only consider updating the protection ref-count of the Element immediatel y before returning
503 updatedHasPendingEvent(); 507 // from this function as doing so might result in the destruction of this Im ageLoader.
504 return; 508 updatedHasPendingEvent();
505 }
506 loadEventSender().dispatchEventSoon(this);
507 } 509 }
508 510
509 LayoutImageResource* ImageLoader::layoutImageResource() 511 LayoutImageResource* ImageLoader::layoutImageResource()
510 { 512 {
511 LayoutObject* layoutObject = m_element->layoutObject(); 513 LayoutObject* layoutObject = m_element->layoutObject();
512 514
513 if (!layoutObject) 515 if (!layoutObject)
514 return 0; 516 return 0;
515 517
516 // We don't return style generated image because it doesn't belong to the Im ageLoader. 518 // We don't return style generated image because it doesn't belong to the Im ageLoader.
(...skipping 25 matching lines...) Expand all
542 imageResource->setImageResource(m_image.get()); 544 imageResource->setImageResource(m_image.get());
543 } 545 }
544 546
545 void ImageLoader::updatedHasPendingEvent() 547 void ImageLoader::updatedHasPendingEvent()
546 { 548 {
547 // If an Element that does image loading is removed from the DOM the load/er ror event for the image is still observable. 549 // If an Element that does image loading is removed from the DOM the load/er ror event for the image is still observable.
548 // As long as the ImageLoader is actively loading, the Element itself needs to be ref'ed to keep it from being 550 // As long as the ImageLoader is actively loading, the Element itself needs to be ref'ed to keep it from being
549 // destroyed by DOM manipulation or garbage collection. 551 // destroyed by DOM manipulation or garbage collection.
550 // If such an Element wishes for the load to stop when removed from the DOM it needs to stop the ImageLoader explicitly. 552 // If such an Element wishes for the load to stop when removed from the DOM it needs to stop the ImageLoader explicitly.
551 bool wasProtected = m_elementIsProtected; 553 bool wasProtected = m_elementIsProtected;
552 m_elementIsProtected = m_hasPendingLoadEvent || m_hasPendingErrorEvent; 554 m_elementIsProtected = m_hasPendingLoadEvent || hasPendingError();
553 if (wasProtected == m_elementIsProtected) 555 if (wasProtected == m_elementIsProtected)
554 return; 556 return;
555 557
556 if (m_elementIsProtected) { 558 if (m_elementIsProtected) {
557 if (m_derefElementTimer.isActive()) 559 if (m_derefElementTimer.isActive())
558 m_derefElementTimer.stop(); 560 m_derefElementTimer.stop();
559 else 561 else
560 m_keepAlive = m_element; 562 m_keepAlive = m_element;
561 } else { 563 } else {
562 ASSERT(!m_derefElementTimer.isActive()); 564 ASSERT(!m_derefElementTimer.isActive());
563 m_derefElementTimer.startOneShot(0, BLINK_FROM_HERE); 565 m_derefElementTimer.startOneShot(0, BLINK_FROM_HERE);
564 } 566 }
565 } 567 }
566 568
567 void ImageLoader::timerFired(Timer<ImageLoader>*) 569 void ImageLoader::timerFired(Timer<ImageLoader>*)
568 { 570 {
569 m_keepAlive.clear(); 571 m_keepAlive.clear();
570 } 572 }
571 573
572 void ImageLoader::dispatchPendingEvent(ImageEventSender* eventSender) 574 void ImageLoader::dispatchErrorEventWithoutUpdatedHasPendingEvent()
573 { 575 {
574 WTF_LOG(Timers, "ImageLoader::dispatchPendingEvent %p", this); 576 if (element()->document().frame())
575 ASSERT(eventSender == &loadEventSender() || eventSender == &errorEventSender ()); 577 element()->dispatchEvent(Event::create(EventTypeNames::error));
576 const AtomicString& eventType = eventSender->eventType(); 578 m_loadDelayCounterForError.clear();
577 if (eventType == EventTypeNames::load)
578 dispatchPendingLoadEvent();
579 if (eventType == EventTypeNames::error)
580 dispatchPendingErrorEvent();
581 } 579 }
582 580
583 void ImageLoader::dispatchPendingLoadEvent() 581 void ImageLoader::dispatchErrorEvent()
584 { 582 {
585 if (!m_hasPendingLoadEvent) 583 dispatchErrorEventWithoutUpdatedHasPendingEvent();
586 return;
587 if (!m_image)
588 return;
589 m_hasPendingLoadEvent = false;
590 if (element()->document().frame())
591 dispatchLoadEvent();
592 584
593 // Only consider updating the protection ref-count of the Element immediatel y before returning 585 // Only consider updating the protection ref-count of the Element immediatel y before returning
594 // from this function as doing so might result in the destruction of this Im ageLoader. 586 // from this function as doing so might result in the destruction of this Im ageLoader.
595 updatedHasPendingEvent();
596 }
597
598 void ImageLoader::dispatchPendingErrorEvent()
599 {
600 if (!m_hasPendingErrorEvent)
601 return;
602 m_hasPendingErrorEvent = false;
603
604 if (element()->document().frame())
605 element()->dispatchEvent(Event::create(EventTypeNames::error));
606
607 // Only consider updating the protection ref-count of the Element immediatel y before returning
608 // from this function as doing so might result in the destruction of this Im ageLoader.
609 updatedHasPendingEvent(); 587 updatedHasPendingEvent();
610 } 588 }
611 589
612 bool ImageLoader::getImageAnimationPolicy(ImageAnimationPolicy& policy) 590 bool ImageLoader::getImageAnimationPolicy(ImageAnimationPolicy& policy)
613 { 591 {
614 if (!element()->document().settings()) 592 if (!element()->document().settings())
615 return false; 593 return false;
616 594
617 policy = element()->document().settings()->imageAnimationPolicy(); 595 policy = element()->document().settings()->imageAnimationPolicy();
618 return true; 596 return true;
619 } 597 }
620 598
621 void ImageLoader::dispatchPendingLoadEvents()
622 {
623 loadEventSender().dispatchPendingEvents();
624 }
625
626 void ImageLoader::dispatchPendingErrorEvents()
627 {
628 errorEventSender().dispatchPendingEvents();
629 }
630
631 void ImageLoader::elementDidMoveToNewDocument() 599 void ImageLoader::elementDidMoveToNewDocument()
632 { 600 {
633 if (m_loadDelayCounter) 601 if (m_loadDelayCounterForMicrotask)
634 m_loadDelayCounter->documentChanged(m_element->document()); 602 m_loadDelayCounterForMicrotask->documentChanged(m_element->document());
603 if (m_loadDelayCounterForFinish)
604 m_loadDelayCounterForFinish->documentChanged(m_element->document());
605 if (m_loadDelayCounterForError)
606 m_loadDelayCounterForError->documentChanged(m_element->document());
635 clearFailedLoadURL(); 607 clearFailedLoadURL();
636 setImage(0); 608 setImage(0);
637 } 609 }
638 610
639 } // namespace blink 611 } // namespace blink
OLDNEW
« 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