From 7cf95402beedfa28eb471a88d3f2aad3ccae4561 Mon Sep 17 00:00:00 2001 From: Henri Sivonen Date: Wed, 5 Mar 2014 21:38:49 +0200 Subject: [PATCH] Bug 959150 part 2 - Split reusable operations out of nsHtml5TreeOperation::Perform into static methods. r=smaug. --- parser/html/nsHtml5TreeOperation.cpp | 759 +++++++++++++++------------ parser/html/nsHtml5TreeOperation.h | 121 ++++- 2 files changed, 530 insertions(+), 350 deletions(-) diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index 3adf4e2d118..9681d3b3c3b 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -244,11 +244,395 @@ IsElementOrTemplateContent(nsINode* aNode) { return false; } +void +nsHtml5TreeOperation::Detach(nsIContent* aNode, nsHtml5TreeOpExecutor* aBuilder) +{ + aBuilder->FlushPendingAppendNotifications(); + nsCOMPtr parent = aNode->GetParentNode(); + if (parent) { + nsHtml5OtherDocUpdate update(parent->OwnerDoc(), + aBuilder->GetDocument()); + int32_t pos = parent->IndexOf(aNode); + NS_ASSERTION((pos >= 0), "Element not found as child of its parent"); + parent->RemoveChildAt(pos, true); + } +} + +nsresult +nsHtml5TreeOperation::AppendChildrenToNewParent(nsIContent* aNode, + nsIContent* aParent, + nsHtml5TreeOpExecutor* aBuilder) +{ + aBuilder->FlushPendingAppendNotifications(); + + nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), + aBuilder->GetDocument()); + + uint32_t childCount = aParent->GetChildCount(); + bool didAppend = false; + while (aNode->HasChildren()) { + nsCOMPtr child = aNode->GetFirstChild(); + aNode->RemoveChildAt(0, true); + nsresult rv = aParent->AppendChildTo(child, false); + NS_ENSURE_SUCCESS(rv, rv); + didAppend = true; + } + if (didAppend) { + nsNodeUtils::ContentAppended(aParent, aParent->GetChildAt(childCount), + childCount); + } + return NS_OK; +} + +nsresult +nsHtml5TreeOperation::FosterParent(nsIContent* aNode, + nsIContent* aParent, + nsIContent* aTable, + nsHtml5TreeOpExecutor* aBuilder) +{ + nsIContent* foster = aTable->GetParent(); + + if (IsElementOrTemplateContent(foster)) { + aBuilder->FlushPendingAppendNotifications(); + + nsHtml5OtherDocUpdate update(foster->OwnerDoc(), + aBuilder->GetDocument()); + + uint32_t pos = foster->IndexOf(aTable); + nsresult rv = foster->InsertChildAt(aNode, pos, false); + NS_ENSURE_SUCCESS(rv, rv); + nsNodeUtils::ContentInserted(foster, aNode, pos); + return rv; + } + + return Append(aNode, aParent, aBuilder); +} + +nsresult +nsHtml5TreeOperation::AddAttributes(nsIContent* aNode, + nsHtml5HtmlAttributes* aAttributes, + nsHtml5TreeOpExecutor* aBuilder) +{ + dom::Element* node = aNode->AsElement(); + nsHtml5OtherDocUpdate update(node->OwnerDoc(), + aBuilder->GetDocument()); + + int32_t len = aAttributes->getLength(); + for (int32_t i = len; i > 0;) { + --i; + // prefix doesn't need regetting. it is always null or a static atom + // local name is never null + nsCOMPtr localName = + Reget(aAttributes->getLocalNameNoBoundsCheck(i)); + int32_t nsuri = aAttributes->getURINoBoundsCheck(i); + if (!node->HasAttr(nsuri, localName)) { + // prefix doesn't need regetting. it is always null or a static atom + // local name is never null + node->SetAttr(nsuri, + localName, + aAttributes->getPrefixNoBoundsCheck(i), + *(aAttributes->getValueNoBoundsCheck(i)), + true); + // XXX what to do with nsresult? + } + } + return NS_OK; +} + + +nsIContent* +nsHtml5TreeOperation::CreateElement(int32_t aNs, + nsIAtom* aName, + nsHtml5HtmlAttributes* aAttributes, + bool aFromNetwork, + nsHtml5TreeOpExecutor* aBuilder) +{ + bool isKeygen = (aName == nsHtml5Atoms::keygen && aNs == kNameSpaceID_XHTML); + if (MOZ_UNLIKELY(isKeygen)) { + aName = nsHtml5Atoms::select; + } + + nsCOMPtr newContent; + nsCOMPtr nodeInfo = aBuilder->GetNodeInfoManager()-> + GetNodeInfo(aName, nullptr, aNs, nsIDOMNode::ELEMENT_NODE); + NS_ASSERTION(nodeInfo, "Got null nodeinfo."); + NS_NewElement(getter_AddRefs(newContent), + nodeInfo.forget(), + (aFromNetwork ? + dom::FROM_PARSER_NETWORK + : (aBuilder->BelongsToStringParser() ? + dom::FROM_PARSER_FRAGMENT : + dom::FROM_PARSER_DOCUMENT_WRITE))); + NS_ASSERTION(newContent, "Element creation created null pointer."); + + aBuilder->HoldElement(newContent); + + if (MOZ_UNLIKELY(aName == nsHtml5Atoms::style || aName == nsHtml5Atoms::link)) { + nsCOMPtr ssle(do_QueryInterface(newContent)); + if (ssle) { + ssle->InitStyleLinkElement(false); + ssle->SetEnableUpdates(false); + } + } else if (MOZ_UNLIKELY(isKeygen)) { + // Adapted from CNavDTD + nsresult rv; + nsCOMPtr theFormProcessor = + do_GetService(kFormProcessorCID, &rv); + if (NS_FAILED(rv)) { + return newContent; + } + + nsTArray theContent; + nsAutoString theAttribute; + + (void) theFormProcessor->ProvideContent(NS_LITERAL_STRING("select"), + theContent, + theAttribute); + + newContent->SetAttr(kNameSpaceID_None, + nsGkAtoms::moztype, + nullptr, + theAttribute, + false); + + nsCOMPtr optionNodeInfo = + aBuilder->GetNodeInfoManager()->GetNodeInfo(nsHtml5Atoms::option, + nullptr, + kNameSpaceID_XHTML, + nsIDOMNode::ELEMENT_NODE); + + for (uint32_t i = 0; i < theContent.Length(); ++i) { + nsCOMPtr optionElt; + nsCOMPtr ni = optionNodeInfo; + NS_NewElement(getter_AddRefs(optionElt), + ni.forget(), + (aFromNetwork ? + dom::FROM_PARSER_NETWORK + : (aBuilder->BelongsToStringParser() ? + dom::FROM_PARSER_FRAGMENT : + dom::FROM_PARSER_DOCUMENT_WRITE))); + nsRefPtr optionText = + new nsTextNode(aBuilder->GetNodeInfoManager()); + (void) optionText->SetText(theContent[i], false); + optionElt->AppendChildTo(optionText, false); + newContent->AppendChildTo(optionElt, false); + newContent->DoneAddingChildren(false); + } + } + + if (!aAttributes) { + return newContent; + } + + int32_t len = aAttributes->getLength(); + for (int32_t i = len; i > 0;) { + --i; + // prefix doesn't need regetting. it is always null or a static atom + // local name is never null + nsCOMPtr localName = + Reget(aAttributes->getLocalNameNoBoundsCheck(i)); + nsCOMPtr prefix = aAttributes->getPrefixNoBoundsCheck(i); + int32_t nsuri = aAttributes->getURINoBoundsCheck(i); + + if (aNs == kNameSpaceID_XHTML && + nsHtml5Atoms::a == aName && + nsHtml5Atoms::name == localName) { + // This is an HTML5-incompliant Geckoism. + // Remove when fixing bug 582361 + NS_ConvertUTF16toUTF8 cname(*(aAttributes->getValueNoBoundsCheck(i))); + NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting())); + newContent->SetAttr(nsuri, + localName, + prefix, + uv, + false); + } else { + nsString& value = *(aAttributes->getValueNoBoundsCheck(i)); + newContent->SetAttr(nsuri, + localName, + prefix, + value, + false); + + // Custom element prototype swizzling may be needed if there is an + // "is" attribute. + if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) { + ErrorResult errorResult; + newContent->OwnerDoc()->SwizzleCustomElement(newContent, + value, + newContent->GetNameSpaceID(), + errorResult); + } + } + } + return newContent; +} + +void +nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent) +{ + nsCOMPtr formControl(do_QueryInterface(aNode)); + nsCOMPtr domImageElement = do_QueryInterface(aNode); + // NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl."); + // TODO: uncomment the above line when (bug 101019) is supported by Gecko + nsCOMPtr formElement(do_QueryInterface(aParent)); + NS_ASSERTION(formElement, "The form element doesn't implement nsIDOMHTMLFormElement."); + // avoid crashing on + if (formControl && + !aNode->HasAttr(kNameSpaceID_None, nsGkAtoms::form)) { + formControl->SetForm(formElement); + } else if (domImageElement) { + nsRefPtr imageElement = + static_cast(domImageElement.get()); + MOZ_ASSERT(imageElement); + imageElement->SetForm(formElement); + } +} + +nsresult +nsHtml5TreeOperation::AppendIsindexPrompt(nsIContent* parent, nsHtml5TreeOpExecutor* aBuilder) +{ + nsXPIDLString prompt; + nsresult rv = + nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES, + "IsIndexPromptWithSpace", prompt); + uint32_t len = prompt.Length(); + if (NS_FAILED(rv)) { + return rv; + } + if (!len) { + // Don't bother appending a zero-length text node. + return NS_OK; + } + return AppendText(prompt.BeginReading(), len, parent, aBuilder); +} + +nsresult +nsHtml5TreeOperation::FosterParentText(nsIContent* aStackParent, + char16_t* aBuffer, + uint32_t aLength, + nsIContent* aTable, + nsHtml5TreeOpExecutor* aBuilder) +{ + nsresult rv = NS_OK; + nsIContent* foster = aTable->GetParent(); + + if (IsElementOrTemplateContent(foster)) { + aBuilder->FlushPendingAppendNotifications(); + + nsHtml5OtherDocUpdate update(foster->OwnerDoc(), + aBuilder->GetDocument()); + + uint32_t pos = foster->IndexOf(aTable); + + nsIContent* previousSibling = aTable->GetPreviousSibling(); + if (previousSibling && previousSibling->IsNodeOfType(nsINode::eTEXT)) { + return AppendTextToTextNode(aBuffer, + aLength, + previousSibling, + aBuilder); + } + + nsRefPtr text = + new nsTextNode(aBuilder->GetNodeInfoManager()); + NS_ASSERTION(text, "Infallible malloc failed?"); + rv = text->SetText(aBuffer, aLength, false); + NS_ENSURE_SUCCESS(rv, rv); + + rv = foster->InsertChildAt(text, pos, false); + NS_ENSURE_SUCCESS(rv, rv); + nsNodeUtils::ContentInserted(foster, text, pos); + return rv; + } + + return AppendText(aBuffer, aLength, aStackParent, aBuilder); +} + +nsresult +nsHtml5TreeOperation::AppendComment(nsIContent* aParent, + char16_t* aBuffer, + int32_t aLength, + nsHtml5TreeOpExecutor* aBuilder) +{ + nsRefPtr comment = + new dom::Comment(aBuilder->GetNodeInfoManager()); + NS_ASSERTION(comment, "Infallible malloc failed?"); + nsresult rv = comment->SetText(aBuffer, aLength, false); + NS_ENSURE_SUCCESS(rv, rv); + + return Append(comment, aParent, aBuilder); +} + +nsresult +nsHtml5TreeOperation::AppendCommentToDocument(char16_t* aBuffer, + int32_t aLength, + nsHtml5TreeOpExecutor* aBuilder) +{ + nsRefPtr comment = + new dom::Comment(aBuilder->GetNodeInfoManager()); + NS_ASSERTION(comment, "Infallible malloc failed?"); + nsresult rv = comment->SetText(aBuffer, aLength, false); + NS_ENSURE_SUCCESS(rv, rv); + + return AppendToDocument(comment, aBuilder); +} + +nsresult +nsHtml5TreeOperation::AppendDoctypeToDocument(nsIAtom* aName, + const nsAString& aPublicId, + const nsAString& aSystemId, + nsHtml5TreeOpExecutor* aBuilder) +{ + // Adapted from nsXMLContentSink + // Create a new doctype node + nsCOMPtr docType; + nsAutoString voidString; + voidString.SetIsVoid(true); + NS_NewDOMDocumentType(getter_AddRefs(docType), + aBuilder->GetNodeInfoManager(), + aName, + aPublicId, + aSystemId, + voidString); + NS_ASSERTION(docType, "Doctype creation failed."); + nsCOMPtr asContent = do_QueryInterface(docType); + return AppendToDocument(asContent, aBuilder); +} + +nsIContent* +nsHtml5TreeOperation::GetDocumentFragmentForTemplate(nsIContent* aNode) +{ + dom::HTMLTemplateElement* tempElem = + static_cast(aNode); + nsRefPtr frag = tempElem->Content(); + return frag; +} + +void +nsHtml5TreeOperation::PreventScriptExecution(nsIContent* aNode) +{ + nsCOMPtr sele = do_QueryInterface(aNode); + MOZ_ASSERT(sele); + sele->PreventExecution(); +} + +void +nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode, + nsHtml5TreeOpExecutor* aBuilder) +{ + aNode->DoneAddingChildren(aBuilder->HaveNotified(aNode)); +} + +void +nsHtml5TreeOperation::DoneCreatingElement(nsIContent* aNode) +{ + aNode->DoneCreatingElement(); +} + nsresult nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, nsIContent** aScriptElement) { - nsresult rv = NS_OK; switch(mOpCode) { case eTreeOpAppend: { nsIContent* node = *(mOne.node); @@ -257,93 +641,28 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, } case eTreeOpDetach: { nsIContent* node = *(mOne.node); - aBuilder->FlushPendingAppendNotifications(); - nsCOMPtr parent = node->GetParentNode(); - if (parent) { - nsHtml5OtherDocUpdate update(parent->OwnerDoc(), - aBuilder->GetDocument()); - int32_t pos = parent->IndexOf(node); - NS_ASSERTION((pos >= 0), "Element not found as child of its parent"); - parent->RemoveChildAt(pos, true); - } + Detach(node, aBuilder); return NS_OK; } case eTreeOpAppendChildrenToNewParent: { nsCOMPtr node = *(mOne.node); nsIContent* parent = *(mTwo.node); - aBuilder->FlushPendingAppendNotifications(); - - nsHtml5OtherDocUpdate update(parent->OwnerDoc(), - aBuilder->GetDocument()); - - uint32_t childCount = parent->GetChildCount(); - bool didAppend = false; - while (node->HasChildren()) { - nsCOMPtr child = node->GetFirstChild(); - node->RemoveChildAt(0, true); - rv = parent->AppendChildTo(child, false); - NS_ENSURE_SUCCESS(rv, rv); - didAppend = true; - } - if (didAppend) { - nsNodeUtils::ContentAppended(parent, parent->GetChildAt(childCount), - childCount); - } - return rv; + return AppendChildrenToNewParent(node, parent, aBuilder); } case eTreeOpFosterParent: { nsIContent* node = *(mOne.node); nsIContent* parent = *(mTwo.node); nsIContent* table = *(mThree.node); - nsIContent* foster = table->GetParent(); - - if (IsElementOrTemplateContent(foster)) { - aBuilder->FlushPendingAppendNotifications(); - - nsHtml5OtherDocUpdate update(foster->OwnerDoc(), - aBuilder->GetDocument()); - - uint32_t pos = foster->IndexOf(table); - rv = foster->InsertChildAt(node, pos, false); - NS_ENSURE_SUCCESS(rv, rv); - nsNodeUtils::ContentInserted(foster, node, pos); - return rv; - } - - return Append(node, parent, aBuilder); + return FosterParent(node, parent, table, aBuilder); } case eTreeOpAppendToDocument: { nsIContent* node = *(mOne.node); return AppendToDocument(node, aBuilder); } case eTreeOpAddAttributes: { - dom::Element* node = (*(mOne.node))->AsElement(); + nsIContent* node = *(mOne.node); nsHtml5HtmlAttributes* attributes = mTwo.attributes; - - nsHtml5OtherDocUpdate update(node->OwnerDoc(), - aBuilder->GetDocument()); - - int32_t len = attributes->getLength(); - for (int32_t i = len; i > 0;) { - --i; - // prefix doesn't need regetting. it is always null or a static atom - // local name is never null - nsCOMPtr localName = - Reget(attributes->getLocalNameNoBoundsCheck(i)); - int32_t nsuri = attributes->getURINoBoundsCheck(i); - if (!node->HasAttr(nsuri, localName)) { - // prefix doesn't need regetting. it is always null or a static atom - // local name is never null - node->SetAttr(nsuri, - localName, - attributes->getPrefixNoBoundsCheck(i), - *(attributes->getValueNoBoundsCheck(i)), - true); - // XXX what to do with nsresult? - } - } - - return rv; + return AddAttributes(node, attributes, aBuilder); } case eTreeOpCreateElementNetwork: case eTreeOpCreateElementNotNetwork: { @@ -351,150 +670,19 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, int32_t ns = mFour.integer; nsCOMPtr name = Reget(mTwo.atom); nsHtml5HtmlAttributes* attributes = mThree.attributes; - - bool isKeygen = (name == nsHtml5Atoms::keygen && ns == kNameSpaceID_XHTML); - if (MOZ_UNLIKELY(isKeygen)) { - name = nsHtml5Atoms::select; - } - - nsCOMPtr newContent; - nsCOMPtr nodeInfo = aBuilder->GetNodeInfoManager()-> - GetNodeInfo(name, nullptr, ns, nsIDOMNode::ELEMENT_NODE); - NS_ASSERTION(nodeInfo, "Got null nodeinfo."); - NS_NewElement(getter_AddRefs(newContent), - nodeInfo.forget(), - (mOpCode == eTreeOpCreateElementNetwork ? - dom::FROM_PARSER_NETWORK - : (aBuilder->BelongsToStringParser() ? - dom::FROM_PARSER_FRAGMENT : - dom::FROM_PARSER_DOCUMENT_WRITE))); - NS_ASSERTION(newContent, "Element creation created null pointer."); - aBuilder->HoldElement(*target = newContent); - - if (MOZ_UNLIKELY(name == nsHtml5Atoms::style || name == nsHtml5Atoms::link)) { - nsCOMPtr ssle(do_QueryInterface(newContent)); - if (ssle) { - ssle->InitStyleLinkElement(false); - ssle->SetEnableUpdates(false); - } - } else if (MOZ_UNLIKELY(isKeygen)) { - // Adapted from CNavDTD - nsCOMPtr theFormProcessor = - do_GetService(kFormProcessorCID, &rv); - if (NS_FAILED(rv)) { - return NS_OK; - } - - nsTArray theContent; - nsAutoString theAttribute; - - (void) theFormProcessor->ProvideContent(NS_LITERAL_STRING("select"), - theContent, - theAttribute); - - newContent->SetAttr(kNameSpaceID_None, - nsGkAtoms::moztype, - nullptr, - theAttribute, - false); - - nsCOMPtr optionNodeInfo = - aBuilder->GetNodeInfoManager()->GetNodeInfo(nsHtml5Atoms::option, - nullptr, - kNameSpaceID_XHTML, - nsIDOMNode::ELEMENT_NODE); - - for (uint32_t i = 0; i < theContent.Length(); ++i) { - nsCOMPtr optionElt; - nsCOMPtr ni = optionNodeInfo; - NS_NewElement(getter_AddRefs(optionElt), - ni.forget(), - (mOpCode == eTreeOpCreateElementNetwork ? - dom::FROM_PARSER_NETWORK - : (aBuilder->BelongsToStringParser() ? - dom::FROM_PARSER_FRAGMENT : - dom::FROM_PARSER_DOCUMENT_WRITE))); - nsRefPtr optionText = - new nsTextNode(aBuilder->GetNodeInfoManager()); - (void) optionText->SetText(theContent[i], false); - optionElt->AppendChildTo(optionText, false); - newContent->AppendChildTo(optionElt, false); - newContent->DoneAddingChildren(false); - } - } - - if (!attributes) { - return rv; - } - - int32_t len = attributes->getLength(); - for (int32_t i = len; i > 0;) { - --i; - // prefix doesn't need regetting. it is always null or a static atom - // local name is never null - nsCOMPtr localName = - Reget(attributes->getLocalNameNoBoundsCheck(i)); - nsCOMPtr prefix = attributes->getPrefixNoBoundsCheck(i); - int32_t nsuri = attributes->getURINoBoundsCheck(i); - - if (ns == kNameSpaceID_XHTML && - nsHtml5Atoms::a == name && - nsHtml5Atoms::name == localName) { - // This is an HTML5-incompliant Geckoism. - // Remove when fixing bug 582361 - NS_ConvertUTF16toUTF8 cname(*(attributes->getValueNoBoundsCheck(i))); - NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting())); - newContent->SetAttr(nsuri, - localName, - prefix, - uv, - false); - } else { - nsString& value = *(attributes->getValueNoBoundsCheck(i)); - - newContent->SetAttr(nsuri, - localName, - prefix, - value, - false); - - // Custom element prototype swizzling may be needed if there is an - // "is" attribute. - if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) { - ErrorResult errorResult; - newContent->OwnerDoc()->SwizzleCustomElement(newContent, - value, - newContent->GetNameSpaceID(), - errorResult); - - } - } - } - - return rv; + *target = CreateElement(ns, + name, + attributes, + mOpCode == eTreeOpCreateElementNetwork, + aBuilder); + return NS_OK; } case eTreeOpSetFormElement: { nsIContent* node = *(mOne.node); nsIContent* parent = *(mTwo.node); - nsCOMPtr formControl(do_QueryInterface(node)); - nsCOMPtr domImageElement = do_QueryInterface(node); - // NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl."); - // TODO: uncomment the above line when (bug 101019) is supported by Gecko - nsCOMPtr formElement(do_QueryInterface(parent)); - NS_ASSERTION(formElement, "The form element doesn't implement nsIDOMHTMLFormElement."); - // avoid crashing on - if (formControl && - !node->HasAttr(kNameSpaceID_None, nsGkAtoms::form)) { - formControl->SetForm(formElement); - } else if (domImageElement) { - nsRefPtr imageElement = - static_cast(domImageElement.get()); - MOZ_ASSERT(imageElement); - imageElement->SetForm(formElement); - } - - return rv; + SetFormElement(node, parent); + return NS_OK; } case eTreeOpAppendText: { nsIContent* parent = *mOne.node; @@ -504,81 +692,25 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, } case eTreeOpAppendIsindexPrompt: { nsIContent* parent = *mOne.node; - nsXPIDLString prompt; - nsresult rv = - nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES, - "IsIndexPromptWithSpace", prompt); - uint32_t len = prompt.Length(); - if (NS_FAILED(rv)) { - return rv; - } - if (!len) { - // Don't bother appending a zero-length text node. - return NS_OK; - } - return AppendText(prompt.BeginReading(), len, parent, aBuilder); + return AppendIsindexPrompt(parent, aBuilder); } case eTreeOpFosterParentText: { nsIContent* stackParent = *mOne.node; char16_t* buffer = mTwo.unicharPtr; uint32_t length = mFour.integer; nsIContent* table = *mThree.node; - nsIContent* foster = table->GetParent(); - - if (IsElementOrTemplateContent(foster)) { - aBuilder->FlushPendingAppendNotifications(); - - nsHtml5OtherDocUpdate update(foster->OwnerDoc(), - aBuilder->GetDocument()); - - uint32_t pos = foster->IndexOf(table); - - nsIContent* previousSibling = table->GetPreviousSibling(); - if (previousSibling && previousSibling->IsNodeOfType(nsINode::eTEXT)) { - return AppendTextToTextNode(buffer, - length, - previousSibling, - aBuilder); - } - - nsRefPtr text = - new nsTextNode(aBuilder->GetNodeInfoManager()); - NS_ASSERTION(text, "Infallible malloc failed?"); - rv = text->SetText(buffer, length, false); - NS_ENSURE_SUCCESS(rv, rv); - - rv = foster->InsertChildAt(text, pos, false); - NS_ENSURE_SUCCESS(rv, rv); - nsNodeUtils::ContentInserted(foster, text, pos); - return rv; - } - - return AppendText(buffer, length, stackParent, aBuilder); + return FosterParentText(stackParent, buffer, length, table, aBuilder); } case eTreeOpAppendComment: { nsIContent* parent = *mOne.node; char16_t* buffer = mTwo.unicharPtr; int32_t length = mFour.integer; - - nsRefPtr comment = - new dom::Comment(aBuilder->GetNodeInfoManager()); - NS_ASSERTION(comment, "Infallible malloc failed?"); - rv = comment->SetText(buffer, length, false); - NS_ENSURE_SUCCESS(rv, rv); - - return Append(comment, parent, aBuilder); + return AppendComment(parent, buffer, length, aBuilder); } case eTreeOpAppendCommentToDocument: { char16_t* buffer = mTwo.unicharPtr; int32_t length = mFour.integer; - - nsRefPtr comment = - new dom::Comment(aBuilder->GetNodeInfoManager()); - NS_ASSERTION(comment, "Infallible malloc failed?"); - rv = comment->SetText(buffer, length, false); - NS_ENSURE_SUCCESS(rv, rv); - - return AppendToDocument(comment, aBuilder); + return AppendCommentToDocument(buffer, length, aBuilder); } case eTreeOpAppendDoctypeToDocument: { nsCOMPtr name = Reget(mOne.atom); @@ -586,32 +718,16 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, nsString publicId; nsString systemId; pair->Get(publicId, systemId); - - // Adapted from nsXMLContentSink - // Create a new doctype node - nsCOMPtr docType; - nsAutoString voidString; - voidString.SetIsVoid(true); - NS_NewDOMDocumentType(getter_AddRefs(docType), - aBuilder->GetNodeInfoManager(), - name, - publicId, - systemId, - voidString); - NS_ASSERTION(docType, "Doctype creation failed."); - nsCOMPtr asContent = do_QueryInterface(docType); - return AppendToDocument(asContent, aBuilder); + return AppendDoctypeToDocument(name, publicId, systemId, aBuilder); } case eTreeOpGetDocumentFragmentForTemplate: { - dom::HTMLTemplateElement* tempElem = - static_cast(*mOne.node); - nsRefPtr frag = tempElem->Content(); - *mTwo.node = frag.get(); - return rv; + nsIContent* node = *(mOne.node); + *mTwo.node = GetDocumentFragmentForTemplate(node); + return NS_OK; } case eTreeOpMarkAsBroken: { aBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY); - return rv; + return NS_OK; } case eTreeOpRunScript: { nsIContent* node = *(mOne.node); @@ -620,64 +736,61 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, aBuilder->InitializeDocWriteParserState(snapshot, mFour.integer); } *aScriptElement = node; - return rv; + return NS_OK; } case eTreeOpRunScriptAsyncDefer: { nsIContent* node = *(mOne.node); aBuilder->RunScript(node); - return rv; + return NS_OK; } case eTreeOpPreventScriptExecution: { nsIContent* node = *(mOne.node); - nsCOMPtr sele = do_QueryInterface(node); - MOZ_ASSERT(sele); - sele->PreventExecution(); - return rv; + PreventScriptExecution(node); + return NS_OK; } case eTreeOpDoneAddingChildren: { nsIContent* node = *(mOne.node); node->DoneAddingChildren(aBuilder->HaveNotified(node)); - return rv; + return NS_OK; } case eTreeOpDoneCreatingElement: { nsIContent* node = *(mOne.node); - node->DoneCreatingElement(); - return rv; + DoneCreatingElement(node); + return NS_OK; } case eTreeOpFlushPendingAppendNotifications: { aBuilder->FlushPendingAppendNotifications(); - return rv; + return NS_OK; } case eTreeOpSetDocumentCharset: { char* str = mOne.charPtr; int32_t charsetSource = mFour.integer; nsDependentCString dependentString(str); aBuilder->SetDocumentCharsetAndSource(dependentString, charsetSource); - return rv; + return NS_OK; } case eTreeOpNeedsCharsetSwitchTo: { char* str = mOne.charPtr; int32_t charsetSource = mFour.integer; int32_t lineNumber = mTwo.integer; aBuilder->NeedsCharsetSwitchTo(str, charsetSource, (uint32_t)lineNumber); - return rv; + return NS_OK; } case eTreeOpUpdateStyleSheet: { nsIContent* node = *(mOne.node); aBuilder->FlushPendingAppendNotifications(); aBuilder->UpdateStyleSheet(node); - return rv; + return NS_OK; } case eTreeOpProcessMeta: { nsIContent* node = *(mOne.node); - rv = aBuilder->ProcessMETATag(node); - return rv; + return aBuilder->ProcessMETATag(node); } case eTreeOpProcessOfflineManifest: { char16_t* str = mOne.unicharPtr; nsDependentString dependentString(str); aBuilder->ProcessOfflineManifest(dependentString); - return rv; + return NS_OK; } case eTreeOpMarkMalformedIfScript: { nsIContent* node = *(mOne.node); @@ -686,26 +799,26 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, // Make sure to serialize this script correctly, for nice round tripping. sele->SetIsMalformed(); } - return rv; + return NS_OK; } case eTreeOpStreamEnded: { aBuilder->DidBuildModel(false); // this causes a notifications flush anyway - return rv; + return NS_OK; } case eTreeOpStartLayout: { aBuilder->StartLayout(); // this causes a notification flush anyway - return rv; + return NS_OK; } case eTreeOpDocumentMode: { aBuilder->SetDocumentMode(mOne.mode); - return rv; + return NS_OK; } case eTreeOpSetStyleLineNumber: { nsIContent* node = *(mOne.node); nsCOMPtr ssle = do_QueryInterface(node); NS_ASSERTION(ssle, "Node didn't QI to style."); ssle->SetLineNumber(mFour.integer); - return rv; + return NS_OK; } case eTreeOpSetScriptLineNumberAndFreeze: { nsIContent* node = *(mOne.node); @@ -713,7 +826,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, NS_ASSERTION(sele, "Node didn't QI to script."); sele->SetScriptLineNumber(mFour.integer); sele->FreezeUriAsyncDefer(); - return rv; + return NS_OK; } case eTreeOpSvgLoad: { nsIContent* node = *(mOne.node); @@ -721,14 +834,14 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, if (NS_FAILED(NS_DispatchToMainThread(event))) { NS_WARNING("failed to dispatch svg load dispatcher"); } - return rv; + return NS_OK; } case eTreeOpMaybeComplainAboutCharset: { char* msgId = mOne.charPtr; bool error = mTwo.integer; int32_t lineNumber = mThree.integer; aBuilder->MaybeComplainAboutCharset(msgId, error, (uint32_t)lineNumber); - return rv; + return NS_OK; } case eTreeOpAddClass: { nsIContent* node = *(mOne.node); @@ -744,7 +857,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, } else { node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true); } - return rv; + return NS_OK; } case eTreeOpAddLineNumberId: { nsIContent* node = *(mOne.node); @@ -752,7 +865,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, nsAutoString val(NS_LITERAL_STRING("line")); val.AppendInt(lineNumber); node->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true); - return rv; + return NS_OK; } case eTreeOpAddViewSourceHref: { nsIContent* node = *mOne.node; @@ -765,10 +878,10 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, const nsCString& charset = doc->GetDocumentCharacterSet(); nsCOMPtr uri; - rv = NS_NewURI(getter_AddRefs(uri), - relative, - charset.get(), - aBuilder->GetViewSourceBaseURI()); + nsresult rv = NS_NewURI(getter_AddRefs(uri), + relative, + charset.get(), + aBuilder->GetViewSourceBaseURI()); NS_ENSURE_SUCCESS(rv, NS_OK); // Reuse the fix for bug 467852 @@ -827,6 +940,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, true); } + nsresult rv; nsXPIDLString message; if (otherAtom) { const char16_t* params[] = { atom->GetUTF16String(), @@ -860,6 +974,5 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, NS_NOTREACHED("Bogus tree op"); } } - return rv; // keep compiler happy + return NS_OK; // keep compiler happy } - diff --git a/parser/html/nsHtml5TreeOperation.h b/parser/html/nsHtml5TreeOperation.h index 4dd7667281b..dbb66820c09 100644 --- a/parser/html/nsHtml5TreeOperation.h +++ b/parser/html/nsHtml5TreeOperation.h @@ -88,6 +88,100 @@ class nsHtml5TreeOperationStringPair { class nsHtml5TreeOperation { public: + /** + * Atom is used inside the parser core are either static atoms that are + * the same as Gecko-wide static atoms or they are dynamic atoms scoped by + * both thread and parser to a particular nsHtml5AtomTable. In order to + * such scoped atoms coming into contact with the rest of Gecko, atoms + * that are about to exit the parser must go through this method which + * reobtains dynamic atoms from the Gecko-global atom table. + * + * @param aAtom a potentially parser-scoped atom + * @return an nsIAtom that's pointer comparable on the main thread with + * other not-parser atoms. + */ + static inline already_AddRefed Reget(nsIAtom* aAtom) + { + if (!aAtom || aAtom->IsStaticAtom()) { + return dont_AddRef(aAtom); + } + nsAutoString str; + aAtom->ToString(str); + return do_GetAtom(str); + } + + static nsresult AppendTextToTextNode(const char16_t* aBuffer, + uint32_t aLength, + nsIContent* aTextNode, + nsHtml5TreeOpExecutor* aBuilder); + + static nsresult AppendText(const char16_t* aBuffer, + uint32_t aLength, + nsIContent* aParent, + nsHtml5TreeOpExecutor* aBuilder); + + static nsresult Append(nsIContent* aNode, + nsIContent* aParent, + nsHtml5TreeOpExecutor* aBuilder); + + static nsresult AppendToDocument(nsIContent* aNode, + nsHtml5TreeOpExecutor* aBuilder); + + static void Detach(nsIContent* aNode, nsHtml5TreeOpExecutor* aBuilder); + + static nsresult AppendChildrenToNewParent(nsIContent* aNode, + nsIContent* aParent, + nsHtml5TreeOpExecutor* aBuilder); + + static nsresult FosterParent(nsIContent* aNode, + nsIContent* aParent, + nsIContent* aTable, + nsHtml5TreeOpExecutor* aBuilder); + + static nsresult AddAttributes(nsIContent* aNode, + nsHtml5HtmlAttributes* aAttributes, + nsHtml5TreeOpExecutor* aBuilder); + + static nsIContent* CreateElement(int32_t aNs, + nsIAtom* aName, + nsHtml5HtmlAttributes* aAttributes, + bool aFromNetwork, + nsHtml5TreeOpExecutor* aBuilder); + + static void SetFormElement(nsIContent* aNode, nsIContent* aParent); + + static nsresult AppendIsindexPrompt(nsIContent* parent, + nsHtml5TreeOpExecutor* aBuilder); + + static nsresult FosterParentText(nsIContent* aStackParent, + char16_t* aBuffer, + uint32_t aLength, + nsIContent* aTable, + nsHtml5TreeOpExecutor* aBuilder); + + static nsresult AppendComment(nsIContent* aParent, + char16_t* aBuffer, + int32_t aLength, + nsHtml5TreeOpExecutor* aBuilder); + + static nsresult AppendCommentToDocument(char16_t* aBuffer, + int32_t aLength, + nsHtml5TreeOpExecutor* aBuilder); + + static nsresult AppendDoctypeToDocument(nsIAtom* aName, + const nsAString& aPublicId, + const nsAString& aSystemId, + nsHtml5TreeOpExecutor* aBuilder); + + static nsIContent* GetDocumentFragmentForTemplate(nsIContent* aNode); + + static void PreventScriptExecution(nsIContent* aNode); + + static void DoneAddingChildren(nsIContent* aNode, + nsHtml5TreeOpExecutor* aBuilder); + + static void DoneCreatingElement(nsIContent* aNode); + nsHtml5TreeOperation(); ~nsHtml5TreeOperation(); @@ -349,34 +443,7 @@ class nsHtml5TreeOperation { nsresult Perform(nsHtml5TreeOpExecutor* aBuilder, nsIContent** aScriptElement); - inline already_AddRefed Reget(nsIAtom* aAtom) { - if (!aAtom || aAtom->IsStaticAtom()) { - return dont_AddRef(aAtom); - } - nsAutoString str; - aAtom->ToString(str); - return do_GetAtom(str); - } - private: - - nsresult AppendTextToTextNode(const char16_t* aBuffer, - uint32_t aLength, - nsIContent* aTextNode, - nsHtml5TreeOpExecutor* aBuilder); - - nsresult AppendText(const char16_t* aBuffer, - uint32_t aLength, - nsIContent* aParent, - nsHtml5TreeOpExecutor* aBuilder); - - nsresult Append(nsIContent* aNode, - nsIContent* aParent, - nsHtml5TreeOpExecutor* aBuilder); - - nsresult AppendToDocument(nsIContent* aNode, - nsHtml5TreeOpExecutor* aBuilder); - // possible optimization: // Make the queue take items the size of pointer and make the op code // decide how many operands it dequeues after it.