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 54namespace blink { 55 56using namespace HTMLNames; 57 58template <typename CharacterType> 59static 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 119static LinkEventSender& linkLoadEventSender() 120{ 121 DEFINE_STATIC_LOCAL(LinkEventSender, sharedLoadEventSender, (EventTypeNames::load)); 122 return sharedLoadEventSender; 123} 124 125void 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 136inline 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 145PassRefPtrWillBeRawPtr<HTMLLinkElement> HTMLLinkElement::create(Document& document, bool createdByParser) 146{ 147 return adoptRefWillBeNoop(new HTMLLinkElement(document, createdByParser)); 148} 149 150HTMLLinkElement::~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 162void 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 192bool HTMLLinkElement::shouldLoadLink() 193{ 194 return inDocument(); 195} 196 197bool HTMLLinkElement::loadLink(const String& type, const KURL& url) 198{ 199 return m_linkLoader.loadLink(m_relAttribute, fastGetAttribute(HTMLNames::crossoriginAttr), type, url, document()); 200} 201 202LinkResource* 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 226LinkStyle* 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 233LinkImport* 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 240Document* HTMLLinkElement::import() const 241{ 242 if (LinkImport* link = linkImport()) 243 return link->importedDocument(); 244 return 0; 245} 246 247void HTMLLinkElement::process() 248{ 249 if (LinkResource* link = linkResourceToProcess()) 250 link->process(); 251} 252 253void HTMLLinkElement::enableIfExitTransitionStyle() 254{ 255 if (m_relAttribute.isTransitionExitingStylesheet()) { 256 if (LinkStyle* link = linkStyle()) 257 link->setDisabledState(false); 258 } 259} 260 261Node::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 291void 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 313void HTMLLinkElement::finishParsingChildren() 314{ 315 m_createdByParser = false; 316 HTMLElement::finishParsingChildren(); 317} 318 319bool HTMLLinkElement::styleSheetIsLoading() const 320{ 321 return linkStyle() && linkStyle()->styleSheetIsLoading(); 322} 323 324void HTMLLinkElement::linkLoaded() 325{ 326 dispatchEvent(Event::create(EventTypeNames::load)); 327} 328 329void HTMLLinkElement::linkLoadingErrored() 330{ 331 dispatchEvent(Event::create(EventTypeNames::error)); 332} 333 334void HTMLLinkElement::didStartLinkPrerender() 335{ 336 dispatchEvent(Event::create(EventTypeNames::webkitprerenderstart)); 337} 338 339void HTMLLinkElement::didStopLinkPrerender() 340{ 341 dispatchEvent(Event::create(EventTypeNames::webkitprerenderstop)); 342} 343 344void HTMLLinkElement::didSendLoadForLinkPrerender() 345{ 346 dispatchEvent(Event::create(EventTypeNames::webkitprerenderload)); 347} 348 349void HTMLLinkElement::didSendDOMContentLoadedForLinkPrerender() 350{ 351 dispatchEvent(Event::create(EventTypeNames::webkitprerenderdomcontentloaded)); 352} 353 354bool HTMLLinkElement::sheetLoaded() 355{ 356 ASSERT(linkStyle()); 357 return linkStyle()->sheetLoaded(); 358} 359 360void HTMLLinkElement::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred) 361{ 362 ASSERT(linkStyle()); 363 linkStyle()->notifyLoadedSheetAndAllCriticalSubresources(errorOccurred); 364} 365 366void HTMLLinkElement::dispatchPendingLoadEvents() 367{ 368 linkLoadEventSender().dispatchPendingEvents(); 369} 370 371void 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 381void HTMLLinkElement::scheduleEvent() 382{ 383 linkLoadEventSender().dispatchEventSoon(this); 384} 385 386void HTMLLinkElement::startLoadingDynamicSheet() 387{ 388 ASSERT(linkStyle()); 389 linkStyle()->startLoadingDynamicSheet(); 390} 391 392bool HTMLLinkElement::isURLAttribute(const Attribute& attribute) const 393{ 394 return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute); 395} 396 397bool HTMLLinkElement::hasLegalLinkAttribute(const QualifiedName& name) const 398{ 399 return name == hrefAttr || HTMLElement::hasLegalLinkAttribute(name); 400} 401 402const 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 413KURL HTMLLinkElement::href() const 414{ 415 return document().completeURL(getAttribute(hrefAttr)); 416} 417 418const AtomicString& HTMLLinkElement::rel() const 419{ 420 return getAttribute(relAttr); 421} 422 423const AtomicString& HTMLLinkElement::type() const 424{ 425 return getAttribute(typeAttr); 426} 427 428bool HTMLLinkElement::async() const 429{ 430 return fastHasAttribute(HTMLNames::asyncAttr); 431} 432 433IconType HTMLLinkElement::iconType() const 434{ 435 return m_relAttribute.iconType(); 436} 437 438const Vector<IntSize>& HTMLLinkElement::iconSizes() const 439{ 440 return m_iconSizes; 441} 442 443DOMSettableTokenList* HTMLLinkElement::sizes() const 444{ 445 return m_sizes.get(); 446} 447 448void HTMLLinkElement::trace(Visitor* visitor) 449{ 450 visitor->trace(m_link); 451 visitor->trace(m_sizes); 452 HTMLElement::trace(visitor); 453} 454 455void 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 471PassOwnPtrWillBeRawPtr<LinkStyle> LinkStyle::create(HTMLLinkElement* owner) 472{ 473 return adoptPtrWillBeNoop(new LinkStyle(owner)); 474} 475 476LinkStyle::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 486LinkStyle::~LinkStyle() 487{ 488#if !ENABLE(OILPAN) 489 if (m_sheet) 490 m_sheet->clearOwnerNode(); 491#endif 492} 493 494Document& LinkStyle::document() 495{ 496 return m_owner->document(); 497} 498 499void 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 544bool LinkStyle::sheetLoaded() 545{ 546 if (!styleSheetIsLoading()) { 547 removePendingSheet(); 548 return true; 549 } 550 return false; 551} 552 553void 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 563void LinkStyle::startLoadingDynamicSheet() 564{ 565 ASSERT(m_pendingSheetType < Blocking); 566 addPendingSheet(Blocking); 567} 568 569void LinkStyle::clearSheet() 570{ 571 ASSERT(m_sheet); 572 ASSERT(m_sheet->ownerNode() == m_owner); 573 m_sheet->clearOwnerNode(); 574 m_sheet = nullptr; 575} 576 577bool 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 586void 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 597void 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 617void 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 659void 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 726void LinkStyle::setSheetTitle(const String& title) 727{ 728 if (m_sheet) 729 m_sheet->setTitle(title); 730} 731 732void LinkStyle::ownerRemoved() 733{ 734 if (m_sheet) 735 clearSheet(); 736 737 if (styleSheetIsLoading()) 738 removePendingSheet(); 739} 740 741void LinkStyle::trace(Visitor* visitor) 742{ 743 visitor->trace(m_sheet); 744 LinkResource::trace(visitor); 745} 746 747} // namespace blink 748