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"
8 #include "nsElementTable.h"
9 #include "nsReadableUtils.h"
11 #include "nsUnicharUtils.h"
12 #include "mozilla/HashFunctions.h"
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"
26 int32_t nsHTMLTags::gTableRefCount
;
27 nsHTMLTags::TagStringHash
* nsHTMLTags::gTagTable
;
28 nsHTMLTags::TagAtomHash
* nsHTMLTags::gTagAtomTable
;
30 #define NS_HTMLTAG_NAME_MAX_LENGTH 10
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
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.
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
);
58 gTagAtomTable
->InsertOrUpdate(atom
, tagValue
);
62 // Check all tagNames are lowercase, and that NS_HTMLTAG_NAME_MAX_LENGTH is
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
);
86 void nsHTMLTags::ReleaseTable(void) {
87 if (0 == --gTableRefCount
) {
91 gTagAtomTable
= nullptr;
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
114 for (uint32_t i
= 0; i
< length
; 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
);
128 void nsHTMLTags::TestTagTable() {
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
) {
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
);
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");