Bug 1213818 - Align document.title for SVG documents with HTML spec; r=bz

This allows setting, and for getting, pays attention to only children of
the root element (instead of all descendants as in HTML).
This commit is contained in:
Aryeh Gregor 2015-10-13 18:14:43 +03:00
Родитель 591940732d
Коммит 67f02040d6
4 изменённых файлов: 119 добавлений и 71 удалений

Просмотреть файл

@ -7014,8 +7014,8 @@ nsIDocument::GetHtmlChildElement(nsIAtom* aTag)
return nullptr;
}
nsIContent*
nsDocument::GetTitleContent(uint32_t aNamespace)
Element*
nsDocument::GetTitleElement()
{
// mMayHaveTitleElement will have been set to true if any HTML or SVG
// <title> element has been bound to this document. So if it's false,
@ -7025,19 +7025,26 @@ nsDocument::GetTitleContent(uint32_t aNamespace)
if (!mMayHaveTitleElement)
return nullptr;
Element* root = GetRootElement();
if (root && root->IsSVGElement(nsGkAtoms::svg)) {
// In SVG, the document's title must be a child
for (nsIContent* child = root->GetFirstChild();
child; child = child->GetNextSibling()) {
if (child->IsSVGElement(nsGkAtoms::title)) {
return child->AsElement();
}
}
return nullptr;
}
// We check the HTML namespace even for non-HTML documents, except SVG. This
// matches the spec and the behavior of all tested browsers.
nsRefPtr<nsContentList> list =
NS_GetContentList(this, aNamespace, NS_LITERAL_STRING("title"));
NS_GetContentList(this, kNameSpaceID_XHTML, NS_LITERAL_STRING("title"));
return list->Item(0, false);
}
nsIContent* first = list->Item(0, false);
void
nsDocument::GetTitleFromElement(uint32_t aNamespace, nsAString& aTitle)
{
nsIContent* title = GetTitleContent(aNamespace);
if (!title)
return;
nsContentUtils::GetNodeTextContent(title, false, aTitle);
return first ? first->AsElement() : nullptr;
}
NS_IMETHODIMP
@ -7054,26 +7061,24 @@ nsDocument::GetTitle(nsString& aTitle)
{
aTitle.Truncate();
nsIContent *rootElement = GetRootElement();
if (!rootElement)
Element* rootElement = GetRootElement();
if (!rootElement) {
return;
}
nsAutoString tmp;
switch (rootElement->GetNameSpaceID()) {
#ifdef MOZ_XUL
case kNameSpaceID_XUL:
rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, tmp);
break;
if (rootElement->IsXULElement()) {
rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, tmp);
} else
#endif
case kNameSpaceID_SVG:
if (rootElement->IsSVGElement(nsGkAtoms::svg)) {
GetTitleFromElement(kNameSpaceID_SVG, tmp);
break;
} // else fall through
default:
GetTitleFromElement(kNameSpaceID_XHTML, tmp);
break;
{
Element* title = GetTitleElement();
if (!title) {
return;
}
nsContentUtils::GetNodeTextContent(title, false, tmp);
}
tmp.CompressWhitespace();
@ -7083,41 +7088,56 @@ nsDocument::GetTitle(nsString& aTitle)
NS_IMETHODIMP
nsDocument::SetTitle(const nsAString& aTitle)
{
Element *rootElement = GetRootElement();
if (!rootElement)
Element* rootElement = GetRootElement();
if (!rootElement) {
return NS_OK;
switch (rootElement->GetNameSpaceID()) {
case kNameSpaceID_SVG:
return NS_OK; // SVG doesn't support setting a title
#ifdef MOZ_XUL
case kNameSpaceID_XUL:
return rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::title,
aTitle, true);
#endif
}
#ifdef MOZ_XUL
if (rootElement->IsXULElement()) {
return rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::title,
aTitle, true);
}
#endif
// Batch updates so that mutation events don't change "the title
// element" under us
mozAutoDocUpdate updateBatch(this, UPDATE_CONTENT_MODEL, true);
nsIContent* title = GetTitleContent(kNameSpaceID_XHTML);
if (!title) {
Element *head = GetHeadElement();
if (!head)
return NS_OK;
nsCOMPtr<Element> title = GetTitleElement();
if (rootElement->IsSVGElement(nsGkAtoms::svg)) {
if (!title) {
nsRefPtr<mozilla::dom::NodeInfo> titleInfo =
mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr,
kNameSpaceID_SVG,
nsIDOMNode::ELEMENT_NODE);
NS_NewSVGElement(getter_AddRefs(title), titleInfo.forget(),
NOT_FROM_PARSER);
if (!title) {
return NS_OK;
}
rootElement->InsertChildAt(title, 0, true);
}
} else if (rootElement->IsHTMLElement()) {
if (!title) {
Element* head = GetHeadElement();
if (!head) {
return NS_OK;
}
{
nsRefPtr<mozilla::dom::NodeInfo> titleInfo;
titleInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr,
kNameSpaceID_XHTML,
nsIDOMNode::ELEMENT_NODE);
kNameSpaceID_XHTML,
nsIDOMNode::ELEMENT_NODE);
title = NS_NewHTMLTitleElement(titleInfo.forget());
if (!title)
if (!title) {
return NS_OK;
}
}
head->AppendChildTo(title, true);
head->AppendChildTo(title, true);
}
} else {
return NS_OK;
}
return nsContentUtils::SetNodeTextContent(title, aTitle, false);

Просмотреть файл

@ -1474,13 +1474,15 @@ protected:
nsIContent* GetFirstBaseNodeWithHref();
nsresult SetFirstBaseNodeWithHref(nsIContent *node);
// Get the first <title> element with the given IsNodeOfType type, or
// return null if there isn't one
nsIContent* GetTitleContent(uint32_t aNodeType);
// Find the first "title" element in the given IsNodeOfType type and
// append the concatenation of its text node children to aTitle. Do
// nothing if there is no such element.
void GetTitleFromElement(uint32_t aNodeType, nsAString& aTitle);
/**
* Returns the title element of the document as defined by the HTML
* specification, or null if there isn't one. For documents whose root
* element is an <svg:svg>, this is the first <svg:title> element that's a
* child of the root. For other documents, it's the first HTML title element
* in the document.
*/
Element* GetTitleElement();
public:
// Get our title
virtual void GetTitle(nsString& aTitle) override;

Просмотреть файл

@ -1,11 +0,0 @@
[document.title-09.html]
type: testharness
[No title element in SVG document]
expected: FAIL
[Title element in SVG document]
expected: FAIL
[Title element not child of SVG root]
expected: FAIL

Просмотреть файл

@ -5,21 +5,25 @@
<div id="log"></div>
<script>
var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
function newSVGDocument() {
return document.implementation.createDocument(SVG_NAMESPACE, "svg");
}
function assertIsSVGTitle(element, expectedText) {
assert_equals(element.namespaceURI, SVG_NAMESPACE);
assert_equals(element.localName, "title");
assert_equals(element.textContent, expectedText);
}
test(function() {
var doc = newSVGDocument();
assert_equals(doc.title, "");
var child = doc.createElementNS(SVG_NAMESPACE, "x-child");
doc.documentElement.appendChild(child);
doc.title = "foo";
var lastChild = doc.documentElement.lastChild;
assert_equals(lastChild.namespaceURI, SVG_NAMESPACE);
assert_equals(lastChild.localName, "title");
assert_equals(lastChild.textContent, "foo");
assertIsSVGTitle(doc.documentElement.firstChild, "foo");
assert_equals(doc.title, "foo");
}, "No title element in SVG document");
@ -48,13 +52,46 @@ test(function() {
child.appendChild(title);
doc.documentElement.appendChild(child);
assert_equals(doc.title, "");
// Now test that on setting, we create a new element and don't change the
// existing one
doc.title = "bar";
assert_equals(title.textContent, "foo");
assertIsSVGTitle(doc.documentElement.firstChild, "bar");
assert_equals(doc.title, "bar");
}, "Title element not child of SVG root");
test(function() {
var doc = newSVGDocument();
var title = doc.createElement("title");
var title = doc.createElementNS(HTML_NAMESPACE, "title");
title.textContent = "foo";
doc.documentElement.appendChild(title);
assert_equals(doc.title, "");
}, "Title element not in SVG namespace");
test(function() {
// "SVG" != "svg"
var doc = document.implementation.createDocument(SVG_NAMESPACE, "SVG", null);
// Per spec, this does nothing
doc.title = "foo";
assert_equals(doc.documentElement.childNodes.length, 0);
assert_equals(doc.title, "");
// An SVG title is ignored by .title
doc.documentElement.appendChild(doc.createElementNS(SVG_NAMESPACE, "title"));
doc.documentElement.lastChild.textContent = "foo";
assert_equals(doc.title, "");
// But an HTML title is respected
doc.documentElement.appendChild(doc.createElementNS(HTML_NAMESPACE, "title"));
doc.documentElement.lastChild.textContent = "bar";
assert_equals(doc.title, "bar");
// Even if it's not a child of the root
var div = doc.createElementNS(HTML_NAMESPACE, "div");
div.appendChild(doc.documentElement.lastChild);
doc.documentElement.appendChild(div);
assert_equals(doc.title, "bar");
}, 'Root element not named "svg"');
</script>