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