Bug 483155 - Put content creator function pointers onto nsHtml5ElementName.

This is all the manual work for Bug 483155, minus the added functionality to disable SVG and MathML which can be done at any time and are out of scope.

Tag UXP Issue #1344
This commit is contained in:
Gaming4JC 2020-01-19 09:57:36 -05:00 committed by Roy Tam
commit 48844fe691
16 changed files with 475 additions and 129 deletions

View file

@ -52,3 +52,12 @@ NS_NewHTMLElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
{
return new mozilla::dom::HTMLElement(aNodeInfo);
}
// Distinct from the above in order to have function pointer that compared unequal
// to a function pointer to the above.
nsGenericHTMLElement*
NS_NewCustomElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser)
{
return new mozilla::dom::HTMLElement(aNodeInfo);
}

View file

@ -1590,6 +1590,15 @@ protected:
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, \
mNodeInfo->Equals(nsGkAtoms::_tag))
namespace mozilla {
namespace dom {
typedef nsGenericHTMLElement* (*HTMLContentCreatorFunction)(
already_AddRefed<mozilla::dom::NodeInfo>&&,
mozilla::dom::FromParser aFromParser);
} // namespace dom
} // namespace mozilla
/**
* A macro to declare the NS_NewHTMLXXXElement() functions.
@ -1638,6 +1647,13 @@ nsGenericHTMLElement*
NS_NewHTMLElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER);
// Distinct from the above in order to have function pointer that compared unequal
// to a function pointer to the above.
nsGenericHTMLElement*
NS_NewCustomElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER);
NS_DECLARE_NS_NEW_HTML_ELEMENT(Shared)
NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedList)
NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedObject)

View file

@ -84,10 +84,6 @@ using namespace mozilla::dom;
//----------------------------------------------------------------------
typedef nsGenericHTMLElement*
(*contentCreatorCallback)(already_AddRefed<mozilla::dom::NodeInfo>&&,
FromParser aFromParser);
nsGenericHTMLElement*
NS_NewHTMLNOTUSEDElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser)
@ -98,7 +94,7 @@ NS_NewHTMLNOTUSEDElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
#define HTML_TAG(_tag, _classname, _interfacename) NS_NewHTML##_classname##Element,
#define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
static const contentCreatorCallback sContentCreatorCallbacks[] = {
static const HTMLContentCreatorFunction sHTMLContentCreatorFunctions[] = {
NS_NewHTMLUnknownElement,
#include "nsHTMLTagList.h"
#undef HTML_TAG
@ -383,7 +379,7 @@ CreateHTMLElement(uint32_t aNodeType,
aNodeType == eHTMLTag_userdefined,
"aNodeType is out of bounds");
contentCreatorCallback cb = sContentCreatorCallbacks[aNodeType];
HTMLContentCreatorFunction cb = sHTMLContentCreatorFunctions[aNodeType];
NS_ASSERTION(cb != NS_NewHTMLNOTUSEDElement,
"Don't know how to construct tag element!");

View file

@ -15,31 +15,28 @@ using namespace mozilla;
using namespace mozilla::dom;
// Hash table that maps nsIAtom* SVG tags to an offset index
// within the array sContentCreatorCallbacks (offset by TABLE_VALUE_OFFSET)
// within the array sSVGContentCreatorFunctions (offset by TABLE_VALUE_OFFSET)
static PLHashTable* sTagAtomTable = nullptr;
// We don't want to store 0 in the hash table as a return value of 0 from
// PL_HashTableLookupConst indicates that the value is not found
#define TABLE_VALUE_OFFSET 1
#define SVG_TAG(_tag, _classname) \
nsresult \
NS_NewSVG##_classname##Element(nsIContent** aResult, \
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); \
\
static inline nsresult \
Create##_classname##Element(nsIContent** aResult, \
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
FromParser aFromParser) \
{ \
return NS_NewSVG##_classname##Element(aResult, mozilla::Move(aNodeInfo)); \
}
#define SVG_TAG(_tag, _classname) \
nsresult NS_NewSVG##_classname##Element( \
nsIContent** aResult, \
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); \
\
nsresult NS_NewSVG##_classname##Element( \
nsIContent** aResult, \
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
FromParser aFromParser) \
{ \
return NS_NewSVG##_classname##Element(aResult, mozilla::Move(aNodeInfo)); \
}
#define SVG_FROM_PARSER_TAG(_tag, _classname)
#define SVG_FROM_PARSER_TAG(_tag, _classname) \
nsresult \
NS_NewSVG##_classname##Element(nsIContent** aResult, \
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
FromParser aFromParser);
#include "SVGTagList.h"
#undef SVG_TAG
#undef SVG_FROM_PARSER_TAG
@ -48,13 +45,8 @@ nsresult
NS_NewSVGElement(Element** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
typedef nsresult
(*contentCreatorCallback)(nsIContent** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser);
static const contentCreatorCallback sContentCreatorCallbacks[] = {
#define SVG_TAG(_tag, _classname) Create##_classname##Element,
static const SVGContentCreatorFunction sSVGContentCreatorFunctions[] = {
#define SVG_TAG(_tag, _classname) NS_NewSVG##_classname##Element,
#define SVG_FROM_PARSER_TAG(_tag, _classname) NS_NewSVG##_classname##Element,
#include "SVGTagList.h"
#undef SVG_TAG
@ -124,7 +116,7 @@ NS_NewSVGElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& a
MOZ_CRASH();
}
contentCreatorCallback cb = sContentCreatorCallbacks[index];
SVGContentCreatorFunction cb = sSVGContentCreatorFunctions[index];
nsCOMPtr<nsIContent> content;
nsresult rv = cb(getter_AddRefs(content), ni.forget(), aFromParser);
@ -135,3 +127,15 @@ NS_NewSVGElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& a
// if we don't know what to create, just create a standard svg element:
return NS_NewSVGElement(aResult, ni.forget());
}
nsresult
NS_NewSVGUnknownElement(nsIContent** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser)
{
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
nsCOMPtr<Element> element;
nsresult rv = NS_NewSVGElement(getter_AddRefs(element), ni.forget());
element.forget(aResult);
return rv;
}

View file

@ -18,7 +18,32 @@ public:
static void Shutdown();
};
typedef nsresult (*SVGContentCreatorFunction)(
nsIContent** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser);
} // namespace dom
} // namespace mozilla
#define SVG_TAG(_tag, _classname) \
nsresult NS_NewSVG##_classname##Element( \
nsIContent** aResult, \
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
mozilla::dom::FromParser aFromParser);
#define SVG_FROM_PARSER_TAG(_tag, _classname) \
nsresult NS_NewSVG##_classname##Element( \
nsIContent** aResult, \
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
mozilla::dom::FromParser aFromParser);
#include "SVGTagList.h"
#undef SVG_TAG
#undef SVG_FROM_PARSER_TAG
nsresult
NS_NewSVGUnknownElement(nsIContent** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser);
#endif /* mozilla_dom_SVGElementFactory_h */

View file

@ -9,7 +9,14 @@
This file contains the list of all SVG tags.
It is designed to be used as inline input to SVGElementFactory.cpp
*only* through the magic of C preprocessing.
through the magic of C preprocessing.
Additionally, it is consumed by the self-regeneration code in
ElementName.java from which nsHtml5ElementName.cpp/h is translated.
See parser/html/java/README.txt.
If you edit this list, you need to re-run ElementName.java
self-regeneration and the HTML parser Java to C++ translation.
All entries must be enclosed in the macro SVG_TAG or SVG_FROM_PARSER_TAG
which will have cruel and unusual things done to them.

View file

@ -14,6 +14,7 @@ EXPORTS += [
'SVGContentUtils.h',
'SVGPreserveAspectRatio.h',
'SVGStringList.h',
'SVGTagList.h',
]
EXPORTS.mozilla.dom += [
@ -39,6 +40,7 @@ EXPORTS.mozilla.dom += [
'SVGDefsElement.h',
'SVGDescElement.h',
'SVGDocument.h',
'SVGElementFactory.h',
'SVGEllipseElement.h',
'SVGFEBlendElement.h',
'SVGFEColorMatrixElement.h',

View file

@ -1,13 +1,13 @@
If this is your first time building the HTML5 parser, you need to execute the
following commands (from this directory) to accomplish the translation:
make translate # perform the Java-to-C++ translation from the remote
make translate # perform the Java-to-C++ translation from the remote
# sources
make named_characters # Generate tables for named character tokenization
If you make changes to the translator or the javaparser, you can rebuild by
retyping 'make' in this directory. If you make changes to the HTML5 Java
implementation, you can retranslate the Java sources from the htmlparser
implementation, you can retranslate the Java sources from the htmlparser
repository by retyping 'make translate' in this directory.
The makefile supports the following targets:
@ -36,6 +36,43 @@ clean-javasrc:
clean:
Runs clean-javaparser, clean-htmlparser, and clean-javasrc.
## How to add an attribute
# starting from the root of a UXP checkout
cd parser/html/java/htmlparser/src/
$EDITOR nu/validator/htmlparser/impl/AttributeName.java
# Search for the word "uncomment" and uncomment stuff according to the comments that talk about uncommenting
# Duplicate the declaration a normal attribute (nothings special in SVG mode, etc.). Let's use "alt", since it's the first one.
# In the duplicate, replace ALT with the new name in all caps and "alt" with the new name in quotes in lower case.
# Search for "ALT,", duplicate that line and change the duplicate to say the new name in all caps followed by comma.
# Save.
javac nu/validator/htmlparser/impl/AttributeName.java
java nu.validator.htmlparser.impl.AttributeName
# Copy and paste the output into nu/validator/htmlparser/impl/AttributeName.java replacing the text below the comment "START GENERATED CODE" and above the very last "}".
# Recomment the bits that you uncommented earlier.
# Save.
cd ../.. # Back to parser/html/java/
make translate
## How to add an element
# First, add an entry to parser/htmlparser/nsHTMLTagList.h or dom/svg/SVGTagList.h!
# Then, starting from the root of a UXP checkout
cd parser/html/java/htmlparser/src/
$EDITOR nu/validator/htmlparser/impl/ElementName.java
# Search for the word "uncomment" and uncomment stuff according to the comments that talk about uncommenting
# Duplicate the declaration a normal element. Let's use "bdo", since it's the first normal one.
# In the duplicate, replace BDO with the new name in all caps and "bdo" with the new name in quotes in lower case (twice).
# Search for "BDO,", duplicate that line and change the duplicate to say the new name in all caps followed by comma.
# Save.
javac nu/validator/htmlparser/impl/ElementName.java
java nu.validator.htmlparser.impl.ElementName ../../../../../parser/htmlparser/nsHTMLTagList.h ../../../../../dom/svg/SVGTagList.h
# Copy and paste the output into nu/validator/htmlparser/impl/ElementName.java replacing the text below the comment "START GENERATED CODE" and above the very last "}".
# Recomment the bits that you uncommented earlier.
# Save.
cd ../.. # Back to parser/html/java/
make translate
Ben Newman (23 September 2009)
Henri Sivonen (11 August 2016)
Matt A. Tobin (16 January 2020)

View file

@ -22,6 +22,7 @@ EXPORTS += [
'nsHtml5AttributeEntry.h',
'nsHtml5AttributeName.h',
'nsHtml5ByteReadable.h',
'nsHtml5ContentCreatorFunction.h',
'nsHtml5DependentUTF16Buffer.h',
'nsHtml5DocumentBuilder.h',
'nsHtml5DocumentMode.h',

View file

@ -0,0 +1,17 @@
/* 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/. */
#ifndef nsHtml5ContentCreatorFunction_h
#define nsHtml5ContentCreatorFunction_h
#include "nsGenericHTMLElement.h"
#include "mozilla/dom/SVGElementFactory.h"
union nsHtml5ContentCreatorFunction
{
mozilla::dom::HTMLContentCreatorFunction html;
mozilla::dom::SVGContentCreatorFunction svg;
};
#endif // nsHtml5ContentCreatorFunction_h

View file

@ -79,13 +79,16 @@ nsHtml5Highlighter::Start(const nsAutoString& aTitle)
mOpQueue.AppendElement()->Init(STANDARDS_MODE);
nsIContent** root = CreateElement(nsHtml5Atoms::html, nullptr, nullptr);
// <html> uses NS_NewHTMLSharedElement creator
nsIContent** root =
CreateElement(nsHtml5Atoms::html, nullptr, nullptr, NS_NewHTMLSharedElement);
mOpQueue.AppendElement()->Init(eTreeOpAppendToDocument, root);
mStack.AppendElement(root);
Push(nsGkAtoms::head, nullptr);
// <head> uses NS_NewHTMLSharedElement creator
Push(nsGkAtoms::head, nullptr, NS_NewHTMLSharedElement);
Push(nsGkAtoms::title, nullptr);
Push(nsGkAtoms::title, nullptr, NS_NewHTMLTitleElement);
// XUL will add the "Source of: " prefix.
uint32_t length = aTitle.Length();
if (length > INT32_MAX) {
@ -94,7 +97,9 @@ nsHtml5Highlighter::Start(const nsAutoString& aTitle)
AppendCharacters(aTitle.BeginReading(), 0, (int32_t)length);
Pop(); // title
Push(nsGkAtoms::link, nsHtml5ViewSourceUtils::NewLinkAttributes());
Push(nsGkAtoms::link,
nsHtml5ViewSourceUtils::NewLinkAttributes(),
NS_NewHTMLLinkElement);
mOpQueue.AppendElement()->Init(eTreeOpUpdateStyleSheet, CurrentNode());
@ -102,12 +107,14 @@ nsHtml5Highlighter::Start(const nsAutoString& aTitle)
Pop(); // head
Push(nsGkAtoms::body, nsHtml5ViewSourceUtils::NewBodyAttributes());
Push(nsGkAtoms::body,
nsHtml5ViewSourceUtils::NewBodyAttributes(),
NS_NewHTMLBodyElement);
nsHtml5HtmlAttributes* preAttrs = new nsHtml5HtmlAttributes(0);
nsHtml5String preId = nsHtml5Portability::newStringFromLiteral("line1");
preAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, preId, -1);
Push(nsGkAtoms::pre, preAttrs);
Push(nsGkAtoms::pre, preAttrs, NS_NewHTMLPreElement);
StartCharacters();
@ -492,7 +499,7 @@ void
nsHtml5Highlighter::StartSpan()
{
FlushChars();
Push(nsGkAtoms::span, nullptr);
Push(nsGkAtoms::span, nullptr, NS_NewHTMLSpanElement);
++mInlinesOpen;
}
@ -516,7 +523,7 @@ nsHtml5Highlighter::StartCharacters()
{
NS_PRECONDITION(!mInCharacters, "Already in characters!");
FlushChars();
Push(nsGkAtoms::span, nullptr);
Push(nsGkAtoms::span, nullptr, NS_NewHTMLSpanElement);
mCurrentRun = CurrentNode();
mInCharacters = true;
}
@ -537,7 +544,7 @@ void
nsHtml5Highlighter::StartA()
{
FlushChars();
Push(nsGkAtoms::a, nullptr);
Push(nsGkAtoms::a, nullptr, NS_NewHTMLAnchorElement);
AddClass(sAttributeValue);
++mInlinesOpen;
}
@ -579,7 +586,7 @@ nsHtml5Highlighter::FlushChars()
mCStart = i;
}
++mLineNumber;
Push(nsGkAtoms::span, nullptr);
Push(nsGkAtoms::span, nullptr, NS_NewHTMLSpanElement);
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->InitAddLineNumberId(CurrentNode(), mLineNumber);
@ -656,16 +663,20 @@ nsHtml5Highlighter::AllocateContentHandle()
nsIContent**
nsHtml5Highlighter::CreateElement(nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
nsIContent** aIntendedParent)
nsIContent** aIntendedParent,
mozilla::dom::HTMLContentCreatorFunction aCreator)
{
NS_PRECONDITION(aName, "Got null name.");
nsHtml5ContentCreatorFunction creator;
creator.html = aCreator;
nsIContent** content = AllocateContentHandle();
mOpQueue.AppendElement()->Init(kNameSpaceID_XHTML,
aName,
aAttributes,
content,
aIntendedParent,
true);
true,
creator);
return content;
}
@ -678,10 +689,13 @@ nsHtml5Highlighter::CurrentNode()
void
nsHtml5Highlighter::Push(nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes)
nsHtml5HtmlAttributes* aAttributes,
mozilla::dom::HTMLContentCreatorFunction aCreator)
{
NS_PRECONDITION(mStack.Length() >= 1, "Pushing without root.");
nsIContent** elt = CreateElement(aName, aAttributes, CurrentNode()); // Don't inline below!
nsIContent** elt = CreateElement(aName, aAttributes,
CurrentNode(),
aCreator); // Don't inline below!
mOpQueue.AppendElement()->Init(eTreeOpAppend, elt, CurrentNode());
mStack.AppendElement(elt);
}

View file

@ -227,11 +227,13 @@ class nsHtml5Highlighter
* @param aAttributes the attribute holder (ownership will be taken) or
* nullptr for no attributes
* @param aIntendedParent the intended parent node for the created element
* @param aCreator the content creator function
* @return the handle for the element that will be created
*/
nsIContent** CreateElement(nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
nsIContent** aIntendedParent);
nsIContent** aIntendedParent,
mozilla::dom::HTMLContentCreatorFunction aCreator);
/**
* Gets the handle for the current node. May be called only after the
@ -247,8 +249,11 @@ class nsHtml5Highlighter
* @param aName the name of the element
* @param aAttributes the attribute holder (ownership will be taken) or
* nullptr for no attributes
* @param aCreator the content creator function
*/
void Push(nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes);
void Push(nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
mozilla::dom::HTMLContentCreatorFunction aCreator);
/**
* Pops the current node off the stack.

View file

@ -68,9 +68,10 @@ nsHtml5TreeBuilder::~nsHtml5TreeBuilder()
}
nsIContentHandle*
nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
nsIContentHandle* aIntendedParent)
nsHtml5TreeBuilder::createElement(int32_t aNamespace,
nsIAtom* aName,
nsIContentHandle* aIntendedParent,
nsHtml5ContentCreatorFunction aCreator)
{
NS_PRECONDITION(aAttributes, "Got null attributes.");
NS_PRECONDITION(aName, "Got null name.");
@ -91,13 +92,28 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
intendedParent->OwnerDoc()->NodeInfoManager() :
mBuilder->GetNodeInfoManager();
nsIContent* elem =
nsHtml5TreeOperation::CreateElement(aNamespace,
name,
aAttributes,
mozilla::dom::FROM_PARSER_FRAGMENT,
nodeInfoManager,
mBuilder);
nsIContent* elem;
if (aNamespace == kNameSpaceID_XHTML) {
elem = nsHtml5TreeOperation::CreateHTMLElement(
name,
aAttributes,
mozilla::dom::FROM_PARSER_FRAGMENT,
nodeInfoManager,
mBuilder,
aCreator.html);
} else if (aNamespace == kNameSpaceID_SVG) {
elem = nsHtml5TreeOperation::CreateSVGElement(
name,
aAttributes,
mozilla::dom::FROM_PARSER_FRAGMENT,
nodeInfoManager,
mBuilder,
aCreator.svg);
} else {
MOZ_ASSERT(aNamespace == kNameSpaceID_MathML);
elem = nsHtml5TreeOperation::CreateMathMLElement(
name, aAttributes, nodeInfoManager, mBuilder);
}
if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() &&
aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) {
delete aAttributes;
@ -113,7 +129,8 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
aAttributes,
content,
aIntendedParent,
!!mSpeculativeLoadStage);
!!mSpeculativeLoadStage,
aCreator);
// mSpeculativeLoadStage is non-null only in the off-the-main-thread
// tree builder, which handles the network stream
@ -345,13 +362,15 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
}
nsIContentHandle*
nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
nsHtml5TreeBuilder::createElement(int32_t aNamespace,
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
nsIContentHandle* aFormElement,
nsIContentHandle* aIntendedParent)
nsIContentHandle* aIntendedParent,
nsHtml5ContentCreatorFunction aCreator)
{
nsIContentHandle* content = createElement(aNamespace, aName, aAttributes,
aIntendedParent);
nsIContentHandle* content =
createElement(aNamespace, aName, aAttributes, aIntendedParent, aCreator);
if (aFormElement) {
if (mBuilder) {
nsHtml5TreeOperation::SetFormElement(static_cast<nsIContent*>(content),
@ -368,10 +387,11 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
nsIContentHandle*
nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttributes)
{
nsIContentHandle* content = createElement(kNameSpaceID_XHTML,
nsHtml5Atoms::html,
aAttributes,
nullptr);
nsHtml5ContentCreatorFunction creator;
// <html> uses NS_NewHTMLSharedElement creator
creator.html = NS_NewHTMLSharedElement;
nsIContentHandle* content = createElement(
kNameSpaceID_XHTML, nsHtml5Atoms::html, aAttributes, nullptr, creator);
if (mBuilder) {
nsresult rv = nsHtml5TreeOperation::AppendToDocument(static_cast<nsIContent*>(content),
mBuilder);
@ -387,11 +407,13 @@ nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttribute
}
nsIContentHandle*
nsHtml5TreeBuilder::createAndInsertFosterParentedElement(int32_t aNamespace, nsIAtom* aName,
nsHtml5TreeBuilder::createAndInsertFosterParentedElement(int32_t aNamespace,
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
nsIContentHandle* aFormElement,
nsIContentHandle* aTable,
nsIContentHandle* aStackParent)
nsIContentHandle* aStackParent,
nsHtml5ContentCreatorFunction aCreator)
{
NS_PRECONDITION(aTable, "Null table");
NS_PRECONDITION(aStackParent, "Null stack parent");
@ -403,8 +425,8 @@ nsHtml5TreeBuilder::createAndInsertFosterParentedElement(int32_t aNamespace, nsI
static_cast<nsIContent*>(aTable),
static_cast<nsIContent*>(aStackParent));
nsIContentHandle* child = createElement(aNamespace, aName, aAttributes,
aFormElement, fosterParent);
nsIContentHandle* child = createElement(
aNamespace, aName, aAttributes, aFormElement, fosterParent, aCreator);
insertFosterParentedChild(child, aTable, aStackParent);
@ -420,8 +442,8 @@ nsHtml5TreeBuilder::createAndInsertFosterParentedElement(int32_t aNamespace, nsI
aStackParent, fosterParentHandle);
// Create the element with the correct intended parent.
nsIContentHandle* child = createElement(aNamespace, aName, aAttributes,
aFormElement, fosterParentHandle);
nsIContentHandle* child = createElement(
aNamespace, aName, aAttributes, aFormElement, fosterParentHandle, aCreator);
// Insert the child into the foster parent.
insertFosterParentedChild(child, aTable, aStackParent);

View file

@ -88,8 +88,11 @@ nsHtml5TreeOperation::~nsHtml5TreeOperation()
case eTreeOpAddAttributes:
delete mTwo.attributes;
break;
case eTreeOpCreateElementNetwork:
case eTreeOpCreateElementNotNetwork:
case eTreeOpCreateHTMLElementNetwork:
case eTreeOpCreateHTMLElementNotNetwork:
case eTreeOpCreateSVGElementNetwork:
case eTreeOpCreateSVGElementNotNetwork:
case eTreeOpCreateMathMLElement:
delete mThree.attributes;
break;
case eTreeOpAppendDoctypeToDocument:
@ -331,30 +334,37 @@ nsHtml5TreeOperation::AddAttributes(nsIContent* aNode,
nsIContent*
nsHtml5TreeOperation::CreateElement(int32_t aNs,
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
mozilla::dom::FromParser aFromParser,
nsNodeInfoManager* aNodeInfoManager,
nsHtml5DocumentBuilder* aBuilder)
nsHtml5TreeOperation::CreateHTMLElement(
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
mozilla::dom::FromParser aFromParser,
nsNodeInfoManager* aNodeInfoManager,
nsHtml5DocumentBuilder* aBuilder,
mozilla::dom::HTMLContentCreatorFunction aCreator)
{
bool isKeygen = (aName == nsHtml5Atoms::keygen && aNs == kNameSpaceID_XHTML);
bool isKeygen = (aName == nsHtml5Atoms::keygen);
if (MOZ_UNLIKELY(isKeygen)) {
aName = nsHtml5Atoms::select;
aCreator = NS_NewHTMLSelectElement;
}
nsCOMPtr<dom::Element> newElement;
RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->
GetNodeInfo(aName, nullptr, aNs, nsIDOMNode::ELEMENT_NODE);
RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
aName, nullptr, kNameSpaceID_XHTML, nsIDOMNode::ELEMENT_NODE);
NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
NS_NewElement(getter_AddRefs(newElement),
nodeInfo.forget(),
aFromParser);
NS_ASSERTION(newElement, "Element creation created null pointer.");
nsCOMPtr<dom::Element> newElement = aCreator(nodeInfo.forget(), aFromParser);
MOZ_ASSERT(newElement, "Element creation created null pointer.");
dom::Element* newContent = newElement;
aBuilder->HoldElement(newElement.forget());
if (aCreator == NS_NewCustomElement) {
// Not inlining the call below into NS_NewCustomElement itself, because
// in the near future, the code here will need to break out of an update
// batch here.
nsContentUtils::SetupCustomElement(newContent);
}
if (MOZ_UNLIKELY(aName == nsHtml5Atoms::style || aName == nsHtml5Atoms::link)) {
nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent));
if (ssle) {
@ -390,18 +400,15 @@ nsHtml5TreeOperation::CreateElement(int32_t aNs,
nsIDOMNode::ELEMENT_NODE);
for (uint32_t i = 0; i < theContent.Length(); ++i) {
nsCOMPtr<dom::Element> optionElt;
RefPtr<dom::NodeInfo> ni = optionNodeInfo;
NS_NewElement(getter_AddRefs(optionElt),
ni.forget(),
aFromParser);
nsCOMPtr<dom::Element> optionElt =
NS_NewHTMLOptionElement(ni.forget(), aFromParser);
RefPtr<nsTextNode> optionText = new nsTextNode(aNodeInfoManager);
(void) optionText->SetText(theContent[i], false);
optionElt->AppendChildTo(optionText, false);
newContent->AppendChildTo(optionElt, false);
// XXXsmaug Shouldn't we call this after adding all the child nodes.
newContent->DoneAddingChildren(false);
}
newContent->DoneAddingChildren(false);
}
if (!aAttributes) {
@ -419,9 +426,7 @@ nsHtml5TreeOperation::CreateElement(int32_t aNs,
nsString value; // Not Auto, because using it to hold nsStringBuffer*
aAttributes->getValueNoBoundsCheck(i).ToString(value);
if (aNs == kNameSpaceID_XHTML &&
nsHtml5Atoms::a == aName &&
nsHtml5Atoms::name == localName) {
if (nsHtml5Atoms::a == aName && nsHtml5Atoms::name == localName) {
// This is an HTML5-incompliant Geckoism.
// Remove when fixing bug 582361
NS_ConvertUTF16toUTF8 cname(value);
@ -449,6 +454,117 @@ nsHtml5TreeOperation::CreateElement(int32_t aNs,
return newContent;
}
nsIContent*
nsHtml5TreeOperation::CreateSVGElement(
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
mozilla::dom::FromParser aFromParser,
nsNodeInfoManager* aNodeInfoManager,
nsHtml5DocumentBuilder* aBuilder,
mozilla::dom::SVGContentCreatorFunction aCreator)
{
nsCOMPtr<nsIContent> newElement;
if (MOZ_LIKELY(aNodeInfoManager->SVGEnabled())) {
RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
aName, nullptr, kNameSpaceID_SVG, nsIDOMNode::ELEMENT_NODE);
MOZ_ASSERT(nodeInfo, "Got null nodeinfo.");
mozilla::DebugOnly<nsresult> rv =
aCreator(getter_AddRefs(newElement), nodeInfo.forget(), aFromParser);
MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
} else {
RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
aName, nullptr, kNameSpaceID_disabled_SVG, nsIDOMNode::ELEMENT_NODE);
MOZ_ASSERT(nodeInfo, "Got null nodeinfo.");
// The mismatch between NS_NewXMLElement and SVGContentCreatorFunction
// argument types is annoying.
nsCOMPtr<dom::Element> xmlElement;
mozilla::DebugOnly<nsresult> rv =
NS_NewXMLElement(getter_AddRefs(xmlElement), nodeInfo.forget());
MOZ_ASSERT(NS_SUCCEEDED(rv) && xmlElement);
newElement = xmlElement;
}
dom::Element* newContent = newElement->AsElement();
aBuilder->HoldElement(newElement.forget());
if (MOZ_UNLIKELY(aName == nsHtml5Atoms::style)) {
nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent));
if (ssle) {
ssle->InitStyleLinkElement(false);
ssle->SetEnableUpdates(false);
}
}
if (!aAttributes) {
return newContent;
}
int32_t len = aAttributes->getLength();
for (int32_t i = 0; i < len; i++) {
// prefix doesn't need regetting. it is always null or a static atom
// local name is never null
nsCOMPtr<nsIAtom> localName =
Reget(aAttributes->getLocalNameNoBoundsCheck(i));
nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
nsString value; // Not Auto, because using it to hold nsStringBuffer*
aAttributes->getValueNoBoundsCheck(i).ToString(value);
newContent->SetAttr(nsuri, localName, prefix, value, false);
}
return newContent;
}
nsIContent*
nsHtml5TreeOperation::CreateMathMLElement(nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
nsNodeInfoManager* aNodeInfoManager,
nsHtml5DocumentBuilder* aBuilder)
{
nsCOMPtr<dom::Element> newElement;
if (MOZ_LIKELY(aNodeInfoManager->MathMLEnabled())) {
RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
aName, nullptr, kNameSpaceID_MathML, nsIDOMNode::ELEMENT_NODE);
NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
mozilla::DebugOnly<nsresult> rv =
NS_NewMathMLElement(getter_AddRefs(newElement), nodeInfo.forget());
MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
} else {
RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
aName, nullptr, kNameSpaceID_disabled_MathML, nsIDOMNode::ELEMENT_NODE);
NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
mozilla::DebugOnly<nsresult> rv =
NS_NewXMLElement(getter_AddRefs(newElement), nodeInfo.forget());
MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
}
dom::Element* newContent = newElement;
aBuilder->HoldElement(newElement.forget());
if (!aAttributes) {
return newContent;
}
int32_t len = aAttributes->getLength();
for (int32_t i = 0; i < len; i++) {
// prefix doesn't need regetting. it is always null or a static atom
// local name is never null
nsCOMPtr<nsIAtom> localName =
Reget(aAttributes->getLocalNameNoBoundsCheck(i));
nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
nsString value; // Not Auto, because using it to hold nsStringBuffer*
aAttributes->getValueNoBoundsCheck(i).ToString(value);
newContent->SetAttr(nsuri, localName, prefix, value, false);
}
return newContent;
}
void
nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent)
{
@ -675,10 +791,56 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
aBuilder->SetDocumentMode(mOne.mode);
return NS_OK;
}
case eTreeOpCreateElementNetwork:
case eTreeOpCreateElementNotNetwork: {
case eTreeOpCreateHTMLElementNetwork:
case eTreeOpCreateHTMLElementNotNetwork: {
nsIContent** target = mOne.node;
mozilla::dom::HTMLContentCreatorFunction creator = mFour.htmlCreator;
nsCOMPtr<nsIAtom> name = Reget(mTwo.atom);
nsHtml5HtmlAttributes* attributes = mThree.attributes;
nsIContent* intendedParent = mFive.node ? *(mFive.node) : nullptr;
// intendedParent == nullptr is a special case where the
// intended parent is the document.
nsNodeInfoManager* nodeInfoManager =
intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
: aBuilder->GetNodeInfoManager();
*target = CreateHTMLElement(name,
attributes,
mOpCode == eTreeOpCreateHTMLElementNetwork
? dom::FROM_PARSER_NETWORK
: dom::FROM_PARSER_DOCUMENT_WRITE,
nodeInfoManager,
aBuilder,
creator);
return NS_OK;
}
case eTreeOpCreateSVGElementNetwork:
case eTreeOpCreateSVGElementNotNetwork: {
nsIContent** target = mOne.node;
mozilla::dom::SVGContentCreatorFunction creator = mFour.svgCreator;
nsCOMPtr<nsIAtom> name = Reget(mTwo.atom);
nsHtml5HtmlAttributes* attributes = mThree.attributes;
nsIContent* intendedParent = mFive.node ? *(mFive.node) : nullptr;
// intendedParent == nullptr is a special case where the
// intended parent is the document.
nsNodeInfoManager* nodeInfoManager =
intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
: aBuilder->GetNodeInfoManager();
*target = CreateSVGElement(name,
attributes,
mOpCode == eTreeOpCreateSVGElementNetwork
? dom::FROM_PARSER_NETWORK
: dom::FROM_PARSER_DOCUMENT_WRITE,
nodeInfoManager,
aBuilder,
creator);
return NS_OK;
}
case eTreeOpCreateMathMLElement: {
nsIContent** target = mOne.node;
int32_t ns = mFour.integer;
nsCOMPtr<nsIAtom> name = Reget(mTwo.atom);
nsHtml5HtmlAttributes* attributes = mThree.attributes;
nsIContent* intendedParent = mFive.node ? *(mFive.node) : nullptr;
@ -689,14 +851,8 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
intendedParent->OwnerDoc()->NodeInfoManager() :
aBuilder->GetNodeInfoManager();
*target = CreateElement(ns,
name,
attributes,
mOpCode == eTreeOpCreateElementNetwork ?
dom::FROM_PARSER_NETWORK :
dom::FROM_PARSER_DOCUMENT_WRITE,
nodeInfoManager,
aBuilder);
*target =
CreateMathMLElement(name, attributes, nodeInfoManager, aBuilder);
return NS_OK;
}
case eTreeOpSetFormElement: {

View file

@ -14,7 +14,8 @@ class nsIContent;
class nsHtml5TreeOpExecutor;
class nsHtml5DocumentBuilder;
enum eHtml5TreeOperation {
enum eHtml5TreeOperation
{
eTreeOpUninitialized,
// main HTML5 ops
eTreeOpAppend,
@ -24,8 +25,11 @@ enum eHtml5TreeOperation {
eTreeOpAppendToDocument,
eTreeOpAddAttributes,
eTreeOpDocumentMode,
eTreeOpCreateElementNetwork,
eTreeOpCreateElementNotNetwork,
eTreeOpCreateHTMLElementNetwork,
eTreeOpCreateHTMLElementNotNetwork,
eTreeOpCreateSVGElementNetwork,
eTreeOpCreateSVGElementNotNetwork,
eTreeOpCreateMathMLElement,
eTreeOpSetFormElement,
eTreeOpAppendText,
eTreeOpAppendIsindexPrompt,
@ -143,12 +147,26 @@ class nsHtml5TreeOperation {
nsHtml5HtmlAttributes* aAttributes,
nsHtml5DocumentBuilder* aBuilder);
static nsIContent* CreateElement(int32_t aNs,
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
mozilla::dom::FromParser aFromParser,
nsNodeInfoManager* aNodeInfoManager,
nsHtml5DocumentBuilder* aBuilder);
static nsIContent* CreateHTMLElement(
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
mozilla::dom::FromParser aFromParser,
nsNodeInfoManager* aNodeInfoManager,
nsHtml5DocumentBuilder* aBuilder,
mozilla::dom::HTMLContentCreatorFunction aCreator);
static nsIContent* CreateSVGElement(
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
mozilla::dom::FromParser aFromParser,
nsNodeInfoManager* aNodeInfoManager,
nsHtml5DocumentBuilder* aBuilder,
mozilla::dom::SVGContentCreatorFunction aCreator);
static nsIContent* CreateMathMLElement(nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
nsNodeInfoManager* aNodeInfoManager,
nsHtml5DocumentBuilder* aBuilder);
static void SetFormElement(nsIContent* aNode, nsIContent* aParent);
@ -284,22 +302,31 @@ class nsHtml5TreeOperation {
mOne.node = static_cast<nsIContent**>(aNode);
mTwo.state = nullptr;
}
inline void Init(int32_t aNamespace,
nsIAtom* aName,
inline void Init(int32_t aNamespace,
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
nsIContentHandle* aTarget,
nsIContentHandle* aIntendedParent,
bool aFromNetwork)
bool aFromNetwork,
nsHtml5ContentCreatorFunction aCreator)
{
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aName, "Initialized tree op with null name.");
NS_PRECONDITION(aTarget, "Initialized tree op with null target node.");
mOpCode = aFromNetwork ?
eTreeOpCreateElementNetwork :
eTreeOpCreateElementNotNetwork;
mFour.integer = aNamespace;
if (aNamespace == kNameSpaceID_XHTML) {
mOpCode = aFromNetwork ? eTreeOpCreateHTMLElementNetwork
: eTreeOpCreateHTMLElementNotNetwork;
mFour.htmlCreator = aCreator.html;
} else if (aNamespace == kNameSpaceID_SVG) {
mOpCode = aFromNetwork ? eTreeOpCreateSVGElementNetwork
: eTreeOpCreateSVGElementNotNetwork;
mFour.svgCreator = aCreator.svg;
} else {
MOZ_ASSERT(aNamespace == kNameSpaceID_MathML);
mOpCode = eTreeOpCreateMathMLElement;
}
mFive.node = static_cast<nsIContent**>(aIntendedParent);
mOne.node = static_cast<nsIContent**>(aTarget);
mTwo.atom = aName;
@ -507,6 +534,8 @@ class nsHtml5TreeOperation {
nsAHtml5TreeBuilderState* state;
int32_t integer;
nsresult result;
mozilla::dom::HTMLContentCreatorFunction htmlCreator;
mozilla::dom::SVGContentCreatorFunction svgCreator;
} mOne, mTwo, mThree, mFour, mFive;
};

View file

@ -12,6 +12,12 @@
It is designed to be used as input to various places that will define the
HTML_TAG macro in useful ways through the magic of C preprocessing.
Additionally, it is consumed by the self-regeneration code in
ElementName.java from which nsHtml5ElementName.cpp/h is translated.
See parser/html/java/README.txt.
If you edit this list, you need to re-run ElementName.java
self-regeneration and the HTML parser Java to C++ translation.
All entries must be enclosed in the macro HTML_TAG which will have cruel
and unusual things done to it.