diff options
author | Matt A. Tobin <email@mattatobin.com> | 2020-04-17 05:47:12 -0400 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2020-04-17 05:47:12 -0400 |
commit | 32e8155127126c187ce32f7368742057bcaf69da (patch) | |
tree | 61fd4472558f959f7695b3940e7ed5ea7628e5ed | |
parent | 2e2190a5044943bde31679996afdc3558d22231b (diff) | |
download | UXP-32e8155127126c187ce32f7368742057bcaf69da.tar UXP-32e8155127126c187ce32f7368742057bcaf69da.tar.gz UXP-32e8155127126c187ce32f7368742057bcaf69da.tar.lz UXP-32e8155127126c187ce32f7368742057bcaf69da.tar.xz UXP-32e8155127126c187ce32f7368742057bcaf69da.zip |
Bug 1372829 - Part 2: mozilla::EditorBase should cache raw pointer of nsISelectionController and nsIDocument with nsWeakPtr
Tag #1375
-rw-r--r-- | dom/base/FragmentOrElement.h | 1 | ||||
-rw-r--r-- | editor/libeditor/EditorBase.cpp | 214 | ||||
-rw-r--r-- | editor/libeditor/EditorBase.h | 68 | ||||
-rw-r--r-- | editor/libeditor/HTMLEditor.cpp | 160 | ||||
-rw-r--r-- | editor/libeditor/HTMLTableEditor.cpp | 1 | ||||
-rw-r--r-- | editor/libeditor/TextEditor.cpp | 2 | ||||
-rw-r--r-- | xpcom/base/nsIWeakReference.idl | 5 | ||||
-rw-r--r-- | xpcom/glue/nsWeakReference.cpp | 1 |
8 files changed, 288 insertions, 164 deletions
diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h index 4edd88908..07403cf39 100644 --- a/dom/base/FragmentOrElement.h +++ b/dom/base/FragmentOrElement.h @@ -62,6 +62,7 @@ public: // nsIWeakReference NS_DECL_NSIWEAKREFERENCE virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override; + virtual bool IsAlive() const override { return mNode != nullptr; } void NoticeNodeDestruction() { diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp index f068e9179..5df4ff2c4 100644 --- a/editor/libeditor/EditorBase.cpp +++ b/editor/libeditor/EditorBase.cpp @@ -37,6 +37,7 @@ #include "mozilla/TextComposition.h" // for TextComposition #include "mozilla/TextEvents.h" #include "mozilla/dom/Element.h" // for Element, nsINode::AsElement +#include "mozilla/dom/HTMLBodyElement.h" #include "mozilla/dom/Text.h" #include "mozilla/dom/Event.h" #include "mozilla/mozalloc.h" // for operator new, etc. @@ -71,7 +72,6 @@ #include "nsIDOMNode.h" // for nsIDOMNode, etc. #include "nsIDOMNodeList.h" // for nsIDOMNodeList #include "nsIDOMText.h" // for nsIDOMText -#include "nsIDocument.h" // for nsIDocument #include "nsIDocumentStateListener.h" // for nsIDocumentStateListener #include "nsIEditActionListener.h" // for nsIEditActionListener #include "nsIEditorObserver.h" // for nsIEditorObserver @@ -151,7 +151,8 @@ EditorBase::EditorBase() EditorBase::~EditorBase() { - NS_ASSERTION(!mDocWeak || mDidPreDestroy, "Why PreDestroy hasn't been called?"); + MOZ_ASSERT(!IsInitialized() || mDidPreDestroy, + "Why PreDestroy hasn't been called?"); if (mComposition) { mComposition->OnEditorDestroyed(); @@ -220,20 +221,21 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(EditorBase) NS_IMETHODIMP -EditorBase::Init(nsIDOMDocument* aDoc, +EditorBase::Init(nsIDOMDocument* aDOMDocument, nsIContent* aRoot, - nsISelectionController* aSelCon, + nsISelectionController* aSelectionController, uint32_t aFlags, const nsAString& aValue) { MOZ_ASSERT(mAction == EditAction::none, "Initializing during an edit action is an error"); - MOZ_ASSERT(aDoc); - if (!aDoc) + MOZ_ASSERT(aDOMDocument); + if (!aDOMDocument) { return NS_ERROR_NULL_POINTER; + } // First only set flags, but other stuff shouldn't be initialized now. - // Don't move this call after initializing mDocWeak. + // Don't move this call after initializing mDocumentWeak. // SetFlags() can check whether it's called during initialization or not by // them. Note that SetFlags() will be called by PostCreate(). #ifdef DEBUG @@ -242,19 +244,21 @@ EditorBase::Init(nsIDOMDocument* aDoc, SetFlags(aFlags); NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed"); - mDocWeak = do_GetWeakReference(aDoc); // weak reference to doc + nsCOMPtr<nsIDocument> document = do_QueryInterface(aDOMDocument); + mDocumentWeak = document.get(); // HTML editors currently don't have their own selection controller, // so they'll pass null as aSelCon, and we'll get the selection controller // off of the presshell. - nsCOMPtr<nsISelectionController> selCon; - if (aSelCon) { - mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller - selCon = aSelCon; + nsCOMPtr<nsISelectionController> selectionController; + if (aSelectionController) { + mSelectionControllerWeak = aSelectionController; + selectionController = aSelectionController; } else { nsCOMPtr<nsIPresShell> presShell = GetPresShell(); - selCon = do_QueryInterface(presShell); + selectionController = do_QueryInterface(presShell); } - NS_ASSERTION(selCon, "Selection controller should be available at this point"); + MOZ_ASSERT(selectionController, + "Selection controller should be available at this point"); //set up root element if we are passed one. if (aRoot) @@ -271,13 +275,14 @@ EditorBase::Init(nsIDOMDocument* aDoc, mIMETextNode = nullptr; } - /* Show the caret */ - selCon->SetCaretReadOnly(false); - selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); - - selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);//we want to see all the selection reflected to user + // Show the caret. + selectionController->SetCaretReadOnly(false); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_ON); + // Show all the selection reflected to user. + selectionController->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL); - NS_POSTCONDITION(mDocWeak, "bad state"); + MOZ_ASSERT(IsInitialized()); // Make sure that the editor will be destroyed properly mDidPreDestroy = false; @@ -356,8 +361,9 @@ EditorBase::CreateEventListeners() nsresult EditorBase::InstallEventListeners() { - NS_ENSURE_TRUE(mDocWeak && mEventListener, - NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized()) || NS_WARN_IF(!mEventListener)) { + return NS_ERROR_NOT_INITIALIZED; + } // Initialize the event target. nsCOMPtr<nsIContent> rootContent = GetRoot(); @@ -378,7 +384,7 @@ EditorBase::InstallEventListeners() void EditorBase::RemoveEventListeners() { - if (!mDocWeak || !mEventListener) { + if (!IsInitialized() || !mEventListener) { return; } reinterpret_cast<EditorEventListener*>(mEventListener.get())->Disconnect(); @@ -501,7 +507,7 @@ EditorBase::SetFlags(uint32_t aFlags) bool spellcheckerWasEnabled = CanEnableSpellCheck(); mFlags = aFlags; - if (!mDocWeak) { + if (!IsInitialized()) { // If we're initializing, we shouldn't do anything now. // SetFlags() will be called by PostCreate(), // we should synchronize some stuff for the flags at that time. @@ -567,17 +573,15 @@ EditorBase::GetIsDocumentEditable(bool* aIsDocumentEditable) already_AddRefed<nsIDocument> EditorBase::GetDocument() { - NS_PRECONDITION(mDocWeak, "bad state, mDocWeak weak pointer not initialized"); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - return doc.forget(); + nsCOMPtr<nsIDocument> document = mDocumentWeak.get(); + return document.forget(); } already_AddRefed<nsIDOMDocument> EditorBase::GetDOMDocument() { - NS_PRECONDITION(mDocWeak, "bad state, mDocWeak weak pointer not initialized"); - nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak); - return doc.forget(); + nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(mDocumentWeak); + return domDocument.forget(); } NS_IMETHODIMP @@ -590,11 +594,12 @@ EditorBase::GetDocument(nsIDOMDocument** aDoc) already_AddRefed<nsIPresShell> EditorBase::GetPresShell() { - NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak"); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, nullptr); - nsCOMPtr<nsIPresShell> ps = doc->GetShell(); - return ps.forget(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return nullptr; + } + nsCOMPtr<nsIPresShell> presShell = document->GetShell(); + return presShell.forget(); } already_AddRefed<nsIWidget> @@ -640,14 +645,14 @@ EditorBase::GetSelectionController(nsISelectionController** aSel) already_AddRefed<nsISelectionController> EditorBase::GetSelectionController() { - nsCOMPtr<nsISelectionController> selCon; - if (mSelConWeak) { - selCon = do_QueryReferent(mSelConWeak); + nsCOMPtr<nsISelectionController> selectionController; + if (mSelectionControllerWeak) { + selectionController = mSelectionControllerWeak.get(); } else { nsCOMPtr<nsIPresShell> presShell = GetPresShell(); - selCon = do_QueryInterface(presShell); + selectionController = do_QueryInterface(presShell); } - return selCon.forget(); + return selectionController.forget(); } NS_IMETHODIMP @@ -1065,7 +1070,8 @@ EditorBase::GetDocumentIsEmpty(bool* aDocumentIsEmpty) NS_IMETHODIMP EditorBase::SelectAll() { - if (!mDocWeak) { + // XXX Why doesn't this check if the document is alive? + if (!IsInitialized()) { return NS_ERROR_NOT_INITIALIZED; } ForceCompositionEnd(); @@ -1078,7 +1084,8 @@ EditorBase::SelectAll() NS_IMETHODIMP EditorBase::BeginningOfDocument() { - if (!mDocWeak) { + // XXX Why doesn't this check if the document is alive? + if (!IsInitialized()) { return NS_ERROR_NOT_INITIALIZED; } @@ -1115,7 +1122,10 @@ EditorBase::BeginningOfDocument() NS_IMETHODIMP EditorBase::EndOfDocument() { - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); + // XXX Why doesn't this check if the document is alive? + if (NS_WARN_IF(!IsInitialized())) { + return NS_ERROR_NOT_INITIALIZED; + } // get selection RefPtr<Selection> selection = GetSelection(); @@ -1150,20 +1160,22 @@ EditorBase::GetDocumentModified(bool* outDocModified) NS_IMETHODIMP EditorBase::GetDocumentCharacterSet(nsACString& characterSet) { - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); - - characterSet = doc->GetDocumentCharacterSet(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_UNEXPECTED; + } + characterSet = document->GetDocumentCharacterSet(); return NS_OK; } NS_IMETHODIMP EditorBase::SetDocumentCharacterSet(const nsACString& characterSet) { - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); - - doc->SetDocumentCharacterSet(characterSet); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_UNEXPECTED; + } + document->SetDocumentCharacterSet(characterSet); return NS_OK; } @@ -2004,12 +2016,17 @@ NS_IMETHODIMP EditorBase::DebugDumpContent() { #ifdef DEBUG - nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); - - nsCOMPtr<nsIDOMHTMLElement>bodyElem; - doc->GetBody(getter_AddRefs(bodyElem)); - nsCOMPtr<nsIContent> content = do_QueryInterface(bodyElem); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_NOT_INITIALIZED; + } + nsCOMPtr<nsIDOMHTMLDocument> domHTMLDocument = do_QueryInterface(document); + if (NS_WARN_IF(!domHTMLDocument)) { + return NS_ERROR_NOT_INITIALIZED; + } + nsCOMPtr<nsIDOMHTMLElement> bodyElement; + domHTMLDocument->GetBody(getter_AddRefs(bodyElement)); + nsCOMPtr<nsIContent> content = do_QueryInterface(bodyElement); if (content) { content->List(); } @@ -2323,18 +2340,20 @@ EditorBase::CloneAttributes(Element* aDest, NS_IMETHODIMP EditorBase::ScrollSelectionIntoView(bool aScrollToAnchor) { - nsCOMPtr<nsISelectionController> selCon; - if (NS_SUCCEEDED(GetSelectionController(getter_AddRefs(selCon))) && selCon) { - int16_t region = nsISelectionController::SELECTION_FOCUS_REGION; - - if (aScrollToAnchor) { - region = nsISelectionController::SELECTION_ANCHOR_REGION; - } - - selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, - region, nsISelectionController::SCROLL_OVERFLOW_HIDDEN); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (!selectionController) { + return NS_OK; } + int16_t region = nsISelectionController::SELECTION_FOCUS_REGION; + if (aScrollToAnchor) { + region = nsISelectionController::SELECTION_ANCHOR_REGION; + } + selectionController->ScrollSelectionIntoView( + nsISelectionController::SELECTION_NORMAL, + region, + nsISelectionController::SCROLL_OVERFLOW_HIDDEN); return NS_OK; } @@ -4784,22 +4803,27 @@ EditorBase::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget) nsCOMPtr<nsIPresShell> presShell = GetPresShell(); NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED); - nsCOMPtr<nsISelectionController> selCon; - nsresult rv = GetSelectionController(getter_AddRefs(selCon)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (NS_WARN_IF(!selectionController)) { + return NS_ERROR_FAILURE; + } // Init the caret RefPtr<nsCaret> caret = presShell->GetCaret(); NS_ENSURE_TRUE(caret, NS_ERROR_UNEXPECTED); caret->SetIgnoreUserModify(false); caret->SetSelection(selection); - selCon->SetCaretReadOnly(IsReadonly()); - selCon->SetCaretEnabled(true); + selectionController->SetCaretReadOnly(IsReadonly()); + selectionController->SetCaretEnabled(true); // Init selection - selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); - selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL); - selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_ON); + selectionController->SetSelectionFlags( + nsISelectionDisplay::DISPLAY_ALL); + selectionController->RepaintSelection( + nsISelectionController::SELECTION_NORMAL); // If the computed selection root isn't root content, we should set it // as selection ancestor limit. However, if that is root element, it means // there is not limitation of the selection, then, we must set nullptr. @@ -4867,9 +4891,11 @@ private: NS_IMETHODIMP EditorBase::FinalizeSelection() { - nsCOMPtr<nsISelectionController> selCon; - nsresult rv = GetSelectionController(getter_AddRefs(selCon)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (NS_WARN_IF(!selectionController)) { + return NS_ERROR_FAILURE; + } RefPtr<Selection> selection = GetSelection(); NS_ENSURE_STATE(selection); @@ -4879,7 +4905,7 @@ EditorBase::FinalizeSelection() nsCOMPtr<nsIPresShell> presShell = GetPresShell(); NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED); - selCon->SetCaretEnabled(false); + selectionController->SetCaretEnabled(false); nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, NS_ERROR_NOT_INITIALIZED); @@ -4894,29 +4920,33 @@ EditorBase::FinalizeSelection() ErrorResult ret; if (!doc || !doc->HasFocus(ret)) { // If the document already lost focus, mark the selection as disabled. - selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_DISABLED); } else { // Otherwise, mark selection as normal because outside of a // contenteditable element should be selected with normal selection // color after here. - selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_ON); } } else if (IsFormWidget() || IsPasswordEditor() || IsReadonly() || IsDisabled() || IsInputFiltered()) { // In <input> or <textarea>, the independent selection should be hidden // while this editor doesn't have focus. - selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_HIDDEN); } else { // Otherwise, although we're not sure how this case happens, the // independent selection should be marked as disabled. - selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED); + selectionController->SetDisplaySelection( + nsISelectionController::SELECTION_DISABLED); } // FinalizeSelection might be called from ContentRemoved even if selection // isn't updated. So we need to call RepaintSelection after updated it. nsContentUtils::AddScriptRunner( - new RepaintSelectionRunner(selCon)); + new RepaintSelectionRunner(selectionController)); return NS_OK; } @@ -5127,8 +5157,11 @@ EditorBase::IsActiveInDOMWindow() nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, false); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - nsPIDOMWindowOuter* ourWindow = doc->GetWindow(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return false; + } + nsPIDOMWindowOuter* ourWindow = document->GetWindow(); nsCOMPtr<nsPIDOMWindowOuter> win; nsIContent* content = nsFocusManager::GetFocusedDescendant(ourWindow, false, @@ -5236,10 +5269,11 @@ EditorBase::GetIMESelectionStartOffsetIn(nsINode* aTextNode) { MOZ_ASSERT(aTextNode, "aTextNode must not be nullptr"); - nsCOMPtr<nsISelectionController> selectionController; - nsresult rv = GetSelectionController(getter_AddRefs(selectionController)); - NS_ENSURE_SUCCESS(rv, -1); - NS_ENSURE_TRUE(selectionController, -1); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (NS_WARN_IF(!selectionController)) { + return -1; + } int32_t minOffset = INT32_MAX; static const SelectionType kIMESelectionTypes[] = { diff --git a/editor/libeditor/EditorBase.h b/editor/libeditor/EditorBase.h index 7ea0f4dab..618da12a8 100644 --- a/editor/libeditor/EditorBase.h +++ b/editor/libeditor/EditorBase.h @@ -17,6 +17,7 @@ #include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr #include "nsCycleCollectionParticipant.h" #include "nsGkAtoms.h" +#include "nsIDocument.h" // for nsIDocument #include "nsIEditor.h" // for nsIEditor::EDirection, etc. #include "nsIEditorIMESupport.h" // for NS_DECL_NSIEDITORIMESUPPORT, etc. #include "nsIObserver.h" // for NS_DECL_NSIOBSERVER, etc. @@ -32,7 +33,6 @@ class nsIAtom; class nsIContent; -class nsIDOMDocument; class nsIDOMEvent; class nsIDOMEventListener; class nsIDOMEventTarget; @@ -135,6 +135,57 @@ namespace widget { struct IMEState; } // namespace widget +/** + * CachedWeakPtr stores a pointer to a class which inherits nsIWeakReference. + * If the instance of the class has already been destroyed, this returns + * nullptr. Otherwise, returns cached pointer. + */ +template<class T> +class CachedWeakPtr final +{ +public: + CachedWeakPtr<T>() + : mCache(nullptr) + { + } + + CachedWeakPtr<T>& operator=(T* aObject) + { + mWeakPtr = do_GetWeakReference(aObject); + mCache = aObject; + return *this; + } + CachedWeakPtr<T>& operator=(const nsCOMPtr<T>& aOther) + { + mWeakPtr = do_GetWeakReference(aOther); + mCache = aOther; + return *this; + } + CachedWeakPtr<T>& operator=(already_AddRefed<T>& aOther) + { + nsCOMPtr<T> other = aOther; + mWeakPtr = do_GetWeakReference(other); + mCache = other; + return *this; + } + + bool IsAlive() const { return mWeakPtr && mWeakPtr->IsAlive(); } + + explicit operator bool() const { return mWeakPtr; } + operator T*() const { return get(); } + T* get() const + { + if (mCache && !mWeakPtr->IsAlive()) { + const_cast<CachedWeakPtr<T>*>(this)->mCache = nullptr; + } + return mCache; + } + +private: + nsWeakPtr mWeakPtr; + T* MOZ_NON_OWNING_REF mCache; +}; + #define kMOZEditorBogusNodeAttrAtom nsGkAtoms::mozeditorbogusnode #define kMOZEditorBogusNodeValue NS_LITERAL_STRING("TRUE") @@ -178,6 +229,7 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor) + bool IsInitialized() const { return !!mDocumentWeak; } already_AddRefed<nsIDOMDocument> GetDOMDocument(); already_AddRefed<nsIDocument> GetDocument(); already_AddRefed<nsIPresShell> GetPresShell(); @@ -848,7 +900,7 @@ public: bool HasIndependentSelection() const { - return !!mSelConWeak; + return !!mSelectionControllerWeak; } /** @@ -954,6 +1006,14 @@ public: } } +private: + // Weak reference to the nsISelectionController. + // Use GetSelectionController() to retrieve actual pointer. + CachedWeakPtr<nsISelectionController> mSelectionControllerWeak; + // Weak reference to the nsIDocument. + // Use GetDocument() to retrieve actual pointer. + CachedWeakPtr<nsIDocument> mDocumentWeak; + protected: enum Tristate { @@ -975,12 +1035,8 @@ protected: // The form field as an event receiver. nsCOMPtr<dom::EventTarget> mEventTarget; nsCOMPtr<nsIDOMEventListener> mEventListener; - // Weak reference to the nsISelectionController. - nsWeakPtr mSelConWeak; // Weak reference to placeholder for begin/end batch purposes. WeakPtr<PlaceholderTransaction> mPlaceholderTransactionWeak; - // Weak reference to the nsIDOMDocument. - nsWeakPtr mDocWeak; // Name of placeholder transaction. nsIAtom* mPlaceholderName; // Saved selection state for placeholder transaction batching. diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index 3c43ade3b..fd11d1a45 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -165,7 +165,7 @@ HTMLEditor::~HTMLEditor() // free any default style propItems RemoveAllDefaultProperties(); - if (mLinkHandler && mDocWeak) { + if (mLinkHandler && IsInitialized()) { nsCOMPtr<nsIPresShell> ps = GetPresShell(); if (ps && ps->GetPresContext()) { @@ -335,7 +335,7 @@ HTMLEditor::PreDestroy(bool aDestroyingFrames) return NS_OK; } - nsCOMPtr<nsINode> document = do_QueryReferent(mDocWeak); + nsCOMPtr<nsIDocument> document = GetDocument(); if (document) { document->RemoveMutationObserver(this); } @@ -365,7 +365,7 @@ HTMLEditor::UpdateRootElement() } else { // If there is no HTML body element, // we should use the document root element instead. - nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak); + nsCOMPtr<nsIDOMDocument> doc = GetDOMDocument(); if (doc) { doc->GetDocumentElement(getter_AddRefs(rootElement)); } @@ -430,8 +430,9 @@ HTMLEditor::CreateEventListeners() nsresult HTMLEditor::InstallEventListeners() { - NS_ENSURE_TRUE(mDocWeak && mEventListener, - NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized()) || NS_WARN_IF(!mEventListener)) { + return NS_ERROR_NOT_INITIALIZED; + } // NOTE: HTMLEditor doesn't need to initialize mEventTarget here because // the target must be document node and it must be referenced as weak pointer. @@ -444,7 +445,7 @@ HTMLEditor::InstallEventListeners() void HTMLEditor::RemoveEventListeners() { - if (!mDocWeak) { + if (!IsInitialized()) { return; } @@ -506,7 +507,8 @@ HTMLEditor::InitRules() NS_IMETHODIMP HTMLEditor::BeginningOfDocument() { - if (!mDocWeak) { + // XXX Why doesn't this check if the document is alive? + if (!IsInitialized()) { return NS_ERROR_NOT_INITIALIZED; } @@ -1183,11 +1185,13 @@ HTMLEditor::ReplaceHeadContentsWithHTML(const nsAString& aSourceToInsert) // Do not use AutoRules -- rules code won't let us insert in <head>. Use // the head node as a parent and delete/insert directly. - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_NOT_INITIALIZED; + } RefPtr<nsContentList> nodeList = - doc->GetElementsByTagName(NS_LITERAL_STRING("head")); + document->GetElementsByTagName(NS_LITERAL_STRING("head")); NS_ENSURE_TRUE(nodeList, NS_ERROR_NULL_POINTER); nsCOMPtr<nsIContent> headNode = nodeList->Item(0); @@ -2705,7 +2709,7 @@ HTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement) nsresult HTMLEditor::SetHTMLBackgroundColor(const nsAString& aColor) { - NS_PRECONDITION(mDocWeak, "Missing Editor DOM Document"); + MOZ_ASSERT(IsInitialized(), "The HTMLEditor hasn't been initialized yet"); // Find a selected or enclosing table element to set background on nsCOMPtr<nsIDOMElement> element; @@ -2753,7 +2757,7 @@ HTMLEditor::SetBodyAttribute(const nsAString& aAttribute, { // TODO: Check selection for Cell, Row, Column or table and do color on appropriate level - NS_ASSERTION(mDocWeak, "Missing Editor DOM Document"); + MOZ_ASSERT(IsInitialized(), "The HTMLEditor hasn't been initialized yet"); // Set the background color attribute on the body tag nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot()); @@ -2832,7 +2836,9 @@ HTMLEditor::ReplaceStyleSheet(const nsAString& aURL) } // Make sure the pres shell doesn't disappear during the load. - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized())) { + return NS_ERROR_NOT_INITIALIZED; + } nsCOMPtr<nsIPresShell> ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); @@ -2941,7 +2947,9 @@ HTMLEditor::RemoveOverrideStyleSheet(const nsAString& aURL) NS_ENSURE_TRUE(sheet, NS_OK); /// Don't fail if sheet not found - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized())) { + return NS_ERROR_NOT_INITIALIZED; + } nsCOMPtr<nsIPresShell> ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); @@ -2960,8 +2968,8 @@ HTMLEditor::EnableStyleSheet(const nsAString& aURL, NS_ENSURE_TRUE(sheet, NS_OK); // Don't fail if sheet not found // Ensure the style sheet is owned by our document. - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - sheet->SetAssociatedDocument(doc, StyleSheet::NotOwnedByDocument); + nsCOMPtr<nsIDocument> document = GetDocument(); + sheet->SetAssociatedDocument(document, StyleSheet::NotOwnedByDocument); if (sheet->IsServo()) { // XXXheycam ServoStyleSheets don't support being enabled/disabled yet. @@ -2982,8 +2990,8 @@ HTMLEditor::EnableExistingStyleSheet(const nsAString& aURL) } // Ensure the style sheet is owned by our document. - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - sheet->SetAssociatedDocument(doc, StyleSheet::NotOwnedByDocument); + nsCOMPtr<nsIDocument> document = GetDocument(); + sheet->SetAssociatedDocument(document, StyleSheet::NotOwnedByDocument); if (sheet->IsServo()) { // XXXheycam ServoStyleSheets don't support being enabled/disabled yet. @@ -3374,13 +3382,12 @@ HTMLEditor::GetIsSelectionEditable(bool* aIsSelectionEditable) static nsresult SetSelectionAroundHeadChildren(Selection* aSelection, - nsIWeakReference* aDocWeak) + nsCOMPtr<nsIDocument>& aDocument) { - // Set selection around <head> node - nsCOMPtr<nsIDocument> doc = do_QueryReferent(aDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); + MOZ_ASSERT(aDocument); - dom::Element* headNode = doc->GetHeadElement(); + // Set selection around <head> node + dom::Element* headNode = aDocument->GetHeadElement(); NS_ENSURE_STATE(headNode); // Collapse selection to before first child of the head, @@ -3401,7 +3408,11 @@ HTMLEditor::GetHeadContentsAsHTML(nsAString& aOutputString) // Save current selection AutoSelectionRestorer selectionRestorer(selection, this); - nsresult rv = SetSelectionAroundHeadChildren(selection, mDocWeak); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_NOT_INITIALIZED; + } + nsresult rv = SetSelectionAroundHeadChildren(selection, document); NS_ENSURE_SUCCESS(rv, rv); rv = OutputToString(NS_LITERAL_STRING("text/html"), @@ -4275,10 +4286,11 @@ HTMLEditor::IsVisTextNode(nsIContent* aNode, uint32_t length = aNode->TextLength(); if (aSafeToAskFrames) { - nsCOMPtr<nsISelectionController> selCon; - nsresult rv = GetSelectionController(getter_AddRefs(selCon)); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE); + nsCOMPtr<nsISelectionController> selectionController = + GetSelectionController(); + if (NS_WARN_IF(!selectionController)) { + return NS_ERROR_FAILURE; + } bool isVisible = false; // ask the selection controller for information about whether any // of the data in the node is really rendered. This is really @@ -4286,7 +4298,8 @@ HTMLEditor::IsVisTextNode(nsIContent* aNode, // So we put a call in the selection controller interface, since it's already // in bed with frames anyway. (this is a fix for bug 22227, and a // partial fix for bug 46209) - rv = selCon->CheckVisibilityContent(aNode, 0, length, &isVisible); + nsresult rv = selectionController->CheckVisibilityContent(aNode, 0, length, + &isVisible); NS_ENSURE_SUCCESS(rv, rv); if (isVisible) { *outIsEmptyNode = false; @@ -4802,7 +4815,9 @@ HTMLEditor::GetElementOrigin(nsIDOMElement* aElement, aX = 0; aY = 0; - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!IsInitialized())) { + return NS_ERROR_NOT_INITIALIZED; + } nsCOMPtr<nsIPresShell> ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); @@ -4944,28 +4959,29 @@ HTMLEditor::GetReturnInParagraphCreatesNewParagraph(bool* aCreatesNewParagraph) already_AddRefed<nsIContent> HTMLEditor::GetFocusedContent() { - NS_ENSURE_TRUE(mDocWeak, nullptr); - nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, nullptr); nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent(); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - bool inDesignMode = doc->HasFlag(NODE_IS_EDITABLE); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return nullptr; + } + bool inDesignMode = document->HasFlag(NODE_IS_EDITABLE); if (!focusedContent) { // in designMode, nobody gets focus in most cases. if (inDesignMode && OurWindowHasFocus()) { - nsCOMPtr<nsIContent> docRoot = doc->GetRootElement(); - return docRoot.forget(); + nsCOMPtr<nsIContent> rootContent = document->GetRootElement(); + return rootContent.forget(); } return nullptr; } if (inDesignMode) { return OurWindowHasFocus() && - nsContentUtils::ContentIsDescendantOf(focusedContent, doc) ? - focusedContent.forget() : nullptr; + nsContentUtils::ContentIsDescendantOf(focusedContent, document) ? + focusedContent.forget() : nullptr; } // We're HTML editor for contenteditable @@ -4988,28 +5004,32 @@ HTMLEditor::GetFocusedContentForIME() return nullptr; } - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, nullptr); - return doc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent.forget(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return nullptr; + } + return document->HasFlag(NODE_IS_EDITABLE) ? nullptr : + focusedContent.forget(); } bool HTMLEditor::IsActiveInDOMWindow() { - NS_ENSURE_TRUE(mDocWeak, false); - nsFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, false); - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - bool inDesignMode = doc->HasFlag(NODE_IS_EDITABLE); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return false; + } + bool inDesignMode = document->HasFlag(NODE_IS_EDITABLE); // If we're in designMode, we're always active in the DOM window. if (inDesignMode) { return true; } - nsPIDOMWindowOuter* ourWindow = doc->GetWindow(); + nsPIDOMWindowOuter* ourWindow = document->GetWindow(); nsCOMPtr<nsPIDOMWindowOuter> win; nsIContent* content = nsFocusManager::GetFocusedDescendant(ourWindow, false, @@ -5032,12 +5052,12 @@ HTMLEditor::IsActiveInDOMWindow() Element* HTMLEditor::GetActiveEditingHost() { - NS_ENSURE_TRUE(mDocWeak, nullptr); - - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, nullptr); - if (doc->HasFlag(NODE_IS_EDITABLE)) { - return doc->GetBodyElement(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return nullptr; + } + if (document->HasFlag(NODE_IS_EDITABLE)) { + return document->GetBodyElement(); } // We're HTML editor for contenteditable @@ -5066,8 +5086,8 @@ HTMLEditor::GetDOMEventTarget() // Don't use getDocument here, because we have no way of knowing // whether Init() was ever called. So we need to get the document // ourselves, if it exists. - NS_PRECONDITION(mDocWeak, "This editor has not been initialized yet"); - nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryReferent(mDocWeak); + MOZ_ASSERT(IsInitialized(), "The HTMLEditor has not been initialized yet"); + nsCOMPtr<mozilla::dom::EventTarget> target = GetDocument(); return target.forget(); } @@ -5121,12 +5141,16 @@ HTMLEditor::NotifyRootChanged() nsresult HTMLEditor::GetBodyElement(nsIDOMHTMLElement** aBody) { - NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak"); - nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryReferent(mDocWeak); - if (!htmlDoc) { + MOZ_ASSERT(IsInitialized(), "The HTMLEditor hasn't been initialized yet"); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return NS_ERROR_NOT_INITIALIZED; + } + nsCOMPtr<nsIDOMHTMLDocument> domHTMLDocument = do_QueryInterface(document); + if (!domHTMLDocument) { return NS_ERROR_NOT_INITIALIZED; } - return htmlDoc->GetBody(aBody); + return domHTMLDocument->GetBody(aBody); } already_AddRefed<nsINode> @@ -5146,14 +5170,13 @@ HTMLEditor::GetFocusedNode() return node.forget(); } - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - return doc.forget(); + nsCOMPtr<nsIDocument> document = GetDocument(); + return document.forget(); } bool HTMLEditor::OurWindowHasFocus() { - NS_ENSURE_TRUE(mDocWeak, false); nsIFocusManager* fm = nsFocusManager::GetFocusManager(); NS_ENSURE_TRUE(fm, false); nsCOMPtr<mozIDOMWindowProxy> focusedWindow; @@ -5161,8 +5184,11 @@ HTMLEditor::OurWindowHasFocus() if (!focusedWindow) { return false; } - nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); - nsPIDOMWindowOuter* ourWindow = doc->GetWindow(); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return false; + } + nsPIDOMWindowOuter* ourWindow = document->GetWindow(); return ourWindow == focusedWindow; } @@ -5180,12 +5206,14 @@ HTMLEditor::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) return true; } - NS_ENSURE_TRUE(mDocWeak, false); - nsCOMPtr<nsIDOMEventTarget> target = aGUIEvent->GetDOMEventTarget(); NS_ENSURE_TRUE(target, false); - nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocWeak); + nsCOMPtr<nsIDocument> document = GetDocument(); + if (NS_WARN_IF(!document)) { + return false; + } + if (document->HasFlag(NODE_IS_EDITABLE)) { // If this editor is in designMode and the event target is the document, // the event is for this editor. diff --git a/editor/libeditor/HTMLTableEditor.cpp b/editor/libeditor/HTMLTableEditor.cpp index 778bf1d2d..06d6cae26 100644 --- a/editor/libeditor/HTMLTableEditor.cpp +++ b/editor/libeditor/HTMLTableEditor.cpp @@ -2594,7 +2594,6 @@ HTMLEditor::GetCellIndexes(nsIDOMElement* aCell, aCell = cell; } - NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); nsCOMPtr<nsIPresShell> ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); diff --git a/editor/libeditor/TextEditor.cpp b/editor/libeditor/TextEditor.cpp index 35ea5da83..9d07c198b 100644 --- a/editor/libeditor/TextEditor.cpp +++ b/editor/libeditor/TextEditor.cpp @@ -1237,7 +1237,7 @@ TextEditor::GetAndInitDocEncoder(const nsAString& aFormatType, nsCOMPtr<nsIDocumentEncoder> docEncoder (do_CreateInstance(formatType.get(), &rv)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsIDOMDocument> domDoc = do_QueryReferent(mDocWeak); + nsCOMPtr<nsIDOMDocument> domDoc = GetDOMDocument(); NS_ASSERTION(domDoc, "Need a document"); rv = docEncoder->Init(domDoc, aFormatType, aFlags); diff --git a/xpcom/base/nsIWeakReference.idl b/xpcom/base/nsIWeakReference.idl index 73390b15f..7f6880fad 100644 --- a/xpcom/base/nsIWeakReference.idl +++ b/xpcom/base/nsIWeakReference.idl @@ -37,6 +37,11 @@ interface nsIWeakReference : nsISupports %{C++ virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0; + + /** + * Returns true if the referring object is alive. Otherwise, false. + */ + virtual bool IsAlive() const = 0; %} }; diff --git a/xpcom/glue/nsWeakReference.cpp b/xpcom/glue/nsWeakReference.cpp index 57f372641..be263e1c2 100644 --- a/xpcom/glue/nsWeakReference.cpp +++ b/xpcom/glue/nsWeakReference.cpp @@ -37,6 +37,7 @@ public: // nsIWeakReference... NS_DECL_NSIWEAKREFERENCE virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override; + bool IsAlive() const override { return mReferent != nullptr; } private: MOZ_WEAKREF_DECL_OWNINGTHREAD |