OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |