Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / HTMLLinkElement.cpp
index cc88600..6095285 100644 (file)
 #include "config.h"
 #include "core/html/HTMLLinkElement.h"
 
-#include "HTMLNames.h"
-#include "RuntimeEnabledFeatures.h"
-#include "bindings/v8/ScriptEventListener.h"
+#include "bindings/core/v8/ScriptEventListener.h"
+#include "bindings/core/v8/V8DOMActivityLogger.h"
+#include "core/HTMLNames.h"
 #include "core/css/MediaList.h"
 #include "core/css/MediaQueryEvaluator.h"
 #include "core/css/StyleSheetContents.h"
 #include "core/css/resolver/StyleResolver.h"
 #include "core/dom/Attribute.h"
 #include "core/dom/Document.h"
+#include "core/dom/StyleEngine.h"
 #include "core/events/Event.h"
 #include "core/events/EventSender.h"
-#include "core/dom/StyleEngine.h"
 #include "core/fetch/CSSStyleSheetResource.h"
 #include "core/fetch/FetchRequest.h"
 #include "core/fetch/ResourceFetcher.h"
-#include "core/html/LinkImport.h"
+#include "core/frame/FrameView.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/SubresourceIntegrity.h"
+#include "core/frame/csp/ContentSecurityPolicy.h"
+#include "core/html/LinkManifest.h"
+#include "core/html/imports/LinkImport.h"
 #include "core/loader/FrameLoader.h"
 #include "core/loader/FrameLoaderClient.h"
-#include "core/frame/ContentSecurityPolicy.h"
-#include "core/frame/Frame.h"
-#include "core/frame/FrameView.h"
+#include "core/rendering/style/StyleInheritedData.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "wtf/StdLibExtras.h"
 
-namespace WebCore {
+namespace blink {
 
 using namespace HTMLNames;
 
+template <typename CharacterType>
+static void parseSizes(const CharacterType* value, unsigned length, Vector<IntSize>& iconSizes)
+{
+    enum State {
+        ParseStart,
+        ParseWidth,
+        ParseHeight
+    };
+    int width = 0;
+    unsigned start = 0;
+    unsigned i = 0;
+    State state = ParseStart;
+    bool invalid = false;
+    for (; i < length; ++i) {
+        if (state == ParseWidth) {
+            if (value[i] == 'x' || value[i] == 'X') {
+                if (i == start) {
+                    invalid = true;
+                    break;
+                }
+                width = charactersToInt(value + start, i - start);
+                start = i + 1;
+                state = ParseHeight;
+            } else if (value[i] < '0' || value[i] > '9') {
+                invalid = true;
+                break;
+            }
+        } else if (state == ParseHeight) {
+            if (value[i] == ' ') {
+                if (i == start) {
+                    invalid = true;
+                    break;
+                }
+                int height = charactersToInt(value + start, i - start);
+                iconSizes.append(IntSize(width, height));
+                start = i + 1;
+                state = ParseStart;
+            } else if (value[i] < '0' || value[i] > '9') {
+                invalid = true;
+                break;
+            }
+        } else if (state == ParseStart) {
+            if (value[i] >= '0' && value[i] <= '9') {
+                start = i;
+                state = ParseWidth;
+            } else if (value[i] != ' ') {
+                invalid = true;
+                break;
+            }
+        }
+    }
+    if (invalid || state == ParseWidth || (state == ParseHeight && start == i)) {
+        iconSizes.clear();
+        return;
+    }
+    if (state == ParseHeight && i > start) {
+        int height = charactersToInt(value + start, i - start);
+        iconSizes.append(IntSize(width, height));
+    }
+}
+
 static LinkEventSender& linkLoadEventSender()
 {
     DEFINE_STATIC_LOCAL(LinkEventSender, sharedLoadEventSender, (EventTypeNames::load));
     return sharedLoadEventSender;
 }
 
+void HTMLLinkElement::parseSizesAttribute(const AtomicString& value, Vector<IntSize>& iconSizes)
+{
+    ASSERT(iconSizes.isEmpty());
+    if (value.isEmpty())
+        return;
+    if (value.is8Bit())
+        parseSizes(value.characters8(), value.length(), iconSizes);
+    else
+        parseSizes(value.characters16(), value.length(), iconSizes);
+}
+
 inline HTMLLinkElement::HTMLLinkElement(Document& document, bool createdByParser)
     : HTMLElement(linkTag, document)
     , m_linkLoader(this)
     , m_sizes(DOMSettableTokenList::create())
     , m_createdByParser(createdByParser)
     , m_isInShadowTree(false)
-    , m_beforeLoadRecurseCount(0)
 {
-    ScriptWrappable::init(this);
 }
 
-PassRefPtr<HTMLLinkElement> HTMLLinkElement::create(Document& document, bool createdByParser)
+PassRefPtrWillBeRawPtr<HTMLLinkElement> HTMLLinkElement::create(Document& document, bool createdByParser)
 {
-    return adoptRef(new HTMLLinkElement(document, createdByParser));
+    return adoptRefWillBeNoop(new HTMLLinkElement(document, createdByParser));
 }
 
 HTMLLinkElement::~HTMLLinkElement()
 {
+#if !ENABLE(OILPAN)
     m_link.clear();
 
     if (inDocument())
         document().styleEngine()->removeStyleSheetCandidateNode(this);
+#endif
 
     linkLoadEventSender().cancelEvent(this);
 }
@@ -96,16 +172,15 @@ void HTMLLinkElement::parseAttribute(const QualifiedName& name, const AtomicStri
         process();
     } else if (name == sizesAttr) {
         m_sizes->setValue(value);
+        parseSizesAttribute(value, m_iconSizes);
         process();
     } else if (name == mediaAttr) {
-        m_media = value.string().lower();
+        m_media = value.lower();
         process();
     } else if (name == disabledAttr) {
         if (LinkStyle* link = linkStyle())
             link->setDisabledState(!value.isNull());
-    } else if (name == onbeforeloadAttr)
-        setAttributeEventListener(EventTypeNames::beforeload, createAttributeEventListener(this, name, value));
-    else {
+    } else {
         if (name == titleAttr) {
             if (LinkStyle* link = linkStyle())
                 link->setSheetTitle(value);
@@ -117,25 +192,12 @@ void HTMLLinkElement::parseAttribute(const QualifiedName& name, const AtomicStri
 
 bool HTMLLinkElement::shouldLoadLink()
 {
-    bool continueLoad = true;
-    RefPtr<Document> originalDocument(document());
-    int recursionRank = ++m_beforeLoadRecurseCount;
-    if (!dispatchBeforeLoadEvent(getNonEmptyURLAttribute(hrefAttr)))
-        continueLoad = false;
-
-    // A beforeload handler might have removed us from the document or changed the document.
-    if (continueLoad && (!inDocument() || document() != originalDocument))
-        continueLoad = false;
-
-    // If the beforeload handler recurses into the link element by mutating it, we should only
-    // let the latest (innermost) mutation occur.
-    if (recursionRank != m_beforeLoadRecurseCount)
-        continueLoad = false;
-
-    if (recursionRank == 1)
-        m_beforeLoadRecurseCount = 0;
+    return inDocument();
+}
 
-    return continueLoad;
+bool HTMLLinkElement::loadLink(const String& type, const KURL& url)
+{
+    return m_linkLoader.loadLink(m_relAttribute, fastGetAttribute(HTMLNames::crossoriginAttr), type, url, document());
 }
 
 LinkResource* HTMLLinkElement::linkResourceToProcess()
@@ -143,15 +205,17 @@ LinkResource* HTMLLinkElement::linkResourceToProcess()
     bool visible = inDocument() && !m_isInShadowTree;
     if (!visible) {
         ASSERT(!linkStyle() || !linkStyle()->hasSheet());
-        return 0;
+        return nullptr;
     }
 
     if (!m_link) {
-        if (m_relAttribute.isImport() && RuntimeEnabledFeatures::htmlImportsEnabled())
+        if (m_relAttribute.isImport()) {
             m_link = LinkImport::create(this);
-        else {
-            OwnPtr<LinkStyle> link = LinkStyle::create(this);
-            if (fastHasAttribute(disabledAttr))
+        } else if (m_relAttribute.isManifest()) {
+            m_link = LinkManifest::create(this);
+        } else {
+            OwnPtrWillBeRawPtr<LinkStyle> link = LinkStyle::create(this);
+            if (fastHasAttribute(disabledAttr) || m_relAttribute.isTransitionExitingStylesheet())
                 link->setDisabledState(true);
             m_link = link.release();
         }
@@ -163,30 +227,22 @@ LinkResource* HTMLLinkElement::linkResourceToProcess()
 LinkStyle* HTMLLinkElement::linkStyle() const
 {
     if (!m_link || m_link->type() != LinkResource::Style)
-        return 0;
+        return nullptr;
     return static_cast<LinkStyle*>(m_link.get());
 }
 
 LinkImport* HTMLLinkElement::linkImport() const
 {
     if (!m_link || m_link->type() != LinkResource::Import)
-        return 0;
+        return nullptr;
     return static_cast<LinkImport*>(m_link.get());
 }
 
-bool HTMLLinkElement::importOwnsLoader() const
-{
-    LinkImport* import = linkImport();
-    if (!import)
-        return false;
-    return import->ownsLoader();
-}
-
 Document* HTMLLinkElement::import() const
 {
     if (LinkImport* link = linkImport())
         return link->importedDocument();
-    return 0;
+    return nullptr;
 }
 
 void HTMLLinkElement::process()
@@ -195,19 +251,44 @@ void HTMLLinkElement::process()
         link->process();
 }
 
+void HTMLLinkElement::enableIfExitTransitionStyle()
+{
+    if (m_relAttribute.isTransitionExitingStylesheet()) {
+        if (LinkStyle* link = linkStyle())
+            link->setDisabledState(false);
+    }
+}
+
 Node::InsertionNotificationRequest HTMLLinkElement::insertedInto(ContainerNode* insertionPoint)
 {
+    if (insertionPoint->inDocument()) {
+        V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
+        if (activityLogger) {
+            Vector<String> argv;
+            argv.append("link");
+            argv.append(fastGetAttribute(relAttr));
+            argv.append(fastGetAttribute(hrefAttr));
+            activityLogger->logEvent("blinkAddElement", argv.size(), argv.data());
+        }
+    }
     HTMLElement::insertedInto(insertionPoint);
     if (!insertionPoint->inDocument())
         return InsertionDone;
 
     m_isInShadowTree = isInShadowTree();
-    if (m_isInShadowTree)
+    if (m_isInShadowTree) {
+        String message = "HTML element <link> is ignored in shadow tree.";
+        document().addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message));
         return InsertionDone;
+    }
 
     document().styleEngine()->addStyleSheetCandidateNode(this, m_createdByParser);
 
     process();
+
+    if (m_link)
+        m_link->ownerInserted();
+
     return InsertionDone;
 }
 
@@ -225,7 +306,7 @@ void HTMLLinkElement::removedFrom(ContainerNode* insertionPoint)
     }
     document().styleEngine()->removeStyleSheetCandidateNode(this);
 
-    RefPtr<StyleSheet> removedSheet = sheet();
+    RefPtrWillBeRawPtr<StyleSheet> removedSheet = sheet();
 
     if (m_link)
         m_link->ownerRemoved();
@@ -295,11 +376,6 @@ void HTMLLinkElement::dispatchPendingEvent(LinkEventSender* eventSender)
 {
     ASSERT_UNUSED(eventSender, eventSender == &linkLoadEventSender());
     ASSERT(m_link);
-    dispatchEventImmediately();
-}
-
-void HTMLLinkElement::dispatchEventImmediately()
-{
     if (m_link->hasLoaded())
         linkLoaded();
     else
@@ -322,6 +398,22 @@ bool HTMLLinkElement::isURLAttribute(const Attribute& attribute) const
     return attribute.name().localName() == hrefAttr || HTMLElement::isURLAttribute(attribute);
 }
 
+bool HTMLLinkElement::hasLegalLinkAttribute(const QualifiedName& name) const
+{
+    return name == hrefAttr || HTMLElement::hasLegalLinkAttribute(name);
+}
+
+const QualifiedName& HTMLLinkElement::subResourceAttributeName() const
+{
+    // If the link element is not css, ignore it.
+    if (equalIgnoringCase(getAttribute(typeAttr), "text/css")) {
+        // FIXME: Add support for extracting links of sub-resources which
+        // are inside style-sheet such as @import, @font-face, url(), etc.
+        return hrefAttr;
+    }
+    return HTMLElement::subResourceAttributeName();
+}
+
 KURL HTMLLinkElement::href() const
 {
     return document().completeURL(getAttribute(hrefAttr));
@@ -337,14 +429,19 @@ const AtomicString& HTMLLinkElement::type() const
     return getAttribute(typeAttr);
 }
 
+bool HTMLLinkElement::async() const
+{
+    return fastHasAttribute(HTMLNames::asyncAttr);
+}
+
 IconType HTMLLinkElement::iconType() const
 {
     return m_relAttribute.iconType();
 }
 
-const AtomicString& HTMLLinkElement::iconSizes() const
+const Vector<IntSize>& HTMLLinkElement::iconSizes() const
 {
-    return m_sizes->toString();
+    return m_iconSizes;
 }
 
 DOMSettableTokenList* HTMLLinkElement::sizes() const
@@ -352,9 +449,32 @@ DOMSettableTokenList* HTMLLinkElement::sizes() const
     return m_sizes.get();
 }
 
-PassOwnPtr<LinkStyle> LinkStyle::create(HTMLLinkElement* owner)
+void HTMLLinkElement::trace(Visitor* visitor)
+{
+    visitor->trace(m_link);
+    visitor->trace(m_sizes);
+    HTMLElement::trace(visitor);
+}
+
+void HTMLLinkElement::attributeWillChange(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
 {
-    return adoptPtr(new LinkStyle(owner));
+    if (name == hrefAttr && inDocument()) {
+        V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
+        if (activityLogger) {
+            Vector<String> argv;
+            argv.append("link");
+            argv.append(hrefAttr.toString());
+            argv.append(oldValue);
+            argv.append(newValue);
+            activityLogger->logEvent("blinkSetAttribute", argv.size(), argv.data());
+        }
+    }
+    HTMLElement::attributeWillChange(name, oldValue, newValue);
+}
+
+PassOwnPtrWillBeRawPtr<LinkStyle> LinkStyle::create(HTMLLinkElement* owner)
+{
+    return adoptPtrWillBeNoop(new LinkStyle(owner));
 }
 
 LinkStyle::LinkStyle(HTMLLinkElement* owner)
@@ -369,8 +489,10 @@ LinkStyle::LinkStyle(HTMLLinkElement* owner)
 
 LinkStyle::~LinkStyle()
 {
+#if !ENABLE(OILPAN)
     if (m_sheet)
         m_sheet->clearOwnerNode();
+#endif
 }
 
 Document& LinkStyle::document()
@@ -383,14 +505,20 @@ void LinkStyle::setCSSStyleSheet(const String& href, const KURL& baseURL, const
     if (!m_owner->inDocument()) {
         ASSERT(!m_sheet);
         return;
+    }
 
+    if (!SubresourceIntegrity::CheckSubresourceIntegrity(*m_owner, cachedStyleSheet->sheetText(), KURL(KURL(), href))) {
+        m_loading = false;
+        removePendingSheet();
+        return;
     }
+
     // Completing the sheet load may cause scripts to execute.
-    RefPtr<Node> protector(m_owner);
+    RefPtrWillBeRawPtr<Node> protector(m_owner.get());
 
-    CSSParserContext parserContext(m_owner->document(), baseURL, charset);
+    CSSParserContext parserContext(m_owner->document(), 0, baseURL, charset);
 
-    if (RefPtr<StyleSheetContents> restoredSheet = const_cast<CSSStyleSheetResource*>(cachedStyleSheet)->restoreParsedStyleSheet(parserContext)) {
+    if (RefPtrWillBeRawPtr<StyleSheetContents> restoredSheet = const_cast<CSSStyleSheetResource*>(cachedStyleSheet)->restoreParsedStyleSheet(parserContext)) {
         ASSERT(restoredSheet->isCacheable());
         ASSERT(!restoredSheet->isLoading());
 
@@ -405,10 +533,11 @@ void LinkStyle::setCSSStyleSheet(const String& href, const KURL& baseURL, const
         return;
     }
 
-    RefPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(href, parserContext);
+    RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(href, parserContext);
 
     if (m_sheet)
         clearSheet();
+
     m_sheet = CSSStyleSheet::create(styleSheet, m_owner);
     m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media()));
     m_sheet->setTitle(m_owner->title());
@@ -453,7 +582,7 @@ void LinkStyle::clearSheet()
     ASSERT(m_sheet);
     ASSERT(m_sheet->ownerNode() == m_owner);
     m_sheet->clearOwnerNode();
-    m_sheet = 0;
+    m_sheet = nullptr;
 }
 
 bool LinkStyle::styleSheetIsLoading() const
@@ -476,7 +605,7 @@ void LinkStyle::addPendingSheet(PendingSheetType type)
     m_owner->document().styleEngine()->addPendingSheet();
 }
 
-void LinkStyle::removePendingSheet(RemovePendingSheetNotificationType notification)
+void LinkStyle::removePendingSheet()
 {
     PendingSheetType type = m_pendingSheetType;
     m_pendingSheetType = None;
@@ -489,14 +618,11 @@ void LinkStyle::removePendingSheet(RemovePendingSheetNotificationType notificati
         // Document::removePendingSheet() triggers the style selector recalc for blocking sheets.
         // FIXME: We don't have enough knowledge at this point to know if we're adding or removing a sheet
         // so we can't call addedStyleSheet() or removedStyleSheet().
-        m_owner->document().styleResolverChanged(RecalcStyleImmediately);
+        m_owner->document().styleResolverChanged();
         return;
     }
 
-    m_owner->document().styleEngine()->removePendingSheet(m_owner,
-        notification == RemovePendingSheetNotifyImmediately
-        ? StyleEngine::RemovePendingSheetNotifyImmediately
-        : StyleEngine::RemovePendingSheetNotifyLater);
+    m_owner->document().styleEngine()->removePendingSheet(m_owner);
 }
 
 void LinkStyle::setDisabledState(bool disabled)
@@ -536,7 +662,7 @@ void LinkStyle::setDisabledState(bool disabled)
                 process();
         } else {
             // FIXME: We don't have enough knowledge here to know if we should call addedStyleSheet() or removedStyleSheet().
-            m_owner->document().styleResolverChanged(RecalcStyleDeferred);
+            m_owner->document().styleResolverChanged();
         }
     }
 }
@@ -554,14 +680,14 @@ void LinkStyle::process()
             return;
         if (!document().contentSecurityPolicy()->allowImageFromSource(builder.url()))
             return;
-        if (document().frame())
+        if (document().frame() && document().frame()->loader().client())
             document().frame()->loader().client()->dispatchDidChangeIcons(m_owner->relAttribute().iconType());
     }
 
     if (!m_owner->loadLink(type, builder.url()))
         return;
 
-    if ((m_disabledState != Disabled) && m_owner->relAttribute().isStyleSheet()
+    if ((m_disabledState != Disabled) && (m_owner->relAttribute().isStyleSheet() || m_owner->relAttribute().isTransitionExitingStylesheet())
         && shouldLoadResource() && builder.url().isValid()) {
 
         if (resource()) {
@@ -572,14 +698,14 @@ void LinkStyle::process()
         if (!m_owner->shouldLoadLink())
             return;
 
-        Frame* frame = loadingFrame();
         m_loading = true;
 
         bool mediaQueryMatches = true;
-        if (!m_owner->media().isEmpty()) {
-            RefPtr<RenderStyle> documentStyle = StyleResolver::styleForDocument(document());
-            RefPtr<MediaQuerySet> media = MediaQuerySet::create(m_owner->media());
-            MediaQueryEvaluator evaluator(frame->view()->mediaType(), frame, documentStyle.get());
+        LocalFrame* frame = loadingFrame();
+        if (!m_owner->media().isEmpty() && frame && frame->document()) {
+            RefPtr<RenderStyle> documentStyle = StyleResolver::styleForDocument(*frame->document());
+            RefPtrWillBeRawPtr<MediaQuerySet> media = MediaQuerySet::create(m_owner->media());
+            MediaQueryEvaluator evaluator(frame);
             mediaQueryMatches = evaluator.eval(media.get());
         }
 
@@ -590,6 +716,9 @@ void LinkStyle::process()
 
         // Load stylesheets that are not needed for the rendering immediately with low priority.
         FetchRequest request = builder.build(blocking);
+        AtomicString crossOriginMode = m_owner->fastGetAttribute(HTMLNames::crossoriginAttr);
+        if (!crossOriginMode.isNull())
+            request.setCrossOriginAccessControl(document().securityOrigin(), crossOriginMode);
         setResource(document().fetcher()->fetchCSSStyleSheet(request));
 
         if (!resource()) {
@@ -599,7 +728,7 @@ void LinkStyle::process()
         }
     } else if (m_sheet) {
         // we no longer contain a stylesheet, e.g. perhaps rel or type was changed
-        RefPtr<StyleSheet> removedSheet = m_sheet;
+        RefPtrWillBeRawPtr<StyleSheet> removedSheet = m_sheet.get();
         clearSheet();
         document().removedStyleSheet(removedSheet.get());
     }
@@ -617,7 +746,13 @@ void LinkStyle::ownerRemoved()
         clearSheet();
 
     if (styleSheetIsLoading())
-        removePendingSheet(RemovePendingSheetNotifyLater);
+        removePendingSheet();
+}
+
+void LinkStyle::trace(Visitor* visitor)
+{
+    visitor->trace(m_sheet);
+    LinkResource::trace(visitor);
 }
 
-} // namespace WebCore
+} // namespace blink