Source/WebCore/ChangeLog

 12011-12-13 Ryosuke Niwa <rniwa@webkit.org>
 2
 3 NodeChildList shouldn't be in NodeListNodeData
 4 https://bugs.webkit.org/show_bug.cgi?id=73969
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Move NodeChildList out of NodeListNodeData to separate it from the other node lists in order to
 9 resolve the bug 73853. Unlike other DynamicNodeList, we don't need to invalidate NodeChildList
 10 on ancestors when children change. Moving ChildNodeList out of NodeListNodeData makes this difference
 11 apparent and makes DynamicNodeList::Caches in NodeListNodeData always held by a DynamicSubtreeNodeList,
 12 eliminating the need for hasOwnCaches() checks in various places.
 13
 14 Also renamed the existing DynamicNodeList to DynamicSubtreeNodeList and re-introduced DynamicNodeList
 15 from which DynamicSubtreeNodeList and ChildNodeList both inherit to share the code for itemWithName.
 16
 17 In addition, renamed registerDynamicNodeList and unregisterDynamicNodeList, which updates a counter for
 18 TreeScope::hasNodeListCaches, to registerDynamicSubtreeNodeList and unregisterDynamicSubtreeNodeList
 19 respectively. They are no longer called by ChildNodeList in order to avoid walking up the DOM tree
 20 inside invalidateNodeListsCacheAfterAttributeChanged and invalidateNodeListsCacheAfterChildrenChanged.
 21
 22 Test: fast/dom/childnode-item-after-itemname.html
 23
 24 * bindings/js/JSNodeListCustom.cpp:
 25 (WebCore::JSNodeListOwner::isReachableFromOpaqueRoots):
 26 * dom/ChildNodeList.cpp:
 27 (WebCore::ChildNodeList::ChildNodeList):
 28 (WebCore::ChildNodeList::length):
 29 (WebCore::ChildNodeList::item):
 30 (WebCore::ChildNodeList::nodeMatches):
 31 * dom/ChildNodeList.h:
 32 * dom/ClassNodeList.cpp:
 33 (WebCore::ClassNodeList::ClassNodeList):
 34 (WebCore::ClassNodeList::~ClassNodeList):
 35 * dom/ClassNodeList.h:
 36 * dom/ContainerNode.cpp:
 37 (WebCore::ContainerNode::childrenChanged):
 38 * dom/DynamicNodeList.cpp:
 39 (WebCore::DynamicSubtreeNodeList::DynamicSubtreeNodeList):
 40 (WebCore::DynamicSubtreeNodeList::~DynamicSubtreeNodeList):
 41 (WebCore::DynamicSubtreeNodeList::length):
 42 (WebCore::DynamicSubtreeNodeList::itemForwardsFromCurrent):
 43 (WebCore::DynamicSubtreeNodeList::itemBackwardsFromCurrent):
 44 (WebCore::DynamicSubtreeNodeList::item):
 45 (WebCore::DynamicNodeList::itemWithName):
 46 (WebCore::DynamicSubtreeNodeList::isDynamicNodeList):
 47 (WebCore::DynamicSubtreeNodeList::invalidateCache):
 48 (WebCore::DynamicSubtreeNodeList::Caches::Caches):
 49 (WebCore::DynamicSubtreeNodeList::Caches::create):
 50 (WebCore::DynamicSubtreeNodeList::Caches::reset):
 51 * dom/DynamicNodeList.h:
 52 (WebCore::DynamicNodeList::DynamicNodeList):
 53 (WebCore::DynamicNodeList::~DynamicNodeList):
 54 (WebCore::DynamicNodeList::node):
 55 (WebCore::DynamicSubtreeNodeList::rootNode):
 56 * dom/NameNodeList.cpp:
 57 (WebCore::NameNodeList::NameNodeList):
 58 (WebCore::NameNodeList::~NameNodeList):
 59 * dom/NameNodeList.h:
 60 * dom/Node.cpp:
 61 (WebCore::Node::childNodes):
 62 (WebCore::Node::registerDynamicSubtreeNodeList):
 63 (WebCore::Node::unregisterDynamicSubtreeNodeList):
 64 (WebCore::Node::invalidateNodeListsCacheAfterAttributeChanged):
 65 (WebCore::Node::invalidateNodeListsCacheAfterChildrenChanged):
 66 (WebCore::Node::removeCachedClassNodeList):
 67 (WebCore::Node::removeCachedNameNodeList):
 68 (WebCore::Node::removeCachedTagNodeList):
 69 (WebCore::Node::removeCachedLabelsNodeList):
 70 (WebCore::NodeListsNodeData::invalidateCaches):
 71 (WebCore::NodeListsNodeData::isEmpty):
 72 (WebCore::NodeRareData::clearChildNodeListCache):
 73 * dom/Node.h:
 74 * dom/NodeRareData.h:
 75 (WebCore::NodeRareData::nodeLists):
 76 (WebCore::NodeRareData::ensureChildNodeListCache):
 77 * dom/TagNodeList.cpp:
 78 (WebCore::TagNodeList::TagNodeList):
 79 (WebCore::TagNodeList::~TagNodeList):
 80 * dom/TagNodeList.h:
 81 * html/LabelsNodeList.cpp:
 82 (WebCore::LabelsNodeList::LabelsNodeList):
 83 * html/LabelsNodeList.h:
 84
1852011-12-13 Robin Dunn <robin@alldunn.com>
286
387 Don't make the bitmap transparent when using theme drawing
102720

Source/WebCore/bindings/js/JSNodeListCustom.cpp

@@bool JSNodeListOwner::isReachableFromOpa
4343 return false;
4444 if (!jsNodeList->impl()->isDynamicNodeList())
4545 return false;
46  return visitor.containsOpaqueRoot(root(static_cast<DynamicNodeList*>(jsNodeList->impl())->rootNode()));
 46 return visitor.containsOpaqueRoot(root(static_cast<DynamicNodeList*>(jsNodeList->impl())->node()));
4747}
4848
4949bool JSNodeList::canGetItemsForName(ExecState*, NodeList* impl, const Identifier& propertyName)
102444

Source/WebCore/dom/ChildNodeList.cpp

2727
2828namespace WebCore {
2929
30 ChildNodeList::ChildNodeList(PassRefPtr<Node> rootNode, DynamicNodeList::Caches* info)
31  : DynamicNodeList(rootNode, info)
 30ChildNodeList::ChildNodeList(PassRefPtr<Node> node, DynamicNodeList::Caches* caches)
 31 : DynamicNodeList(node)
 32 , m_caches(caches)
3233{
3334}
3435

@@unsigned ChildNodeList::length() const
3839 return m_caches->cachedLength;
3940
4041 unsigned len = 0;
41  for (Node* n = m_rootNode->firstChild(); n; n = n->nextSibling())
 42 for (Node* n = node()->firstChild(); n; n = n->nextSibling())
4243 len++;
4344
4445 m_caches->cachedLength = len;

@@unsigned ChildNodeList::length() const
5051Node* ChildNodeList::item(unsigned index) const
5152{
5253 unsigned int pos = 0;
53  Node* n = m_rootNode->firstChild();
 54 Node* n = node()->firstChild();
5455
5556 if (m_caches->isItemCacheValid) {
5657 if (index == m_caches->lastItemOffset)

@@Node* ChildNodeList::item(unsigned index
7172 int diff = index - pos;
7273 unsigned dist = abs(diff);
7374 if (dist > m_caches->cachedLength - 1 - index) {
74  n = m_rootNode->lastChild();
 75 n = node()->lastChild();
7576 pos = m_caches->cachedLength - 1;
7677 }
7778 }

@@bool ChildNodeList::nodeMatches(Element*
103104 // Note: Due to the overrides of the length and item functions above,
104105 // this function will be called only by DynamicNodeList::itemWithName,
105106 // for an element that was located with getElementById.
106  return testNode->parentNode() == m_rootNode;
 107 return testNode->parentNode() == node();
107108}
108109
109110} // namespace WebCore
102444

Source/WebCore/dom/ChildNodeList.h

@@namespace WebCore {
4343 ChildNodeList(PassRefPtr<Node> rootNode, Caches*);
4444
4545 virtual bool nodeMatches(Element*) const;
 46
 47 mutable RefPtr<DynamicNodeList::Caches> m_caches;
4648 };
4749
4850} // namespace WebCore
102444

Source/WebCore/dom/ClassNodeList.cpp

3636namespace WebCore {
3737
3838ClassNodeList::ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames)
39  : DynamicNodeList(rootNode)
40  , m_classNames(classNames, m_rootNode->document()->inQuirksMode())
 39 : DynamicSubtreeNodeList(rootNode)
 40 , m_classNames(classNames, node()->document()->inQuirksMode())
4141 , m_originalClassNames(classNames)
4242{
4343}
4444
4545ClassNodeList::~ClassNodeList()
4646{
47  m_rootNode->removeCachedClassNodeList(this, m_originalClassNames);
 47 rootNode()->removeCachedClassNodeList(this, m_originalClassNames);
4848}
4949
5050bool ClassNodeList::nodeMatches(Element* testNode) const
102444

Source/WebCore/dom/ClassNodeList.h

3636
3737namespace WebCore {
3838
39  class ClassNodeList : public DynamicNodeList {
 39 class ClassNodeList : public DynamicSubtreeNodeList {
4040 public:
4141 static PassRefPtr<ClassNodeList> create(PassRefPtr<Node> rootNode, const String& classNames)
4242 {
102444

Source/WebCore/dom/ContainerNode.cpp

@@void ContainerNode::childrenChanged(bool
844844 Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
845845 if (!changedByParser && childCountDelta)
846846 document()->updateRangesAfterChildrenChanged(this);
847  if (treeScope()->hasNodeListCaches())
848  invalidateNodeListsCacheAfterChildrenChanged();
 847 invalidateNodeListsCacheAfterChildrenChanged();
849848}
850849
851850void ContainerNode::cloneChildNodes(ContainerNode *clone)
102444

Source/WebCore/dom/DynamicNodeList.cpp

2828
2929namespace WebCore {
3030
31 DynamicNodeList::DynamicNodeList(PassRefPtr<Node> rootNode)
32  : m_rootNode(rootNode)
 31DynamicSubtreeNodeList::DynamicSubtreeNodeList(PassRefPtr<Node> node)
 32 : DynamicNodeList(node)
3333 , m_caches(Caches::create())
34  , m_ownsCaches(true)
3534{
36  m_rootNode->registerDynamicNodeList(this);
37 }
38 
39 DynamicNodeList::DynamicNodeList(PassRefPtr<Node> rootNode, DynamicNodeList::Caches* caches)
40  : m_rootNode(rootNode)
41  , m_caches(caches)
42  , m_ownsCaches(false)
43 {
44  m_rootNode->registerDynamicNodeList(this);
45 }
 35 rootNode()->registerDynamicSubtreeNodeList(this);
 36}
4637
47 DynamicNodeList::~DynamicNodeList()
 38DynamicSubtreeNodeList::~DynamicSubtreeNodeList()
4839{
49  m_rootNode->unregisterDynamicNodeList(this);
 40 rootNode()->unregisterDynamicSubtreeNodeList(this);
5041}
5142
52 unsigned DynamicNodeList::length() const
 43unsigned DynamicSubtreeNodeList::length() const
5344{
5445 if (m_caches->isLengthCacheValid)
5546 return m_caches->cachedLength;
5647
5748 unsigned length = 0;
5849
59  for (Node* n = m_rootNode->firstChild(); n; n = n->traverseNextNode(m_rootNode.get()))
 50 for (Node* n = node()->firstChild(); n; n = n->traverseNextNode(rootNode()))
6051 length += n->isElementNode() && nodeMatches(static_cast<Element*>(n));
6152
6253 m_caches->cachedLength = length;

@@unsigned DynamicNodeList::length() const
6556 return length;
6657}
6758
68 Node* DynamicNodeList::itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const
 59Node* DynamicSubtreeNodeList::itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const
6960{
7061 ASSERT(remainingOffset >= 0);
71  for (Node* n = start; n; n = n->traverseNextNode(m_rootNode.get())) {
 62 for (Node* n = start; n; n = n->traverseNextNode(rootNode())) {
7263 if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) {
7364 if (!remainingOffset) {
7465 m_caches->lastItem = n;

@@Node* DynamicNodeList::itemForwardsFromC
8374 return 0; // no matching node in this subtree
8475}
8576
86 Node* DynamicNodeList::itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const
 77Node* DynamicSubtreeNodeList::itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const
8778{
8879 ASSERT(remainingOffset < 0);
89  for (Node* n = start; n; n = n->traversePreviousNode(m_rootNode.get())) {
 80 for (Node* n = start; n; n = n->traversePreviousNode(rootNode())) {
9081 if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) {
9182 if (!remainingOffset) {
9283 m_caches->lastItem = n;

@@Node* DynamicNodeList::itemBackwardsFrom
10192 return 0; // no matching node in this subtree
10293}
10394
104 Node* DynamicNodeList::item(unsigned offset) const
 95Node* DynamicSubtreeNodeList::item(unsigned offset) const
10596{
10697 int remainingOffset = offset;
107  Node* start = m_rootNode->firstChild();
 98 Node* start = node()->firstChild();
10899 if (m_caches->isItemCacheValid) {
109100 if (offset == m_caches->lastItemOffset)
110101 return m_caches->lastItem;

@@Node* DynamicNodeList::item(unsigned off
121112
122113Node* DynamicNodeList::itemWithName(const AtomicString& elementId) const
123114{
124  if (m_rootNode->isDocumentNode() || m_rootNode->inDocument()) {
125  Element* node = m_rootNode->treeScope()->getElementById(elementId);
126  if (node && nodeMatches(node)) {
127  for (ContainerNode* p = node->parentNode(); p; p = p->parentNode()) {
128  if (p == m_rootNode)
129  return node;
130  }
131  }
 115 if (node()->isDocumentNode() || node()->inDocument()) {
 116 Element* node = this->node()->treeScope()->getElementById(elementId);
 117 if (node && nodeMatches(node) && node->isDescendantOf(this->node()))
 118 return node;
132119 if (!node)
133120 return 0;
134121 // In the case of multiple nodes with the same name, just fall through.

@@Node* DynamicNodeList::itemWithName(cons
145132 return 0;
146133}
147134
148 bool DynamicNodeList::isDynamicNodeList() const
 135bool DynamicSubtreeNodeList::isDynamicNodeList() const
149136{
150137 return true;
151138}
152139
153 void DynamicNodeList::invalidateCache()
 140void DynamicSubtreeNodeList::invalidateCache()
154141{
155  // This should only be called for node lists that own their own caches.
156  ASSERT(m_ownsCaches);
157142 m_caches->reset();
158143}
159144
160 DynamicNodeList::Caches::Caches()
 145DynamicSubtreeNodeList::Caches::Caches()
161146 : lastItem(0)
162147 , isLengthCacheValid(false)
163148 , isItemCacheValid(false)
164149{
165150}
166151
167 PassRefPtr<DynamicNodeList::Caches> DynamicNodeList::Caches::create()
 152PassRefPtr<DynamicSubtreeNodeList::Caches> DynamicSubtreeNodeList::Caches::create()
168153{
169154 return adoptRef(new Caches());
170155}
171156
172 void DynamicNodeList::Caches::reset()
 157void DynamicSubtreeNodeList::Caches::reset()
173158{
174159 lastItem = 0;
175160 isLengthCacheValid = false;
102444

Source/WebCore/dom/DynamicNodeList.h

3131
3232namespace WebCore {
3333
34  class Element;
35  class Node;
36 
37  class DynamicNodeList : public NodeList {
38  public:
39  struct Caches : RefCounted<Caches> {
40  static PassRefPtr<Caches> create();
41  void reset();
42 
43  unsigned cachedLength;
44  Node* lastItem;
45  unsigned lastItemOffset;
46  bool isLengthCacheValid : 1;
47  bool isItemCacheValid : 1;
48  protected:
49  Caches();
50  };
51 
52  virtual ~DynamicNodeList();
53 
54  bool hasOwnCaches() const { return m_ownsCaches; }
55 
56  // DOM methods & attributes for NodeList
57  virtual unsigned length() const;
58  virtual Node* item(unsigned index) const;
59  virtual Node* itemWithName(const AtomicString&) const;
60 
61  // Other methods (not part of DOM)
62  void invalidateCache();
63  Node* rootNode() const { return m_rootNode.get(); }
 34class Element;
 35class Node;
6436
 37class DynamicNodeList : public NodeList {
 38public:
 39 struct Caches : RefCounted<Caches> {
 40 static PassRefPtr<Caches> create();
 41 void reset();
 42
 43 unsigned cachedLength;
 44 Node* lastItem;
 45 unsigned lastItemOffset;
 46 bool isLengthCacheValid : 1;
 47 bool isItemCacheValid : 1;
6548 protected:
66  DynamicNodeList(PassRefPtr<Node> rootNode);
67  DynamicNodeList(PassRefPtr<Node> rootNode, Caches*);
68 
69  virtual bool nodeMatches(Element*) const = 0;
70 
71  RefPtr<Node> m_rootNode;
72  mutable RefPtr<Caches> m_caches;
73  bool m_ownsCaches;
74 
75  private:
76  virtual bool isDynamicNodeList() const;
77  Node* itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
78  Node* itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
 49 Caches();
7950 };
 51 DynamicNodeList(PassRefPtr<Node> node)
 52 : m_node(node)
 53 { }
 54 virtual ~DynamicNodeList() { }
 55
 56 // DOM methods & attributes for NodeList
 57 virtual unsigned length() const = 0;
 58 virtual Node* item(unsigned index) const = 0;
 59 virtual Node* itemWithName(const AtomicString&) const;
 60
 61 // Other methods (not part of DOM)
 62 Node* node() const { return m_node.get(); }
 63
 64protected:
 65 virtual bool nodeMatches(Element*) const = 0;
 66 RefPtr<Node> m_node;
 67};
 68
 69class DynamicSubtreeNodeList : public DynamicNodeList {
 70public:
 71 virtual ~DynamicSubtreeNodeList();
 72 virtual unsigned length() const OVERRIDE;
 73 virtual Node* item(unsigned index) const OVERRIDE;
 74 void invalidateCache();
 75 Node* rootNode() const { return node(); }
 76
 77protected:
 78 DynamicSubtreeNodeList(PassRefPtr<Node> rootNode);
 79 mutable RefPtr<Caches> m_caches;
 80
 81private:
 82 virtual bool isDynamicNodeList() const;
 83 Node* itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
 84 Node* itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
 85};
8086
8187} // namespace WebCore
8288
102444

Source/WebCore/dom/NameNodeList.cpp

@@namespace WebCore {
3232using namespace HTMLNames;
3333
3434NameNodeList::NameNodeList(PassRefPtr<Node> rootNode, const String& name)
35  : DynamicNodeList(rootNode)
 35 : DynamicSubtreeNodeList(rootNode)
3636 , m_nodeName(name)
3737{
3838}
3939
4040NameNodeList::~NameNodeList()
4141{
42  m_rootNode->removeCachedNameNodeList(this, m_nodeName);
 42 rootNode()->removeCachedNameNodeList(this, m_nodeName);
4343}
4444
4545bool NameNodeList::nodeMatches(Element* testNode) const
102444

Source/WebCore/dom/NameNodeList.h

3131namespace WebCore {
3232
3333 // NodeList which lists all Nodes in a Element with a given "name" attribute
34  class NameNodeList : public DynamicNodeList {
 34 class NameNodeList : public DynamicSubtreeNodeList {
3535 public:
3636 static PassRefPtr<NameNodeList> create(PassRefPtr<Node> rootNode, const String& name)
3737 {
102444

Source/WebCore/dom/Node.cpp

@@void Node::setNodeValue(const String& /*
623623
624624PassRefPtr<NodeList> Node::childNodes()
625625{
626  NodeListsNodeData* nodeLists = ensureRareData()->ensureNodeLists(this);
627  if (!nodeLists->m_childNodeListCaches)
628  nodeLists->m_childNodeListCaches = DynamicNodeList::Caches::create();
629  return ChildNodeList::create(this, nodeLists->m_childNodeListCaches.get());
 626 return ChildNodeList::create(this, ensureRareData()->ensureChildNodeListCache());
630627}
631628
632629Node *Node::lastDescendant() const

@@static void removeNodeListCacheIfPossibl
10041001 node->treeScope()->removeNodeListCache();
10051002}
10061003
1007 void Node::registerDynamicNodeList(DynamicNodeList* list)
 1004void Node::registerDynamicSubtreeNodeList(DynamicSubtreeNodeList* list)
10081005{
10091006 NodeRareData* data = ensureRareData();
10101007 // We haven't been receiving notifications while there were no registered lists, so the cache is invalid now.
10111008 if (data->nodeLists() && (!treeScope() || !treeScope()->hasNodeListCaches()))
10121009 data->nodeLists()->invalidateCaches();
10131010
1014  if (list->hasOwnCaches())
1015  data->ensureNodeLists(this)->m_listsWithCaches.add(list);
 1011 data->ensureNodeLists(this)->m_listsWithCaches.add(list);
10161012}
10171013
1018 void Node::unregisterDynamicNodeList(DynamicNodeList* list)
 1014void Node::unregisterDynamicSubtreeNodeList(DynamicSubtreeNodeList* list)
10191015{
1020  ASSERT(rareData());
 1016 ASSERT(hasRareData());
10211017 ASSERT(rareData()->nodeLists());
1022  if (list->hasOwnCaches()) {
1023  NodeRareData* data = rareData();
1024  data->nodeLists()->m_listsWithCaches.remove(list);
1025  removeNodeListCacheIfPossible(this, data);
1026  }
 1018 NodeRareData* data = rareData();
 1019 data->nodeLists()->m_listsWithCaches.remove(list);
 1020 removeNodeListCacheIfPossible(this, data);
10271021}
10281022
10291023void Node::invalidateNodeListsCacheAfterAttributeChanged()
10301024{
 1025 if (hasRareData() && isAttributeNode()) {
 1026 NodeRareData* data = rareData();
 1027 ASSERT(!data->nodeLists());
 1028 data->clearChildNodeListCache();
 1029 }
 1030
 1031 if (!treeScope()->hasNodeListCaches())
 1032 return;
 1033
10311034 for (Node* node = this; node; node = node->parentNode()) {
 1035 ASSERT(this == node || !node->isAttributeNode());
10321036 if (!node->hasRareData())
10331037 continue;
10341038 NodeRareData* data = node->rareData();
10351039 if (!data->nodeLists())
10361040 continue;
10371041
1038  // For attribute nodes, we need to invalidate childNodes as well.
1039  if (node->isAttributeNode())
1040  data->nodeLists()->invalidateCaches();
1041  else
1042  data->nodeLists()->invalidateCachesThatDependOnAttributes();
1043 
 1042 data->nodeLists()->invalidateCachesThatDependOnAttributes();
10441043 removeNodeListCacheIfPossible(node, data);
10451044 }
10461045}
10471046
10481047void Node::invalidateNodeListsCacheAfterChildrenChanged()
10491048{
 1049 if (hasRareData())
 1050 rareData()->clearChildNodeListCache();
 1051
 1052 if (!treeScope()->hasNodeListCaches())
 1053 return;
10501054 for (Node* node = this; node; node = node->parentNode()) {
10511055 if (!node->hasRareData())
10521056 continue;

@@void Node::removeCachedClassNodeList(Cla
10801084{
10811085 ASSERT(rareData());
10821086 ASSERT(rareData()->nodeLists());
1083  ASSERT_UNUSED(list, list->hasOwnCaches());
10841087
10851088 NodeListsNodeData* data = rareData()->nodeLists();
10861089 ASSERT_UNUSED(list, list == data->m_classNodeListCache.get(className));

@@void Node::removeCachedNameNodeList(Name
10911094{
10921095 ASSERT(rareData());
10931096 ASSERT(rareData()->nodeLists());
1094  ASSERT_UNUSED(list, list->hasOwnCaches());
10951097
10961098 NodeListsNodeData* data = rareData()->nodeLists();
10971099 ASSERT_UNUSED(list, list == data->m_nameNodeListCache.get(nodeName));

@@void Node::removeCachedTagNodeList(TagNo
11021104{
11031105 ASSERT(rareData());
11041106 ASSERT(rareData()->nodeLists());
1105  ASSERT_UNUSED(list, list->hasOwnCaches());
11061107
11071108 NodeListsNodeData* data = rareData()->nodeLists();
11081109 ASSERT_UNUSED(list, list == data->m_tagNodeListCache.get(name.impl()));

@@void Node::removeCachedTagNodeList(TagNo
11131114{
11141115 ASSERT(rareData());
11151116 ASSERT(rareData()->nodeLists());
1116  ASSERT_UNUSED(list, list->hasOwnCaches());
11171117
11181118 NodeListsNodeData* data = rareData()->nodeLists();
11191119 ASSERT_UNUSED(list, list == data->m_tagNodeListCacheNS.get(name.impl()));
11201120 data->m_tagNodeListCacheNS.remove(name.impl());
11211121}
11221122
1123 void Node::removeCachedLabelsNodeList(DynamicNodeList* list)
 1123void Node::removeCachedLabelsNodeList(DynamicSubtreeNodeList* list)
11241124{
11251125 ASSERT(rareData());
11261126 ASSERT(rareData()->nodeLists());
1127  ASSERT_UNUSED(list, list->hasOwnCaches());
1128 
 1127
11291128 NodeListsNodeData* data = rareData()->nodeLists();
 1129 ASSERT_UNUSED(list, list == data->m_labelsNodeListCache);
11301130 data->m_labelsNodeListCache = 0;
11311131}
11321132

@@void Node::showTreeForThisAcrossFrame()
23892389
23902390void NodeListsNodeData::invalidateCaches()
23912391{
2392  if (m_childNodeListCaches) {
2393  if (m_childNodeListCaches->hasOneRef())
2394  m_childNodeListCaches.clear();
2395  else
2396  m_childNodeListCaches->reset();
2397  }
2398 
23992392 if (m_labelsNodeListCache)
24002393 m_labelsNodeListCache->invalidateCache();
24012394 TagNodeListCache::const_iterator tagCacheEnd = m_tagNodeListCache.end();

@@bool NodeListsNodeData::isEmpty() const
24382431 if (!m_listsWithCaches.isEmpty())
24392432 return false;
24402433
2441  if (m_childNodeListCaches)
2442  return false;
2443 
24442434 if (!m_tagNodeListCache.isEmpty())
24452435 return false;
24462436 if (!m_tagNodeListCacheNS.isEmpty())

@@void NodeRareData::createNodeLists(Node*
30042994 treeScope->addNodeListCache();
30052995}
30062996
 2997void NodeRareData::clearChildNodeListCache()
 2998{
 2999 if (!m_childNodeListCache)
 3000 return;
 3001
 3002 if (m_childNodeListCache->hasOneRef())
 3003 m_childNodeListCache.clear();
 3004 else
 3005 m_childNodeListCache->reset();
 3006}
 3007
30073008} // namespace WebCore
30083009
30093010#ifndef NDEBUG
102444

Source/WebCore/dom/Node.h

@@class ClassNodeList;
5050class ContainerNode;
5151class DOMSettableTokenList;
5252class Document;
53 class DynamicNodeList;
 53class DynamicSubtreeNodeList;
5454class Element;
5555class Event;
5656class EventContext;

@@public:
517517 void showTreeForThisAcrossFrame() const;
518518#endif
519519
520  void registerDynamicNodeList(DynamicNodeList*);
521  void unregisterDynamicNodeList(DynamicNodeList*);
 520 void registerDynamicSubtreeNodeList(DynamicSubtreeNodeList*);
 521 void unregisterDynamicSubtreeNodeList(DynamicSubtreeNodeList*);
522522 void invalidateNodeListsCacheAfterAttributeChanged();
523523 void invalidateNodeListsCacheAfterChildrenChanged();
524524 void notifyLocalNodeListsLabelChanged();

@@public:
527527 void removeCachedNameNodeList(NameNodeList*, const String&);
528528 void removeCachedTagNodeList(TagNodeList*, const AtomicString&);
529529 void removeCachedTagNodeList(TagNodeList*, const QualifiedName&);
530  void removeCachedLabelsNodeList(DynamicNodeList*);
 530 void removeCachedLabelsNodeList(DynamicSubtreeNodeList*);
531531
532532 PassRefPtr<NodeList> getElementsByTagName(const AtomicString&);
533533 PassRefPtr<NodeList> getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName);
102444

Source/WebCore/dom/NodeRareData.h

2222#ifndef NodeRareData_h
2323#define NodeRareData_h
2424
 25#include "ChildNodeList.h"
2526#include "ClassNodeList.h"
2627#include "DOMSettableTokenList.h"
2728#include "DynamicNodeList.h"

@@class TreeScope;
4950struct NodeListsNodeData {
5051 WTF_MAKE_NONCOPYABLE(NodeListsNodeData); WTF_MAKE_FAST_ALLOCATED;
5152public:
52  typedef HashSet<DynamicNodeList*> NodeListSet;
 53 typedef HashSet<DynamicSubtreeNodeList*> NodeListSet;
5354 NodeListSet m_listsWithCaches;
54 
55  RefPtr<DynamicNodeList::Caches> m_childNodeListCaches;
56 
 55
5756 typedef HashMap<String, ClassNodeList*> ClassNodeListCache;
5857 ClassNodeListCache m_classNodeListCache;
5958

@@public:
126125 void clearNodeLists() { m_nodeLists.clear(); }
127126 void setNodeLists(PassOwnPtr<NodeListsNodeData> lists) { m_nodeLists = lists; }
128127 NodeListsNodeData* nodeLists() const { return m_nodeLists.get(); }
129 
130128 NodeListsNodeData* ensureNodeLists(Node* node)
131129 {
132130 if (!m_nodeLists)
133131 createNodeLists(node);
134132 return m_nodeLists.get();
135133 }
 134 void clearChildNodeListCache();
 135 DynamicNodeList::Caches* ensureChildNodeListCache()
 136 {
 137 if (!m_childNodeListCache)
 138 m_childNodeListCache = DynamicNodeList::Caches::create();
 139 return m_childNodeListCache.get();
 140 }
136141
137142 short tabIndex() const { return m_tabIndex; }
138143 void setTabIndexExplicitly(short index) { m_tabIndex = index; m_tabIndexWasSetExplicitly = true; }

@@private:
236241
237242 TreeScope* m_treeScope;
238243 OwnPtr<NodeListsNodeData> m_nodeLists;
 244 RefPtr<DynamicNodeList::Caches> m_childNodeListCache;
239245 OwnPtr<EventTargetData> m_eventTargetData;
240246 short m_tabIndex;
241247 bool m_tabIndexWasSetExplicitly : 1;
102444

Source/WebCore/dom/TagNodeList.cpp

3030namespace WebCore {
3131
3232TagNodeList::TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName)
33  : DynamicNodeList(rootNode)
 33 : DynamicSubtreeNodeList(rootNode)
3434 , m_namespaceURI(namespaceURI)
3535 , m_localName(localName)
3636{

@@TagNodeList::TagNodeList(PassRefPtr<Node
4040TagNodeList::~TagNodeList()
4141{
4242 if (m_namespaceURI == starAtom)
43  m_rootNode->removeCachedTagNodeList(this, m_localName);
 43 rootNode()->removeCachedTagNodeList(this, m_localName);
4444 else
45  m_rootNode->removeCachedTagNodeList(this, QualifiedName(nullAtom, m_localName, m_namespaceURI));
 45 rootNode()->removeCachedTagNodeList(this, QualifiedName(nullAtom, m_localName, m_namespaceURI));
4646}
4747
4848bool TagNodeList::nodeMatches(Element* testNode) const
102444

Source/WebCore/dom/TagNodeList.h

3030namespace WebCore {
3131
3232 // NodeList that limits to a particular tag.
33  class TagNodeList : public DynamicNodeList {
 33 class TagNodeList : public DynamicSubtreeNodeList {
3434 public:
3535 static PassRefPtr<TagNodeList> create(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName)
3636 {
102444

Source/WebCore/html/LabelsNodeList.cpp

@@namespace WebCore {
3333using namespace HTMLNames;
3434
3535LabelsNodeList::LabelsNodeList(Node* forNode )
36  : DynamicNodeList(forNode->document()) , m_forNode(forNode)
 36 : DynamicSubtreeNodeList(forNode->document()) , m_forNode(forNode)
3737{
3838}
3939
102444

Source/WebCore/html/LabelsNodeList.h

3030
3131namespace WebCore {
3232
33 class LabelsNodeList : public DynamicNodeList {
 33class LabelsNodeList : public DynamicSubtreeNodeList {
3434public:
3535 static PassRefPtr<LabelsNodeList> create(Node* forNode)
3636 {
102444

LayoutTests/ChangeLog

 12011-12-09 Ryosuke Niwa <rniwa@webkit.org>
 2
 3 NodeChildList shouldn't be in NodeListNodeData
 4 https://bugs.webkit.org/show_bug.cgi?id=73969
 5
 6 Added a regression test for ChildNodeList; it catches a bug caught in the review process.
 7
 8 * fast/dom/childnode-item-after-itemname-expected.txt: Added.
 9 * fast/dom/childnode-item-after-itemname.html: Added.
 10
1112011-12-09 Tony Chang <tony@chromium.org>
212
313 Fix test expectations from r102486: flex-flow returns direction and wrap now.
102496

LayoutTests/fast/dom/childnode-item-after-itemname-expected.txt

 1This tests accessing the first element in childNodes after accessing the second element by its id. WebKit should retrieve each element correctly, and you should see 2 1 below:
 2
 32 1
0

LayoutTests/fast/dom/childnode-item-after-itemname.html

 1<!DOCTYPE html>
 2<html>
 3<body>
 4<p>This tests accessing the first element in childNodes after accessing the second element by its id.
 5WebKit should retrieve each element correctly, and you should see 2 1 below:</p>
 6<span id="item"></span><span id="tests" style="display: none;">1<span id="item">2</span></span>
 7<script>
 8
 9if (window.layoutTestController)
 10 layoutTestController.dumpAsText();
 11
 12var tests = document.querySelector('#tests');
 13document.writeln(tests.childNodes['item'].textContent);
 14document.writeln(tests.childNodes[0].textContent);
 15
 16</script>
 17</body>
 18</html>
0