Bug 911477: Implement DOM4 methods: prepend(), append(), before(), after() and replaceWith() + Bug 1301777 (CVE-2016-9067)

This commit is contained in:
janekptacijarabaci
2017-10-13 22:59:54 +02:00
committed by Roy Tam
parent 5daba22c79
commit 6b7653b9c6
4 changed files with 213 additions and 7 deletions
+188
View File
@@ -1591,6 +1591,168 @@ nsINode::GetNextElementSibling() const
return nullptr;
}
static already_AddRefed<nsINode>
GetNodeFromNodeOrString(const OwningNodeOrString& aNode,
nsIDocument* aDocument)
{
if (aNode.IsNode()) {
nsCOMPtr<nsINode> node = aNode.GetAsNode();
return node.forget();
}
if (aNode.IsString()){
nsRefPtr<nsTextNode> textNode =
aDocument->CreateTextNode(aNode.GetAsString());
return textNode.forget();
}
MOZ_CRASH("Impossible type");
}
/**
* Implement the algorithm specified at
* https://dom.spec.whatwg.org/#converting-nodes-into-a-node for |prepend()|,
* |append()|, |before()|, |after()|, and |replaceWith()| APIs.
*/
static already_AddRefed<nsINode>
ConvertNodesOrStringsIntoNode(const Sequence<OwningNodeOrString>& aNodes,
nsIDocument* aDocument,
ErrorResult& aRv)
{
if (aNodes.Length() == 1) {
return GetNodeFromNodeOrString(aNodes[0], aDocument);
}
nsCOMPtr<nsINode> fragment = aDocument->CreateDocumentFragment();
for (const auto& node : aNodes) {
nsCOMPtr<nsINode> childNode = GetNodeFromNodeOrString(node, aDocument);
fragment->AppendChild(*childNode, aRv);
if (aRv.Failed()) {
return nullptr;
}
}
return fragment.forget();
}
static void
InsertNodesIntoHashset(const Sequence<OwningNodeOrString>& aNodes,
nsTHashtable<nsPtrHashKey<nsINode>>& aHashset)
{
for (const auto& node : aNodes) {
if (node.IsNode()) {
aHashset.PutEntry(node.GetAsNode());
}
}
}
static nsINode*
FindViablePreviousSibling(const nsINode& aNode,
const Sequence<OwningNodeOrString>& aNodes)
{
nsTHashtable<nsPtrHashKey<nsINode>> nodeSet(16);
InsertNodesIntoHashset(aNodes, nodeSet);
nsINode* viablePreviousSibling = nullptr;
for (nsINode* sibling = aNode.GetPreviousSibling(); sibling;
sibling = sibling->GetPreviousSibling()) {
if (!nodeSet.Contains(sibling)) {
viablePreviousSibling = sibling;
break;
}
}
return viablePreviousSibling;
}
static nsINode*
FindViableNextSibling(const nsINode& aNode,
const Sequence<OwningNodeOrString>& aNodes)
{
nsTHashtable<nsPtrHashKey<nsINode>> nodeSet(16);
InsertNodesIntoHashset(aNodes, nodeSet);
nsINode* viableNextSibling = nullptr;
for (nsINode* sibling = aNode.GetNextSibling(); sibling;
sibling = sibling->GetNextSibling()) {
if (!nodeSet.Contains(sibling)) {
viableNextSibling = sibling;
break;
}
}
return viableNextSibling;
}
void
nsINode::Before(const Sequence<OwningNodeOrString>& aNodes,
ErrorResult& aRv)
{
nsCOMPtr<nsINode> parent = GetParentNode();
if (!parent) {
return;
}
nsCOMPtr<nsINode> viablePreviousSibling =
FindViablePreviousSibling(*this, aNodes);
nsCOMPtr<nsINode> node =
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
if (aRv.Failed()) {
return;
}
viablePreviousSibling = viablePreviousSibling ?
viablePreviousSibling->GetNextSibling() : parent->GetFirstChild();
parent->InsertBefore(*node, viablePreviousSibling, aRv);
}
void
nsINode::After(const Sequence<OwningNodeOrString>& aNodes,
ErrorResult& aRv)
{
nsCOMPtr<nsINode> parent = GetParentNode();
if (!parent) {
return;
}
nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
nsCOMPtr<nsINode> node =
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
if (aRv.Failed()) {
return;
}
parent->InsertBefore(*node, viableNextSibling, aRv);
}
void
nsINode::ReplaceWith(const Sequence<OwningNodeOrString>& aNodes,
ErrorResult& aRv)
{
nsCOMPtr<nsINode> parent = GetParentNode();
if (!parent) {
return;
}
nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
nsCOMPtr<nsINode> node =
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
if (aRv.Failed()) {
return;
}
if (parent == GetParentNode()) {
parent->ReplaceChild(*node, *this, aRv);
} else {
parent->InsertBefore(*node, viableNextSibling, aRv);
}
}
void
nsINode::Remove()
{
@@ -1634,6 +1796,32 @@ nsINode::GetLastElementChild() const
return nullptr;
}
void
nsINode::Prepend(const Sequence<OwningNodeOrString>& aNodes,
ErrorResult& aRv)
{
nsCOMPtr<nsINode> node =
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
if (aRv.Failed()) {
return;
}
InsertBefore(*node, mFirstChild, aRv);
}
void
nsINode::Append(const Sequence<OwningNodeOrString>& aNodes,
ErrorResult& aRv)
{
nsCOMPtr<nsINode> node =
ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv);
if (aRv.Failed()) {
return;
}
AppendChild(*node, aRv);
}
void
nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify,
nsIContent* aKid, nsAttrAndChildArray& aChildArray)
+14
View File
@@ -73,6 +73,8 @@ class Element;
class EventHandlerNonNull;
class OnErrorEventHandlerNonNull;
template<typename T> class Optional;
class OwningNodeOrString;
template<typename> class Sequence;
class Text;
class TextOrElementOrDocument;
struct DOMPointInit;
@@ -265,9 +267,13 @@ public:
typedef mozilla::dom::DOMPointInit DOMPointInit;
typedef mozilla::dom::DOMQuad DOMQuad;
typedef mozilla::dom::DOMRectReadOnly DOMRectReadOnly;
typedef mozilla::dom::OwningNodeOrString OwningNodeOrString;
typedef mozilla::dom::TextOrElementOrDocument TextOrElementOrDocument;
typedef mozilla::ErrorResult ErrorResult;
template<class T>
using Sequence = mozilla::dom::Sequence<T>;
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID)
// Among the sub-classes that inherit (directly or indirectly) from nsINode,
@@ -1655,6 +1661,11 @@ public:
// ChildNode methods
mozilla::dom::Element* GetPreviousElementSibling() const;
mozilla::dom::Element* GetNextElementSibling() const;
void Before(const Sequence<OwningNodeOrString>& aNodes, ErrorResult& aRv);
void After(const Sequence<OwningNodeOrString>& aNodes, ErrorResult& aRv);
void ReplaceWith(const Sequence<OwningNodeOrString>& aNodes,
ErrorResult& aRv);
/**
* Remove this node from its parent, if any.
*/
@@ -1664,6 +1675,9 @@ public:
mozilla::dom::Element* GetFirstElementChild() const;
mozilla::dom::Element* GetLastElementChild() const;
void Prepend(const Sequence<OwningNodeOrString>& aNodes, ErrorResult& aRv);
void Append(const Sequence<OwningNodeOrString>& aNodes, ErrorResult& aRv);
void GetBoxQuads(const BoxQuadOptions& aOptions,
nsTArray<nsRefPtr<DOMQuad> >& aResult,
mozilla::ErrorResult& aRv);
+7 -4
View File
@@ -9,10 +9,13 @@
[NoInterfaceObject]
interface ChildNode {
// Not implemented yet:
// void before((Node or DOMString)... nodes);
// void after((Node or DOMString)... nodes);
// void replace((Node or DOMString)... nodes);
[Throws, Unscopable]
void before((Node or DOMString)... nodes);
[Throws, Unscopable]
void after((Node or DOMString)... nodes);
[Throws, Unscopable]
void replaceWith((Node or DOMString)... nodes);
[Unscopable]
void remove();
};
+4 -3
View File
@@ -18,7 +18,8 @@ interface ParentNode {
[Pure]
readonly attribute unsigned long childElementCount;
// Not implemented yet
// void prepend((Node or DOMString)... nodes);
// void append((Node or DOMString)... nodes);
[Throws, Unscopable]
void prepend((Node or DOMString)... nodes);
[Throws, Unscopable]
void append((Node or DOMString)... nodes);
};