Changeset 154940 in webkit


Ignore:
Timestamp:
Sep 1, 2013 3:33:08 AM (11 years ago)
Author:
Antti Koivisto
Message:

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):

Location:
trunk/Source/WebCore
Files:
1 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r154939 r154940  
     12013-08-31  Antti Koivisto  <antti@apple.com>
     2
     3        Add element ancestor iterator
     4        https://bugs.webkit.org/show_bug.cgi?id=120563
     5
     6        Reviewed by Andreas Kling.
     7
     8        This patch adds ancestor iterators. They iterate over elements parent chain up to the root.
     9       
     10        To iterate over Element ancestors:
     11       
     12        auto ancestors = elementAncestors(this);
     13        for (auto it = ancestors.begin(), end = ancestors.end(); it != end; ++it) {
     14            Element& element = *it;
     15            ...
     16
     17        To iterate over Element ancestors including the current element:
     18       
     19        auto lineage = elementLineage(this);
     20        for (auto it = lineage.begin(), end = lineage.end(); it != end; ++it) {
     21            Element& element = *it;
     22            ...
     23           
     24        To iterate over ancestors of a specific Element subclass:
     25
     26        auto htmlAncestors = ancestorsOfType<HTMLElement>(this);
     27        for (auto it = htmlAncestors.begin(), end = htmlAncestors.end(); it != end; ++it) {
     28            HTMLElement& htmlElement = *it;
     29            ...
     30           
     31        To iterate over ancestors of a specific Element subclass including the current element:
     32
     33        auto htmlLineage = lineageOfType<HTMLElement>(this);
     34        for (auto it = htmlLineage.begin(), end = htmlLineage.end(); it != end; ++it) {
     35            HTMLElement& htmlElement = *it;
     36            ...
     37           
     38        The patch also uses the new types in a few places.
     39
     40        * WebCore.xcodeproj/project.pbxproj:
     41        * accessibility/AccessibilityNodeObject.cpp:
     42        (WebCore::AccessibilityNodeObject::mouseButtonListener):
     43        (WebCore::AccessibilityNodeObject::labelForElement):
     44        * dom/ElementAncestorIterator.h: Added.
     45        (WebCore::::ElementAncestorIterator):
     46        (WebCore::::operator):
     47        (WebCore::::ElementAncestorConstIterator):
     48        (WebCore::::ElementAncestorIteratorAdapter):
     49        (WebCore::::begin):
     50        (WebCore::::end):
     51        (WebCore::::ElementAncestorConstIteratorAdapter):
     52        (WebCore::elementLineage):
     53        (WebCore::elementAncestors):
     54        (WebCore::ancestorsOfType):
     55        * dom/ElementIterator.h:
     56        (WebCore::findElementAncestorOfType):
     57        (WebCore::::traverseAncestor):
     58        (WebCore::=):
     59        * html/HTMLElement.cpp:
     60        (WebCore::HTMLElement::adjustDirectionalityIfNeededAfterChildAttributeChanged):
     61        * html/HTMLFieldSetElement.h:
     62        (WebCore::isHTMLFieldSetElement):
     63        (WebCore::HTMLFieldSetElement):
     64        * html/HTMLFrameSetElement.cpp:
     65        (WebCore::HTMLFrameSetElement::findContaining):
     66        * html/HTMLFrameSetElement.h:
     67        (WebCore::HTMLFrameSetElement):
     68        * html/HTMLInputElement.h:
     69        (WebCore::isHTMLInputElement):
     70        (WebCore::toHTMLInputElement):
     71        * html/HTMLLegendElement.cpp:
     72        (WebCore::HTMLLegendElement::associatedControl):
     73
    1742013-08-31  Darin Adler  <darin@apple.com>
    275
  • trunk/Source/WebCore/GNUmakefile.list.am

    r154928 r154940  
    28702870        Source/WebCore/dom/Element.cpp \
    28712871        Source/WebCore/dom/Element.h \
     2872        Source/WebCore/dom/ElementAncestorIterator.h \
    28722873        Source/WebCore/dom/ElementChildIterator.h \
    28732874        Source/WebCore/dom/ElementData.cpp \
  • trunk/Source/WebCore/Target.pri

    r154928 r154940  
    16111611    dom/DatasetDOMStringMap.h \
    16121612    dom/Element.h \
     1613    dom/ElementAncestorIterator.h \
    16131614    dom/ElementChildIterator.h \
    16141615    dom/ElementData.h \
  • trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj

    r154928 r154940  
    1 <?xml version="1.0" encoding="utf-8"?>
     1<?xml version="1.0" encoding="utf-8"?>
    22<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    33  <ItemGroup Label="ProjectConfigurations">
     
    2026320263    <ClInclude Include="..\dom\DOMTimeStamp.h" />
    2026420264    <ClInclude Include="..\dom\Element.h" />
     20265    <ClInclude Include="..\dom\ElementAncestorIterator.h" />
    2026520266    <ClInclude Include="..\dom\ElementChildIterator.h" />
    2026620267    <ClInclude Include="..\dom\ElementData.h" />
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r154928 r154940  
    55075507                E49BDA0B131FD3E5003C56F0 /* CSSValuePool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E49BDA0A131FD3E5003C56F0 /* CSSValuePool.cpp */; };
    55085508                E4AE7C1617D1BB950009FB31 /* ElementIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1517D1BB950009FB31 /* ElementIterator.h */; };
     5509                E4AE7C1A17D232350009FB31 /* ElementAncestorIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */; };
    55095510                E4AFCFA50DAF29A300F5F55C /* UnitBezier.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AFCFA40DAF29A300F5F55C /* UnitBezier.h */; };
    55105511                E4AFD00B0DAF335400F5F55C /* SMILTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4AFD0050DAF335400F5F55C /* SMILTime.cpp */; };
     
    1228112282                E49BDA0A131FD3E5003C56F0 /* CSSValuePool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSValuePool.cpp; sourceTree = "<group>"; };
    1228212283                E4AE7C1517D1BB950009FB31 /* ElementIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementIterator.h; sourceTree = "<group>"; };
     12284                E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementAncestorIterator.h; sourceTree = "<group>"; };
    1228312285                E4AFCFA40DAF29A300F5F55C /* UnitBezier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnitBezier.h; sourceTree = "<group>"; };
    1228412286                E4AFD0050DAF335400F5F55C /* SMILTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SMILTime.cpp; sourceTree = "<group>"; };
     
    2022420226                                A8C4A7F509D563270003AC8D /* Element.h */,
    2022520227                                93EEC1EA09C2877700C515D1 /* Element.idl */,
     20228                                E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */,
    2022620229                                E46A2B1D17CA76B1000DBCD8 /* ElementChildIterator.h */,
    2022720230                                B5B7A16F17C1080600E4AA0A /* ElementData.cpp */,
     
    2222622229                                59A86008119DAFA100DEF1EF /* JSDeviceOrientationEvent.h in Headers */,
    2222722230                                BCE4389C140B1BA8005E437E /* JSDictionary.h in Headers */,
     22231                                E4AE7C1A17D232350009FB31 /* ElementAncestorIterator.h in Headers */,
    2222822232                                8987858B122CA26A003AABDA /* JSDirectoryEntry.h in Headers */,
    2222922233                                893C483312495472002B3D86 /* JSDirectoryEntrySync.h in Headers */,
  • trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp

    r154928 r154940  
    978978
    979979    // check if our parent is a mouse button listener
    980     while (node && !node->isElementNode())
    981         node = node->parentNode();
    982 
    983     if (!node)
    984         return 0;
    985 
    986980    // FIXME: Do the continuation search like anchorElement does
    987     for (Element* element = toElement(node); element; element = element->parentElement()) {
     981    auto lineage = elementLineage(node->isElementNode() ? toElement(node) : node->parentElement());
     982    for (auto element = lineage.begin(), end = lineage.end(); element != end; ++element) {
    988983        // If we've reached the body and this is not a control element, do not expose press action for this element.
    989984        // It can cause false positives, where every piece of text is labeled as accepting press actions.
     
    992987       
    993988        if (element->hasEventListeners(eventNames().clickEvent) || element->hasEventListeners(eventNames().mousedownEvent) || element->hasEventListeners(eventNames().mouseupEvent))
    994             return element;
     989            return &*element;
    995990    }
    996991
     
    11001095    }
    11011096
    1102     for (Element* parent = element->parentElement(); parent; parent = parent->parentElement()) {
    1103         if (isHTMLLabelElement(parent))
    1104             return toHTMLLabelElement(parent);
    1105     }
    1106 
    1107     return 0;
     1097    auto labelAncestors = ancestorsOfType<HTMLLabelElement>(element);
     1098    auto enclosingLabel = labelAncestors.begin();
     1099    return enclosingLabel != labelAncestors.end() ? &*enclosingLabel : nullptr;
    11081100}
    11091101
  • trunk/Source/WebCore/dom/ElementIterator.h

    r154928 r154940  
    4444    ElementType* operator->();
    4545
     46    bool operator==(const ElementIterator& other) const;
    4647    bool operator!=(const ElementIterator& other) const;
    4748
     
    5051    ElementIterator& traverseNextSibling();
    5152    ElementIterator& traversePreviousSibling();
     53    ElementIterator& traverseAncestor();
    5254
    5355private:
     
    6971    const ElementType* operator->() const;
    7072
     73    bool operator==(const ElementConstIterator& other) const;
    7174    bool operator!=(const ElementConstIterator& other) const;
    7275
     
    7578    ElementConstIterator& traverseNextSibling();
    7679    ElementConstIterator& traversePreviousSibling();
     80    ElementConstIterator& traverseAncestor();
    7781
    7882private:
     
    160164}
    161165
     166template <typename ElementTypeWithConst>
     167inline ElementTypeWithConst* findElementAncestorOfType(const Element& current)
     168{
     169    ContainerNode* ancestor = current.parentNode();
     170    while (ancestor && ancestor->isElementNode()) {
     171        // Non-root containers are always Elements.
     172        Element* element = toElement(ancestor);
     173        if (isElementOfType<ElementTypeWithConst>(element))
     174            return static_cast<ElementTypeWithConst*>(element);
     175        ancestor = ancestor->parentNode();
     176    }
     177    return nullptr;
     178}
     179
     180template <typename ElementType>
     181inline ElementIterator<ElementType>& ElementIterator<ElementType>::traverseAncestor()
     182{
     183    ASSERT(m_current);
     184    ASSERT(m_current != m_root);
     185    ASSERT(!m_assertions.domTreeHasMutated());
     186
     187    m_current = findElementAncestorOfType<ElementType>(*m_current);
     188
     189#if !ASSERT_DISABLED
     190    // Drop the assertion when the iterator reaches the end.
     191    if (!m_current)
     192        m_assertions.dropEventDispatchAssertion();
     193#endif
     194    return *this;
     195}
     196
    162197template <typename ElementType>
    163198inline ElementType& ElementIterator<ElementType>::operator*()
     
    177212
    178213template <typename ElementType>
     214inline bool ElementIterator<ElementType>::operator==(const ElementIterator& other) const
     215{
     216    ASSERT(m_root == other.m_root);
     217    ASSERT(!m_assertions.domTreeHasMutated());
     218    return m_current == other.m_current;
     219}
     220
     221template <typename ElementType>
    179222inline bool ElementIterator<ElementType>::operator!=(const ElementIterator& other) const
    180223{
    181     ASSERT(m_root == other.m_root);
    182     ASSERT(!m_assertions.domTreeHasMutated());
    183     return m_current != other.m_current;
     224    return !(*this == other);
    184225}
    185226
     
    260301
    261302template <typename ElementType>
     303inline ElementConstIterator<ElementType>& ElementConstIterator<ElementType>::traverseAncestor()
     304{
     305    ASSERT(m_current);
     306    ASSERT(m_current != m_root);
     307    ASSERT(!m_assertions.domTreeHasMutated());
     308
     309    m_current = findElementAncestorOfType<const ElementType>(*m_current);
     310
     311#if !ASSERT_DISABLED
     312    // Drop the assertion when the iterator reaches the end.
     313    if (!m_current)
     314        m_assertions.dropEventDispatchAssertion();
     315#endif
     316    return *this;
     317}
     318
     319template <typename ElementType>
    262320inline const ElementType& ElementConstIterator<ElementType>::operator*() const
    263321{
     
    276334
    277335template <typename ElementType>
     336inline bool ElementConstIterator<ElementType>::operator==(const ElementConstIterator& other) const
     337{
     338    ASSERT(m_root == other.m_root);
     339    ASSERT(!m_assertions.domTreeHasMutated());
     340    return m_current == other.m_current;
     341}
     342
     343template <typename ElementType>
    278344inline bool ElementConstIterator<ElementType>::operator!=(const ElementConstIterator& other) const
    279345{
    280     ASSERT(m_root == other.m_root);
    281     ASSERT(!m_assertions.domTreeHasMutated());
    282     return m_current != other.m_current;
    283 }
    284 
    285 }
    286 
     346    return !(*this == other);
     347}
     348
     349}
     350
     351#include "ElementAncestorIterator.h"
    287352#include "ElementChildIterator.h"
    288353#include "ElementDescendantIterator.h"
  • trunk/Source/WebCore/html/HTMLElement.cpp

    r154877 r154940  
    3333#include "DOMSettableTokenList.h"
    3434#include "DocumentFragment.h"
     35#include "ElementIterator.h"
    3536#include "Event.h"
    3637#include "EventListener.h"
     
    890891    TextDirection textDirection = directionality(&strongDirectionalityTextNode);
    891892    setHasDirAutoFlagRecursively(child, false);
    892     if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection) {
    893         Element* elementToAdjust = this;
    894         for (; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) {
    895             if (elementAffectsDirectionality(elementToAdjust)) {
    896                 elementToAdjust->setNeedsStyleRecalc();
    897                 return;
    898             }
     893    if (!renderer() || !renderer()->style() || renderer()->style()->direction() == textDirection)
     894        return;
     895    auto lineage = elementLineage(this);
     896    for (auto elementToAdjust = lineage.begin(), end = lineage.end(); elementToAdjust != end; ++elementToAdjust) {
     897        if (elementAffectsDirectionality(&*elementToAdjust)) {
     898            elementToAdjust->setNeedsStyleRecalc();
     899            return;
    899900        }
    900901    }
     
    931932        setHasDirAutoFlagRecursively(oldMarkedNode, false);
    932933
    933     for (Element* elementToAdjust = this; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) {
    934         if (elementAffectsDirectionality(elementToAdjust)) {
    935             toHTMLElement(elementToAdjust)->calculateAndAdjustDirectionality();
     934    auto lineage = lineageOfType<HTMLElement>(this);
     935    for (auto elementToAdjust = lineage.begin(), end = lineage.end(); elementToAdjust != end; ++elementToAdjust) {
     936        if (elementAffectsDirectionality(&*elementToAdjust)) {
     937            elementToAdjust->calculateAndAdjustDirectionality();
    936938            return;
    937939        }
  • trunk/Source/WebCore/html/HTMLFieldSetElement.h

    r154769 r154940  
    6464};
    6565
     66inline bool isHTMLFieldSetElement(const Node* node)
     67{
     68    return node->isElementNode() && toElement(node)->hasTagName(HTMLNames::fieldsetTag);
     69}
     70
     71inline bool isHTMLFieldSetElement(const Element* element)
     72{
     73    return element->hasTagName(HTMLNames::fieldsetTag);
     74}
     75
     76template <> inline bool isElementOfType<HTMLFieldSetElement>(const Element* element) { return isHTMLFieldSetElement(element); }
     77
     78
    6679} // namespace
    6780
  • trunk/Source/WebCore/html/HTMLFrameSetElement.cpp

    r154877 r154940  
    2828#include "CSSPropertyNames.h"
    2929#include "Document.h"
     30#include "ElementIterator.h"
    3031#include "Event.h"
    3132#include "EventNames.h"
     
    164165}
    165166
    166 HTMLFrameSetElement* HTMLFrameSetElement::findContaining(Node* node)
    167 {
    168     for (Element* parent = node->parentElement(); parent; parent = parent->parentElement()) {
    169         if (isHTMLFrameSetElement(parent))
    170             return toHTMLFrameSetElement(parent);
    171     }
    172     return 0;
     167HTMLFrameSetElement* HTMLFrameSetElement::findContaining(Element* descendant)
     168{
     169    auto ancestorFrameSets = ancestorsOfType<HTMLFrameSetElement>(descendant);
     170    auto enclosingFrameSet = ancestorFrameSets.begin();
     171    return enclosingFrameSet != ancestorFrameSets.end() ? &*enclosingFrameSet : nullptr;
    173172}
    174173
  • trunk/Source/WebCore/html/HTMLFrameSetElement.h

    r154358 r154940  
    4646    const Length* colLengths() const { return m_colLengths.get(); }
    4747
    48     static HTMLFrameSetElement* findContaining(Node* descendant);
     48    static HTMLFrameSetElement* findContaining(Element* descendant);
    4949
    5050    // Declared virtual in Element
     
    123123}
    124124
     125template <> inline bool isElementOfType<HTMLFrameSetElement>(const Element* element) { return isHTMLFrameSetElement(element); }
     126
    125127} // namespace WebCore
    126128
  • trunk/Source/WebCore/html/HTMLInputElement.h

    r154358 r154940  
    444444};
    445445
    446 inline bool isHTMLInputElement(Node* node)
     446inline bool isHTMLInputElement(const Node* node)
    447447{
    448448    return node->hasTagName(HTMLNames::inputTag);
    449449}
    450450
    451 inline bool isHTMLInputElement(Element* element)
     451inline bool isHTMLInputElement(const Element* element)
    452452{
    453453    return element->hasTagName(HTMLNames::inputTag);
     
    460460}
    461461
     462inline const HTMLInputElement* toHTMLInputElement(const Node* node)
     463{
     464    ASSERT_WITH_SECURITY_IMPLICATION(!node || isHTMLInputElement(node));
     465    return static_cast<const HTMLInputElement*>(node);
     466}
     467
    462468} //namespace
    463469#endif
  • trunk/Source/WebCore/html/HTMLLegendElement.cpp

    r153939 r154940  
    2626#include "HTMLLegendElement.h"
    2727
    28 #include "ElementTraversal.h"
     28#include "ElementIterator.h"
    2929#include "HTMLFieldSetElement.h"
    3030#include "HTMLFormControlElement.h"
     
    5050{
    5151    // Check if there's a fieldset belonging to this legend.
    52     Element* fieldset = parentElement();
    53     while (fieldset && !fieldset->hasTagName(fieldsetTag))
    54         fieldset = fieldset->parentElement();
    55     if (!fieldset)
     52    auto fieldsetAncestors = ancestorsOfType<HTMLFieldSetElement>(this);
     53    auto enclosingFieldset = fieldsetAncestors.begin();
     54    if (enclosingFieldset == fieldsetAncestors.end())
    5655        return 0;
    5756
    5857    // Find first form element inside the fieldset that is not a legend element.
    5958    // FIXME: Should we consider tabindex?
    60     Element* element = fieldset;
    61     while ((element = ElementTraversal::next(element, fieldset))) {
    62         if (element->isFormControlElement())
    63             return static_cast<HTMLFormControlElement*>(element);
    64     }
    65 
    66     return 0;
     59    auto fieldsetFormControlDescendants = descendantsOfType<HTMLFormControlElement>(&*enclosingFieldset);
     60    auto firstFormControl = fieldsetFormControlDescendants.begin();
     61    return firstFormControl != fieldsetFormControlDescendants.end() ? &*firstFormControl : nullptr;
    6762}
    6863
Note: See TracChangeset for help on using the changeset viewer.