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/core/v8/ScriptEventListener.h"
29 #include "bindings/core/v8/V8DOMActivityLogger.h"
30 #include "core/HTMLNames.h"
31 #include "core/css/MediaList.h"
32 #include "core/css/MediaQueryEvaluator.h"
33 #include "core/css/StyleSheetContents.h"
34 #include "core/css/resolver/StyleResolver.h"
35 #include "core/dom/Attribute.h"
36 #include "core/dom/Document.h"
37 #include "core/dom/StyleEngine.h"
38 #include "core/events/Event.h"
39 #include "core/events/EventSender.h"
40 #include "core/fetch/CSSStyleSheetResource.h"
41 #include "core/fetch/FetchRequest.h"
42 #include "core/fetch/ResourceFetcher.h"
43 #include "core/frame/FrameView.h"
44 #include "core/frame/LocalFrame.h"
45 #include "core/frame/csp/ContentSecurityPolicy.h"
46 #include "core/html/LinkManifest.h"
47 #include "core/html/imports/LinkImport.h"
48 #include "core/loader/FrameLoader.h"
49 #include "core/loader/FrameLoaderClient.h"
50 #include "core/rendering/style/StyleInheritedData.h"
51 #include "platform/RuntimeEnabledFeatures.h"
52 #include "wtf/StdLibExtras.h"
53
54 namespace blink {
55
56 using namespace HTMLNames;
57
58 template <typename CharacterType>
parseSizes(const CharacterType * value,unsigned length,Vector<IntSize> & iconSizes)59 static void parseSizes(const CharacterType* value, unsigned length, Vector<IntSize>& iconSizes)
60 {
61 enum State {
62 ParseStart,
63 ParseWidth,
64 ParseHeight
65 };
66 int width = 0;
67 unsigned start = 0;
68 unsigned i = 0;
69 State state = ParseStart;
70 bool invalid = false;
71 for (; i < length; ++i) {
72 if (state == ParseWidth) {
73 if (value[i] == 'x' || value[i] == 'X') {
74 if (i == start) {
75 invalid = true;
76 break;
77 }
78 width = charactersToInt(value + start, i - start);
79 start = i + 1;
80 state = ParseHeight;
81 } else if (value[i] < '0' || value[i] > '9') {
82 invalid = true;
83 break;
84 }
85 } else if (state == ParseHeight) {
86 if (value[i] == ' ') {
87 if (i == start) {
88 invalid = true;
89 break;
90 }
91 int height = charactersToInt(value + start, i - start);
92 iconSizes.append(IntSize(width, height));
93 start = i + 1;
94 state = ParseStart;
95 } else if (value[i] < '0' || value[i] > '9') {
96 invalid = true;
97 break;
98 }
99 } else if (state == ParseStart) {
100 if (value[i] >= '0' && value[i] <= '9') {
101 start = i;
102 state = ParseWidth;
103 } else if (value[i] != ' ') {
104 invalid = true;
105 break;
106 }
107 }
108 }
109 if (invalid || state == ParseWidth || (state == ParseHeight && start == i)) {
110 iconSizes.clear();
111 return;
112 }
113 if (state == ParseHeight && i > start) {
114 int height = charactersToInt(value + start, i - start);
115 iconSizes.append(IntSize(width, height));
116 }
117 }
118
linkLoadEventSender()119 static LinkEventSender& linkLoadEventSender()
120 {
121 DEFINE_STATIC_LOCAL(LinkEventSender, sharedLoadEventSender, (EventTypeNames::load));
122 return sharedLoadEventSender;
123 }
124
parseSizesAttribute(const AtomicString & value,Vector<IntSize> & iconSizes)125 void HTMLLinkElement::parseSizesAttribute(const AtomicString& value, Vector<IntSize>& iconSizes)
126 {
127 ASSERT(iconSizes.isEmpty());
128 if (value.isEmpty())
129 return;
130 if (value.is8Bit())
131 parseSizes(value.characters8(), value.length(), iconSizes);
132 else
133 parseSizes(value.characters16(), value.length(), iconSizes);
134 }
135
HTMLLinkElement(Document & document,bool createdByParser)136 inline HTMLLinkElement::HTMLLinkElement(Document& document, bool createdByParser)
137 : HTMLElement(linkTag, document)
138 , m_linkLoader(this)
139 , m_sizes(DOMSettableTokenList::create())
140 , m_createdByParser(createdByParser)
141 , m_isInShadowTree(false)
142 {
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.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()) {
212 m_link = LinkImport::create(this);
213 } else if (m_relAttribute.isManifest()) {
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 if (insertionPoint->inDocument()) {
264 V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
265 if (activityLogger) {
266 Vector<String> argv;
267 argv.append("link");
268 argv.append(fastGetAttribute(relAttr));
269 argv.append(fastGetAttribute(hrefAttr));
270 activityLogger->logEvent("blinkAddElement", argv.size(), argv.data());
271 }
272 }
273 HTMLElement::insertedInto(insertionPoint);
274 if (!insertionPoint->inDocument())
275 return InsertionDone;
276
277 m_isInShadowTree = isInShadowTree();
278 if (m_isInShadowTree)
279 return InsertionDone;
280
281 document().styleEngine()->addStyleSheetCandidateNode(this, m_createdByParser);
282
283 process();
284
285 if (m_link)
286 m_link->ownerInserted();
287
288 return InsertionDone;
289 }
290
removedFrom(ContainerNode * insertionPoint)291 void HTMLLinkElement::removedFrom(ContainerNode* insertionPoint)
292 {
293 HTMLElement::removedFrom(insertionPoint);
294 if (!insertionPoint->inDocument())
295 return;
296
297 m_linkLoader.released();
298
299 if (m_isInShadowTree) {
300 ASSERT(!linkStyle() || !linkStyle()->hasSheet());
301 return;
302 }
303 document().styleEngine()->removeStyleSheetCandidateNode(this);
304
305 RefPtrWillBeRawPtr<StyleSheet> removedSheet = sheet();
306
307 if (m_link)
308 m_link->ownerRemoved();
309
310 document().removedStyleSheet(removedSheet.get());
311 }
312
finishParsingChildren()313 void HTMLLinkElement::finishParsingChildren()
314 {
315 m_createdByParser = false;
316 HTMLElement::finishParsingChildren();
317 }
318
styleSheetIsLoading() const319 bool HTMLLinkElement::styleSheetIsLoading() const
320 {
321 return linkStyle() && linkStyle()->styleSheetIsLoading();
322 }
323
linkLoaded()324 void HTMLLinkElement::linkLoaded()
325 {
326 dispatchEvent(Event::create(EventTypeNames::load));
327 }
328
linkLoadingErrored()329 void HTMLLinkElement::linkLoadingErrored()
330 {
331 dispatchEvent(Event::create(EventTypeNames::error));
332 }
333
didStartLinkPrerender()334 void HTMLLinkElement::didStartLinkPrerender()
335 {
336 dispatchEvent(Event::create(EventTypeNames::webkitprerenderstart));
337 }
338
didStopLinkPrerender()339 void HTMLLinkElement::didStopLinkPrerender()
340 {
341 dispatchEvent(Event::create(EventTypeNames::webkitprerenderstop));
342 }
343
didSendLoadForLinkPrerender()344 void HTMLLinkElement::didSendLoadForLinkPrerender()
345 {
346 dispatchEvent(Event::create(EventTypeNames::webkitprerenderload));
347 }
348
didSendDOMContentLoadedForLinkPrerender()349 void HTMLLinkElement::didSendDOMContentLoadedForLinkPrerender()
350 {
351 dispatchEvent(Event::create(EventTypeNames::webkitprerenderdomcontentloaded));
352 }
353
sheetLoaded()354 bool HTMLLinkElement::sheetLoaded()
355 {
356 ASSERT(linkStyle());
357 return linkStyle()->sheetLoaded();
358 }
359
notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)360 void HTMLLinkElement::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)
361 {
362 ASSERT(linkStyle());
363 linkStyle()->notifyLoadedSheetAndAllCriticalSubresources(errorOccurred);
364 }
365
dispatchPendingLoadEvents()366 void HTMLLinkElement::dispatchPendingLoadEvents()
367 {
368 linkLoadEventSender().dispatchPendingEvents();
369 }
370
dispatchPendingEvent(LinkEventSender * eventSender)371 void HTMLLinkElement::dispatchPendingEvent(LinkEventSender* eventSender)
372 {
373 ASSERT_UNUSED(eventSender, eventSender == &linkLoadEventSender());
374 ASSERT(m_link);
375 if (m_link->hasLoaded())
376 linkLoaded();
377 else
378 linkLoadingErrored();
379 }
380
scheduleEvent()381 void HTMLLinkElement::scheduleEvent()
382 {
383 linkLoadEventSender().dispatchEventSoon(this);
384 }
385
startLoadingDynamicSheet()386 void HTMLLinkElement::startLoadingDynamicSheet()
387 {
388 ASSERT(linkStyle());
389 linkStyle()->startLoadingDynamicSheet();
390 }
391
isURLAttribute(const Attribute & attribute) const392 bool HTMLLinkElement::isURLAttribute(const Attribute& attribute) const
393 {
394 return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute);
395 }
396
hasLegalLinkAttribute(const QualifiedName & name) const397 bool HTMLLinkElement::hasLegalLinkAttribute(const QualifiedName& name) const
398 {
399 return name == hrefAttr || HTMLElement::hasLegalLinkAttribute(name);
400 }
401
subResourceAttributeName() const402 const QualifiedName& HTMLLinkElement::subResourceAttributeName() const
403 {
404 // If the link element is not css, ignore it.
405 if (equalIgnoringCase(getAttribute(typeAttr), "text/css")) {
406 // FIXME: Add support for extracting links of sub-resources which
407 // are inside style-sheet such as @import, @font-face, url(), etc.
408 return hrefAttr;
409 }
410 return HTMLElement::subResourceAttributeName();
411 }
412
href() const413 KURL HTMLLinkElement::href() const
414 {
415 return document().completeURL(getAttribute(hrefAttr));
416 }
417
rel() const418 const AtomicString& HTMLLinkElement::rel() const
419 {
420 return getAttribute(relAttr);
421 }
422
type() const423 const AtomicString& HTMLLinkElement::type() const
424 {
425 return getAttribute(typeAttr);
426 }
427
async() const428 bool HTMLLinkElement::async() const
429 {
430 return fastHasAttribute(HTMLNames::asyncAttr);
431 }
432
iconType() const433 IconType HTMLLinkElement::iconType() const
434 {
435 return m_relAttribute.iconType();
436 }
437
iconSizes() const438 const Vector<IntSize>& HTMLLinkElement::iconSizes() const
439 {
440 return m_iconSizes;
441 }
442
sizes() const443 DOMSettableTokenList* HTMLLinkElement::sizes() const
444 {
445 return m_sizes.get();
446 }
447
trace(Visitor * visitor)448 void HTMLLinkElement::trace(Visitor* visitor)
449 {
450 visitor->trace(m_link);
451 visitor->trace(m_sizes);
452 HTMLElement::trace(visitor);
453 }
454
attributeWillChange(const QualifiedName & name,const AtomicString & oldValue,const AtomicString & newValue)455 void HTMLLinkElement::attributeWillChange(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
456 {
457 if (name == hrefAttr && inDocument()) {
458 V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
459 if (activityLogger) {
460 Vector<String> argv;
461 argv.append("link");
462 argv.append(hrefAttr.toString());
463 argv.append(oldValue);
464 argv.append(newValue);
465 activityLogger->logEvent("blinkSetAttribute", argv.size(), argv.data());
466 }
467 }
468 HTMLElement::attributeWillChange(name, oldValue, newValue);
469 }
470
create(HTMLLinkElement * owner)471 PassOwnPtrWillBeRawPtr<LinkStyle> LinkStyle::create(HTMLLinkElement* owner)
472 {
473 return adoptPtrWillBeNoop(new LinkStyle(owner));
474 }
475
LinkStyle(HTMLLinkElement * owner)476 LinkStyle::LinkStyle(HTMLLinkElement* owner)
477 : LinkResource(owner)
478 , m_disabledState(Unset)
479 , m_pendingSheetType(None)
480 , m_loading(false)
481 , m_firedLoad(false)
482 , m_loadedSheet(false)
483 {
484 }
485
~LinkStyle()486 LinkStyle::~LinkStyle()
487 {
488 #if !ENABLE(OILPAN)
489 if (m_sheet)
490 m_sheet->clearOwnerNode();
491 #endif
492 }
493
document()494 Document& LinkStyle::document()
495 {
496 return m_owner->document();
497 }
498
setCSSStyleSheet(const String & href,const KURL & baseURL,const String & charset,const CSSStyleSheetResource * cachedStyleSheet)499 void LinkStyle::setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CSSStyleSheetResource* cachedStyleSheet)
500 {
501 if (!m_owner->inDocument()) {
502 ASSERT(!m_sheet);
503 return;
504
505 }
506 // Completing the sheet load may cause scripts to execute.
507 RefPtrWillBeRawPtr<Node> protector(m_owner.get());
508
509 CSSParserContext parserContext(m_owner->document(), 0, baseURL, charset);
510
511 if (RefPtrWillBeRawPtr<StyleSheetContents> restoredSheet = const_cast<CSSStyleSheetResource*>(cachedStyleSheet)->restoreParsedStyleSheet(parserContext)) {
512 ASSERT(restoredSheet->isCacheable());
513 ASSERT(!restoredSheet->isLoading());
514
515 if (m_sheet)
516 clearSheet();
517 m_sheet = CSSStyleSheet::create(restoredSheet, m_owner);
518 m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media()));
519 m_sheet->setTitle(m_owner->title());
520
521 m_loading = false;
522 restoredSheet->checkLoaded();
523 return;
524 }
525
526 RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(href, parserContext);
527
528 if (m_sheet)
529 clearSheet();
530 m_sheet = CSSStyleSheet::create(styleSheet, m_owner);
531 m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media()));
532 m_sheet->setTitle(m_owner->title());
533
534 styleSheet->parseAuthorStyleSheet(cachedStyleSheet, m_owner->document().securityOrigin());
535
536 m_loading = false;
537 styleSheet->notifyLoadedSheet(cachedStyleSheet);
538 styleSheet->checkLoaded();
539
540 if (styleSheet->isCacheable())
541 const_cast<CSSStyleSheetResource*>(cachedStyleSheet)->saveParsedStyleSheet(styleSheet);
542 }
543
sheetLoaded()544 bool LinkStyle::sheetLoaded()
545 {
546 if (!styleSheetIsLoading()) {
547 removePendingSheet();
548 return true;
549 }
550 return false;
551 }
552
notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)553 void LinkStyle::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)
554 {
555 if (m_firedLoad)
556 return;
557 m_loadedSheet = !errorOccurred;
558 if (m_owner)
559 m_owner->scheduleEvent();
560 m_firedLoad = true;
561 }
562
startLoadingDynamicSheet()563 void LinkStyle::startLoadingDynamicSheet()
564 {
565 ASSERT(m_pendingSheetType < Blocking);
566 addPendingSheet(Blocking);
567 }
568
clearSheet()569 void LinkStyle::clearSheet()
570 {
571 ASSERT(m_sheet);
572 ASSERT(m_sheet->ownerNode() == m_owner);
573 m_sheet->clearOwnerNode();
574 m_sheet = nullptr;
575 }
576
styleSheetIsLoading() const577 bool LinkStyle::styleSheetIsLoading() const
578 {
579 if (m_loading)
580 return true;
581 if (!m_sheet)
582 return false;
583 return m_sheet->contents()->isLoading();
584 }
585
addPendingSheet(PendingSheetType type)586 void LinkStyle::addPendingSheet(PendingSheetType type)
587 {
588 if (type <= m_pendingSheetType)
589 return;
590 m_pendingSheetType = type;
591
592 if (m_pendingSheetType == NonBlocking)
593 return;
594 m_owner->document().styleEngine()->addPendingSheet();
595 }
596
removePendingSheet()597 void LinkStyle::removePendingSheet()
598 {
599 PendingSheetType type = m_pendingSheetType;
600 m_pendingSheetType = None;
601
602 if (type == None)
603 return;
604 if (type == NonBlocking) {
605 // Tell StyleEngine to re-compute styleSheets of this m_owner's treescope.
606 m_owner->document().styleEngine()->modifiedStyleSheetCandidateNode(m_owner);
607 // Document::removePendingSheet() triggers the style selector recalc for blocking sheets.
608 // FIXME: We don't have enough knowledge at this point to know if we're adding or removing a sheet
609 // so we can't call addedStyleSheet() or removedStyleSheet().
610 m_owner->document().styleResolverChanged();
611 return;
612 }
613
614 m_owner->document().styleEngine()->removePendingSheet(m_owner);
615 }
616
setDisabledState(bool disabled)617 void LinkStyle::setDisabledState(bool disabled)
618 {
619 LinkStyle::DisabledState oldDisabledState = m_disabledState;
620 m_disabledState = disabled ? Disabled : EnabledViaScript;
621 if (oldDisabledState != m_disabledState) {
622 // If we change the disabled state while the sheet is still loading, then we have to
623 // perform three checks:
624 if (styleSheetIsLoading()) {
625 // Check #1: The sheet becomes disabled while loading.
626 if (m_disabledState == Disabled)
627 removePendingSheet();
628
629 // Check #2: An alternate sheet becomes enabled while it is still loading.
630 if (m_owner->relAttribute().isAlternate() && m_disabledState == EnabledViaScript)
631 addPendingSheet(Blocking);
632
633 // Check #3: A main sheet becomes enabled while it was still loading and
634 // after it was disabled via script. It takes really terrible code to make this
635 // happen (a double toggle for no reason essentially). This happens on
636 // virtualplastic.net, which manages to do about 12 enable/disables on only 3
637 // sheets. :)
638 if (!m_owner->relAttribute().isAlternate() && m_disabledState == EnabledViaScript && oldDisabledState == Disabled)
639 addPendingSheet(Blocking);
640
641 // If the sheet is already loading just bail.
642 return;
643 }
644
645 if (m_sheet)
646 m_sheet->setDisabled(disabled);
647
648 // Load the sheet, since it's never been loaded before.
649 if (!m_sheet && m_disabledState == EnabledViaScript) {
650 if (m_owner->shouldProcessStyle())
651 process();
652 } else {
653 // FIXME: We don't have enough knowledge here to know if we should call addedStyleSheet() or removedStyleSheet().
654 m_owner->document().styleResolverChanged();
655 }
656 }
657 }
658
process()659 void LinkStyle::process()
660 {
661 ASSERT(m_owner->shouldProcessStyle());
662 String type = m_owner->typeValue().lower();
663 LinkRequestBuilder builder(m_owner);
664
665 if (m_owner->relAttribute().iconType() != InvalidIcon && builder.url().isValid() && !builder.url().isEmpty()) {
666 if (!m_owner->shouldLoadLink())
667 return;
668 if (!document().securityOrigin()->canDisplay(builder.url()))
669 return;
670 if (!document().contentSecurityPolicy()->allowImageFromSource(builder.url()))
671 return;
672 if (document().frame() && document().frame()->loader().client())
673 document().frame()->loader().client()->dispatchDidChangeIcons(m_owner->relAttribute().iconType());
674 }
675
676 if (!m_owner->loadLink(type, builder.url()))
677 return;
678
679 if ((m_disabledState != Disabled) && (m_owner->relAttribute().isStyleSheet() || m_owner->relAttribute().isTransitionExitingStylesheet())
680 && shouldLoadResource() && builder.url().isValid()) {
681
682 if (resource()) {
683 removePendingSheet();
684 clearResource();
685 }
686
687 if (!m_owner->shouldLoadLink())
688 return;
689
690 m_loading = true;
691
692 bool mediaQueryMatches = true;
693 LocalFrame* frame = loadingFrame();
694 if (!m_owner->media().isEmpty() && frame && frame->document()) {
695 RefPtr<RenderStyle> documentStyle = StyleResolver::styleForDocument(*frame->document());
696 RefPtrWillBeRawPtr<MediaQuerySet> media = MediaQuerySet::create(m_owner->media());
697 MediaQueryEvaluator evaluator(frame);
698 mediaQueryMatches = evaluator.eval(media.get());
699 }
700
701 // Don't hold up render tree construction and script execution on stylesheets
702 // that are not needed for the rendering at the moment.
703 bool blocking = mediaQueryMatches && !m_owner->isAlternate();
704 addPendingSheet(blocking ? Blocking : NonBlocking);
705
706 // Load stylesheets that are not needed for the rendering immediately with low priority.
707 FetchRequest request = builder.build(blocking);
708 AtomicString crossOriginMode = m_owner->fastGetAttribute(HTMLNames::crossoriginAttr);
709 if (!crossOriginMode.isNull())
710 request.setCrossOriginAccessControl(document().securityOrigin(), crossOriginMode);
711 setResource(document().fetcher()->fetchCSSStyleSheet(request));
712
713 if (!resource()) {
714 // The request may have been denied if (for example) the stylesheet is local and the document is remote.
715 m_loading = false;
716 removePendingSheet();
717 }
718 } else if (m_sheet) {
719 // we no longer contain a stylesheet, e.g. perhaps rel or type was changed
720 RefPtrWillBeRawPtr<StyleSheet> removedSheet = m_sheet.get();
721 clearSheet();
722 document().removedStyleSheet(removedSheet.get());
723 }
724 }
725
setSheetTitle(const String & title)726 void LinkStyle::setSheetTitle(const String& title)
727 {
728 if (m_sheet)
729 m_sheet->setTitle(title);
730 }
731
ownerRemoved()732 void LinkStyle::ownerRemoved()
733 {
734 if (m_sheet)
735 clearSheet();
736
737 if (styleSheetIsLoading())
738 removePendingSheet();
739 }
740
trace(Visitor * visitor)741 void LinkStyle::trace(Visitor* visitor)
742 {
743 visitor->trace(m_sheet);
744 LinkResource::trace(visitor);
745 }
746
747 } // namespace blink
748