Home | History | Annotate | Download | only in inspector
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "core/inspector/InspectorResourceContentLoader.h"
      7 
      8 #include "FetchInitiatorTypeNames.h"
      9 #include "core/css/CSSStyleSheet.h"
     10 #include "core/css/StyleSheetContents.h"
     11 #include "core/fetch/CSSStyleSheetResource.h"
     12 #include "core/fetch/Resource.h"
     13 #include "core/fetch/ResourceFetcher.h"
     14 #include "core/fetch/ResourcePtr.h"
     15 #include "core/fetch/StyleSheetResourceClient.h"
     16 #include "core/frame/LocalFrame.h"
     17 #include "core/html/VoidCallback.h"
     18 #include "core/inspector/InspectorCSSAgent.h"
     19 #include "core/inspector/InspectorPageAgent.h"
     20 #include "core/page/Page.h"
     21 
     22 namespace WebCore {
     23 
     24 class InspectorResourceContentLoader::ResourceClient FINAL : private StyleSheetResourceClient {
     25 public:
     26     ResourceClient(InspectorResourceContentLoader* loader)
     27         : m_loader(loader)
     28     {
     29     }
     30 
     31     void waitForResource(Resource* resource)
     32     {
     33         resource->addClient(this);
     34     }
     35 
     36 private:
     37     InspectorResourceContentLoader* m_loader;
     38 
     39     virtual void setCSSStyleSheet(const String&, const KURL&, const String&, const CSSStyleSheetResource*) OVERRIDE;
     40 
     41     friend class InspectorResourceContentLoader;
     42 };
     43 
     44 void InspectorResourceContentLoader::ResourceClient::setCSSStyleSheet(const String&, const KURL& url, const String&, const CSSStyleSheetResource* resource)
     45 {
     46     if (m_loader)
     47         m_loader->resourceFinished(this);
     48     const_cast<CSSStyleSheetResource*>(resource)->removeClient(this);
     49     delete this;
     50 }
     51 
     52 InspectorResourceContentLoader::InspectorResourceContentLoader(Page* page)
     53     : m_allRequestsStarted(false)
     54 {
     55     Vector<Document*> documents;
     56     for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
     57         if (!frame->isLocalFrame())
     58             continue;
     59         LocalFrame* localFrame = toLocalFrame(frame);
     60         documents.append(localFrame->document());
     61         documents.appendVector(InspectorPageAgent::importsForFrame(localFrame));
     62     }
     63     for (Vector<Document*>::const_iterator documentIt = documents.begin(); documentIt != documents.end(); ++documentIt) {
     64         Document* document = *documentIt;
     65 
     66         HashSet<String> urlsToFetch;
     67         Vector<CSSStyleSheet*> styleSheets;
     68         InspectorCSSAgent::collectAllDocumentStyleSheets(document, styleSheets);
     69         for (Vector<CSSStyleSheet*>::const_iterator stylesheetIt = styleSheets.begin(); stylesheetIt != styleSheets.end(); ++stylesheetIt) {
     70             CSSStyleSheet* styleSheet = *stylesheetIt;
     71             if (styleSheet->isInline() || !styleSheet->contents()->loadCompleted())
     72                 continue;
     73             String url = styleSheet->baseURL().string();
     74             if (url.isEmpty() || urlsToFetch.contains(url))
     75                 continue;
     76             urlsToFetch.add(url);
     77             FetchRequest request(ResourceRequest(url), FetchInitiatorTypeNames::internal);
     78             ResourcePtr<Resource> resource = document->fetcher()->fetchCSSStyleSheet(request);
     79             // Prevent garbage collection by holding a reference to this resource.
     80             m_resources.append(resource.get());
     81             ResourceClient* resourceClient = new ResourceClient(this);
     82             m_pendingResourceClients.add(resourceClient);
     83             resourceClient->waitForResource(resource.get());
     84         }
     85     }
     86 
     87     m_allRequestsStarted = true;
     88     checkDone();
     89 }
     90 
     91 void InspectorResourceContentLoader::addListener(PassOwnPtr<VoidCallback> callback)
     92 {
     93     m_callbacks.append(callback);
     94     checkDone();
     95 }
     96 
     97 InspectorResourceContentLoader::~InspectorResourceContentLoader()
     98 {
     99     stop();
    100 }
    101 
    102 void InspectorResourceContentLoader::stop()
    103 {
    104     HashSet<ResourceClient*> pendingResourceClients;
    105     m_pendingResourceClients.swap(pendingResourceClients);
    106     for (HashSet<ResourceClient*>::const_iterator it = pendingResourceClients.begin(); it != pendingResourceClients.end(); ++it)
    107         (*it)->m_loader = 0;
    108     m_resources.clear();
    109     // Make sure all callbacks are called to prevent infinite waiting time.
    110     checkDone();
    111 }
    112 
    113 bool InspectorResourceContentLoader::hasFinished()
    114 {
    115     return m_allRequestsStarted && m_pendingResourceClients.size() == 0;
    116 }
    117 
    118 void InspectorResourceContentLoader::checkDone()
    119 {
    120     if (!hasFinished())
    121         return;
    122     Vector<OwnPtr<VoidCallback> > callbacks;
    123     callbacks.swap(m_callbacks);
    124     for (Vector<OwnPtr<VoidCallback> >::const_iterator it = callbacks.begin(); it != callbacks.end(); ++it)
    125         (*it)->handleEvent();
    126 }
    127 
    128 void InspectorResourceContentLoader::resourceFinished(ResourceClient* client)
    129 {
    130     m_pendingResourceClients.remove(client);
    131     checkDone();
    132 }
    133 
    134 } // namespace WebCore
    135