Add helpers for partial descendant traversal to element iterators
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 3 Nov 2013 11:13:53 +0000 (11:13 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 3 Nov 2013 11:13:53 +0000 (11:13 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123703

Reviewed by Andreas Kling.

* dom/ElementAncestorIterator.h:
(WebCore::lineageOfType):

    lineageOfType definition didn't match the declaration.

* dom/ElementDescendantIterator.h:
(WebCore::::find):
(WebCore::::from):

    Add find and from for getting begin iterator for partial traversals.

* editing/FrameSelection.cpp:
(WebCore::scanForForm):
(WebCore::FrameSelection::currentForm):
* html/HTMLFormElement.cpp:
(WebCore::HTMLFormElement::formElementIndex):
(WebCore::HTMLFormElement::findClosestFormAncestor):

    Use them in a few places.

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

Source/WebCore/ChangeLog
Source/WebCore/dom/ElementAncestorIterator.h
Source/WebCore/dom/ElementDescendantIterator.h
Source/WebCore/editing/FrameSelection.cpp
Source/WebCore/html/HTMLFormElement.cpp

index bc48453..bc570d1 100644 (file)
@@ -1,3 +1,30 @@
+2013-11-03  Antti Koivisto  <antti@apple.com>
+
+        Add helpers for partial descendant traversal to element iterators
+        https://bugs.webkit.org/show_bug.cgi?id=123703
+
+        Reviewed by Andreas Kling.
+
+        * dom/ElementAncestorIterator.h:
+        (WebCore::lineageOfType):
+        
+            lineageOfType definition didn't match the declaration.
+
+        * dom/ElementDescendantIterator.h:
+        (WebCore::::find):
+        (WebCore::::from):
+        
+            Add find and from for getting begin iterator for partial traversals.
+
+        * editing/FrameSelection.cpp:
+        (WebCore::scanForForm):
+        (WebCore::FrameSelection::currentForm):
+        * html/HTMLFormElement.cpp:
+        (WebCore::HTMLFormElement::formElementIndex):
+        (WebCore::HTMLFormElement::findClosestFormAncestor):
+        
+            Use them in a few places.
+
 2013-11-03  Andreas Kling  <akling@apple.com>
 
         Inline RenderStyle functions for getting/setting pseudo style bits.
index 8c48321..6125cb8 100644 (file)
@@ -182,15 +182,19 @@ inline ElementAncestorConstIteratorAdapter<Element> elementAncestors(const Eleme
 }
 
 template <typename ElementType>
-inline ElementAncestorIteratorAdapter<ElementType> lineageOfType(ElementType& first)
+inline ElementAncestorIteratorAdapter<ElementType> lineageOfType(Element& first)
 {
-    return ElementAncestorIteratorAdapter<ElementType>(&first);
+    if (isElementOfType<const ElementType>(first))
+        return ElementAncestorIteratorAdapter<ElementType>(static_cast<ElementType*>(&first));
+    return ancestorsOfType<ElementType>(first);
 }
 
 template <typename ElementType>
-inline ElementAncestorConstIteratorAdapter<ElementType> lineageOfType(const ElementType& first)
+inline ElementAncestorConstIteratorAdapter<ElementType> lineageOfType(const Element& first)
 {
-    return ElementAncestorConstIteratorAdapter<ElementType>(&first);
+    if (isElementOfType<const ElementType>(first))
+        return ElementAncestorConstIteratorAdapter<ElementType>(static_cast<const ElementType*>(&first));
+    return ancestorsOfType<ElementType>(first);
 }
 
 template <typename ElementType>
index 73e2abf..d48e41a 100644 (file)
@@ -52,6 +52,9 @@ public:
     ElementDescendantIteratorAdapter(ContainerNode& root);
     ElementDescendantIterator<ElementType> begin();
     ElementDescendantIterator<ElementType> end();
+    ElementDescendantIterator<ElementType> find(Element&);
+    ElementDescendantIterator<ElementType> from(Element&);
+
     ElementType* first();
     ElementType* last();
 
@@ -65,6 +68,9 @@ public:
     ElementDescendantConstIteratorAdapter(const ContainerNode& root);
     ElementDescendantConstIterator<ElementType> begin() const;
     ElementDescendantConstIterator<ElementType> end() const;
+    ElementDescendantConstIterator<ElementType> find(const Element&) const;
+    ElementDescendantConstIterator<ElementType> from(const Element&) const;
+
     const ElementType* first() const;
     const ElementType* last() const;
 
@@ -137,6 +143,26 @@ inline ElementDescendantIterator<ElementType> ElementDescendantIteratorAdapter<E
 {
     return ElementDescendantIterator<ElementType>(m_root);
 }
+    
+template <typename ElementType>
+inline ElementDescendantIterator<ElementType> ElementDescendantIteratorAdapter<ElementType>::find(Element& descendant)
+{
+    if (!isElementOfType<const ElementType>(descendant))
+        return end();
+    if (!descendant.isDescendantOf(&m_root))
+        return end();
+    return ElementDescendantIterator<ElementType>(m_root, static_cast<ElementType*>(&descendant));
+}
+
+template <typename ElementType>
+inline ElementDescendantIterator<ElementType> ElementDescendantIteratorAdapter<ElementType>::from(Element& descendant)
+{
+    ASSERT(descendant.isDescendantOf(&m_root));
+    if (isElementOfType<const ElementType>(descendant))
+        return ElementDescendantIterator<ElementType>(m_root, static_cast<ElementType*>(&descendant));
+    ElementType* next = Traversal<ElementType>::next(&m_root, &descendant);
+    return ElementDescendantIterator<ElementType>(m_root, next);
+}
 
 template <typename ElementType>
 inline ElementType* ElementDescendantIteratorAdapter<ElementType>::first()
@@ -171,6 +197,26 @@ inline ElementDescendantConstIterator<ElementType> ElementDescendantConstIterato
 }
 
 template <typename ElementType>
+inline ElementDescendantConstIterator<ElementType> ElementDescendantConstIteratorAdapter<ElementType>::find(const Element& descendant) const
+{
+    if (!isElementOfType<const ElementType>(descendant))
+        return end();
+    if (!descendant.isDescendantOf(&m_root))
+        return end();
+    return ElementDescendantConstIterator<ElementType>(m_root, static_cast<const ElementType*>(&descendant));
+}
+
+template <typename ElementType>
+inline ElementDescendantConstIterator<ElementType> ElementDescendantConstIteratorAdapter<ElementType>::from(const Element& descendant) const
+{
+    ASSERT(descendant.isDescendantOf(&m_root));
+    if (isElementOfType<const ElementType>(descendant))
+        return ElementDescendantConstIterator<ElementType>(m_root, static_cast<const ElementType*>(&descendant));
+    const ElementType* next = Traversal<ElementType>::next(&m_root, &descendant);
+    return ElementDescendantConstIterator<ElementType>(m_root, next);
+}
+
+template <typename ElementType>
 inline const ElementType* ElementDescendantConstIteratorAdapter<ElementType>::first() const
 {
     return Traversal<ElementType>::firstWithin(&m_root);
index 3598a79..c0d75f1 100644 (file)
@@ -32,7 +32,7 @@
 #include "Editor.h"
 #include "EditorClient.h"
 #include "Element.h"
-#include "ElementTraversal.h"
+#include "ElementIterator.h"
 #include "EventHandler.h"
 #include "ExceptionCode.h"
 #include "FloatQuad.h"
@@ -1949,39 +1949,40 @@ void FrameSelection::getClippedVisibleTextRectangles(Vector<FloatRect>& rectangl
 }
 
 // Scans logically forward from "start", including any child frames.
-static HTMLFormElement* scanForForm(Node* start)
+static HTMLFormElement* scanForForm(Element* start)
 {
     if (!start)
-        return 0;
-    HTMLElement* element = start->isHTMLElement() ? toHTMLElement(start) : Traversal<HTMLElement>::next(start);
-    for (; element; element = Traversal<HTMLElement>::next(element)) {
-        if (isHTMLFormElement(element))
-            return toHTMLFormElement(element);
-        if (element->isFormControlElement())
-            return static_cast<HTMLFormControlElement*>(element)->form();
-        if (element->hasTagName(frameTag) || element->hasTagName(iframeTag))
-            if (HTMLFormElement* frameResult = scanForForm(toHTMLFrameElementBase(element)->contentDocument()))
+        return nullptr;
+
+    auto descendants = descendantsOfType<HTMLElement>(start->document());
+    for (auto it = descendants.from(*start), end = descendants.end(); it != end; ++it) {
+        HTMLElement& element = *it;
+        if (isHTMLFormElement(&element))
+            return toHTMLFormElement(&element);
+        if (element.isFormControlElement())
+            return static_cast<HTMLFormControlElement&>(element).form();
+        if (element.hasTagName(frameTag) || element.hasTagName(iframeTag)) {
+            if (HTMLFormElement* frameResult = scanForForm(toHTMLFrameElementBase(element).contentDocument()->documentElement()))
                 return frameResult;
+        }
     }
-    return 0;
+    return nullptr;
 }
 
 // We look for either the form containing the current focus, or for one immediately after it
 HTMLFormElement* FrameSelection::currentForm() const
 {
     // Start looking either at the active (first responder) node, or where the selection is.
-    Node* start = m_frame->document()->focusedElement();
+    Element* start = m_frame->document()->focusedElement();
     if (!start)
-        start = this->start().deprecatedNode();
-
-    // Try walking up the node tree to find a form element.
-    Node* node;
-    for (node = start; node; node = node->parentNode()) {
-        if (isHTMLFormElement(node))
-            return toHTMLFormElement(node);
-        if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
-            return static_cast<HTMLFormControlElement*>(node)->form();
-    }
+        start = this->start().element();
+    if (!start)
+        return nullptr;
+
+    if (auto form = lineageOfType<HTMLFormElement>(*start).first())
+        return form;
+    if (auto formControl = lineageOfType<HTMLFormControlElement>(*start).first())
+        return formControl->form();
 
     // Try walking forward in the node tree to find a form element.
     return scanForForm(start);
index 958903e..8b4307e 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "Attribute.h"
 #include "Document.h"
-#include "ElementTraversal.h"
+#include "ElementIterator.h"
 #include "Event.h"
 #include "EventNames.h"
 #include "FormController.h"
@@ -462,25 +462,31 @@ unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElem
             return HTMLFormElement::formElementIndexWithFormAttribute(&associatedHTMLElement, m_associatedElementsAfterIndex, m_associatedElements.size());
     }
 
+    unsigned currentAssociatedElementsAfterIndex = m_associatedElementsAfterIndex;
+    ++m_associatedElementsAfterIndex;
+
     // Check for the special case where this element is the very last thing in
     // the form's tree of children; we don't want to walk the entire tree in that
     // common case that occurs during parsing; instead we'll just return a value
     // that says "add this form element to the end of the array".
-    if (ElementTraversal::next(&associatedHTMLElement, this)) {
-        unsigned i = m_associatedElementsBeforeIndex;
-        for (Element* element = this; element; element = ElementTraversal::next(element, this)) {
-            if (element == &associatedHTMLElement) {
-                ++m_associatedElementsAfterIndex;
-                return i;
-            }
-            if (!element->isFormControlElement() && !element->hasTagName(objectTag))
-                continue;
-            if (!element->isHTMLElement() || toHTMLElement(element)->form() != this)
-                continue;
-            ++i;
-        }
+    auto descendants = descendantsOfType<HTMLElement>(*this);
+    auto it = descendants.find(associatedHTMLElement);
+    auto end = descendants.end();
+    if (it == end || ++it == end)
+        return currentAssociatedElementsAfterIndex;
+
+    unsigned i = m_associatedElementsBeforeIndex;
+    for (auto it = descendants.begin(); it != end; ++it) {
+        HTMLElement& element = *it;
+        if (&element == &associatedHTMLElement)
+            return i;
+        if (!element.isFormControlElement() && !element.hasTagName(objectTag))
+            continue;
+        if (element.form() != this)
+            continue;
+        ++i;
     }
-    return m_associatedElementsAfterIndex++;
+    return currentAssociatedElementsAfterIndex;
 }
 
 void HTMLFormElement::registerFormElement(FormAssociatedElement* e)
@@ -727,11 +733,7 @@ void HTMLFormElement::copyNonAttributePropertiesFromElement(const Element& sourc
 
 HTMLFormElement* HTMLFormElement::findClosestFormAncestor(const Element& startElement)
 {
-    for (Element* element = startElement.parentElement(); element; element = element->parentElement()) {
-        if (isHTMLFormElement(element))
-            return toHTMLFormElement(element);
-    }
-    return 0;
+    return const_cast<HTMLFormElement*>(ancestorsOfType<HTMLFormElement>(startElement).first());
 }
 
 } // namespace