Changeset 31038 in webkit


Ignore:
Timestamp:
Mar 13, 2008 2:20:31 PM (16 years ago)
Author:
Antti Koivisto
Message:

WebCore:

Reviewed by Darin.


Make page loads go fast.


http://bugs.webkit.org/show_bug.cgi?id=17480

  • Implement speculative preloading. When a script load blocks the main parser, use a side parser to pick up more resources.
  • Implement per-host load queues, prioritize scripts and stylesheets over images.


Depending on content and network latency this may speed things up quite a bit.

  • WebCore.xcodeproj/project.pbxproj:
  • dom/Document.cpp: (WebCore::Document::implicitClose): Clear the preloads after laoding completes.


  • html/HTMLLinkElement.cpp: (WebCore::HTMLLinkElement::parseMappedAttribute): (WebCore::HTMLLinkElement::tokenizeRelAttribute):
  • html/HTMLLinkElement.h: Make tokenizeRelAttribute() public static so it can be used from elsewhere. Eliminate a pointless bitfield so I can get references.


  • html/HTMLTokenizer.cpp: (WebCore::HTMLTokenizer::scriptHandler): (WebCore::HTMLTokenizer::scriptExecution): (WebCore::HTMLTokenizer::write):
  • html/HTMLTokenizer.h: Spin up the preload scanner whenever a script load blocks the parser. One scanner tracks the end of the document while temporary ones are created as needed to scan document.write() output.


  • html/PreloadScanner.cpp: Added. (WebCore::PreloadScanner::PreloadScanner): (WebCore::PreloadScanner::~PreloadScanner): (WebCore::PreloadScanner::begin): (WebCore::PreloadScanner::end): (WebCore::PreloadScanner::reset): (WebCore::PreloadScanner::write): (WebCore::isWhitespace): (WebCore::PreloadScanner::clearLastCharacters): (WebCore::PreloadScanner::rememberCharacter): (WebCore::PreloadScanner::lastCharactersMatch): (WebCore::legalEntityFor): (WebCore::PreloadScanner::consumeEntity): (WebCore::PreloadScanner::tokenize): (WebCore::PreloadScanner::processAttribute): (WebCore::PreloadScanner::emitCharacter): (WebCore::PreloadScanner::tokenizeCSS): (WebCore::PreloadScanner::emitTag): (WebCore::PreloadScanner::emitCSSRule):
  • html/PreloadScanner.h: Added. (WebCore::PreloadScanner::inProgress): (WebCore::PreloadScanner::): HTML5 tokenization plus some glue code. Fake CSS parsing thrown in just for fun.


  • loader/Cache.cpp: (WebCore::Cache::pruneDeadResources): Preloads have zero refcount, avoid kicking them out too early.


  • loader/CachedResource.cpp: (WebCore::CachedResource::CachedResource): (WebCore::CachedResource::ref):
  • loader/CachedResource.h: (WebCore::CachedResource::): (WebCore::CachedResource::preloadResult): (WebCore::CachedResource::setRequestedFromNetworkingLayer): (WebCore::CachedResource::canDelete): (WebCore::CachedResource::isPreloaded): (WebCore::CachedResource::increasePreloadCount): (WebCore::CachedResource::decreasePreloadCount): Keep track which resources are preloads. Avoid deleting them. Track at which point of the loading preloads get utilized to enable some interesting statistics.


  • loader/DocLoader.cpp: (WebCore::DocLoader::~DocLoader): (WebCore::DocLoader::checkForReload): (WebCore::DocLoader::registerPreload): (WebCore::DocLoader::clearPreloads): (WebCore::DocLoader::printPreloadStats):
  • loader/DocLoader.h: Ensure we utilize preloaded resources during reloads. Keep a list of all preloads in the document. Clear the preloads after parsing is complete. Some debug statistics.


  • loader/DocumentLoader.cpp: (WebCore::DocumentLoader::isLoadingInAPISense): Avoid signaling that loading is complete too early.


  • loader/loader.cpp: (WebCore::Loader::Loader): (WebCore::Loader::~Loader): (WebCore::Loader::determinePriority): (WebCore::Loader::load): (WebCore::Loader::scheduleServePendingRequests): (WebCore::Loader::requestTimerFired): (WebCore::Loader::servePendingRequests): (WebCore::Loader::cancelRequests): (WebCore::Loader::Host::Host): (WebCore::Loader::Host::~Host): (WebCore::Loader::Host::addRequest): (WebCore::Loader::Host::hasRequests): (WebCore::Loader::Host::servePendingRequests): (WebCore::Loader::Host::didFinishLoading): (WebCore::Loader::Host::didFail): (WebCore::Loader::Host::didReceiveResponse): (WebCore::Loader::Host::didReceiveData): (WebCore::Loader::Host::cancelPendingRequests): (WebCore::Loader::Host::cancelRequests):
  • loader/loader.h: (WebCore::Loader::): Distribute load requests to per-host priority queues. Limit the number of loads issued to the networking layer so we have better changes of getting important requests through first. Prioritize scripts > stylesheets > images.

WebKit/mac:

Reviewed by Darin.

  • ForwardingHeaders/wtf/Deque.h: Added.
Location:
trunk
Files:
3 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r31037 r31038  
     12008-03-13  Antti Koivisto  <antti@apple.com>
     2
     3        Reviewed by Darin.
     4       
     5        Make page loads go fast.
     6       
     7        http://bugs.webkit.org/show_bug.cgi?id=17480
     8
     9        - Implement speculative preloading. When a script load blocks the main parser, use a side
     10          parser to pick up more resources.
     11        - Implement per-host load queues, prioritize scripts and stylesheets over images.
     12       
     13        Depending on content and network latency this may speed things up quite a bit.
     14
     15        * WebCore.xcodeproj/project.pbxproj:
     16        * dom/Document.cpp:
     17        (WebCore::Document::implicitClose):
     18        Clear the preloads after laoding completes.
     19       
     20        * html/HTMLLinkElement.cpp:
     21        (WebCore::HTMLLinkElement::parseMappedAttribute):
     22        (WebCore::HTMLLinkElement::tokenizeRelAttribute):
     23        * html/HTMLLinkElement.h:
     24        Make tokenizeRelAttribute() public static so it can be used from elsewhere.
     25        Eliminate a pointless bitfield so I can get references.
     26       
     27        * html/HTMLTokenizer.cpp:
     28        (WebCore::HTMLTokenizer::scriptHandler):
     29        (WebCore::HTMLTokenizer::scriptExecution):
     30        (WebCore::HTMLTokenizer::write):
     31        * html/HTMLTokenizer.h:
     32        Spin up the preload scanner whenever a script load blocks the parser. One scanner tracks the end of
     33        the document while temporary ones are created as needed to scan document.write() output.
     34       
     35        * html/PreloadScanner.cpp: Added.
     36        (WebCore::PreloadScanner::PreloadScanner):
     37        (WebCore::PreloadScanner::~PreloadScanner):
     38        (WebCore::PreloadScanner::begin):
     39        (WebCore::PreloadScanner::end):
     40        (WebCore::PreloadScanner::reset):
     41        (WebCore::PreloadScanner::write):
     42        (WebCore::isWhitespace):
     43        (WebCore::PreloadScanner::clearLastCharacters):
     44        (WebCore::PreloadScanner::rememberCharacter):
     45        (WebCore::PreloadScanner::lastCharactersMatch):
     46        (WebCore::legalEntityFor):
     47        (WebCore::PreloadScanner::consumeEntity):
     48        (WebCore::PreloadScanner::tokenize):
     49        (WebCore::PreloadScanner::processAttribute):
     50        (WebCore::PreloadScanner::emitCharacter):
     51        (WebCore::PreloadScanner::tokenizeCSS):
     52        (WebCore::PreloadScanner::emitTag):
     53        (WebCore::PreloadScanner::emitCSSRule):
     54        * html/PreloadScanner.h: Added.
     55        (WebCore::PreloadScanner::inProgress):
     56        (WebCore::PreloadScanner::):
     57        HTML5 tokenization plus some glue code. Fake CSS parsing thrown in just for fun.
     58       
     59        * loader/Cache.cpp:
     60        (WebCore::Cache::pruneDeadResources):
     61        Preloads have zero refcount, avoid kicking them out too early.
     62       
     63        * loader/CachedResource.cpp:
     64        (WebCore::CachedResource::CachedResource):
     65        (WebCore::CachedResource::ref):
     66        * loader/CachedResource.h:
     67        (WebCore::CachedResource::):
     68        (WebCore::CachedResource::preloadResult):
     69        (WebCore::CachedResource::setRequestedFromNetworkingLayer):
     70        (WebCore::CachedResource::canDelete):
     71        (WebCore::CachedResource::isPreloaded):
     72        (WebCore::CachedResource::increasePreloadCount):
     73        (WebCore::CachedResource::decreasePreloadCount):
     74        Keep track which resources are preloads. Avoid deleting them. Track
     75        at which point of the loading preloads get utilized to enable some interesting
     76        statistics.
     77       
     78        * loader/DocLoader.cpp:
     79        (WebCore::DocLoader::~DocLoader):
     80        (WebCore::DocLoader::checkForReload):
     81        (WebCore::DocLoader::registerPreload):
     82        (WebCore::DocLoader::clearPreloads):
     83        (WebCore::DocLoader::printPreloadStats):
     84        * loader/DocLoader.h:
     85        Ensure we utilize preloaded resources during reloads.
     86        Keep a list of all preloads in the document. Clear the preloads after
     87        parsing is complete. Some debug statistics.
     88       
     89        * loader/DocumentLoader.cpp:
     90        (WebCore::DocumentLoader::isLoadingInAPISense):
     91        Avoid signaling that loading is complete too early.
     92       
     93        * loader/loader.cpp:
     94        (WebCore::Loader::Loader):
     95        (WebCore::Loader::~Loader):
     96        (WebCore::Loader::determinePriority):
     97        (WebCore::Loader::load):
     98        (WebCore::Loader::scheduleServePendingRequests):
     99        (WebCore::Loader::requestTimerFired):
     100        (WebCore::Loader::servePendingRequests):
     101        (WebCore::Loader::cancelRequests):
     102        (WebCore::Loader::Host::Host):
     103        (WebCore::Loader::Host::~Host):
     104        (WebCore::Loader::Host::addRequest):
     105        (WebCore::Loader::Host::hasRequests):
     106        (WebCore::Loader::Host::servePendingRequests):
     107        (WebCore::Loader::Host::didFinishLoading):
     108        (WebCore::Loader::Host::didFail):
     109        (WebCore::Loader::Host::didReceiveResponse):
     110        (WebCore::Loader::Host::didReceiveData):
     111        (WebCore::Loader::Host::cancelPendingRequests):
     112        (WebCore::Loader::Host::cancelRequests):
     113        * loader/loader.h:
     114        (WebCore::Loader::):
     115        Distribute load requests to per-host priority queues. Limit the number of loads issued to the
     116        networking layer so we have better changes of getting important requests through first.
     117        Prioritize scripts > stylesheets > images.
     118
    11192008-03-13  David Hyatt  <hyatt@apple.com>
    2120
  • trunk/WebCore/WebCore.xcodeproj/project.pbxproj

    r31014 r31038  
    38423842                E44614510CD68A3500FADA75 /* RenderVideo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4B41E330CBFB60900AF2ECE /* RenderVideo.cpp */; };
    38433843                E44614520CD68A3500FADA75 /* RenderVideo.h in Headers */ = {isa = PBXBuildFile; fileRef = E4B41E340CBFB60900AF2ECE /* RenderVideo.h */; };
     3844                E49626C20D80D94800E3405C /* PreloadScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4D4ABE00D7542F000F96869 /* PreloadScanner.cpp */; };
     3845                E49626C30D80D94900E3405C /* PreloadScanner.h in Headers */ = {isa = PBXBuildFile; fileRef = E4D4ABE10D7542F100F96869 /* PreloadScanner.h */; };
    38443846                E4C279580CF9741900E97B98 /* RenderMedia.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4C279560CF9741900E97B98 /* RenderMedia.cpp */; };
    38453847                E4C279590CF9741900E97B98 /* RenderMedia.h in Headers */ = {isa = PBXBuildFile; fileRef = E4C279570CF9741900E97B98 /* RenderMedia.h */; };
     
    80428044                E4C279560CF9741900E97B98 /* RenderMedia.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderMedia.cpp; sourceTree = "<group>"; };
    80438045                E4C279570CF9741900E97B98 /* RenderMedia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderMedia.h; sourceTree = "<group>"; };
     8046                E4D4ABE00D7542F000F96869 /* PreloadScanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreloadScanner.cpp; sourceTree = "<group>"; };
     8047                E4D4ABE10D7542F100F96869 /* PreloadScanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreloadScanner.h; sourceTree = "<group>"; };
    80448048                E4EEFFC60D34550C00469A58 /* JSAudioConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAudioConstructor.cpp; sourceTree = "<group>"; };
    80458049                E4EEFFC70D34550C00469A58 /* JSAudioConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAudioConstructor.h; sourceTree = "<group>"; };
     
    1024910253                                E446139B0CD6331000FADA75 /* MediaError.h */,
    1025010254                                E446139C0CD6331000FADA75 /* MediaError.idl */,
     10255                                E4D4ABE00D7542F000F96869 /* PreloadScanner.cpp */,
     10256                                E4D4ABE10D7542F100F96869 /* PreloadScanner.h */,
    1025110257                                E446139D0CD6331000FADA75 /* TimeRanges.cpp */,
    1025210258                                E446139E0CD6331000FADA75 /* TimeRanges.h */,
     
    1452314529                                1A569D250D7E2B82007C3983 /* runtime_root.h in Headers */,
    1452414530                                BC6932740D7E293900AE44D1 /* JSDOMWindowBase.h in Headers */,
     14531                                E49626C30D80D94900E3405C /* PreloadScanner.h in Headers */,
    1452514532                                C02B14C20D81E02A00D8A970 /* JavaScriptDebugListener.h in Headers */,
    1452614533                                C02B14C40D81E02A00D8A970 /* JavaScriptDebugServer.h in Headers */,
     
    1615416161                                1A569D240D7E2B82007C3983 /* runtime_root.cpp in Sources */,
    1615516162                                BC6932730D7E293900AE44D1 /* JSDOMWindowBase.cpp in Sources */,
     16163                                E49626C20D80D94800E3405C /* PreloadScanner.cpp in Sources */,
    1615616164                                C02B14C30D81E02A00D8A970 /* JavaScriptDebugServer.cpp in Sources */,
    1615716165                                A9C6E4E30D745E05006442E9 /* MimeType.cpp in Sources */,
  • trunk/WebCore/dom/Document.cpp

    r31037 r31038  
    15041504    m_tokenizer = 0;
    15051505
     1506    // Parser should have picked up all preloads by now
     1507    m_docLoader->clearPreloads();
     1508
    15061509    // Create a body element if we don't already have one. See Radar 3758785.
    15071510    if (!this->body() && isHTMLDocument()) {
  • trunk/WebCore/html/HTMLLinkElement.cpp

    r30673 r31038  
    105105{
    106106    if (attr->name() == relAttr) {
    107         tokenizeRelAttribute(attr->value());
     107        tokenizeRelAttribute(attr->value(), m_isStyleSheet, m_alternate, m_isIcon);
    108108        process();
    109109    } else if (attr->name() == hrefAttr) {
     
    125125}
    126126
    127 void HTMLLinkElement::tokenizeRelAttribute(const AtomicString& relStr)
    128 {
    129     m_isStyleSheet = m_isIcon = m_alternate = false;
     127void HTMLLinkElement::tokenizeRelAttribute(const AtomicString& relStr, bool& styleSheet, bool& alternate, bool& icon)
     128{
     129    styleSheet = false;
     130    icon = false;
     131    alternate = false;
    130132    String rel = relStr.string().lower();
    131133    if (rel == "stylesheet")
    132         m_isStyleSheet = true;
     134        styleSheet = true;
    133135    else if (rel == "icon" || rel == "shortcut icon")
    134         m_isIcon = true;
    135     else if (rel == "alternate stylesheet" || rel == "stylesheet alternate")
    136         m_isStyleSheet = m_alternate = true;
    137     else {
     136        icon = true;
     137    else if (rel == "alternate stylesheet" || rel == "stylesheet alternate") {
     138        styleSheet = true;
     139        alternate = true;
     140    } else {
    138141        // Tokenize the rel attribute and set bits based on specific keywords that we find.
    139142        rel.replace('\n', ' ');
     
    143146        for (Vector<String>::const_iterator it = list.begin(); it != end; ++it) {
    144147            if (*it == "stylesheet")
    145                 m_isStyleSheet = true;
     148                styleSheet = true;
    146149            else if (*it == "alternate")
    147                 m_alternate = true;
     150                alternate = true;
    148151            else if (*it == "icon")
    149                 m_isIcon = true;
     152                icon = true;
    150153        }
    151154    }
  • trunk/WebCore/html/HTMLLinkElement.h

    r30243 r31038  
    9292    virtual bool isURLAttribute(Attribute*) const;
    9393   
    94     void tokenizeRelAttribute(const AtomicString& rel);
     94    static void tokenizeRelAttribute(const AtomicString& value, bool& stylesheet, bool& alternate, bool& icon);
    9595
    9696protected:
     
    101101    String m_media;
    102102    int m_disabledState; // 0=unset(default), 1=enabled via script, 2=disabled
    103     bool m_loading : 1;
    104     bool m_alternate : 1;
    105     bool m_isStyleSheet : 1;
    106     bool m_isIcon : 1;
     103    bool m_loading;
     104    bool m_alternate;
     105    bool m_isStyleSheet;
     106    bool m_isIcon;
    107107};
    108108
  • trunk/WebCore/html/HTMLTokenizer.cpp

    r30928 r31038  
    4242#include "HTMLScriptElement.h"
    4343#include "HTMLViewSourceDocument.h"
     44#include "PreloadScanner.h"
    4445#include "Settings.h"
    4546#include "SystemTime.h"
     
    500501            state = m_state;
    501502        }
    502     }
    503 
     503    }
     504   
     505#if PRELOAD_SCANNER_ENABLED
     506    if (!pendingScripts.isEmpty() && !m_executingScript) {
     507        if (!m_preloadScanner)
     508            m_preloadScanner.set(new PreloadScanner(m_doc));
     509        if (!m_preloadScanner->inProgress()) {
     510            m_preloadScanner->begin();
     511            m_preloadScanner->write(pendingSrc);
     512        }
     513    }
     514#endif
    504515    currentPrependingSrc = savedPrependingSrc;
    505516
     
    553564            else
    554565                pendingSrc.prepend(prependingSrc);
     566           
     567#if PRELOAD_SCANNER_ENABLED
     568            // We are stuck waiting for another script. Lets check the source that
     569            // was just document.write()n for anything to load.
     570            PreloadScanner documentWritePreloadScanner(m_doc);
     571            documentWritePreloadScanner.begin();
     572            documentWritePreloadScanner.write(prependingSrc);
     573            documentWritePreloadScanner.end();
     574#endif
    555575        } else {
    556576            m_state = state;
     
    15831603        if (currentPrependingSrc)
    15841604            currentPrependingSrc->append(source);
    1585         else
     1605        else {
    15861606            pendingSrc.append(source);
     1607#if PRELOAD_SCANNER_ENABLED
     1608            if (m_preloadScanner && m_preloadScanner->inProgress() && appendData)
     1609                m_preloadScanner->write(source);
     1610#endif
     1611        }
    15871612        return false;
    15881613    }
     1614   
     1615#if PRELOAD_SCANNER_ENABLED
     1616    if (m_preloadScanner && m_preloadScanner->inProgress() && appendData)
     1617        m_preloadScanner->end();
     1618#endif
    15891619
    15901620    if (!src.isEmpty())
  • trunk/WebCore/html/HTMLTokenizer.h

    r30431 r31038  
    3434#include <wtf/OwnPtr.h>
    3535
     36// FIXME: temporary, add PreloadScanner to all build files
     37#if PLATFORM(MAC)
     38#define PRELOAD_SCANNER_ENABLED 1
     39#else
     40#define PRELOAD_SCANNER_ENABLED 0
     41#endif
     42
    3643namespace WebCore {
    3744
     
    4451class HTMLParser;
    4552class Node;
     53class PreloadScanner;
    4654
    4755/**
     
    403411    bool inWrite;
    404412    bool m_fragment;
     413
     414#if PRELOAD_SCANNER_ENABLED
     415    OwnPtr<PreloadScanner> m_preloadScanner;
     416#endif
    405417};
    406418
  • trunk/WebCore/loader/Cache.cpp

    r30564 r31038  
    230230        while (current) {
    231231            CachedResource* prev = current->m_prevInAllResourcesList;
    232             if (!current->referenced() && current->isLoaded() && current->decodedSize()) {
     232            if (!current->referenced() && !current->isPreloaded() && current->isLoaded() && current->decodedSize()) {
    233233                // Destroy our decoded data. This will remove us from
    234234                // m_liveDecodedResources, and possibly move us to a differnt
     
    246246        while (current) {
    247247            CachedResource* prev = current->m_prevInAllResourcesList;
    248             if (!current->referenced()) {
     248            if (!current->referenced() && !current->isPreloaded()) {
    249249                remove(current);
    250250
  • trunk/WebCore/loader/CachedResource.cpp

    r28639 r31038  
    4040    , m_lastDecodedAccessTime(0)
    4141    , m_sendResourceLoadCallbacks(sendResourceLoadCallbacks)
     42    , m_preloadCount(0)
     43    , m_preloadResult(PreloadNotReferenced)
     44    , m_requestedFromNetworkingLayer(false)
    4245    , m_inCache(forCache)
    4346    , m_docLoader(0)
     
    102105void CachedResource::ref(CachedResourceClient *c)
    103106{
     107    if (m_preloadResult == PreloadNotReferenced) {
     108        if (isLoaded())
     109            m_preloadResult = PreloadReferencedWhileComplete;
     110        else if (m_requestedFromNetworkingLayer)
     111            m_preloadResult = PreloadReferencedWhileLoading;
     112        else
     113            m_preloadResult = PreloadReferenced;
     114    }
    104115    if (!referenced() && inCache())
    105116        cache()->addToLiveResourcesSize(this);
  • trunk/WebCore/loader/CachedResource.h

    r28639 r31038  
    8080    void deref(CachedResourceClient*);
    8181    bool referenced() const { return !m_clients.isEmpty(); }
     82
     83    enum PreloadResult {
     84        PreloadNotReferenced,
     85        PreloadReferenced,
     86        PreloadReferencedWhileLoading,
     87        PreloadReferencedWhileComplete
     88    };
     89    PreloadResult preloadResult() const { return m_preloadResult; }
     90    void setRequestedFromNetworkingLayer() { m_requestedFromNetworkingLayer = true; }
     91       
    8292    virtual void allReferencesRemoved() {};
    8393
     
    118128    const ResourceResponse& response() const { return m_response; }
    119129   
    120     bool canDelete() const { return !referenced() && !m_request; }
     130    bool canDelete() const { return !referenced() && !m_request && !m_preloadCount; }
    121131
    122132    bool isExpired() const;
     
    136146
    137147    void setDocLoader(DocLoader* docLoader) { m_docLoader = docLoader; }
     148   
     149    bool isPreloaded() const { return m_preloadCount; }
     150    void increasePreloadCount() { ++m_preloadCount; }
     151    void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; }
    138152   
    139153protected:
     
    164178   
    165179    bool m_sendResourceLoadCallbacks;
     180   
     181    unsigned m_preloadCount;
     182    PreloadResult m_preloadResult;
     183    bool m_requestedFromNetworkingLayer;
     184
    166185protected:
    167186    bool m_inCache;
  • trunk/WebCore/loader/DocLoader.cpp

    r30243 r31038  
    3333#include "CachedScript.h"
    3434#include "CachedXSLStyleSheet.h"
     35#include "CString.h"
    3536#include "Document.h"
    3637#include "Frame.h"
    3738#include "FrameLoader.h"
    3839#include "loader.h"
     40
     41#define PRELOAD_DEBUG 0
    3942
    4043namespace WebCore {
     
    5558DocLoader::~DocLoader()
    5659{
     60    clearPreloads();
    5761    HashMap<String, CachedResource*>::iterator end = m_docResources.end();
    5862    for (HashMap<String, CachedResource*>::iterator it = m_docResources.begin(); it != end; ++it)
     
    7276       if (!m_reloadedURLs.contains(fullURL.string())) {
    7377          CachedResource* existing = cache()->resourceForURL(fullURL.string());
    74           if (existing && existing->isExpired()) {
     78          if (existing && existing->isExpired() && !existing->isPreloaded()) {
    7579             cache()->remove(existing);
    7680             m_reloadedURLs.add(fullURL.string());
     
    7983    } else if ((m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh)) {
    8084       if (!m_reloadedURLs.contains(fullURL.string())) {
    81           CachedResource* existing = cache()->resourceForURL(fullURL.string());
    82           if (existing)
    83              cache()->remove(existing);
    84           m_reloadedURLs.add(fullURL.string());
     85           CachedResource* existing = cache()->resourceForURL(fullURL.string());
     86           if (existing && !existing->isPreloaded()) {
     87               cache()->remove(existing);
     88               m_reloadedURLs.add(fullURL.string());
     89           }
    8590       }
    8691    }
     
    244249    return m_requestCount;
    245250}
    246 
    247 }
     251   
     252void DocLoader::registerPreload(CachedResource* resource)
     253{
     254    if (!resource || resource->isLoaded() || m_preloads.contains(resource))
     255        return;
     256    resource->increasePreloadCount();
     257    m_preloads.add(resource);
     258#if PRELOAD_DEBUG
     259    printf("PRELOADING %s\n",  resource->url().latin1().data());
     260#endif
     261}
     262
     263void DocLoader::clearPreloads()
     264{
     265#if PRELOAD_DEBUG
     266    printPreloadStats();
     267#endif
     268    ListHashSet<CachedResource*>::iterator end = m_preloads.end();
     269    for (ListHashSet<CachedResource*>::iterator it = m_preloads.begin(); it != end; ++it) {
     270        CachedResource* res = *it;
     271        if (res->preloadResult() == CachedResource::PreloadNotReferenced)
     272            cache()->remove(res);
     273        res->decreasePreloadCount();
     274    }
     275    m_preloads.clear();
     276}
     277
     278#if PRELOAD_DEBUG
     279void DocLoader::printPreloadStats()
     280{
     281    unsigned scripts = 0;
     282    unsigned scriptMisses = 0;
     283    unsigned stylesheets = 0;
     284    unsigned stylesheetMisses = 0;
     285    unsigned images = 0;
     286    unsigned imageMisses = 0;
     287    ListHashSet<CachedResource*>::iterator end = m_preloads.end();
     288    for (ListHashSet<CachedResource*>::iterator it = m_preloads.begin(); it != end; ++it) {
     289        CachedResource* res = *it;
     290        if (res->preloadResult() == CachedResource::PreloadNotReferenced)
     291            printf("!! UNREFERENCED PRELOAD %s\n", res->url().latin1().data());
     292        else if (res->preloadResult() == CachedResource::PreloadReferencedWhileComplete)
     293            printf("HIT COMPLETE PRELOAD %s\n", res->url().latin1().data());
     294        else if (res->preloadResult() == CachedResource::PreloadReferencedWhileLoading
     295            printf("HIT LOADING PRELOAD %s\n", res->url().latin1().data());
     296       
     297        if (res->type() == CachedResource::Script) {
     298            scripts++;
     299            if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
     300                scriptMisses++;
     301        } else if (res->type() == CachedResource::CSSStyleSheet) {
     302            stylesheets++;
     303            if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
     304                stylesheetMisses++;
     305        } else {
     306            images++;
     307            if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
     308                imageMisses++;
     309        }
     310       
     311        if (res->errorOccurred())
     312            cache()->remove(res);
     313       
     314        res->decreasePreloadCount();
     315    }
     316    m_preloads.clear();
     317   
     318    if (scripts)
     319        printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
     320    if (stylesheets)
     321        printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
     322    if (images)
     323        printf("IMAGES:  %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
     324}
     325#endif
     326   
     327}
  • trunk/WebCore/loader/DocLoader.h

    r26484 r31038  
    3131#include <wtf/HashMap.h>
    3232#include <wtf/HashSet.h>
     33#include <wtf/ListHashSet.h>
    3334
    3435namespace WebCore {
     
    9394    void decrementRequestCount();
    9495    int requestCount();
     96   
     97    void clearPreloads();
     98    void registerPreload(CachedResource*);
     99    void printPreloadStats();
     100   
    95101private:
    96102    CachedResource* requestResource(CachedResource::Type, const String& url, const String* charset = 0, bool skipCanLoadCheck = false, bool sendResourceLoadCallbacks = true);
     
    108114    int m_requestCount;
    109115   
     116    ListHashSet<CachedResource*> m_preloads;
     117   
    110118    //29 bits left
    111119    bool m_autoLoadImages : 1;
  • trunk/WebCore/loader/DocumentLoader.cpp

    r31035 r31038  
    3131
    3232#include "CachedPage.h"
     33#include "DocLoader.h"
    3334#include "Document.h"
    3435#include "Event.h"
     
    427428        if (!m_subresourceLoaders.isEmpty())
    428429            return true;
    429         if (Document* doc = m_frame->document())
     430        if (Document* doc = m_frame->document()) {
     431            if (doc->docLoader()->requestCount())
     432                return true;
    430433            if (Tokenizer* tok = doc->tokenizer())
    431434                if (tok->processingData())
    432435                    return true;
     436        }
    433437    }
    434438    return frameLoader()->subframeIsLoading();
  • trunk/WebCore/loader/loader.cpp

    r31034 r31038  
    2828#include "CachedImage.h"
    2929#include "CachedResource.h"
     30#include "CString.h"
    3031#include "DocLoader.h"
    3132#include "Frame.h"
     
    4041#include <wtf/Vector.h>
    4142
     43#define REQUEST_MANAGEMENT_ENABLED 1
     44#define REQUEST_DEBUG 0
     45
    4246namespace WebCore {
    4347
     48#if REQUEST_MANAGEMENT_ENABLED
     49// Match the parallel connection count used by the networking layer
     50// FIXME should not hardcode something like this
     51static const unsigned maxRequestsInFlightPerHost = 4;
     52// Having a limit might still help getting more important resources first
     53static const unsigned maxRequestsInFlightForNonHTTPProtocols = 20;
     54#else
     55static const unsigned maxRequestsInFlightPerHost = 10000;
     56static const unsigned maxRequestsInFlightForNonHTTPProtocols = 10000;
     57#endif
     58   
     59   
    4460Loader::Loader()
    45 {
    46     m_requestsPending.setAutoDelete(true);
     61    : m_nonHTTPProtocolHost(maxRequestsInFlightForNonHTTPProtocols)
     62    , m_requestTimer(this, &Loader::requestTimerFired)
     63{
    4764}
    4865
    4966Loader::~Loader()
    50 {
    51     deleteAllValues(m_requestsLoading);
    52 }
    53 
    54 void Loader::load(DocLoader* dl, CachedResource* object, bool incremental, bool skipCanLoadCheck, bool sendResourceLoadCallbacks)
    55 {
    56     ASSERT(dl);
    57     Request* req = new Request(dl, object, incremental, skipCanLoadCheck, sendResourceLoadCallbacks);
    58     m_requestsPending.append(req);
    59     dl->incrementRequestCount();
     67{   
     68    ASSERT_NOT_REACHED();
     69}
     70   
     71Loader::Priority Loader::determinePriority(const CachedResource* resource) const
     72{
     73#if REQUEST_MANAGEMENT_ENABLED
     74    switch (resource->type()) {
     75        case CachedResource::Script:
     76#if ENABLE(XBL)
     77        case CachedResource::XBL:
     78#endif
     79            return High;
     80        case CachedResource::CSSStyleSheet:
     81        case CachedResource::FontResource:
     82#if ENABLE(XSLT)
     83        case CachedResource::XSLStyleSheet:
     84#endif
     85            return Medium;
     86        case CachedResource::ImageResource:
     87            return Low;
     88    }
     89    ASSERT_NOT_REACHED();
     90    return Low;
     91#else
     92    return High;
     93#endif
     94}
     95
     96void Loader::load(DocLoader* docLoader, CachedResource* resource, bool incremental, bool skipCanLoadCheck, bool sendResourceLoadCallbacks)
     97{
     98    ASSERT(docLoader);
     99    Request* request = new Request(docLoader, resource, incremental, skipCanLoadCheck, sendResourceLoadCallbacks);
     100
     101    Host* host;
     102    KURL url(resource->url());
     103    bool isHTTP = url.protocolIs("http") || url.protocolIs("https");
     104    if (isHTTP) {
     105        String hostName = url.host();
     106        host = m_hosts.get(hostName);
     107        if (!host) {
     108            host = new Host(maxRequestsInFlightPerHost);
     109            m_hosts.add(hostName, host);
     110        }
     111    } else
     112        host = &m_nonHTTPProtocolHost;
     113   
     114    Priority priority = determinePriority(resource);
     115    host->addRequest(request, priority);
     116    docLoader->incrementRequestCount();
     117
     118    if (priority > Low || !isHTTP) {
     119        // Try to request important resources immediately
     120        host->servePendingRequests(priority);
     121    } else {
     122        // Handle asynchronously so early low priority requests don't get scheduled before later high priority ones
     123        scheduleServePendingRequests();
     124    }
     125}
     126   
     127void Loader::scheduleServePendingRequests()
     128{
     129    if (!m_requestTimer.isActive())
     130        m_requestTimer.startOneShot(0);
     131}
     132
     133void Loader::requestTimerFired(Timer<Loader>*)
     134{
    60135    servePendingRequests();
    61136}
    62137
    63 void Loader::servePendingRequests()
    64 {
    65     while (!m_requestsPending.isEmpty()) {
    66         // get the first pending request
    67         Request* req = m_requestsPending.take(0);
    68         DocLoader* dl = req->docLoader();
    69         dl->decrementRequestCount();
    70 
    71         ResourceRequest request(req->cachedResource()->url());
    72 
    73         if (!req->cachedResource()->accept().isEmpty())
    74             request.setHTTPAccept(req->cachedResource()->accept());
    75 
    76         KURL r = dl->doc()->url();
    77         if ((r.protocolIs("http") || r.protocolIs("https")) && r.path().isEmpty())
    78             r.setPath("/");
    79         request.setHTTPReferrer(r.string());
    80 
    81         RefPtr<SubresourceLoader> loader = SubresourceLoader::create(dl->doc()->frame(),
    82             this, request, req->shouldSkipCanLoadCheck(), req->sendResourceLoadCallbacks());
    83 
     138void Loader::servePendingRequests(Priority minimumPriority)
     139{
     140    m_requestTimer.stop();
     141   
     142    m_nonHTTPProtocolHost.servePendingRequests(minimumPriority);
     143
     144    HostMap::iterator end = m_hosts.end();
     145    Vector<String> toRemove;
     146    for (HostMap::iterator it = m_hosts.begin(); it != end; ++it) {
     147        Host* host = it->second;
     148        if (host->hasRequests())
     149            host->servePendingRequests(minimumPriority);
     150        else
     151            toRemove.append(it->first);
     152    }
     153    for (unsigned n = 0; n < toRemove.size(); ++n) {
     154        HostMap::iterator it = m_hosts.find(toRemove[n]);
     155        delete it->second;
     156        m_hosts.remove(it);
     157    }
     158}
     159   
     160void Loader::cancelRequests(DocLoader* docLoader)
     161{
     162    if (m_nonHTTPProtocolHost.hasRequests())
     163        m_nonHTTPProtocolHost.cancelRequests(docLoader);
     164   
     165    HostMap::iterator end = m_hosts.end();
     166    for (HostMap::iterator it = m_hosts.begin(); it != end; ++it) {
     167        Host* host = it->second;
     168        if (host->hasRequests());
     169            host->cancelRequests(docLoader);
     170    }
     171
     172    scheduleServePendingRequests();
     173   
     174    if (docLoader->loadInProgress())
     175        ASSERT(docLoader->requestCount() == 1);
     176    else
     177        ASSERT(docLoader->requestCount() == 0);
     178}
     179   
     180Loader::Host::Host(unsigned maxRequestsInFlight)
     181    : m_maxRequestsInFlight(maxRequestsInFlight)
     182{
     183}
     184
     185Loader::Host::~Host()
     186{
     187    ASSERT(m_requestsLoading.isEmpty());
     188    for (unsigned p = 0; p <= High; p++)
     189        ASSERT(m_requestsPending[p].isEmpty());
     190}
     191   
     192void Loader::Host::addRequest(Request* request, Priority priority)
     193{
     194    m_requestsPending[priority].append(request);
     195}
     196   
     197bool Loader::Host::hasRequests() const
     198{
     199    if (!m_requestsLoading.isEmpty())
     200        return true;
     201    for (unsigned p = 0; p <= High; p++) {
     202        if (!m_requestsPending[p].isEmpty())
     203            return true;
     204    }
     205    return false;
     206}
     207
     208void Loader::Host::servePendingRequests(Loader::Priority minimumPriority)
     209{
     210    for (int priority = High; priority >= minimumPriority; --priority)
     211        servePendingRequests(m_requestsPending[priority]);
     212}
     213   
     214void Loader::Host::servePendingRequests(RequestQueue& requestsPending)
     215{
     216    while (m_requestsLoading.size() < m_maxRequestsInFlight && !requestsPending.isEmpty()) {       
     217        Request* request = requestsPending.first();
     218        requestsPending.removeFirst();
     219
     220        DocLoader* docLoader = request->docLoader();
     221       
     222        ResourceRequest resourceRequest(request->cachedResource()->url());
     223       
     224        if (!request->cachedResource()->accept().isEmpty())
     225            resourceRequest.setHTTPAccept(request->cachedResource()->accept());
     226       
     227        KURL referrer = docLoader->doc()->url();
     228        if ((referrer.protocolIs("http") || referrer.protocolIs("https")) && referrer.path().isEmpty())
     229            referrer.setPath("/");
     230        resourceRequest.setHTTPReferrer(referrer.string());
     231
     232        RefPtr<SubresourceLoader> loader = SubresourceLoader::create(docLoader->doc()->frame(),
     233                                                                     this, resourceRequest, request->shouldSkipCanLoadCheck(), request->sendResourceLoadCallbacks());
    84234        if (loader) {
    85             m_requestsLoading.add(loader.release(), req);
    86             dl->incrementRequestCount();
    87             break;
     235            m_requestsLoading.add(loader.release(), request);
     236            request->cachedResource()->setRequestedFromNetworkingLayer();
     237#if REQUEST_DEBUG
     238            printf("HOST %s COUNT %d LOADING %s\n", resourceRequest.url().host().latin1().data(), m_requestsLoading.size(), req->cachedResource()->url().latin1().data());
     239#endif
     240        } else {           
     241            docLoader->decrementRequestCount();
     242            docLoader->setLoadInProgress(true);
     243            request->cachedResource()->error();
     244            docLoader->setLoadInProgress(false);
     245            delete request;
    88246        }
    89 
    90         dl->setLoadInProgress(true);
    91         req->cachedResource()->error();
    92         dl->setLoadInProgress(false);
    93 
    94         delete req;
    95     }
    96 }
    97 
    98 void Loader::didFinishLoading(SubresourceLoader* loader)
     247    }
     248}
     249
     250void Loader::Host::didFinishLoading(SubresourceLoader* loader)
    99251{
    100252    RequestMap::iterator i = m_requestsLoading.find(loader);
     
    102254        return;
    103255
    104     Request* req = i->second;
     256    Request* request = i->second;
    105257    m_requestsLoading.remove(i);
    106     DocLoader* docLoader = req->docLoader();
    107     if (!req->isMultipart())
     258    DocLoader* docLoader = request->docLoader();
     259    if (!request->isMultipart())
    108260        docLoader->decrementRequestCount();
    109261
    110     CachedResource* object = req->cachedResource();
     262    CachedResource* resource = request->cachedResource();
     263    delete request;
    111264
    112265    // If we got a 4xx response, we're pretending to have received a network
    113266    // error, so we can't send the successful data() and finish() callbacks.
    114     if (!object->errorOccurred()) {
     267    if (!resource->errorOccurred()) {
    115268        docLoader->setLoadInProgress(true);
    116         object->data(loader->resourceData(), true);
    117         object->finish();
     269        resource->data(loader->resourceData(), true);
     270        resource->finish();
    118271    }
    119272
    120273    docLoader->setLoadInProgress(false);
    121274
    122     delete req;
    123 
     275#if REQUEST_DEBUG
     276    KURL u(resource->url());
     277    printf("HOST %s COUNT %d RECEIVED %s\n", u.host().latin1().data(), m_requestsLoading.size(), resource->url().latin1().data());
     278#endif
    124279    servePendingRequests();
    125280}
    126281
    127 void Loader::didFail(SubresourceLoader* loader, const ResourceError&)
     282void Loader::Host::didFail(SubresourceLoader* loader, const ResourceError&)
    128283{
    129284    didFail(loader);
    130285}
    131286
    132 void Loader::didFail(SubresourceLoader* loader, bool cancelled)
     287void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
    133288{
    134289    RequestMap::iterator i = m_requestsLoading.find(loader);
     
    136291        return;
    137292
    138     Request* req = i->second;
     293    Request* request = i->second;
    139294    m_requestsLoading.remove(i);
    140     DocLoader* docLoader = req->docLoader();
    141     if (!req->isMultipart())
     295    DocLoader* docLoader = request->docLoader();
     296    if (!request->isMultipart())
    142297        docLoader->decrementRequestCount();
    143298
    144     CachedResource* object = req->cachedResource();
     299    CachedResource* resource = request->cachedResource();
     300    delete request;
    145301
    146302    if (!cancelled) {
    147303        docLoader->setLoadInProgress(true);
    148         object->error();
     304        resource->error();
    149305    }
    150306   
    151307    docLoader->setLoadInProgress(false);
    152     cache()->remove(object);
    153 
    154     delete req;
     308    if (cancelled || !resource->isPreloaded())
     309        cache()->remove(resource);
    155310
    156311    servePendingRequests();
    157312}
    158313
    159 void Loader::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
    160 {
    161     Request* req = m_requestsLoading.get(loader);
     314void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
     315{
     316    Request* request = m_requestsLoading.get(loader);
    162317   
    163318    // FIXME: This is a workaround for <rdar://problem/5236843>
    164319    // If a load starts while the frame is still in the provisional state
    165320    // (this can be the case when loading the user style sheet), committing the load then causes all
    166     // requests to be removed from the m_requestsLoading map. This means that req might be null here.
     321    // requests to be removed from the m_requestsLoading map. This means that request might be null here.
    167322    // In that case we just return early.
    168     // ASSERT(req);
    169     if (!req)
    170         return;
    171     req->cachedResource()->setResponse(response);
     323    // ASSERT(request);
     324    if (!request)
     325        return;
     326    request->cachedResource()->setResponse(response);
    172327   
    173328    String encoding = response.textEncodingName();
    174329    if (!encoding.isNull())
    175         req->cachedResource()->setEncoding(encoding);
    176    
    177     if (req->isMultipart()) {
    178         ASSERT(req->cachedResource()->isImage());
    179         static_cast<CachedImage*>(req->cachedResource())->clear();
    180         if (req->docLoader()->frame())
    181             req->docLoader()->frame()->loader()->checkCompleted();
     330        request->cachedResource()->setEncoding(encoding);
     331   
     332    if (request->isMultipart()) {
     333        ASSERT(request->cachedResource()->isImage());
     334        static_cast<CachedImage*>(request->cachedResource())->clear();
     335        if (request->docLoader()->frame())
     336            request->docLoader()->frame()->loader()->checkCompleted();
    182337    } else if (response.isMultipart()) {
    183         req->setIsMultipart(true);
     338        request->setIsMultipart(true);
    184339       
    185340        // We don't count multiParts in a DocLoader's request count
    186         req->docLoader()->decrementRequestCount();
     341        request->docLoader()->decrementRequestCount();
    187342           
    188343        // If we get a multipart response, we must have a handle
    189344        ASSERT(loader->handle());
    190         if (!req->cachedResource()->isImage())
     345        if (!request->cachedResource()->isImage())
    191346            loader->handle()->cancel();
    192347    }
    193348}
    194349
    195 void Loader::didReceiveData(SubresourceLoader* loader, const char* data, int size)
     350void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, int size)
    196351{
    197352    Request* request = m_requestsLoading.get(loader);
     
    199354        return;
    200355
    201     CachedResource* object = request->cachedResource();   
    202     if (object->errorOccurred())
    203         return;
    204    
    205     if (object->response().httpStatusCode() / 100 == 4) {
     356    CachedResource* resource = request->cachedResource();   
     357    if (resource->errorOccurred())
     358        return;
     359   
     360    if (resource->response().httpStatusCode() / 100 == 4) {
    206361        // Treat a 4xx response like a network error.
    207         object->error();
     362        resource->error();
    208363        return;
    209364    }
     
    214369        // The resource data will change as the next part is loaded, so we need to make a copy.
    215370        RefPtr<SharedBuffer> copiedData = SharedBuffer::create(data, size);
    216         object->data(copiedData.release(), true);
     371        resource->data(copiedData.release(), true);
    217372    } else if (request->isIncremental())
    218         object->data(loader->resourceData(), false);
    219 }
    220 
    221 void Loader::cancelRequests(DocLoader* dl)
    222 {
    223     DeprecatedPtrListIterator<Request> pIt(m_requestsPending);
    224     while (pIt.current()) {
    225         if (pIt.current()->docLoader() == dl) {
    226             cache()->remove(pIt.current()->cachedResource());
    227             m_requestsPending.remove(pIt);
    228             dl->decrementRequestCount();
     373        resource->data(loader->resourceData(), false);
     374}
     375   
     376void Loader::Host::cancelPendingRequests(RequestQueue& requestsPending, DocLoader* docLoader)
     377{
     378    RequestQueue remaining;
     379    RequestQueue::iterator end = requestsPending.end();
     380    for (RequestQueue::iterator it = requestsPending.begin(); it != end; ++it) {
     381        Request* request = *it;
     382        if (request->docLoader() == docLoader) {
     383            cache()->remove(request->cachedResource());
     384            delete request;
     385            docLoader->decrementRequestCount();
    229386        } else
    230             ++pIt;
    231     }
     387            remaining.append(request);
     388    }
     389    requestsPending.swap(remaining);
     390}
     391
     392void Loader::Host::cancelRequests(DocLoader* docLoader)
     393{
     394    for (unsigned p = 0; p <= High; p++)
     395        cancelPendingRequests(m_requestsPending[p], docLoader);
    232396
    233397    Vector<SubresourceLoader*, 256> loadersToCancel;
     
    236400    for (RequestMap::iterator i = m_requestsLoading.begin(); i != end; ++i) {
    237401        Request* r = i->second;
    238         if (r->docLoader() == dl)
     402        if (r->docLoader() == docLoader)
    239403            loadersToCancel.append(i->first.get());
    240404    }
     
    244408        didFail(loader, true);
    245409    }
    246    
    247     if (dl->loadInProgress())
    248         ASSERT(dl->requestCount() == 1);
    249     else
    250         ASSERT(dl->requestCount() == 0);
    251410}
    252411
  • trunk/WebCore/loader/loader.h

    r25754 r31038  
    22    Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
    33    Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
    4     Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
     4    Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved.
    55
    66    This library is free software; you can redistribute it and/or
     
    2323#define loader_h
    2424
    25 #include "DeprecatedPtrList.h"
     25#include "PlatformString.h"
     26#include "StringHash.h"
    2627#include "SubresourceLoaderClient.h"
     28#include "Timer.h"
     29#include <wtf/Deque.h>
    2730#include <wtf/HashMap.h>
     31#include <wtf/Noncopyable.h>
    2832
    2933namespace WebCore {
     
    3337    class Request;
    3438
    35     class Loader : private SubresourceLoaderClient {
     39    class Loader : Noncopyable {
    3640    public:
    3741        Loader();
     
    4145
    4246        void cancelRequests(DocLoader*);
     47       
     48        enum Priority { Low, Medium, High };
     49        void servePendingRequests(Priority minimumPriority = Low);
    4350
    4451    private:
    45         virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
    46         virtual void didReceiveData(SubresourceLoader*, const char*, int);
    47         virtual void didFinishLoading(SubresourceLoader*);
    48         virtual void didFail(SubresourceLoader*, const ResourceError&);
    49         void didFail(SubresourceLoader*, bool cancelled = false);
     52        Priority determinePriority(const CachedResource*) const;
     53        void scheduleServePendingRequests();
     54       
     55        void requestTimerFired(Timer<Loader>*);
    5056
    51         void servePendingRequests();
    52 
    53         DeprecatedPtrList<Request> m_requestsPending;
    54         typedef HashMap<RefPtr<SubresourceLoader>, Request*> RequestMap;
    55         RequestMap m_requestsLoading;
     57        class Host : private SubresourceLoaderClient {
     58        public:
     59            Host(unsigned maxRequestsInFlight);
     60            ~Host();
     61           
     62            void addRequest(Request*, Priority);
     63            void servePendingRequests(Priority minimumPriority = Low);
     64            void cancelRequests(DocLoader*);
     65            bool hasRequests() const;
     66       
     67        private:
     68            virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
     69            virtual void didReceiveData(SubresourceLoader*, const char*, int);
     70            virtual void didFinishLoading(SubresourceLoader*);
     71            virtual void didFail(SubresourceLoader*, const ResourceError&);
     72           
     73            typedef Deque<Request*> RequestQueue;
     74            void servePendingRequests(RequestQueue& requestsPending);
     75            void didFail(SubresourceLoader*, bool cancelled = false);
     76            void cancelPendingRequests(RequestQueue& requestsPending, DocLoader*);
     77           
     78            RequestQueue m_requestsPending[High + 1];
     79            typedef HashMap<RefPtr<SubresourceLoader>, Request*> RequestMap;
     80            RequestMap m_requestsLoading;
     81            const int m_maxRequestsInFlight;
     82        };
     83        typedef HashMap<String, Host*> HostMap;
     84        HostMap m_hosts;
     85        Host m_nonHTTPProtocolHost;
     86       
     87        Timer<Loader> m_requestTimer;
    5688    };
    5789
  • trunk/WebKit/mac/ChangeLog

    r31035 r31038  
     12008-03-13  Antti Koivisto  <antti@apple.com>
     2
     3        Reviewed by Darin.
     4
     5        * ForwardingHeaders/wtf/Deque.h: Added.
     6
    172008-03-13  Anders Carlsson  <andersca@apple.com>
    28
Note: See TracChangeset for help on using the changeset viewer.