diff options
Diffstat (limited to 'parser/htmlparser/nsHTMLTags.cpp')
-rw-r--r-- | parser/htmlparser/nsHTMLTags.cpp | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/parser/htmlparser/nsHTMLTags.cpp b/parser/htmlparser/nsHTMLTags.cpp new file mode 100644 index 000000000..d5a68d46a --- /dev/null +++ b/parser/htmlparser/nsHTMLTags.cpp @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsHTMLTags.h" +#include "nsCRT.h" +#include "nsReadableUtils.h" +#include "nsString.h" +#include "nsStaticAtom.h" +#include "nsUnicharUtils.h" +#include "mozilla/HashFunctions.h" +#include <algorithm> + +using namespace mozilla; + +// static array of unicode tag names +#define HTML_TAG(_tag, _classname) (u"" #_tag), +#define HTML_HTMLELEMENT_TAG(_tag) (u"" #_tag), +#define HTML_OTHER(_tag) +const char16_t* const nsHTMLTags::sTagUnicodeTable[] = { +#include "nsHTMLTagList.h" +}; +#undef HTML_TAG +#undef HTML_HTMLELEMENT_TAG +#undef HTML_OTHER + +// static array of tag atoms +nsIAtom* nsHTMLTags::sTagAtomTable[eHTMLTag_userdefined - 1]; + +int32_t nsHTMLTags::gTableRefCount; +PLHashTable* nsHTMLTags::gTagTable; +PLHashTable* nsHTMLTags::gTagAtomTable; + + +// char16_t* -> id hash +static PLHashNumber +HTMLTagsHashCodeUCPtr(const void *key) +{ + return HashString(static_cast<const char16_t*>(key)); +} + +static int +HTMLTagsKeyCompareUCPtr(const void *key1, const void *key2) +{ + const char16_t *str1 = (const char16_t *)key1; + const char16_t *str2 = (const char16_t *)key2; + + return nsCRT::strcmp(str1, str2) == 0; +} + +// nsIAtom* -> id hash +static PLHashNumber +HTMLTagsHashCodeAtom(const void *key) +{ + return NS_PTR_TO_INT32(key) >> 2; +} + +#define NS_HTMLTAG_NAME_MAX_LENGTH 10 + +// static +void +nsHTMLTags::RegisterAtoms(void) +{ +#define HTML_TAG(_tag, _classname) NS_STATIC_ATOM_BUFFER(Atombuffer_##_tag, #_tag) +#define HTML_HTMLELEMENT_TAG(_tag) NS_STATIC_ATOM_BUFFER(Atombuffer_##_tag, #_tag) +#define HTML_OTHER(_tag) +#include "nsHTMLTagList.h" +#undef HTML_TAG +#undef HTML_HTMLELEMENT_TAG +#undef HTML_OTHER + +// static array of tag StaticAtom structs +#define HTML_TAG(_tag, _classname) NS_STATIC_ATOM(Atombuffer_##_tag, &nsHTMLTags::sTagAtomTable[eHTMLTag_##_tag - 1]), +#define HTML_HTMLELEMENT_TAG(_tag) NS_STATIC_ATOM(Atombuffer_##_tag, &nsHTMLTags::sTagAtomTable[eHTMLTag_##_tag - 1]), +#define HTML_OTHER(_tag) + static const nsStaticAtom sTagAtoms_info[] = { +#include "nsHTMLTagList.h" + }; +#undef HTML_TAG +#undef HTML_HTMLELEMENT_TAG +#undef HTML_OTHER + + // Fill in our static atom pointers + NS_RegisterStaticAtoms(sTagAtoms_info); + + +#if defined(DEBUG) + { + // let's verify that all names in the the table are lowercase... + for (int32_t i = 0; i < NS_HTML_TAG_MAX; ++i) { + nsAutoString temp1((char16_t*)sTagAtoms_info[i].mStringBuffer->Data()); + nsAutoString temp2((char16_t*)sTagAtoms_info[i].mStringBuffer->Data()); + ToLowerCase(temp1); + NS_ASSERTION(temp1.Equals(temp2), "upper case char in table"); + } + + // let's verify that all names in the unicode strings above are + // correct. + for (int32_t i = 0; i < NS_HTML_TAG_MAX; ++i) { + nsAutoString temp1(sTagUnicodeTable[i]); + nsAutoString temp2((char16_t*)sTagAtoms_info[i].mStringBuffer->Data()); + NS_ASSERTION(temp1.Equals(temp2), "Bad unicode tag name!"); + } + + // let's verify that NS_HTMLTAG_NAME_MAX_LENGTH is correct + uint32_t maxTagNameLength = 0; + for (int32_t i = 0; i < NS_HTML_TAG_MAX; ++i) { + uint32_t len = NS_strlen(sTagUnicodeTable[i]); + maxTagNameLength = std::max(len, maxTagNameLength); + } + NS_ASSERTION(maxTagNameLength == NS_HTMLTAG_NAME_MAX_LENGTH, + "NS_HTMLTAG_NAME_MAX_LENGTH not set correctly!"); + } +#endif +} + +// static +nsresult +nsHTMLTags::AddRefTable(void) +{ + if (gTableRefCount++ == 0) { + NS_ASSERTION(!gTagTable && !gTagAtomTable, "pre existing hash!"); + + gTagTable = PL_NewHashTable(64, HTMLTagsHashCodeUCPtr, + HTMLTagsKeyCompareUCPtr, PL_CompareValues, + nullptr, nullptr); + NS_ENSURE_TRUE(gTagTable, NS_ERROR_OUT_OF_MEMORY); + + gTagAtomTable = PL_NewHashTable(64, HTMLTagsHashCodeAtom, + PL_CompareValues, PL_CompareValues, + nullptr, nullptr); + NS_ENSURE_TRUE(gTagAtomTable, NS_ERROR_OUT_OF_MEMORY); + + // Fill in gTagTable with the above static char16_t strings as + // keys and the value of the corresponding enum as the value in + // the table. + + int32_t i; + for (i = 0; i < NS_HTML_TAG_MAX; ++i) { + PL_HashTableAdd(gTagTable, sTagUnicodeTable[i], + NS_INT32_TO_PTR(i + 1)); + + PL_HashTableAdd(gTagAtomTable, sTagAtomTable[i], + NS_INT32_TO_PTR(i + 1)); + } + } + + return NS_OK; +} + +// static +void +nsHTMLTags::ReleaseTable(void) +{ + if (0 == --gTableRefCount) { + if (gTagTable) { + // Nothing to delete/free in this table, just destroy the table. + + PL_HashTableDestroy(gTagTable); + PL_HashTableDestroy(gTagAtomTable); + gTagTable = nullptr; + gTagAtomTable = nullptr; + } + } +} + +// static +nsHTMLTag +nsHTMLTags::LookupTag(const nsAString& aTagName) +{ + uint32_t length = aTagName.Length(); + + if (length > NS_HTMLTAG_NAME_MAX_LENGTH) { + return eHTMLTag_userdefined; + } + + char16_t buf[NS_HTMLTAG_NAME_MAX_LENGTH + 1]; + + nsAString::const_iterator iter; + uint32_t i = 0; + char16_t c; + + aTagName.BeginReading(iter); + + // Fast lowercasing-while-copying of ASCII characters into a + // char16_t buffer + + while (i < length) { + c = *iter; + + if (c <= 'Z' && c >= 'A') { + c |= 0x20; // Lowercase the ASCII character. + } + + buf[i] = c; // Copy ASCII character. + + ++i; + ++iter; + } + + buf[i] = 0; + + return CaseSensitiveLookupTag(buf); +} + +#ifdef DEBUG +void +nsHTMLTags::TestTagTable() +{ + const char16_t *tag; + nsHTMLTag id; + nsCOMPtr<nsIAtom> atom; + + nsHTMLTags::AddRefTable(); + // Make sure we can find everything we are supposed to + for (int i = 0; i < NS_HTML_TAG_MAX; ++i) { + tag = sTagUnicodeTable[i]; + id = LookupTag(nsDependentString(tag)); + NS_ASSERTION(id != eHTMLTag_userdefined, "can't find tag id"); + const char16_t* check = GetStringValue(id); + NS_ASSERTION(0 == nsCRT::strcmp(check, tag), "can't map id back to tag"); + + nsAutoString uname(tag); + ToUpperCase(uname); + NS_ASSERTION(id == LookupTag(uname), "wrong id"); + + NS_ASSERTION(id == CaseSensitiveLookupTag(tag), "wrong id"); + + atom = NS_Atomize(tag); + NS_ASSERTION(id == CaseSensitiveLookupTag(atom), "wrong id"); + NS_ASSERTION(atom == GetAtom(id), "can't map id back to atom"); + } + + // Make sure we don't find things that aren't there + id = LookupTag(NS_LITERAL_STRING("@")); + NS_ASSERTION(id == eHTMLTag_userdefined, "found @"); + id = LookupTag(NS_LITERAL_STRING("zzzzz")); + NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz"); + + atom = NS_Atomize("@"); + id = CaseSensitiveLookupTag(atom); + NS_ASSERTION(id == eHTMLTag_userdefined, "found @"); + atom = NS_Atomize("zzzzz"); + id = CaseSensitiveLookupTag(atom); + NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz"); + + tag = GetStringValue((nsHTMLTag) 0); + NS_ASSERTION(!tag, "found enum 0"); + tag = GetStringValue((nsHTMLTag) -1); + NS_ASSERTION(!tag, "found enum -1"); + tag = GetStringValue((nsHTMLTag) (NS_HTML_TAG_MAX + 1)); + NS_ASSERTION(!tag, "found past max enum"); + + atom = GetAtom((nsHTMLTag) 0); + NS_ASSERTION(!atom, "found enum 0"); + atom = GetAtom((nsHTMLTag) -1); + NS_ASSERTION(!atom, "found enum -1"); + atom = GetAtom((nsHTMLTag) (NS_HTML_TAG_MAX + 1)); + NS_ASSERTION(!atom, "found past max enum"); + + ReleaseTable(); +} + +#endif // DEBUG |