Backed out changeset ddccd40117a0 (bug 1853271) for causing bug 1854769. CLOSED TREE
[gecko.git] / parser / htmlparser / nsHTMLTags.cpp
blobec3c4f322da183757903ed39e323bb661ec2aeba
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/. */
6 #include "nsHTMLTags.h"
7 #include "nsCRT.h"
8 #include "nsElementTable.h"
9 #include "nsReadableUtils.h"
10 #include "nsString.h"
11 #include "nsUnicharUtils.h"
12 #include "mozilla/HashFunctions.h"
13 #include <algorithm>
15 using namespace mozilla;
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::sTagNames[] = {
21 #include "nsHTMLTagList.h"
23 #undef HTML_TAG
24 #undef HTML_OTHER
26 int32_t nsHTMLTags::gTableRefCount;
27 nsHTMLTags::TagStringHash* nsHTMLTags::gTagTable;
28 nsHTMLTags::TagAtomHash* nsHTMLTags::gTagAtomTable;
30 #define NS_HTMLTAG_NAME_MAX_LENGTH 10
32 // static
33 nsresult nsHTMLTags::AddRefTable(void) {
34 if (gTableRefCount++ == 0) {
35 NS_ASSERTION(!gTagTable && !gTagAtomTable, "pre existing hash!");
37 gTagTable = new TagStringHash(64);
38 gTagAtomTable = new TagAtomHash(64);
40 // Fill in gTagTable with the above static char16_t strings as
41 // keys and the value of the corresponding enum as the value in
42 // the table.
44 for (int32_t i = 0; i < NS_HTML_TAG_MAX; ++i) {
45 const char16_t* tagName = sTagNames[i];
46 const nsHTMLTag tagValue = static_cast<nsHTMLTag>(i + 1);
48 // We use AssignLiteral here to avoid a string copy. This is okay
49 // because this is truly static data.
50 nsString tmp;
51 tmp.AssignLiteral(tagName, nsString::char_traits::length(tagName));
52 gTagTable->InsertOrUpdate(tmp, tagValue);
54 // All the HTML tag names are static atoms within nsGkAtoms, and they are
55 // registered before this code is reached.
56 nsStaticAtom* atom = NS_GetStaticAtom(tmp);
57 MOZ_ASSERT(atom);
58 gTagAtomTable->InsertOrUpdate(atom, tagValue);
61 #ifdef DEBUG
62 // Check all tagNames are lowercase, and that NS_HTMLTAG_NAME_MAX_LENGTH is
63 // correct.
64 uint32_t maxTagNameLength = 0;
65 for (int i = 0; i < NS_HTML_TAG_MAX; ++i) {
66 const char16_t* tagName = sTagNames[i];
68 nsAutoString lowerTagName(tagName);
69 ToLowerCase(lowerTagName);
70 MOZ_ASSERT(lowerTagName.Equals(tagName));
72 maxTagNameLength = std::max(NS_strlen(tagName), maxTagNameLength);
75 MOZ_ASSERT(maxTagNameLength == NS_HTMLTAG_NAME_MAX_LENGTH);
77 CheckElementTable();
78 TestTagTable();
79 #endif
82 return NS_OK;
85 // static
86 void nsHTMLTags::ReleaseTable(void) {
87 if (0 == --gTableRefCount) {
88 delete gTagTable;
89 delete gTagAtomTable;
90 gTagTable = nullptr;
91 gTagAtomTable = nullptr;
95 // static
96 nsHTMLTag nsHTMLTags::StringTagToId(const nsAString& aTagName) {
97 uint32_t length = aTagName.Length();
99 if (length > NS_HTMLTAG_NAME_MAX_LENGTH) {
100 return eHTMLTag_userdefined;
103 // Setup a stack allocated string buffer with the appropriate length.
104 nsAutoString lowerCase;
105 lowerCase.SetLength(length);
107 // Operate on the raw buffers to avoid bounds checks.
108 auto src = aTagName.BeginReading();
109 auto dst = lowerCase.BeginWriting();
111 // Fast lowercasing-while-copying of ASCII characters into a
112 // nsString buffer.
114 for (uint32_t i = 0; i < length; i++) {
115 char16_t c = src[i];
117 if (c <= 'Z' && c >= 'A') {
118 c |= 0x20; // Lowercase the ASCII character.
121 dst[i] = c; // Copy ASCII character.
124 return CaseSensitiveStringTagToId(lowerCase);
127 #ifdef DEBUG
128 void nsHTMLTags::TestTagTable() {
129 const char16_t* tag;
130 nsHTMLTag id;
131 RefPtr<nsAtom> atom;
133 nsHTMLTags::AddRefTable();
134 // Make sure we can find everything we are supposed to
135 for (int i = 0; i < NS_HTML_TAG_MAX; ++i) {
136 tag = sTagNames[i];
137 const nsAString& tagString = nsDependentString(tag);
138 id = StringTagToId(tagString);
139 NS_ASSERTION(id != eHTMLTag_userdefined, "can't find tag id");
141 nsAutoString uname(tagString);
142 ToUpperCase(uname);
143 NS_ASSERTION(id == StringTagToId(uname), "wrong id");
145 NS_ASSERTION(id == CaseSensitiveStringTagToId(tagString), "wrong id");
147 atom = NS_Atomize(tag);
148 NS_ASSERTION(id == CaseSensitiveAtomTagToId(atom), "wrong id");
151 // Make sure we don't find things that aren't there
152 id = StringTagToId(u"@"_ns);
153 NS_ASSERTION(id == eHTMLTag_userdefined, "found @");
154 id = StringTagToId(u"zzzzz"_ns);
155 NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz");
157 atom = NS_Atomize("@");
158 id = CaseSensitiveAtomTagToId(atom);
159 NS_ASSERTION(id == eHTMLTag_userdefined, "found @");
160 atom = NS_Atomize("zzzzz");
161 id = CaseSensitiveAtomTagToId(atom);
162 NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz");
164 ReleaseTable();
167 #endif // DEBUG