Add element ancestor iterator
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 1 Sep 2013 10:33:08 +0000 (10:33 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 1 Sep 2013 10:33:08 +0000 (10:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=120563

Reviewed by Andreas Kling.

This patch adds ancestor iterators. They iterate over elements parent chain up to the root.

To iterate over Element ancestors:

auto ancestors = elementAncestors(this);
for (auto it = ancestors.begin(), end = ancestors.end(); it != end; ++it) {
    Element& element = *it;
    ...

To iterate over Element ancestors including the current element:

auto lineage = elementLineage(this);
for (auto it = lineage.begin(), end = lineage.end(); it != end; ++it) {
    Element& element = *it;
    ...

To iterate over ancestors of a specific Element subclass:

auto htmlAncestors = ancestorsOfType<HTMLElement>(this);
for (auto it = htmlAncestors.begin(), end = htmlAncestors.end(); it != end; ++it) {
    HTMLElement& htmlElement = *it;
    ...

To iterate over ancestors of a specific Element subclass including the current element:

auto htmlLineage = lineageOfType<HTMLElement>(this);
for (auto it = htmlLineage.begin(), end = htmlLineage.end(); it != end; ++it) {
    HTMLElement& htmlElement = *it;
    ...

The patch also uses the new types in a few places.

* WebCore.xcodeproj/project.pbxproj:
* accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::mouseButtonListener):
(WebCore::AccessibilityNodeObject::labelForElement):
* dom/ElementAncestorIterator.h: Added.
(WebCore::::ElementAncestorIterator):
(WebCore::::operator):
(WebCore::::ElementAncestorConstIterator):
(WebCore::::ElementAncestorIteratorAdapter):
(WebCore::::begin):
(WebCore::::end):
(WebCore::::ElementAncestorConstIteratorAdapter):
(WebCore::elementLineage):
(WebCore::elementAncestors):
(WebCore::ancestorsOfType):
* dom/ElementIterator.h:
(WebCore::findElementAncestorOfType):
(WebCore::::traverseAncestor):
(WebCore::=):
* html/HTMLElement.cpp:
(WebCore::HTMLElement::adjustDirectionalityIfNeededAfterChildAttributeChanged):
* html/HTMLFieldSetElement.h:
(WebCore::isHTMLFieldSetElement):
(WebCore::HTMLFieldSetElement):
* html/HTMLFrameSetElement.cpp:
(WebCore::HTMLFrameSetElement::findContaining):
* html/HTMLFrameSetElement.h:
(WebCore::HTMLFrameSetElement):
* html/HTMLInputElement.h:
(WebCore::isHTMLInputElement):
(WebCore::toHTMLInputElement):
* html/HTMLLegendElement.cpp:
(WebCore::HTMLLegendElement::associatedControl):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@154940 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/accessibility/AccessibilityNodeObject.cpp
Source/WebCore/dom/ElementAncestorIterator.h [new file with mode: 0644]
Source/WebCore/dom/ElementIterator.h
Source/WebCore/html/HTMLElement.cpp
Source/WebCore/html/HTMLFieldSetElement.h
Source/WebCore/html/HTMLFrameSetElement.cpp
Source/WebCore/html/HTMLFrameSetElement.h
Source/WebCore/html/HTMLInputElement.h
Source/WebCore/html/HTMLLegendElement.cpp

index 693101c..c5b23be 100644 (file)
@@ -1,3 +1,76 @@
+2013-08-31  Antti Koivisto  <antti@apple.com>
+
+        Add element ancestor iterator
+        https://bugs.webkit.org/show_bug.cgi?id=120563
+
+        Reviewed by Andreas Kling.
+
+        This patch adds ancestor iterators. They iterate over elements parent chain up to the root.
+        
+        To iterate over Element ancestors:
+        
+        auto ancestors = elementAncestors(this);
+        for (auto it = ancestors.begin(), end = ancestors.end(); it != end; ++it) {
+            Element& element = *it;
+            ...
+
+        To iterate over Element ancestors including the current element:
+        
+        auto lineage = elementLineage(this);
+        for (auto it = lineage.begin(), end = lineage.end(); it != end; ++it) {
+            Element& element = *it;
+            ...
+            
+        To iterate over ancestors of a specific Element subclass:
+
+        auto htmlAncestors = ancestorsOfType<HTMLElement>(this);
+        for (auto it = htmlAncestors.begin(), end = htmlAncestors.end(); it != end; ++it) {
+            HTMLElement& htmlElement = *it;
+            ...
+            
+        To iterate over ancestors of a specific Element subclass including the current element:
+
+        auto htmlLineage = lineageOfType<HTMLElement>(this);
+        for (auto it = htmlLineage.begin(), end = htmlLineage.end(); it != end; ++it) {
+            HTMLElement& htmlElement = *it;
+            ...
+            
+        The patch also uses the new types in a few places.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * accessibility/AccessibilityNodeObject.cpp:
+        (WebCore::AccessibilityNodeObject::mouseButtonListener):
+        (WebCore::AccessibilityNodeObject::labelForElement):
+        * dom/ElementAncestorIterator.h: Added.
+        (WebCore::::ElementAncestorIterator):
+        (WebCore::::operator):
+        (WebCore::::ElementAncestorConstIterator):
+        (WebCore::::ElementAncestorIteratorAdapter):
+        (WebCore::::begin):
+        (WebCore::::end):
+        (WebCore::::ElementAncestorConstIteratorAdapter):
+        (WebCore::elementLineage):
+        (WebCore::elementAncestors):
+        (WebCore::ancestorsOfType):
+        * dom/ElementIterator.h:
+        (WebCore::findElementAncestorOfType):
+        (WebCore::::traverseAncestor):
+        (WebCore::=):
+        * html/HTMLElement.cpp:
+        (WebCore::HTMLElement::adjustDirectionalityIfNeededAfterChildAttributeChanged):
+        * html/HTMLFieldSetElement.h:
+        (WebCore::isHTMLFieldSetElement):
+        (WebCore::HTMLFieldSetElement):
+        * html/HTMLFrameSetElement.cpp:
+        (WebCore::HTMLFrameSetElement::findContaining):
+        * html/HTMLFrameSetElement.h:
+        (WebCore::HTMLFrameSetElement):
+        * html/HTMLInputElement.h:
+        (WebCore::isHTMLInputElement):
+        (WebCore::toHTMLInputElement):
+        * html/HTMLLegendElement.cpp:
+        (WebCore::HTMLLegendElement::associatedControl):
+
 2013-08-31  Darin Adler  <darin@apple.com>
 
         Refactor URL and image writing so layer-violating parts are in Editor, not Pasteboard (Mac-only at first)
index c4626d9..eefc906 100644 (file)
@@ -2869,6 +2869,7 @@ webcore_sources += \
        Source/WebCore/dom/DOMTimeStamp.h \
        Source/WebCore/dom/Element.cpp \
        Source/WebCore/dom/Element.h \
+       Source/WebCore/dom/ElementAncestorIterator.h \
        Source/WebCore/dom/ElementChildIterator.h \
        Source/WebCore/dom/ElementData.cpp \
        Source/WebCore/dom/ElementData.h \
index aa4a2c5..74536a1 100644 (file)
@@ -1610,6 +1610,7 @@ HEADERS += \
     dom/DOMTimeStamp.h \
     dom/DatasetDOMStringMap.h \
     dom/Element.h \
+    dom/ElementAncestorIterator.h \
     dom/ElementChildIterator.h \
     dom/ElementData.h \
     dom/ElementDescendantIterator.h \
index c2e44f8..002b375 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="DebugSuffix|Win32">
     <ClInclude Include="..\dom\DOMStringMap.h" />
     <ClInclude Include="..\dom\DOMTimeStamp.h" />
     <ClInclude Include="..\dom\Element.h" />
+    <ClInclude Include="..\dom\ElementAncestorIterator.h" />
     <ClInclude Include="..\dom\ElementChildIterator.h" />
     <ClInclude Include="..\dom\ElementData.h" />
     <ClInclude Include="..\dom\ElementDescendantIterator.h" />
index ef31f6f..da3ff28 100644 (file)
                E49BD9FA131FD2ED003C56F0 /* CSSValuePool.h in Headers */ = {isa = PBXBuildFile; fileRef = E49BD9F9131FD2ED003C56F0 /* CSSValuePool.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E49BDA0B131FD3E5003C56F0 /* CSSValuePool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E49BDA0A131FD3E5003C56F0 /* CSSValuePool.cpp */; };
                E4AE7C1617D1BB950009FB31 /* ElementIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1517D1BB950009FB31 /* ElementIterator.h */; };
+               E4AE7C1A17D232350009FB31 /* ElementAncestorIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */; };
                E4AFCFA50DAF29A300F5F55C /* UnitBezier.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AFCFA40DAF29A300F5F55C /* UnitBezier.h */; };
                E4AFD00B0DAF335400F5F55C /* SMILTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4AFD0050DAF335400F5F55C /* SMILTime.cpp */; };
                E4AFD00C0DAF335400F5F55C /* SMILTime.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AFD0060DAF335400F5F55C /* SMILTime.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E49BD9F9131FD2ED003C56F0 /* CSSValuePool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSValuePool.h; sourceTree = "<group>"; };
                E49BDA0A131FD3E5003C56F0 /* CSSValuePool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSValuePool.cpp; sourceTree = "<group>"; };
                E4AE7C1517D1BB950009FB31 /* ElementIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementIterator.h; sourceTree = "<group>"; };
+               E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementAncestorIterator.h; sourceTree = "<group>"; };
                E4AFCFA40DAF29A300F5F55C /* UnitBezier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnitBezier.h; sourceTree = "<group>"; };
                E4AFD0050DAF335400F5F55C /* SMILTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SMILTime.cpp; sourceTree = "<group>"; };
                E4AFD0060DAF335400F5F55C /* SMILTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMILTime.h; sourceTree = "<group>"; };
                                A8C4A7F609D563270003AC8D /* Element.cpp */,
                                A8C4A7F509D563270003AC8D /* Element.h */,
                                93EEC1EA09C2877700C515D1 /* Element.idl */,
+                               E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */,
                                E46A2B1D17CA76B1000DBCD8 /* ElementChildIterator.h */,
                                B5B7A16F17C1080600E4AA0A /* ElementData.cpp */,
                                B5B7A16E17C1048000E4AA0A /* ElementData.h */,
                                31FB1A66120A5D3F00DC02A0 /* JSDeviceMotionEvent.h in Headers */,
                                59A86008119DAFA100DEF1EF /* JSDeviceOrientationEvent.h in Headers */,
                                BCE4389C140B1BA8005E437E /* JSDictionary.h in Headers */,
+                               E4AE7C1A17D232350009FB31 /* ElementAncestorIterator.h in Headers */,
                                8987858B122CA26A003AABDA /* JSDirectoryEntry.h in Headers */,
                                893C483312495472002B3D86 /* JSDirectoryEntrySync.h in Headers */,
                                8987858D122CA26A003AABDA /* JSDirectoryReader.h in Headers */,
index e7dfd9b..2ae889a 100644 (file)
@@ -977,21 +977,16 @@ Element* AccessibilityNodeObject::mouseButtonListener() const
         return 0;
 
     // check if our parent is a mouse button listener
-    while (node && !node->isElementNode())
-        node = node->parentNode();
-
-    if (!node)
-        return 0;
-
     // FIXME: Do the continuation search like anchorElement does
-    for (Element* element = toElement(node); element; element = element->parentElement()) {
+    auto lineage = elementLineage(node->isElementNode() ? toElement(node) : node->parentElement());
+    for (auto element = lineage.begin(), end = lineage.end(); element != end; ++element) {
         // If we've reached the body and this is not a control element, do not expose press action for this element.
         // It can cause false positives, where every piece of text is labeled as accepting press actions. 
         if (element->hasTagName(bodyTag) && isStaticText())
             break;
         
         if (element->hasEventListeners(eventNames().clickEvent) || element->hasEventListeners(eventNames().mousedownEvent) || element->hasEventListeners(eventNames().mouseupEvent))
-            return element;
+            return &*element;
     }
 
     return 0;
@@ -1099,12 +1094,9 @@ HTMLLabelElement* AccessibilityNodeObject::labelForElement(Element* element) con
             return label;
     }
 
-    for (Element* parent = element->parentElement(); parent; parent = parent->parentElement()) {
-        if (isHTMLLabelElement(parent))
-            return toHTMLLabelElement(parent);
-    }
-
-    return 0;
+    auto labelAncestors = ancestorsOfType<HTMLLabelElement>(element);
+    auto enclosingLabel = labelAncestors.begin();
+    return enclosingLabel != labelAncestors.end() ? &*enclosingLabel : nullptr;
 }
 
 String AccessibilityNodeObject::ariaAccessibilityDescription() const
diff --git a/Source/WebCore/dom/ElementAncestorIterator.h b/Source/WebCore/dom/ElementAncestorIterator.h
new file mode 100644 (file)
index 0000000..e8b417c
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ElementAncestorIterator_h
+#define ElementAncestorIterator_h
+
+#include "ElementIterator.h"
+
+namespace WebCore {
+
+template <typename ElementType>
+class ElementAncestorIterator : public ElementIterator<ElementType> {
+public:
+    ElementAncestorIterator();
+    ElementAncestorIterator(ElementType* current);
+    ElementAncestorIterator& operator++();
+};
+
+template <typename ElementType>
+class ElementAncestorConstIterator : public ElementConstIterator<ElementType> {
+public:
+    ElementAncestorConstIterator();
+    ElementAncestorConstIterator(const ElementType* current);
+    ElementAncestorConstIterator& operator++();
+};
+
+template <typename ElementType>
+class ElementAncestorIteratorAdapter {
+public:
+    ElementAncestorIteratorAdapter(ElementType* descendant);
+    ElementAncestorIterator<ElementType> begin();
+    ElementAncestorIterator<ElementType> end();
+
+private:
+    ElementType* m_first;
+};
+
+template <typename ElementType>
+class ElementAncestorConstIteratorAdapter {
+public:
+    ElementAncestorConstIteratorAdapter(const ElementType* descendant);
+    ElementAncestorConstIterator<ElementType> begin() const;
+    ElementAncestorConstIterator<ElementType> end() const;
+
+private:
+    const ElementType* m_first;
+};
+
+ElementAncestorIteratorAdapter<Element> elementLineage(Element* first);
+ElementAncestorConstIteratorAdapter<Element> elementLineage(const Element* first);
+ElementAncestorIteratorAdapter<Element> elementAncestors(Element* descendant);
+ElementAncestorConstIteratorAdapter<Element> elementAncestors(const Element* descendant);
+template <typename ElementType> ElementAncestorIteratorAdapter<ElementType> lineageOfType(Element* first);
+template <typename ElementType> ElementAncestorConstIteratorAdapter<ElementType> lineageOfType(const Element* first);
+template <typename ElementType> ElementAncestorIteratorAdapter<ElementType> ancestorsOfType(Element* descendant);
+template <typename ElementType> ElementAncestorConstIteratorAdapter<ElementType> ancestorsOfType(const Element* descendant);
+
+// ElementAncestorIterator
+
+template <typename ElementType>
+inline ElementAncestorIterator<ElementType>::ElementAncestorIterator()
+    : ElementIterator<ElementType>(nullptr)
+{
+}
+
+template <typename ElementType>
+inline ElementAncestorIterator<ElementType>::ElementAncestorIterator(ElementType* current)
+    : ElementIterator<ElementType>(nullptr, current)
+{
+}
+
+template <typename ElementType>
+inline ElementAncestorIterator<ElementType>& ElementAncestorIterator<ElementType>::operator++()
+{
+    return static_cast<ElementAncestorIterator<ElementType>&>(ElementIterator<ElementType>::traverseAncestor());
+}
+
+// ElementAncestorConstIterator
+
+template <typename ElementType>
+inline ElementAncestorConstIterator<ElementType>::ElementAncestorConstIterator()
+    : ElementConstIterator<ElementType>(nullptr)
+{
+}
+
+template <typename ElementType>
+inline ElementAncestorConstIterator<ElementType>::ElementAncestorConstIterator(const ElementType* current)
+    : ElementConstIterator<ElementType>(nullptr, current)
+{
+}
+
+template <typename ElementType>
+inline ElementAncestorConstIterator<ElementType>& ElementAncestorConstIterator<ElementType>::operator++()
+{
+    return static_cast<ElementAncestorConstIterator<ElementType>&>(ElementConstIterator<ElementType>::traverseAncestor());
+}
+
+// ElementAncestorIteratorAdapter
+
+template <typename ElementType>
+inline ElementAncestorIteratorAdapter<ElementType>::ElementAncestorIteratorAdapter(ElementType* first)
+    : m_first(first)
+{
+}
+
+template <typename ElementType>
+inline ElementAncestorIterator<ElementType> ElementAncestorIteratorAdapter<ElementType>::begin()
+{
+    return ElementAncestorIterator<ElementType>(m_first);
+}
+
+template <typename ElementType>
+inline ElementAncestorIterator<ElementType> ElementAncestorIteratorAdapter<ElementType>::end()
+{
+    return ElementAncestorIterator<ElementType>();
+}
+
+// ElementAncestorConstIteratorAdapter
+
+template <typename ElementType>
+inline ElementAncestorConstIteratorAdapter<ElementType>::ElementAncestorConstIteratorAdapter(const ElementType* first)
+    : m_first(first)
+{
+}
+
+template <typename ElementType>
+inline ElementAncestorConstIterator<ElementType> ElementAncestorConstIteratorAdapter<ElementType>::begin() const
+{
+    return ElementAncestorConstIterator<ElementType>(m_first);
+}
+
+template <typename ElementType>
+inline ElementAncestorConstIterator<ElementType> ElementAncestorConstIteratorAdapter<ElementType>::end() const
+{
+    return ElementAncestorConstIterator<ElementType>();
+}
+
+// Standalone functions
+
+inline ElementAncestorIteratorAdapter<Element> elementLineage(Element* first)
+{
+    return ElementAncestorIteratorAdapter<Element>(first);
+}
+
+inline ElementAncestorConstIteratorAdapter<Element> elementLineage(const Element* first)
+{
+    return ElementAncestorConstIteratorAdapter<Element>(first);
+}
+
+inline ElementAncestorIteratorAdapter<Element> elementAncestors(Element* descendant)
+{
+    return ElementAncestorIteratorAdapter<Element>(descendant->parentElement());
+}
+
+inline ElementAncestorConstIteratorAdapter<Element> elementAncestors(const Element* descendant)
+{
+    return ElementAncestorConstIteratorAdapter<Element>(descendant->parentElement());
+}
+
+template <typename ElementType>
+inline ElementAncestorIteratorAdapter<ElementType> lineageOfType(ElementType* first)
+{
+    return ElementAncestorIteratorAdapter<ElementType>(first);
+}
+
+template <typename ElementType>
+inline ElementAncestorConstIteratorAdapter<ElementType> lineageOfType(const ElementType* first)
+{
+    return ElementAncestorConstIteratorAdapter<ElementType>(first);
+}
+
+template <typename ElementType>
+inline ElementAncestorIteratorAdapter<ElementType> ancestorsOfType(Element* descendant)
+{
+    ElementType* first = findElementAncestorOfType<ElementType>(*descendant);
+    return ElementAncestorIteratorAdapter<ElementType>(first);
+}
+
+template <typename ElementType>
+inline ElementAncestorConstIteratorAdapter<ElementType> ancestorsOfType(const Element* descendant)
+{
+    const ElementType* first = findElementAncestorOfType<const ElementType>(*descendant);
+    return ElementAncestorConstIteratorAdapter<ElementType>(first);
+}
+
+}
+
+#endif
index 42680c5..a9dcd0c 100644 (file)
@@ -43,12 +43,14 @@ public:
     ElementType& operator*();
     ElementType* operator->();
 
+    bool operator==(const ElementIterator& other) const;
     bool operator!=(const ElementIterator& other) const;
 
     ElementIterator& traverseNext();
     ElementIterator& traversePrevious();
     ElementIterator& traverseNextSibling();
     ElementIterator& traversePreviousSibling();
+    ElementIterator& traverseAncestor();
 
 private:
     const ContainerNode* m_root;
@@ -68,12 +70,14 @@ public:
     const ElementType& operator*() const;
     const ElementType* operator->() const;
 
+    bool operator==(const ElementConstIterator& other) const;
     bool operator!=(const ElementConstIterator& other) const;
 
     ElementConstIterator& traverseNext();
     ElementConstIterator& traversePrevious();
     ElementConstIterator& traverseNextSibling();
     ElementConstIterator& traversePreviousSibling();
+    ElementConstIterator& traverseAncestor();
 
 private:
     const ContainerNode* m_root;
@@ -159,6 +163,37 @@ inline ElementIterator<ElementType>& ElementIterator<ElementType>::traversePrevi
     return *this;
 }
 
+template <typename ElementTypeWithConst>
+inline ElementTypeWithConst* findElementAncestorOfType(const Element& current)
+{
+    ContainerNode* ancestor = current.parentNode();
+    while (ancestor && ancestor->isElementNode()) {
+        // Non-root containers are always Elements.
+        Element* element = toElement(ancestor);
+        if (isElementOfType<ElementTypeWithConst>(element))
+            return static_cast<ElementTypeWithConst*>(element);
+        ancestor = ancestor->parentNode();
+    }
+    return nullptr;
+}
+
+template <typename ElementType>
+inline ElementIterator<ElementType>& ElementIterator<ElementType>::traverseAncestor()
+{
+    ASSERT(m_current);
+    ASSERT(m_current != m_root);
+    ASSERT(!m_assertions.domTreeHasMutated());
+
+    m_current = findElementAncestorOfType<ElementType>(*m_current);
+
+#if !ASSERT_DISABLED
+    // Drop the assertion when the iterator reaches the end.
+    if (!m_current)
+        m_assertions.dropEventDispatchAssertion();
+#endif
+    return *this;
+}
+
 template <typename ElementType>
 inline ElementType& ElementIterator<ElementType>::operator*()
 {
@@ -176,11 +211,17 @@ inline ElementType* ElementIterator<ElementType>::operator->()
 }
 
 template <typename ElementType>
-inline bool ElementIterator<ElementType>::operator!=(const ElementIterator& other) const
+inline bool ElementIterator<ElementType>::operator==(const ElementIterator& other) const
 {
     ASSERT(m_root == other.m_root);
     ASSERT(!m_assertions.domTreeHasMutated());
-    return m_current != other.m_current;
+    return m_current == other.m_current;
+}
+
+template <typename ElementType>
+inline bool ElementIterator<ElementType>::operator!=(const ElementIterator& other) const
+{
+    return !(*this == other);
 }
 
 // ElementConstIterator
@@ -259,6 +300,23 @@ inline ElementConstIterator<ElementType>& ElementConstIterator<ElementType>::tra
 }
 
 template <typename ElementType>
+inline ElementConstIterator<ElementType>& ElementConstIterator<ElementType>::traverseAncestor()
+{
+    ASSERT(m_current);
+    ASSERT(m_current != m_root);
+    ASSERT(!m_assertions.domTreeHasMutated());
+
+    m_current = findElementAncestorOfType<const ElementType>(*m_current);
+
+#if !ASSERT_DISABLED
+    // Drop the assertion when the iterator reaches the end.
+    if (!m_current)
+        m_assertions.dropEventDispatchAssertion();
+#endif
+    return *this;
+}
+
+template <typename ElementType>
 inline const ElementType& ElementConstIterator<ElementType>::operator*() const
 {
     ASSERT(m_current);
@@ -275,15 +333,22 @@ inline const ElementType* ElementConstIterator<ElementType>::operator->() const
 }
 
 template <typename ElementType>
-inline bool ElementConstIterator<ElementType>::operator!=(const ElementConstIterator& other) const
+inline bool ElementConstIterator<ElementType>::operator==(const ElementConstIterator& other) const
 {
     ASSERT(m_root == other.m_root);
     ASSERT(!m_assertions.domTreeHasMutated());
-    return m_current != other.m_current;
+    return m_current == other.m_current;
+}
+
+template <typename ElementType>
+inline bool ElementConstIterator<ElementType>::operator!=(const ElementConstIterator& other) const
+{
+    return !(*this == other);
 }
 
 }
 
+#include "ElementAncestorIterator.h"
 #include "ElementChildIterator.h"
 #include "ElementDescendantIterator.h"
 
index 8d6efe6..19615c2 100644 (file)
@@ -32,6 +32,7 @@
 #include "CSSValuePool.h"
 #include "DOMSettableTokenList.h"
 #include "DocumentFragment.h"
+#include "ElementIterator.h"
 #include "Event.h"
 #include "EventListener.h"
 #include "EventNames.h"
@@ -889,13 +890,13 @@ void HTMLElement::adjustDirectionalityIfNeededAfterChildAttributeChanged(Element
     Node* strongDirectionalityTextNode;
     TextDirection textDirection = directionality(&strongDirectionalityTextNode);
     setHasDirAutoFlagRecursively(child, false);
-    if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection) {
-        Element* elementToAdjust = this;
-        for (; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) {
-            if (elementAffectsDirectionality(elementToAdjust)) {
-                elementToAdjust->setNeedsStyleRecalc();
-                return;
-            }
+    if (!renderer() || !renderer()->style() || renderer()->style()->direction() == textDirection)
+        return;
+    auto lineage = elementLineage(this);
+    for (auto elementToAdjust = lineage.begin(), end = lineage.end(); elementToAdjust != end; ++elementToAdjust) {
+        if (elementAffectsDirectionality(&*elementToAdjust)) {
+            elementToAdjust->setNeedsStyleRecalc();
+            return;
         }
     }
 }
@@ -930,9 +931,10 @@ void HTMLElement::adjustDirectionalityIfNeededAfterChildrenChanged(Node* beforeC
     if (oldMarkedNode)
         setHasDirAutoFlagRecursively(oldMarkedNode, false);
 
-    for (Element* elementToAdjust = this; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) {
-        if (elementAffectsDirectionality(elementToAdjust)) {
-            toHTMLElement(elementToAdjust)->calculateAndAdjustDirectionality();
+    auto lineage = lineageOfType<HTMLElement>(this);
+    for (auto elementToAdjust = lineage.begin(), end = lineage.end(); elementToAdjust != end; ++elementToAdjust) {
+        if (elementAffectsDirectionality(&*elementToAdjust)) {
+            elementToAdjust->calculateAndAdjustDirectionality();
             return;
         }
     }
index 8a1ed1a..0c7f809 100644 (file)
@@ -63,6 +63,19 @@ private:
     mutable uint64_t m_documentVersion;
 };
 
+inline bool isHTMLFieldSetElement(const Node* node)
+{
+    return node->isElementNode() && toElement(node)->hasTagName(HTMLNames::fieldsetTag);
+}
+
+inline bool isHTMLFieldSetElement(const Element* element)
+{
+    return element->hasTagName(HTMLNames::fieldsetTag);
+}
+
+template <> inline bool isElementOfType<HTMLFieldSetElement>(const Element* element) { return isHTMLFieldSetElement(element); }
+
+
 } // namespace
 
 #endif
index 042bb64..8fd2d61 100644 (file)
@@ -27,6 +27,7 @@
 #include "Attribute.h"
 #include "CSSPropertyNames.h"
 #include "Document.h"
+#include "ElementIterator.h"
 #include "Event.h"
 #include "EventNames.h"
 #include "Frame.h"
@@ -163,13 +164,11 @@ RenderObject *HTMLFrameSetElement::createRenderer(RenderArena *arena, RenderStyl
     return new (arena) RenderFrameSet(this);
 }
 
-HTMLFrameSetElement* HTMLFrameSetElement::findContaining(Node* node)
+HTMLFrameSetElement* HTMLFrameSetElement::findContaining(Element* descendant)
 {
-    for (Element* parent = node->parentElement(); parent; parent = parent->parentElement()) {
-        if (isHTMLFrameSetElement(parent))
-            return toHTMLFrameSetElement(parent);
-    }
-    return 0;
+    auto ancestorFrameSets = ancestorsOfType<HTMLFrameSetElement>(descendant);
+    auto enclosingFrameSet = ancestorFrameSets.begin();
+    return enclosingFrameSet != ancestorFrameSets.end() ? &*enclosingFrameSet : nullptr;
 }
 
 void HTMLFrameSetElement::willAttachRenderers()
index 843faad..7dd931e 100644 (file)
@@ -45,7 +45,7 @@ public:
     const Length* rowLengths() const { return m_rowLengths.get(); }
     const Length* colLengths() const { return m_colLengths.get(); }
 
-    static HTMLFrameSetElement* findContaining(Node* descendant);
+    static HTMLFrameSetElement* findContaining(Element* descendant);
 
     // Declared virtual in Element
     DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(blur);
@@ -122,6 +122,8 @@ inline const HTMLFrameSetElement* toHTMLFrameSetElement(const Node* node)
     return static_cast<const HTMLFrameSetElement*>(node);
 }
 
+template <> inline bool isElementOfType<HTMLFrameSetElement>(const Element* element) { return isHTMLFrameSetElement(element); }
+
 } // namespace WebCore
 
 #endif // HTMLFrameSetElement_h
index 5072bbf..5b7660b 100644 (file)
@@ -443,12 +443,12 @@ private:
 #endif
 };
 
-inline bool isHTMLInputElement(Node* node)
+inline bool isHTMLInputElement(const Node* node)
 {
     return node->hasTagName(HTMLNames::inputTag);
 }
 
-inline bool isHTMLInputElement(Element* element)
+inline bool isHTMLInputElement(const Element* element)
 {
     return element->hasTagName(HTMLNames::inputTag);
 }
@@ -459,5 +459,11 @@ inline HTMLInputElement* toHTMLInputElement(Node* node)
     return static_cast<HTMLInputElement*>(node);
 }
 
+inline const HTMLInputElement* toHTMLInputElement(const Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLInputElement(node));
+    return static_cast<const HTMLInputElement*>(node);
+}
+
 } //namespace
 #endif
index 03b14e7..9a5588d 100644 (file)
@@ -25,7 +25,7 @@
 #include "config.h"
 #include "HTMLLegendElement.h"
 
-#include "ElementTraversal.h"
+#include "ElementIterator.h"
 #include "HTMLFieldSetElement.h"
 #include "HTMLFormControlElement.h"
 #include "HTMLNames.h"
@@ -49,21 +49,16 @@ PassRefPtr<HTMLLegendElement> HTMLLegendElement::create(const QualifiedName& tag
 HTMLFormControlElement* HTMLLegendElement::associatedControl()
 {
     // Check if there's a fieldset belonging to this legend.
-    Element* fieldset = parentElement();
-    while (fieldset && !fieldset->hasTagName(fieldsetTag))
-        fieldset = fieldset->parentElement();
-    if (!fieldset)
+    auto fieldsetAncestors = ancestorsOfType<HTMLFieldSetElement>(this);
+    auto enclosingFieldset = fieldsetAncestors.begin();
+    if (enclosingFieldset == fieldsetAncestors.end())
         return 0;
 
     // Find first form element inside the fieldset that is not a legend element.
     // FIXME: Should we consider tabindex?
-    Element* element = fieldset;
-    while ((element = ElementTraversal::next(element, fieldset))) {
-        if (element->isFormControlElement())
-            return static_cast<HTMLFormControlElement*>(element);
-    }
-
-    return 0;
+    auto fieldsetFormControlDescendants = descendantsOfType<HTMLFormControlElement>(&*enclosingFieldset);
+    auto firstFormControl = fieldsetFormControlDescendants.begin();
+    return firstFormControl != fieldsetFormControlDescendants.end() ? &*firstFormControl : nullptr;
 }
 
 void HTMLLegendElement::focus(bool, FocusDirection direction)