mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
336 lines
9.5 KiB
C++
336 lines
9.5 KiB
C++
/*
|
|
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
|
|
* (C) 1999 Antti Koivisto (koivisto@kde.org)
|
|
* (C) 2001 Dirk Mueller (mueller@kde.org)
|
|
* Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
|
|
* Copyright (C) 2009 Rob Buis (rwlbuis@gmail.com)
|
|
* Copyright (C) 2011 Google Inc. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "core/html/HTMLLinkElement.h"
|
|
|
|
#include "bindings/core/v8/ScriptEventListener.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/fetch/FetchRequest.h"
|
|
#include "core/fetch/ResourceFetcher.h"
|
|
#include "core/frame/FrameView.h"
|
|
#include "core/frame/LocalFrame.h"
|
|
#include "core/html/imports/LinkImport.h"
|
|
#include "core/html/parser/HTMLParserIdioms.h"
|
|
#include "core/loader/FrameLoaderClient.h"
|
|
#include "core/rendering/style/RenderStyle.h"
|
|
#include "core/rendering/style/StyleInheritedData.h"
|
|
#include "platform/RuntimeEnabledFeatures.h"
|
|
#include "wtf/StdLibExtras.h"
|
|
|
|
namespace blink {
|
|
|
|
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(HTMLNames::linkTag, document)
|
|
, m_sizes(DOMSettableTokenList::create())
|
|
, m_createdByParser(createdByParser)
|
|
, m_isInShadowTree(false)
|
|
{
|
|
ScriptWrappable::init(this);
|
|
}
|
|
|
|
PassRefPtrWillBeRawPtr<HTMLLinkElement> HTMLLinkElement::create(Document& document, bool 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);
|
|
}
|
|
|
|
void HTMLLinkElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
|
|
{
|
|
if (name == HTMLNames::relAttr) {
|
|
m_relAttribute = LinkRelAttribute(value);
|
|
process();
|
|
} else if (name == HTMLNames::hrefAttr) {
|
|
process();
|
|
} else if (name == HTMLNames::typeAttr) {
|
|
m_type = value;
|
|
process();
|
|
} else if (name == HTMLNames::sizesAttr) {
|
|
m_sizes->setValue(value);
|
|
parseSizesAttribute(value, m_iconSizes);
|
|
process();
|
|
} else if (name == HTMLNames::mediaAttr) {
|
|
m_media = value.string().lower();
|
|
process();
|
|
} else {
|
|
HTMLElement::parseAttribute(name, value);
|
|
}
|
|
}
|
|
|
|
LinkResource* HTMLLinkElement::linkResourceToProcess()
|
|
{
|
|
bool visible = inDocument() && !m_isInShadowTree;
|
|
if (!visible)
|
|
return 0;
|
|
|
|
if (!m_link && m_relAttribute.isImport())
|
|
m_link = LinkImport::create(this);
|
|
|
|
return m_link.get();
|
|
}
|
|
|
|
LinkImport* HTMLLinkElement::linkImport() const
|
|
{
|
|
if (!m_link || m_link->type() != LinkResource::Import)
|
|
return 0;
|
|
return static_cast<LinkImport*>(m_link.get());
|
|
}
|
|
|
|
Document* HTMLLinkElement::import() const
|
|
{
|
|
if (LinkImport* link = linkImport())
|
|
return link->importedDocument();
|
|
return 0;
|
|
}
|
|
|
|
void HTMLLinkElement::process()
|
|
{
|
|
if (LinkResource* link = linkResourceToProcess())
|
|
link->process();
|
|
}
|
|
|
|
Node::InsertionNotificationRequest HTMLLinkElement::insertedInto(ContainerNode* insertionPoint)
|
|
{
|
|
HTMLElement::insertedInto(insertionPoint);
|
|
if (!insertionPoint->inDocument())
|
|
return InsertionDone;
|
|
|
|
m_isInShadowTree = isInShadowTree();
|
|
if (m_isInShadowTree)
|
|
return InsertionDone;
|
|
|
|
document().styleEngine()->addStyleSheetCandidateNode(this, m_createdByParser);
|
|
|
|
process();
|
|
|
|
if (m_link)
|
|
m_link->ownerInserted();
|
|
|
|
return InsertionDone;
|
|
}
|
|
|
|
void HTMLLinkElement::removedFrom(ContainerNode* insertionPoint)
|
|
{
|
|
HTMLElement::removedFrom(insertionPoint);
|
|
if (!insertionPoint->inDocument())
|
|
return;
|
|
|
|
if (m_isInShadowTree)
|
|
return;
|
|
document().styleEngine()->removeStyleSheetCandidateNode(this);
|
|
|
|
RefPtrWillBeRawPtr<StyleSheet> removedSheet = sheet();
|
|
|
|
if (m_link)
|
|
m_link->ownerRemoved();
|
|
|
|
document().removedStyleSheet(removedSheet.get());
|
|
}
|
|
|
|
void HTMLLinkElement::finishParsingChildren()
|
|
{
|
|
m_createdByParser = false;
|
|
HTMLElement::finishParsingChildren();
|
|
}
|
|
|
|
void HTMLLinkElement::dispatchPendingLoadEvents()
|
|
{
|
|
linkLoadEventSender().dispatchPendingEvents();
|
|
}
|
|
|
|
void HTMLLinkElement::dispatchPendingEvent(LinkEventSender* eventSender)
|
|
{
|
|
ASSERT_UNUSED(eventSender, eventSender == &linkLoadEventSender());
|
|
ASSERT(m_link);
|
|
// FIXME(sky): Remove
|
|
}
|
|
|
|
void HTMLLinkElement::scheduleEvent()
|
|
{
|
|
linkLoadEventSender().dispatchEventSoon(this);
|
|
}
|
|
|
|
bool HTMLLinkElement::isURLAttribute(const Attribute& attribute) const
|
|
{
|
|
return attribute.name().localName() == HTMLNames::hrefAttr || HTMLElement::isURLAttribute(attribute);
|
|
}
|
|
|
|
bool HTMLLinkElement::hasLegalLinkAttribute(const QualifiedName& name) const
|
|
{
|
|
return name == HTMLNames::hrefAttr || HTMLElement::hasLegalLinkAttribute(name);
|
|
}
|
|
|
|
const QualifiedName& HTMLLinkElement::subResourceAttributeName() const
|
|
{
|
|
// If the link element is not css, ignore it.
|
|
if (equalIgnoringCase(getAttribute(HTMLNames::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 HTMLNames::hrefAttr;
|
|
}
|
|
return HTMLElement::subResourceAttributeName();
|
|
}
|
|
|
|
KURL HTMLLinkElement::href() const
|
|
{
|
|
return document().completeURL(getAttribute(HTMLNames::hrefAttr));
|
|
}
|
|
|
|
const AtomicString& HTMLLinkElement::rel() const
|
|
{
|
|
return getAttribute(HTMLNames::relAttr);
|
|
}
|
|
|
|
const AtomicString& HTMLLinkElement::type() const
|
|
{
|
|
return getAttribute(HTMLNames::typeAttr);
|
|
}
|
|
|
|
bool HTMLLinkElement::async() const
|
|
{
|
|
return hasAttribute(HTMLNames::asyncAttr);
|
|
}
|
|
|
|
String HTMLLinkElement::as() const
|
|
{
|
|
return stripLeadingAndTrailingHTMLSpaces(getAttribute(HTMLNames::asAttr));
|
|
}
|
|
|
|
const Vector<IntSize>& HTMLLinkElement::iconSizes() const
|
|
{
|
|
return m_iconSizes;
|
|
}
|
|
|
|
DOMSettableTokenList* HTMLLinkElement::sizes() const
|
|
{
|
|
return m_sizes.get();
|
|
}
|
|
|
|
void HTMLLinkElement::trace(Visitor* visitor)
|
|
{
|
|
visitor->trace(m_link);
|
|
visitor->trace(m_sizes);
|
|
HTMLElement::trace(visitor);
|
|
}
|
|
|
|
} // namespace blink
|