Changeset 87628 in webkit


Ignore:
Timestamp:
May 28, 2011 6:37:59 PM (13 years ago)
Author:
ap@apple.com
Message:

Reviewed by Geoff Garen.

REGRESSION (r85375): Load event is sometimes lost when multiple image elements use the same URL
https://bugs.webkit.org/show_bug.cgi?id=61692
<rdar://problem/9488628>

Test: fast/dom/gc-image-element-2.html

Manually verified that tests from bug 59604 and from bug 40926 still pass.

The problem here was that HTMLImageElement::hasPendingActivity() could return false when
a load (or error) event was still expected to fire.

  • loader/cache/CachedResource.cpp: (WebCore::CachedResource::setRequest):
  • loader/cache/CachedResource.h: (WebCore::CachedResource::wasCanceled): (WebCore::CachedResource::errorOccurred): Track whether the load was canceled. We want to always notify clients of load outcome, as that's the only way they could make intelligent decisions.
  • dom/ScriptElement.cpp: (WebCore::ScriptElement::execute): Cached resource clients now get a notifyFinished call on cancellation. Handle this case, where we don't need the execute the script, but also don't need to fire an error event.
  • html/HTMLImageElement.cpp: Moved hasPendingActivity() to header, since it's just a single function call now.
  • html/HTMLImageElement.h: (WebCore::HTMLImageElement::hasPendingActivity): There is a large window between when CachedResource::isLoading() becomes false and events are queued. ImageLoader::haveFiredLoadEvent() is a much better indication of whether we are expecting an event to fire.
  • html/HTMLLinkElement.cpp: (WebCore::HTMLLinkElement::onloadTimerFired): Again, don't do anything on cancellation.
  • loader/ImageLoader.cpp: (WebCore::ImageEventSender::hasPendingEvents): Made it debug-only again, and fixed to give an accurate result while looping over the list of events to dispatch. (WebCore::ImageLoader::notifyFinished): Don't do anything when cancelled. We don't want to switch to a broken image icon, or to dispatch events. (WebCore::ImageEventSender::dispatchPendingEvents): Clear the current loader from dispatching list, as the event is no longer pending when it's being dispatched.
  • loader/ImageLoader.h: Removed unnecessary hasPendingLoadEvent(). We don't care whether one is already pending, we only care if one is expected at some time in the future, and !haveFiredLoadEvent() is our best idea of that.
  • dom/XMLDocumentParser.cpp: (WebCore::XMLDocumentParser::notifyFinished): Another place to handle cancellation.
Location:
trunk
Files:
2 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r87625 r87628  
     12011-05-28  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Reviewed by Geoff Garen.
     4
     5        REGRESSION (r85375): Load event is sometimes lost when multiple image elements use the same URL
     6        https://bugs.webkit.org/show_bug.cgi?id=61692
     7        <rdar://problem/9488628>
     8
     9        * fast/dom/gc-image-element-2-expected.txt: Added.
     10        * fast/dom/gc-image-element-2.html: Added.
     11
    1122011-05-28  Martin Robinson  <mrobinson@igalia.com>
    213
  • trunk/Source/WebCore/ChangeLog

    r87623 r87628  
     12011-05-28  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Reviewed by Geoff Garen.
     4
     5        REGRESSION (r85375): Load event is sometimes lost when multiple image elements use the same URL
     6        https://bugs.webkit.org/show_bug.cgi?id=61692
     7        <rdar://problem/9488628>
     8
     9        Test: fast/dom/gc-image-element-2.html
     10
     11        Manually verified that tests from bug 59604 and from bug 40926 still pass.
     12
     13        The problem here was that HTMLImageElement::hasPendingActivity() could return false when
     14        a load (or error) event was still expected to fire.
     15
     16        * loader/cache/CachedResource.cpp:
     17        (WebCore::CachedResource::setRequest):
     18        * loader/cache/CachedResource.h:
     19        (WebCore::CachedResource::wasCanceled):
     20        (WebCore::CachedResource::errorOccurred):
     21        Track whether the load was canceled. We want to always notify clients of load outcome,
     22        as that's the only way they could make intelligent decisions.
     23
     24        * dom/ScriptElement.cpp: (WebCore::ScriptElement::execute): Cached resource clients now
     25        get a notifyFinished call on cancellation. Handle this case, where we don't need the
     26        execute the script, but also don't need to fire an error event.
     27
     28        * html/HTMLImageElement.cpp: Moved hasPendingActivity() to header, since it's just a single
     29        function call now.
     30
     31        * html/HTMLImageElement.h: (WebCore::HTMLImageElement::hasPendingActivity): There is a large
     32        window between when CachedResource::isLoading() becomes false and events are queued.
     33        ImageLoader::haveFiredLoadEvent() is a much better indication of whether we are expecting
     34        an event to fire.
     35
     36        * html/HTMLLinkElement.cpp: (WebCore::HTMLLinkElement::onloadTimerFired): Again, don't do
     37        anything on cancellation.
     38
     39        * loader/ImageLoader.cpp:
     40        (WebCore::ImageEventSender::hasPendingEvents): Made it debug-only again, and fixed to
     41        give an accurate result while looping over the list of events to dispatch.
     42        (WebCore::ImageLoader::notifyFinished): Don't do anything when cancelled. We don't want to
     43        switch to a broken image icon, or to dispatch events.
     44        (WebCore::ImageEventSender::dispatchPendingEvents): Clear the current loader from dispatching
     45        list, as the event is no longer pending when it's being dispatched.
     46
     47        * loader/ImageLoader.h: Removed unnecessary hasPendingLoadEvent(). We don't care whether one
     48        is already pending, we only care if one is expected at some time in the future, and
     49        !haveFiredLoadEvent() is our best idea of that.
     50
     51        * dom/XMLDocumentParser.cpp: (WebCore::XMLDocumentParser::notifyFinished): Another place to
     52        handle cancellation.
     53
    1542011-05-28  Adam Barth  <abarth@webkit.org>
    255
  • trunk/Source/WebCore/dom/ScriptElement.cpp

    r87239 r87628  
    297297    if (cachedScript->errorOccurred())
    298298        dispatchErrorEvent();
    299     else {
     299    else if (!cachedScript->wasCanceled()) {
    300300        executeScript(ScriptSourceCode(cachedScript));
    301301        dispatchLoadEvent();
  • trunk/Source/WebCore/dom/XMLDocumentParser.cpp

    r86921 r87628  
    326326    ScriptSourceCode sourceCode(m_pendingScript.get());
    327327    bool errorOccurred = m_pendingScript->errorOccurred();
     328    bool wasCanceled = m_pendingScript->wasCanceled();
    328329
    329330    m_pendingScript->removeClient(this);
     
    341342    if (errorOccurred)
    342343        scriptElement->dispatchErrorEvent();
    343     else {
     344    else if (!wasCanceled) {
    344345        scriptElement->executeScript(sourceCode);
    345346        scriptElement->dispatchLoadEvent();
  • trunk/Source/WebCore/html/HTMLImageElement.cpp

    r85375 r87628  
    386386}
    387387
    388 bool HTMLImageElement::hasPendingActivity()
    389 {
    390     return (cachedImage() && cachedImage()->isLoading()) || m_imageLoader.hasPendingLoadEvent();
    391 }
    392 
    393388void HTMLImageElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
    394389{
  • trunk/Source/WebCore/html/HTMLImageElement.h

    r86491 r87628  
    7474
    7575    bool haveFiredLoadEvent() const { return m_imageLoader.haveFiredLoadEvent(); }
    76     bool hasPendingActivity();
     76    bool hasPendingActivity() const { return !m_imageLoader.haveFiredLoadEvent(); }
    7777
    7878    virtual bool canContainRangeEndPoint() const { return false; }
  • trunk/Source/WebCore/html/HTMLLinkElement.cpp

    r87618 r87628  
    449449    if (m_cachedLinkResource->errorOccurred())
    450450        dispatchEvent(Event::create(eventNames().errorEvent, false, false));
    451     else
     451    else if (!m_cachedLinkResource->wasCanceled())
    452452        dispatchEvent(Event::create(eventNames().loadEvent, false, false));
    453453
  • trunk/Source/WebCore/loader/ImageLoader.cpp

    r87473 r87628  
    6969    void dispatchPendingEvents();
    7070
    71     bool hasPendingEvents(ImageLoader* loader) { return m_dispatchSoonList.find(loader) != notFound; }
     71#ifndef NDEBUG
     72    bool hasPendingEvents(ImageLoader* loader) const
     73    {
     74        return m_dispatchSoonList.find(loader) != notFound || m_dispatchingList.find(loader) != notFound;
     75    }
     76#endif
    7277
    7378private:
     
    218223}
    219224
    220 void ImageLoader::notifyFinished(CachedResource*)
     225void ImageLoader::notifyFinished(CachedResource* resource)
    221226{
    222227    ASSERT(m_failedLoadURL.isEmpty());
     228    ASSERT_UNUSED(m_image, resource == m_image.get());
    223229
    224230    m_imageComplete = true;
     
    227233
    228234    if (m_firedLoad)
     235        return;
     236
     237    if (resource->wasCanceled())
    229238        return;
    230239
     
    320329}
    321330
    322 bool ImageLoader::hasPendingLoadEvent()
    323 {
    324     return loadEventSender().hasPendingEvents(this);
    325 }
    326 
    327331ImageEventSender::ImageEventSender(const AtomicString& eventType)
    328332    : m_eventType(eventType)
     
    372376    for (size_t i = 0; i < size; ++i) {
    373377        if (ImageLoader* loader = m_dispatchingList[i]) {
     378            m_dispatchingList[i] = 0;
    374379            if (m_eventType == eventNames().beforeloadEvent)
    375380                loader->dispatchPendingBeforeLoadEvent();
  • trunk/Source/WebCore/loader/ImageLoader.h

    r85375 r87628  
    5959    bool haveFiredBeforeLoadEvent() const { return m_firedBeforeLoad; }
    6060    bool haveFiredLoadEvent() const { return m_firedLoad; }
    61     bool hasPendingLoadEvent();
    6261
    6362    static void dispatchPendingBeforeLoadEvents();
  • trunk/Source/WebCore/loader/cache/CachedResource.cpp

    r87473 r87628  
    263263
    264264    // All loads finish with data(allDataReceived = true) or error(), except for
    265     // canceled loads, which silently set our request to 0. Be sure to set our
    266     // loading flag to false in that case, so we don't seem to continue loading
    267     // forever.
    268     if (!m_request)
     265    // canceled loads, which silently set our request to 0. Be sure to notify our
     266    // client in that case, so we don't seem to continue loading forever.
     267    if (!m_request && isLoading()) {
    269268        setLoading(false);
     269        setStatus(Canceled);
     270        checkNotify();
     271    }
    270272
    271273    if (canDelete() && !inCache())
  • trunk/Source/WebCore/loader/cache/CachedResource.h

    r87473 r87628  
    7878        Pending,      // only partially loaded
    7979        Cached,       // regular case
     80        Canceled,
    8081        LoadError,
    8182        DecodeError
     
    190191    void setAccept(const String& accept) { m_accept = accept; }
    191192
    192     bool errorOccurred() const { return (status() == LoadError || status() == DecodeError); }
     193    bool wasCanceled() const { return m_status == Canceled; }
     194    bool errorOccurred() const { return (m_status == LoadError || m_status == DecodeError); }
    193195
    194196    bool sendResourceLoadCallbacks() const { return m_sendResourceLoadCallbacks; }
Note: See TracChangeset for help on using the changeset viewer.