зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1386110 - Use a smart pointer to reliably de-register NAC regardless of how it goes away. r=masayuki
MozReview-Commit-ID: HTSu5BjxD8I
This commit is contained in:
Родитель
693c0c370f
Коммит
1bd3bc937c
|
@ -66,6 +66,7 @@
|
|||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/InternalMutationEvent.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/ManualNAC.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
|
@ -10348,7 +10349,7 @@ nsContentUtils::AppendNativeAnonymousChildren(
|
|||
}
|
||||
|
||||
// Get manually created NAC (editor resize handles, etc.).
|
||||
if (auto nac = static_cast<ManualNAC*>(
|
||||
if (auto nac = static_cast<ManualNACArray*>(
|
||||
aContent->GetProperty(nsGkAtoms::manualNACProperty))) {
|
||||
aKids.AppendElements(*nac);
|
||||
}
|
||||
|
|
|
@ -197,15 +197,6 @@ struct EventNameMapping
|
|||
typedef bool (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
|
||||
void* aArg);
|
||||
|
||||
namespace mozilla {
|
||||
// 16 seems to be the maximum number of manual NAC nodes that editor
|
||||
// creates for a given element.
|
||||
//
|
||||
// These need to be manually removed by the machinery that sets the NAC,
|
||||
// otherwise we'll leak.
|
||||
typedef AutoTArray<RefPtr<mozilla::dom::Element>,16> ManualNAC;
|
||||
}
|
||||
|
||||
class nsContentUtils
|
||||
{
|
||||
friend class nsAutoScriptBlockerSuppressNodeRemoved;
|
||||
|
|
|
@ -229,11 +229,11 @@ HTMLEditor::GetElementZIndex(nsIDOMElement* aElement,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
ManualNACPtr
|
||||
HTMLEditor::CreateGrabber(nsINode* aParentNode)
|
||||
{
|
||||
// let's create a grabber through the element factory
|
||||
RefPtr<Element> ret =
|
||||
ManualNACPtr ret =
|
||||
CreateAnonymousElement(nsGkAtoms::span, GetAsDOMNode(aParentNode),
|
||||
NS_LITERAL_STRING("mozGrabber"), false);
|
||||
if (NS_WARN_IF(!ret)) {
|
||||
|
@ -245,7 +245,7 @@ HTMLEditor::CreateGrabber(nsINode* aParentNode)
|
|||
evtTarget->AddEventListener(NS_LITERAL_STRING("mousedown"),
|
||||
mEventListener, false);
|
||||
|
||||
return ret.forget();
|
||||
return ret;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -289,10 +289,8 @@ HTMLEditor::HideGrabber()
|
|||
// are no document observers to notify, but we still want to
|
||||
// UnbindFromTree.
|
||||
|
||||
DeleteRefToAnonymousNode(mGrabber, ps);
|
||||
mGrabber = nullptr;
|
||||
DeleteRefToAnonymousNode(mPositioningShadow, ps);
|
||||
mPositioningShadow = nullptr;
|
||||
DeleteRefToAnonymousNode(Move(mGrabber), ps);
|
||||
DeleteRefToAnonymousNode(Move(mPositioningShadow), ps);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -391,7 +389,7 @@ HTMLEditor::EndMoving()
|
|||
nsCOMPtr<nsIPresShell> ps = GetPresShell();
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
DeleteRefToAnonymousNode(mPositioningShadow, ps);
|
||||
DeleteRefToAnonymousNode(Move(mPositioningShadow), ps);
|
||||
|
||||
mPositioningShadow = nullptr;
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ ElementDeletionObserver::NodeWillBeDestroyed(const nsINode* aNode)
|
|||
NS_RELEASE_THIS();
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
ManualNACPtr
|
||||
HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
||||
nsIDOMNode* aParentNode,
|
||||
const nsAString& aAnonClass,
|
||||
|
@ -196,16 +196,16 @@ HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
|||
}
|
||||
|
||||
// Create a new node through the element factory
|
||||
RefPtr<Element> newContent = CreateHTMLContent(aTag);
|
||||
if (NS_WARN_IF(!newContent)) {
|
||||
RefPtr<Element> newContentRaw = CreateHTMLContent(aTag);
|
||||
if (NS_WARN_IF(!newContentRaw)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// add the "hidden" class if needed
|
||||
if (aIsCreatedHidden) {
|
||||
nsresult rv =
|
||||
newContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
|
||||
NS_LITERAL_STRING("hidden"), true);
|
||||
newContentRaw->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
|
||||
NS_LITERAL_STRING("hidden"), true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -214,8 +214,8 @@ HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
|||
// add an _moz_anonclass attribute if needed
|
||||
if (!aAnonClass.IsEmpty()) {
|
||||
nsresult rv =
|
||||
newContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_anonclass,
|
||||
aAnonClass, true);
|
||||
newContentRaw->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_anonclass,
|
||||
aAnonClass, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -225,24 +225,16 @@ HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
|||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
// establish parenthood of the element
|
||||
newContent->SetIsNativeAnonymousRoot();
|
||||
newContentRaw->SetIsNativeAnonymousRoot();
|
||||
nsresult rv =
|
||||
newContent->BindToTree(doc, parentContent, parentContent, true);
|
||||
newContentRaw->BindToTree(doc, parentContent, parentContent, true);
|
||||
if (NS_FAILED(rv)) {
|
||||
newContent->UnbindFromTree();
|
||||
newContentRaw->UnbindFromTree();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Record the NAC on the element, so that AllChildrenIterator can find it.
|
||||
auto nac = static_cast<ManualNAC*>(
|
||||
parentContent->GetProperty(nsGkAtoms::manualNACProperty));
|
||||
if (!nac) {
|
||||
nac = new ManualNAC();
|
||||
parentContent->SetProperty(nsGkAtoms::manualNACProperty, nac,
|
||||
nsINode::DeleteProperty<ManualNAC>);
|
||||
}
|
||||
nac->AppendElement(newContent);
|
||||
ManualNACPtr newContent(newContentRaw.forget());
|
||||
|
||||
// Must style the new element, otherwise the PostRecreateFramesFor call
|
||||
// below will do nothing.
|
||||
|
@ -268,7 +260,7 @@ HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
|||
// display the element
|
||||
ps->PostRecreateFramesFor(newContent);
|
||||
|
||||
return newContent.forget();
|
||||
return Move(newContent);
|
||||
}
|
||||
|
||||
// Removes event listener and calls DeleteRefToAnonymousNode.
|
||||
|
@ -276,19 +268,19 @@ void
|
|||
HTMLEditor::RemoveListenerAndDeleteRef(const nsAString& aEvent,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
Element* aElement,
|
||||
ManualNACPtr aElement,
|
||||
nsIPresShell* aShell)
|
||||
{
|
||||
nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement));
|
||||
if (evtTarget) {
|
||||
evtTarget->RemoveEventListener(aEvent, aListener, aUseCapture);
|
||||
}
|
||||
DeleteRefToAnonymousNode(aElement, aShell);
|
||||
DeleteRefToAnonymousNode(Move(aElement), aShell);
|
||||
}
|
||||
|
||||
// Deletes all references to an anonymous element
|
||||
void
|
||||
HTMLEditor::DeleteRefToAnonymousNode(nsIContent* aContent,
|
||||
HTMLEditor::DeleteRefToAnonymousNode(ManualNACPtr aContent,
|
||||
nsIPresShell* aShell)
|
||||
{
|
||||
// call ContentRemoved() for the anonymous content
|
||||
|
@ -332,19 +324,7 @@ HTMLEditor::DeleteRefToAnonymousNode(nsIContent* aContent,
|
|||
}
|
||||
}
|
||||
|
||||
// Remove reference from the parent element.
|
||||
auto nac = static_cast<mozilla::ManualNAC*>(
|
||||
parentContent->GetProperty(nsGkAtoms::manualNACProperty));
|
||||
// nsIDocument::AdoptNode might remove all properties before destroying
|
||||
// editor. So we have to consider that NAC could be already removed.
|
||||
if (nac) {
|
||||
nac->RemoveElement(aContent);
|
||||
if (nac->IsEmpty()) {
|
||||
parentContent->DeleteProperty(nsGkAtoms::manualNACProperty);
|
||||
}
|
||||
}
|
||||
|
||||
aContent->UnbindFromTree();
|
||||
// The ManualNACPtr destructor will invoke UnbindFromTree.
|
||||
}
|
||||
|
||||
// The following method is mostly called by a selection listener. When a
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CSSEditUtils.h"
|
||||
#include "mozilla/ManualNAC.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/TextEditor.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
@ -857,9 +858,9 @@ protected:
|
|||
void RemoveListenerAndDeleteRef(const nsAString& aEvent,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
Element* aElement,
|
||||
ManualNACPtr aElement,
|
||||
nsIPresShell* aShell);
|
||||
void DeleteRefToAnonymousNode(nsIContent* aContent,
|
||||
void DeleteRefToAnonymousNode(ManualNACPtr aContent,
|
||||
nsIPresShell* aShell);
|
||||
|
||||
nsresult ShowResizersInner(nsIDOMElement *aResizedElement);
|
||||
|
@ -900,19 +901,19 @@ protected:
|
|||
bool mIsInlineTableEditingEnabled;
|
||||
|
||||
// resizing
|
||||
nsCOMPtr<Element> mTopLeftHandle;
|
||||
nsCOMPtr<Element> mTopHandle;
|
||||
nsCOMPtr<Element> mTopRightHandle;
|
||||
nsCOMPtr<Element> mLeftHandle;
|
||||
nsCOMPtr<Element> mRightHandle;
|
||||
nsCOMPtr<Element> mBottomLeftHandle;
|
||||
nsCOMPtr<Element> mBottomHandle;
|
||||
nsCOMPtr<Element> mBottomRightHandle;
|
||||
ManualNACPtr mTopLeftHandle;
|
||||
ManualNACPtr mTopHandle;
|
||||
ManualNACPtr mTopRightHandle;
|
||||
ManualNACPtr mLeftHandle;
|
||||
ManualNACPtr mRightHandle;
|
||||
ManualNACPtr mBottomLeftHandle;
|
||||
ManualNACPtr mBottomHandle;
|
||||
ManualNACPtr mBottomRightHandle;
|
||||
|
||||
nsCOMPtr<Element> mActivatedHandle;
|
||||
|
||||
nsCOMPtr<Element> mResizingShadow;
|
||||
nsCOMPtr<Element> mResizingInfo;
|
||||
ManualNACPtr mResizingShadow;
|
||||
ManualNACPtr mResizingInfo;
|
||||
|
||||
nsCOMPtr<Element> mResizedObject;
|
||||
|
||||
|
@ -943,18 +944,17 @@ protected:
|
|||
|
||||
nsresult SetAllResizersPosition();
|
||||
|
||||
already_AddRefed<Element> CreateResizer(int16_t aLocation,
|
||||
nsIDOMNode* aParentNode);
|
||||
ManualNACPtr CreateResizer(int16_t aLocation, nsIDOMNode* aParentNode);
|
||||
void SetAnonymousElementPosition(int32_t aX, int32_t aY,
|
||||
Element* aResizer);
|
||||
|
||||
already_AddRefed<Element> CreateShadow(nsIDOMNode* aParentNode,
|
||||
nsIDOMElement* aOriginalObject);
|
||||
ManualNACPtr CreateShadow(nsIDOMNode* aParentNode,
|
||||
nsIDOMElement* aOriginalObject);
|
||||
nsresult SetShadowPosition(Element* aShadow, Element* aOriginalObject,
|
||||
int32_t aOriginalObjectX,
|
||||
int32_t aOriginalObjectY);
|
||||
|
||||
already_AddRefed<Element> CreateResizingInfo(nsIDOMNode* aParentNode);
|
||||
ManualNACPtr CreateResizingInfo(nsIDOMNode* aParentNode);
|
||||
nsresult SetResizingInfoPosition(int32_t aX, int32_t aY,
|
||||
int32_t aW, int32_t aH);
|
||||
|
||||
|
@ -983,12 +983,12 @@ protected:
|
|||
int32_t mPositionedObjectBorderTop;
|
||||
|
||||
nsCOMPtr<Element> mAbsolutelyPositionedObject;
|
||||
nsCOMPtr<Element> mGrabber;
|
||||
nsCOMPtr<Element> mPositioningShadow;
|
||||
ManualNACPtr mGrabber;
|
||||
ManualNACPtr mPositioningShadow;
|
||||
|
||||
int32_t mGridSize;
|
||||
|
||||
already_AddRefed<Element> CreateGrabber(nsINode* aParentNode);
|
||||
ManualNACPtr CreateGrabber(nsINode* aParentNode);
|
||||
nsresult StartMoving(nsIDOMElement* aHandle);
|
||||
nsresult SetFinalPosition(int32_t aX, int32_t aY);
|
||||
void AddPositioningOffset(int32_t& aX, int32_t& aY);
|
||||
|
@ -1001,13 +1001,13 @@ protected:
|
|||
// inline table editing
|
||||
nsCOMPtr<nsIDOMElement> mInlineEditedCell;
|
||||
|
||||
RefPtr<Element> mAddColumnBeforeButton;
|
||||
RefPtr<Element> mRemoveColumnButton;
|
||||
RefPtr<Element> mAddColumnAfterButton;
|
||||
ManualNACPtr mAddColumnBeforeButton;
|
||||
ManualNACPtr mRemoveColumnButton;
|
||||
ManualNACPtr mAddColumnAfterButton;
|
||||
|
||||
RefPtr<Element> mAddRowBeforeButton;
|
||||
RefPtr<Element> mRemoveRowButton;
|
||||
RefPtr<Element> mAddRowAfterButton;
|
||||
ManualNACPtr mAddRowBeforeButton;
|
||||
ManualNACPtr mRemoveRowButton;
|
||||
ManualNACPtr mAddRowAfterButton;
|
||||
|
||||
void AddMouseClickListener(Element* aElement);
|
||||
void RemoveMouseClickListener(Element* aElement);
|
||||
|
@ -1053,11 +1053,10 @@ private:
|
|||
* is to be added to the created anonymous
|
||||
* element
|
||||
*/
|
||||
already_AddRefed<Element> CreateAnonymousElement(
|
||||
nsIAtom* aTag,
|
||||
nsIDOMNode* aParentNode,
|
||||
const nsAString& aAnonClass,
|
||||
bool aIsCreatedHidden);
|
||||
ManualNACPtr CreateAnonymousElement(nsIAtom* aTag,
|
||||
nsIDOMNode* aParentNode,
|
||||
const nsAString& aAnonClass,
|
||||
bool aIsCreatedHidden);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -131,11 +131,11 @@ ResizerMouseMotionListener::HandleEvent(nsIDOMEvent* aMouseEvent)
|
|||
* mozilla::HTMLEditor
|
||||
******************************************************************************/
|
||||
|
||||
already_AddRefed<Element>
|
||||
ManualNACPtr
|
||||
HTMLEditor::CreateResizer(int16_t aLocation,
|
||||
nsIDOMNode* aParentNode)
|
||||
{
|
||||
RefPtr<Element> ret =
|
||||
ManualNACPtr ret =
|
||||
CreateAnonymousElement(nsGkAtoms::span,
|
||||
aParentNode,
|
||||
NS_LITERAL_STRING("mozResizer"),
|
||||
|
@ -182,10 +182,10 @@ HTMLEditor::CreateResizer(int16_t aLocation,
|
|||
nsresult rv =
|
||||
ret->SetAttr(kNameSpaceID_None, nsGkAtoms::anonlocation, locationStr, true);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return ret.forget();
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
ManualNACPtr
|
||||
HTMLEditor::CreateShadow(nsIDOMNode* aParentNode,
|
||||
nsIDOMElement* aOriginalObject)
|
||||
{
|
||||
|
@ -196,20 +196,17 @@ HTMLEditor::CreateShadow(nsIDOMNode* aParentNode,
|
|||
} else {
|
||||
name = nsGkAtoms::span;
|
||||
}
|
||||
RefPtr<Element> ret =
|
||||
CreateAnonymousElement(name, aParentNode,
|
||||
NS_LITERAL_STRING("mozResizingShadow"), true);
|
||||
return ret.forget();
|
||||
|
||||
return CreateAnonymousElement(name, aParentNode,
|
||||
NS_LITERAL_STRING("mozResizingShadow"), true);
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
ManualNACPtr
|
||||
HTMLEditor::CreateResizingInfo(nsIDOMNode* aParentNode)
|
||||
{
|
||||
// let's create an info box through the element factory
|
||||
RefPtr<Element> ret =
|
||||
CreateAnonymousElement(nsGkAtoms::span, aParentNode,
|
||||
NS_LITERAL_STRING("mozResizingInfo"), true);
|
||||
return ret.forget();
|
||||
return CreateAnonymousElement(nsGkAtoms::span, aParentNode,
|
||||
NS_LITERAL_STRING("mozResizingInfo"), true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -386,44 +383,34 @@ HTMLEditor::HideResizers()
|
|||
NS_NAMED_LITERAL_STRING(mousedown, "mousedown");
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mTopLeftHandle, ps);
|
||||
mTopLeftHandle = nullptr;
|
||||
Move(mTopLeftHandle), ps);
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mTopHandle, ps);
|
||||
mTopHandle = nullptr;
|
||||
Move(mTopHandle), ps);
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mTopRightHandle, ps);
|
||||
mTopRightHandle = nullptr;
|
||||
Move(mTopRightHandle), ps);
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mLeftHandle, ps);
|
||||
mLeftHandle = nullptr;
|
||||
Move(mLeftHandle), ps);
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mRightHandle, ps);
|
||||
mRightHandle = nullptr;
|
||||
Move(mRightHandle), ps);
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mBottomLeftHandle, ps);
|
||||
mBottomLeftHandle = nullptr;
|
||||
Move(mBottomLeftHandle), ps);
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mBottomHandle, ps);
|
||||
mBottomHandle = nullptr;
|
||||
Move(mBottomHandle), ps);
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mBottomRightHandle, ps);
|
||||
mBottomRightHandle = nullptr;
|
||||
Move(mBottomRightHandle), ps);
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mResizingShadow, ps);
|
||||
mResizingShadow = nullptr;
|
||||
Move(mResizingShadow), ps);
|
||||
|
||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||
mResizingInfo, ps);
|
||||
mResizingInfo = nullptr;
|
||||
Move(mResizingInfo), ps);
|
||||
|
||||
if (mActivatedHandle) {
|
||||
mActivatedHandle->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_activated,
|
||||
|
|
|
@ -110,18 +110,12 @@ HTMLEditor::HideInlineTableEditingUI()
|
|||
// are no document observers to notify, but we still want to
|
||||
// UnbindFromTree.
|
||||
|
||||
DeleteRefToAnonymousNode(mAddColumnBeforeButton, ps);
|
||||
mAddColumnBeforeButton = nullptr;
|
||||
DeleteRefToAnonymousNode(mRemoveColumnButton, ps);
|
||||
mRemoveColumnButton = nullptr;
|
||||
DeleteRefToAnonymousNode(mAddColumnAfterButton, ps);
|
||||
mAddColumnAfterButton = nullptr;
|
||||
DeleteRefToAnonymousNode(mAddRowBeforeButton, ps);
|
||||
mAddRowBeforeButton = nullptr;
|
||||
DeleteRefToAnonymousNode(mRemoveRowButton, ps);
|
||||
mRemoveRowButton = nullptr;
|
||||
DeleteRefToAnonymousNode(mAddRowAfterButton, ps);
|
||||
mAddRowAfterButton = nullptr;
|
||||
DeleteRefToAnonymousNode(Move(mAddColumnBeforeButton), ps);
|
||||
DeleteRefToAnonymousNode(Move(mRemoveColumnButton), ps);
|
||||
DeleteRefToAnonymousNode(Move(mAddColumnAfterButton), ps);
|
||||
DeleteRefToAnonymousNode(Move(mAddRowBeforeButton), ps);
|
||||
DeleteRefToAnonymousNode(Move(mRemoveRowButton), ps);
|
||||
DeleteRefToAnonymousNode(Move(mAddRowAfterButton), ps);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ManualNAC_h
|
||||
#define mozilla_ManualNAC_h
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// 16 seems to be the maximum number of manual Native Anonymous Content (NAC)
|
||||
// nodes that editor creates for a given element.
|
||||
//
|
||||
// These need to be manually removed by the machinery that sets the NAC,
|
||||
// otherwise we'll leak.
|
||||
typedef AutoTArray<RefPtr<dom::Element>, 16> ManualNACArray;
|
||||
|
||||
/**
|
||||
* Smart pointer class to own "manual" Native Anonymous Content, and perform
|
||||
* the necessary registration and deregistration on the parent element.
|
||||
*/
|
||||
class ManualNACPtr final
|
||||
{
|
||||
public:
|
||||
ManualNACPtr() {}
|
||||
MOZ_IMPLICIT ManualNACPtr(decltype(nullptr)) {}
|
||||
explicit ManualNACPtr(already_AddRefed<Element> aNewNAC)
|
||||
: mPtr(aNewNAC)
|
||||
{
|
||||
if (!mPtr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the NAC on the element, so that AllChildrenIterator can find it.
|
||||
nsIContent* parentContent = mPtr->GetParent();
|
||||
auto nac = static_cast<ManualNACArray*>(
|
||||
parentContent->GetProperty(nsGkAtoms::manualNACProperty));
|
||||
if (!nac) {
|
||||
nac = new ManualNACArray();
|
||||
parentContent->SetProperty(nsGkAtoms::manualNACProperty, nac,
|
||||
nsINode::DeleteProperty<ManualNACArray>);
|
||||
}
|
||||
nac->AppendElement(mPtr);
|
||||
}
|
||||
|
||||
// We use move semantics, and delete the copy-constructor and operator=.
|
||||
ManualNACPtr(ManualNACPtr&& aOther) : mPtr(aOther.mPtr.forget()) {}
|
||||
ManualNACPtr(ManualNACPtr& aOther) = delete;
|
||||
ManualNACPtr& operator=(ManualNACPtr&& aOther)
|
||||
{
|
||||
mPtr = aOther.mPtr.forget();
|
||||
return *this;
|
||||
}
|
||||
ManualNACPtr& operator=(ManualNACPtr& aOther) = delete;
|
||||
|
||||
~ManualNACPtr() { Reset(); }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
if (!mPtr) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Element> ptr = mPtr.forget();
|
||||
nsIContent* parentContent = ptr->GetParent();
|
||||
if (!parentContent) {
|
||||
NS_WARNING("Potentially leaking manual NAC");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove reference from the parent element.
|
||||
auto nac = static_cast<mozilla::ManualNACArray*>(
|
||||
parentContent->GetProperty(nsGkAtoms::manualNACProperty));
|
||||
// nsIDocument::AdoptNode might remove all properties before destroying
|
||||
// editor. So we have to consider that NAC could be already removed.
|
||||
if (nac) {
|
||||
nac->RemoveElement(ptr);
|
||||
if (nac->IsEmpty()) {
|
||||
parentContent->DeleteProperty(nsGkAtoms::manualNACProperty);
|
||||
}
|
||||
}
|
||||
|
||||
ptr->UnbindFromTree();
|
||||
}
|
||||
|
||||
Element* get() const { return mPtr.get(); }
|
||||
Element* operator->() const { return get(); }
|
||||
operator Element*() const &
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<Element> mPtr;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
inline void
|
||||
ImplCycleCollectionUnlink(mozilla::ManualNACPtr& field)
|
||||
{
|
||||
field.Reset();
|
||||
}
|
||||
|
||||
inline void
|
||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
|
||||
const mozilla::ManualNACPtr& field,
|
||||
const char* name,
|
||||
uint32_t flags = 0)
|
||||
{
|
||||
CycleCollectionNoteChild(callback, field.get(), name, flags);
|
||||
}
|
||||
|
||||
#endif // #ifndef mozilla_ManualNAC_h
|
|
@ -25,6 +25,7 @@ EXPORTS.mozilla += [
|
|||
'EditorUtils.h',
|
||||
'EditTransactionBase.h',
|
||||
'HTMLEditor.h',
|
||||
'ManualNAC.h',
|
||||
'SelectionState.h',
|
||||
'TextEditor.h',
|
||||
'TextEditRules.h',
|
||||
|
|
Загрузка…
Ссылка в новой задаче