diff options
author | Gaming4JC <g4jc@hyperbola.info> | 2020-01-19 09:57:36 -0500 |
---|---|---|
committer | Gaming4JC <g4jc@hyperbola.info> | 2020-01-26 15:50:42 -0500 |
commit | d163c367d9ee5f13769b8580b97bcc511fdd13cd (patch) | |
tree | d8fba280f76b3ff92d5bf1c4d574731ab956f662 /parser/html | |
parent | 9bf83c6a785ba7463822a159cdaf9eb06ece3690 (diff) | |
download | uxp-d163c367d9ee5f13769b8580b97bcc511fdd13cd.tar.gz |
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
Diffstat (limited to 'parser/html')
-rw-r--r-- | parser/html/java/README.txt | 41 | ||||
-rw-r--r-- | parser/html/moz.build | 1 | ||||
-rw-r--r-- | parser/html/nsHtml5ContentCreatorFunction.h | 17 | ||||
-rw-r--r-- | parser/html/nsHtml5Highlighter.cpp | 42 | ||||
-rw-r--r-- | parser/html/nsHtml5Highlighter.h | 9 | ||||
-rw-r--r-- | parser/html/nsHtml5TreeBuilderCppSupplement.h | 72 | ||||
-rw-r--r-- | parser/html/nsHtml5TreeOperation.cpp | 228 | ||||
-rw-r--r-- | parser/html/nsHtml5TreeOperation.h | 63 |
8 files changed, 377 insertions, 96 deletions
diff --git a/parser/html/java/README.txt b/parser/html/java/README.txt index b358cc595b..569a5c842f 100644 --- a/parser/html/java/README.txt +++ b/parser/html/java/README.txt @@ -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) diff --git a/parser/html/moz.build b/parser/html/moz.build index 12809fe8d1..3556a00712 100644 --- a/parser/html/moz.build +++ b/parser/html/moz.build @@ -22,6 +22,7 @@ EXPORTS += [ 'nsHtml5AttributeEntry.h', 'nsHtml5AttributeName.h', 'nsHtml5ByteReadable.h', + 'nsHtml5ContentCreatorFunction.h', 'nsHtml5DependentUTF16Buffer.h', 'nsHtml5DocumentBuilder.h', 'nsHtml5DocumentMode.h', diff --git a/parser/html/nsHtml5ContentCreatorFunction.h b/parser/html/nsHtml5ContentCreatorFunction.h new file mode 100644 index 0000000000..f46246a416 --- /dev/null +++ b/parser/html/nsHtml5ContentCreatorFunction.h @@ -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 diff --git a/parser/html/nsHtml5Highlighter.cpp b/parser/html/nsHtml5Highlighter.cpp index 92e4b03738..b08179fbd2 100644 --- a/parser/html/nsHtml5Highlighter.cpp +++ b/parser/html/nsHtml5Highlighter.cpp @@ -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); } diff --git a/parser/html/nsHtml5Highlighter.h b/parser/html/nsHtml5Highlighter.h index 366f115826..c37b703b8b 100644 --- a/parser/html/nsHtml5Highlighter.h +++ b/parser/html/nsHtml5Highlighter.h @@ -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. diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index 6121c61862..61906d53c8 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -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); diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index 57835bd36a..0a9a574eba 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -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: { diff --git a/parser/html/nsHtml5TreeOperation.h b/parser/html/nsHtml5TreeOperation.h index a93f44c46f..0cdb08e2e9 100644 --- a/parser/html/nsHtml5TreeOperation.h +++ b/parser/html/nsHtml5TreeOperation.h @@ -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; }; |