diff options
Diffstat (limited to 'Source/WebCore/html/HTMLCollection.cpp')
-rw-r--r-- | Source/WebCore/html/HTMLCollection.cpp | 226 |
1 files changed, 139 insertions, 87 deletions
diff --git a/Source/WebCore/html/HTMLCollection.cpp b/Source/WebCore/html/HTMLCollection.cpp index 2782e50..2c6b135 100644 --- a/Source/WebCore/html/HTMLCollection.cpp +++ b/Source/WebCore/html/HTMLCollection.cpp @@ -2,6 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2012 The Linux Foundation 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 @@ -22,6 +23,7 @@ #include "config.h" #include "HTMLCollection.h" +#include "HTMLAllCollection.h" #include "HTMLDocument.h" #include "HTMLElement.h" @@ -38,24 +40,30 @@ using namespace HTMLNames; HTMLCollection::HTMLCollection(PassRefPtr<Node> base, CollectionType type) : m_idsDone(false) + , m_matchTag(htmlTag) , m_base(base) , m_type(type) , m_info(m_base->isDocumentNode() ? static_cast<Document*>(m_base.get())->collectionInfo(type) : 0) , m_ownsInfo(false) { + init(); } HTMLCollection::HTMLCollection(PassRefPtr<Node> base, CollectionType type, CollectionCache* info) : m_idsDone(false) + , m_matchTag(htmlTag) , m_base(base) , m_type(type) , m_info(info) , m_ownsInfo(false) { + init(); } PassRefPtr<HTMLCollection> HTMLCollection::create(PassRefPtr<Node> base, CollectionType type) { + if (type == DocAll || type == NodeChildren) + return HTMLAllCollection::create(base, type); return adoptRef(new HTMLCollection(base, type)); } @@ -65,32 +73,9 @@ HTMLCollection::~HTMLCollection() delete m_info; } -void HTMLCollection::resetCollectionInfo() const -{ - uint64_t docversion = static_cast<HTMLDocument*>(m_base->document())->domTreeVersion(); - - if (!m_info) { - m_info = new CollectionCache; - m_ownsInfo = true; - m_info->version = docversion; - return; - } - - if (m_info->version != docversion) { - m_info->reset(); - m_info->version = docversion; - } -} - -static Node* nextNodeOrSibling(Node* base, Node* node, bool includeChildren) -{ - return includeChildren ? node->traverseNextNode(base) : node->traverseNextSibling(base); -} - -Element* HTMLCollection::itemAfter(Element* previous) const +void HTMLCollection::init() { - bool deep = true; - + m_includeChildren = true; switch (m_type) { case DocAll: case DocAnchors: @@ -112,91 +97,158 @@ Element* HTMLCollection::itemAfter(Element* previous) const case TRCells: case TSectionRows: case TableTBodies: - deep = false; + m_includeChildren = false; break; } - Node* current; - if (!previous) - current = m_base->firstChild(); - else - current = nextNodeOrSibling(m_base.get(), previous, deep); + m_matchType = MatchNone; + switch (m_type) { + case DocImages: + m_matchTag = imgTag; + m_matchType = MatchTag; + break; + case DocScripts: + m_matchTag = scriptTag; + m_matchType = MatchTag; + break; + case DocForms: + m_matchTag = formTag; + m_matchType = MatchTag; + break; + case TableTBodies: + m_matchTag = tbodyTag; + m_matchType = MatchTag; + break; + case TSectionRows: + m_matchTag = trTag; + m_matchType = MatchTag; + break; + case SelectOptions: + m_matchTag = optionTag; + m_matchType = MatchTag; + break; + case MapAreas: + m_matchTag = areaTag; + m_matchType = MatchTag; + break; + case DocEmbeds: + m_matchTag = embedTag; + m_matchType = MatchTag; + break; + case DocObjects: + m_matchTag = objectTag; + m_matchType = MatchTag; + break; + case TRCells: + case DataListOptions: + case DocApplets: // all <applet> elements and <object> elements that contain Java Applets + case DocLinks: // all <a> and <area> elements with a value for href + case DocAnchors: // all <a> elements with a value for name + m_matchType = MatchCustom; + break; + case DocAll: + case NodeChildren: + m_matchType = MatchAll; + break; + case DocumentNamedItems: + case OtherCollection: + case WindowNamedItems: + m_matchType = MatchNone; + break; + } +} - for (; current; current = nextNodeOrSibling(m_base.get(), current, deep)) { - if (!current->isElementNode()) - continue; - Element* e = static_cast<Element*>(current); +void HTMLCollection::resetCollectionInfo() const +{ + uint64_t docversion = static_cast<HTMLDocument*>(m_base->document())->domTreeVersion(); + + if (!m_info) { + m_info = new CollectionCache; + m_ownsInfo = true; + m_info->version = docversion; + return; + } + + if (m_info->version != docversion) { + m_info->reset(); + m_info->version = docversion; + } +} + +static Node* nextNodeOrSibling(Node* base, Node* node, bool includeChildren) +{ + return includeChildren ? node->traverseNextNode(base) : node->traverseNextSibling(base); +} + +inline bool HTMLCollection::nodeMatchesShallow(Element* e) const +{ + if (m_matchType == MatchTag && e->hasLocalName(m_matchTag)) + return true; + if (m_type == TRCells && (e->hasLocalName(tdTag) || e->hasLocalName(thTag))) + return true; + + return false; +} + +inline bool HTMLCollection::nodeMatchesDeep(Element* e) const +{ + if (m_matchType == MatchTag && e->hasLocalName(m_matchTag)) + return true; + if (m_matchType == MatchCustom) { switch (m_type) { - case DocImages: - if (e->hasLocalName(imgTag)) - return e; - break; - case DocScripts: - if (e->hasLocalName(scriptTag)) - return e; - break; - case DocForms: - if (e->hasLocalName(formTag)) - return e; - break; - case TableTBodies: - if (e->hasLocalName(tbodyTag)) - return e; - break; - case TRCells: - if (e->hasLocalName(tdTag) || e->hasLocalName(thTag)) - return e; - break; - case TSectionRows: - if (e->hasLocalName(trTag)) - return e; - break; - case SelectOptions: - if (e->hasLocalName(optionTag)) - return e; - break; case DataListOptions: if (e->hasLocalName(optionTag)) { HTMLOptionElement* option = static_cast<HTMLOptionElement*>(e); if (!option->disabled() && !option->value().isEmpty()) - return e; + return true; } break; - case MapAreas: - if (e->hasLocalName(areaTag)) - return e; - break; case DocApplets: // all <applet> elements and <object> elements that contain Java Applets if (e->hasLocalName(appletTag)) - return e; + return true; if (e->hasLocalName(objectTag) && static_cast<HTMLObjectElement*>(e)->containsJavaApplet()) - return e; - break; - case DocEmbeds: - if (e->hasLocalName(embedTag)) - return e; - break; - case DocObjects: - if (e->hasLocalName(objectTag)) - return e; + return true; break; case DocLinks: // all <a> and <area> elements with a value for href if ((e->hasLocalName(aTag) || e->hasLocalName(areaTag)) && e->fastHasAttribute(hrefAttr)) - return e; + return true; break; case DocAnchors: // all <a> elements with a value for name if (e->hasLocalName(aTag) && e->fastHasAttribute(nameAttr)) - return e; + return true; break; - case DocAll: - case NodeChildren: - return e; - case DocumentNamedItems: - case OtherCollection: - case WindowNamedItems: - ASSERT_NOT_REACHED(); + } + } + + return false; +} + +Element* HTMLCollection::itemAfter(Element* previous) const +{ + Node* current; + Node* base = m_base.get(); + if (!previous) + current = base->firstChild(); + else + current = nextNodeOrSibling(base, previous, m_includeChildren); + + if (m_includeChildren) { + if (!m_info->lastDecendantOfBase) + m_info->lastDecendantOfBase = base->lastDescendantNode(); + + for (; current; current = current->traverseNextNodeFastPath()) { + if (current->isElementNode() && HTMLCollection::nodeMatchesDeep(static_cast<Element*>(current))) + return static_cast<Element*>(current); + if (current == m_info->lastDecendantOfBase) break; } + } else { + for (; current; current = current->traverseNextSibling(base)) { + if (!current->isElementNode()) + continue; + if (HTMLCollection::nodeMatchesShallow(static_cast<Element*>(current))) + return static_cast<Element*>(current); + } } return 0; |