1 /*
2 * Copyright (C) 2008, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 David Smith <catfish.man@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_NODE_LISTS_NODE_DATA_H_
23 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_NODE_LISTS_NODE_DATA_H_
24
25 #include "base/macros.h"
26 #include "third_party/blink/renderer/core/dom/child_node_list.h"
27 #include "third_party/blink/renderer/core/dom/empty_node_list.h"
28 #include "third_party/blink/renderer/core/dom/qualified_name.h"
29 #include "third_party/blink/renderer/core/dom/tag_collection.h"
30 #include "third_party/blink/renderer/core/html/collection_type.h"
31 #include "third_party/blink/renderer/platform/heap/handle.h"
32 #include "third_party/blink/renderer/platform/heap/heap.h"
33 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
34 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
35
36 namespace blink {
37
38 class NodeListsNodeData final : public GarbageCollected<NodeListsNodeData> {
39 public:
GetChildNodeList(ContainerNode & node)40 ChildNodeList* GetChildNodeList(ContainerNode& node) {
41 DCHECK(!child_node_list_ || node == child_node_list_->VirtualOwnerNode());
42 return To<ChildNodeList>(child_node_list_.Get());
43 }
44
EnsureChildNodeList(ContainerNode & node)45 ChildNodeList* EnsureChildNodeList(ContainerNode& node) {
46 if (child_node_list_)
47 return To<ChildNodeList>(child_node_list_.Get());
48 auto* list = MakeGarbageCollected<ChildNodeList>(node);
49 child_node_list_ = list;
50 return list;
51 }
52
EnsureEmptyChildNodeList(Node & node)53 EmptyNodeList* EnsureEmptyChildNodeList(Node& node) {
54 if (child_node_list_)
55 return To<EmptyNodeList>(child_node_list_.Get());
56 auto* list = MakeGarbageCollected<EmptyNodeList>(node);
57 child_node_list_ = list;
58 return list;
59 }
60
61 using NamedNodeListKey = std::pair<CollectionType, AtomicString>;
62 struct NodeListAtomicCacheMapEntryHash {
63 STATIC_ONLY(NodeListAtomicCacheMapEntryHash);
GetHashNodeListAtomicCacheMapEntryHash64 static unsigned GetHash(const NamedNodeListKey& entry) {
65 return DefaultHash<AtomicString>::Hash::GetHash(
66 entry.second == CSSSelector::UniversalSelectorAtom()
67 ? g_star_atom
68 : entry.second) +
69 entry.first;
70 }
EqualNodeListAtomicCacheMapEntryHash71 static bool Equal(const NamedNodeListKey& a, const NamedNodeListKey& b) {
72 return a == b;
73 }
74 static const bool safe_to_compare_to_empty_or_deleted =
75 DefaultHash<AtomicString>::Hash::safe_to_compare_to_empty_or_deleted;
76 };
77
78 typedef HeapHashMap<NamedNodeListKey,
79 Member<LiveNodeListBase>,
80 NodeListAtomicCacheMapEntryHash>
81 NodeListAtomicNameCacheMap;
82 typedef HeapHashMap<QualifiedName, Member<TagCollectionNS>>
83 TagCollectionNSCache;
84
85 template <typename T>
AddCache(ContainerNode & node,CollectionType collection_type,const AtomicString & name)86 T* AddCache(ContainerNode& node,
87 CollectionType collection_type,
88 const AtomicString& name) {
89 NodeListAtomicNameCacheMap::AddResult result = atomic_name_caches_.insert(
90 std::make_pair(collection_type, name), nullptr);
91 if (!result.is_new_entry) {
92 return static_cast<T*>(result.stored_value->value.Get());
93 }
94
95 auto* list = MakeGarbageCollected<T>(node, collection_type, name);
96 result.stored_value->value = list;
97 return list;
98 }
99
100 template <typename T>
AddCache(ContainerNode & node,CollectionType collection_type)101 T* AddCache(ContainerNode& node, CollectionType collection_type) {
102 NodeListAtomicNameCacheMap::AddResult result = atomic_name_caches_.insert(
103 NamedNodeListKey(collection_type, CSSSelector::UniversalSelectorAtom()),
104 nullptr);
105 if (!result.is_new_entry) {
106 return static_cast<T*>(result.stored_value->value.Get());
107 }
108
109 auto* list = MakeGarbageCollected<T>(node, collection_type);
110 result.stored_value->value = list;
111 return list;
112 }
113
114 template <typename T>
Cached(CollectionType collection_type)115 T* Cached(CollectionType collection_type) {
116 return static_cast<T*>(atomic_name_caches_.at(NamedNodeListKey(
117 collection_type, CSSSelector::UniversalSelectorAtom())));
118 }
119
AddCache(ContainerNode & node,const AtomicString & namespace_uri,const AtomicString & local_name)120 TagCollectionNS* AddCache(ContainerNode& node,
121 const AtomicString& namespace_uri,
122 const AtomicString& local_name) {
123 QualifiedName name(g_null_atom, local_name, namespace_uri);
124 TagCollectionNSCache::AddResult result =
125 tag_collection_ns_caches_.insert(name, nullptr);
126 if (!result.is_new_entry)
127 return result.stored_value->value;
128
129 auto* list = MakeGarbageCollected<TagCollectionNS>(
130 node, kTagCollectionNSType, namespace_uri, local_name);
131 result.stored_value->value = list;
132 return list;
133 }
134
NodeListsNodeData()135 NodeListsNodeData() : child_node_list_(nullptr) {}
136
137 void InvalidateCaches(const QualifiedName* attr_name = nullptr);
138
IsEmpty()139 bool IsEmpty() const {
140 return !child_node_list_ && atomic_name_caches_.IsEmpty() &&
141 tag_collection_ns_caches_.IsEmpty();
142 }
143
AdoptTreeScope()144 void AdoptTreeScope() { InvalidateCaches(); }
145
AdoptDocument(Document & old_document,Document & new_document)146 void AdoptDocument(Document& old_document, Document& new_document) {
147 DCHECK_NE(old_document, new_document);
148
149 NodeListAtomicNameCacheMap::const_iterator atomic_name_cache_end =
150 atomic_name_caches_.end();
151 for (NodeListAtomicNameCacheMap::const_iterator it =
152 atomic_name_caches_.begin();
153 it != atomic_name_cache_end; ++it) {
154 LiveNodeListBase* list = it->value;
155 list->DidMoveToDocument(old_document, new_document);
156 }
157
158 TagCollectionNSCache::const_iterator tag_end =
159 tag_collection_ns_caches_.end();
160 for (TagCollectionNSCache::const_iterator it =
161 tag_collection_ns_caches_.begin();
162 it != tag_end; ++it) {
163 LiveNodeListBase* list = it->value;
164 DCHECK(!list->IsRootedAtTreeScope());
165 list->DidMoveToDocument(old_document, new_document);
166 }
167 }
168
169 void Trace(Visitor*);
170
171 private:
172 // Can be a ChildNodeList or an EmptyNodeList.
173 Member<NodeList> child_node_list_;
174 NodeListAtomicNameCacheMap atomic_name_caches_;
175 TagCollectionNSCache tag_collection_ns_caches_;
176 DISALLOW_COPY_AND_ASSIGN(NodeListsNodeData);
177 };
178
179 template <typename Collection>
EnsureCachedCollection(CollectionType type)180 inline Collection* ContainerNode::EnsureCachedCollection(CollectionType type) {
181 return EnsureNodeLists().AddCache<Collection>(*this, type);
182 }
183
184 template <typename Collection>
EnsureCachedCollection(CollectionType type,const AtomicString & name)185 inline Collection* ContainerNode::EnsureCachedCollection(
186 CollectionType type,
187 const AtomicString& name) {
188 return EnsureNodeLists().AddCache<Collection>(*this, type, name);
189 }
190
191 template <typename Collection>
EnsureCachedCollection(CollectionType type,const AtomicString & namespace_uri,const AtomicString & local_name)192 inline Collection* ContainerNode::EnsureCachedCollection(
193 CollectionType type,
194 const AtomicString& namespace_uri,
195 const AtomicString& local_name) {
196 DCHECK_EQ(type, kTagCollectionNSType);
197 return EnsureNodeLists().AddCache(*this, namespace_uri, local_name);
198 }
199
200 template <typename Collection>
CachedCollection(CollectionType type)201 inline Collection* ContainerNode::CachedCollection(CollectionType type) {
202 NodeListsNodeData* node_lists = NodeLists();
203 return node_lists ? node_lists->Cached<Collection>(type) : nullptr;
204 }
205
206 } // namespace blink
207
208 #endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_NODE_LISTS_NODE_DATA_H_
209