Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "nsHTMLTags.h"
7 : #include "nsCRT.h"
8 : #include "nsReadableUtils.h"
9 : #include "nsString.h"
10 : #include "nsStaticAtom.h"
11 : #include "nsUnicharUtils.h"
12 : #include "mozilla/HashFunctions.h"
13 : #include <algorithm>
14 :
15 : using namespace mozilla;
16 :
17 : // static array of unicode tag names
18 : #define HTML_TAG(_tag, _classname, _interfacename) (u"" #_tag),
19 : #define HTML_OTHER(_tag)
20 : const char16_t* const nsHTMLTags::sTagUnicodeTable[] = {
21 : #include "nsHTMLTagList.h"
22 : };
23 : #undef HTML_TAG
24 : #undef HTML_OTHER
25 :
26 : // static array of tag atoms
27 : nsIAtom* nsHTMLTags::sTagAtomTable[eHTMLTag_userdefined - 1];
28 :
29 : int32_t nsHTMLTags::gTableRefCount;
30 : PLHashTable* nsHTMLTags::gTagTable;
31 : PLHashTable* nsHTMLTags::gTagAtomTable;
32 :
33 :
34 : // char16_t* -> id hash
35 : static PLHashNumber
36 1100 : HTMLTagsHashCodeUCPtr(const void *key)
37 : {
38 1100 : return HashString(static_cast<const char16_t*>(key));
39 : }
40 :
41 : static int
42 822 : HTMLTagsKeyCompareUCPtr(const void *key1, const void *key2)
43 : {
44 822 : const char16_t *str1 = (const char16_t *)key1;
45 822 : const char16_t *str2 = (const char16_t *)key2;
46 :
47 822 : return nsCRT::strcmp(str1, str2) == 0;
48 : }
49 :
50 : // nsIAtom* -> id hash
51 : static PLHashNumber
52 626 : HTMLTagsHashCodeAtom(const void *key)
53 : {
54 626 : return NS_PTR_TO_INT32(key) >> 2;
55 : }
56 :
57 : #define NS_HTMLTAG_NAME_MAX_LENGTH 10
58 :
59 : // static
60 : void
61 3 : nsHTMLTags::RegisterAtoms(void)
62 : {
63 : #define HTML_TAG(_tag, _classname, _interfacename) NS_STATIC_ATOM_BUFFER(Atombuffer_##_tag, #_tag)
64 : #define HTML_OTHER(_tag)
65 : #include "nsHTMLTagList.h"
66 : #undef HTML_TAG
67 : #undef HTML_OTHER
68 :
69 : // static array of tag StaticAtom structs
70 : #define HTML_TAG(_tag, _classname, _interfacename) NS_STATIC_ATOM(Atombuffer_##_tag, &nsHTMLTags::sTagAtomTable[eHTMLTag_##_tag - 1]),
71 : #define HTML_OTHER(_tag)
72 : static const nsStaticAtom sTagAtoms_info[] = {
73 : #include "nsHTMLTagList.h"
74 : };
75 : #undef HTML_TAG
76 : #undef HTML_OTHER
77 :
78 : // Fill in our static atom pointers
79 3 : NS_RegisterStaticAtoms(sTagAtoms_info);
80 :
81 :
82 : #if defined(DEBUG)
83 : {
84 : // let's verify that all names in the the table are lowercase...
85 414 : for (int32_t i = 0; i < NS_HTML_TAG_MAX; ++i) {
86 822 : nsAutoString temp1((char16_t*)sTagAtoms_info[i].mStringBuffer->Data());
87 822 : nsAutoString temp2((char16_t*)sTagAtoms_info[i].mStringBuffer->Data());
88 411 : ToLowerCase(temp1);
89 411 : NS_ASSERTION(temp1.Equals(temp2), "upper case char in table");
90 : }
91 :
92 : // let's verify that all names in the unicode strings above are
93 : // correct.
94 414 : for (int32_t i = 0; i < NS_HTML_TAG_MAX; ++i) {
95 822 : nsAutoString temp1(sTagUnicodeTable[i]);
96 822 : nsAutoString temp2((char16_t*)sTagAtoms_info[i].mStringBuffer->Data());
97 411 : NS_ASSERTION(temp1.Equals(temp2), "Bad unicode tag name!");
98 : }
99 :
100 : // let's verify that NS_HTMLTAG_NAME_MAX_LENGTH is correct
101 3 : uint32_t maxTagNameLength = 0;
102 414 : for (int32_t i = 0; i < NS_HTML_TAG_MAX; ++i) {
103 411 : uint32_t len = NS_strlen(sTagUnicodeTable[i]);
104 411 : maxTagNameLength = std::max(len, maxTagNameLength);
105 : }
106 3 : NS_ASSERTION(maxTagNameLength == NS_HTMLTAG_NAME_MAX_LENGTH,
107 : "NS_HTMLTAG_NAME_MAX_LENGTH not set correctly!");
108 : }
109 : #endif
110 3 : }
111 :
112 : // static
113 : nsresult
114 4 : nsHTMLTags::AddRefTable(void)
115 : {
116 4 : if (gTableRefCount++ == 0) {
117 2 : NS_ASSERTION(!gTagTable && !gTagAtomTable, "pre existing hash!");
118 :
119 2 : gTagTable = PL_NewHashTable(64, HTMLTagsHashCodeUCPtr,
120 : HTMLTagsKeyCompareUCPtr, PL_CompareValues,
121 : nullptr, nullptr);
122 2 : NS_ENSURE_TRUE(gTagTable, NS_ERROR_OUT_OF_MEMORY);
123 :
124 2 : gTagAtomTable = PL_NewHashTable(64, HTMLTagsHashCodeAtom,
125 : PL_CompareValues, PL_CompareValues,
126 : nullptr, nullptr);
127 2 : NS_ENSURE_TRUE(gTagAtomTable, NS_ERROR_OUT_OF_MEMORY);
128 :
129 : // Fill in gTagTable with the above static char16_t strings as
130 : // keys and the value of the corresponding enum as the value in
131 : // the table.
132 :
133 : int32_t i;
134 276 : for (i = 0; i < NS_HTML_TAG_MAX; ++i) {
135 274 : PL_HashTableAdd(gTagTable, sTagUnicodeTable[i],
136 548 : NS_INT32_TO_PTR(i + 1));
137 :
138 274 : PL_HashTableAdd(gTagAtomTable, sTagAtomTable[i],
139 548 : NS_INT32_TO_PTR(i + 1));
140 : }
141 : }
142 :
143 4 : return NS_OK;
144 : }
145 :
146 : // static
147 : void
148 2 : nsHTMLTags::ReleaseTable(void)
149 : {
150 2 : if (0 == --gTableRefCount) {
151 0 : if (gTagTable) {
152 : // Nothing to delete/free in this table, just destroy the table.
153 :
154 0 : PL_HashTableDestroy(gTagTable);
155 0 : PL_HashTableDestroy(gTagAtomTable);
156 0 : gTagTable = nullptr;
157 0 : gTagAtomTable = nullptr;
158 : }
159 : }
160 2 : }
161 :
162 : // static
163 : nsHTMLTag
164 552 : nsHTMLTags::LookupTag(const nsAString& aTagName)
165 : {
166 552 : uint32_t length = aTagName.Length();
167 :
168 552 : if (length > NS_HTMLTAG_NAME_MAX_LENGTH) {
169 0 : return eHTMLTag_userdefined;
170 : }
171 :
172 : char16_t buf[NS_HTMLTAG_NAME_MAX_LENGTH + 1];
173 :
174 552 : nsAString::const_iterator iter;
175 552 : uint32_t i = 0;
176 : char16_t c;
177 :
178 552 : aTagName.BeginReading(iter);
179 :
180 : // Fast lowercasing-while-copying of ASCII characters into a
181 : // char16_t buffer
182 :
183 5632 : while (i < length) {
184 2540 : c = *iter;
185 :
186 2540 : if (c <= 'Z' && c >= 'A') {
187 1252 : c |= 0x20; // Lowercase the ASCII character.
188 : }
189 :
190 2540 : buf[i] = c; // Copy ASCII character.
191 :
192 2540 : ++i;
193 2540 : ++iter;
194 : }
195 :
196 552 : buf[i] = 0;
197 :
198 552 : return CaseSensitiveLookupTag(buf);
199 : }
200 :
201 : #ifdef DEBUG
202 : void
203 2 : nsHTMLTags::TestTagTable()
204 : {
205 : const char16_t *tag;
206 : nsHTMLTag id;
207 4 : nsCOMPtr<nsIAtom> atom;
208 :
209 2 : nsHTMLTags::AddRefTable();
210 : // Make sure we can find everything we are supposed to
211 276 : for (int i = 0; i < NS_HTML_TAG_MAX; ++i) {
212 274 : tag = sTagUnicodeTable[i];
213 274 : id = LookupTag(nsDependentString(tag));
214 274 : NS_ASSERTION(id != eHTMLTag_userdefined, "can't find tag id");
215 274 : const char16_t* check = GetStringValue(id);
216 274 : NS_ASSERTION(0 == nsCRT::strcmp(check, tag), "can't map id back to tag");
217 :
218 548 : nsAutoString uname(tag);
219 274 : ToUpperCase(uname);
220 274 : NS_ASSERTION(id == LookupTag(uname), "wrong id");
221 :
222 274 : NS_ASSERTION(id == CaseSensitiveLookupTag(tag), "wrong id");
223 :
224 274 : atom = NS_Atomize(tag);
225 274 : NS_ASSERTION(id == CaseSensitiveLookupTag(atom), "wrong id");
226 274 : NS_ASSERTION(atom == GetAtom(id), "can't map id back to atom");
227 : }
228 :
229 : // Make sure we don't find things that aren't there
230 2 : id = LookupTag(NS_LITERAL_STRING("@"));
231 2 : NS_ASSERTION(id == eHTMLTag_userdefined, "found @");
232 2 : id = LookupTag(NS_LITERAL_STRING("zzzzz"));
233 2 : NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz");
234 :
235 2 : atom = NS_Atomize("@");
236 2 : id = CaseSensitiveLookupTag(atom);
237 2 : NS_ASSERTION(id == eHTMLTag_userdefined, "found @");
238 2 : atom = NS_Atomize("zzzzz");
239 2 : id = CaseSensitiveLookupTag(atom);
240 2 : NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz");
241 :
242 2 : tag = GetStringValue((nsHTMLTag) 0);
243 2 : NS_ASSERTION(!tag, "found enum 0");
244 2 : tag = GetStringValue((nsHTMLTag) -1);
245 2 : NS_ASSERTION(!tag, "found enum -1");
246 2 : tag = GetStringValue((nsHTMLTag) (NS_HTML_TAG_MAX + 1));
247 2 : NS_ASSERTION(!tag, "found past max enum");
248 :
249 2 : atom = GetAtom((nsHTMLTag) 0);
250 2 : NS_ASSERTION(!atom, "found enum 0");
251 2 : atom = GetAtom((nsHTMLTag) -1);
252 2 : NS_ASSERTION(!atom, "found enum -1");
253 2 : atom = GetAtom((nsHTMLTag) (NS_HTML_TAG_MAX + 1));
254 2 : NS_ASSERTION(!atom, "found past max enum");
255 :
256 2 : ReleaseTable();
257 2 : }
258 :
259 : #endif // DEBUG
|