Element child and descendant iterators
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 25 Aug 2013 21:30:10 +0000 (21:30 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 25 Aug 2013 21:30:10 +0000 (21:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=120248

Reviewed by Sam Weinig and Andreas Kling.

Add iterators for Element children and descendants.

To iterate over element children:

#include "ChildIterator.h"

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

for (auto it = childrenOfType<HTMLAreaElement>(this).begin(), end = childrenOfType<HTMLAreaElement>(this).end(); it != end; ++it) {
    HTMLAreaElement& area = *it;
    ...

To iteratate over element descendants in pre-order:

#include "DescendantIterator.h"

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

for (auto it = descendantsOfType<HTMLAreaElement>(this).begin(), end = descendantsOfType<HTMLAreaElement>(this).end(); it != end; ++it) {
    HTMLAreaElement& area = *it;
    ...

The iterators assert against DOM mutations and event dispatch while iterating in debug builds.

They are compatible with C++11 range-based for loops. In the future we can use

for (auto& element : elementChildren(this))
    ...

etc.

The patch all uses the new iterators in a few places.

* WebCore.xcodeproj/project.pbxproj:
* accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::canvasHasFallbackContent):
(WebCore::siblingWithAriaRole):
* accessibility/AccessibilityRenderObject.cpp:
* accessibility/AccessibilityTable.cpp:
(WebCore::AccessibilityTable::isDataTable):
* dom/ChildIterator.h: Added.
(WebCore::ChildIterator::operator*):
(WebCore::ChildIterator::operator->):
(WebCore::::ChildIterator):
(WebCore::::operator):
(WebCore::=):
(WebCore::::ChildIteratorAdapter):
(WebCore::::begin):
(WebCore::::end):
(WebCore::elementChildren):
(WebCore::childrenOfType):
* dom/DescendantIterator.h: Added.
(WebCore::DescendantIterator::operator*):
(WebCore::DescendantIterator::operator->):
(WebCore::::DescendantIterator):
(WebCore::::operator):
(WebCore::=):
(WebCore::::DescendantIteratorAdapter):
(WebCore::::begin):
(WebCore::::end):
(WebCore::elementDescendants):
(WebCore::descendantsOfType):
* dom/Document.cpp:
(WebCore::Document::buildAccessKeyMap):
(WebCore::Document::childrenChanged):
(WebCore::Document::attach):
(WebCore::Document::detach):
* editing/ApplyStyleCommand.cpp:
(WebCore::ApplyStyleCommand::cleanupUnstyledAppleStyleSpans):
* editing/markup.cpp:
(WebCore::completeURLs):
* html/HTMLMapElement.cpp:
(WebCore::HTMLMapElement::mapMouseEvent):
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::selectMediaResource):
(WebCore::HTMLMediaElement::textTrackModeChanged):

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

15 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/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/accessibility/AccessibilityTable.cpp
Source/WebCore/dom/ChildIterator.h [new file with mode: 0644]
Source/WebCore/dom/DescendantIterator.h [new file with mode: 0644]
Source/WebCore/dom/Document.cpp
Source/WebCore/editing/ApplyStyleCommand.cpp
Source/WebCore/editing/markup.cpp
Source/WebCore/html/HTMLMapElement.cpp
Source/WebCore/html/HTMLMediaElement.cpp

index 23f4ef1..70baca9 100644 (file)
@@ -1,3 +1,91 @@
+2013-08-25  Antti Koivisto  <antti@apple.com>
+
+        Element child and descendant iterators
+        https://bugs.webkit.org/show_bug.cgi?id=120248
+
+        Reviewed by Sam Weinig and Andreas Kling.
+
+        Add iterators for Element children and descendants.
+        
+        To iterate over element children:
+        
+        #include "ChildIterator.h"
+        
+        for (auto it = elementChildren(this).begin(), end = elementChildren(this).end(); it != end; ++it) {
+            Element& element = *it;
+            ...
+
+        for (auto it = childrenOfType<HTMLAreaElement>(this).begin(), end = childrenOfType<HTMLAreaElement>(this).end(); it != end; ++it) {
+            HTMLAreaElement& area = *it;
+            ...
+
+        To iteratate over element descendants in pre-order:
+        
+        #include "DescendantIterator.h"
+        
+        for (auto it = elementDescendants(this).begin(), end = elementDescendants(this).end(); it != end; ++it) {
+            Element& element = *it;
+            ...
+
+        for (auto it = descendantsOfType<HTMLAreaElement>(this).begin(), end = descendantsOfType<HTMLAreaElement>(this).end(); it != end; ++it) {
+            HTMLAreaElement& area = *it;
+            ...
+            
+        The iterators assert against DOM mutations and event dispatch while iterating in debug builds.
+            
+        They are compatible with C++11 range-based for loops. In the future we can use
+        
+        for (auto& element : elementChildren(this))
+            ...
+
+        etc.
+        
+        The patch all uses the new iterators in a few places.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * accessibility/AccessibilityNodeObject.cpp:
+        (WebCore::AccessibilityNodeObject::canvasHasFallbackContent):
+        (WebCore::siblingWithAriaRole):
+        * accessibility/AccessibilityRenderObject.cpp:
+        * accessibility/AccessibilityTable.cpp:
+        (WebCore::AccessibilityTable::isDataTable):
+        * dom/ChildIterator.h: Added.
+        (WebCore::ChildIterator::operator*):
+        (WebCore::ChildIterator::operator->):
+        (WebCore::::ChildIterator):
+        (WebCore::::operator):
+        (WebCore::=):
+        (WebCore::::ChildIteratorAdapter):
+        (WebCore::::begin):
+        (WebCore::::end):
+        (WebCore::elementChildren):
+        (WebCore::childrenOfType):
+        * dom/DescendantIterator.h: Added.
+        (WebCore::DescendantIterator::operator*):
+        (WebCore::DescendantIterator::operator->):
+        (WebCore::::DescendantIterator):
+        (WebCore::::operator):
+        (WebCore::=):
+        (WebCore::::DescendantIteratorAdapter):
+        (WebCore::::begin):
+        (WebCore::::end):
+        (WebCore::elementDescendants):
+        (WebCore::descendantsOfType):
+        * dom/Document.cpp:
+        (WebCore::Document::buildAccessKeyMap):
+        (WebCore::Document::childrenChanged):
+        (WebCore::Document::attach):
+        (WebCore::Document::detach):
+        * editing/ApplyStyleCommand.cpp:
+        (WebCore::ApplyStyleCommand::cleanupUnstyledAppleStyleSpans):
+        * editing/markup.cpp:
+        (WebCore::completeURLs):
+        * html/HTMLMapElement.cpp:
+        (WebCore::HTMLMapElement::mapMouseEvent):
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::selectMediaResource):
+        (WebCore::HTMLMediaElement::textTrackModeChanged):
+
 2013-08-25  Andreas Kling  <akling@apple.com>
 
         RenderObject::document() should return a reference.
index 4a0164e..a064204 100644 (file)
@@ -2771,6 +2771,7 @@ webcore_sources += \
        Source/WebCore/dom/CharacterData.h \
        Source/WebCore/dom/CheckedRadioButtons.cpp \
        Source/WebCore/dom/CheckedRadioButtons.h \
+       Source/WebCore/dom/ChildIterator.h \
        Source/WebCore/dom/ChildListMutationScope.cpp \
        Source/WebCore/dom/ChildListMutationScope.h \
        Source/WebCore/dom/ChildNodeList.cpp \
@@ -2815,6 +2816,7 @@ webcore_sources += \
        Source/WebCore/dom/DecodedDataDocumentParser.h \
        Source/WebCore/dom/default/PlatformMessagePortChannel.cpp \
        Source/WebCore/dom/default/PlatformMessagePortChannel.h \
+       Source/WebCore/dom/DescendantIterator.h \
        Source/WebCore/dom/DeviceMotionClient.h \
        Source/WebCore/dom/DeviceMotionController.cpp \
        Source/WebCore/dom/DeviceMotionController.h \
index d8c998c..1d3a876 100644 (file)
@@ -1575,6 +1575,7 @@ HEADERS += \
     dom/CDATASection.h \
     dom/CharacterData.h \
     dom/CheckedRadioButtons.h \
+    dom/ChildIterator.h \
     dom/ChildNodeList.h \
     dom/ClassNodeList.h \
     dom/ClientRect.h \
@@ -1588,6 +1589,7 @@ HEADERS += \
     dom/ContextFeatures.h \
     dom/CustomEvent.h \
     dom/default/PlatformMessagePortChannel.h \
+    dom/DescendantIterator.h \
     dom/DeviceMotionClient.h \
     dom/DeviceMotionController.h \
     dom/DeviceMotionData.h \
index c726ff7..df858c5 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\CDATASection.h" />
     <ClInclude Include="..\dom\CharacterData.h" />
     <ClInclude Include="..\dom\CheckedRadioButtons.h" />
+    <ClInclude Include="..\dom\ChildIterator.h" />
     <ClInclude Include="..\dom\ChildListMutationScope.h" />
     <ClInclude Include="..\dom\ChildNodeList.h" />
     <ClInclude Include="..\dom\ClassNodeList.h" />
     <ClInclude Include="..\dom\DataTransferItem.h" />
     <ClInclude Include="..\dom\DataTransferItemList.h" />
     <ClInclude Include="..\dom\DecodedDataDocumentParser.h" />
+    <ClInclude Include="..\dom\DescendantIterator.h" />
     <ClInclude Include="..\dom\DeviceMotionClient.h" />
     <ClInclude Include="..\dom\DeviceMotionController.h" />
     <ClInclude Include="..\dom\DeviceMotionData.h" />
index 49336d3..6f23143 100644 (file)
                E453901E0EAFCACA003695C8 /* PasteboardIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = E45390190EAFCACA003695C8 /* PasteboardIOS.mm */; };
                E45390460EAFD637003695C8 /* SharedTimerIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = E45390350EAFD637003695C8 /* SharedTimerIOS.mm */; };
                E462A4A1113E71BE004A4220 /* IntPointHash.h in Headers */ = {isa = PBXBuildFile; fileRef = E462A4A0113E71BE004A4220 /* IntPointHash.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E46A2B1C17CA65B9000DBCD8 /* DescendantIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E46A2B1B17CA65B9000DBCD8 /* DescendantIterator.h */; };
+               E46A2B1E17CA76B1000DBCD8 /* ChildIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E46A2B1D17CA76B1000DBCD8 /* ChildIterator.h */; };
                E47127CA163438A100ED6F5A /* StyleInvalidationAnalysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E47A97CE163059FC005DCD99 /* StyleInvalidationAnalysis.cpp */; };
                E47127CB163438AE00ED6F5A /* StyleInvalidationAnalysis.h in Headers */ = {isa = PBXBuildFile; fileRef = E47A97CF163059FC005DCD99 /* StyleInvalidationAnalysis.h */; };
                E4778B7F115A581A00B5D372 /* JSCustomEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4778B7D115A581A00B5D372 /* JSCustomEvent.cpp */; };
                E45390190EAFCACA003695C8 /* PasteboardIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PasteboardIOS.mm; path = ios/PasteboardIOS.mm; sourceTree = "<group>"; };
                E45390350EAFD637003695C8 /* SharedTimerIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = SharedTimerIOS.mm; path = ios/SharedTimerIOS.mm; sourceTree = "<group>"; };
                E462A4A0113E71BE004A4220 /* IntPointHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntPointHash.h; sourceTree = "<group>"; };
+               E46A2B1B17CA65B9000DBCD8 /* DescendantIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DescendantIterator.h; sourceTree = "<group>"; };
+               E46A2B1D17CA76B1000DBCD8 /* ChildIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChildIterator.h; sourceTree = "<group>"; };
                E4778B7D115A581A00B5D372 /* JSCustomEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCustomEvent.cpp; sourceTree = "<group>"; };
                E4778B7E115A581A00B5D372 /* JSCustomEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCustomEvent.h; sourceTree = "<group>"; };
                E47A97CE163059FC005DCD99 /* StyleInvalidationAnalysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StyleInvalidationAnalysis.cpp; sourceTree = "<group>"; };
                                93EEC1E609C2877700C515D1 /* CharacterData.idl */,
                                93F925420F7EF5B8007E37C9 /* CheckedRadioButtons.cpp */,
                                93F925410F7EF5B8007E37C9 /* CheckedRadioButtons.h */,
+                               E46A2B1D17CA76B1000DBCD8 /* ChildIterator.h */,
                                D619A305144E00BE004BC302 /* ChildListMutationScope.cpp */,
                                D619A306144E00BE004BC302 /* ChildListMutationScope.h */,
                                A818721A0977D3C0005826D9 /* ChildNodeList.cpp */,
                                81AC5AE91316392E0009A7E0 /* DataTransferItemList.idl */,
                                A8C228A011D5722E00D5A7D3 /* DecodedDataDocumentParser.cpp */,
                                A8C2289F11D5722E00D5A7D3 /* DecodedDataDocumentParser.h */,
+                               E46A2B1B17CA65B9000DBCD8 /* DescendantIterator.h */,
                                31FB1A4F120A5D0600DC02A0 /* DeviceMotionClient.h */,
                                31FB1A50120A5D0600DC02A0 /* DeviceMotionController.cpp */,
                                31FB1A51120A5D0600DC02A0 /* DeviceMotionController.h */,
                                A80E6CE60A1989CA007FB8C5 /* CSSPrimitiveValue.h in Headers */,
                                E1ED8AC30CC49BE000BFC557 /* CSSPrimitiveValueMappings.h in Headers */,
                                A80E6CFF0A1989CA007FB8C5 /* CSSProperty.h in Headers */,
+                               E46A2B1E17CA76B1000DBCD8 /* ChildIterator.h in Headers */,
                                78D02BC6154A18DF00B62D05 /* CSSPropertyAnimation.h in Headers */,
                                656580F409D12B20000E61D7 /* CSSPropertyNames.h in Headers */,
                                82E3D8DF122EA0D1003AE5BC /* CSSPropertySourceData.h in Headers */,
                                371E65CC13661EDC00BEEDB0 /* PageSerializer.h in Headers */,
                                A7197F24175689C4007B9442 /* PageThrottler.h in Headers */,
                                E1284AE110447D4500EAEB52 /* PageTransitionEvent.h in Headers */,
+                               E46A2B1C17CA65B9000DBCD8 /* DescendantIterator.h in Headers */,
                                51E1ECC30C91C90400DC255B /* PageURLRecord.h in Headers */,
                                FFD5B97B135CC97800D5E92A /* PageVisibilityState.h in Headers */,
                                9377ABA015DEFEEF0031FD04 /* Pagination.h in Headers */,
index 574b06b..47eb651 100644 (file)
@@ -34,7 +34,7 @@
 #include "AccessibilityListBox.h"
 #include "AccessibilitySpinButton.h"
 #include "AccessibilityTable.h"
-#include "ElementTraversal.h"
+#include "ChildIterator.h"
 #include "EventNames.h"
 #include "FloatRect.h"
 #include "Frame.h"
@@ -417,7 +417,7 @@ bool AccessibilityNodeObject::canvasHasFallbackContent() const
     // If it has any children that are elements, we'll assume it might be fallback
     // content. If it has no children or its only children are not elements
     // (e.g. just text nodes), it doesn't have fallback content.
-    return !!ElementTraversal::firstChild(node);
+    return elementChildren(node).begin() != elementChildren(node).end();
 }
 
 bool AccessibilityNodeObject::isImageButton() const
@@ -1121,11 +1121,11 @@ static Element* siblingWithAriaRole(String role, Node* node)
     Node* parent = node->parentNode();
     if (!parent)
         return 0;
-    
-    for (Element* sibling = ElementTraversal::firstChild(parent); sibling; sibling = ElementTraversal::nextSibling(sibling)) {
+
+    for (auto sibling = elementChildren(parent).begin(), end = elementChildren(parent).end(); sibling != end; ++sibling) {
         const AtomicString& siblingAriaRole = sibling->fastGetAttribute(roleAttr);
         if (equalIgnoringCase(siblingAriaRole, role))
-            return sibling;
+            return &*sibling;
     }
 
     return 0;
index f099070..ed56a34 100644 (file)
@@ -37,7 +37,7 @@
 #include "AccessibilityTable.h"
 #include "CachedImage.h"
 #include "Chrome.h"
-#include "ElementTraversal.h"
+#include "DescendantIterator.h"
 #include "EventNames.h"
 #include "FloatRect.h"
 #include "Frame.h"
@@ -2737,18 +2737,18 @@ void AccessibilityRenderObject::addImageMapChildren()
     if (!map)
         return;
 
-    for (HTMLAreaElement* current = Traversal<HTMLAreaElement>::firstWithin(map); current; current = Traversal<HTMLAreaElement>::next(current, map)) {
+    for (auto area = descendantsOfType<HTMLAreaElement>(map).begin(), end = descendantsOfType<HTMLAreaElement>(map).end() ; area != end; ++area) {
         // add an <area> element for this child if it has a link
-        if (current->isLink()) {
-            AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(axObjectCache()->getOrCreate(ImageMapLinkRole));
-            areaObject->setHTMLAreaElement(toHTMLAreaElement(current));
-            areaObject->setHTMLMapElement(map);
-            areaObject->setParent(this);
-            if (!areaObject->accessibilityIsIgnored())
-                m_children.append(areaObject);
-            else
-                axObjectCache()->remove(areaObject->axObjectID());
-        }
+        if (!area->isLink())
+            continue;
+        AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(axObjectCache()->getOrCreate(ImageMapLinkRole));
+        areaObject->setHTMLAreaElement(&*area);
+        areaObject->setHTMLMapElement(map);
+        areaObject->setParent(this);
+        if (!areaObject->accessibilityIsIgnored())
+            m_children.append(areaObject);
+        else
+            axObjectCache()->remove(areaObject->axObjectID());
     }
 }
 
index 34de8d1..b35aeb0 100644 (file)
@@ -34,7 +34,7 @@
 #include "AccessibilityTableColumn.h"
 #include "AccessibilityTableHeaderContainer.h"
 #include "AccessibilityTableRow.h"
-#include "ElementTraversal.h"
+#include "ChildIterator.h"
 #include "HTMLNames.h"
 #include "HTMLTableCaptionElement.h"
 #include "HTMLTableCellElement.h"
@@ -125,7 +125,7 @@ bool AccessibilityTable::isDataTable() const
         return true;    
 
     // if there's a colgroup or col element, it's probably a data table.
-    for (Element* child = ElementTraversal::firstChild(tableElement); child; child = ElementTraversal::nextSibling(child)) {
+    for (auto child = elementChildren(tableElement).begin(), end = elementChildren(tableElement).end(); child != end; ++child) {
         if (child->hasTagName(colTag) || child->hasTagName(colgroupTag))
             return true;
     }
diff --git a/Source/WebCore/dom/ChildIterator.h b/Source/WebCore/dom/ChildIterator.h
new file mode 100644 (file)
index 0000000..19b952e
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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 ChildIterator_h
+#define ChildIterator_h
+
+#include "ElementTraversal.h"
+
+#ifndef NDEBUG
+#include "Document.h"
+#endif
+
+namespace WebCore {
+
+template <typename ElementType>
+class ChildIterator {
+public:
+    ChildIterator();
+    ChildIterator(ElementType* current);
+    ChildIterator& operator++();
+    ElementType& operator*() { return *m_current; }
+    ElementType* operator->() { return m_current; }
+    bool operator!=(const ChildIterator& other) const;
+
+private:
+    ElementType* m_current;
+#ifndef NDEBUG
+    OwnPtr<NoEventDispatchAssertion> m_noEventDispatchAssertion;
+    uint64_t m_initialDOMTreeVersion;
+#endif
+};
+
+template <typename ElementType, typename ContainerType>
+class ChildIteratorAdapter {
+public:
+    ChildIteratorAdapter(ContainerType* root);
+    ChildIterator<ElementType> begin();
+    ChildIterator<ElementType> end();
+
+private:
+    const ContainerType* m_root;
+};
+
+ChildIteratorAdapter<Element, ContainerNode> elementChildren(ContainerNode* root);
+ChildIteratorAdapter<Element, Node> elementChildren(Node* root);
+template <typename ElementType> ChildIteratorAdapter<ElementType, ContainerNode> childrenOfType(ContainerNode* root);
+template <typename ElementType> ChildIteratorAdapter<ElementType, Node> childrenOfType(Node* root);
+
+template <typename ElementType>
+inline ChildIterator<ElementType>::ChildIterator()
+    : m_current(nullptr)
+#ifndef NDEBUG
+    , m_initialDOMTreeVersion(0)
+#endif
+{
+}
+
+template <typename ElementType>
+inline ChildIterator<ElementType>::ChildIterator(ElementType* current)
+    : m_current(current)
+#ifndef NDEBUG
+    , m_noEventDispatchAssertion(adoptPtr(new NoEventDispatchAssertion))
+    , m_initialDOMTreeVersion(m_current ? m_current->document()->domTreeVersion() : 0)
+#endif
+{
+}
+
+template <typename ElementType>
+inline ChildIterator<ElementType>& ChildIterator<ElementType>::operator++()
+{
+    ASSERT(m_current);
+    ASSERT(m_current->document()->domTreeVersion() == m_initialDOMTreeVersion);
+    m_current = Traversal<ElementType>::nextSibling(m_current);
+    return *this;
+}
+
+template <typename ElementType>
+inline bool ChildIterator<ElementType>::operator!=(const ChildIterator& other) const
+{
+    return m_current != other.m_current;
+}
+
+template <typename ElementType, typename ContainerType>
+inline ChildIteratorAdapter<ElementType, ContainerType>::ChildIteratorAdapter(ContainerType* root)
+    : m_root(root)
+{
+}
+
+template <typename ElementType, typename ContainerType>
+inline ChildIterator<ElementType> ChildIteratorAdapter<ElementType, ContainerType>::begin()
+{
+    return ChildIterator<ElementType>(Traversal<ElementType>::firstChild(m_root));
+}
+
+template <typename ElementType, typename ContainerType>
+inline ChildIterator<ElementType> ChildIteratorAdapter<ElementType, ContainerType>::end()
+{
+    return ChildIterator<ElementType>();
+}
+
+inline ChildIteratorAdapter<Element, ContainerNode> elementChildren(ContainerNode* root)
+{
+    return ChildIteratorAdapter<Element, ContainerNode>(root);
+}
+
+inline ChildIteratorAdapter<Element, Node> elementChildren(Node* root)
+{
+    return ChildIteratorAdapter<Element, Node>(root);
+}
+
+template <typename ElementType>
+inline ChildIteratorAdapter<ElementType, ContainerNode> childrenOfType(ContainerNode* root)
+{
+    return ChildIteratorAdapter<ElementType, ContainerNode>(root);
+}
+
+template <typename ElementType>
+inline ChildIteratorAdapter<ElementType, Node> childrenOfType(Node* root)
+{
+    return ChildIteratorAdapter<ElementType, Node>(root);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/dom/DescendantIterator.h b/Source/WebCore/dom/DescendantIterator.h
new file mode 100644 (file)
index 0000000..52a6d28
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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 DescendantIterator_h
+#define DescendantIterator_h
+
+#include "ElementTraversal.h"
+
+#ifndef NDEBUG
+#include "Document.h"
+#endif
+
+namespace WebCore {
+
+template <typename ElementType>
+class DescendantIterator {
+public:
+    DescendantIterator(const ContainerNode* root);
+    DescendantIterator(const ContainerNode* root, ElementType* current);
+    DescendantIterator& operator++();
+    ElementType& operator*() { return *m_current; }
+    ElementType* operator->() { return m_current; }
+    bool operator!=(const DescendantIterator& other) const;
+
+private:
+    const ContainerNode* m_root;
+    ElementType* m_current;
+#ifndef NDEBUG
+    OwnPtr<NoEventDispatchAssertion> m_noEventDispatchAssertion;
+    uint64_t m_initialDOMTreeVersion;
+#endif
+};
+
+template <typename ElementType, typename ContainerType>
+class DescendantIteratorAdapter {
+public:
+    DescendantIteratorAdapter(ContainerType* root);
+    DescendantIterator<ElementType> begin();
+    DescendantIterator<ElementType> end();
+
+private:
+    ContainerType* m_root;
+};
+
+DescendantIteratorAdapter<Element, ContainerNode> elementDescendants(ContainerNode* root);
+DescendantIteratorAdapter<Element, Node> elementDescendants(Node* root);
+template <typename ElementType> DescendantIteratorAdapter<ElementType, ContainerNode> descendantsOfType(ContainerNode* root);
+template <typename ElementType> DescendantIteratorAdapter<ElementType, Node> descendantsOfType(Node* root);
+
+template <typename ElementType>
+inline DescendantIterator<ElementType>::DescendantIterator(const ContainerNode* root)
+    : m_root(root)
+    , m_current(nullptr)
+#ifndef NDEBUG
+    , m_initialDOMTreeVersion(0)
+#endif
+{
+}
+
+template <typename ElementType>
+inline DescendantIterator<ElementType>::DescendantIterator(const ContainerNode* root, ElementType* current)
+    : m_root(root)
+    , m_current(current)
+#ifndef NDEBUG
+    , m_noEventDispatchAssertion(adoptPtr(new NoEventDispatchAssertion))
+    , m_initialDOMTreeVersion(m_current ? m_current->document()->domTreeVersion() : 0)
+#endif
+{
+}
+
+template <typename ElementType>
+inline DescendantIterator<ElementType>& DescendantIterator<ElementType>::operator++()
+{
+    ASSERT(m_current);
+    ASSERT(m_current->document()->domTreeVersion() == m_initialDOMTreeVersion);
+    m_current = Traversal<ElementType>::next(m_current, m_root);
+    return *this;
+}
+
+template <typename ElementType>
+inline bool DescendantIterator<ElementType>::operator!=(const DescendantIterator& other) const
+{
+    ASSERT(m_root == other.m_root);
+    return m_current != other.m_current;
+}
+
+template <typename ElementType, typename ContainerType>
+inline DescendantIteratorAdapter<ElementType, ContainerType>::DescendantIteratorAdapter(ContainerType* root)
+    : m_root(root)
+{
+}
+
+template <typename ElementType, typename ContainerType>
+inline DescendantIterator<ElementType> DescendantIteratorAdapter<ElementType, ContainerType>::begin()
+{
+    if (!m_root->isContainerNode())
+        return DescendantIterator<ElementType>(m_root);
+    return DescendantIterator<ElementType>(m_root, Traversal<ElementType>::firstWithin(static_cast<ContainerNode*>(m_root)));
+}
+
+template <typename ElementType, typename ContainerType>
+inline DescendantIterator<ElementType> DescendantIteratorAdapter<ElementType, ContainerType>::end()
+{
+    return DescendantIterator<ElementType>(m_root);
+}
+
+inline DescendantIteratorAdapter<Element, ContainerNode> elementDescendants(ContainerNode* root)
+{
+    return DescendantIteratorAdapter<Element, ContainerNode>(root);
+}
+
+inline DescendantIteratorAdapter<Element, Node> elementDescendants(Node* root)
+{
+    return DescendantIteratorAdapter<Element, Node>(root);
+}
+
+template <typename ElementType>
+inline DescendantIteratorAdapter<ElementType, ContainerNode> descendantsOfType(ContainerNode* root)
+{
+    return DescendantIteratorAdapter<ElementType, ContainerNode>(root);
+}
+
+template <typename ElementType>
+inline DescendantIteratorAdapter<ElementType, Node> descendantsOfType(Node* root)
+{
+    return DescendantIteratorAdapter<ElementType, Node>(root);
+}
+
+}
+
+#endif
index ebed3d8..a66b81b 100644 (file)
@@ -37,6 +37,7 @@
 #include "CSSStyleSheet.h"
 #include "CachedCSSStyleSheet.h"
 #include "CachedResourceLoader.h"
+#include "ChildIterator.h"
 #include "Chrome.h"
 #include "ChromeClient.h"
 #include "Comment.h"
@@ -49,6 +50,7 @@
 #include "DOMNamedFlowCollection.h"
 #include "DOMWindow.h"
 #include "DateComponents.h"
+#include "DescendantIterator.h"
 #include "Dictionary.h"
 #include "DocumentEventQueue.h"
 #include "DocumentFragment.h"
@@ -59,7 +61,6 @@
 #include "DocumentType.h"
 #include "Editor.h"
 #include "Element.h"
-#include "ElementTraversal.h"
 #include "EntityReference.h"
 #include "Event.h"
 #include "EventFactory.h"
@@ -677,10 +678,10 @@ void Document::buildAccessKeyMap(TreeScope* scope)
 {
     ASSERT(scope);
     ContainerNode* rootNode = scope->rootNode();
-    for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) {
+    for (auto element = elementDescendants(rootNode).begin(), end = elementDescendants(rootNode).end(); element != end; ++element) {
         const AtomicString& accessKey = element->fastGetAttribute(accesskeyAttr);
         if (!accessKey.isEmpty())
-            m_elementsByAccessKey.set(accessKey.impl(), element);
+            m_elementsByAccessKey.set(accessKey.impl(), &*element);
 
         if (ShadowRoot* root = element->shadowRoot())
             buildAccessKeyMap(root);
@@ -776,7 +777,7 @@ void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* a
 {
     ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
     
-    Element* newDocumentElement = ElementTraversal::firstWithin(this);
+    Element* newDocumentElement = &*elementChildren(this).begin();
     if (newDocumentElement == m_documentElement)
         return;
     m_documentElement = newDocumentElement;
@@ -1976,8 +1977,8 @@ void Document::createRenderTree()
 
     recalcStyle(Style::Force);
 
-    for (Element* child = ElementTraversal::firstWithin(this); child; child = ElementTraversal::nextSibling(child))
-        Style::attachRenderTree(child);
+    for (auto child = elementDescendants(this).begin(), end = elementDescendants(this).end(); child != end; ++child)
+        Style::attachRenderTree(&*child);
 
     setAttached(true);
 }
@@ -2076,8 +2077,8 @@ void Document::detach()
 
     TemporaryChange<bool> change(m_renderTreeBeingDestroyed, true);
 
-    for (Element* child = ElementTraversal::firstWithin(this); child; child = ElementTraversal::nextSibling(child))
-        Style::detachRenderTree(child);
+    for (auto child = elementDescendants(this).begin(), end = elementDescendants(this).end(); child != end; ++child)
+        Style::detachRenderTree(&*child);
 
     clearChildNeedsStyleRecalc();
     setAttached(false);
index f947ab6..f25df98 100644 (file)
 #include "CSSPropertyNames.h"
 #include "CSSValueKeywords.h"
 #include "CSSValuePool.h"
+#include "ChildIterator.h"
 #include "Document.h"
 #include "EditingStyle.h"
 #include "Editor.h"
-#include "ElementTraversal.h"
 #include "Frame.h"
 #include "HTMLFontElement.h"
 #include "HTMLInterchange.h"
@@ -442,12 +442,14 @@ void ApplyStyleCommand::cleanupUnstyledAppleStyleSpans(Node* dummySpanAncestor)
     // can be propagated, which can result in more splitting. If a dummy span gets
     // cloned/split, the new node is always a sibling of it. Therefore, we scan
     // all the children of the dummy's parent
-    Element* next;
-    for (Element* element = ElementTraversal::firstWithin(dummySpanAncestor); element; element = next) {
-        next = ElementTraversal::nextSibling(element);
-        if (isSpanWithoutAttributesOrUnstyledStyleSpan(element))
-            removeNodePreservingChildren(element);
+
+    Vector<Element*> toRemove;
+    for (auto child = elementChildren(dummySpanAncestor).begin(), end = elementChildren(dummySpanAncestor).end(); child != end; ++child) {
+        if (isSpanWithoutAttributesOrUnstyledStyleSpan(&*child))
+            toRemove.append(&*child);
     }
+    for (unsigned i = 0; i < toRemove.size(); ++i)
+        removeNodePreservingChildren(toRemove[i]);
 }
 
 HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi(Node* node, bool before, WritingDirection allowedDirection)
index a71cdcb..df2b937 100644 (file)
 #include "CSSValueKeywords.h"
 #include "ChildListMutationScope.h"
 #include "ContextFeatures.h"
+#include "DescendantIterator.h"
 #include "DocumentFragment.h"
 #include "DocumentType.h"
 #include "Editor.h"
-#include "ElementTraversal.h"
 #include "ExceptionCode.h"
 #include "ExceptionCodePlaceholder.h"
 #include "Frame.h"
@@ -103,14 +103,14 @@ static void completeURLs(DocumentFragment* fragment, const String& baseURL)
 
     KURL parsedBaseURL(ParsedURLString, baseURL);
 
-    for (Element* element = ElementTraversal::firstWithin(fragment); element; element = ElementTraversal::next(element, fragment)) {
+    for (auto element = elementDescendants(fragment).begin(), end = elementDescendants(fragment).end(); element != end; ++element) {
         if (!element->hasAttributes())
             continue;
         unsigned length = element->attributeCount();
         for (unsigned i = 0; i < length; i++) {
             const Attribute& attribute = element->attributeAt(i);
             if (element->isURLAttribute(attribute) && !attribute.value().isEmpty())
-                changes.append(AttributeChange(element, attribute.name(), KURL(parsedBaseURL, attribute.value()).string()));
+                changes.append(AttributeChange(&*element, attribute.name(), KURL(parsedBaseURL, attribute.value()).string()));
         }
     }
 
index 9555716..4963818 100644 (file)
@@ -23,8 +23,8 @@
 #include "HTMLMapElement.h"
 
 #include "Attribute.h"
+#include "DescendantIterator.h"
 #include "Document.h"
-#include "ElementTraversal.h"
 #include "HTMLAreaElement.h"
 #include "HTMLCollection.h"
 #include "HTMLImageElement.h"
@@ -62,10 +62,11 @@ HTMLMapElement::~HTMLMapElement()
 bool HTMLMapElement::mapMouseEvent(LayoutPoint location, const LayoutSize& size, HitTestResult& result)
 {
     HTMLAreaElement* defaultArea = 0;
-    for (HTMLAreaElement* area = Traversal<HTMLAreaElement>::firstWithin(this); area; area = Traversal<HTMLAreaElement>::next(area, this)) {
+
+    for (auto area = descendantsOfType<HTMLAreaElement>(this).begin(), end = descendantsOfType<HTMLAreaElement>(this).end(); area != end; ++area) {
         if (area->isDefault()) {
             if (!defaultArea)
-                defaultArea = area;
+                defaultArea = &*area;
         } else if (area->mapMouseEvent(location, size, result))
             return true;
     }
index 31f342b..c8c2bff 100644 (file)
@@ -30,6 +30,7 @@
 #include "ApplicationCacheHost.h"
 #include "ApplicationCacheResource.h"
 #include "Attribute.h"
+#include "ChildIterator.h"
 #include "Chrome.h"
 #include "ChromeClient.h"
 #include "ClientRect.h"
@@ -40,7 +41,6 @@
 #include "CSSValueKeywords.h"
 #include "DiagnosticLoggingKeys.h"
 #include "DocumentLoader.h"
-#include "ElementTraversal.h"
 #include "Event.h"
 #include "EventNames.h"
 #include "ExceptionCode.h"
@@ -927,9 +927,10 @@ void HTMLMediaElement::selectMediaResource()
         // Otherwise, if the media element does not have a src attribute but has a source 
         // element child, then let mode be children and let candidate be the first such 
         // source element child in tree order.
-        if (auto sourceElement = Traversal<HTMLSourceElement>::firstChild(this)) {
+        auto source = childrenOfType<HTMLSourceElement>(this).begin();
+        if (source != childrenOfType<HTMLSourceElement>(this).end()) {
             mode = children;
-            m_nextChildNodeToConsider = sourceElement;
+            m_nextChildNodeToConsider = &*source;
             m_currentSourceNode = 0;
         } else {
             // Otherwise the media element has neither a src attribute nor a source element 
@@ -1417,7 +1418,8 @@ void HTMLMediaElement::textTrackModeChanged(TextTrack* track)
     bool trackIsLoaded = true;
     if (track->trackType() == TextTrack::TrackElement) {
         trackIsLoaded = false;
-        for (auto trackElement = Traversal<HTMLTrackElement>::firstChild(this); trackElement; trackElement = Traversal<HTMLTrackElement>::nextSibling(trackElement)) {
+        auto end = childrenOfType<HTMLTrackElement>(this).end();
+        for (auto trackElement = childrenOfType<HTMLTrackElement>(this).begin(); trackElement != end; ++trackElement) {
             if (trackElement->track() == track) {
                 if (trackElement->readyState() == HTMLTrackElement::LOADING || trackElement->readyState() == HTMLTrackElement::LOADED)
                     trackIsLoaded = true;