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 "nsReadableUtils.h"
10 #include "nsUnicharUtils.h"
11 #include "mozilla/HashFunctions.h"
14 using namespace mozilla
;
16 // static array of unicode tag names
17 #define HTML_TAG(_tag, _classname, _interfacename) (u"" #_tag),
18 #define HTML_OTHER(_tag)
19 const char16_t
* const nsHTMLTags::sTagNames
[] = {
20 #include "nsHTMLTagList.h"
25 int32_t nsHTMLTags::gTableRefCount
;
26 nsHTMLTags::TagStringHash
* nsHTMLTags::gTagTable
;
27 nsHTMLTags::TagAtomHash
* nsHTMLTags::gTagAtomTable
;
29 #define NS_HTMLTAG_NAME_MAX_LENGTH 10
32 nsresult
nsHTMLTags::AddRefTable(void) {
33 if (gTableRefCount
++ == 0) {
34 NS_ASSERTION(!gTagTable
&& !gTagAtomTable
, "pre existing hash!");
36 gTagTable
= new TagStringHash(64);
37 gTagAtomTable
= new TagAtomHash(64);
39 // Fill in gTagTable with the above static char16_t strings as
40 // keys and the value of the corresponding enum as the value in
43 for (int32_t i
= 0; i
< NS_HTML_TAG_MAX
; ++i
) {
44 const char16_t
* tagName
= sTagNames
[i
];
45 const nsHTMLTag tagValue
= static_cast<nsHTMLTag
>(i
+ 1);
47 // We use AssignLiteral here to avoid a string copy. This is okay
48 // because this is truly static data.
50 tmp
.AssignLiteral(tagName
, nsString::char_traits::length(tagName
));
51 gTagTable
->InsertOrUpdate(tmp
, tagValue
);
53 // All the HTML tag names are static atoms within nsGkAtoms, and they are
54 // registered before this code is reached.
55 nsStaticAtom
* atom
= NS_GetStaticAtom(tmp
);
57 gTagAtomTable
->InsertOrUpdate(atom
, tagValue
);
61 // Check all tagNames are lowercase, and that NS_HTMLTAG_NAME_MAX_LENGTH is
63 uint32_t maxTagNameLength
= 0;
64 for (int i
= 0; i
< NS_HTML_TAG_MAX
; ++i
) {
65 const char16_t
* tagName
= sTagNames
[i
];
67 nsAutoString
lowerTagName(tagName
);
68 ToLowerCase(lowerTagName
);
69 MOZ_ASSERT(lowerTagName
.Equals(tagName
));
71 maxTagNameLength
= std::max(NS_strlen(tagName
), maxTagNameLength
);
74 MOZ_ASSERT(maxTagNameLength
== NS_HTMLTAG_NAME_MAX_LENGTH
);
82 void nsHTMLTags::ReleaseTable(void) {
83 if (0 == --gTableRefCount
) {
87 gTagAtomTable
= nullptr;
92 nsHTMLTag
nsHTMLTags::StringTagToId(const nsAString
& aTagName
) {
93 uint32_t length
= aTagName
.Length();
95 if (length
> NS_HTMLTAG_NAME_MAX_LENGTH
) {
96 return eHTMLTag_userdefined
;
99 // Setup a stack allocated string buffer with the appropriate length.
100 nsAutoString lowerCase
;
101 lowerCase
.SetLength(length
);
103 // Operate on the raw buffers to avoid bounds checks.
104 auto src
= aTagName
.BeginReading();
105 auto dst
= lowerCase
.BeginWriting();
107 // Fast lowercasing-while-copying of ASCII characters into a
110 for (uint32_t i
= 0; i
< length
; i
++) {
113 if (c
<= 'Z' && c
>= 'A') {
114 c
|= 0x20; // Lowercase the ASCII character.
117 dst
[i
] = c
; // Copy ASCII character.
120 return CaseSensitiveStringTagToId(lowerCase
);
124 void nsHTMLTags::TestTagTable() {
129 nsHTMLTags::AddRefTable();
130 // Make sure we can find everything we are supposed to
131 for (int i
= 0; i
< NS_HTML_TAG_MAX
; ++i
) {
133 const nsAString
& tagString
= nsDependentString(tag
);
134 id
= StringTagToId(tagString
);
135 NS_ASSERTION(id
!= eHTMLTag_userdefined
, "can't find tag id");
137 nsAutoString
uname(tagString
);
139 NS_ASSERTION(id
== StringTagToId(uname
), "wrong id");
141 NS_ASSERTION(id
== CaseSensitiveStringTagToId(tagString
), "wrong id");
143 atom
= NS_Atomize(tag
);
144 NS_ASSERTION(id
== CaseSensitiveAtomTagToId(atom
), "wrong id");
147 // Make sure we don't find things that aren't there
148 id
= StringTagToId(u
"@"_ns
);
149 NS_ASSERTION(id
== eHTMLTag_userdefined
, "found @");
150 id
= StringTagToId(u
"zzzzz"_ns
);
151 NS_ASSERTION(id
== eHTMLTag_userdefined
, "found zzzzz");
153 atom
= NS_Atomize("@");
154 id
= CaseSensitiveAtomTagToId(atom
);
155 NS_ASSERTION(id
== eHTMLTag_userdefined
, "found @");
156 atom
= NS_Atomize("zzzzz");
157 id
= CaseSensitiveAtomTagToId(atom
);
158 NS_ASSERTION(id
== eHTMLTag_userdefined
, "found zzzzz");