Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      6  * Copyright (C) 2009 Rob Buis (rwlbuis (at) 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>
     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 
    118 static LinkEventSender& linkLoadEventSender()
    119 {
    120     DEFINE_STATIC_LOCAL(LinkEventSender, sharedLoadEventSender, (EventTypeNames::load));
    121     return sharedLoadEventSender;
    122 }
    123 
    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 
    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 
    145 PassRefPtrWillBeRawPtr<HTMLLinkElement> HTMLLinkElement::create(Document& document, bool createdByParser)
    146 {
    147     return adoptRefWillBeNoop(new HTMLLinkElement(document, createdByParser));
    148 }
    149 
    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 
    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 
    192 bool HTMLLinkElement::shouldLoadLink()
    193 {
    194     return inDocument();
    195 }
    196 
    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 
    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 
    226 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 
    233 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 
    240 Document* HTMLLinkElement::import() const
    241 {
    242     if (LinkImport* link = linkImport())
    243         return link->importedDocument();
    244     return 0;
    245 }
    246 
    247 void HTMLLinkElement::process()
    248 {
    249     if (LinkResource* link = linkResourceToProcess())
    250         link->process();
    251 }
    252 
    253 void HTMLLinkElement::enableIfExitTransitionStyle()
    254 {
    255     if (m_relAttribute.isTransitionExitingStylesheet()) {
    256         if (LinkStyle* link = linkStyle())
    257             link->setDisabledState(false);
    258     }
    259 }
    260 
    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 
    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 
    303 void HTMLLinkElement::finishParsingChildren()
    304 {
    305     m_createdByParser = false;
    306     HTMLElement::finishParsingChildren();
    307 }
    308 
    309 bool HTMLLinkElement::styleSheetIsLoading() const
    310 {
    311     return linkStyle() && linkStyle()->styleSheetIsLoading();
    312 }
    313 
    314 void HTMLLinkElement::linkLoaded()
    315 {
    316     dispatchEvent(Event::create(EventTypeNames::load));
    317 }
    318 
    319 void HTMLLinkElement::linkLoadingErrored()
    320 {
    321     dispatchEvent(Event::create(EventTypeNames::error));
    322 }
    323 
    324 void HTMLLinkElement::didStartLinkPrerender()
    325 {
    326     dispatchEvent(Event::create(EventTypeNames::webkitprerenderstart));
    327 }
    328 
    329 void HTMLLinkElement::didStopLinkPrerender()
    330 {
    331     dispatchEvent(Event::create(EventTypeNames::webkitprerenderstop));
    332 }
    333 
    334 void HTMLLinkElement::didSendLoadForLinkPrerender()
    335 {
    336     dispatchEvent(Event::create(EventTypeNames::webkitprerenderload));
    337 }
    338 
    339 void HTMLLinkElement::didSendDOMContentLoadedForLinkPrerender()
    340 {
    341     dispatchEvent(Event::create(EventTypeNames::webkitprerenderdomcontentloaded));
    342 }
    343 
    344 bool HTMLLinkElement::sheetLoaded()
    345 {
    346     ASSERT(linkStyle());
    347     return linkStyle()->sheetLoaded();
    348 }
    349 
    350 void HTMLLinkElement::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)
    351 {
    352     ASSERT(linkStyle());
    353     linkStyle()->notifyLoadedSheetAndAllCriticalSubresources(errorOccurred);
    354 }
    355 
    356 void HTMLLinkElement::dispatchPendingLoadEvents()
    357 {
    358     linkLoadEventSender().dispatchPendingEvents();
    359 }
    360 
    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 
    371 void HTMLLinkElement::scheduleEvent()
    372 {
    373     linkLoadEventSender().dispatchEventSoon(this);
    374 }
    375 
    376 void HTMLLinkElement::startLoadingDynamicSheet()
    377 {
    378     ASSERT(linkStyle());
    379     linkStyle()->startLoadingDynamicSheet();
    380 }
    381 
    382 bool HTMLLinkElement::isURLAttribute(const Attribute& attribute) const
    383 {
    384     return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute);
    385 }
    386 
    387 bool HTMLLinkElement::hasLegalLinkAttribute(const QualifiedName& name) const
    388 {
    389     return name == hrefAttr || HTMLElement::hasLegalLinkAttribute(name);
    390 }
    391 
    392 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 
    403 KURL HTMLLinkElement::href() const
    404 {
    405     return document().completeURL(getAttribute(hrefAttr));
    406 }
    407 
    408 const AtomicString& HTMLLinkElement::rel() const
    409 {
    410     return getAttribute(relAttr);
    411 }
    412 
    413 const AtomicString& HTMLLinkElement::type() const
    414 {
    415     return getAttribute(typeAttr);
    416 }
    417 
    418 bool HTMLLinkElement::async() const
    419 {
    420     return fastHasAttribute(HTMLNames::asyncAttr);
    421 }
    422 
    423 IconType HTMLLinkElement::iconType() const
    424 {
    425     return m_relAttribute.iconType();
    426 }
    427 
    428 const Vector<IntSize>& HTMLLinkElement::iconSizes() const
    429 {
    430     return m_iconSizes;
    431 }
    432 
    433 DOMSettableTokenList* HTMLLinkElement::sizes() const
    434 {
    435     return m_sizes.get();
    436 }
    437 
    438 void HTMLLinkElement::trace(Visitor* visitor)
    439 {
    440     visitor->trace(m_link);
    441     visitor->trace(m_sizes);
    442     HTMLElement::trace(visitor);
    443 }
    444 
    445 PassOwnPtrWillBeRawPtr<LinkStyle> LinkStyle::create(HTMLLinkElement* owner)
    446 {
    447     return adoptPtrWillBeNoop(new LinkStyle(owner));
    448 }
    449 
    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 
    460 LinkStyle::~LinkStyle()
    461 {
    462 #if !ENABLE(OILPAN)
    463     if (m_sheet)
    464         m_sheet->clearOwnerNode();
    465 #endif
    466 }
    467 
    468 Document& LinkStyle::document()
    469 {
    470     return m_owner->document();
    471 }
    472 
    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 
    518 bool LinkStyle::sheetLoaded()
    519 {
    520     if (!styleSheetIsLoading()) {
    521         removePendingSheet();
    522         return true;
    523     }
    524     return false;
    525 }
    526 
    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 
    537 void LinkStyle::startLoadingDynamicSheet()
    538 {
    539     ASSERT(m_pendingSheetType < Blocking);
    540     addPendingSheet(Blocking);
    541 }
    542 
    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 
    551 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 
    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 
    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 
    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 
    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 
    702 void LinkStyle::setSheetTitle(const String& title)
    703 {
    704     if (m_sheet)
    705         m_sheet->setTitle(title);
    706 }
    707 
    708 void LinkStyle::ownerRemoved()
    709 {
    710     if (m_sheet)
    711         clearSheet();
    712 
    713     if (styleSheetIsLoading())
    714         removePendingSheet();
    715 }
    716 
    717 void LinkStyle::trace(Visitor* visitor)
    718 {
    719     visitor->trace(m_sheet);
    720     LinkResource::trace(visitor);
    721 }
    722 
    723 } // namespace WebCore
    724