void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy) { AtomicString imageSourceURL = m_element->imageSourceURL(); m_suppressErrorEvents = (updateBehavior == UpdateSizeChanged); if (updateBehavior == UpdateIgnorePreviousError) clearFailedLoadURL(); if (!m_failedLoadURL.isEmpty() && imageSourceURL == m_failedLoadURL) return; // Prevent the creation of a ResourceLoader (and therefore a network request) // for ImageDocument loads. In this case, the image contents have already been // requested as a main resource and ImageDocumentParser will take care of // funneling the main resource bytes into m_image, so just create an // ImageResource to be populated later. if (m_loadingImageDocument && updateBehavior != UpdateForcedReload) { setImage( ImageResource::create(imageSourceToKURL(m_element->imageSourceURL()))); m_image->setStatus(Resource::Pending); return; } // If we have a pending task, we have to clear it -- either we're now loading // immediately, or we need to reset the task's state. if (m_pendingTask) { m_pendingTask->clearLoader(); m_pendingTask.reset(); } KURL url = imageSourceToKURL(imageSourceURL); if (shouldLoadImmediately(url)) { doUpdateFromElement(DoNotBypassMainWorldCSP, updateBehavior, url, referrerPolicy); return; } // Allow the idiom "img.src=''; img.src='.." to clear down the image before an // asynchronous load completes. if (imageSourceURL.isEmpty()) { ImageResource* image = m_image.get(); if (image) { image->removeObserver(this); } m_image = nullptr; } // Don't load images for inactive documents. We don't want to slow down the // raw HTML parsing case by loading images we don't intend to display. Document& document = m_element->document(); if (document.isActive()) enqueueImageLoadingMicroTask(updateBehavior, referrerPolicy); }
void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior) { AtomicString imageSourceURL = m_element->imageSourceURL(); m_suppressErrorEvents = (updateBehavior == UpdateSizeChanged); if (updateBehavior == UpdateIgnorePreviousError) clearFailedLoadURL(); if (!m_failedLoadURL.isEmpty() && imageSourceURL == m_failedLoadURL) return; // If we have a pending task, we have to clear it -- either we're // now loading immediately, or we need to reset the task's state. if (m_pendingTask) { m_pendingTask->clearLoader(); m_pendingTask.clear(); } KURL url = imageSourceToKURL(imageSourceURL); if (shouldLoadImmediately(url)) { doUpdateFromElement(DoNotBypassMainWorldCSP, updateBehavior); return; } // Allow the idiom "img.src=''; img.src='.." to clear down the image before // an asynchronous load completes. if (imageSourceURL.isEmpty()) { ImageResource* image = m_image.get(); if (image) image->removeClient(this); m_image = nullptr; } // Don't load images for inactive documents. We don't want to slow down the // raw HTML parsing case by loading images we don't intend to display. Document& document = m_element->document(); if (document.isActive()) enqueueImageLoadingMicroTask(updateBehavior); }
void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior, LoadType loadType) { AtomicString imageSourceURL = m_element->imageSourceURL(); if (updateBehavior == UpdateIgnorePreviousError) clearFailedLoadURL(); if (!m_failedLoadURL.isEmpty() && imageSourceURL == m_failedLoadURL) return; // If we have a pending task, we have to clear it -- either we're // now loading immediately, or we need to reset the task's state. if (m_pendingTask) { m_pendingTask->clearLoader(); m_pendingTask.clear(); } KURL url = imageSourceToKURL(imageSourceURL); if (imageSourceURL.isNull() || url.isNull() || shouldLoadImmediately(url, loadType)) { doUpdateFromElement(updateBehavior); return; } enqueueImageLoadingMicroTask(updateBehavior); }
void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, UpdateFromElementBehavior updateBehavior) { // FIXME: According to // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content.html#the-img-element:the-img-element-55 // When "update image" is called due to environment changes and the load fails, onerror should not be called. // That is currently not the case. // // We don't need to call clearLoader here: Either we were called from the // task, or our caller updateFromElement cleared the task's loader (and set // m_pendingTask to null). m_pendingTask.clear(); // Make sure to only decrement the count when we exit this function OwnPtr<IncrementLoadEventDelayCount> loadDelayCounter; loadDelayCounter.swap(m_loadDelayCounter); Document& document = m_element->document(); if (!document.isActive()) return; AtomicString imageSourceURL = m_element->imageSourceURL(); KURL url = imageSourceToKURL(imageSourceURL); ResourcePtr<ImageResource> newImage = 0; RefPtrWillBeRawPtr<Element> protectElement(m_element.get()); if (!url.isNull()) { // Unlike raw <img>, we block mixed content inside of <picture> or <img srcset>. ResourceLoaderOptions resourceLoaderOptions = ResourceFetcher::defaultResourceOptions(); ResourceRequest resourceRequest(url); resourceRequest.setFetchCredentialsMode(WebURLRequest::FetchCredentialsModeSameOrigin); if (updateBehavior == UpdateForcedReload) { resourceRequest.setCachePolicy(ResourceRequestCachePolicy::ReloadBypassingCache); // ImageLoader defers the load of images when in an ImageDocument. Don't defer this load on a forced reload. m_loadingImageDocument = false; } if (isHTMLPictureElement(element()->parentNode()) || !element()->fastGetAttribute(HTMLNames::srcsetAttr).isNull()) resourceRequest.setRequestContext(WebURLRequest::RequestContextImageSet); FetchRequest request(resourceRequest, element()->localName(), resourceLoaderOptions); configureRequest(request, bypassBehavior, *m_element, document.clientHintsPreferences()); // Prevent the immediate creation of a ResourceLoader (and therefore a network // request) for ImageDocument loads. In this case, the image contents have already // been requested as a main resource and ImageDocumentParser will take care of // funneling the main resource bytes into the ImageResource. if (m_loadingImageDocument) { request.setDefer(FetchRequest::DeferredByClient); request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy); } newImage = ImageResource::fetch(request, document.fetcher()); if (m_loadingImageDocument && newImage) newImage->setLoading(true); if (!newImage && !pageIsBeingDismissed(&document)) { crossSiteOrCSPViolationOccurred(imageSourceURL); dispatchErrorEvent(); } else { clearFailedLoadURL(); } } else { if (!imageSourceURL.isNull()) { // Fire an error event if the url string is not empty, but the KURL is. dispatchErrorEvent(); } noImageResourceToLoad(); } ImageResource* oldImage = m_image.get(); if (updateBehavior == UpdateSizeChanged && m_element->layoutObject() && m_element->layoutObject()->isImage() && newImage == oldImage) { toLayoutImage(m_element->layoutObject())->intrinsicSizeChanged(); } else { if (newImage != oldImage) sourceImageChanged(); if (m_hasPendingLoadEvent) { loadEventSender().cancelEvent(this); m_hasPendingLoadEvent = false; } // Cancel error events that belong to the previous load, which is now cancelled by changing the src attribute. // If newImage is null and m_hasPendingErrorEvent is true, we know the error event has been just posted by // this load and we should not cancel the event. // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two. if (m_hasPendingErrorEvent && newImage) { errorEventSender().cancelEvent(this); m_hasPendingErrorEvent = false; } m_image = newImage; m_hasPendingLoadEvent = newImage; m_imageComplete = !newImage; updateLayoutObject(); // If newImage exists and is cached, addClient() will result in the load event // being queued to fire. Ensure this happens after beforeload is dispatched. if (newImage) newImage->addClient(this); if (oldImage) oldImage->removeClient(this); } if (LayoutImageResource* imageResource = layoutImageResource()) imageResource->resetAnimation(); // Only consider updating the protection ref-count of the Element immediately before returning // from this function as doing so might result in the destruction of this ImageLoader. updatedHasPendingEvent(); }
void ImageLoader::doUpdateFromElement(UpdateFromElementBehavior updateBehavior) { // FIXME: According to // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content.html#the-img-element:the-img-element-55 // When "update image" is called due to environment changes and the load fails, onerror should not be called. // That is currently not the case. // // We don't need to call clearLoader here: Either we were called from the // task, or our caller updateFromElement cleared the task's loader (and set // m_pendingTask to null). m_pendingTask.clear(); // Make sure to only decrement the count when we exit this function OwnPtr<IncrementLoadEventDelayCount> loadDelayCounter; loadDelayCounter.swap(m_loadDelayCounter); Document& document = m_element->document(); if (!document.isActive()) return; AtomicString imageSourceURL = m_element->imageSourceURL(); KURL url = imageSourceToKURL(imageSourceURL); ResourcePtr<ImageResource> newImage = 0; if (!url.isNull()) { // Unlike raw <img>, we block mixed content inside of <picture> or <img srcset>. ResourceLoaderOptions resourceLoaderOptions = ResourceFetcher::defaultResourceOptions(); ResourceRequest resourceRequest(url); FetchRequest request(ResourceRequest(url), element()->localName(), resourceLoaderOptions); newImage = document.fetcher()->fetchImage(request); if (!newImage && !pageIsBeingDismissed(&document)) crossSiteOrCSPViolationOccured(imageSourceURL); else clearFailedLoadURL(); } else if (!imageSourceURL.isNull()) { // Fire an error event if the url string is not empty, but the KURL is. m_hasPendingErrorEvent = true; errorEventSender().dispatchEventSoon(this); } ImageResource* oldImage = m_image.get(); if (newImage != oldImage) { sourceImageChanged(); if (m_hasPendingLoadEvent) { loadEventSender().cancelEvent(this); m_hasPendingLoadEvent = false; } // Cancel error events that belong to the previous load, which is now cancelled by changing the src attribute. // If newImage is null and m_hasPendingErrorEvent is true, we know the error event has been just posted by // this load and we should not cancel the event. // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two. if (m_hasPendingErrorEvent && newImage) { errorEventSender().cancelEvent(this); m_hasPendingErrorEvent = false; } m_image = newImage; m_hasPendingLoadEvent = newImage; m_imageComplete = !newImage; updateRenderer(); // If newImage exists and is cached, addClient() will result in the load event // being queued to fire. Ensure this happens after beforeload is dispatched. if (newImage) newImage->addClient(this); if (oldImage) oldImage->removeClient(this); } else if (updateBehavior == UpdateSizeChanged && m_element->renderer() && m_element->renderer()->isImage()) { toRenderImage(m_element->renderer())->intrinsicSizeChanged(); } if (RenderImageResource* imageResource = renderImageResource()) imageResource->resetAnimation(); // Only consider updating the protection ref-count of the Element immediately before returning // from this function as doing so might result in the destruction of this ImageLoader. updatedHasPendingEvent(); }