Changeset 182247 in webkit


Ignore:
Timestamp:
Apr 1, 2015 12:02:35 PM (9 years ago)
Author:
yoav@yoav.ws
Message:

Async loading of image resources
https://bugs.webkit.org/show_bug.cgi?id=134488

Reviewed by Dean Jackson.

Source/WebCore:

This patch changes image loading to be asynchronous (per spec), in order
for it to be agnostic to property setting order when it comes to src, srcset and crossorigin,
as well as to enable future hooking of the <picture>-based selection logic on top of it.

Tests: fast/dom/HTMLImageElement/image-load-post-onload.html
fast/dom/HTMLImageElement/sizes/image-sizes-js-change-reverse.html

  • WebCore.xcodeproj/project.pbxproj: Change MicroTask.h to be private.
  • bindings/js/JSEventListener.cpp:

(WebCore::JSEventListener::handleEvent): Add a microtask checkpoint after event handling.

  • bindings/js/ScheduledAction.cpp:

(WebCore::ScheduledAction::execute): Add a microtask checkpoint after running of a scheduled action.

  • html/HTMLImageElement.cpp:

(WebCore::HTMLImageElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.

  • html/HTMLImageLoader.cpp:

(WebCore::HTMLImageLoader::notifyFinished): Avoid a crash when notifyFinished is called and there's no CachedImage.

  • html/HTMLInputElement.cpp:

(WebCore::HTMLInputElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.

  • html/HTMLPlugInImageElement.cpp:

(WebCore::HTMLPlugInImageElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.

  • html/HTMLVideoElement.cpp:

(WebCore::HTMLVideoElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.

  • html/parser/HTMLDocumentParser.cpp:

(WebCore::HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd): Add a microtask checkpoint.

  • loader/ImageLoader.cpp: Move image resource loading to be asynchronous.

(WebCore::ImageLoader::ImageLoaderTask::create):
(WebCore::ImageLoader::ImageLoaderTask::run): Run the image loading microtask and called doUpdateFromElement.
(WebCore::ImageLoader::ImageLoaderTask::ImageLoaderTask):
(WebCore::ImageLoader::ImageLoader):
(WebCore::ImageLoader::doUpdateFromElement): This is split from the previous updateFromElement, and performs the actual resource loading.
(WebCore::ImageLoader::updateFromElement): Now only prepares the stage for the actual image resource loading.
(WebCore::ImageLoader::shouldLoadImmediately): If this returns true, the image resource is loaded immediately, without queueing a microtask.
(WebCore::ImageLoader::notifyFinished): Add asserts.
(WebCore::ImageLoader::elementDidMoveToNewDocument): Handle document load event counters decrementing and incrementing.

  • loader/ImageLoader.h:

(WebCore::ImageLoader::imageComplete): Make sure that the image is complete only if there aren't any pending tasks.
(WebCore::ImageLoader::hasPendingActivity): Make sure that pending activity takes pending tasks into account.
(WebCore::ImageLoader::hasPendingTask): Getter to know if an ImageLoader has a pending task. (Used by the image loading microtask)
(WebCore::ImageLoader::createWeakPtr): Create a weakPtr to be used by the microtask, so it can called back the loader if it's still alive.

  • loader/cache/CachedResourceLoader.cpp:

(WebCore::CachedResourceLoader::canRequest): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag and act upon it.
(WebCore::CachedResourceLoader::requestImage): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag.
(WebCore::CachedResourceLoader::requestResource): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag.

  • loader/cache/CachedResourceLoader.h:

(WebCore::CachedResourceLoader::canRequest): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag and act upon it.
(WebCore::CachedResourceLoader::requestImage): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag.
(WebCore::CachedResourceLoader::requestResource): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag.

  • svg/SVGImageElement.cpp:

(WebCore::SVGImageElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.

  • xml/parser/XMLDocumentParser.cpp:

(WebCore::XMLDocumentParser::end): Add a microtask checkpoint after XML finishes parsing.

LayoutTests:

  • fast/dom/HTMLImageElement/image-load-post-onload-expected.txt: Added.
  • fast/dom/HTMLImageElement/image-load-post-onload.html: Added.
  • fast/dom/HTMLImageElement/image-loading-gc.html: Cosmetic changes.
  • fast/dom/HTMLImageElement/sizes/image-sizes-js-change-reverse-expected.txt: Added.
  • fast/dom/HTMLImageElement/sizes/image-sizes-js-change-reverse.html: Added.
  • fast/dom/image-object.html: Cosmetic changes.
  • http/tests/misc/image-blocked-src-change-expected.txt: Removed line numbers from console.
  • http/tests/misc/image-blocked-src-no-change-expected.txt: Removed line numbers from console.
  • http/tests/security/contentSecurityPolicy/report-blocked-file-uri-expected.txt: Removed line numbers from console.
  • http/tests/security/frame-loading-via-document-write-expected.txt: Removed line numbers from console.
  • http/tests/security/local-image-from-remote-expected.txt: Removed line numbers from console.
Location:
trunk
Files:
4 added
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r182242 r182247  
     12015-04-01  Yoav Weiss  <yoav@yoav.ws>
     2
     3        Async loading of image resources
     4        https://bugs.webkit.org/show_bug.cgi?id=134488
     5
     6        Reviewed by Dean Jackson.
     7
     8        * fast/dom/HTMLImageElement/image-load-post-onload-expected.txt: Added.
     9        * fast/dom/HTMLImageElement/image-load-post-onload.html: Added.
     10        * fast/dom/HTMLImageElement/image-loading-gc.html: Cosmetic changes.
     11        * fast/dom/HTMLImageElement/sizes/image-sizes-js-change-reverse-expected.txt: Added.
     12        * fast/dom/HTMLImageElement/sizes/image-sizes-js-change-reverse.html: Added.
     13        * fast/dom/image-object.html: Cosmetic changes.
     14        * http/tests/misc/image-blocked-src-change-expected.txt: Removed line numbers from console.
     15        * http/tests/misc/image-blocked-src-no-change-expected.txt: Removed line numbers from console.
     16        * http/tests/security/contentSecurityPolicy/report-blocked-file-uri-expected.txt: Removed line numbers from console.
     17        * http/tests/security/frame-loading-via-document-write-expected.txt: Removed line numbers from console.
     18        * http/tests/security/local-image-from-remote-expected.txt: Removed line numbers from console.
     19
    1202015-03-31  Simon Fraser  <simon.fraser@apple.com>
    221
  • trunk/LayoutTests/fast/dom/HTMLImageElement/image-loading-gc.html

    r120792 r182247  
    3333</script>
    3434<body onload="runTest()">
    35 <div>This tests that an image element won't be garbage collected when it's loading, even if it doesn't have any references.
     35    <div>This tests that an image element won't be garbage collected when it's loading, even if it doesn't have any references.</div>
    3636<div id="result">FAILURE</div>
    3737</body>
  • trunk/LayoutTests/fast/dom/image-object.html

    r120792 r182247  
    4747        numErrs++;
    4848    }
    49    
    50     i2 = new Image()
     49    i2 = new Image();
    5150    i2.onload = imageLoaded;
    5251    i2.src = 'resources/apple.gif';
  • trunk/LayoutTests/http/tests/misc/image-blocked-src-change-expected.txt

    r136657 r182247  
    1 CONSOLE MESSAGE: line 44: Not allowed to load local resource: compass.jpg
     1CONSOLE MESSAGE: Not allowed to load local resource: compass.jpg
    22Test case for bug 17897 : Not Rendering Images Imported from XHTML Document
    33
  • trunk/LayoutTests/http/tests/misc/image-blocked-src-no-change-expected.txt

    r178527 r182247  
    1 CONSOLE MESSAGE: line 27: Not allowed to load local resource: compass.jpg
    2 CONSOLE MESSAGE: line 21: Not allowed to load local resource: compass.jpg
     1CONSOLE MESSAGE: Not allowed to load local resource: compass.jpg
     2CONSOLE MESSAGE: Not allowed to load local resource: compass.jpg
    33Test case for bug 17897 : Not Rendering Images Imported from XHTML Document
    44
  • trunk/LayoutTests/http/tests/security/contentSecurityPolicy/report-blocked-file-uri-expected.txt

    r146758 r182247  
    66REQUEST_METHOD: POST
    77=== POST DATA ===
    8 {"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-blocked-file-uri.html","referrer":"","violated-directive":"img-src 'none'","original-policy":"img-src 'none'; report-uri resources/save-report.php","blocked-uri":"file","source-file":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-blocked-file-uri.html","line-number":12}}
     8{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-blocked-file-uri.html","referrer":"","violated-directive":"img-src 'none'","original-policy":"img-src 'none'; report-uri resources/save-report.php","blocked-uri":"file"}}
  • trunk/LayoutTests/http/tests/security/frame-loading-via-document-write-expected.txt

    r136657 r182247  
    1 CONSOLE MESSAGE: line 1: Not allowed to load local resource: abe.png
     1CONSOLE MESSAGE: Not allowed to load local resource: abe.png
    22
    33
  • trunk/LayoutTests/http/tests/security/local-image-from-remote-expected.txt

    r178527 r182247  
    1 CONSOLE MESSAGE: line 14: Not allowed to load local resource: compass.jpg
     1CONSOLE MESSAGE: Not allowed to load local resource: compass.jpg
    22This test is to see if a remote file can include a local image.
    33Currently this test cannot be run manually on Windows because we do not have a function like pathToLocalResource() outside of DRT.
  • trunk/Source/WebCore/ChangeLog

    r182244 r182247  
     12015-04-01  Yoav Weiss  <yoav@yoav.ws>
     2
     3        Async loading of image resources
     4        https://bugs.webkit.org/show_bug.cgi?id=134488
     5
     6        Reviewed by Dean Jackson.
     7
     8        This patch changes image loading to be asynchronous (per spec), in order
     9        for it to be agnostic to property setting order when it comes to src, srcset and crossorigin,
     10        as well as to enable future hooking of the <picture>-based selection logic on top of it.
     11
     12        Tests: fast/dom/HTMLImageElement/image-load-post-onload.html
     13        fast/dom/HTMLImageElement/sizes/image-sizes-js-change-reverse.html
     14
     15        * WebCore.xcodeproj/project.pbxproj: Change MicroTask.h to be private.
     16        * bindings/js/JSEventListener.cpp:
     17        (WebCore::JSEventListener::handleEvent): Add a microtask checkpoint after event handling.
     18        * bindings/js/ScheduledAction.cpp:
     19        (WebCore::ScheduledAction::execute): Add a microtask checkpoint after running of a scheduled action.
     20        * html/HTMLImageElement.cpp:
     21        (WebCore::HTMLImageElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.
     22        * html/HTMLImageLoader.cpp:
     23        (WebCore::HTMLImageLoader::notifyFinished): Avoid a crash when notifyFinished is called and there's no CachedImage.
     24        * html/HTMLInputElement.cpp:
     25        (WebCore::HTMLInputElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.
     26        * html/HTMLPlugInImageElement.cpp:
     27        (WebCore::HTMLPlugInImageElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.
     28        * html/HTMLVideoElement.cpp:
     29        (WebCore::HTMLVideoElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.
     30        * html/parser/HTMLDocumentParser.cpp:
     31        (WebCore::HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd): Add a microtask checkpoint.
     32        * loader/ImageLoader.cpp: Move image resource loading to be asynchronous.
     33        (WebCore::ImageLoader::ImageLoaderTask::create):
     34        (WebCore::ImageLoader::ImageLoaderTask::run): Run the image loading microtask and called doUpdateFromElement.
     35        (WebCore::ImageLoader::ImageLoaderTask::ImageLoaderTask):
     36        (WebCore::ImageLoader::ImageLoader):
     37        (WebCore::ImageLoader::doUpdateFromElement): This is split from the previous updateFromElement, and performs the actual resource loading.
     38        (WebCore::ImageLoader::updateFromElement): Now only prepares the stage for the actual image resource loading.
     39        (WebCore::ImageLoader::shouldLoadImmediately): If this returns true, the image resource is loaded immediately, without queueing a microtask.
     40        (WebCore::ImageLoader::notifyFinished): Add asserts.
     41        (WebCore::ImageLoader::elementDidMoveToNewDocument): Handle document load event counters decrementing and incrementing.
     42        * loader/ImageLoader.h:
     43        (WebCore::ImageLoader::imageComplete): Make sure that the image is complete only if there aren't any pending tasks.
     44        (WebCore::ImageLoader::hasPendingActivity): Make sure that pending activity takes pending tasks into account.
     45        (WebCore::ImageLoader::hasPendingTask): Getter to know if an ImageLoader has a pending task. (Used by the image loading microtask)
     46        (WebCore::ImageLoader::createWeakPtr): Create a weakPtr to be used by the microtask, so it can called back the loader if it's still alive.
     47        * loader/cache/CachedResourceLoader.cpp:
     48        (WebCore::CachedResourceLoader::canRequest): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag and act upon it.
     49        (WebCore::CachedResourceLoader::requestImage): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag.
     50        (WebCore::CachedResourceLoader::requestResource): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag.
     51        * loader/cache/CachedResourceLoader.h:
     52        (WebCore::CachedResourceLoader::canRequest): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag and act upon it.
     53        (WebCore::CachedResourceLoader::requestImage): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag.
     54        (WebCore::CachedResourceLoader::requestResource): Add a 'shouldBypassMainWorldContentSecurityPolicy' flag.
     55        * svg/SVGImageElement.cpp:
     56        (WebCore::SVGImageElement::didMoveToNewDocument): Add the old document to call of elementDidMoveToNewDocument.
     57        * xml/parser/XMLDocumentParser.cpp:
     58        (WebCore::XMLDocumentParser::end): Add a microtask checkpoint after XML finishes parsing.
     59
    1602015-04-01  Alex Christensen  <achristensen@webkit.org>
    261
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r182211 r182247  
    21022102                536D5A25193F40FC00CE4CAB /* SourceSizeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 536D5A24193F40FC00CE4CAB /* SourceSizeList.cpp */; };
    21032103                536D5A27193F410B00CE4CAB /* SourceSizeList.h in Headers */ = {isa = PBXBuildFile; fileRef = 536D5A26193F410B00CE4CAB /* SourceSizeList.h */; settings = {ATTRIBUTES = (Private, ); }; };
    2104                 53B895AF19DC7ED9009CAA93 /* MicroTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 53B895AD19DC7C37009CAA93 /* MicroTask.h */; settings = {ATTRIBUTES = (Public, ); }; };
     2104                53B895AF19DC7ED9009CAA93 /* MicroTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 53B895AD19DC7C37009CAA93 /* MicroTask.h */; settings = {ATTRIBUTES = (Private, ); }; };
    21052105                53C8298D13D8D92700DE2DEB /* RenderFlexibleBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53C8298B13D8D92700DE2DEB /* RenderFlexibleBox.cpp */; };
    21062106                53C8298E13D8D92700DE2DEB /* RenderFlexibleBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 53C8298C13D8D92700DE2DEB /* RenderFlexibleBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
  • trunk/Source/WebCore/bindings/js/JSEventListener.cpp

    r182205 r182247  
    3030#include "JSMainThreadExecState.h"
    3131#include "JSMainThreadExecStateInstrumentation.h"
     32#include "MicroTask.h"
    3233#include "ScriptController.h"
    3334#include "WorkerGlobalScope.h"
     
    152153        }
    153154    }
     155    if (scriptExecutionContext->isDocument())
     156        MicroTaskQueue::singleton().runMicroTasks();
    154157}
    155158
  • trunk/Source/WebCore/bindings/js/ScheduledAction.cpp

    r176065 r182247  
    3535#include "JSMainThreadExecStateInstrumentation.h"
    3636#include "JSWorkerGlobalScope.h"
     37#include "MicroTask.h"
    3738#include "ScriptController.h"
    3839#include "ScriptExecutionContext.h"
     
    126127    else
    127128        frame->script().executeScriptInWorld(*m_isolatedWorld, m_code);
     129
     130    MicroTaskQueue::singleton().runMicroTasks();
    128131}
    129132
  • trunk/Source/WebCore/html/HTMLImageElement.cpp

    r182120 r182247  
    453453void HTMLImageElement::didMoveToNewDocument(Document* oldDocument)
    454454{
    455     m_imageLoader.elementDidMoveToNewDocument();
     455    m_imageLoader.elementDidMoveToNewDocument(oldDocument);
    456456    HTMLElement::didMoveToNewDocument(oldDocument);
    457457}
  • trunk/Source/WebCore/html/HTMLImageLoader.cpp

    r181412 r182247  
    7777{
    7878    CachedImage* cachedImage = image();
     79    if (!cachedImage)
     80        return;
    7981
    8082    Ref<Element> protect(element());
  • trunk/Source/WebCore/html/HTMLInputElement.cpp

    r181615 r182247  
    14961496{
    14971497    if (imageLoader())
    1498         imageLoader()->elementDidMoveToNewDocument();
     1498        imageLoader()->elementDidMoveToNewDocument(oldDocument);
    14991499
    15001500    bool needsSuspensionCallback = this->needsSuspensionCallback();
  • trunk/Source/WebCore/html/HTMLPlugInImageElement.cpp

    r182205 r182247  
    307307
    308308    if (m_imageLoader)
    309         m_imageLoader->elementDidMoveToNewDocument();
     309        m_imageLoader->elementDidMoveToNewDocument(oldDocument);
    310310
    311311    HTMLPlugInElement::didMoveToNewDocument(oldDocument);
  • trunk/Source/WebCore/html/HTMLVideoElement.cpp

    r182120 r182247  
    310310{
    311311    if (m_imageLoader)
    312         m_imageLoader->elementDidMoveToNewDocument();
     312        m_imageLoader->elementDidMoveToNewDocument(oldDocument);
    313313    HTMLMediaElement::didMoveToNewDocument(oldDocument);
    314314}
  • trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp

    r178648 r182247  
    3535#include "HTMLDocument.h"
    3636#include "InspectorInstrumentation.h"
     37#include "MicroTask.h"
    3738
    3839namespace WebCore {
     
    410411        return;
    411412    end();
     413    if (!isExecutingScript())
     414        MicroTaskQueue::singleton().runMicroTasks();
    412415}
    413416
  • trunk/Source/WebCore/loader/ImageLoader.cpp

    r181897 r182247  
    33 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
    44 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 Apple Inc. All rights reserved.
     5 * Copyright 2014 The Chromium Authors. All rights reserved.
     6 * Copyright (C) 2015 Akamai Technologies Inc. All rights reserved.
    57 *
    68 * This library is free software; you can redistribute it and/or
     
    3537#include "HTMLObjectElement.h"
    3638#include "HTMLParserIdioms.h"
     39#include "MemoryCache.h"
    3740#include "Page.h"
    3841#include "RenderImage.h"
    3942#include "RenderSVGImage.h"
     43#include "ScriptController.h"
    4044#include "SecurityOrigin.h"
    4145#include <wtf/NeverDestroyed.h>
     
    6468namespace WebCore {
    6569
     70class ImageLoader::ImageLoaderTask : public MicroTask {
     71public:
     72    ImageLoaderTask(WeakPtr<ImageLoader> loader, CachedResourceLoader::ShouldBypassMainWorldContentSecurityPolicy shouldBypassMainWorldContentSecurityPolicy)
     73        : m_loader(loader)
     74        , m_shouldBypassMainWorldContentSecurityPolicy(shouldBypassMainWorldContentSecurityPolicy)
     75    {
     76    }
     77
     78private:
     79    virtual void run() override
     80    {
     81        if (m_loader && m_loader->hasPendingTask())
     82            m_loader->doUpdateFromElement(m_shouldBypassMainWorldContentSecurityPolicy);
     83    }
     84
     85    WeakPtr<ImageLoader> m_loader;
     86    CachedResourceLoader::ShouldBypassMainWorldContentSecurityPolicy m_shouldBypassMainWorldContentSecurityPolicy;
     87};
     88
    6689static ImageEventSender& beforeLoadEventSender()
    6790{
     
    92115    , m_image(0)
    93116    , m_derefElementTimer(*this, &ImageLoader::timerFired)
     117    , m_weakFactory(this)
    94118    , m_hasPendingBeforeLoadEvent(false)
    95119    , m_hasPendingLoadEvent(false)
     
    98122    , m_loadManually(false)
    99123    , m_elementIsProtected(false)
     124    , m_hasPendingTask(false)
    100125{
    101126}
     
    160185}
    161186
    162 void ImageLoader::updateFromElement()
    163 {
    164     // If we're not making renderers for the page, then don't load images.  We don't want to slow
    165     // down the raw HTML parsing case by loading images we don't intend to display.
    166     Document& document = element().document();
    167     if (!document.hasLivingRenderTree())
    168         return;
    169 
    170     AtomicString attr = element().imageSourceURL();
    171 
    172     // Avoid loading a URL we already failed to load.
    173     if (!m_failedLoadURL.isEmpty() && attr == m_failedLoadURL)
    174         return;
    175 
     187void ImageLoader::doUpdateFromElement(CachedResourceLoader::ShouldBypassMainWorldContentSecurityPolicy shouldBypassMainWorldContentSecurityPolicy)
     188{
     189    m_hasPendingTask = false;
     190    Document& document = m_element.document();
     191    AtomicString attr = m_element.imageSourceURL();
     192
     193    String srcURI = sourceURI(attr);
     194    URL url;
     195    // Set url value only if srcURI is not empty. Otherwise, url will be the URL for the document itself.
     196    if (!srcURI.isEmpty())
     197        url = document.completeURL(srcURI);
    176198    // Do not load any image if the 'src' attribute is missing or if it is
    177199    // an empty string.
    178200    CachedResourceHandle<CachedImage> newImage = 0;
    179     if (!attr.isNull() && !stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) {
    180         CachedResourceRequest request(ResourceRequest(document.completeURL(sourceURI(attr))));
     201    if (!url.isNull()) {
     202        ResourceRequest resourceRequest(url);
     203        CachedResourceRequest request(resourceRequest);
    181204        request.setInitiator(&element());
    182205
    183         String crossOriginMode = element().fastGetAttribute(HTMLNames::crossoriginAttr);
     206        AtomicString crossOriginMode = m_element.fastGetAttribute(HTMLNames::crossoriginAttr);
    184207        if (!crossOriginMode.isNull()) {
    185208            StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials;
     
    196219            document.cachedResourceLoader().setAutoLoadImages(autoLoadOtherImages);
    197220        } else
    198             newImage = document.cachedResourceLoader().requestImage(request);
     221            newImage = document.cachedResourceLoader().requestImage(request, shouldBypassMainWorldContentSecurityPolicy);
    199222
    200223        // If we do not have an image here, it means that a cross-site
     
    214237        errorEventSender().dispatchEventSoon(*this);
    215238    }
    216    
     239
    217240    CachedImage* oldImage = m_image.get();
    218241    if (newImage != oldImage) {
     
    266289    // from this function as doing so might result in the destruction of this ImageLoader.
    267290    updatedHasPendingEvent();
     291    document.decrementLoadEventDelayCount();
     292}
     293
     294void ImageLoader::updateFromElement()
     295{
     296    AtomicString attribute = m_element.imageSourceURL();
     297
     298    // Avoid loading a URL we already failed to load.
     299    if (!m_failedLoadURL.isEmpty() && attribute == m_failedLoadURL)
     300        return;
     301
     302    // If we're not making renderers for the page, then don't load images. We don't want to slow
     303    // down the raw HTML parsing case by loading images we don't intend to display.
     304    Document& document = element().document();
     305    if (!document.hasLivingRenderTree())
     306        return;
     307
     308    CachedResourceLoader::ShouldBypassMainWorldContentSecurityPolicy shouldBypassMainWorldContentSecurityPolicy = CachedResourceLoader::ShouldBypassMainWorldContentSecurityPolicy::No;
     309    if (document.frame() && document.frame()->script().shouldBypassMainWorldContentSecurityPolicy())
     310        shouldBypassMainWorldContentSecurityPolicy = CachedResourceLoader::ShouldBypassMainWorldContentSecurityPolicy::Yes;
     311
     312    if (!m_hasPendingTask) {
     313        m_hasPendingTask = true;
     314        document.incrementLoadEventDelayCount();
     315        if (shouldLoadImmediately(attribute))
     316            doUpdateFromElement(CachedResourceLoader::ShouldBypassMainWorldContentSecurityPolicy::No);
     317        else
     318            MicroTaskQueue::singleton().queueMicroTask(std::make_unique<ImageLoaderTask>(createWeakPtr(), shouldBypassMainWorldContentSecurityPolicy));
     319    }
     320}
     321
     322bool ImageLoader::shouldLoadImmediately(const AtomicString& attribute) const
     323{
     324    String srcURI = sourceURI(attribute);
     325    URL url = element().document().completeURL(srcURI);
     326    return (srcURI.isEmpty()
     327        || url.isEmpty()
     328        || m_loadManually
     329        || !is<HTMLImageElement>(m_element)
     330        || url.protocolIsData()
     331        || MemoryCache::singleton().resourceForURL(url));
    268332}
    269333
     
    277341{
    278342    ASSERT(m_failedLoadURL.isEmpty());
     343    ASSERT(resource);
    279344    ASSERT(resource == m_image.get());
    280345
     
    285350    if (!m_hasPendingLoadEvent)
    286351        return;
     352
     353    ASSERT(image());
     354    ASSERT(element().document().securityOrigin());
    287355
    288356    if (element().fastHasAttribute(HTMLNames::crossoriginAttr)
     
    465533}
    466534
    467 void ImageLoader::elementDidMoveToNewDocument()
    468 {
     535void ImageLoader::elementDidMoveToNewDocument(Document* oldDocument)
     536{
     537    if (m_hasPendingTask) {
     538        if (oldDocument)
     539            oldDocument->decrementLoadEventDelayCount();
     540        m_element.document().incrementLoadEventDelayCount();
     541    }
    469542    clearFailedLoadURL();
    470543    clearImage();
  • trunk/Source/WebCore/loader/ImageLoader.h

    r181849 r182247  
    2626#include "CachedImageClient.h"
    2727#include "CachedResourceHandle.h"
     28#include "CachedResourceLoader.h"
     29#include "MicroTask.h"
    2830#include "Timer.h"
     31#include <wtf/RefCounted.h>
     32#include <wtf/WeakPtr.h>
    2933#include <wtf/text/AtomicString.h>
    3034
    3135namespace WebCore {
    3236
     37class Document;
    3338class Element;
    3439class ImageLoader;
    3540class RenderImageResource;
     41class URL;
     42class Task;
    3643
    3744template<typename T> class EventSender;
     
    5158    void updateFromElementIgnoringPreviousError();
    5259
    53     void elementDidMoveToNewDocument();
     60    void elementDidMoveToNewDocument(Document* oldDocument);
    5461
    5562    Element& element() { return m_element; }
    5663    const Element& element() const { return m_element; }
    5764
    58     bool imageComplete() const { return m_imageComplete; }
     65    bool imageComplete() const { return m_imageComplete && !m_hasPendingTask; }
    5966
    6067    CachedImage* image() const { return m_image.get(); }
     
    6471
    6572    bool hasPendingBeforeLoadEvent() const { return m_hasPendingBeforeLoadEvent; }
    66     bool hasPendingActivity() const { return m_hasPendingLoadEvent || m_hasPendingErrorEvent; }
     73    bool hasPendingActivity() const { return m_hasPendingLoadEvent || m_hasPendingErrorEvent || m_hasPendingTask; }
    6774
    6875    void dispatchPendingEvent(ImageEventSender*);
     
    7279    static void dispatchPendingErrorEvents();
    7380
     81    bool hasPendingTask() const { return m_hasPendingTask; }
     82
    7483protected:
    7584    explicit ImageLoader(Element&);
     
    7786
    7887private:
     88    class ImageLoaderTask;
     89
     90    // Called from the task or from updateFromElement to initiate the load.
     91    void doUpdateFromElement(CachedResourceLoader::ShouldBypassMainWorldContentSecurityPolicy);
    7992    virtual void dispatchLoadEvent() = 0;
    8093    virtual String sourceURI(const AtomicString&) const = 0;
     
    94107    void timerFired();
    95108
     109    // Determine whether to initiate a synchronous load or to schedule a microtask.
     110    bool shouldLoadImmediately(const AtomicString& attribtue) const;
     111    WeakPtr<ImageLoader> createWeakPtr() { return m_weakFactory.createWeakPtr(); }
     112
    96113    Element& m_element;
    97114    CachedResourceHandle<CachedImage> m_image;
    98115    Timer m_derefElementTimer;
     116    WeakPtrFactory<ImageLoader> m_weakFactory;
    99117    AtomicString m_failedLoadURL;
    100118    bool m_hasPendingBeforeLoadEvent : 1;
     
    104122    bool m_loadManually : 1;
    105123    bool m_elementIsProtected : 1;
     124    bool m_hasPendingTask : 1;
    106125};
    107126
  • trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp

    r182016 r182247  
    174174}
    175175
    176 CachedResourceHandle<CachedImage> CachedResourceLoader::requestImage(CachedResourceRequest& request)
     176CachedResourceHandle<CachedImage> CachedResourceLoader::requestImage(CachedResourceRequest& request, ShouldBypassMainWorldContentSecurityPolicy shouldBypassMainWorldContentSecurityPolicy)
    177177{
    178178    if (Frame* frame = this->frame()) {
     
    186186   
    187187    request.setDefer(clientDefersImage(request.resourceRequest().url()) ? CachedResourceRequest::DeferredByClient : CachedResourceRequest::NoDefer);
    188     return downcast<CachedImage>(requestResource(CachedResource::ImageResource, request).get());
     188    return downcast<CachedImage>(requestResource(CachedResource::ImageResource, request, shouldBypassMainWorldContentSecurityPolicy).get());
    189189}
    190190
     
    358358}
    359359
    360 bool CachedResourceLoader::canRequest(CachedResource::Type type, const URL& url, const ResourceLoaderOptions& options, bool forPreload)
     360bool CachedResourceLoader::canRequest(CachedResource::Type type, const URL& url, const ResourceLoaderOptions& options, bool forPreload, ShouldBypassMainWorldContentSecurityPolicy bypassMainWorldContentSecurityPolicy)
    361361{
    362362    if (document() && !document()->securityOrigin()->canDisplay(url)) {
     
    367367    }
    368368
     369
    369370    // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
    370     bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script().shouldBypassMainWorldContentSecurityPolicy());
     371    bool shouldBypassMainWorldContentSecurityPolicy = (bypassMainWorldContentSecurityPolicy == ShouldBypassMainWorldContentSecurityPolicy::Yes)
     372        || (frame() && frame()->script().shouldBypassMainWorldContentSecurityPolicy());
    371373
    372374    // Some types of resources can be loaded only from the same origin.  Other
     
    493495}
    494496
    495 CachedResourceHandle<CachedResource> CachedResourceLoader::requestResource(CachedResource::Type type, CachedResourceRequest& request)
     497CachedResourceHandle<CachedResource> CachedResourceLoader::requestResource(CachedResource::Type type, CachedResourceRequest& request, ShouldBypassMainWorldContentSecurityPolicy shouldBypassMainWorldContentSecurityPolicy)
    496498{
    497499    URL url = request.resourceRequest().url();
     
    505507        return nullptr;
    506508
    507     if (!canRequest(type, url, request.options(), request.forPreload()))
     509    if (!canRequest(type, url, request.options(), request.forPreload(), shouldBypassMainWorldContentSecurityPolicy))
    508510        return nullptr;
    509511
  • trunk/Source/WebCore/loader/cache/CachedResourceLoader.h

    r179626 r182247  
    7272    ~CachedResourceLoader();
    7373
    74     CachedResourceHandle<CachedImage> requestImage(CachedResourceRequest&);
     74    enum class ShouldBypassMainWorldContentSecurityPolicy { No, Yes };
     75
     76    CachedResourceHandle<CachedImage> requestImage(CachedResourceRequest&, ShouldBypassMainWorldContentSecurityPolicy = ShouldBypassMainWorldContentSecurityPolicy::No);
    7577    CachedResourceHandle<CachedCSSStyleSheet> requestCSSStyleSheet(CachedResourceRequest&);
    7678    CachedResourceHandle<CachedCSSStyleSheet> requestUserCSSStyleSheet(CachedResourceRequest&);
     
    132134    void checkForPendingPreloads();
    133135    void printPreloadStats();
    134     bool canRequest(CachedResource::Type, const URL&, const ResourceLoaderOptions&, bool forPreload = false);
     136    bool canRequest(CachedResource::Type, const URL&, const ResourceLoaderOptions&, bool forPreload = false, ShouldBypassMainWorldContentSecurityPolicy = ShouldBypassMainWorldContentSecurityPolicy::No);
    135137
    136138    static const ResourceLoaderOptions& defaultCachedResourceOptions();
     
    141143    explicit CachedResourceLoader(DocumentLoader*);
    142144
    143     CachedResourceHandle<CachedResource> requestResource(CachedResource::Type, CachedResourceRequest&);
     145    CachedResourceHandle<CachedResource> requestResource(CachedResource::Type, CachedResourceRequest&, ShouldBypassMainWorldContentSecurityPolicy = ShouldBypassMainWorldContentSecurityPolicy::No);
    144146    CachedResourceHandle<CachedResource> revalidateResource(const CachedResourceRequest&, CachedResource*);
    145147    CachedResourceHandle<CachedResource> loadResource(CachedResource::Type, CachedResourceRequest&);
  • trunk/Source/WebCore/svg/SVGImageElement.cpp

    r182121 r182247  
    206206void SVGImageElement::didMoveToNewDocument(Document* oldDocument)
    207207{
    208     m_imageLoader.elementDidMoveToNewDocument();
     208    m_imageLoader.elementDidMoveToNewDocument(oldDocument);
    209209    SVGGraphicsElement::didMoveToNewDocument(oldDocument);
    210210}
  • trunk/Source/WebCore/xml/parser/XMLDocumentParser.cpp

    r178648 r182247  
    4141#include "HTMLStyleElement.h"
    4242#include "ImageLoader.h"
     43#include "MicroTask.h"
    4344#include "ProcessingInstruction.h"
    4445#include "ResourceError.h"
     
    201202    clearCurrentNodeStack();
    202203    document()->finishedParsing();
     204    MicroTaskQueue::singleton().runMicroTasks();
    203205}
    204206
Note: See TracChangeset for help on using the changeset viewer.