mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
Bug 911477: Implement DOM4 methods: prepend(), append(), before(), after() and replaceWith() + Bug 1301777 (CVE-2016-9067)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user