зеркало из 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/IMEStateManager.h"
|
||||||
#include "mozilla/InternalMutationEvent.h"
|
#include "mozilla/InternalMutationEvent.h"
|
||||||
#include "mozilla/Likely.h"
|
#include "mozilla/Likely.h"
|
||||||
|
#include "mozilla/ManualNAC.h"
|
||||||
#include "mozilla/MouseEvents.h"
|
#include "mozilla/MouseEvents.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/dom/Selection.h"
|
#include "mozilla/dom/Selection.h"
|
||||||
|
@ -10348,7 +10349,7 @@ nsContentUtils::AppendNativeAnonymousChildren(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get manually created NAC (editor resize handles, etc.).
|
// Get manually created NAC (editor resize handles, etc.).
|
||||||
if (auto nac = static_cast<ManualNAC*>(
|
if (auto nac = static_cast<ManualNACArray*>(
|
||||||
aContent->GetProperty(nsGkAtoms::manualNACProperty))) {
|
aContent->GetProperty(nsGkAtoms::manualNACProperty))) {
|
||||||
aKids.AppendElements(*nac);
|
aKids.AppendElements(*nac);
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,15 +197,6 @@ struct EventNameMapping
|
||||||
typedef bool (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
|
typedef bool (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
|
||||||
void* aArg);
|
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
|
class nsContentUtils
|
||||||
{
|
{
|
||||||
friend class nsAutoScriptBlockerSuppressNodeRemoved;
|
friend class nsAutoScriptBlockerSuppressNodeRemoved;
|
||||||
|
|
|
@ -229,11 +229,11 @@ HTMLEditor::GetElementZIndex(nsIDOMElement* aElement,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Element>
|
ManualNACPtr
|
||||||
HTMLEditor::CreateGrabber(nsINode* aParentNode)
|
HTMLEditor::CreateGrabber(nsINode* aParentNode)
|
||||||
{
|
{
|
||||||
// let's create a grabber through the element factory
|
// let's create a grabber through the element factory
|
||||||
RefPtr<Element> ret =
|
ManualNACPtr ret =
|
||||||
CreateAnonymousElement(nsGkAtoms::span, GetAsDOMNode(aParentNode),
|
CreateAnonymousElement(nsGkAtoms::span, GetAsDOMNode(aParentNode),
|
||||||
NS_LITERAL_STRING("mozGrabber"), false);
|
NS_LITERAL_STRING("mozGrabber"), false);
|
||||||
if (NS_WARN_IF(!ret)) {
|
if (NS_WARN_IF(!ret)) {
|
||||||
|
@ -245,7 +245,7 @@ HTMLEditor::CreateGrabber(nsINode* aParentNode)
|
||||||
evtTarget->AddEventListener(NS_LITERAL_STRING("mousedown"),
|
evtTarget->AddEventListener(NS_LITERAL_STRING("mousedown"),
|
||||||
mEventListener, false);
|
mEventListener, false);
|
||||||
|
|
||||||
return ret.forget();
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
@ -289,10 +289,8 @@ HTMLEditor::HideGrabber()
|
||||||
// are no document observers to notify, but we still want to
|
// are no document observers to notify, but we still want to
|
||||||
// UnbindFromTree.
|
// UnbindFromTree.
|
||||||
|
|
||||||
DeleteRefToAnonymousNode(mGrabber, ps);
|
DeleteRefToAnonymousNode(Move(mGrabber), ps);
|
||||||
mGrabber = nullptr;
|
DeleteRefToAnonymousNode(Move(mPositioningShadow), ps);
|
||||||
DeleteRefToAnonymousNode(mPositioningShadow, ps);
|
|
||||||
mPositioningShadow = nullptr;
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -391,7 +389,7 @@ HTMLEditor::EndMoving()
|
||||||
nsCOMPtr<nsIPresShell> ps = GetPresShell();
|
nsCOMPtr<nsIPresShell> ps = GetPresShell();
|
||||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||||
|
|
||||||
DeleteRefToAnonymousNode(mPositioningShadow, ps);
|
DeleteRefToAnonymousNode(Move(mPositioningShadow), ps);
|
||||||
|
|
||||||
mPositioningShadow = nullptr;
|
mPositioningShadow = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ ElementDeletionObserver::NodeWillBeDestroyed(const nsINode* aNode)
|
||||||
NS_RELEASE_THIS();
|
NS_RELEASE_THIS();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Element>
|
ManualNACPtr
|
||||||
HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
||||||
nsIDOMNode* aParentNode,
|
nsIDOMNode* aParentNode,
|
||||||
const nsAString& aAnonClass,
|
const nsAString& aAnonClass,
|
||||||
|
@ -196,16 +196,16 @@ HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new node through the element factory
|
// Create a new node through the element factory
|
||||||
RefPtr<Element> newContent = CreateHTMLContent(aTag);
|
RefPtr<Element> newContentRaw = CreateHTMLContent(aTag);
|
||||||
if (NS_WARN_IF(!newContent)) {
|
if (NS_WARN_IF(!newContentRaw)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the "hidden" class if needed
|
// add the "hidden" class if needed
|
||||||
if (aIsCreatedHidden) {
|
if (aIsCreatedHidden) {
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
newContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
|
newContentRaw->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
|
||||||
NS_LITERAL_STRING("hidden"), true);
|
NS_LITERAL_STRING("hidden"), true);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -214,8 +214,8 @@ HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
||||||
// add an _moz_anonclass attribute if needed
|
// add an _moz_anonclass attribute if needed
|
||||||
if (!aAnonClass.IsEmpty()) {
|
if (!aAnonClass.IsEmpty()) {
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
newContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_anonclass,
|
newContentRaw->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_anonclass,
|
||||||
aAnonClass, true);
|
aAnonClass, true);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -225,24 +225,16 @@ HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
||||||
nsAutoScriptBlocker scriptBlocker;
|
nsAutoScriptBlocker scriptBlocker;
|
||||||
|
|
||||||
// establish parenthood of the element
|
// establish parenthood of the element
|
||||||
newContent->SetIsNativeAnonymousRoot();
|
newContentRaw->SetIsNativeAnonymousRoot();
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
newContent->BindToTree(doc, parentContent, parentContent, true);
|
newContentRaw->BindToTree(doc, parentContent, parentContent, true);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
newContent->UnbindFromTree();
|
newContentRaw->UnbindFromTree();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the NAC on the element, so that AllChildrenIterator can find it.
|
ManualNACPtr newContent(newContentRaw.forget());
|
||||||
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);
|
|
||||||
|
|
||||||
// Must style the new element, otherwise the PostRecreateFramesFor call
|
// Must style the new element, otherwise the PostRecreateFramesFor call
|
||||||
// below will do nothing.
|
// below will do nothing.
|
||||||
|
@ -268,7 +260,7 @@ HTMLEditor::CreateAnonymousElement(nsIAtom* aTag,
|
||||||
// display the element
|
// display the element
|
||||||
ps->PostRecreateFramesFor(newContent);
|
ps->PostRecreateFramesFor(newContent);
|
||||||
|
|
||||||
return newContent.forget();
|
return Move(newContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes event listener and calls DeleteRefToAnonymousNode.
|
// Removes event listener and calls DeleteRefToAnonymousNode.
|
||||||
|
@ -276,19 +268,19 @@ void
|
||||||
HTMLEditor::RemoveListenerAndDeleteRef(const nsAString& aEvent,
|
HTMLEditor::RemoveListenerAndDeleteRef(const nsAString& aEvent,
|
||||||
nsIDOMEventListener* aListener,
|
nsIDOMEventListener* aListener,
|
||||||
bool aUseCapture,
|
bool aUseCapture,
|
||||||
Element* aElement,
|
ManualNACPtr aElement,
|
||||||
nsIPresShell* aShell)
|
nsIPresShell* aShell)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement));
|
nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement));
|
||||||
if (evtTarget) {
|
if (evtTarget) {
|
||||||
evtTarget->RemoveEventListener(aEvent, aListener, aUseCapture);
|
evtTarget->RemoveEventListener(aEvent, aListener, aUseCapture);
|
||||||
}
|
}
|
||||||
DeleteRefToAnonymousNode(aElement, aShell);
|
DeleteRefToAnonymousNode(Move(aElement), aShell);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes all references to an anonymous element
|
// Deletes all references to an anonymous element
|
||||||
void
|
void
|
||||||
HTMLEditor::DeleteRefToAnonymousNode(nsIContent* aContent,
|
HTMLEditor::DeleteRefToAnonymousNode(ManualNACPtr aContent,
|
||||||
nsIPresShell* aShell)
|
nsIPresShell* aShell)
|
||||||
{
|
{
|
||||||
// call ContentRemoved() for the anonymous content
|
// call ContentRemoved() for the anonymous content
|
||||||
|
@ -332,19 +324,7 @@ HTMLEditor::DeleteRefToAnonymousNode(nsIContent* aContent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove reference from the parent element.
|
// The ManualNACPtr destructor will invoke UnbindFromTree.
|
||||||
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 following method is mostly called by a selection listener. When a
|
// The following method is mostly called by a selection listener. When a
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/CSSEditUtils.h"
|
#include "mozilla/CSSEditUtils.h"
|
||||||
|
#include "mozilla/ManualNAC.h"
|
||||||
#include "mozilla/StyleSheet.h"
|
#include "mozilla/StyleSheet.h"
|
||||||
#include "mozilla/TextEditor.h"
|
#include "mozilla/TextEditor.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
|
@ -857,9 +858,9 @@ protected:
|
||||||
void RemoveListenerAndDeleteRef(const nsAString& aEvent,
|
void RemoveListenerAndDeleteRef(const nsAString& aEvent,
|
||||||
nsIDOMEventListener* aListener,
|
nsIDOMEventListener* aListener,
|
||||||
bool aUseCapture,
|
bool aUseCapture,
|
||||||
Element* aElement,
|
ManualNACPtr aElement,
|
||||||
nsIPresShell* aShell);
|
nsIPresShell* aShell);
|
||||||
void DeleteRefToAnonymousNode(nsIContent* aContent,
|
void DeleteRefToAnonymousNode(ManualNACPtr aContent,
|
||||||
nsIPresShell* aShell);
|
nsIPresShell* aShell);
|
||||||
|
|
||||||
nsresult ShowResizersInner(nsIDOMElement *aResizedElement);
|
nsresult ShowResizersInner(nsIDOMElement *aResizedElement);
|
||||||
|
@ -900,19 +901,19 @@ protected:
|
||||||
bool mIsInlineTableEditingEnabled;
|
bool mIsInlineTableEditingEnabled;
|
||||||
|
|
||||||
// resizing
|
// resizing
|
||||||
nsCOMPtr<Element> mTopLeftHandle;
|
ManualNACPtr mTopLeftHandle;
|
||||||
nsCOMPtr<Element> mTopHandle;
|
ManualNACPtr mTopHandle;
|
||||||
nsCOMPtr<Element> mTopRightHandle;
|
ManualNACPtr mTopRightHandle;
|
||||||
nsCOMPtr<Element> mLeftHandle;
|
ManualNACPtr mLeftHandle;
|
||||||
nsCOMPtr<Element> mRightHandle;
|
ManualNACPtr mRightHandle;
|
||||||
nsCOMPtr<Element> mBottomLeftHandle;
|
ManualNACPtr mBottomLeftHandle;
|
||||||
nsCOMPtr<Element> mBottomHandle;
|
ManualNACPtr mBottomHandle;
|
||||||
nsCOMPtr<Element> mBottomRightHandle;
|
ManualNACPtr mBottomRightHandle;
|
||||||
|
|
||||||
nsCOMPtr<Element> mActivatedHandle;
|
nsCOMPtr<Element> mActivatedHandle;
|
||||||
|
|
||||||
nsCOMPtr<Element> mResizingShadow;
|
ManualNACPtr mResizingShadow;
|
||||||
nsCOMPtr<Element> mResizingInfo;
|
ManualNACPtr mResizingInfo;
|
||||||
|
|
||||||
nsCOMPtr<Element> mResizedObject;
|
nsCOMPtr<Element> mResizedObject;
|
||||||
|
|
||||||
|
@ -943,18 +944,17 @@ protected:
|
||||||
|
|
||||||
nsresult SetAllResizersPosition();
|
nsresult SetAllResizersPosition();
|
||||||
|
|
||||||
already_AddRefed<Element> CreateResizer(int16_t aLocation,
|
ManualNACPtr CreateResizer(int16_t aLocation, nsIDOMNode* aParentNode);
|
||||||
nsIDOMNode* aParentNode);
|
|
||||||
void SetAnonymousElementPosition(int32_t aX, int32_t aY,
|
void SetAnonymousElementPosition(int32_t aX, int32_t aY,
|
||||||
Element* aResizer);
|
Element* aResizer);
|
||||||
|
|
||||||
already_AddRefed<Element> CreateShadow(nsIDOMNode* aParentNode,
|
ManualNACPtr CreateShadow(nsIDOMNode* aParentNode,
|
||||||
nsIDOMElement* aOriginalObject);
|
nsIDOMElement* aOriginalObject);
|
||||||
nsresult SetShadowPosition(Element* aShadow, Element* aOriginalObject,
|
nsresult SetShadowPosition(Element* aShadow, Element* aOriginalObject,
|
||||||
int32_t aOriginalObjectX,
|
int32_t aOriginalObjectX,
|
||||||
int32_t aOriginalObjectY);
|
int32_t aOriginalObjectY);
|
||||||
|
|
||||||
already_AddRefed<Element> CreateResizingInfo(nsIDOMNode* aParentNode);
|
ManualNACPtr CreateResizingInfo(nsIDOMNode* aParentNode);
|
||||||
nsresult SetResizingInfoPosition(int32_t aX, int32_t aY,
|
nsresult SetResizingInfoPosition(int32_t aX, int32_t aY,
|
||||||
int32_t aW, int32_t aH);
|
int32_t aW, int32_t aH);
|
||||||
|
|
||||||
|
@ -983,12 +983,12 @@ protected:
|
||||||
int32_t mPositionedObjectBorderTop;
|
int32_t mPositionedObjectBorderTop;
|
||||||
|
|
||||||
nsCOMPtr<Element> mAbsolutelyPositionedObject;
|
nsCOMPtr<Element> mAbsolutelyPositionedObject;
|
||||||
nsCOMPtr<Element> mGrabber;
|
ManualNACPtr mGrabber;
|
||||||
nsCOMPtr<Element> mPositioningShadow;
|
ManualNACPtr mPositioningShadow;
|
||||||
|
|
||||||
int32_t mGridSize;
|
int32_t mGridSize;
|
||||||
|
|
||||||
already_AddRefed<Element> CreateGrabber(nsINode* aParentNode);
|
ManualNACPtr CreateGrabber(nsINode* aParentNode);
|
||||||
nsresult StartMoving(nsIDOMElement* aHandle);
|
nsresult StartMoving(nsIDOMElement* aHandle);
|
||||||
nsresult SetFinalPosition(int32_t aX, int32_t aY);
|
nsresult SetFinalPosition(int32_t aX, int32_t aY);
|
||||||
void AddPositioningOffset(int32_t& aX, int32_t& aY);
|
void AddPositioningOffset(int32_t& aX, int32_t& aY);
|
||||||
|
@ -1001,13 +1001,13 @@ protected:
|
||||||
// inline table editing
|
// inline table editing
|
||||||
nsCOMPtr<nsIDOMElement> mInlineEditedCell;
|
nsCOMPtr<nsIDOMElement> mInlineEditedCell;
|
||||||
|
|
||||||
RefPtr<Element> mAddColumnBeforeButton;
|
ManualNACPtr mAddColumnBeforeButton;
|
||||||
RefPtr<Element> mRemoveColumnButton;
|
ManualNACPtr mRemoveColumnButton;
|
||||||
RefPtr<Element> mAddColumnAfterButton;
|
ManualNACPtr mAddColumnAfterButton;
|
||||||
|
|
||||||
RefPtr<Element> mAddRowBeforeButton;
|
ManualNACPtr mAddRowBeforeButton;
|
||||||
RefPtr<Element> mRemoveRowButton;
|
ManualNACPtr mRemoveRowButton;
|
||||||
RefPtr<Element> mAddRowAfterButton;
|
ManualNACPtr mAddRowAfterButton;
|
||||||
|
|
||||||
void AddMouseClickListener(Element* aElement);
|
void AddMouseClickListener(Element* aElement);
|
||||||
void RemoveMouseClickListener(Element* aElement);
|
void RemoveMouseClickListener(Element* aElement);
|
||||||
|
@ -1053,11 +1053,10 @@ private:
|
||||||
* is to be added to the created anonymous
|
* is to be added to the created anonymous
|
||||||
* element
|
* element
|
||||||
*/
|
*/
|
||||||
already_AddRefed<Element> CreateAnonymousElement(
|
ManualNACPtr CreateAnonymousElement(nsIAtom* aTag,
|
||||||
nsIAtom* aTag,
|
nsIDOMNode* aParentNode,
|
||||||
nsIDOMNode* aParentNode,
|
const nsAString& aAnonClass,
|
||||||
const nsAString& aAnonClass,
|
bool aIsCreatedHidden);
|
||||||
bool aIsCreatedHidden);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -131,11 +131,11 @@ ResizerMouseMotionListener::HandleEvent(nsIDOMEvent* aMouseEvent)
|
||||||
* mozilla::HTMLEditor
|
* mozilla::HTMLEditor
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
already_AddRefed<Element>
|
ManualNACPtr
|
||||||
HTMLEditor::CreateResizer(int16_t aLocation,
|
HTMLEditor::CreateResizer(int16_t aLocation,
|
||||||
nsIDOMNode* aParentNode)
|
nsIDOMNode* aParentNode)
|
||||||
{
|
{
|
||||||
RefPtr<Element> ret =
|
ManualNACPtr ret =
|
||||||
CreateAnonymousElement(nsGkAtoms::span,
|
CreateAnonymousElement(nsGkAtoms::span,
|
||||||
aParentNode,
|
aParentNode,
|
||||||
NS_LITERAL_STRING("mozResizer"),
|
NS_LITERAL_STRING("mozResizer"),
|
||||||
|
@ -182,10 +182,10 @@ HTMLEditor::CreateResizer(int16_t aLocation,
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
ret->SetAttr(kNameSpaceID_None, nsGkAtoms::anonlocation, locationStr, true);
|
ret->SetAttr(kNameSpaceID_None, nsGkAtoms::anonlocation, locationStr, true);
|
||||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
return ret.forget();
|
return Move(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Element>
|
ManualNACPtr
|
||||||
HTMLEditor::CreateShadow(nsIDOMNode* aParentNode,
|
HTMLEditor::CreateShadow(nsIDOMNode* aParentNode,
|
||||||
nsIDOMElement* aOriginalObject)
|
nsIDOMElement* aOriginalObject)
|
||||||
{
|
{
|
||||||
|
@ -196,20 +196,17 @@ HTMLEditor::CreateShadow(nsIDOMNode* aParentNode,
|
||||||
} else {
|
} else {
|
||||||
name = nsGkAtoms::span;
|
name = nsGkAtoms::span;
|
||||||
}
|
}
|
||||||
RefPtr<Element> ret =
|
|
||||||
CreateAnonymousElement(name, aParentNode,
|
return CreateAnonymousElement(name, aParentNode,
|
||||||
NS_LITERAL_STRING("mozResizingShadow"), true);
|
NS_LITERAL_STRING("mozResizingShadow"), true);
|
||||||
return ret.forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Element>
|
ManualNACPtr
|
||||||
HTMLEditor::CreateResizingInfo(nsIDOMNode* aParentNode)
|
HTMLEditor::CreateResizingInfo(nsIDOMNode* aParentNode)
|
||||||
{
|
{
|
||||||
// let's create an info box through the element factory
|
// let's create an info box through the element factory
|
||||||
RefPtr<Element> ret =
|
return CreateAnonymousElement(nsGkAtoms::span, aParentNode,
|
||||||
CreateAnonymousElement(nsGkAtoms::span, aParentNode,
|
NS_LITERAL_STRING("mozResizingInfo"), true);
|
||||||
NS_LITERAL_STRING("mozResizingInfo"), true);
|
|
||||||
return ret.forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -386,44 +383,34 @@ HTMLEditor::HideResizers()
|
||||||
NS_NAMED_LITERAL_STRING(mousedown, "mousedown");
|
NS_NAMED_LITERAL_STRING(mousedown, "mousedown");
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mTopLeftHandle, ps);
|
Move(mTopLeftHandle), ps);
|
||||||
mTopLeftHandle = nullptr;
|
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mTopHandle, ps);
|
Move(mTopHandle), ps);
|
||||||
mTopHandle = nullptr;
|
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mTopRightHandle, ps);
|
Move(mTopRightHandle), ps);
|
||||||
mTopRightHandle = nullptr;
|
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mLeftHandle, ps);
|
Move(mLeftHandle), ps);
|
||||||
mLeftHandle = nullptr;
|
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mRightHandle, ps);
|
Move(mRightHandle), ps);
|
||||||
mRightHandle = nullptr;
|
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mBottomLeftHandle, ps);
|
Move(mBottomLeftHandle), ps);
|
||||||
mBottomLeftHandle = nullptr;
|
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mBottomHandle, ps);
|
Move(mBottomHandle), ps);
|
||||||
mBottomHandle = nullptr;
|
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mBottomRightHandle, ps);
|
Move(mBottomRightHandle), ps);
|
||||||
mBottomRightHandle = nullptr;
|
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mResizingShadow, ps);
|
Move(mResizingShadow), ps);
|
||||||
mResizingShadow = nullptr;
|
|
||||||
|
|
||||||
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
|
||||||
mResizingInfo, ps);
|
Move(mResizingInfo), ps);
|
||||||
mResizingInfo = nullptr;
|
|
||||||
|
|
||||||
if (mActivatedHandle) {
|
if (mActivatedHandle) {
|
||||||
mActivatedHandle->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_activated,
|
mActivatedHandle->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_activated,
|
||||||
|
|
|
@ -110,18 +110,12 @@ HTMLEditor::HideInlineTableEditingUI()
|
||||||
// are no document observers to notify, but we still want to
|
// are no document observers to notify, but we still want to
|
||||||
// UnbindFromTree.
|
// UnbindFromTree.
|
||||||
|
|
||||||
DeleteRefToAnonymousNode(mAddColumnBeforeButton, ps);
|
DeleteRefToAnonymousNode(Move(mAddColumnBeforeButton), ps);
|
||||||
mAddColumnBeforeButton = nullptr;
|
DeleteRefToAnonymousNode(Move(mRemoveColumnButton), ps);
|
||||||
DeleteRefToAnonymousNode(mRemoveColumnButton, ps);
|
DeleteRefToAnonymousNode(Move(mAddColumnAfterButton), ps);
|
||||||
mRemoveColumnButton = nullptr;
|
DeleteRefToAnonymousNode(Move(mAddRowBeforeButton), ps);
|
||||||
DeleteRefToAnonymousNode(mAddColumnAfterButton, ps);
|
DeleteRefToAnonymousNode(Move(mRemoveRowButton), ps);
|
||||||
mAddColumnAfterButton = nullptr;
|
DeleteRefToAnonymousNode(Move(mAddRowAfterButton), ps);
|
||||||
DeleteRefToAnonymousNode(mAddRowBeforeButton, ps);
|
|
||||||
mAddRowBeforeButton = nullptr;
|
|
||||||
DeleteRefToAnonymousNode(mRemoveRowButton, ps);
|
|
||||||
mRemoveRowButton = nullptr;
|
|
||||||
DeleteRefToAnonymousNode(mAddRowAfterButton, ps);
|
|
||||||
mAddRowAfterButton = nullptr;
|
|
||||||
|
|
||||||
return NS_OK;
|
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',
|
'EditorUtils.h',
|
||||||
'EditTransactionBase.h',
|
'EditTransactionBase.h',
|
||||||
'HTMLEditor.h',
|
'HTMLEditor.h',
|
||||||
|
'ManualNAC.h',
|
||||||
'SelectionState.h',
|
'SelectionState.h',
|
||||||
'TextEditor.h',
|
'TextEditor.h',
|
||||||
'TextEditRules.h',
|
'TextEditRules.h',
|
||||||
|
|
Загрузка…
Ссылка в новой задаче