[GStreamer] TextCombinerGStreamer is failing to compile with Gst1.14
[WebKit-https.git] / Source / WebCore / html / HTMLLinkElement.cpp
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-2017 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 "HTMLLinkElement.h"
27
28 #include "Attribute.h"
29 #include "CachedCSSStyleSheet.h"
30 #include "CachedResource.h"
31 #include "CachedResourceLoader.h"
32 #include "CachedResourceRequest.h"
33 #include "ContentSecurityPolicy.h"
34 #include "CrossOriginAccessControl.h"
35 #include "DOMTokenList.h"
36 #include "Document.h"
37 #include "Event.h"
38 #include "EventNames.h"
39 #include "EventSender.h"
40 #include "Frame.h"
41 #include "FrameLoader.h"
42 #include "FrameLoaderClient.h"
43 #include "FrameTree.h"
44 #include "FrameView.h"
45 #include "HTMLAnchorElement.h"
46 #include "HTMLNames.h"
47 #include "HTMLParserIdioms.h"
48 #include "Logging.h"
49 #include "MediaList.h"
50 #include "MediaQueryEvaluator.h"
51 #include "MediaQueryParser.h"
52 #include "MouseEvent.h"
53 #include "ParsedContentType.h"
54 #include "RenderStyle.h"
55 #include "RuntimeEnabledFeatures.h"
56 #include "SecurityOrigin.h"
57 #include "Settings.h"
58 #include "StyleInheritedData.h"
59 #include "StyleResolveForDocument.h"
60 #include "StyleScope.h"
61 #include "StyleSheetContents.h"
62 #include "SubresourceIntegrity.h"
63 #include <wtf/IsoMallocInlines.h>
64 #include <wtf/Ref.h>
65 #include <wtf/Scope.h>
66 #include <wtf/StdLibExtras.h>
67
68 namespace WebCore {
69
70 WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLLinkElement);
71
72 using namespace HTMLNames;
73
74 static LinkEventSender& linkLoadEventSender()
75 {
76     static NeverDestroyed<LinkEventSender> sharedLoadEventSender(eventNames().loadEvent);
77     return sharedLoadEventSender;
78 }
79
80 static LinkEventSender& linkErrorEventSender()
81 {
82     static NeverDestroyed<LinkEventSender> sharedErrorEventSender(eventNames().errorEvent);
83     return sharedErrorEventSender;
84 }
85
86 inline HTMLLinkElement::HTMLLinkElement(const QualifiedName& tagName, Document& document, bool createdByParser)
87     : HTMLElement(tagName, document)
88     , m_linkLoader(*this)
89     , m_disabledState(Unset)
90     , m_loading(false)
91     , m_createdByParser(createdByParser)
92     , m_firedLoad(false)
93     , m_loadedResource(false)
94     , m_isHandlingBeforeLoad(false)
95     , m_allowPrefetchLoadAndErrorForTesting(false)
96     , m_pendingSheetType(Unknown)
97 {
98     ASSERT(hasTagName(linkTag));
99 }
100
101 Ref<HTMLLinkElement> HTMLLinkElement::create(const QualifiedName& tagName, Document& document, bool createdByParser)
102 {
103     return adoptRef(*new HTMLLinkElement(tagName, document, createdByParser));
104 }
105
106 HTMLLinkElement::~HTMLLinkElement()
107 {
108     if (m_sheet)
109         m_sheet->clearOwnerNode();
110
111     if (m_cachedSheet)
112         m_cachedSheet->removeClient(*this);
113
114     if (m_styleScope)
115         m_styleScope->removeStyleSheetCandidateNode(*this);
116
117     linkLoadEventSender().cancelEvent(*this);
118     linkErrorEventSender().cancelEvent(*this);
119 }
120
121 void HTMLLinkElement::setDisabledState(bool disabled)
122 {
123     DisabledState oldDisabledState = m_disabledState;
124     m_disabledState = disabled ? Disabled : EnabledViaScript;
125     if (oldDisabledState == m_disabledState)
126         return;
127
128     ASSERT(isConnected() || !styleSheetIsLoading());
129     if (!isConnected())
130         return;
131
132     // If we change the disabled state while the sheet is still loading, then we have to
133     // perform three checks:
134     if (styleSheetIsLoading()) {
135         // Check #1: The sheet becomes disabled while loading.
136         if (m_disabledState == Disabled)
137             removePendingSheet();
138
139         // Check #2: An alternate sheet becomes enabled while it is still loading.
140         if (m_relAttribute.isAlternate && m_disabledState == EnabledViaScript)
141             addPendingSheet(ActiveSheet);
142
143         // Check #3: A main sheet becomes enabled while it was still loading and
144         // after it was disabled via script. It takes really terrible code to make this
145         // happen (a double toggle for no reason essentially). This happens on
146         // virtualplastic.net, which manages to do about 12 enable/disables on only 3
147         // sheets. :)
148         if (!m_relAttribute.isAlternate && m_disabledState == EnabledViaScript && oldDisabledState == Disabled)
149             addPendingSheet(ActiveSheet);
150
151         // If the sheet is already loading just bail.
152         return;
153     }
154
155     // Load the sheet, since it's never been loaded before.
156     if (!m_sheet && m_disabledState == EnabledViaScript)
157         process();
158     else {
159         ASSERT(m_styleScope);
160         m_styleScope->didChangeActiveStyleSheetCandidates();
161     }
162 }
163
164 void HTMLLinkElement::parseAttribute(const QualifiedName& name, const AtomString& value)
165 {
166     if (name == relAttr) {
167         m_relAttribute = LinkRelAttribute(document(), value);
168         if (m_relList)
169             m_relList->associatedAttributeValueChanged(value);
170         process();
171         return;
172     }
173     if (name == hrefAttr) {
174         bool wasLink = isLink();
175         setIsLink(!value.isNull() && !shouldProhibitLinks(this));
176         if (wasLink != isLink())
177             invalidateStyleForSubtree();
178         process();
179         return;
180     }
181     if (name == typeAttr) {
182         m_type = value;
183         process();
184         return;
185     }
186     if (name == sizesAttr) {
187         if (m_sizes)
188             m_sizes->associatedAttributeValueChanged(value);
189         process();
190         return;
191     }
192     if (name == mediaAttr) {
193         m_media = value.string().convertToASCIILowercase();
194         process();
195         if (m_sheet && !isDisabled())
196             m_styleScope->didChangeActiveStyleSheetCandidates();
197         return;
198     }
199     if (name == disabledAttr) {
200         setDisabledState(!value.isNull());
201         return;
202     }
203     if (name == titleAttr) {
204         if (m_sheet && !isInShadowTree())
205             m_sheet->setTitle(value);
206         return;
207     }
208     HTMLElement::parseAttribute(name, value);
209 }
210
211 bool HTMLLinkElement::shouldLoadLink()
212 {
213     Ref<Document> originalDocument = document();
214     if (!dispatchBeforeLoadEvent(getNonEmptyURLAttribute(hrefAttr)))
215         return false;
216     // A beforeload handler might have removed us from the document or changed the document.
217     if (!isConnected() || &document() != originalDocument.ptr())
218         return false;
219     return true;
220 }
221
222 void HTMLLinkElement::setCrossOrigin(const AtomString& value)
223 {
224     setAttributeWithoutSynchronization(crossoriginAttr, value);
225 }
226
227 String HTMLLinkElement::crossOrigin() const
228 {
229     return parseCORSSettingsAttribute(attributeWithoutSynchronization(crossoriginAttr));
230 }
231
232 void HTMLLinkElement::setAs(const AtomString& value)
233 {
234     setAttributeWithoutSynchronization(asAttr, value);
235 }
236
237 String HTMLLinkElement::as() const
238 {
239     String as = attributeWithoutSynchronization(asAttr);
240     if (equalLettersIgnoringASCIICase(as, "fetch")
241         || equalLettersIgnoringASCIICase(as, "image")
242         || equalLettersIgnoringASCIICase(as, "script")
243         || equalLettersIgnoringASCIICase(as, "style")
244         || (RuntimeEnabledFeatures::sharedFeatures().mediaPreloadingEnabled()
245             && (equalLettersIgnoringASCIICase(as, "video")
246                 || equalLettersIgnoringASCIICase(as, "audio")))
247 #if ENABLE(VIDEO_TRACK)
248         || equalLettersIgnoringASCIICase(as, "track")
249 #endif
250         || equalLettersIgnoringASCIICase(as, "font"))
251         return as.convertToASCIILowercase();
252     return String();
253 }
254
255 void HTMLLinkElement::process()
256 {
257     if (!isConnected()) {
258         ASSERT(!m_sheet);
259         return;
260     }
261
262     // Prevent recursive loading of link.
263     if (m_isHandlingBeforeLoad)
264         return;
265
266     URL url = getNonEmptyURLAttribute(hrefAttr);
267
268     LinkLoadParameters params {
269         m_relAttribute,
270         url,
271         attributeWithoutSynchronization(asAttr),
272         attributeWithoutSynchronization(mediaAttr),
273         attributeWithoutSynchronization(typeAttr),
274         attributeWithoutSynchronization(crossoriginAttr),
275         attributeWithoutSynchronization(imagesrcsetAttr),
276         attributeWithoutSynchronization(imagesizesAttr)
277     };
278
279     m_linkLoader.loadLink(params, document());
280
281     bool treatAsStyleSheet = false;
282     if (m_relAttribute.isStyleSheet) {
283         if (m_type.isNull())
284             treatAsStyleSheet = true;
285         else if (auto parsedContentType = ParsedContentType::create(m_type))
286             treatAsStyleSheet = equalLettersIgnoringASCIICase(parsedContentType->mimeType(), "text/css");
287     }
288     if (!treatAsStyleSheet)
289         treatAsStyleSheet = document().settings().treatsAnyTextCSSLinkAsStylesheet() && m_type.containsIgnoringASCIICase("text/css");
290
291     if (m_disabledState != Disabled && treatAsStyleSheet && document().frame() && url.isValid()) {
292         String charset = attributeWithoutSynchronization(charsetAttr);
293         if (charset.isEmpty())
294             charset = document().charset();
295
296         if (m_cachedSheet) {
297             removePendingSheet();
298             m_cachedSheet->removeClient(*this);
299             m_cachedSheet = nullptr;
300         }
301
302         {
303             bool previous = m_isHandlingBeforeLoad;
304             m_isHandlingBeforeLoad = true;
305             makeScopeExit([&] { m_isHandlingBeforeLoad = previous; });
306             if (!shouldLoadLink())
307                 return;
308         }
309
310         m_loading = true;
311
312         bool mediaQueryMatches = true;
313         if (!m_media.isEmpty()) {
314             Optional<RenderStyle> documentStyle;
315             if (document().hasLivingRenderTree())
316                 documentStyle = Style::resolveForDocument(document());
317             auto media = MediaQuerySet::create(m_media, MediaQueryParserContext(document()));
318             LOG(MediaQueries, "HTMLLinkElement::process evaluating queries");
319             mediaQueryMatches = MediaQueryEvaluator { document().frame()->view()->mediaType(), document(), documentStyle ? &*documentStyle : nullptr }.evaluate(media.get());
320         }
321
322         // Don't hold up render tree construction and script execution on stylesheets
323         // that are not needed for the rendering at the moment.
324         bool isActive = mediaQueryMatches && !isAlternate();
325         addPendingSheet(isActive ? ActiveSheet : InactiveSheet);
326
327         // Load stylesheets that are not needed for the rendering immediately with low priority.
328         Optional<ResourceLoadPriority> priority;
329         if (!isActive)
330             priority = ResourceLoadPriority::VeryLow;
331
332         if (document().settings().subresourceIntegrityEnabled())
333             m_integrityMetadataForPendingSheetRequest = attributeWithoutSynchronization(HTMLNames::integrityAttr);
334
335         ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
336         options.sameOriginDataURLFlag = SameOriginDataURLFlag::Set;
337         if (document().contentSecurityPolicy()->allowStyleWithNonce(attributeWithoutSynchronization(HTMLNames::nonceAttr)))
338             options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::SkipPolicyCheck;
339         options.integrity = m_integrityMetadataForPendingSheetRequest;
340
341         auto request = createPotentialAccessControlRequest(WTFMove(url), WTFMove(options), document(), crossOrigin());
342         request.setPriority(WTFMove(priority));
343         request.setCharset(WTFMove(charset));
344         request.setInitiator(*this);
345
346         ASSERT_WITH_SECURITY_IMPLICATION(!m_cachedSheet);
347         m_cachedSheet = document().cachedResourceLoader().requestCSSStyleSheet(WTFMove(request)).value_or(nullptr);
348
349         if (m_cachedSheet)
350             m_cachedSheet->addClient(*this);
351         else {
352             // The request may have been denied if (for example) the stylesheet is local and the document is remote.
353             m_loading = false;
354             sheetLoaded();
355             notifyLoadedSheetAndAllCriticalSubresources(true);
356         }
357     } else if (m_sheet) {
358         // we no longer contain a stylesheet, e.g. perhaps rel or type was changed
359         clearSheet();
360         m_styleScope->didChangeActiveStyleSheetCandidates();
361     }
362 }
363
364 void HTMLLinkElement::clearSheet()
365 {
366     ASSERT(m_sheet);
367     ASSERT(m_sheet->ownerNode() == this);
368     m_sheet->clearOwnerNode();
369     m_sheet = nullptr;
370 }
371
372 Node::InsertedIntoAncestorResult HTMLLinkElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
373 {
374     HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
375     if (!insertionType.connectedToDocument)
376         return InsertedIntoAncestorResult::Done;
377
378     m_styleScope = &Style::Scope::forNode(*this);
379     m_styleScope->addStyleSheetCandidateNode(*this, m_createdByParser);
380
381     return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
382 }
383
384 void HTMLLinkElement::didFinishInsertingNode()
385 {
386     process();
387 }
388
389 void HTMLLinkElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
390 {
391     HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
392     if (!removalType.disconnectedFromDocument)
393         return;
394
395     m_linkLoader.cancelLoad();
396
397     bool wasLoading = styleSheetIsLoading();
398
399     if (m_sheet)
400         clearSheet();
401
402     if (wasLoading)
403         removePendingSheet();
404     
405     if (m_styleScope) {
406         m_styleScope->removeStyleSheetCandidateNode(*this);
407         m_styleScope = nullptr;
408     }
409 }
410
411 void HTMLLinkElement::finishParsingChildren()
412 {
413     m_createdByParser = false;
414     HTMLElement::finishParsingChildren();
415 }
416
417 void HTMLLinkElement::initializeStyleSheet(Ref<StyleSheetContents>&& styleSheet, const CachedCSSStyleSheet& cachedStyleSheet, MediaQueryParserContext context)
418 {
419     // FIXME: originClean should be turned to false except if fetch mode is CORS.
420     Optional<bool> originClean;
421     if (cachedStyleSheet.options().mode == FetchOptions::Mode::Cors)
422         originClean = cachedStyleSheet.isCORSSameOrigin();
423
424     m_sheet = CSSStyleSheet::create(WTFMove(styleSheet), *this, originClean);
425     m_sheet->setMediaQueries(MediaQuerySet::create(m_media, context));
426     if (!isInShadowTree())
427         m_sheet->setTitle(title());
428
429     if (!m_sheet->canAccessRules())
430         m_sheet->contents().setAsOpaque();
431 }
432
433 void HTMLLinkElement::setCSSStyleSheet(const String& href, const URL& baseURL, const String& charset, const CachedCSSStyleSheet* cachedStyleSheet)
434 {
435     if (!isConnected()) {
436         ASSERT(!m_sheet);
437         return;
438     }
439     auto frame = makeRefPtr(document().frame());
440     if (!frame)
441         return;
442
443     // Completing the sheet load may cause scripts to execute.
444     Ref<HTMLLinkElement> protectedThis(*this);
445
446     if (!cachedStyleSheet->errorOccurred() && !matchIntegrityMetadata(*cachedStyleSheet, m_integrityMetadataForPendingSheetRequest)) {
447         document().addConsoleMessage(MessageSource::Security, MessageLevel::Error, makeString("Cannot load stylesheet ", integrityMismatchDescription(*cachedStyleSheet, m_integrityMetadataForPendingSheetRequest)));
448
449         m_loading = false;
450         sheetLoaded();
451         notifyLoadedSheetAndAllCriticalSubresources(true);
452         return;
453     }
454
455     CSSParserContext parserContext(document(), baseURL, charset);
456     auto cachePolicy = frame->loader().subresourceCachePolicy(baseURL);
457
458     if (auto restoredSheet = const_cast<CachedCSSStyleSheet*>(cachedStyleSheet)->restoreParsedStyleSheet(parserContext, cachePolicy, frame->loader())) {
459         ASSERT(restoredSheet->isCacheable());
460         ASSERT(!restoredSheet->isLoading());
461         initializeStyleSheet(restoredSheet.releaseNonNull(), *cachedStyleSheet, MediaQueryParserContext(document()));
462
463         m_loading = false;
464         sheetLoaded();
465         notifyLoadedSheetAndAllCriticalSubresources(false);
466         return;
467     }
468
469     auto styleSheet = StyleSheetContents::create(href, parserContext);
470     initializeStyleSheet(styleSheet.copyRef(), *cachedStyleSheet, MediaQueryParserContext(document()));
471
472     // FIXME: Set the visibility option based on m_sheet being clean or not.
473     // Best approach might be to set it on the style sheet content itself or its context parser otherwise.
474     if (!styleSheet.get().parseAuthorStyleSheet(cachedStyleSheet, &document().securityOrigin())) {
475         m_loading = false;
476         sheetLoaded();
477         notifyLoadedSheetAndAllCriticalSubresources(true);
478         return;
479     }
480
481     m_loading = false;
482     styleSheet.get().notifyLoadedSheet(cachedStyleSheet);
483     styleSheet.get().checkLoaded();
484
485     if (styleSheet.get().isCacheable())
486         const_cast<CachedCSSStyleSheet*>(cachedStyleSheet)->saveParsedStyleSheet(WTFMove(styleSheet));
487 }
488
489 bool HTMLLinkElement::styleSheetIsLoading() const
490 {
491     if (m_loading)
492         return true;
493     if (!m_sheet)
494         return false;
495     return m_sheet->contents().isLoading();
496 }
497
498 DOMTokenList& HTMLLinkElement::sizes()
499 {
500     if (!m_sizes)
501         m_sizes = makeUnique<DOMTokenList>(*this, sizesAttr);
502     return *m_sizes;
503 }
504
505 void HTMLLinkElement::linkLoaded()
506 {
507     m_loadedResource = true;
508     if (!m_relAttribute.isLinkPrefetch || m_allowPrefetchLoadAndErrorForTesting)
509         linkLoadEventSender().dispatchEventSoon(*this);
510 }
511
512 void HTMLLinkElement::linkLoadingErrored()
513 {
514     if (!m_relAttribute.isLinkPrefetch || m_allowPrefetchLoadAndErrorForTesting)
515         linkErrorEventSender().dispatchEventSoon(*this);
516 }
517
518 bool HTMLLinkElement::sheetLoaded()
519 {
520     if (!styleSheetIsLoading()) {
521         removePendingSheet();
522         return true;
523     }
524     return false;
525 }
526
527 void HTMLLinkElement::dispatchPendingLoadEvents()
528 {
529     linkLoadEventSender().dispatchPendingEvents();
530 }
531
532 void HTMLLinkElement::dispatchPendingEvent(LinkEventSender* eventSender)
533 {
534     ASSERT_UNUSED(eventSender, eventSender == &linkLoadEventSender() || eventSender == &linkErrorEventSender());
535     if (m_loadedResource)
536         dispatchEvent(Event::create(eventNames().loadEvent, Event::CanBubble::No, Event::IsCancelable::No));
537     else
538         dispatchEvent(Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No));
539 }
540
541 DOMTokenList& HTMLLinkElement::relList()
542 {
543     if (!m_relList) 
544         m_relList = makeUnique<DOMTokenList>(*this, HTMLNames::relAttr, [](Document& document, StringView token) {
545             return LinkRelAttribute::isSupported(document, token);
546         });
547     return *m_relList;
548 }
549
550 void HTMLLinkElement::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)
551 {
552     if (m_firedLoad)
553         return;
554     m_loadedResource = !errorOccurred;
555     linkLoadEventSender().dispatchEventSoon(*this);
556     m_firedLoad = true;
557 }
558
559 void HTMLLinkElement::startLoadingDynamicSheet()
560 {
561     // We don't support multiple active sheets.
562     ASSERT(m_pendingSheetType < ActiveSheet);
563     addPendingSheet(ActiveSheet);
564 }
565
566 bool HTMLLinkElement::isURLAttribute(const Attribute& attribute) const
567 {
568     return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute);
569 }
570
571 void HTMLLinkElement::defaultEventHandler(Event& event)
572 {
573     if (MouseEvent::canTriggerActivationBehavior(event)) {
574         handleClick(event);
575         return;
576     }
577     HTMLElement::defaultEventHandler(event);
578 }
579
580 void HTMLLinkElement::handleClick(Event& event)
581 {
582     event.setDefaultHandled();
583     URL url = href();
584     if (url.isNull())
585         return;
586     RefPtr<Frame> frame = document().frame();
587     if (!frame)
588         return;
589     frame->loader().urlSelected(url, target(), &event, LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, document().shouldOpenExternalURLsPolicyToPropagate());
590 }
591
592 URL HTMLLinkElement::href() const
593 {
594     return document().completeURL(attributeWithoutSynchronization(hrefAttr));
595 }
596
597 const AtomString& HTMLLinkElement::rel() const
598 {
599     return attributeWithoutSynchronization(relAttr);
600 }
601
602 String HTMLLinkElement::target() const
603 {
604     return attributeWithoutSynchronization(targetAttr);
605 }
606
607 const AtomString& HTMLLinkElement::type() const
608 {
609     return attributeWithoutSynchronization(typeAttr);
610 }
611
612 Optional<LinkIconType> HTMLLinkElement::iconType() const
613 {
614     return m_relAttribute.iconType;
615 }
616
617 void HTMLLinkElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
618 {
619     HTMLElement::addSubresourceAttributeURLs(urls);
620
621     // Favicons are handled by a special case in LegacyWebArchive::create()
622     if (m_relAttribute.iconType)
623         return;
624
625     if (!m_relAttribute.isStyleSheet)
626         return;
627     
628     // Append the URL of this link element.
629     addSubresourceURL(urls, href());
630
631     if (auto styleSheet = makeRefPtr(this->sheet())) {
632         styleSheet->contents().traverseSubresources([&] (auto& resource) {
633             urls.add(resource.url());
634             return false;
635         });
636     }
637 }
638
639 void HTMLLinkElement::addPendingSheet(PendingSheetType type)
640 {
641     if (type <= m_pendingSheetType)
642         return;
643     m_pendingSheetType = type;
644
645     if (m_pendingSheetType == InactiveSheet)
646         return;
647     ASSERT(m_styleScope);
648     m_styleScope->addPendingSheet(*this);
649 }
650
651 void HTMLLinkElement::removePendingSheet()
652 {
653     PendingSheetType type = m_pendingSheetType;
654     m_pendingSheetType = Unknown;
655
656     if (type == Unknown)
657         return;
658
659     ASSERT(m_styleScope);
660     if (type == InactiveSheet) {
661         // Document just needs to know about the sheet for exposure through document.styleSheets
662         m_styleScope->didChangeActiveStyleSheetCandidates();
663         return;
664     }
665
666     m_styleScope->removePendingSheet(*this);
667 }
668
669 } // namespace WebCore