Bug 1425440 - Introduce nsINode::RemoveChildNode, r=catalinb

This commit is contained in:
Andrea Marchesini 2018-01-15 17:18:38 +01:00
Родитель 205d40e2d7
Коммит 41d4da5cef
22 изменённых файлов: 226 добавлений и 2 удалений

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

@ -331,6 +331,11 @@ Attr::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
{
}
void
Attr::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
}
nsresult
Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{

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

@ -70,6 +70,7 @@ public:
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;

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

@ -1177,6 +1177,12 @@ FragmentOrElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
}
}
void
FragmentOrElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
doRemoveChildAt(IndexOf(aKid), aNotify, aKid, mAttrsAndChildren);
}
void
FragmentOrElement::GetTextContentInternal(nsAString& aTextContent,
OOMReporter& aError)

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

@ -123,6 +123,7 @@ public:
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual void GetTextContentInternal(nsAString& aTextContent,
mozilla::OOMReporter& aError) override;
virtual void SetTextContentInternal(const nsAString& aTextContent,

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

@ -4401,6 +4401,28 @@ nsDocument::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
"(maybe somebody called GetRootElement() too early?)");
}
void
nsDocument::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
if (aKid->IsElement()) {
// Destroy the link map up front before we mess with the child list.
DestroyElementMaps();
}
// Preemptively clear mCachedRootElement, since we may be about to remove it
// from our child list, and we don't want to return this maybe-obsolete value
// from any GetRootElement() calls that happen inside of doRemoveChildAt().
// (NOTE: for this to be useful, doRemoveChildAt() must NOT trigger any
// GetRootElement() calls until after it's removed the child from mChildren.
// Any call before that point would restore this soon-to-be-obsolete cached
// answer, and our clearing here would be fruitless.)
mCachedRootElement = nullptr;
doRemoveChildAt(IndexOf(aKid), aNotify, aKid, mChildren);
MOZ_ASSERT(mCachedRootElement != aKid,
"Stale pointer in mCachedRootElement, after we tried to clear it "
"(maybe somebody called GetRootElement() too early?)");
}
void
nsDocument::EnsureOnDemandBuiltInUASheet(StyleSheet* aSheet)
{

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

@ -560,6 +560,7 @@ public:
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override
{

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

@ -663,6 +663,11 @@ nsGenericDOMDataNode::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
{
}
void
nsGenericDOMDataNode::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
}
nsXBLBinding *
nsGenericDOMDataNode::DoGetXBLBinding() const
{

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

@ -110,6 +110,7 @@ public:
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual void GetTextContentInternal(nsAString& aTextContent,
mozilla::OOMReporter& aError) override
{

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

@ -1927,7 +1927,7 @@ nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify,
// nsIDocument::GetRootElement() calls until *after* it has removed aKid from
// aChildArray. Any calls before then could potentially restore a stale
// value for our cached root element, per note in
// nsDocument::RemoveChildAt_Deprecated().
// nsDocument::RemoveChildNode().
MOZ_ASSERT(aKid && aKid->GetParentNode() == this &&
aKid == GetChildAt_Deprecated(aIndex) &&
IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");

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

@ -778,6 +778,17 @@ public:
*/
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) = 0;
/**
* Remove a child from this node. This method handles calling UnbindFromTree
* on the child appropriately.
*
* @param aKid the content to remove
* @param aNotify whether to notify the document (current document for
* nsIContent, and |this| for nsIDocument) that the remove has
* occurred
*/
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) = 0;
/**
* Get a property associated with this node.
*

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

@ -195,6 +195,32 @@ HTMLFieldSetElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
}
}
void
HTMLFieldSetElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
bool firstLegendHasChanged = false;
if (mFirstLegend && aKid == mFirstLegend) {
// If we are removing the first legend we have to found another one.
nsIContent* child = mFirstLegend->GetNextSibling();
mFirstLegend = nullptr;
firstLegendHasChanged = true;
for (; child; child = child->GetNextSibling()) {
if (child->IsHTMLElement(nsGkAtoms::legend)) {
mFirstLegend = child;
break;
}
}
}
nsGenericHTMLFormElement::RemoveChildNode(aKid, aNotify);
if (firstLegendHasChanged) {
NotifyElementsForFirstLegendChange(aNotify);
}
}
void
HTMLFieldSetElement::AddElement(nsGenericHTMLFormElement* aElement)
{

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

@ -44,6 +44,7 @@ public:
virtual nsresult InsertChildAt(nsIContent* aChild, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
// nsIFormControl
NS_IMETHOD Reset() override;

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

@ -95,6 +95,14 @@ HTMLOptGroupElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
nsGenericHTMLElement::RemoveChildAt_Deprecated(aIndex, aNotify);
}
void
HTMLOptGroupElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
SafeOptionListMutation safeMutation(GetSelect(), this, nullptr, IndexOf(aKid),
aNotify);
nsGenericHTMLElement::RemoveChildNode(aKid, aNotify);
}
nsresult
HTMLOptGroupElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
const nsAttrValue* aValue,

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

@ -28,6 +28,7 @@ public:
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
// nsIContent
virtual nsresult GetEventTargetParent(

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

@ -58,6 +58,30 @@ HTMLPictureElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
nsGenericHTMLElement::RemoveChildAt_Deprecated(aIndex, aNotify);
}
void
HTMLPictureElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
if (aKid && aKid->IsHTMLElement(nsGkAtoms::img)) {
HTMLImageElement* img = HTMLImageElement::FromContent(aKid);
if (img) {
img->PictureSourceRemoved(aKid->AsContent());
}
} else if (aKid && aKid->IsHTMLElement(nsGkAtoms::source)) {
// Find all img siblings after this <source> to notify them of its demise
nsCOMPtr<nsIContent> nextSibling = aKid->GetNextSibling();
if (nextSibling && nextSibling->GetParentNode() == this) {
do {
HTMLImageElement* img = HTMLImageElement::FromContent(nextSibling);
if (img) {
img->PictureSourceRemoved(aKid->AsContent());
}
} while ( (nextSibling = nextSibling->GetNextSibling()) );
}
}
nsGenericHTMLElement::RemoveChildNode(aKid, aNotify);
}
nsresult
HTMLPictureElement::InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify)
{

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

@ -24,6 +24,7 @@ public:
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
bool aPreallocateChildren) const override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify) override;
protected:

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

@ -224,7 +224,12 @@ HTMLSelectElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
nsGenericHTMLFormElementWithState::RemoveChildAt_Deprecated(aIndex, aNotify);
}
void
HTMLSelectElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
SafeOptionListMutation safeMutation(this, this, nullptr, IndexOf(aKid), aNotify);
nsGenericHTMLFormElementWithState::RemoveChildNode(aKid, aNotify);
}
void
HTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions,

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

@ -294,6 +294,7 @@ public:
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
// Overriden nsIFormControl methods
NS_IMETHOD Reset() override;

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

@ -100,6 +100,13 @@ SVGSwitchElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
MaybeInvalidate();
}
void
SVGSwitchElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
SVGSwitchElementBase::RemoveChildNode(aKid, aNotify);
MaybeInvalidate();
}
//----------------------------------------------------------------------
// nsIContent methods

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

@ -43,6 +43,7 @@ public:
virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
// nsIContent
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;

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

@ -949,6 +949,101 @@ nsXULElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
}
}
void
nsXULElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
{
// On the removal of a <treeitem>, <treechildren>, or <treecell> element,
// the possibility exists that some of the items in the removed subtree
// are selected (and therefore need to be deselected). We need to account for this.
nsCOMPtr<nsIDOMXULMultiSelectControlElement> controlElement;
nsCOMPtr<nsIListBoxObject> listBox;
bool fireSelectionHandler = false;
// -1 = do nothing, -2 = null out current item
// anything else = index to re-set as current
int32_t newCurrentIndex = -1;
if (aKid->NodeInfo()->Equals(nsGkAtoms::listitem, kNameSpaceID_XUL)) {
// This is the nasty case. We have (potentially) a slew of selected items
// and cells going away.
// First, retrieve the tree.
// Check first whether this element IS the tree
controlElement = do_QueryObject(this);
// If it's not, look at our parent
if (!controlElement)
GetParentTree(getter_AddRefs(controlElement));
nsCOMPtr<nsIContent> controlContent(do_QueryInterface(controlElement));
RefPtr<nsXULElement> xulElement = FromContentOrNull(controlContent);
nsCOMPtr<nsIDOMElement> oldKidElem = do_QueryInterface(aKid);
if (xulElement && oldKidElem) {
// Iterate over all of the items and find out if they are contained inside
// the removed subtree.
int32_t length;
controlElement->GetSelectedCount(&length);
for (int32_t i = 0; i < length; i++) {
nsCOMPtr<nsIDOMXULSelectControlItemElement> node;
controlElement->MultiGetSelectedItem(i, getter_AddRefs(node));
// we need to QI here to do an XPCOM-correct pointercompare
nsCOMPtr<nsIDOMElement> selElem = do_QueryInterface(node);
if (selElem == oldKidElem &&
NS_SUCCEEDED(controlElement->RemoveItemFromSelection(node))) {
length--;
i--;
fireSelectionHandler = true;
}
}
nsCOMPtr<nsIDOMXULSelectControlItemElement> curItem;
controlElement->GetCurrentItem(getter_AddRefs(curItem));
nsCOMPtr<nsIContent> curNode = do_QueryInterface(curItem);
if (curNode && nsContentUtils::ContentIsDescendantOf(curNode, aKid)) {
// Current item going away
IgnoredErrorResult ignored;
nsCOMPtr<nsIBoxObject> box = xulElement->GetBoxObject(ignored);
listBox = do_QueryInterface(box);
if (listBox && oldKidElem) {
listBox->GetIndexOfItem(oldKidElem, &newCurrentIndex);
}
// If any of this fails, we'll just set the current item to null
if (newCurrentIndex == -1)
newCurrentIndex = -2;
}
}
}
nsStyledElement::RemoveChildNode(aKid, aNotify);
if (newCurrentIndex == -2) {
controlElement->SetCurrentItem(nullptr);
} else if (newCurrentIndex > -1) {
// Make sure the index is still valid
int32_t treeRows;
listBox->GetRowCount(&treeRows);
if (treeRows > 0) {
newCurrentIndex = std::min((treeRows - 1), newCurrentIndex);
nsCOMPtr<nsIDOMElement> newCurrentItem;
listBox->GetItemAtIndex(newCurrentIndex, getter_AddRefs(newCurrentItem));
nsCOMPtr<nsIDOMXULSelectControlItemElement> xulCurItem = do_QueryInterface(newCurrentItem);
if (xulCurItem)
controlElement->SetCurrentItem(xulCurItem);
} else {
controlElement->SetCurrentItem(nullptr);
}
}
nsIDocument* doc;
if (fireSelectionHandler && (doc = GetComposedDoc())) {
nsContentUtils::DispatchTrustedEvent(doc,
static_cast<nsIContent*>(this),
NS_LITERAL_STRING("select"),
false,
true);
}
}
void
nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
{

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

@ -367,6 +367,7 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual void DestroyContent() override;
#ifdef DEBUG