Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(263)

Side by Side Diff: third_party/WebKit/Source/core/html/HTMLLinkElement.cpp

Issue 2426513003: Refactor LinkStyle out of HTMLLinkElement (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv ed. 5 * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv ed.
6 * Copyright (C) 2009 Rob Buis (rwlbuis@gmail.com) 6 * Copyright (C) 2009 Rob Buis (rwlbuis@gmail.com)
7 * Copyright (C) 2011 Google Inc. All rights reserved. 7 * Copyright (C) 2011 Google Inc. All rights reserved.
8 * 8 *
9 * This library is free software; you can redistribute it and/or 9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public 10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either 11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version. 12 * version 2 of the License, or (at your option) any later version.
13 * 13 *
14 * This library is distributed in the hope that it will be useful, 14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details. 17 * Library General Public License for more details.
18 * 18 *
19 * You should have received a copy of the GNU Library General Public License 19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to 20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA. 22 * Boston, MA 02110-1301, USA.
23 */ 23 */
24 24
25 #include "core/html/HTMLLinkElement.h" 25 #include "core/html/HTMLLinkElement.h"
26 26
27 #include "bindings/core/v8/ScriptEventListener.h" 27 #include "bindings/core/v8/ScriptEventListener.h"
28 #include "core/HTMLNames.h" 28 #include "core/HTMLNames.h"
29 #include "core/css/MediaList.h"
30 #include "core/css/MediaQueryEvaluator.h"
31 #include "core/css/StyleSheetContents.h"
32 #include "core/css/resolver/StyleResolver.h"
33 #include "core/dom/Attribute.h" 29 #include "core/dom/Attribute.h"
34 #include "core/dom/Document.h" 30 #include "core/dom/Document.h"
35 #include "core/dom/StyleEngine.h"
36 #include "core/dom/TaskRunnerHelper.h" 31 #include "core/dom/TaskRunnerHelper.h"
37 #include "core/events/Event.h" 32 #include "core/events/Event.h"
38 #include "core/fetch/CSSStyleSheetResource.h"
39 #include "core/fetch/FetchRequest.h"
40 #include "core/fetch/ResourceFetcher.h"
41 #include "core/frame/FrameView.h"
42 #include "core/frame/LocalFrame.h"
43 #include "core/frame/SubresourceIntegrity.h"
44 #include "core/frame/UseCounter.h" 33 #include "core/frame/UseCounter.h"
45 #include "core/frame/csp/ContentSecurityPolicy.h"
46 #include "core/html/CrossOriginAttribute.h" 34 #include "core/html/CrossOriginAttribute.h"
47 #include "core/html/LinkManifest.h" 35 #include "core/html/LinkManifest.h"
48 #include "core/html/imports/LinkImport.h" 36 #include "core/html/imports/LinkImport.h"
49 #include "core/inspector/ConsoleMessage.h" 37 #include "core/inspector/ConsoleMessage.h"
50 #include "core/loader/FrameLoader.h"
51 #include "core/loader/FrameLoaderClient.h" 38 #include "core/loader/FrameLoaderClient.h"
52 #include "core/loader/NetworkHintsInterface.h" 39 #include "core/loader/NetworkHintsInterface.h"
53 #include "core/origin_trials/OriginTrials.h" 40 #include "core/origin_trials/OriginTrials.h"
54 #include "core/style/StyleInheritedData.h"
55 #include "platform/ContentType.h"
56 #include "platform/Histogram.h"
57 #include "platform/MIMETypeRegistry.h"
58 #include "platform/RuntimeEnabledFeatures.h"
59 #include "public/platform/WebIconSizesParser.h" 41 #include "public/platform/WebIconSizesParser.h"
60 #include "public/platform/WebSize.h" 42 #include "public/platform/WebSize.h"
61 #include "wtf/StdLibExtras.h"
62 43
63 namespace blink { 44 namespace blink {
64 45
65 using namespace HTMLNames; 46 using namespace HTMLNames;
66 47
67 static bool styleSheetTypeIsSupported(const String& type) {
68 String trimmedType = ContentType(type).type();
69 return trimmedType.isEmpty() ||
70 MIMETypeRegistry::isSupportedStyleSheetMIMEType(trimmedType);
71 }
72
73 inline HTMLLinkElement::HTMLLinkElement(Document& document, 48 inline HTMLLinkElement::HTMLLinkElement(Document& document,
74 bool createdByParser) 49 bool createdByParser)
75 : HTMLElement(linkTag, document), 50 : HTMLElement(linkTag, document),
76 m_linkLoader(LinkLoader::create(this)), 51 m_linkLoader(LinkLoader::create(this)),
77 m_sizes(DOMTokenList::create(this)), 52 m_sizes(DOMTokenList::create(this)),
78 m_relList(RelList::create(this)), 53 m_relList(RelList::create(this)),
79 m_createdByParser(createdByParser) {} 54 m_createdByParser(createdByParser) {}
80 55
81 HTMLLinkElement* HTMLLinkElement::create(Document& document, 56 HTMLLinkElement* HTMLLinkElement::create(Document& document,
82 bool createdByParser) { 57 bool createdByParser) {
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 HTMLElement::trace(visitor); 350 HTMLElement::trace(visitor);
376 LinkLoaderClient::trace(visitor); 351 LinkLoaderClient::trace(visitor);
377 DOMTokenListObserver::trace(visitor); 352 DOMTokenListObserver::trace(visitor);
378 } 353 }
379 354
380 DEFINE_TRACE_WRAPPERS(HTMLLinkElement) { 355 DEFINE_TRACE_WRAPPERS(HTMLLinkElement) {
381 visitor->traceWrappers(m_relList); 356 visitor->traceWrappers(m_relList);
382 HTMLElement::traceWrappers(visitor); 357 HTMLElement::traceWrappers(visitor);
383 } 358 }
384 359
385 LinkStyle* LinkStyle::create(HTMLLinkElement* owner) {
386 return new LinkStyle(owner);
387 }
388
389 LinkStyle::LinkStyle(HTMLLinkElement* owner)
390 : LinkResource(owner),
391 m_disabledState(Unset),
392 m_pendingSheetType(None),
393 m_loading(false),
394 m_firedLoad(false),
395 m_loadedSheet(false),
396 m_fetchFollowingCORS(false) {}
397
398 LinkStyle::~LinkStyle() {}
399
400 Document& LinkStyle::document() {
401 return m_owner->document();
402 }
403
404 enum StyleSheetCacheStatus {
405 StyleSheetNewEntry,
406 StyleSheetInDiskCache,
407 StyleSheetInMemoryCache,
408 StyleSheetCacheStatusCount,
409 };
410
411 void LinkStyle::setCSSStyleSheet(
412 const String& href,
413 const KURL& baseURL,
414 const String& charset,
415 const CSSStyleSheetResource* cachedStyleSheet) {
416 if (!m_owner->isConnected()) {
417 // While the stylesheet is asynchronously loading, the owner can be disconne cted from a document.
418 // In that case, cancel any processing on the loaded content.
419 m_loading = false;
420 removePendingSheet();
421 if (m_sheet)
422 clearSheet();
423 return;
424 }
425
426 // See the comment in PendingScript.cpp about why this check is necessary
427 // here, instead of in the resource fetcher. https://crbug.com/500701.
428 if (!cachedStyleSheet->errorOccurred() &&
429 m_owner->fastHasAttribute(HTMLNames::integrityAttr) &&
430 cachedStyleSheet->resourceBuffer() &&
431 !SubresourceIntegrity::CheckSubresourceIntegrity(
432 *m_owner, cachedStyleSheet->resourceBuffer()->data(),
433 cachedStyleSheet->resourceBuffer()->size(), KURL(baseURL, href),
434 *cachedStyleSheet)) {
435 m_loading = false;
436 removePendingSheet();
437 notifyLoadedSheetAndAllCriticalSubresources(
438 Node::ErrorOccurredLoadingSubresource);
439 return;
440 }
441
442 CSSParserContext parserContext(m_owner->document(), nullptr, baseURL,
443 charset);
444
445 DEFINE_STATIC_LOCAL(EnumerationHistogram, restoredCachedStyleSheetHistogram,
446 ("Blink.RestoredCachedStyleSheet", 2));
447 DEFINE_STATIC_LOCAL(
448 EnumerationHistogram, restoredCachedStyleSheet2Histogram,
449 ("Blink.RestoredCachedStyleSheet2", StyleSheetCacheStatusCount));
450
451 if (StyleSheetContents* restoredSheet =
452 const_cast<CSSStyleSheetResource*>(cachedStyleSheet)
453 ->restoreParsedStyleSheet(parserContext)) {
454 DCHECK(restoredSheet->isCacheableForResource());
455 DCHECK(!restoredSheet->isLoading());
456
457 if (m_sheet)
458 clearSheet();
459 m_sheet = CSSStyleSheet::create(restoredSheet, *m_owner);
460 m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media()));
461 if (m_owner->isInDocumentTree())
462 setSheetTitle(m_owner->title());
463 setCrossOriginStylesheetStatus(m_sheet.get());
464
465 m_loading = false;
466 restoredSheet->checkLoaded();
467
468 restoredCachedStyleSheetHistogram.count(true);
469 restoredCachedStyleSheet2Histogram.count(StyleSheetInMemoryCache);
470 return;
471 }
472 restoredCachedStyleSheetHistogram.count(false);
473 StyleSheetCacheStatus cacheStatus = cachedStyleSheet->response().wasCached()
474 ? StyleSheetInDiskCache
475 : StyleSheetNewEntry;
476 restoredCachedStyleSheet2Histogram.count(cacheStatus);
477
478 StyleSheetContents* styleSheet =
479 StyleSheetContents::create(href, parserContext);
480
481 if (m_sheet)
482 clearSheet();
483
484 m_sheet = CSSStyleSheet::create(styleSheet, *m_owner);
485 m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media()));
486 if (m_owner->isInDocumentTree())
487 setSheetTitle(m_owner->title());
488 setCrossOriginStylesheetStatus(m_sheet.get());
489
490 styleSheet->parseAuthorStyleSheet(cachedStyleSheet,
491 m_owner->document().getSecurityOrigin());
492
493 m_loading = false;
494 styleSheet->notifyLoadedSheet(cachedStyleSheet);
495 styleSheet->checkLoaded();
496
497 if (styleSheet->isCacheableForResource())
498 const_cast<CSSStyleSheetResource*>(cachedStyleSheet)
499 ->saveParsedStyleSheet(styleSheet);
500 clearResource();
501 }
502
503 bool LinkStyle::sheetLoaded() {
504 if (!styleSheetIsLoading()) {
505 removePendingSheet();
506 return true;
507 }
508 return false;
509 }
510
511 void LinkStyle::notifyLoadedSheetAndAllCriticalSubresources(
512 Node::LoadedSheetErrorStatus errorStatus) {
513 if (m_firedLoad)
514 return;
515 m_loadedSheet = (errorStatus == Node::NoErrorLoadingSubresource);
516 if (m_owner)
517 m_owner->scheduleEvent();
518 m_firedLoad = true;
519 }
520
521 void LinkStyle::startLoadingDynamicSheet() {
522 DCHECK_LT(m_pendingSheetType, Blocking);
523 addPendingSheet(Blocking);
524 }
525
526 void LinkStyle::clearSheet() {
527 DCHECK(m_sheet);
528 DCHECK_EQ(m_sheet->ownerNode(), m_owner);
529 m_sheet.release()->clearOwnerNode();
530 }
531
532 bool LinkStyle::styleSheetIsLoading() const {
533 if (m_loading)
534 return true;
535 if (!m_sheet)
536 return false;
537 return m_sheet->contents()->isLoading();
538 }
539
540 void LinkStyle::addPendingSheet(PendingSheetType type) {
541 if (type <= m_pendingSheetType)
542 return;
543 m_pendingSheetType = type;
544
545 if (m_pendingSheetType == NonBlocking)
546 return;
547 m_owner->document().styleEngine().addPendingSheet(m_styleEngineContext);
548 }
549
550 void LinkStyle::removePendingSheet() {
551 DCHECK(m_owner);
552 PendingSheetType type = m_pendingSheetType;
553 m_pendingSheetType = None;
554
555 if (type == None)
556 return;
557 if (type == NonBlocking) {
558 // Tell StyleEngine to re-compute styleSheets of this m_owner's treescope.
559 m_owner->document().styleEngine().modifiedStyleSheetCandidateNode(*m_owner);
560 return;
561 }
562
563 m_owner->document().styleEngine().removePendingSheet(*m_owner,
564 m_styleEngineContext);
565 }
566
567 void LinkStyle::setDisabledState(bool disabled) {
568 LinkStyle::DisabledState oldDisabledState = m_disabledState;
569 m_disabledState = disabled ? Disabled : EnabledViaScript;
570 if (oldDisabledState != m_disabledState) {
571 // If we change the disabled state while the sheet is still loading, then we have to
572 // perform three checks:
573 if (styleSheetIsLoading()) {
574 // Check #1: The sheet becomes disabled while loading.
575 if (m_disabledState == Disabled)
576 removePendingSheet();
577
578 // Check #2: An alternate sheet becomes enabled while it is still loading.
579 if (m_owner->relAttribute().isAlternate() &&
580 m_disabledState == EnabledViaScript)
581 addPendingSheet(Blocking);
582
583 // Check #3: A main sheet becomes enabled while it was still loading and
584 // after it was disabled via script. It takes really terrible code to make this
585 // happen (a double toggle for no reason essentially). This happens on
586 // virtualplastic.net, which manages to do about 12 enable/disables on onl y 3
587 // sheets. :)
588 if (!m_owner->relAttribute().isAlternate() &&
589 m_disabledState == EnabledViaScript && oldDisabledState == Disabled)
590 addPendingSheet(Blocking);
591
592 // If the sheet is already loading just bail.
593 return;
594 }
595
596 if (m_sheet) {
597 m_sheet->setDisabled(disabled);
598 return;
599 }
600
601 if (m_disabledState == EnabledViaScript && m_owner->shouldProcessStyle())
602 process();
603 }
604 }
605
606 void LinkStyle::setCrossOriginStylesheetStatus(CSSStyleSheet* sheet) {
607 if (m_fetchFollowingCORS && resource() && !resource()->errorOccurred()) {
608 // Record the security origin the CORS access check succeeded at, if cross o rigin.
609 // Only origins that are script accessible to it may access the stylesheet's rules.
610 sheet->setAllowRuleAccessFromOrigin(
611 m_owner->document().getSecurityOrigin());
612 }
613 m_fetchFollowingCORS = false;
614 }
615
616 void LinkStyle::process() {
617 DCHECK(m_owner->shouldProcessStyle());
618 String type = m_owner->typeValue().lower();
619 String as = m_owner->asValue().lower();
620 String media = m_owner->media().lower();
621 LinkRequestBuilder builder(m_owner);
622
623 if (m_owner->relAttribute().getIconType() != InvalidIcon &&
624 builder.url().isValid() && !builder.url().isEmpty()) {
625 if (!m_owner->shouldLoadLink())
626 return;
627 if (!document().getSecurityOrigin()->canDisplay(builder.url()))
628 return;
629 if (!document().contentSecurityPolicy()->allowImageFromSource(
630 builder.url()))
631 return;
632 if (document().frame() && document().frame()->loader().client())
633 document().frame()->loader().client()->dispatchDidChangeIcons(
634 m_owner->relAttribute().getIconType());
635 }
636
637 if (!m_owner->loadLink(type, as, media, builder.url()))
638 return;
639
640 if (m_disabledState != Disabled && m_owner->relAttribute().isStyleSheet() &&
641 styleSheetTypeIsSupported(type) && shouldLoadResource() &&
642 builder.url().isValid()) {
643 if (resource()) {
644 removePendingSheet();
645 clearResource();
646 clearFetchFollowingCORS();
647 }
648
649 if (!m_owner->shouldLoadLink())
650 return;
651
652 m_loading = true;
653
654 String title = m_owner->title();
655 if (!title.isEmpty() && !m_owner->isAlternate() &&
656 m_disabledState != EnabledViaScript && m_owner->isInDocumentTree())
657 document().styleEngine().setPreferredStylesheetSetNameIfNotSet(
658 title, StyleEngine::DontUpdateActiveSheets);
659
660 bool mediaQueryMatches = true;
661 LocalFrame* frame = loadingFrame();
662 if (!m_owner->media().isEmpty() && frame) {
663 MediaQuerySet* media = MediaQuerySet::create(m_owner->media());
664 MediaQueryEvaluator evaluator(frame);
665 mediaQueryMatches = evaluator.eval(media);
666 }
667
668 // Don't hold up layout tree construction and script execution on stylesheet s
669 // that are not needed for the layout at the moment.
670 bool blocking = mediaQueryMatches && !m_owner->isAlternate() &&
671 m_owner->isCreatedByParser();
672 addPendingSheet(blocking ? Blocking : NonBlocking);
673
674 // Load stylesheets that are not needed for the layout immediately with low priority.
675 // When the link element is created by scripts, load the stylesheets asynchr onously but in high priority.
676 bool lowPriority = !mediaQueryMatches || m_owner->isAlternate();
677 FetchRequest request = builder.build(lowPriority);
678 CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue(
679 m_owner->fastGetAttribute(HTMLNames::crossoriginAttr));
680 if (crossOrigin != CrossOriginAttributeNotSet) {
681 request.setCrossOriginAccessControl(document().getSecurityOrigin(),
682 crossOrigin);
683 setFetchFollowingCORS();
684 }
685
686 String integrityAttr = m_owner->fastGetAttribute(HTMLNames::integrityAttr);
687 if (!integrityAttr.isEmpty()) {
688 IntegrityMetadataSet metadataSet;
689 SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet);
690 request.setIntegrityMetadata(metadataSet);
691 }
692 setResource(CSSStyleSheetResource::fetch(request, document().fetcher()));
693
694 if (m_loading && !resource()) {
695 // The request may have been denied if (for example) the stylesheet is loc al and the document is remote, or if there was a Content Security Policy Failure .
696 // setCSSStyleSheet() can be called synchronuosly in setResource() and thu s resource() is null and |m_loading| is false in such cases even if the request succeeds.
697 m_loading = false;
698 removePendingSheet();
699 notifyLoadedSheetAndAllCriticalSubresources(
700 Node::ErrorOccurredLoadingSubresource);
701 }
702 } else if (m_sheet) {
703 // we no longer contain a stylesheet, e.g. perhaps rel or type was changed
704 StyleSheet* removedSheet = m_sheet.get();
705 clearSheet();
706 document().styleEngine().setNeedsActiveStyleUpdate(removedSheet,
707 FullStyleUpdate);
708 }
709 }
710
711 void LinkStyle::setSheetTitle(
712 const String& title,
713 StyleEngine::ActiveSheetsUpdate updateActiveSheets) {
714 if (!m_owner->isInDocumentTree() || !m_owner->relAttribute().isStyleSheet())
715 return;
716
717 if (m_sheet)
718 m_sheet->setTitle(title);
719
720 if (title.isEmpty() || !isUnset() || m_owner->isAlternate())
721 return;
722
723 KURL href = m_owner->getNonEmptyURLAttribute(hrefAttr);
724 if (href.isValid() && !href.isEmpty())
725 document().styleEngine().setPreferredStylesheetSetNameIfNotSet(
726 title, updateActiveSheets);
727 }
728
729 void LinkStyle::ownerRemoved() {
730 if (m_sheet)
731 clearSheet();
732
733 if (styleSheetIsLoading())
734 removePendingSheet();
735 }
736
737 DEFINE_TRACE(LinkStyle) { 360 DEFINE_TRACE(LinkStyle) {
738 visitor->trace(m_sheet); 361 visitor->trace(m_sheet);
739 LinkResource::trace(visitor); 362 LinkResource::trace(visitor);
740 ResourceOwner<StyleSheetResource>::trace(visitor); 363 ResourceOwner<StyleSheetResource>::trace(visitor);
741 } 364 }
742 365
743 } // namespace blink 366 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698