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