void StyleSheetContents::checkLoaded() { if (isLoading()) return; // Avoid |this| being deleted by scripts that run via // ScriptableDocumentParser::executeScriptsWaitingForResources(). // See https://bugs.webkit.org/show_bug.cgi?id=95106 RefPtrWillBeRawPtr<StyleSheetContents> protect(this); StyleSheetContents* parentSheet = parentStyleSheet(); if (parentSheet) { parentSheet->checkLoaded(); return; } ASSERT(this == rootStyleSheet()); if (m_loadingClients.isEmpty()) return; // Avoid |CSSSStyleSheet| and |ownerNode| being deleted by scripts that run via // ScriptableDocumentParser::executeScriptsWaitingForResources(). Also protect // the |CSSStyleSheet| from being deleted during iteration via the |sheetLoaded| // method. // // When a sheet is loaded it is moved from the set of loading clients // to the set of completed clients. We therefore need the copy in order to // not modify the set while iterating it. WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > loadingClients; copyToVector(m_loadingClients, loadingClients); for (unsigned i = 0; i < loadingClients.size(); ++i) { if (loadingClients[i]->loadCompleted()) continue; // sheetLoaded might be invoked after its owner node is removed from document. if (RefPtrWillBeRawPtr<Node> ownerNode = loadingClients[i]->ownerNode()) { if (loadingClients[i]->sheetLoaded()) ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur); } } }
void StyleSheetContents::checkLoaded() { if (isLoading()) return; StyleSheetContents* parentSheet = parentStyleSheet(); if (parentSheet) { parentSheet->checkLoaded(); return; } ASSERT(this == rootStyleSheet()); if (m_loadingClients.isEmpty()) return; // Avoid |CSSSStyleSheet| and |ownerNode| being deleted by scripts that run // via ScriptableDocumentParser::executeScriptsWaitingForResources(). Also // protect the |CSSStyleSheet| from being deleted during iteration via the // |sheetLoaded| method. // // When a sheet is loaded it is moved from the set of loading clients // to the set of completed clients. We therefore need the copy in order to // not modify the set while iterating it. HeapVector<Member<CSSStyleSheet>> loadingClients; copyToVector(m_loadingClients, loadingClients); for (unsigned i = 0; i < loadingClients.size(); ++i) { if (loadingClients[i]->loadCompleted()) continue; // sheetLoaded might be invoked after its owner node is removed from // document. if (Node* ownerNode = loadingClients[i]->ownerNode()) { if (loadingClients[i]->sheetLoaded()) ownerNode->notifyLoadedSheetAndAllCriticalSubresources( m_didLoadErrorOccur ? Node::ErrorOccurredLoadingSubresource : Node::NoErrorLoadingSubresource); } } }
void LinkStyle::setCSSStyleSheet( const String& href, const KURL& baseURL, const String& charset, const CSSStyleSheetResource* cachedStyleSheet) { if (!m_owner->isConnected()) { // While the stylesheet is asynchronously loading, the owner can be // disconnected from a document. // In that case, cancel any processing on the loaded content. m_loading = false; removePendingSheet(); if (m_sheet) clearSheet(); return; } // See the comment in PendingScript.cpp about why this check is necessary // here, instead of in the resource fetcher. https://crbug.com/500701. if (!cachedStyleSheet->errorOccurred() && !m_owner->fastGetAttribute(HTMLNames::integrityAttr).isEmpty() && !cachedStyleSheet->integrityMetadata().isEmpty()) { ResourceIntegrityDisposition disposition = cachedStyleSheet->integrityDisposition(); if (disposition == ResourceIntegrityDisposition::NotChecked && !cachedStyleSheet->loadFailedOrCanceled()) { bool checkResult; // cachedStyleSheet->resourceBuffer() can be nullptr on load success. // If response size == 0. const char* data = nullptr; size_t size = 0; if (cachedStyleSheet->resourceBuffer()) { data = cachedStyleSheet->resourceBuffer()->data(); size = cachedStyleSheet->resourceBuffer()->size(); } checkResult = SubresourceIntegrity::CheckSubresourceIntegrity( *m_owner, data, size, KURL(baseURL, href), *cachedStyleSheet); disposition = checkResult ? ResourceIntegrityDisposition::Passed : ResourceIntegrityDisposition::Failed; // TODO(kouhei): Remove this const_cast crbug.com/653502 const_cast<CSSStyleSheetResource*>(cachedStyleSheet) ->setIntegrityDisposition(disposition); } if (disposition == ResourceIntegrityDisposition::Failed) { m_loading = false; removePendingSheet(); notifyLoadedSheetAndAllCriticalSubresources( Node::ErrorOccurredLoadingSubresource); return; } } CSSParserContext parserContext(m_owner->document(), nullptr, baseURL, charset); DEFINE_STATIC_LOCAL(EnumerationHistogram, restoredCachedStyleSheetHistogram, ("Blink.RestoredCachedStyleSheet", 2)); DEFINE_STATIC_LOCAL( EnumerationHistogram, restoredCachedStyleSheet2Histogram, ("Blink.RestoredCachedStyleSheet2", StyleSheetCacheStatusCount)); if (StyleSheetContents* restoredSheet = const_cast<CSSStyleSheetResource*>(cachedStyleSheet) ->restoreParsedStyleSheet(parserContext)) { DCHECK(restoredSheet->isCacheableForResource()); DCHECK(!restoredSheet->isLoading()); if (m_sheet) clearSheet(); m_sheet = CSSStyleSheet::create(restoredSheet, *m_owner); m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media())); if (m_owner->isInDocumentTree()) setSheetTitle(m_owner->title()); setCrossOriginStylesheetStatus(m_sheet.get()); m_loading = false; restoredSheet->checkLoaded(); restoredCachedStyleSheetHistogram.count(true); restoredCachedStyleSheet2Histogram.count(StyleSheetInMemoryCache); return; } restoredCachedStyleSheetHistogram.count(false); StyleSheetCacheStatus cacheStatus = cachedStyleSheet->response().wasCached() ? StyleSheetInDiskCache : StyleSheetNewEntry; restoredCachedStyleSheet2Histogram.count(cacheStatus); StyleSheetContents* styleSheet = StyleSheetContents::create(href, parserContext); if (m_sheet) clearSheet(); m_sheet = CSSStyleSheet::create(styleSheet, *m_owner); m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media())); if (m_owner->isInDocumentTree()) setSheetTitle(m_owner->title()); setCrossOriginStylesheetStatus(m_sheet.get()); styleSheet->parseAuthorStyleSheet(cachedStyleSheet, m_owner->document().getSecurityOrigin()); m_loading = false; styleSheet->notifyLoadedSheet(cachedStyleSheet); styleSheet->checkLoaded(); if (styleSheet->isCacheableForResource()) { const_cast<CSSStyleSheetResource*>(cachedStyleSheet) ->saveParsedStyleSheet(styleSheet); } clearResource(); }