/src/mozilla-central/dom/html/HTMLAllCollection.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "mozilla/dom/HTMLAllCollection.h" |
8 | | |
9 | | #include "mozilla/dom/HTMLAllCollectionBinding.h" |
10 | | #include "mozilla/dom/Nullable.h" |
11 | | #include "mozilla/dom/Element.h" |
12 | | #include "nsHTMLDocument.h" |
13 | | |
14 | | namespace mozilla { |
15 | | namespace dom { |
16 | | |
17 | | HTMLAllCollection::HTMLAllCollection(nsHTMLDocument* aDocument) |
18 | | : mDocument(aDocument) |
19 | 0 | { |
20 | 0 | MOZ_ASSERT(mDocument); |
21 | 0 | } |
22 | | |
23 | | HTMLAllCollection::~HTMLAllCollection() |
24 | 0 | { |
25 | 0 | } |
26 | | |
27 | | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLAllCollection, |
28 | | mDocument, |
29 | | mCollection, |
30 | | mNamedMap) |
31 | | |
32 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLAllCollection) |
33 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLAllCollection) |
34 | | |
35 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLAllCollection) |
36 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
37 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
38 | 0 | NS_INTERFACE_MAP_END |
39 | | |
40 | | nsINode* |
41 | | HTMLAllCollection::GetParentObject() const |
42 | 0 | { |
43 | 0 | return mDocument; |
44 | 0 | } |
45 | | |
46 | | uint32_t |
47 | | HTMLAllCollection::Length() |
48 | 0 | { |
49 | 0 | return Collection()->Length(true); |
50 | 0 | } |
51 | | |
52 | | nsIContent* |
53 | | HTMLAllCollection::Item(uint32_t aIndex) |
54 | 0 | { |
55 | 0 | return Collection()->Item(aIndex); |
56 | 0 | } |
57 | | |
58 | | nsContentList* |
59 | | HTMLAllCollection::Collection() |
60 | 0 | { |
61 | 0 | if (!mCollection) { |
62 | 0 | nsIDocument* document = mDocument; |
63 | 0 | mCollection = document->GetElementsByTagName(NS_LITERAL_STRING("*")); |
64 | 0 | MOZ_ASSERT(mCollection); |
65 | 0 | } |
66 | 0 | return mCollection; |
67 | 0 | } |
68 | | |
69 | | static bool |
70 | | IsAllNamedElement(nsIContent* aContent) |
71 | 0 | { |
72 | 0 | return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, |
73 | 0 | nsGkAtoms::button, |
74 | 0 | nsGkAtoms::embed, |
75 | 0 | nsGkAtoms::form, |
76 | 0 | nsGkAtoms::iframe, |
77 | 0 | nsGkAtoms::img, |
78 | 0 | nsGkAtoms::input, |
79 | 0 | nsGkAtoms::map, |
80 | 0 | nsGkAtoms::meta, |
81 | 0 | nsGkAtoms::object, |
82 | 0 | nsGkAtoms::select, |
83 | 0 | nsGkAtoms::textarea, |
84 | 0 | nsGkAtoms::frame, |
85 | 0 | nsGkAtoms::frameset); |
86 | 0 | } |
87 | | |
88 | | static bool |
89 | | DocAllResultMatch(Element* aElement, int32_t aNamespaceID, nsAtom* aAtom, |
90 | | void* aData) |
91 | 0 | { |
92 | 0 | if (aElement->GetID() == aAtom) { |
93 | 0 | return true; |
94 | 0 | } |
95 | 0 | |
96 | 0 | nsGenericHTMLElement* elm = nsGenericHTMLElement::FromNode(aElement); |
97 | 0 | if (!elm) { |
98 | 0 | return false; |
99 | 0 | } |
100 | 0 | |
101 | 0 | if (!IsAllNamedElement(elm)) { |
102 | 0 | return false; |
103 | 0 | } |
104 | 0 | |
105 | 0 | const nsAttrValue* val = elm->GetParsedAttr(nsGkAtoms::name); |
106 | 0 | return val && val->Type() == nsAttrValue::eAtom && |
107 | 0 | val->GetAtomValue() == aAtom; |
108 | 0 | } |
109 | | |
110 | | nsContentList* |
111 | | HTMLAllCollection::GetDocumentAllList(const nsAString& aID) |
112 | 0 | { |
113 | 0 | return mNamedMap.LookupForAdd(aID).OrInsert( |
114 | 0 | [this, &aID] () { |
115 | 0 | RefPtr<nsAtom> id = NS_Atomize(aID); |
116 | 0 | return new nsContentList(mDocument, DocAllResultMatch, nullptr, |
117 | 0 | nullptr, true, id); |
118 | 0 | }); |
119 | 0 | } |
120 | | |
121 | | void |
122 | | HTMLAllCollection::NamedGetter(const nsAString& aID, |
123 | | bool& aFound, |
124 | | Nullable<OwningNodeOrHTMLCollection>& aResult) |
125 | 0 | { |
126 | 0 | if (aID.IsEmpty()) { |
127 | 0 | aFound = false; |
128 | 0 | aResult.SetNull(); |
129 | 0 | return; |
130 | 0 | } |
131 | 0 | |
132 | 0 | nsContentList* docAllList = GetDocumentAllList(aID); |
133 | 0 | if (!docAllList) { |
134 | 0 | aFound = false; |
135 | 0 | aResult.SetNull(); |
136 | 0 | return; |
137 | 0 | } |
138 | 0 | |
139 | 0 | // Check if there are more than 1 entries. Do this by getting the second one |
140 | 0 | // rather than the length since getting the length always requires walking |
141 | 0 | // the entire document. |
142 | 0 | if (docAllList->Item(1, true)) { |
143 | 0 | aFound = true; |
144 | 0 | aResult.SetValue().SetAsHTMLCollection() = docAllList; |
145 | 0 | return; |
146 | 0 | } |
147 | 0 | |
148 | 0 | // There's only 0 or 1 items. Return the first one or null. |
149 | 0 | if (nsIContent* node = docAllList->Item(0, true)) { |
150 | 0 | aFound = true; |
151 | 0 | aResult.SetValue().SetAsNode() = node; |
152 | 0 | return; |
153 | 0 | } |
154 | 0 | |
155 | 0 | aFound = false; |
156 | 0 | aResult.SetNull(); |
157 | 0 | } |
158 | | |
159 | | void |
160 | | HTMLAllCollection::GetSupportedNames(nsTArray<nsString>& aNames) |
161 | 0 | { |
162 | 0 | // XXXbz this is very similar to nsContentList::GetSupportedNames, |
163 | 0 | // but has to check IsAllNamedElement for the name case. |
164 | 0 | AutoTArray<nsAtom*, 8> atoms; |
165 | 0 | for (uint32_t i = 0; i < Length(); ++i) { |
166 | 0 | nsIContent *content = Item(i); |
167 | 0 | if (content->HasID()) { |
168 | 0 | nsAtom* id = content->GetID(); |
169 | 0 | MOZ_ASSERT(id != nsGkAtoms::_empty, |
170 | 0 | "Empty ids don't get atomized"); |
171 | 0 | if (!atoms.Contains(id)) { |
172 | 0 | atoms.AppendElement(id); |
173 | 0 | } |
174 | 0 | } |
175 | 0 |
|
176 | 0 | nsGenericHTMLElement* el = nsGenericHTMLElement::FromNode(content); |
177 | 0 | if (el) { |
178 | 0 | // Note: nsINode::HasName means the name is exposed on the document, |
179 | 0 | // which is false for options, so we don't check it here. |
180 | 0 | const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name); |
181 | 0 | if (val && val->Type() == nsAttrValue::eAtom && |
182 | 0 | IsAllNamedElement(content)) { |
183 | 0 | nsAtom* name = val->GetAtomValue(); |
184 | 0 | MOZ_ASSERT(name != nsGkAtoms::_empty, |
185 | 0 | "Empty names don't get atomized"); |
186 | 0 | if (!atoms.Contains(name)) { |
187 | 0 | atoms.AppendElement(name); |
188 | 0 | } |
189 | 0 | } |
190 | 0 | } |
191 | 0 | } |
192 | 0 |
|
193 | 0 | uint32_t atomsLen = atoms.Length(); |
194 | 0 | nsString* names = aNames.AppendElements(atomsLen); |
195 | 0 | for (uint32_t i = 0; i < atomsLen; ++i) { |
196 | 0 | atoms[i]->ToString(names[i]); |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | |
201 | | JSObject* |
202 | | HTMLAllCollection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
203 | 0 | { |
204 | 0 | return HTMLAllCollection_Binding::Wrap(aCx, this, aGivenProto); |
205 | 0 | } |
206 | | |
207 | | } // namespace dom |
208 | | } // namespace mozilla |