• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
6  * Copyright (C) 2009 Rob Buis (rwlbuis@gmail.com)
7  * Copyright (C) 2011 Google Inc. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
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
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 #include "config.h"
26 #include "core/html/HTMLLinkElement.h"
27 
28 #include "bindings/v8/ScriptEventListener.h"
29 #include "core/HTMLNames.h"
30 #include "core/css/MediaList.h"
31 #include "core/css/MediaQueryEvaluator.h"
32 #include "core/css/StyleSheetContents.h"
33 #include "core/css/resolver/StyleResolver.h"
34 #include "core/dom/Attribute.h"
35 #include "core/dom/Document.h"
36 #include "core/dom/StyleEngine.h"
37 #include "core/events/Event.h"
38 #include "core/events/EventSender.h"
39 #include "core/fetch/CSSStyleSheetResource.h"
40 #include "core/fetch/FetchRequest.h"
41 #include "core/fetch/ResourceFetcher.h"
42 #include "core/frame/FrameView.h"
43 #include "core/frame/LocalFrame.h"
44 #include "core/frame/csp/ContentSecurityPolicy.h"
45 #include "core/html/LinkManifest.h"
46 #include "core/html/imports/LinkImport.h"
47 #include "core/loader/FrameLoader.h"
48 #include "core/loader/FrameLoaderClient.h"
49 #include "core/rendering/style/StyleInheritedData.h"
50 #include "platform/RuntimeEnabledFeatures.h"
51 #include "wtf/StdLibExtras.h"
52 
53 namespace WebCore {
54 
55 using namespace HTMLNames;
56 
57 template <typename CharacterType>
parseSizes(const CharacterType * value,unsigned length,Vector<IntSize> & iconSizes)58 static void parseSizes(const CharacterType* value, unsigned length, Vector<IntSize>& iconSizes)
59 {
60     enum State {
61         ParseStart,
62         ParseWidth,
63         ParseHeight
64     };
65     int width = 0;
66     unsigned start = 0;
67     unsigned i = 0;
68     State state = ParseStart;
69     bool invalid = false;
70     for (; i < length; ++i) {
71         if (state == ParseWidth) {
72             if (value[i] == 'x' || value[i] == 'X') {
73                 if (i == start) {
74                     invalid = true;
75                     break;
76                 }
77                 width = charactersToInt(value + start, i - start);
78                 start = i + 1;
79                 state = ParseHeight;
80             } else if (value[i] < '0' || value[i] > '9') {
81                 invalid = true;
82                 break;
83             }
84         } else if (state == ParseHeight) {
85             if (value[i] == ' ') {
86                 if (i == start) {
87                     invalid = true;
88                     break;
89                 }
90                 int height = charactersToInt(value + start, i - start);
91                 iconSizes.append(IntSize(width, height));
92                 start = i + 1;
93                 state = ParseStart;
94             } else if (value[i] < '0' || value[i] > '9') {
95                 invalid = true;
96                 break;
97             }
98         } else if (state == ParseStart) {
99             if (value[i] >= '0' && value[i] <= '9') {
100                 start = i;
101                 state = ParseWidth;
102             } else if (value[i] != ' ') {
103                 invalid = true;
104                 break;
105             }
106         }
107     }
108     if (invalid || state == ParseWidth || (state == ParseHeight && start == i)) {
109         iconSizes.clear();
110         return;
111     }
112     if (state == ParseHeight && i > start) {
113         int height = charactersToInt(value + start, i - start);
114         iconSizes.append(IntSize(width, height));
115     }
116 }
117 
linkLoadEventSender()118 static LinkEventSender& linkLoadEventSender()
119 {
120     DEFINE_STATIC_LOCAL(LinkEventSender, sharedLoadEventSender, (EventTypeNames::load));
121     return sharedLoadEventSender;
122 }
123 
parseSizesAttribute(const AtomicString & value,Vector<IntSize> & iconSizes)124 void HTMLLinkElement::parseSizesAttribute(const AtomicString& value, Vector<IntSize>& iconSizes)
125 {
126     ASSERT(iconSizes.isEmpty());
127     if (value.isEmpty())
128         return;
129     if (value.is8Bit())
130         parseSizes(value.characters8(), value.length(), iconSizes);
131     else
132         parseSizes(value.characters16(), value.length(), iconSizes);
133 }
134 
HTMLLinkElement(Document & document,bool createdByParser)135 inline HTMLLinkElement::HTMLLinkElement(Document& document, bool createdByParser)
136     : HTMLElement(linkTag, document)
137     , m_linkLoader(this)
138     , m_sizes(DOMSettableTokenList::create())
139     , m_createdByParser(createdByParser)
140     , m_isInShadowTree(false)
141 {
142     ScriptWrappable::init(this);
143 }
144 
create(Document & document,bool createdByParser)145 PassRefPtrWillBeRawPtr<HTMLLinkElement> HTMLLinkElement::create(Document& document, bool createdByParser)
146 {
147     return adoptRefWillBeNoop(new HTMLLinkElement(document, createdByParser));
148 }
149 
~HTMLLinkElement()150 HTMLLinkElement::~HTMLLinkElement()
151 {
152 #if !ENABLE(OILPAN)
153     m_link.clear();
154 
155     if (inDocument())
156         document().styleEngine()->removeStyleSheetCandidateNode(this);
157 #endif
158 
159     linkLoadEventSender().cancelEvent(this);
160 }
161 
parseAttribute(const QualifiedName & name,const AtomicString & value)162 void HTMLLinkElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
163 {
164     if (name == relAttr) {
165         m_relAttribute = LinkRelAttribute(value);
166         process();
167     } else if (name == hrefAttr) {
168         process();
169     } else if (name == typeAttr) {
170         m_type = value;
171         process();
172     } else if (name == sizesAttr) {
173         m_sizes->setValue(value);
174         parseSizesAttribute(value, m_iconSizes);
175         process();
176     } else if (name == mediaAttr) {
177         m_media = value.string().lower();
178         process();
179     } else if (name == disabledAttr) {
180         if (LinkStyle* link = linkStyle())
181             link->setDisabledState(!value.isNull());
182     } else {
183         if (name == titleAttr) {
184             if (LinkStyle* link = linkStyle())
185                 link->setSheetTitle(value);
186         }
187 
188         HTMLElement::parseAttribute(name, value);
189     }
190 }
191 
shouldLoadLink()192 bool HTMLLinkElement::shouldLoadLink()
193 {
194     return inDocument();
195 }
196 
loadLink(const String & type,const KURL & url)197 bool HTMLLinkElement::loadLink(const String& type, const KURL& url)
198 {
199     return m_linkLoader.loadLink(m_relAttribute, fastGetAttribute(HTMLNames::crossoriginAttr), type, url, document());
200 }
201 
linkResourceToProcess()202 LinkResource* HTMLLinkElement::linkResourceToProcess()
203 {
204     bool visible = inDocument() && !m_isInShadowTree;
205     if (!visible) {
206         ASSERT(!linkStyle() || !linkStyle()->hasSheet());
207         return 0;
208     }
209 
210     if (!m_link) {
211         if (m_relAttribute.isImport() && RuntimeEnabledFeatures::htmlImportsEnabled()) {
212             m_link = LinkImport::create(this);
213         } else if (m_relAttribute.isManifest() && RuntimeEnabledFeatures::manifestEnabled()) {
214             m_link = LinkManifest::create(this);
215         } else {
216             OwnPtrWillBeRawPtr<LinkStyle> link = LinkStyle::create(this);
217             if (fastHasAttribute(disabledAttr) || m_relAttribute.isTransitionExitingStylesheet())
218                 link->setDisabledState(true);
219             m_link = link.release();
220         }
221     }
222 
223     return m_link.get();
224 }
225 
linkStyle() const226 LinkStyle* HTMLLinkElement::linkStyle() const
227 {
228     if (!m_link || m_link->type() != LinkResource::Style)
229         return 0;
230     return static_cast<LinkStyle*>(m_link.get());
231 }
232 
linkImport() const233 LinkImport* HTMLLinkElement::linkImport() const
234 {
235     if (!m_link || m_link->type() != LinkResource::Import)
236         return 0;
237     return static_cast<LinkImport*>(m_link.get());
238 }
239 
import() const240 Document* HTMLLinkElement::import() const
241 {
242     if (LinkImport* link = linkImport())
243         return link->importedDocument();
244     return 0;
245 }
246 
process()247 void HTMLLinkElement::process()
248 {
249     if (LinkResource* link = linkResourceToProcess())
250         link->process();
251 }
252 
enableIfExitTransitionStyle()253 void HTMLLinkElement::enableIfExitTransitionStyle()
254 {
255     if (m_relAttribute.isTransitionExitingStylesheet()) {
256         if (LinkStyle* link = linkStyle())
257             link->setDisabledState(false);
258     }
259 }
260 
insertedInto(ContainerNode * insertionPoint)261 Node::InsertionNotificationRequest HTMLLinkElement::insertedInto(ContainerNode* insertionPoint)
262 {
263     HTMLElement::insertedInto(insertionPoint);
264     if (!insertionPoint->inDocument())
265         return InsertionDone;
266 
267     m_isInShadowTree = isInShadowTree();
268     if (m_isInShadowTree)
269         return InsertionDone;
270 
271     document().styleEngine()->addStyleSheetCandidateNode(this, m_createdByParser);
272 
273     process();
274 
275     if (m_link)
276         m_link->ownerInserted();
277 
278     return InsertionDone;
279 }
280 
removedFrom(ContainerNode * insertionPoint)281 void HTMLLinkElement::removedFrom(ContainerNode* insertionPoint)
282 {
283     HTMLElement::removedFrom(insertionPoint);
284     if (!insertionPoint->inDocument())
285         return;
286 
287     m_linkLoader.released();
288 
289     if (m_isInShadowTree) {
290         ASSERT(!linkStyle() || !linkStyle()->hasSheet());
291         return;
292     }
293     document().styleEngine()->removeStyleSheetCandidateNode(this);
294 
295     RefPtrWillBeRawPtr<StyleSheet> removedSheet = sheet();
296 
297     if (m_link)
298         m_link->ownerRemoved();
299 
300     document().removedStyleSheet(removedSheet.get());
301 }
302 
finishParsingChildren()303 void HTMLLinkElement::finishParsingChildren()
304 {
305     m_createdByParser = false;
306     HTMLElement::finishParsingChildren();
307 }
308 
styleSheetIsLoading() const309 bool HTMLLinkElement::styleSheetIsLoading() const
310 {
311     return linkStyle() && linkStyle()->styleSheetIsLoading();
312 }
313 
linkLoaded()314 void HTMLLinkElement::linkLoaded()
315 {
316     dispatchEvent(Event::create(EventTypeNames::load));
317 }
318 
linkLoadingErrored()319 void HTMLLinkElement::linkLoadingErrored()
320 {
321     dispatchEvent(Event::create(EventTypeNames::error));
322 }
323 
didStartLinkPrerender()324 void HTMLLinkElement::didStartLinkPrerender()
325 {
326     dispatchEvent(Event::create(EventTypeNames::webkitprerenderstart));
327 }
328 
didStopLinkPrerender()329 void HTMLLinkElement::didStopLinkPrerender()
330 {
331     dispatchEvent(Event::create(EventTypeNames::webkitprerenderstop));
332 }
333 
didSendLoadForLinkPrerender()334 void HTMLLinkElement::didSendLoadForLinkPrerender()
335 {
336     dispatchEvent(Event::create(EventTypeNames::webkitprerenderload));
337 }
338 
didSendDOMContentLoadedForLinkPrerender()339 void HTMLLinkElement::didSendDOMContentLoadedForLinkPrerender()
340 {
341     dispatchEvent(Event::create(EventTypeNames::webkitprerenderdomcontentloaded));
342 }
343 
sheetLoaded()344 bool HTMLLinkElement::sheetLoaded()
345 {
346     ASSERT(linkStyle());
347     return linkStyle()->sheetLoaded();
348 }
349 
notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)350 void HTMLLinkElement::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)
351 {
352     ASSERT(linkStyle());
353     linkStyle()->notifyLoadedSheetAndAllCriticalSubresources(errorOccurred);
354 }
355 
dispatchPendingLoadEvents()356 void HTMLLinkElement::dispatchPendingLoadEvents()
357 {
358     linkLoadEventSender().dispatchPendingEvents();
359 }
360 
dispatchPendingEvent(LinkEventSender * eventSender)361 void HTMLLinkElement::dispatchPendingEvent(LinkEventSender* eventSender)
362 {
363     ASSERT_UNUSED(eventSender, eventSender == &linkLoadEventSender());
364     ASSERT(m_link);
365     if (m_link->hasLoaded())
366         linkLoaded();
367     else
368         linkLoadingErrored();
369 }
370 
scheduleEvent()371 void HTMLLinkElement::scheduleEvent()
372 {
373     linkLoadEventSender().dispatchEventSoon(this);
374 }
375 
startLoadingDynamicSheet()376 void HTMLLinkElement::startLoadingDynamicSheet()
377 {
378     ASSERT(linkStyle());
379     linkStyle()->startLoadingDynamicSheet();
380 }
381 
isURLAttribute(const Attribute & attribute) const382 bool HTMLLinkElement::isURLAttribute(const Attribute& attribute) const
383 {
384     return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute);
385 }
386 
hasLegalLinkAttribute(const QualifiedName & name) const387 bool HTMLLinkElement::hasLegalLinkAttribute(const QualifiedName& name) const
388 {
389     return name == hrefAttr || HTMLElement::hasLegalLinkAttribute(name);
390 }
391 
subResourceAttributeName() const392 const QualifiedName& HTMLLinkElement::subResourceAttributeName() const
393 {
394     // If the link element is not css, ignore it.
395     if (equalIgnoringCase(getAttribute(typeAttr), "text/css")) {
396         // FIXME: Add support for extracting links of sub-resources which
397         // are inside style-sheet such as @import, @font-face, url(), etc.
398         return hrefAttr;
399     }
400     return HTMLElement::subResourceAttributeName();
401 }
402 
href() const403 KURL HTMLLinkElement::href() const
404 {
405     return document().completeURL(getAttribute(hrefAttr));
406 }
407 
rel() const408 const AtomicString& HTMLLinkElement::rel() const
409 {
410     return getAttribute(relAttr);
411 }
412 
type() const413 const AtomicString& HTMLLinkElement::type() const
414 {
415     return getAttribute(typeAttr);
416 }
417 
async() const418 bool HTMLLinkElement::async() const
419 {
420     return fastHasAttribute(HTMLNames::asyncAttr);
421 }
422 
iconType() const423 IconType HTMLLinkElement::iconType() const
424 {
425     return m_relAttribute.iconType();
426 }
427 
iconSizes() const428 const Vector<IntSize>& HTMLLinkElement::iconSizes() const
429 {
430     return m_iconSizes;
431 }
432 
sizes() const433 DOMSettableTokenList* HTMLLinkElement::sizes() const
434 {
435     return m_sizes.get();
436 }
437 
trace(Visitor * visitor)438 void HTMLLinkElement::trace(Visitor* visitor)
439 {
440     visitor->trace(m_link);
441     visitor->trace(m_sizes);
442     HTMLElement::trace(visitor);
443 }
444 
create(HTMLLinkElement * owner)445 PassOwnPtrWillBeRawPtr<LinkStyle> LinkStyle::create(HTMLLinkElement* owner)
446 {
447     return adoptPtrWillBeNoop(new LinkStyle(owner));
448 }
449 
LinkStyle(HTMLLinkElement * owner)450 LinkStyle::LinkStyle(HTMLLinkElement* owner)
451     : LinkResource(owner)
452     , m_disabledState(Unset)
453     , m_pendingSheetType(None)
454     , m_loading(false)
455     , m_firedLoad(false)
456     , m_loadedSheet(false)
457 {
458 }
459 
~LinkStyle()460 LinkStyle::~LinkStyle()
461 {
462 #if !ENABLE(OILPAN)
463     if (m_sheet)
464         m_sheet->clearOwnerNode();
465 #endif
466 }
467 
document()468 Document& LinkStyle::document()
469 {
470     return m_owner->document();
471 }
472 
setCSSStyleSheet(const String & href,const KURL & baseURL,const String & charset,const CSSStyleSheetResource * cachedStyleSheet)473 void LinkStyle::setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CSSStyleSheetResource* cachedStyleSheet)
474 {
475     if (!m_owner->inDocument()) {
476         ASSERT(!m_sheet);
477         return;
478 
479     }
480     // Completing the sheet load may cause scripts to execute.
481     RefPtrWillBeRawPtr<Node> protector(m_owner.get());
482 
483     CSSParserContext parserContext(m_owner->document(), 0, baseURL, charset);
484 
485     if (RefPtrWillBeRawPtr<StyleSheetContents> restoredSheet = const_cast<CSSStyleSheetResource*>(cachedStyleSheet)->restoreParsedStyleSheet(parserContext)) {
486         ASSERT(restoredSheet->isCacheable());
487         ASSERT(!restoredSheet->isLoading());
488 
489         if (m_sheet)
490             clearSheet();
491         m_sheet = CSSStyleSheet::create(restoredSheet, m_owner);
492         m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media()));
493         m_sheet->setTitle(m_owner->title());
494 
495         m_loading = false;
496         restoredSheet->checkLoaded();
497         return;
498     }
499 
500     RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(href, parserContext);
501 
502     if (m_sheet)
503         clearSheet();
504     m_sheet = CSSStyleSheet::create(styleSheet, m_owner);
505     m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media()));
506     m_sheet->setTitle(m_owner->title());
507 
508     styleSheet->parseAuthorStyleSheet(cachedStyleSheet, m_owner->document().securityOrigin());
509 
510     m_loading = false;
511     styleSheet->notifyLoadedSheet(cachedStyleSheet);
512     styleSheet->checkLoaded();
513 
514     if (styleSheet->isCacheable())
515         const_cast<CSSStyleSheetResource*>(cachedStyleSheet)->saveParsedStyleSheet(styleSheet);
516 }
517 
sheetLoaded()518 bool LinkStyle::sheetLoaded()
519 {
520     if (!styleSheetIsLoading()) {
521         removePendingSheet();
522         return true;
523     }
524     return false;
525 }
526 
notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)527 void LinkStyle::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)
528 {
529     if (m_firedLoad)
530         return;
531     m_loadedSheet = !errorOccurred;
532     if (m_owner)
533         m_owner->scheduleEvent();
534     m_firedLoad = true;
535 }
536 
startLoadingDynamicSheet()537 void LinkStyle::startLoadingDynamicSheet()
538 {
539     ASSERT(m_pendingSheetType < Blocking);
540     addPendingSheet(Blocking);
541 }
542 
clearSheet()543 void LinkStyle::clearSheet()
544 {
545     ASSERT(m_sheet);
546     ASSERT(m_sheet->ownerNode() == m_owner);
547     m_sheet->clearOwnerNode();
548     m_sheet = nullptr;
549 }
550 
styleSheetIsLoading() const551 bool LinkStyle::styleSheetIsLoading() const
552 {
553     if (m_loading)
554         return true;
555     if (!m_sheet)
556         return false;
557     return m_sheet->contents()->isLoading();
558 }
559 
addPendingSheet(PendingSheetType type)560 void LinkStyle::addPendingSheet(PendingSheetType type)
561 {
562     if (type <= m_pendingSheetType)
563         return;
564     m_pendingSheetType = type;
565 
566     if (m_pendingSheetType == NonBlocking)
567         return;
568     m_owner->document().styleEngine()->addPendingSheet();
569 }
570 
removePendingSheet()571 void LinkStyle::removePendingSheet()
572 {
573     PendingSheetType type = m_pendingSheetType;
574     m_pendingSheetType = None;
575 
576     if (type == None)
577         return;
578     if (type == NonBlocking) {
579         // Tell StyleEngine to re-compute styleSheets of this m_owner's treescope.
580         m_owner->document().styleEngine()->modifiedStyleSheetCandidateNode(m_owner);
581         // Document::removePendingSheet() triggers the style selector recalc for blocking sheets.
582         // FIXME: We don't have enough knowledge at this point to know if we're adding or removing a sheet
583         // so we can't call addedStyleSheet() or removedStyleSheet().
584         m_owner->document().styleResolverChanged();
585         return;
586     }
587 
588     m_owner->document().styleEngine()->removePendingSheet(m_owner);
589 }
590 
setDisabledState(bool disabled)591 void LinkStyle::setDisabledState(bool disabled)
592 {
593     LinkStyle::DisabledState oldDisabledState = m_disabledState;
594     m_disabledState = disabled ? Disabled : EnabledViaScript;
595     if (oldDisabledState != m_disabledState) {
596         // If we change the disabled state while the sheet is still loading, then we have to
597         // perform three checks:
598         if (styleSheetIsLoading()) {
599             // Check #1: The sheet becomes disabled while loading.
600             if (m_disabledState == Disabled)
601                 removePendingSheet();
602 
603             // Check #2: An alternate sheet becomes enabled while it is still loading.
604             if (m_owner->relAttribute().isAlternate() && m_disabledState == EnabledViaScript)
605                 addPendingSheet(Blocking);
606 
607             // Check #3: A main sheet becomes enabled while it was still loading and
608             // after it was disabled via script. It takes really terrible code to make this
609             // happen (a double toggle for no reason essentially). This happens on
610             // virtualplastic.net, which manages to do about 12 enable/disables on only 3
611             // sheets. :)
612             if (!m_owner->relAttribute().isAlternate() && m_disabledState == EnabledViaScript && oldDisabledState == Disabled)
613                 addPendingSheet(Blocking);
614 
615             // If the sheet is already loading just bail.
616             return;
617         }
618 
619         if (m_sheet)
620             m_sheet->setDisabled(disabled);
621 
622         // Load the sheet, since it's never been loaded before.
623         if (!m_sheet && m_disabledState == EnabledViaScript) {
624             if (m_owner->shouldProcessStyle())
625                 process();
626         } else {
627             // FIXME: We don't have enough knowledge here to know if we should call addedStyleSheet() or removedStyleSheet().
628             m_owner->document().styleResolverChanged();
629         }
630     }
631 }
632 
process()633 void LinkStyle::process()
634 {
635     ASSERT(m_owner->shouldProcessStyle());
636     String type = m_owner->typeValue().lower();
637     LinkRequestBuilder builder(m_owner);
638 
639     if (m_owner->relAttribute().iconType() != InvalidIcon && builder.url().isValid() && !builder.url().isEmpty()) {
640         if (!m_owner->shouldLoadLink())
641             return;
642         if (!document().securityOrigin()->canDisplay(builder.url()))
643             return;
644         if (!document().contentSecurityPolicy()->allowImageFromSource(builder.url()))
645             return;
646         if (document().frame() && document().frame()->loader().client())
647             document().frame()->loader().client()->dispatchDidChangeIcons(m_owner->relAttribute().iconType());
648     }
649 
650     if (!m_owner->loadLink(type, builder.url()))
651         return;
652 
653     if ((m_disabledState != Disabled) && (m_owner->relAttribute().isStyleSheet() || m_owner->relAttribute().isTransitionExitingStylesheet())
654         && shouldLoadResource() && builder.url().isValid()) {
655 
656         if (resource()) {
657             removePendingSheet();
658             clearResource();
659         }
660 
661         if (!m_owner->shouldLoadLink())
662             return;
663 
664         m_loading = true;
665 
666         bool mediaQueryMatches = true;
667         if (!m_owner->media().isEmpty()) {
668             LocalFrame* frame = loadingFrame();
669             if (Document* document = loadingFrame()->document()) {
670                 RefPtr<RenderStyle> documentStyle = StyleResolver::styleForDocument(*document);
671                 RefPtrWillBeRawPtr<MediaQuerySet> media = MediaQuerySet::create(m_owner->media());
672                 MediaQueryEvaluator evaluator(frame->view()->mediaType(), frame);
673                 mediaQueryMatches = evaluator.eval(media.get());
674             }
675         }
676 
677         // Don't hold up render tree construction and script execution on stylesheets
678         // that are not needed for the rendering at the moment.
679         bool blocking = mediaQueryMatches && !m_owner->isAlternate();
680         addPendingSheet(blocking ? Blocking : NonBlocking);
681 
682         // Load stylesheets that are not needed for the rendering immediately with low priority.
683         FetchRequest request = builder.build(blocking);
684         AtomicString crossOriginMode = m_owner->fastGetAttribute(HTMLNames::crossoriginAttr);
685         if (!crossOriginMode.isNull())
686             request.setCrossOriginAccessControl(document().securityOrigin(), crossOriginMode);
687         setResource(document().fetcher()->fetchCSSStyleSheet(request));
688 
689         if (!resource()) {
690             // The request may have been denied if (for example) the stylesheet is local and the document is remote.
691             m_loading = false;
692             removePendingSheet();
693         }
694     } else if (m_sheet) {
695         // we no longer contain a stylesheet, e.g. perhaps rel or type was changed
696         RefPtrWillBeRawPtr<StyleSheet> removedSheet = m_sheet.get();
697         clearSheet();
698         document().removedStyleSheet(removedSheet.get());
699     }
700 }
701 
setSheetTitle(const String & title)702 void LinkStyle::setSheetTitle(const String& title)
703 {
704     if (m_sheet)
705         m_sheet->setTitle(title);
706 }
707 
ownerRemoved()708 void LinkStyle::ownerRemoved()
709 {
710     if (m_sheet)
711         clearSheet();
712 
713     if (styleSheetIsLoading())
714         removePendingSheet();
715 }
716 
trace(Visitor * visitor)717 void LinkStyle::trace(Visitor* visitor)
718 {
719     visitor->trace(m_sheet);
720     LinkResource::trace(visitor);
721 }
722 
723 } // namespace WebCore
724