зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1032979 part 2. Getting outerHTML on a node from an XML document should not use the self-closing form of empty container tags from the HTML namespace. r=smaug
--HG-- rename : testing/web-platform/tests/html/syntax/serializing-html-fragments/outerHTML.html => testing/web-platform/tests/html/syntax/serializing-xml-fragments/outerHTML.html
This commit is contained in:
Родитель
34ae6e1bac
Коммит
6efc9783c7
|
@ -412,47 +412,6 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
nsXHTMLContentSerializer::AppendEndOfElementStart(nsIContent *aOriginalElement,
|
||||
nsIAtom * aName,
|
||||
int32_t aNamespaceID,
|
||||
nsAString& aStr)
|
||||
{
|
||||
// this method is not called by nsHTMLContentSerializer
|
||||
// so we don't have to check HTML element, just XHTML
|
||||
NS_ASSERTION(!mIsHTMLSerializer, "nsHTMLContentSerializer shouldn't call this method !");
|
||||
|
||||
if (kNameSpaceID_XHTML != aNamespaceID) {
|
||||
return nsXMLContentSerializer::AppendEndOfElementStart(aOriginalElement, aName,
|
||||
aNamespaceID, aStr);
|
||||
}
|
||||
|
||||
nsIContent* content = aOriginalElement;
|
||||
|
||||
// for non empty elements, even if they are not a container, we always
|
||||
// serialize their content, because the XHTML element could contain non XHTML
|
||||
// nodes useful in some context, like in an XSLT stylesheet
|
||||
if (HasNoChildren(content)) {
|
||||
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
|
||||
if (parserService) {
|
||||
bool isContainer;
|
||||
parserService->
|
||||
IsContainer(parserService->HTMLCaseSensitiveAtomTagToId(aName),
|
||||
isContainer);
|
||||
if (!isContainer) {
|
||||
// for backward compatibility with HTML 4 user agents
|
||||
// only non-container HTML elements can be closed immediatly,
|
||||
// and a space is added before />
|
||||
return AppendToString(NS_LITERAL_STRING(" />"), aStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return AppendToString(kGreaterThan, aStr);
|
||||
}
|
||||
|
||||
bool
|
||||
nsXHTMLContentSerializer::AfterElementStart(nsIContent* aContent,
|
||||
nsIContent* aOriginalElement,
|
||||
|
@ -552,19 +511,16 @@ nsXHTMLContentSerializer::CheckElementStart(nsIContent * aContent,
|
|||
}
|
||||
|
||||
bool
|
||||
nsXHTMLContentSerializer::CheckElementEnd(nsIContent * aContent,
|
||||
bool & aForceFormat,
|
||||
nsXHTMLContentSerializer::CheckElementEnd(Element* aElement,
|
||||
bool& aForceFormat,
|
||||
nsAString& aStr)
|
||||
{
|
||||
NS_ASSERTION(!mIsHTMLSerializer, "nsHTMLContentSerializer shouldn't call this method !");
|
||||
|
||||
aForceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
|
||||
aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
|
||||
aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
|
||||
|
||||
// this method is not called by nsHTMLContentSerializer
|
||||
// so we don't have to check HTML element, just XHTML
|
||||
if (aContent->IsHTMLElement()) {
|
||||
if (mIsCopying && aContent->IsHTMLElement(nsGkAtoms::ol)) {
|
||||
if (mIsCopying && aElement->IsHTMLElement(nsGkAtoms::ol)) {
|
||||
NS_ASSERTION((!mOLStateStack.IsEmpty()), "Cannot have an empty OL Stack");
|
||||
/* Though at this point we must always have an state to be deleted as all
|
||||
the OL opening tags are supposed to push an olState object to the stack*/
|
||||
|
@ -573,31 +529,8 @@ nsXHTMLContentSerializer::CheckElementEnd(nsIContent * aContent,
|
|||
}
|
||||
}
|
||||
|
||||
if (HasNoChildren(aContent)) {
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
|
||||
if (parserService) {
|
||||
bool isContainer;
|
||||
|
||||
parserService->
|
||||
IsContainer(parserService->HTMLCaseSensitiveAtomTagToId(
|
||||
aContent->NodeInfo()->NameAtom()),
|
||||
isContainer);
|
||||
if (!isContainer) {
|
||||
// non-container HTML elements are already closed,
|
||||
// see AppendEndOfElementStart
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// for backward compatibility with old HTML user agents,
|
||||
// empty elements should have an ending tag, so we mustn't call
|
||||
// nsXMLContentSerializer::CheckElementEnd
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dummyFormat;
|
||||
return nsXMLContentSerializer::CheckElementEnd(aContent, dummyFormat, aStr);
|
||||
return nsXMLContentSerializer::CheckElementEnd(aElement, dummyFormat, aStr);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -47,19 +47,13 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
|
|||
nsAString& aStr,
|
||||
nsresult& aResult) override;
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
virtual bool AppendEndOfElementStart(nsIContent *aOriginalElement,
|
||||
nsIAtom * aName,
|
||||
int32_t aNamespaceID,
|
||||
nsAString& aStr) override;
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
virtual bool AfterElementStart(nsIContent* aContent,
|
||||
nsIContent* aOriginalElement,
|
||||
nsAString& aStr) override;
|
||||
|
||||
virtual bool CheckElementEnd(nsIContent * aContent,
|
||||
bool & aForceFormat,
|
||||
virtual bool CheckElementEnd(mozilla::dom::Element* aContent,
|
||||
bool& aForceFormat,
|
||||
nsAString& aStr) override;
|
||||
|
||||
virtual void AfterElementEnd(nsIContent * aContent,
|
||||
|
|
|
@ -960,8 +960,7 @@ nsXMLContentSerializer::AppendElementStart(Element* aElement,
|
|||
name, aStr, skipAttr, addNSAttr),
|
||||
NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
NS_ENSURE_TRUE(AppendEndOfElementStart(aOriginalElement, name,
|
||||
content->GetNameSpaceID(), aStr),
|
||||
NS_ENSURE_TRUE(AppendEndOfElementStart(aElement, aOriginalElement, aStr),
|
||||
NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()
|
||||
|
@ -974,19 +973,56 @@ nsXMLContentSerializer::AppendElementStart(Element* aElement,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// aElement is the actual element we're outputting. aOriginalElement is the one
|
||||
// in the original DOM, which is the one we have to test for kids.
|
||||
static bool
|
||||
ElementNeedsSeparateEndTag(Element* aElement, Element* aOriginalElement)
|
||||
{
|
||||
if (aOriginalElement->GetChildCount()) {
|
||||
// We have kids, so we need a separate end tag. This needs to be checked on
|
||||
// aOriginalElement because that's the one that's actually in the DOM and
|
||||
// might have kids.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!aElement->IsHTMLElement()) {
|
||||
// Empty non-HTML elements can just skip a separate end tag.
|
||||
return false;
|
||||
}
|
||||
|
||||
// HTML container tags should have a separate end tag even if empty, per spec.
|
||||
// See
|
||||
// https://w3c.github.io/DOM-Parsing/#dfn-concept-xml-serialization-algorithm
|
||||
bool isHTMLContainer = true; // Default in case we get no parser service.
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
if (parserService) {
|
||||
nsIAtom* localName = aElement->NodeInfo()->NameAtom();
|
||||
parserService->IsContainer(
|
||||
parserService->HTMLCaseSensitiveAtomTagToId(localName),
|
||||
isHTMLContainer);
|
||||
}
|
||||
return isHTMLContainer;
|
||||
}
|
||||
|
||||
bool
|
||||
nsXMLContentSerializer::AppendEndOfElementStart(nsIContent *aOriginalElement,
|
||||
nsIAtom * aName,
|
||||
int32_t aNamespaceID,
|
||||
nsXMLContentSerializer::AppendEndOfElementStart(Element* aElement,
|
||||
Element* aOriginalElement,
|
||||
nsAString& aStr)
|
||||
{
|
||||
// We don't output a separate end tag for empty elements
|
||||
if (!aOriginalElement->GetChildCount()) {
|
||||
return AppendToString(NS_LITERAL_STRING("/>"), aStr);
|
||||
}
|
||||
else {
|
||||
if (ElementNeedsSeparateEndTag(aElement, aOriginalElement)) {
|
||||
return AppendToString(kGreaterThan, aStr);
|
||||
}
|
||||
|
||||
// We don't need a separate end tag. For HTML elements (which at this point
|
||||
// must be non-containers), append a space before the '/', per spec. See
|
||||
// https://w3c.github.io/DOM-Parsing/#dfn-concept-xml-serialization-algorithm
|
||||
if (aOriginalElement->IsHTMLElement()) {
|
||||
if (!AppendToString(kSpace, aStr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return AppendToString(NS_LITERAL_STRING("/>"), aStr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -998,7 +1034,7 @@ nsXMLContentSerializer::AppendElementEnd(Element* aElement,
|
|||
nsIContent* content = aElement;
|
||||
|
||||
bool forceFormat = false, outputElementEnd;
|
||||
outputElementEnd = CheckElementEnd(content, forceFormat, aStr);
|
||||
outputElementEnd = CheckElementEnd(aElement, forceFormat, aStr);
|
||||
|
||||
nsIAtom *name = content->NodeInfo()->NameAtom();
|
||||
|
||||
|
@ -1119,13 +1155,17 @@ nsXMLContentSerializer::CheckElementStart(nsIContent * aContent,
|
|||
}
|
||||
|
||||
bool
|
||||
nsXMLContentSerializer::CheckElementEnd(nsIContent * aContent,
|
||||
bool & aForceFormat,
|
||||
nsXMLContentSerializer::CheckElementEnd(Element* aElement,
|
||||
bool& aForceFormat,
|
||||
nsAString& aStr)
|
||||
{
|
||||
// We don't output a separate end tag for empty element
|
||||
aForceFormat = false;
|
||||
return aContent->GetChildCount() > 0;
|
||||
|
||||
// XXXbz this is a bit messed up, but by now we don't have our fixed-up
|
||||
// version of aElement anymore. Let's hope fixup never changes the localName
|
||||
// or namespace...
|
||||
return ElementNeedsSeparateEndTag(aElement, aElement);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -233,13 +233,15 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
|||
nsresult& aResult);
|
||||
|
||||
/**
|
||||
* this method is responsible to finish the start tag,
|
||||
* in particulary to append the "greater than" sign
|
||||
* This method is responsible for appending the '>' at the end of the start
|
||||
* tag, possibly preceded by '/' and maybe a ' ' before that too.
|
||||
*
|
||||
* aElement and aOriginalElement are the same as the corresponding arguments
|
||||
* to AppendElementStart.
|
||||
*/
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
virtual bool AppendEndOfElementStart(nsIContent *aOriginalElement,
|
||||
nsIAtom * aName,
|
||||
int32_t aNamespaceID,
|
||||
bool AppendEndOfElementStart(mozilla::dom::Element* aEleemnt,
|
||||
mozilla::dom::Element* aOriginalElement,
|
||||
nsAString& aStr);
|
||||
|
||||
/**
|
||||
|
@ -260,8 +262,8 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
|||
* by setting aForceFormat to true.
|
||||
* @return boolean true if the element can be output
|
||||
*/
|
||||
virtual bool CheckElementEnd(nsIContent * aContent,
|
||||
bool & aForceFormat,
|
||||
virtual bool CheckElementEnd(mozilla::dom::Element* aElement,
|
||||
bool& aForceFormat,
|
||||
nsAString& aStr);
|
||||
|
||||
/**
|
||||
|
|
|
@ -30174,6 +30174,12 @@
|
|||
"deleted": [],
|
||||
"items": {
|
||||
"testharness": {
|
||||
"html/syntax/serializing-xml-fragments/outerHTML.html": [
|
||||
{
|
||||
"path": "html/syntax/serializing-xml-fragments/outerHTML.html",
|
||||
"url": "/html/syntax/serializing-xml-fragments/outerHTML.html"
|
||||
}
|
||||
],
|
||||
"streams/byte-length-queuing-strategy.https.html": [
|
||||
{
|
||||
"path": "streams/byte-length-queuing-strategy.https.html",
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>HTML Test: element.outerHTML to verify XML fragment serialization algorithm</title>
|
||||
<link rel="author" title="Intel" href="http://www.intel.com/">
|
||||
<link rel="help" href="https://w3c.github.io/DOM-Parsing/#dfn-concept-serialize-xml">
|
||||
<link rel="help" href="https://w3c.github.io/DOM-Parsing/#widl-Element-outerHTML">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../html-element-list.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
test(function() {
|
||||
var doc = document.implementation.createDocument(null, "");
|
||||
assert_equals(doc.contentType, "application/xml");
|
||||
var html_ns = "http://www.w3.org/1999/xhtml";
|
||||
elements_with_end_tag.forEach(function(ele) {
|
||||
test(function() {
|
||||
var e = doc.createElementNS(html_ns, ele);
|
||||
assert_equals(e.outerHTML,
|
||||
`<${ele} xmlns="${html_ns}"></${ele}>`,
|
||||
ele + " node created." );
|
||||
}, "Node for " + ele);
|
||||
});
|
||||
elements_without_end_tag.forEach(function(ele) {
|
||||
test(function() {
|
||||
var e = doc.createElementNS(html_ns, ele);
|
||||
assert_equals(e.outerHTML,
|
||||
`<${ele} xmlns="${html_ns}" />`,
|
||||
ele + " node created." );
|
||||
}, "Node for " + ele);
|
||||
});
|
||||
}, document.title);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче