nsHTMLTags.cpp (4796B)
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 "nsElementTable.h" 9 #include "nsReadableUtils.h" 10 #include "nsString.h" 11 #include "nsUnicharUtils.h" 12 #include <algorithm> 13 14 using namespace mozilla; 15 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" 21 }; 22 #undef HTML_TAG 23 #undef HTML_OTHER 24 25 int32_t nsHTMLTags::gTableRefCount; 26 nsHTMLTags::TagStringHash* nsHTMLTags::gTagTable; 27 nsHTMLTags::TagAtomHash* nsHTMLTags::gTagAtomTable; 28 29 #define NS_HTMLTAG_NAME_MAX_LENGTH 10 30 31 // static 32 nsresult nsHTMLTags::AddRefTable(void) { 33 if (gTableRefCount++ == 0) { 34 NS_ASSERTION(!gTagTable && !gTagAtomTable, "pre existing hash!"); 35 36 gTagTable = new TagStringHash(64); 37 gTagAtomTable = new TagAtomHash(64); 38 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 41 // the table. 42 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); 46 47 // We use AssignLiteral here to avoid a string copy. This is okay 48 // because this is truly static data. 49 nsString tmp; 50 tmp.AssignLiteral(tagName, nsString::char_traits::length(tagName)); 51 gTagTable->InsertOrUpdate(tmp, tagValue); 52 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); 56 MOZ_ASSERT(atom); 57 gTagAtomTable->InsertOrUpdate(atom, tagValue); 58 } 59 60 #ifdef DEBUG 61 // Check all tagNames are lowercase, and that NS_HTMLTAG_NAME_MAX_LENGTH is 62 // correct. 63 uint32_t maxTagNameLength = 0; 64 for (int i = 0; i < NS_HTML_TAG_MAX; ++i) { 65 const char16_t* tagName = sTagNames[i]; 66 67 nsAutoString lowerTagName(tagName); 68 ToLowerCase(lowerTagName); 69 MOZ_ASSERT(lowerTagName.Equals(tagName)); 70 71 maxTagNameLength = std::max(NS_strlen(tagName), maxTagNameLength); 72 } 73 74 MOZ_ASSERT(maxTagNameLength == NS_HTMLTAG_NAME_MAX_LENGTH); 75 76 CheckElementTable(); 77 TestTagTable(); 78 #endif 79 } 80 81 return NS_OK; 82 } 83 84 // static 85 void nsHTMLTags::ReleaseTable(void) { 86 if (0 == --gTableRefCount) { 87 delete gTagTable; 88 delete gTagAtomTable; 89 gTagTable = nullptr; 90 gTagAtomTable = nullptr; 91 } 92 } 93 94 // static 95 nsHTMLTag nsHTMLTags::StringTagToId(const nsAString& aTagName) { 96 uint32_t length = aTagName.Length(); 97 98 if (length > NS_HTMLTAG_NAME_MAX_LENGTH) { 99 return eHTMLTag_userdefined; 100 } 101 102 // Setup a stack allocated string buffer with the appropriate length. 103 nsAutoString lowerCase; 104 lowerCase.SetLength(length); 105 106 // Operate on the raw buffers to avoid bounds checks. 107 auto src = aTagName.BeginReading(); 108 auto dst = lowerCase.BeginWriting(); 109 110 // Fast lowercasing-while-copying of ASCII characters into a 111 // nsString buffer. 112 113 for (uint32_t i = 0; i < length; i++) { 114 char16_t c = src[i]; 115 116 if (c <= 'Z' && c >= 'A') { 117 c |= 0x20; // Lowercase the ASCII character. 118 } 119 120 dst[i] = c; // Copy ASCII character. 121 } 122 123 return CaseSensitiveStringTagToId(lowerCase); 124 } 125 126 #ifdef DEBUG 127 void nsHTMLTags::TestTagTable() { 128 const char16_t* tag; 129 nsHTMLTag id; 130 RefPtr<nsAtom> atom; 131 132 nsHTMLTags::AddRefTable(); 133 // Make sure we can find everything we are supposed to 134 for (int i = 0; i < NS_HTML_TAG_MAX; ++i) { 135 tag = sTagNames[i]; 136 const nsAString& tagString = nsDependentString(tag); 137 id = StringTagToId(tagString); 138 NS_ASSERTION(id != eHTMLTag_userdefined, "can't find tag id"); 139 140 nsAutoString uname(tagString); 141 ToUpperCase(uname); 142 NS_ASSERTION(id == StringTagToId(uname), "wrong id"); 143 144 NS_ASSERTION(id == CaseSensitiveStringTagToId(tagString), "wrong id"); 145 146 atom = NS_Atomize(tag); 147 NS_ASSERTION(id == CaseSensitiveAtomTagToId(atom), "wrong id"); 148 } 149 150 // Make sure we don't find things that aren't there 151 id = StringTagToId(u"@"_ns); 152 NS_ASSERTION(id == eHTMLTag_userdefined, "found @"); 153 id = StringTagToId(u"zzzzz"_ns); 154 NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz"); 155 156 atom = NS_Atomize("@"); 157 id = CaseSensitiveAtomTagToId(atom); 158 NS_ASSERTION(id == eHTMLTag_userdefined, "found @"); 159 atom = NS_Atomize("zzzzz"); 160 id = CaseSensitiveAtomTagToId(atom); 161 NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz"); 162 163 ReleaseTable(); 164 } 165 166 #endif // DEBUG