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 "nsDataHashtable.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
->Put(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
->Put(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
);
83 void nsHTMLTags::ReleaseTable(void) {
84 if (0 == --gTableRefCount
) {
88 gTagAtomTable
= nullptr;
93 nsHTMLTag
nsHTMLTags::StringTagToId(const nsAString
& aTagName
) {
94 uint32_t length
= aTagName
.Length();
96 if (length
> NS_HTMLTAG_NAME_MAX_LENGTH
) {
97 return eHTMLTag_userdefined
;
100 // Setup a stack allocated string buffer with the appropriate length.
101 nsAutoString lowerCase
;
102 lowerCase
.SetLength(length
);
104 // Operate on the raw buffers to avoid bounds checks.
105 auto src
= aTagName
.BeginReading();
106 auto dst
= lowerCase
.BeginWriting();
108 // Fast lowercasing-while-copying of ASCII characters into a
111 for (uint32_t i
= 0; i
< length
; i
++) {
114 if (c
<= 'Z' && c
>= 'A') {
115 c
|= 0x20; // Lowercase the ASCII character.
118 dst
[i
] = c
; // Copy ASCII character.
121 return CaseSensitiveStringTagToId(lowerCase
);
125 void nsHTMLTags::TestTagTable() {
130 nsHTMLTags::AddRefTable();
131 // Make sure we can find everything we are supposed to
132 for (int i
= 0; i
< NS_HTML_TAG_MAX
; ++i
) {
134 const nsAString
& tagString
= nsDependentString(tag
);
135 id
= StringTagToId(tagString
);
136 NS_ASSERTION(id
!= eHTMLTag_userdefined
, "can't find tag id");
138 nsAutoString
uname(tagString
);
140 NS_ASSERTION(id
== StringTagToId(uname
), "wrong id");
142 NS_ASSERTION(id
== CaseSensitiveStringTagToId(tagString
), "wrong id");
144 atom
= NS_Atomize(tag
);
145 NS_ASSERTION(id
== CaseSensitiveAtomTagToId(atom
), "wrong id");
148 // Make sure we don't find things that aren't there
149 id
= StringTagToId(u
"@"_ns
);
150 NS_ASSERTION(id
== eHTMLTag_userdefined
, "found @");
151 id
= StringTagToId(u
"zzzzz"_ns
);
152 NS_ASSERTION(id
== eHTMLTag_userdefined
, "found zzzzz");
154 atom
= NS_Atomize("@");
155 id
= CaseSensitiveAtomTagToId(atom
);
156 NS_ASSERTION(id
== eHTMLTag_userdefined
, "found @");
157 atom
= NS_Atomize("zzzzz");
158 id
= CaseSensitiveAtomTagToId(atom
);
159 NS_ASSERTION(id
== eHTMLTag_userdefined
, "found zzzzz");