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

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: cleanup, fix new layout tests 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(OwnPtrWillBePersistent<ImageEventSender>, sender, (Image EventSender::create(EventTypeNames::load)));
58 return *sender;
59 }
60
61 static ImageEventSender& errorEventSender()
62 {
63 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<ImageEventSender>, sender, (Image EventSender::create(EventTypeNames::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 m_finishTask->cancel();
166 m_loadDelayCounterForFinish.clear();
167 m_hasPendingLoadEvent = false;
168 }
169
170 void ImageLoader::cancelPendingErrorEvent()
171 {
172 if (m_loadDelayCounterForError) {
Nate Chapin 2016/03/29 19:04:13 Why does this have an if() wrapper, but cancelPend
hiroshige 2017/05/18 22:13:12 |m_loadDelayCounterForError| is non-null only betw
173 m_dispatchErrorEventTask->cancel();
174 m_loadDelayCounterForError.clear();
175 }
176 }
177
172 void ImageLoader::dispose() 178 void ImageLoader::dispose()
173 { 179 {
174 WTF_LOG(Timers, "~ImageLoader %p; m_hasPendingLoadEvent=%d, m_hasPendingErro rEvent=%d", 180 WTF_LOG(Timers, "~ImageLoader %p; m_hasPendingLoadEvent=%d, hasPendingErrorE vent=%d",
175 this, m_hasPendingLoadEvent, m_hasPendingErrorEvent); 181 this, m_hasPendingLoadEvent, hasPendingError());
176 182
177 #if !ENABLE(OILPAN) 183 #if !ENABLE(OILPAN)
178 if (m_pendingTask) 184 if (m_pendingMicrotask)
179 m_pendingTask->clearLoader(); 185 m_pendingMicrotask->clearLoader();
180 #endif 186 #endif
181 187
182 if (m_image) { 188 if (m_image) {
183 m_image->removeClient(this); 189 m_image->removeClient(this);
184 m_image->removeObserver(this); 190 m_image->removeObserver(this);
185 m_image = nullptr; 191 m_image = nullptr;
186 } 192 }
187 193 cancelPendingFinish();
188 #if !ENABLE(OILPAN) 194 cancelPendingErrorEvent();
189 ASSERT(m_hasPendingLoadEvent || !loadEventSender().hasPendingEvents(this));
190 if (m_hasPendingLoadEvent)
191 loadEventSender().cancelEvent(this);
192
193 ASSERT(m_hasPendingErrorEvent || !errorEventSender().hasPendingEvents(this)) ;
194 if (m_hasPendingErrorEvent)
195 errorEventSender().cancelEvent(this);
196 #endif
197 } 195 }
198 196
199 DEFINE_TRACE(ImageLoader) 197 DEFINE_TRACE(ImageLoader)
200 { 198 {
201 visitor->trace(m_image); 199 visitor->trace(m_image);
202 visitor->trace(m_element); 200 visitor->trace(m_element);
203 } 201 }
204 202
205 void ImageLoader::setImage(ImageResource* newImage) 203 void ImageLoader::setImage(ImageResource* newImage)
206 { 204 {
207 setImageWithoutConsideringPendingLoadEvent(newImage); 205 setImageWithoutConsideringPendingLoadEvent(newImage);
208 206
209 // Only consider updating the protection ref-count of the Element immediatel y before returning 207 // Only consider updating the protection ref-count of the Element immediatel y before returning
210 // from this function as doing so might result in the destruction of this Im ageLoader. 208 // from this function as doing so might result in the destruction of this Im ageLoader.
211 updatedHasPendingEvent(); 209 updatedHasPendingEvent();
212 } 210 }
213 211
214 void ImageLoader::setImageWithoutConsideringPendingLoadEvent(ImageResource* newI mage) 212 void ImageLoader::setImageWithoutConsideringPendingLoadEvent(ImageResource* newI mage)
215 { 213 {
216 ASSERT(m_failedLoadURL.isEmpty()); 214 ASSERT(m_failedLoadURL.isEmpty());
217 ImageResource* oldImage = m_image.get(); 215 ImageResource* oldImage = m_image.get();
218 if (newImage != oldImage) { 216 if (newImage != oldImage) {
219 m_image = newImage; 217 m_image = newImage;
220 if (m_hasPendingLoadEvent) { 218 cancelPendingFinish();
221 loadEventSender().cancelEvent(this); 219 cancelPendingErrorEvent();
222 m_hasPendingLoadEvent = false;
223 }
224 if (m_hasPendingErrorEvent) {
225 errorEventSender().cancelEvent(this);
226 m_hasPendingErrorEvent = false;
227 }
228 m_imageComplete = true; 220 m_imageComplete = true;
229 if (newImage) { 221 if (newImage) {
230 newImage->addClient(this); 222 newImage->addClient(this);
231 newImage->addObserver(this); 223 newImage->addObserver(this);
232 } 224 }
233 if (oldImage) { 225 if (oldImage) {
234 oldImage->removeClient(this); 226 oldImage->removeClient(this);
235 oldImage->removeObserver(this); 227 oldImage->removeObserver(this);
236 } 228 }
237 } 229 }
238 230
239 if (LayoutImageResource* imageResource = layoutImageResource()) 231 if (LayoutImageResource* imageResource = layoutImageResource())
240 imageResource->resetAnimation(); 232 imageResource->resetAnimation();
241 } 233 }
242 234
243 static void configureRequest(FetchRequest& request, ImageLoader::BypassMainWorld Behavior bypassBehavior, Element& element, const ClientHintsPreferences& clientH intsPreferences) 235 static void configureRequest(FetchRequest& request, ImageLoader::BypassMainWorld Behavior bypassBehavior, Element& element, const ClientHintsPreferences& clientH intsPreferences)
244 { 236 {
245 if (bypassBehavior == ImageLoader::BypassMainWorldCSP) 237 if (bypassBehavior == ImageLoader::BypassMainWorldCSP)
246 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy); 238 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy);
247 239
248 CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue(element.fa stGetAttribute(HTMLNames::crossoriginAttr)); 240 CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue(element.fa stGetAttribute(HTMLNames::crossoriginAttr));
249 if (crossOrigin != CrossOriginAttributeNotSet) 241 if (crossOrigin != CrossOriginAttributeNotSet)
250 request.setCrossOriginAccessControl(element.document().getSecurityOrigin (), crossOrigin); 242 request.setCrossOriginAccessControl(element.document().getSecurityOrigin (), crossOrigin);
251 243
252 if (clientHintsPreferences.shouldSendResourceWidth() && isHTMLImageElement(e lement)) 244 if (clientHintsPreferences.shouldSendResourceWidth() && isHTMLImageElement(e lement))
253 request.setResourceWidth(toHTMLImageElement(element).getResourceWidth()) ; 245 request.setResourceWidth(toHTMLImageElement(element).getResourceWidth()) ;
254 } 246 }
255 247
256 inline void ImageLoader::dispatchErrorEvent() 248 inline void ImageLoader::scheduleErrorEvent()
257 { 249 {
258 m_hasPendingErrorEvent = true; 250 m_loadDelayCounterForError = IncrementLoadEventDelayCount::create(m_element- >document());
259 errorEventSender().dispatchEventSoon(this); 251 Platform::current()->currentThread()->getWebTaskRunner()->postTask(BLINK_FRO M_HERE, m_dispatchErrorEventTask->cancelAndCreate());
260 } 252 }
261 253
262 inline void ImageLoader::crossSiteOrCSPViolationOccurred(AtomicString imageSourc eURL) 254 inline void ImageLoader::crossSiteOrCSPViolationOccurred(AtomicString imageSourc eURL)
263 { 255 {
264 m_failedLoadURL = imageSourceURL; 256 m_failedLoadURL = imageSourceURL;
265 } 257 }
266 258
267 inline void ImageLoader::clearFailedLoadURL() 259 inline void ImageLoader::clearFailedLoadURL()
268 { 260 {
269 m_failedLoadURL = AtomicString(); 261 m_failedLoadURL = AtomicString();
270 } 262 }
271 263
272 inline void ImageLoader::enqueueImageLoadingMicroTask(UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy) 264 inline void ImageLoader::enqueueImageLoadingMicroTask(UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
273 { 265 {
274 OwnPtr<Task> task = Task::create(this, updateBehavior, referrerPolicy); 266 OwnPtr<Task> task = Task::create(this, updateBehavior, referrerPolicy);
275 m_pendingTask = task->createWeakPtr(); 267 m_pendingMicrotask = task->createWeakPtr();
276 Microtask::enqueueMicrotask(task.release()); 268 Microtask::enqueueMicrotask(task.release());
277 m_loadDelayCounter = IncrementLoadEventDelayCount::create(m_element->documen t()); 269 m_loadDelayCounterForMicrotask = IncrementLoadEventDelayCount::create(m_elem ent->document());
278 } 270 }
279 271
280 void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up dateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy) 272 void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up dateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
281 { 273 {
282 // FIXME: According to 274 // FIXME: According to
283 // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-cont ent.html#the-img-element:the-img-element-55 275 // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-cont ent.html#the-img-element:the-img-element-55
284 // When "update image" is called due to environment changes and the load fai ls, onerror should not be called. 276 // When "update image" is called due to environment changes and the load fai ls, onerror should not be called.
285 // That is currently not the case. 277 // That is currently not the case.
286 // 278 //
287 // We don't need to call clearLoader here: Either we were called from the 279 // We don't need to call clearLoader here: Either we were called from the
288 // task, or our caller updateFromElement cleared the task's loader (and set 280 // task, or our caller updateFromElement cleared the task's loader (and set
289 // m_pendingTask to null). 281 // m_pendingMicrotask to null).
290 m_pendingTask.clear(); 282 m_pendingMicrotask.clear();
291 // Make sure to only decrement the count when we exit this function 283 // Make sure to only decrement the count when we exit this function
292 OwnPtr<IncrementLoadEventDelayCount> loadDelayCounter; 284 OwnPtr<IncrementLoadEventDelayCount> loadDelayCounter;
293 loadDelayCounter.swap(m_loadDelayCounter); 285 loadDelayCounter.swap(m_loadDelayCounterForMicrotask);
294 286
295 Document& document = m_element->document(); 287 Document& document = m_element->document();
296 if (!document.isActive()) 288 if (!document.isActive())
297 return; 289 return;
298 290
299 AtomicString imageSourceURL = m_element->imageSourceURL(); 291 AtomicString imageSourceURL = m_element->imageSourceURL();
300 KURL url = imageSourceToKURL(imageSourceURL); 292 KURL url = imageSourceToKURL(imageSourceURL);
301 RefPtrWillBeRawPtr<ImageResource> newImage = nullptr; 293 RefPtrWillBeRawPtr<ImageResource> newImage = nullptr;
302 RefPtrWillBeRawPtr<Element> protectElement(m_element.get()); 294 RefPtrWillBeRawPtr<Element> protectElement(m_element.get());
303 if (!url.isNull()) { 295 if (!url.isNull()) {
(...skipping 24 matching lines...) Expand all
328 request.setDefer(FetchRequest::DeferredByClient); 320 request.setDefer(FetchRequest::DeferredByClient);
329 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy); 321 request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy);
330 } 322 }
331 323
332 newImage = ImageResource::fetch(request, document.fetcher()); 324 newImage = ImageResource::fetch(request, document.fetcher());
333 if (m_loadingImageDocument && newImage) 325 if (m_loadingImageDocument && newImage)
334 newImage->setStatus(Resource::Pending); 326 newImage->setStatus(Resource::Pending);
335 327
336 if (!newImage && !pageIsBeingDismissed(&document)) { 328 if (!newImage && !pageIsBeingDismissed(&document)) {
337 crossSiteOrCSPViolationOccurred(imageSourceURL); 329 crossSiteOrCSPViolationOccurred(imageSourceURL);
338 dispatchErrorEvent(); 330 scheduleErrorEvent();
339 } else { 331 } else {
340 clearFailedLoadURL(); 332 clearFailedLoadURL();
341 } 333 }
342 } else { 334 } else {
343 if (!imageSourceURL.isNull()) { 335 if (!imageSourceURL.isNull()) {
344 // Fire an error event if the url string is not empty, but the KURL is. 336 // Fire an error event if the url string is not empty, but the KURL is.
345 dispatchErrorEvent(); 337 scheduleErrorEvent();
346 } 338 }
347 noImageResourceToLoad(); 339 noImageResourceToLoad();
348 } 340 }
349 341
350 RefPtrWillBeRawPtr<ImageResource> oldImage = m_image.get(); 342 RefPtrWillBeRawPtr<ImageResource> oldImage = m_image.get();
351 if (updateBehavior == UpdateSizeChanged && m_element->layoutObject() && m_el ement->layoutObject()->isImage() && newImage == oldImage) { 343 if (updateBehavior == UpdateSizeChanged && m_element->layoutObject() && m_el ement->layoutObject()->isImage() && newImage == oldImage) {
352 toLayoutImage(m_element->layoutObject())->intrinsicSizeChanged(); 344 toLayoutImage(m_element->layoutObject())->intrinsicSizeChanged();
353 } else { 345 } else {
354 if (m_hasPendingLoadEvent) { 346 cancelPendingFinish();
355 loadEventSender().cancelEvent(this);
356 m_hasPendingLoadEvent = false;
357 }
358 347
359 // Cancel error events that belong to the previous load, which is now ca ncelled by changing the src attribute. 348 // Cancel error events that belong to the previous load, which is now ca ncelled by changing the src attribute.
360 // If newImage is null and m_hasPendingErrorEvent is true, we know the e rror event has been just posted by 349 // If newImage is null and hasPendingError() is true, we know the error event has been just posted by
361 // this load and we should not cancel the event. 350 // this load and we should not cancel the event.
362 // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two. 351 // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two.
363 if (m_hasPendingErrorEvent && newImage) { 352 if (newImage)
364 errorEventSender().cancelEvent(this); 353 cancelPendingErrorEvent();
365 m_hasPendingErrorEvent = false;
366 }
367 354
368 m_image = newImage; 355 m_image = newImage;
369 m_hasPendingLoadEvent = newImage; 356 m_hasPendingLoadEvent = newImage;
370 m_imageComplete = !newImage; 357 m_imageComplete = !newImage;
371 358
372 updateLayoutObject(); 359 updateLayoutObject();
373 // If newImage exists and is cached, addClient() will result in the load event 360 // If newImage exists and is cached, addClient() will result in the load event
374 // being queued to fire. Ensure this happens after beforeload is dispatc hed. 361 // being queued to fire. Ensure this happens after beforeload is dispatc hed.
375 if (newImage) { 362 if (newImage) {
376 newImage->addClient(this); 363 newImage->addClient(this);
(...skipping 19 matching lines...) Expand all
396 m_suppressErrorEvents = (updateBehavior == UpdateSizeChanged); 383 m_suppressErrorEvents = (updateBehavior == UpdateSizeChanged);
397 384
398 if (updateBehavior == UpdateIgnorePreviousError) 385 if (updateBehavior == UpdateIgnorePreviousError)
399 clearFailedLoadURL(); 386 clearFailedLoadURL();
400 387
401 if (!m_failedLoadURL.isEmpty() && imageSourceURL == m_failedLoadURL) 388 if (!m_failedLoadURL.isEmpty() && imageSourceURL == m_failedLoadURL)
402 return; 389 return;
403 390
404 // If we have a pending task, we have to clear it -- either we're 391 // If we have a pending task, we have to clear it -- either we're
405 // now loading immediately, or we need to reset the task's state. 392 // now loading immediately, or we need to reset the task's state.
406 if (m_pendingTask) { 393 if (m_pendingMicrotask) {
407 m_pendingTask->clearLoader(); 394 m_pendingMicrotask->clearLoader();
408 m_pendingTask.clear(); 395 m_pendingMicrotask.clear();
409 } 396 }
410 397
411 KURL url = imageSourceToKURL(imageSourceURL); 398 KURL url = imageSourceToKURL(imageSourceURL);
412 if (shouldLoadImmediately(url)) { 399 if (shouldLoadImmediately(url)) {
413 doUpdateFromElement(DoNotBypassMainWorldCSP, updateBehavior, referrerPol icy); 400 doUpdateFromElement(DoNotBypassMainWorldCSP, updateBehavior, referrerPol icy);
414 return; 401 return;
415 } 402 }
416 // Allow the idiom "img.src=''; img.src='.." to clear down the image before 403 // Allow the idiom "img.src=''; img.src='.." to clear down the image before
417 // an asynchronous load completes. 404 // an asynchronous load completes.
418 if (imageSourceURL.isEmpty()) { 405 if (imageSourceURL.isEmpty()) {
419 ImageResource* image = m_image.get(); 406 ImageResource* image = m_image.get();
420 if (image) { 407 if (image) {
421 image->removeClient(this); 408 image->removeClient(this);
422 image->removeObserver(this); 409 image->removeObserver(this);
423 } 410 }
424 m_image = nullptr; 411 m_image = nullptr;
412 cancelPendingFinish();
413 cancelPendingErrorEvent();
425 } 414 }
426 415
427 // Don't load images for inactive documents. We don't want to slow down the 416 // Don't load images for inactive documents. We don't want to slow down the
428 // raw HTML parsing case by loading images we don't intend to display. 417 // raw HTML parsing case by loading images we don't intend to display.
429 Document& document = m_element->document(); 418 Document& document = m_element->document();
430 if (document.isActive()) 419 if (document.isActive())
431 enqueueImageLoadingMicroTask(updateBehavior, referrerPolicy); 420 enqueueImageLoadingMicroTask(updateBehavior, referrerPolicy);
432 } 421 }
433 422
434 KURL ImageLoader::imageSourceToKURL(AtomicString imageSourceURL) const 423 KURL ImageLoader::imageSourceToKURL(AtomicString imageSourceURL) const
(...skipping 29 matching lines...) Expand all
464 } 453 }
465 454
466 void ImageLoader::notifyFinished(Resource* resource) 455 void ImageLoader::notifyFinished(Resource* resource)
467 { 456 {
468 WTF_LOG(Timers, "ImageLoader::notifyFinished %p; m_hasPendingLoadEvent=%d", 457 WTF_LOG(Timers, "ImageLoader::notifyFinished %p; m_hasPendingLoadEvent=%d",
469 this, m_hasPendingLoadEvent); 458 this, m_hasPendingLoadEvent);
470 459
471 ASSERT(m_failedLoadURL.isEmpty()); 460 ASSERT(m_failedLoadURL.isEmpty());
472 ASSERT(resource == m_image.get()); 461 ASSERT(resource == m_image.get());
473 462
463 scheduleFinish();
464 }
465
466 void ImageLoader::scheduleFinish()
Nate Chapin 2016/03/29 19:04:13 scheduleFinish() is only called once. Inline it in
hiroshige 2017/05/18 22:13:14 Done.
467 {
468 m_loadDelayCounterForFinish = IncrementLoadEventDelayCount::create(m_element ->document());
469 Platform::current()->currentThread()->getWebTaskRunner()->postTask(BLINK_FRO M_HERE, m_finishTask->cancelAndCreate());
470 }
471
472 void ImageLoader::finish()
473 {
474 m_imageComplete = true; 474 m_imageComplete = true;
475 ImageResource* cachedImage = m_image.get();
Nate Chapin 2016/03/29 19:04:13 cachedImage->imageResource? CachedImage is what Im
hiroshige 2017/05/18 22:13:14 Done.
476 ASSERT(cachedImage);
Nate Chapin 2016/03/29 19:04:13 The theory is that the calls to cancelPendingFinis
hiroshige 2017/05/18 22:13:13 Yes. I inserted cancelPendingFinish() at Line 412
475 477
476 // Update ImageAnimationPolicy for m_image. 478 // Update ImageAnimationPolicy for |cachedImage|.
477 if (m_image) 479 if (cachedImage)
478 m_image->updateImageAnimationPolicy(); 480 cachedImage->updateImageAnimationPolicy();
479 481
480 updateLayoutObject(); 482 updateLayoutObject();
481 483
482 if (m_image && m_image->getImage() && m_image->getImage()->isSVGImage()) 484 if (cachedImage && cachedImage->getImage() && cachedImage->getImage()->isSVG Image())
483 toSVGImage(m_image->getImage())->updateUseCounters(element()->document() ); 485 toSVGImage(cachedImage->getImage())->updateUseCounters(element()->docume nt());
484 486
485 if (!m_hasPendingLoadEvent) 487 finishInternal(cachedImage);
486 return;
487 488
488 if (resource->errorOccurred()) { 489 // Dispatches image's load/error event.
489 loadEventSender().cancelEvent(this); 490 if (m_hasPendingLoadEvent) {
490 m_hasPendingLoadEvent = false; 491 m_hasPendingLoadEvent = false;
491 492
492 if (resource->resourceError().isAccessCheck()) 493 if (cachedImage->errorOccurred()) {
493 crossSiteOrCSPViolationOccurred(AtomicString(resource->resourceError ().failingURL())); 494 if (cachedImage->resourceError().isAccessCheck())
495 crossSiteOrCSPViolationOccurred(AtomicString(cachedImage->resour ceError().failingURL()));
494 496
495 // The error event should not fire if the image data update is a result of environment change. 497 // The error event should not fire if the image data update is a res ult of environment change.
496 // https://html.spec.whatwg.org/multipage/embedded-content.html#the-img- element:the-img-element-55 498 // https://html.spec.whatwg.org/multipage/embedded-content.html#the- img-element:the-img-element-55
497 if (!m_suppressErrorEvents) 499 if (!m_suppressErrorEvents)
498 dispatchErrorEvent(); 500 dispatchErrorEventWithoutUpdatedHasPendingEvent();
501 } else if (!cachedImage->wasCanceled()) {
502 if (element()->document().frame())
503 dispatchLoadEvent();
504 }
505 }
499 506
500 // Only consider updating the protection ref-count of the Element immedi ately before returning 507 // Dispatches document's load event if applicable.
501 // from this function as doing so might result in the destruction of thi s ImageLoader. 508 // Calling checkCompleted() and document load event synchronously here has
502 updatedHasPendingEvent(); 509 // no problem regarding reentrancy because ImageLoader::finish() is
503 return; 510 // always executed as a CancellableTask and not called by others.
504 } 511 m_loadDelayCounterForFinish.clear();
505 if (resource->wasCanceled()) { 512 if (element()->document().frame())
506 m_hasPendingLoadEvent = false; 513 element()->document().frame()->loader().checkCompleted();
507 // Only consider updating the protection ref-count of the Element immedi ately before returning 514
508 // from this function as doing so might result in the destruction of thi s ImageLoader. 515 // Only consider updating the protection ref-count of the Element immediatel y before returning
509 updatedHasPendingEvent(); 516 // from this function as doing so might result in the destruction of this Im ageLoader.
510 return; 517 updatedHasPendingEvent();
511 }
512 loadEventSender().dispatchEventSoon(this);
513 } 518 }
514 519
515 LayoutImageResource* ImageLoader::layoutImageResource() 520 LayoutImageResource* ImageLoader::layoutImageResource()
516 { 521 {
517 LayoutObject* layoutObject = m_element->layoutObject(); 522 LayoutObject* layoutObject = m_element->layoutObject();
518 523
519 if (!layoutObject) 524 if (!layoutObject)
520 return 0; 525 return 0;
521 526
522 // We don't return style generated image because it doesn't belong to the Im ageLoader. 527 // We don't return style generated image because it doesn't belong to the Im ageLoader.
(...skipping 25 matching lines...) Expand all
548 imageResource->setImageResource(m_image.get()); 553 imageResource->setImageResource(m_image.get());
549 } 554 }
550 555
551 void ImageLoader::updatedHasPendingEvent() 556 void ImageLoader::updatedHasPendingEvent()
552 { 557 {
553 // If an Element that does image loading is removed from the DOM the load/er ror event for the image is still observable. 558 // If an Element that does image loading is removed from the DOM the load/er ror event for the image is still observable.
554 // As long as the ImageLoader is actively loading, the Element itself needs to be ref'ed to keep it from being 559 // As long as the ImageLoader is actively loading, the Element itself needs to be ref'ed to keep it from being
555 // destroyed by DOM manipulation or garbage collection. 560 // destroyed by DOM manipulation or garbage collection.
556 // If such an Element wishes for the load to stop when removed from the DOM it needs to stop the ImageLoader explicitly. 561 // If such an Element wishes for the load to stop when removed from the DOM it needs to stop the ImageLoader explicitly.
557 bool wasProtected = m_elementIsProtected; 562 bool wasProtected = m_elementIsProtected;
558 m_elementIsProtected = m_hasPendingLoadEvent || m_hasPendingErrorEvent; 563 m_elementIsProtected = m_hasPendingLoadEvent || hasPendingError();
559 if (wasProtected == m_elementIsProtected) 564 if (wasProtected == m_elementIsProtected)
560 return; 565 return;
561 566
562 if (m_elementIsProtected) { 567 if (m_elementIsProtected) {
563 if (m_derefElementTimer.isActive()) 568 if (m_derefElementTimer.isActive())
564 m_derefElementTimer.stop(); 569 m_derefElementTimer.stop();
565 else 570 else
566 m_keepAlive = m_element; 571 m_keepAlive = m_element;
567 } else { 572 } else {
568 ASSERT(!m_derefElementTimer.isActive()); 573 ASSERT(!m_derefElementTimer.isActive());
569 m_derefElementTimer.startOneShot(0, BLINK_FROM_HERE); 574 m_derefElementTimer.startOneShot(0, BLINK_FROM_HERE);
570 } 575 }
571 } 576 }
572 577
573 void ImageLoader::timerFired(Timer<ImageLoader>*) 578 void ImageLoader::timerFired(Timer<ImageLoader>*)
574 { 579 {
575 m_keepAlive.clear(); 580 m_keepAlive.clear();
576 } 581 }
577 582
578 void ImageLoader::dispatchPendingEvent(ImageEventSender* eventSender) 583 void ImageLoader::dispatchErrorEventWithoutUpdatedHasPendingEvent()
579 { 584 {
580 WTF_LOG(Timers, "ImageLoader::dispatchPendingEvent %p", this); 585 if (element()->document().frame())
581 ASSERT(eventSender == &loadEventSender() || eventSender == &errorEventSender ()); 586 element()->dispatchEvent(Event::create(EventTypeNames::error));
582 const AtomicString& eventType = eventSender->eventType(); 587 m_loadDelayCounterForError.clear();
583 if (eventType == EventTypeNames::load)
584 dispatchPendingLoadEvent();
585 if (eventType == EventTypeNames::error)
586 dispatchPendingErrorEvent();
587 } 588 }
588 589
589 void ImageLoader::dispatchPendingLoadEvent() 590 void ImageLoader::dispatchErrorEvent()
590 { 591 {
591 if (!m_hasPendingLoadEvent) 592 dispatchErrorEventWithoutUpdatedHasPendingEvent();
592 return;
593 if (!m_image)
594 return;
595 m_hasPendingLoadEvent = false;
596 if (element()->document().frame())
597 dispatchLoadEvent();
598 593
599 // Only consider updating the protection ref-count of the Element immediatel y before returning 594 // Only consider updating the protection ref-count of the Element immediatel y before returning
600 // from this function as doing so might result in the destruction of this Im ageLoader. 595 // from this function as doing so might result in the destruction of this Im ageLoader.
601 updatedHasPendingEvent();
602 }
603
604 void ImageLoader::dispatchPendingErrorEvent()
605 {
606 if (!m_hasPendingErrorEvent)
607 return;
608 m_hasPendingErrorEvent = false;
609
610 if (element()->document().frame())
611 element()->dispatchEvent(Event::create(EventTypeNames::error));
612
613 // Only consider updating the protection ref-count of the Element immediatel y before returning
614 // from this function as doing so might result in the destruction of this Im ageLoader.
615 updatedHasPendingEvent(); 596 updatedHasPendingEvent();
616 } 597 }
617 598
618 bool ImageLoader::getImageAnimationPolicy(ImageAnimationPolicy& policy) 599 bool ImageLoader::getImageAnimationPolicy(ImageAnimationPolicy& policy)
619 { 600 {
620 if (!element()->document().settings()) 601 if (!element()->document().settings())
621 return false; 602 return false;
622 603
623 policy = element()->document().settings()->imageAnimationPolicy(); 604 policy = element()->document().settings()->imageAnimationPolicy();
624 return true; 605 return true;
625 } 606 }
626 607
627 void ImageLoader::dispatchPendingLoadEvents()
628 {
629 loadEventSender().dispatchPendingEvents();
630 }
631
632 void ImageLoader::dispatchPendingErrorEvents()
633 {
634 errorEventSender().dispatchPendingEvents();
635 }
636
637 void ImageLoader::elementDidMoveToNewDocument() 608 void ImageLoader::elementDidMoveToNewDocument()
638 { 609 {
639 if (m_loadDelayCounter) 610 if (m_loadDelayCounterForMicrotask)
640 m_loadDelayCounter->documentChanged(m_element->document()); 611 m_loadDelayCounterForMicrotask->documentChanged(m_element->document());
612 if (m_loadDelayCounterForFinish)
613 m_loadDelayCounterForFinish->documentChanged(m_element->document());
614 if (m_loadDelayCounterForError)
615 m_loadDelayCounterForError->documentChanged(m_element->document());
641 clearFailedLoadURL(); 616 clearFailedLoadURL();
642 setImage(0); 617 setImage(0);
643 } 618 }
644 619
645 } // namespace blink 620 } // 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