| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/html/LinkStyle.h" | 5 #include "core/html/LinkStyle.h" |
| 6 | 6 |
| 7 #include "core/HTMLNames.h" |
| 7 #include "core/css/StyleSheetContents.h" | 8 #include "core/css/StyleSheetContents.h" |
| 9 #include "core/fetch/FetchRequest.h" |
| 8 #include "core/frame/LocalFrame.h" | 10 #include "core/frame/LocalFrame.h" |
| 9 #include "core/frame/SubresourceIntegrity.h" | 11 #include "core/frame/SubresourceIntegrity.h" |
| 10 #include "core/frame/csp/ContentSecurityPolicy.h" | 12 #include "core/frame/csp/ContentSecurityPolicy.h" |
| 11 #include "core/html/CrossOriginAttribute.h" | 13 #include "core/html/CrossOriginAttribute.h" |
| 12 #include "core/html/HTMLLinkElement.h" | 14 #include "core/html/HTMLLinkElement.h" |
| 15 #include "core/html/imports/HTMLImportsController.h" |
| 13 #include "core/loader/FrameLoaderClient.h" | 16 #include "core/loader/FrameLoaderClient.h" |
| 14 #include "core/loader/resource/CSSStyleSheetResource.h" | 17 #include "core/loader/resource/CSSStyleSheetResource.h" |
| 15 #include "platform/ContentType.h" | 18 #include "platform/ContentType.h" |
| 16 #include "platform/Histogram.h" | 19 #include "platform/Histogram.h" |
| 17 #include "platform/MIMETypeRegistry.h" | 20 #include "platform/MIMETypeRegistry.h" |
| 21 #include "platform/weborigin/KURL.h" |
| 22 #include "wtf/text/WTFString.h" |
| 18 | 23 |
| 19 namespace blink { | 24 namespace blink { |
| 20 | 25 |
| 21 using namespace HTMLNames; | 26 using namespace HTMLNames; |
| 22 | 27 |
| 23 static bool styleSheetTypeIsSupported(const String& type) { | 28 static bool styleSheetTypeIsSupported(const String& type) { |
| 24 String trimmedType = ContentType(type).type(); | 29 String trimmedType = ContentType(type).type(); |
| 25 return trimmedType.isEmpty() || | 30 return trimmedType.isEmpty() || |
| 26 MIMETypeRegistry::isSupportedStyleSheetMIMEType(trimmedType); | 31 MIMETypeRegistry::isSupportedStyleSheetMIMEType(trimmedType); |
| 27 } | 32 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 38 m_firedLoad(false), | 43 m_firedLoad(false), |
| 39 m_loadedSheet(false), | 44 m_loadedSheet(false), |
| 40 m_fetchFollowingCORS(false) {} | 45 m_fetchFollowingCORS(false) {} |
| 41 | 46 |
| 42 LinkStyle::~LinkStyle() {} | 47 LinkStyle::~LinkStyle() {} |
| 43 | 48 |
| 44 Document& LinkStyle::document() { | 49 Document& LinkStyle::document() { |
| 45 return m_owner->document(); | 50 return m_owner->document(); |
| 46 } | 51 } |
| 47 | 52 |
| 53 const Document& LinkStyle::document() const { |
| 54 return m_owner->document(); |
| 55 } |
| 56 |
| 48 enum StyleSheetCacheStatus { | 57 enum StyleSheetCacheStatus { |
| 49 StyleSheetNewEntry, | 58 StyleSheetNewEntry, |
| 50 StyleSheetInDiskCache, | 59 StyleSheetInDiskCache, |
| 51 StyleSheetInMemoryCache, | 60 StyleSheetInMemoryCache, |
| 52 StyleSheetCacheStatusCount, | 61 StyleSheetCacheStatusCount, |
| 53 }; | 62 }; |
| 54 | 63 |
| 55 void LinkStyle::setCSSStyleSheet( | 64 void LinkStyle::setCSSStyleSheet( |
| 56 const String& href, | 65 const String& href, |
| 57 const KURL& baseURL, | 66 const KURL& baseURL, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 | 109 |
| 101 if (disposition == ResourceIntegrityDisposition::Failed) { | 110 if (disposition == ResourceIntegrityDisposition::Failed) { |
| 102 m_loading = false; | 111 m_loading = false; |
| 103 removePendingSheet(); | 112 removePendingSheet(); |
| 104 notifyLoadedSheetAndAllCriticalSubresources( | 113 notifyLoadedSheetAndAllCriticalSubresources( |
| 105 Node::ErrorOccurredLoadingSubresource); | 114 Node::ErrorOccurredLoadingSubresource); |
| 106 return; | 115 return; |
| 107 } | 116 } |
| 108 } | 117 } |
| 109 | 118 |
| 110 CSSParserContext parserContext(m_owner->document(), nullptr, baseURL, | 119 CSSParserContext parserContext(document(), nullptr, baseURL, charset); |
| 111 charset); | |
| 112 | 120 |
| 113 DEFINE_STATIC_LOCAL(EnumerationHistogram, restoredCachedStyleSheetHistogram, | 121 DEFINE_STATIC_LOCAL(EnumerationHistogram, restoredCachedStyleSheetHistogram, |
| 114 ("Blink.RestoredCachedStyleSheet", 2)); | 122 ("Blink.RestoredCachedStyleSheet", 2)); |
| 115 DEFINE_STATIC_LOCAL( | 123 DEFINE_STATIC_LOCAL( |
| 116 EnumerationHistogram, restoredCachedStyleSheet2Histogram, | 124 EnumerationHistogram, restoredCachedStyleSheet2Histogram, |
| 117 ("Blink.RestoredCachedStyleSheet2", StyleSheetCacheStatusCount)); | 125 ("Blink.RestoredCachedStyleSheet2", StyleSheetCacheStatusCount)); |
| 118 | 126 |
| 119 if (StyleSheetContents* restoredSheet = | 127 if (StyleSheetContents* restoredSheet = |
| 120 const_cast<CSSStyleSheetResource*>(cachedStyleSheet) | 128 const_cast<CSSStyleSheetResource*>(cachedStyleSheet) |
| 121 ->restoreParsedStyleSheet(parserContext)) { | 129 ->restoreParsedStyleSheet(parserContext)) { |
| 122 DCHECK(restoredSheet->isCacheableForResource()); | 130 DCHECK(restoredSheet->isCacheableForResource()); |
| 123 DCHECK(!restoredSheet->isLoading()); | 131 DCHECK(!restoredSheet->isLoading()); |
| 124 | 132 |
| 125 if (m_sheet) | 133 if (m_sheet) |
| 126 clearSheet(); | 134 clearSheet(); |
| 127 m_sheet = CSSStyleSheet::create(restoredSheet, *m_owner); | 135 m_sheet = CSSStyleSheet::create(restoredSheet, *m_owner); |
| 128 m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media())); | 136 m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media())); |
| 129 if (m_owner->isInDocumentTree()) | 137 if (m_owner->isInDocumentTree()) |
| 130 setSheetTitle(m_owner->title()); | 138 setSheetTitle(m_owner->title()); |
| 131 setCrossOriginStylesheetStatus(m_sheet.get()); | 139 setCrossOriginStylesheetStatus(); |
| 132 | 140 |
| 133 m_loading = false; | 141 m_loading = false; |
| 134 restoredSheet->checkLoaded(); | 142 restoredSheet->checkLoaded(); |
| 135 | 143 |
| 136 restoredCachedStyleSheetHistogram.count(true); | 144 restoredCachedStyleSheetHistogram.count(true); |
| 137 restoredCachedStyleSheet2Histogram.count(StyleSheetInMemoryCache); | 145 restoredCachedStyleSheet2Histogram.count(StyleSheetInMemoryCache); |
| 138 return; | 146 return; |
| 139 } | 147 } |
| 140 restoredCachedStyleSheetHistogram.count(false); | 148 restoredCachedStyleSheetHistogram.count(false); |
| 141 StyleSheetCacheStatus cacheStatus = cachedStyleSheet->response().wasCached() | 149 StyleSheetCacheStatus cacheStatus = cachedStyleSheet->response().wasCached() |
| 142 ? StyleSheetInDiskCache | 150 ? StyleSheetInDiskCache |
| 143 : StyleSheetNewEntry; | 151 : StyleSheetNewEntry; |
| 144 restoredCachedStyleSheet2Histogram.count(cacheStatus); | 152 restoredCachedStyleSheet2Histogram.count(cacheStatus); |
| 145 | 153 |
| 146 StyleSheetContents* styleSheet = | 154 StyleSheetContents* styleSheet = |
| 147 StyleSheetContents::create(href, parserContext); | 155 StyleSheetContents::create(href, parserContext); |
| 148 | 156 |
| 149 if (m_sheet) | 157 if (m_sheet) |
| 150 clearSheet(); | 158 clearSheet(); |
| 151 | 159 |
| 152 m_sheet = CSSStyleSheet::create(styleSheet, *m_owner); | 160 m_sheet = CSSStyleSheet::create(styleSheet, *m_owner); |
| 153 m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media())); | 161 m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media())); |
| 154 if (m_owner->isInDocumentTree()) | 162 if (m_owner->isInDocumentTree()) |
| 155 setSheetTitle(m_owner->title()); | 163 setSheetTitle(m_owner->title()); |
| 156 setCrossOriginStylesheetStatus(m_sheet.get()); | 164 setCrossOriginStylesheetStatus(); |
| 157 | 165 |
| 158 styleSheet->parseAuthorStyleSheet(cachedStyleSheet, | 166 styleSheet->parseAuthorStyleSheet(cachedStyleSheet, |
| 159 m_owner->document().getSecurityOrigin()); | 167 document().getSecurityOrigin()); |
| 160 | 168 |
| 161 m_loading = false; | 169 m_loading = false; |
| 162 styleSheet->notifyLoadedSheet(cachedStyleSheet); | 170 styleSheet->notifyLoadedSheet(cachedStyleSheet); |
| 163 styleSheet->checkLoaded(); | 171 styleSheet->checkLoaded(); |
| 164 | 172 |
| 165 if (styleSheet->isCacheableForResource()) { | 173 if (styleSheet->isCacheableForResource()) { |
| 166 const_cast<CSSStyleSheetResource*>(cachedStyleSheet) | 174 const_cast<CSSStyleSheetResource*>(cachedStyleSheet) |
| 167 ->saveParsedStyleSheet(styleSheet); | 175 ->saveParsedStyleSheet(styleSheet); |
| 168 } | 176 } |
| 169 clearResource(); | 177 clearResource(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 return m_sheet->contents()->isLoading(); | 214 return m_sheet->contents()->isLoading(); |
| 207 } | 215 } |
| 208 | 216 |
| 209 void LinkStyle::addPendingSheet(PendingSheetType type) { | 217 void LinkStyle::addPendingSheet(PendingSheetType type) { |
| 210 if (type <= m_pendingSheetType) | 218 if (type <= m_pendingSheetType) |
| 211 return; | 219 return; |
| 212 m_pendingSheetType = type; | 220 m_pendingSheetType = type; |
| 213 | 221 |
| 214 if (m_pendingSheetType == NonBlocking) | 222 if (m_pendingSheetType == NonBlocking) |
| 215 return; | 223 return; |
| 216 m_owner->document().styleEngine().addPendingSheet(m_styleEngineContext); | 224 document().styleEngine().addPendingSheet(m_styleEngineContext); |
| 217 } | 225 } |
| 218 | 226 |
| 219 void LinkStyle::removePendingSheet() { | 227 void LinkStyle::removePendingSheet() { |
| 220 DCHECK(m_owner); | 228 DCHECK(m_owner); |
| 221 PendingSheetType type = m_pendingSheetType; | 229 PendingSheetType type = m_pendingSheetType; |
| 222 m_pendingSheetType = None; | 230 m_pendingSheetType = None; |
| 223 | 231 |
| 224 if (type == None) | 232 if (type == None) |
| 225 return; | 233 return; |
| 226 if (type == NonBlocking) { | 234 if (type == NonBlocking) { |
| 227 // Tell StyleEngine to re-compute styleSheets of this m_owner's treescope. | 235 // Tell StyleEngine to re-compute styleSheets of this m_owner's treescope. |
| 228 m_owner->document().styleEngine().modifiedStyleSheetCandidateNode(*m_owner); | 236 document().styleEngine().modifiedStyleSheetCandidateNode(*m_owner); |
| 229 return; | 237 return; |
| 230 } | 238 } |
| 231 | 239 |
| 232 m_owner->document().styleEngine().removePendingSheet(*m_owner, | 240 document().styleEngine().removePendingSheet(*m_owner, m_styleEngineContext); |
| 233 m_styleEngineContext); | |
| 234 } | 241 } |
| 235 | 242 |
| 236 void LinkStyle::setDisabledState(bool disabled) { | 243 void LinkStyle::setDisabledState(bool disabled) { |
| 237 LinkStyle::DisabledState oldDisabledState = m_disabledState; | 244 LinkStyle::DisabledState oldDisabledState = m_disabledState; |
| 238 m_disabledState = disabled ? Disabled : EnabledViaScript; | 245 m_disabledState = disabled ? Disabled : EnabledViaScript; |
| 239 if (oldDisabledState != m_disabledState) { | 246 if (oldDisabledState == m_disabledState) |
| 240 // If we change the disabled state while the sheet is still loading, then we | 247 return; |
| 241 // have to perform three checks: | |
| 242 if (styleSheetIsLoading()) { | |
| 243 // Check #1: The sheet becomes disabled while loading. | |
| 244 if (m_disabledState == Disabled) | |
| 245 removePendingSheet(); | |
| 246 | 248 |
| 247 // Check #2: An alternate sheet becomes enabled while it is still loading. | 249 // If we change the disabled state while the sheet is still loading, then we |
| 248 if (m_owner->relAttribute().isAlternate() && | 250 // have to perform three checks: |
| 249 m_disabledState == EnabledViaScript) | 251 if (styleSheetIsLoading()) { |
| 250 addPendingSheet(Blocking); | 252 // Check #1: The sheet becomes disabled while loading. |
| 253 if (m_disabledState == Disabled) |
| 254 removePendingSheet(); |
| 251 | 255 |
| 252 // Check #3: A main sheet becomes enabled while it was still loading and | 256 // Check #2: An alternate sheet becomes enabled while it is still loading. |
| 253 // after it was disabled via script. It takes really terrible code to make | 257 if (m_owner->relAttribute().isAlternate() && |
| 254 // this happen (a double toggle for no reason essentially). This happens | 258 m_disabledState == EnabledViaScript) |
| 255 // on virtualplastic.net, which manages to do about 12 enable/disables on | 259 addPendingSheet(Blocking); |
| 256 // only 3 sheets. :) | |
| 257 if (!m_owner->relAttribute().isAlternate() && | |
| 258 m_disabledState == EnabledViaScript && oldDisabledState == Disabled) | |
| 259 addPendingSheet(Blocking); | |
| 260 | 260 |
| 261 // If the sheet is already loading just bail. | 261 // Check #3: A main sheet becomes enabled while it was still loading and |
| 262 return; | 262 // after it was disabled via script. It takes really terrible code to make |
| 263 } | 263 // this happen (a double toggle for no reason essentially). This happens |
| 264 // on virtualplastic.net, which manages to do about 12 enable/disables on |
| 265 // only 3 sheets. :) |
| 266 if (!m_owner->relAttribute().isAlternate() && |
| 267 m_disabledState == EnabledViaScript && oldDisabledState == Disabled) |
| 268 addPendingSheet(Blocking); |
| 264 | 269 |
| 265 if (m_sheet) { | 270 // If the sheet is already loading just bail. |
| 266 m_sheet->setDisabled(disabled); | 271 return; |
| 267 return; | 272 } |
| 268 } | |
| 269 | 273 |
| 270 if (m_disabledState == EnabledViaScript && m_owner->shouldProcessStyle()) | 274 if (m_sheet) { |
| 271 process(); | 275 m_sheet->setDisabled(disabled); |
| 276 return; |
| 272 } | 277 } |
| 278 |
| 279 if (m_disabledState == EnabledViaScript && m_owner->shouldProcessStyle()) |
| 280 process(); |
| 273 } | 281 } |
| 274 | 282 |
| 275 void LinkStyle::setCrossOriginStylesheetStatus(CSSStyleSheet* sheet) { | 283 void LinkStyle::setCrossOriginStylesheetStatus() { |
| 276 if (m_fetchFollowingCORS && resource() && !resource()->errorOccurred()) { | 284 if (m_fetchFollowingCORS && resource() && !resource()->errorOccurred()) { |
| 277 // Record the security origin the CORS access check succeeded at, if cross | 285 // Record the security origin the CORS access check succeeded at, if cross |
| 278 // origin. Only origins that are script accessible to it may access the | 286 // origin. Only origins that are script accessible to it may access the |
| 279 // stylesheet's rules. | 287 // stylesheet's rules. |
| 280 sheet->setAllowRuleAccessFromOrigin( | 288 m_sheet->setAllowRuleAccessFromOrigin(document().getSecurityOrigin()); |
| 281 m_owner->document().getSecurityOrigin()); | |
| 282 } | 289 } |
| 283 m_fetchFollowingCORS = false; | 290 m_fetchFollowingCORS = false; |
| 284 } | 291 } |
| 285 | 292 |
| 293 bool LinkStyle::shouldLoadResource() const { |
| 294 return document().frame() || document().importsController(); |
| 295 } |
| 296 |
| 286 // TODO(yoav): move that logic to LinkLoader | 297 // TODO(yoav): move that logic to LinkLoader |
| 287 LinkStyle::LoadReturnValue LinkStyle::loadStylesheetIfNeeded( | 298 void LinkStyle::loadStylesheetIfNeeded(const String& type) { |
| 288 const LinkRequestBuilder& builder, | 299 const KURL& href = m_owner->getNonEmptyURLAttribute(hrefAttr); |
| 289 const String& type) { | 300 |
| 290 if (m_disabledState == Disabled || !m_owner->relAttribute().isStyleSheet() || | 301 if (m_disabledState == Disabled || !m_owner->relAttribute().isStyleSheet() || |
| 291 !styleSheetTypeIsSupported(type) || !shouldLoadResource() || | 302 !styleSheetTypeIsSupported(type) || !shouldLoadResource() || |
| 292 !builder.url().isValid()) | 303 !href.isValid()) { |
| 293 return NotNeeded; | 304 if (!m_sheet) |
| 305 return; |
| 306 |
| 307 // we no longer contain a stylesheet, e.g. perhaps rel or type was changed |
| 308 StyleSheet* removedSheet = m_sheet.get(); |
| 309 clearSheet(); |
| 310 document().styleEngine().setNeedsActiveStyleUpdate(removedSheet, |
| 311 FullStyleUpdate); |
| 312 return; |
| 313 } |
| 294 | 314 |
| 295 if (resource()) { | 315 if (resource()) { |
| 296 removePendingSheet(); | 316 removePendingSheet(); |
| 297 clearResource(); | 317 clearResource(); |
| 298 clearFetchFollowingCORS(); | 318 m_fetchFollowingCORS = false; |
| 299 } | 319 } |
| 300 | 320 |
| 301 if (!m_owner->shouldLoadLink()) | 321 if (m_owner->shouldLoadLink()) |
| 302 return Bail; | 322 loadStylesheet(); |
| 323 } |
| 303 | 324 |
| 325 LocalFrame* LinkStyle::loadingFrame() const { |
| 326 HTMLImportsController* importsController = document().importsController(); |
| 327 if (!importsController) |
| 328 return document().frame(); |
| 329 return importsController->master()->frame(); |
| 330 } |
| 331 |
| 332 void LinkStyle::loadStylesheet() { |
| 304 m_loading = true; | 333 m_loading = true; |
| 305 | 334 |
| 306 String title = m_owner->title(); | 335 String title = m_owner->title(); |
| 307 if (!title.isEmpty() && !m_owner->isAlternate() && | 336 if (!title.isEmpty() && !m_owner->isAlternate() && |
| 308 m_disabledState != EnabledViaScript && m_owner->isInDocumentTree()) { | 337 m_disabledState != EnabledViaScript && m_owner->isInDocumentTree()) { |
| 309 document().styleEngine().setPreferredStylesheetSetNameIfNotSet( | 338 document().styleEngine().setPreferredStylesheetSetNameIfNotSet( |
| 310 title, StyleEngine::DontUpdateActiveSheets); | 339 title, StyleEngine::DontUpdateActiveSheets); |
| 311 } | 340 } |
| 312 | 341 |
| 313 bool mediaQueryMatches = true; | 342 bool mediaQueryMatches = true; |
| 314 LocalFrame* frame = loadingFrame(); | 343 LocalFrame* frame = loadingFrame(); |
| 315 if (!m_owner->media().isEmpty() && frame) { | 344 if (!m_owner->media().isEmpty() && frame) { |
| 316 MediaQuerySet* media = MediaQuerySet::create(m_owner->media()); | 345 MediaQuerySet* media = MediaQuerySet::create(m_owner->media()); |
| 317 MediaQueryEvaluator evaluator(frame); | 346 MediaQueryEvaluator evaluator(frame); |
| 318 mediaQueryMatches = evaluator.eval(media); | 347 mediaQueryMatches = evaluator.eval(media); |
| 319 } | 348 } |
| 320 | 349 |
| 321 // Don't hold up layout tree construction and script execution on | 350 // Don't hold up layout tree construction and script execution on |
| 322 // stylesheets that are not needed for the layout at the moment. | 351 // stylesheets that are not needed for the layout at the moment. |
| 323 bool blocking = mediaQueryMatches && !m_owner->isAlternate() && | 352 bool blocking = mediaQueryMatches && !m_owner->isAlternate() && |
| 324 m_owner->isCreatedByParser(); | 353 m_owner->isCreatedByParser(); |
| 325 addPendingSheet(blocking ? Blocking : NonBlocking); | 354 addPendingSheet(blocking ? Blocking : NonBlocking); |
| 326 | 355 |
| 356 FetchRequest request = m_owner->createFetchRequest(); |
| 357 |
| 327 // Load stylesheets that are not needed for the layout immediately with low | 358 // Load stylesheets that are not needed for the layout immediately with low |
| 328 // priority. When the link element is created by scripts, load the | 359 // priority. When the link element is created by scripts, load the |
| 329 // stylesheets asynchronously but in high priority. | 360 // stylesheets asynchronously but in high priority. |
| 330 bool lowPriority = !mediaQueryMatches || m_owner->isAlternate(); | 361 if (!mediaQueryMatches || m_owner->isAlternate()) |
| 331 FetchRequest request = builder.build(lowPriority); | 362 request.setDefer(FetchRequest::LazyLoad); |
| 363 |
| 332 CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue( | 364 CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue( |
| 333 m_owner->fastGetAttribute(HTMLNames::crossoriginAttr)); | 365 m_owner->fastGetAttribute(HTMLNames::crossoriginAttr)); |
| 334 if (crossOrigin != CrossOriginAttributeNotSet) { | 366 if (crossOrigin != CrossOriginAttributeNotSet) { |
| 335 request.setCrossOriginAccessControl(document().getSecurityOrigin(), | 367 request.setCrossOriginAccessControl(document().getSecurityOrigin(), |
| 336 crossOrigin); | 368 crossOrigin); |
| 337 setFetchFollowingCORS(); | 369 DCHECK(!m_fetchFollowingCORS); |
| 370 m_fetchFollowingCORS = true; |
| 338 } | 371 } |
| 339 | 372 |
| 340 String integrityAttr = m_owner->fastGetAttribute(HTMLNames::integrityAttr); | 373 String integrityAttr = m_owner->fastGetAttribute(HTMLNames::integrityAttr); |
| 341 if (!integrityAttr.isEmpty()) { | 374 if (!integrityAttr.isEmpty()) { |
| 342 IntegrityMetadataSet metadataSet; | 375 IntegrityMetadataSet metadataSet; |
| 343 SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet); | 376 SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet); |
| 344 request.setIntegrityMetadata(metadataSet); | 377 request.setIntegrityMetadata(metadataSet); |
| 345 } | 378 } |
| 346 setResource(CSSStyleSheetResource::fetch(request, document().fetcher())); | 379 setResource(CSSStyleSheetResource::fetch(request, document().fetcher())); |
| 347 | 380 |
| 348 if (m_loading && !resource()) { | 381 if (!m_loading || resource()) |
| 349 // The request may have been denied if (for example) the stylesheet is | 382 return; |
| 350 // local and the document is remote, or if there was a Content Security | 383 |
| 351 // Policy Failure. setCSSStyleSheet() can be called synchronuosly in | 384 // The request may have been denied if (for example) the stylesheet is |
| 352 // setResource() and thus resource() is null and |m_loading| is false in | 385 // local and the document is remote, or if there was a Content Security |
| 353 // such cases even if the request succeeds. | 386 // Policy Failure. setCSSStyleSheet() can be called synchronuosly in |
| 354 m_loading = false; | 387 // setResource() and thus resource() is null and |m_loading| is false in |
| 355 removePendingSheet(); | 388 // such cases even if the request succeeds. |
| 356 notifyLoadedSheetAndAllCriticalSubresources( | 389 m_loading = false; |
| 357 Node::ErrorOccurredLoadingSubresource); | 390 removePendingSheet(); |
| 358 } | 391 notifyLoadedSheetAndAllCriticalSubresources( |
| 359 return Loaded; | 392 Node::ErrorOccurredLoadingSubresource); |
| 360 } | 393 } |
| 361 | 394 |
| 362 void LinkStyle::process() { | 395 void LinkStyle::process() { |
| 363 DCHECK(m_owner->shouldProcessStyle()); | 396 DCHECK(m_owner->shouldProcessStyle()); |
| 397 |
| 364 String type = m_owner->typeValue().lower(); | 398 String type = m_owner->typeValue().lower(); |
| 365 String as = m_owner->asValue().lower(); | 399 String as = m_owner->asValue().lower(); |
| 366 String media = m_owner->media().lower(); | 400 String media = m_owner->media().lower(); |
| 367 LinkRequestBuilder builder(m_owner); | |
| 368 | 401 |
| 369 if (m_owner->relAttribute().getIconType() != InvalidIcon && | 402 const KURL& href = m_owner->getNonEmptyURLAttribute(hrefAttr); |
| 370 builder.url().isValid() && !builder.url().isEmpty()) { | 403 |
| 404 if (m_owner->relAttribute().getIconType() != InvalidIcon && href.isValid() && |
| 405 !href.isEmpty()) { |
| 371 if (!m_owner->shouldLoadLink()) | 406 if (!m_owner->shouldLoadLink()) |
| 372 return; | 407 return; |
| 373 if (!document().getSecurityOrigin()->canDisplay(builder.url())) | 408 if (!document().getSecurityOrigin()->canDisplay(href)) |
| 374 return; | 409 return; |
| 375 if (!document().contentSecurityPolicy()->allowImageFromSource( | 410 if (!document().contentSecurityPolicy()->allowImageFromSource(href)) |
| 376 builder.url())) | |
| 377 return; | 411 return; |
| 378 if (document().frame() && document().frame()->loader().client()) { | 412 if (document().frame() && document().frame()->loader().client()) { |
| 379 document().frame()->loader().client()->dispatchDidChangeIcons( | 413 document().frame()->loader().client()->dispatchDidChangeIcons( |
| 380 m_owner->relAttribute().getIconType()); | 414 m_owner->relAttribute().getIconType()); |
| 381 } | 415 } |
| 382 } | 416 } |
| 383 | 417 |
| 384 if (!m_owner->loadLink(type, as, media, m_owner->referrerPolicy(), | 418 if (m_owner->loadLink(type, as, media, m_owner->referrerPolicy(), href)) |
| 385 builder.url())) | 419 loadStylesheetIfNeeded(type); |
| 386 return; | |
| 387 | |
| 388 if (loadStylesheetIfNeeded(builder, type) == NotNeeded && m_sheet) { | |
| 389 // we no longer contain a stylesheet, e.g. perhaps rel or type was changed | |
| 390 StyleSheet* removedSheet = m_sheet.get(); | |
| 391 clearSheet(); | |
| 392 document().styleEngine().setNeedsActiveStyleUpdate(removedSheet, | |
| 393 FullStyleUpdate); | |
| 394 } | |
| 395 } | 420 } |
| 396 | 421 |
| 397 void LinkStyle::setSheetTitle( | 422 void LinkStyle::setSheetTitle( |
| 398 const String& title, | 423 const String& title, |
| 399 StyleEngine::ActiveSheetsUpdate updateActiveSheets) { | 424 StyleEngine::ActiveSheetsUpdate updateActiveSheets) { |
| 400 if (!m_owner->isInDocumentTree() || !m_owner->relAttribute().isStyleSheet()) | 425 if (!m_owner->isInDocumentTree() || !m_owner->relAttribute().isStyleSheet()) |
| 401 return; | 426 return; |
| 402 | 427 |
| 403 if (m_sheet) | 428 if (m_sheet) |
| 404 m_sheet->setTitle(title); | 429 m_sheet->setTitle(title); |
| 405 | 430 |
| 406 if (title.isEmpty() || !isUnset() || m_owner->isAlternate()) | 431 if (title.isEmpty() || !isUnset() || m_owner->isAlternate()) |
| 407 return; | 432 return; |
| 408 | 433 |
| 409 KURL href = m_owner->getNonEmptyURLAttribute(hrefAttr); | 434 const KURL& href = m_owner->getNonEmptyURLAttribute(hrefAttr); |
| 410 if (href.isValid() && !href.isEmpty()) { | 435 if (href.isValid() && !href.isEmpty()) { |
| 411 document().styleEngine().setPreferredStylesheetSetNameIfNotSet( | 436 document().styleEngine().setPreferredStylesheetSetNameIfNotSet( |
| 412 title, updateActiveSheets); | 437 title, updateActiveSheets); |
| 413 } | 438 } |
| 414 } | 439 } |
| 415 | 440 |
| 416 void LinkStyle::ownerRemoved() { | 441 void LinkStyle::ownerRemoved() { |
| 417 if (m_sheet) | 442 if (m_sheet) |
| 418 clearSheet(); | 443 clearSheet(); |
| 419 | 444 |
| 420 if (styleSheetIsLoading()) | 445 if (styleSheetIsLoading()) |
| 421 removePendingSheet(); | 446 removePendingSheet(); |
| 422 } | 447 } |
| 423 | 448 |
| 424 DEFINE_TRACE(LinkStyle) { | 449 DEFINE_TRACE(LinkStyle) { |
| 425 visitor->trace(m_sheet); | 450 visitor->trace(m_sheet); |
| 426 LinkResource::trace(visitor); | 451 LinkResource::trace(visitor); |
| 427 ResourceOwner<StyleSheetResource>::trace(visitor); | 452 ResourceOwner<StyleSheetResource>::trace(visitor); |
| 428 } | 453 } |
| 429 | 454 |
| 430 } // namespace blink | 455 } // namespace blink |
| OLD | NEW |