Bug 1372829 - Part 2: mozilla::EditorBase should cache raw pointer of nsISelectionController and nsIDocument with nsWeakPtr

Tag #1375
This commit is contained in:
Matt A. Tobin 2020-04-17 05:47:12 -04:00 • committed by Roy Tam
commit 4e14355697
8 changed files with 288 additions and 164 deletions

View file

@ -62,6 +62,7 @@ public:
// nsIWeakReference // nsIWeakReference
NS_DECL_NSIWEAKREFERENCE NS_DECL_NSIWEAKREFERENCE
virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override; virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
virtual bool IsAlive() const override { return mNode != nullptr; }
void NoticeNodeDestruction() void NoticeNodeDestruction()
{ {

View file

@ -37,6 +37,7 @@
#include "mozilla/TextComposition.h" // for TextComposition #include "mozilla/TextComposition.h" // for TextComposition
#include "mozilla/TextEvents.h" #include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h" // for Element, nsINode::AsElement #include "mozilla/dom/Element.h" // for Element, nsINode::AsElement
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/dom/Text.h" #include "mozilla/dom/Text.h"
#include "mozilla/dom/Event.h" #include "mozilla/dom/Event.h"
#include "mozilla/mozalloc.h" // for operator new, etc. #include "mozilla/mozalloc.h" // for operator new, etc.
@ -71,7 +72,6 @@
#include "nsIDOMNode.h" // for nsIDOMNode, etc. #include "nsIDOMNode.h" // for nsIDOMNode, etc.
#include "nsIDOMNodeList.h" // for nsIDOMNodeList #include "nsIDOMNodeList.h" // for nsIDOMNodeList
#include "nsIDOMText.h" // for nsIDOMText #include "nsIDOMText.h" // for nsIDOMText
#include "nsIDocument.h" // for nsIDocument
#include "nsIDocumentStateListener.h" // for nsIDocumentStateListener #include "nsIDocumentStateListener.h" // for nsIDocumentStateListener
#include "nsIEditActionListener.h" // for nsIEditActionListener #include "nsIEditActionListener.h" // for nsIEditActionListener
#include "nsIEditorObserver.h" // for nsIEditorObserver #include "nsIEditorObserver.h" // for nsIEditorObserver
@ -151,7 +151,8 @@ EditorBase::EditorBase()
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) { if (mComposition) {
mComposition->OnEditorDestroyed(); mComposition->OnEditorDestroyed();
@ -220,20 +221,21 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(EditorBase)
NS_IMETHODIMP NS_IMETHODIMP
EditorBase::Init(nsIDOMDocument* aDoc, EditorBase::Init(nsIDOMDocument* aDOMDocument,
nsIContent* aRoot, nsIContent* aRoot,
nsISelectionController* aSelCon, nsISelectionController* aSelectionController,
uint32_t aFlags, uint32_t aFlags,
const nsAString& aValue) const nsAString& aValue)
{ {
MOZ_ASSERT(mAction == EditAction::none, MOZ_ASSERT(mAction == EditAction::none,
"Initializing during an edit action is an error"); "Initializing during an edit action is an error");
MOZ_ASSERT(aDoc); MOZ_ASSERT(aDOMDocument);
if (!aDoc) if (!aDOMDocument) {
return NS_ERROR_NULL_POINTER; return NS_ERROR_NULL_POINTER;
}
// First only set flags, but other stuff shouldn't be initialized now. // 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 // SetFlags() can check whether it's called during initialization or not by
// them. Note that SetFlags() will be called by PostCreate(). // them. Note that SetFlags() will be called by PostCreate().
#ifdef DEBUG #ifdef DEBUG
@ -242,19 +244,21 @@ EditorBase::Init(nsIDOMDocument* aDoc,
SetFlags(aFlags); SetFlags(aFlags);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed"); 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, // HTML editors currently don't have their own selection controller,
// so they'll pass null as aSelCon, and we'll get the selection controller // so they'll pass null as aSelCon, and we'll get the selection controller
// off of the presshell. // off of the presshell.
nsCOMPtr<nsISelectionController> selCon; nsCOMPtr<nsISelectionController> selectionController;
if (aSelCon) { if (aSelectionController) {
mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller mSelectionControllerWeak = aSelectionController;
selCon = aSelCon; selectionController = aSelectionController;
} else { } else {
nsCOMPtr<nsIPresShell> presShell = GetPresShell(); 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. //set up root element if we are passed one.
if (aRoot) if (aRoot)
@ -271,13 +275,14 @@ EditorBase::Init(nsIDOMDocument* aDoc,
mIMETextNode = nullptr; mIMETextNode = nullptr;
} }
/* Show the caret */ // Show the caret.
selCon->SetCaretReadOnly(false); selectionController->SetCaretReadOnly(false);
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); selectionController->SetDisplaySelection(
nsISelectionController::SELECTION_ON);
// Show all the selection reflected to user.
selectionController->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);
selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);//we want to see all the selection reflected to user MOZ_ASSERT(IsInitialized());
NS_POSTCONDITION(mDocWeak, "bad state");
// Make sure that the editor will be destroyed properly // Make sure that the editor will be destroyed properly
mDidPreDestroy = false; mDidPreDestroy = false;
@ -356,8 +361,9 @@ EditorBase::CreateEventListeners()
nsresult nsresult
EditorBase::InstallEventListeners() EditorBase::InstallEventListeners()
{ {
NS_ENSURE_TRUE(mDocWeak && mEventListener, if (NS_WARN_IF(!IsInitialized()) || NS_WARN_IF(!mEventListener)) {
NS_ERROR_NOT_INITIALIZED); return NS_ERROR_NOT_INITIALIZED;
}
// Initialize the event target. // Initialize the event target.
nsCOMPtr<nsIContent> rootContent = GetRoot(); nsCOMPtr<nsIContent> rootContent = GetRoot();
@ -378,7 +384,7 @@ EditorBase::InstallEventListeners()
void void
EditorBase::RemoveEventListeners() EditorBase::RemoveEventListeners()
{ {
if (!mDocWeak || !mEventListener) { if (!IsInitialized() || !mEventListener) {
return; return;
} }
reinterpret_cast<EditorEventListener*>(mEventListener.get())->Disconnect(); reinterpret_cast<EditorEventListener*>(mEventListener.get())->Disconnect();
@ -501,7 +507,7 @@ EditorBase::SetFlags(uint32_t aFlags)
bool spellcheckerWasEnabled = CanEnableSpellCheck(); bool spellcheckerWasEnabled = CanEnableSpellCheck();
mFlags = aFlags; mFlags = aFlags;
if (!mDocWeak) { if (!IsInitialized()) {
// If we're initializing, we shouldn't do anything now. // If we're initializing, we shouldn't do anything now.
// SetFlags() will be called by PostCreate(), // SetFlags() will be called by PostCreate(),
// we should synchronize some stuff for the flags at that time. // we should synchronize some stuff for the flags at that time.
@ -567,17 +573,15 @@ EditorBase::GetIsDocumentEditable(bool* aIsDocumentEditable)
already_AddRefed<nsIDocument> already_AddRefed<nsIDocument>
EditorBase::GetDocument() EditorBase::GetDocument()
{ {
NS_PRECONDITION(mDocWeak, "bad state, mDocWeak weak pointer not initialized"); nsCOMPtr<nsIDocument> document = mDocumentWeak.get();
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); return document.forget();
return doc.forget();
} }
already_AddRefed<nsIDOMDocument> already_AddRefed<nsIDOMDocument>
EditorBase::GetDOMDocument() EditorBase::GetDOMDocument()
{ {
NS_PRECONDITION(mDocWeak, "bad state, mDocWeak weak pointer not initialized"); nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(mDocumentWeak);
nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak); return domDocument.forget();
return doc.forget();
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -590,11 +594,12 @@ EditorBase::GetDocument(nsIDOMDocument** aDoc)
already_AddRefed<nsIPresShell> already_AddRefed<nsIPresShell>
EditorBase::GetPresShell() EditorBase::GetPresShell()
{ {
NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak"); nsCOMPtr<nsIDocument> document = GetDocument();
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); if (NS_WARN_IF(!document)) {
NS_ENSURE_TRUE(doc, nullptr); return nullptr;
nsCOMPtr<nsIPresShell> ps = doc->GetShell(); }
return ps.forget(); nsCOMPtr<nsIPresShell> presShell = document->GetShell();
return presShell.forget();
} }
already_AddRefed<nsIWidget> already_AddRefed<nsIWidget>
@ -640,14 +645,14 @@ EditorBase::GetSelectionController(nsISelectionController** aSel)
already_AddRefed<nsISelectionController> already_AddRefed<nsISelectionController>
EditorBase::GetSelectionController() EditorBase::GetSelectionController()
{ {
nsCOMPtr<nsISelectionController> selCon; nsCOMPtr<nsISelectionController> selectionController;
if (mSelConWeak) { if (mSelectionControllerWeak) {
selCon = do_QueryReferent(mSelConWeak); selectionController = mSelectionControllerWeak.get();
} else { } else {
nsCOMPtr<nsIPresShell> presShell = GetPresShell(); nsCOMPtr<nsIPresShell> presShell = GetPresShell();
selCon = do_QueryInterface(presShell); selectionController = do_QueryInterface(presShell);
} }
return selCon.forget(); return selectionController.forget();
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -1065,7 +1070,8 @@ EditorBase::GetDocumentIsEmpty(bool* aDocumentIsEmpty)
NS_IMETHODIMP NS_IMETHODIMP
EditorBase::SelectAll() EditorBase::SelectAll()
{ {
if (!mDocWeak) { // XXX Why doesn't this check if the document is alive?
if (!IsInitialized()) {
return NS_ERROR_NOT_INITIALIZED; return NS_ERROR_NOT_INITIALIZED;
} }
ForceCompositionEnd(); ForceCompositionEnd();
@ -1078,7 +1084,8 @@ EditorBase::SelectAll()
NS_IMETHODIMP NS_IMETHODIMP
EditorBase::BeginningOfDocument() EditorBase::BeginningOfDocument()
{ {
if (!mDocWeak) { // XXX Why doesn't this check if the document is alive?
if (!IsInitialized()) {
return NS_ERROR_NOT_INITIALIZED; return NS_ERROR_NOT_INITIALIZED;
} }
@ -1115,7 +1122,10 @@ EditorBase::BeginningOfDocument()
NS_IMETHODIMP NS_IMETHODIMP
EditorBase::EndOfDocument() 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 // get selection
RefPtr<Selection> selection = GetSelection(); RefPtr<Selection> selection = GetSelection();
@ -1150,20 +1160,22 @@ EditorBase::GetDocumentModified(bool* outDocModified)
NS_IMETHODIMP NS_IMETHODIMP
EditorBase::GetDocumentCharacterSet(nsACString& characterSet) EditorBase::GetDocumentCharacterSet(nsACString& characterSet)
{ {
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); if (NS_WARN_IF(!document)) {
return NS_ERROR_UNEXPECTED;
characterSet = doc->GetDocumentCharacterSet(); }
characterSet = document->GetDocumentCharacterSet();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
EditorBase::SetDocumentCharacterSet(const nsACString& characterSet) EditorBase::SetDocumentCharacterSet(const nsACString& characterSet)
{ {
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); if (NS_WARN_IF(!document)) {
return NS_ERROR_UNEXPECTED;
doc->SetDocumentCharacterSet(characterSet); }
document->SetDocumentCharacterSet(characterSet);
return NS_OK; return NS_OK;
} }
@ -2004,12 +2016,17 @@ NS_IMETHODIMP
EditorBase::DebugDumpContent() EditorBase::DebugDumpContent()
{ {
#ifdef DEBUG #ifdef DEBUG
nsCOMPtr<nsIDOMHTMLDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); if (NS_WARN_IF(!document)) {
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsIDOMHTMLElement>bodyElem; }
doc->GetBody(getter_AddRefs(bodyElem)); nsCOMPtr<nsIDOMHTMLDocument> domHTMLDocument = do_QueryInterface(document);
nsCOMPtr<nsIContent> content = do_QueryInterface(bodyElem); 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) { if (content) {
content->List(); content->List();
} }
@ -2323,18 +2340,20 @@ EditorBase::CloneAttributes(Element* aDest,
NS_IMETHODIMP NS_IMETHODIMP
EditorBase::ScrollSelectionIntoView(bool aScrollToAnchor) EditorBase::ScrollSelectionIntoView(bool aScrollToAnchor)
{ {
nsCOMPtr<nsISelectionController> selCon; nsCOMPtr<nsISelectionController> selectionController =
if (NS_SUCCEEDED(GetSelectionController(getter_AddRefs(selCon))) && selCon) { GetSelectionController();
int16_t region = nsISelectionController::SELECTION_FOCUS_REGION; if (!selectionController) {
return NS_OK;
}
int16_t region = nsISelectionController::SELECTION_FOCUS_REGION;
if (aScrollToAnchor) { if (aScrollToAnchor) {
region = nsISelectionController::SELECTION_ANCHOR_REGION; region = nsISelectionController::SELECTION_ANCHOR_REGION;
} }
selectionController->ScrollSelectionIntoView(
selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_NORMAL,
region, nsISelectionController::SCROLL_OVERFLOW_HIDDEN); region,
} nsISelectionController::SCROLL_OVERFLOW_HIDDEN);
return NS_OK; return NS_OK;
} }
@ -4784,22 +4803,27 @@ EditorBase::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget)
nsCOMPtr<nsIPresShell> presShell = GetPresShell(); nsCOMPtr<nsIPresShell> presShell = GetPresShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsISelectionController> selCon; nsCOMPtr<nsISelectionController> selectionController =
nsresult rv = GetSelectionController(getter_AddRefs(selCon)); GetSelectionController();
NS_ENSURE_SUCCESS(rv, rv); if (NS_WARN_IF(!selectionController)) {
return NS_ERROR_FAILURE;
}
// Init the caret // Init the caret
RefPtr<nsCaret> caret = presShell->GetCaret(); RefPtr<nsCaret> caret = presShell->GetCaret();
NS_ENSURE_TRUE(caret, NS_ERROR_UNEXPECTED); NS_ENSURE_TRUE(caret, NS_ERROR_UNEXPECTED);
caret->SetIgnoreUserModify(false); caret->SetIgnoreUserModify(false);
caret->SetSelection(selection); caret->SetSelection(selection);
selCon->SetCaretReadOnly(IsReadonly()); selectionController->SetCaretReadOnly(IsReadonly());
selCon->SetCaretEnabled(true); selectionController->SetCaretEnabled(true);
// Init selection // Init selection
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); selectionController->SetDisplaySelection(
selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL); nsISelectionController::SELECTION_ON);
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL); selectionController->SetSelectionFlags(
nsISelectionDisplay::DISPLAY_ALL);
selectionController->RepaintSelection(
nsISelectionController::SELECTION_NORMAL);
// If the computed selection root isn't root content, we should set it // 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 // as selection ancestor limit. However, if that is root element, it means
// there is not limitation of the selection, then, we must set nullptr. // there is not limitation of the selection, then, we must set nullptr.
@ -4867,9 +4891,11 @@ private:
NS_IMETHODIMP NS_IMETHODIMP
EditorBase::FinalizeSelection() EditorBase::FinalizeSelection()
{ {
nsCOMPtr<nsISelectionController> selCon; nsCOMPtr<nsISelectionController> selectionController =
nsresult rv = GetSelectionController(getter_AddRefs(selCon)); GetSelectionController();
NS_ENSURE_SUCCESS(rv, rv); if (NS_WARN_IF(!selectionController)) {
return NS_ERROR_FAILURE;
}
RefPtr<Selection> selection = GetSelection(); RefPtr<Selection> selection = GetSelection();
NS_ENSURE_STATE(selection); NS_ENSURE_STATE(selection);
@ -4879,7 +4905,7 @@ EditorBase::FinalizeSelection()
nsCOMPtr<nsIPresShell> presShell = GetPresShell(); nsCOMPtr<nsIPresShell> presShell = GetPresShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED);
selCon->SetCaretEnabled(false); selectionController->SetCaretEnabled(false);
nsFocusManager* fm = nsFocusManager::GetFocusManager(); nsFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(fm, NS_ERROR_NOT_INITIALIZED);
@ -4894,29 +4920,33 @@ EditorBase::FinalizeSelection()
ErrorResult ret; ErrorResult ret;
if (!doc || !doc->HasFocus(ret)) { if (!doc || !doc->HasFocus(ret)) {
// If the document already lost focus, mark the selection as disabled. // If the document already lost focus, mark the selection as disabled.
selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED); selectionController->SetDisplaySelection(
nsISelectionController::SELECTION_DISABLED);
} else { } else {
// Otherwise, mark selection as normal because outside of a // Otherwise, mark selection as normal because outside of a
// contenteditable element should be selected with normal selection // contenteditable element should be selected with normal selection
// color after here. // color after here.
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); selectionController->SetDisplaySelection(
nsISelectionController::SELECTION_ON);
} }
} else if (IsFormWidget() || IsPasswordEditor() || } else if (IsFormWidget() || IsPasswordEditor() ||
IsReadonly() || IsDisabled() || IsInputFiltered()) { IsReadonly() || IsDisabled() || IsInputFiltered()) {
// In <input> or <textarea>, the independent selection should be hidden // In <input> or <textarea>, the independent selection should be hidden
// while this editor doesn't have focus. // while this editor doesn't have focus.
selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN); selectionController->SetDisplaySelection(
nsISelectionController::SELECTION_HIDDEN);
} else { } else {
// Otherwise, although we're not sure how this case happens, the // Otherwise, although we're not sure how this case happens, the
// independent selection should be marked as disabled. // 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 // FinalizeSelection might be called from ContentRemoved even if selection
// isn't updated. So we need to call RepaintSelection after updated it. // isn't updated. So we need to call RepaintSelection after updated it.
nsContentUtils::AddScriptRunner( nsContentUtils::AddScriptRunner(
new RepaintSelectionRunner(selCon)); new RepaintSelectionRunner(selectionController));
return NS_OK; return NS_OK;
} }
@ -5127,8 +5157,11 @@ EditorBase::IsActiveInDOMWindow()
nsFocusManager* fm = nsFocusManager::GetFocusManager(); nsFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, false); NS_ENSURE_TRUE(fm, false);
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
nsPIDOMWindowOuter* ourWindow = doc->GetWindow(); if (NS_WARN_IF(!document)) {
return false;
}
nsPIDOMWindowOuter* ourWindow = document->GetWindow();
nsCOMPtr<nsPIDOMWindowOuter> win; nsCOMPtr<nsPIDOMWindowOuter> win;
nsIContent* content = nsIContent* content =
nsFocusManager::GetFocusedDescendant(ourWindow, false, nsFocusManager::GetFocusedDescendant(ourWindow, false,
@ -5236,10 +5269,11 @@ EditorBase::GetIMESelectionStartOffsetIn(nsINode* aTextNode)
{ {
MOZ_ASSERT(aTextNode, "aTextNode must not be nullptr"); MOZ_ASSERT(aTextNode, "aTextNode must not be nullptr");
nsCOMPtr<nsISelectionController> selectionController; nsCOMPtr<nsISelectionController> selectionController =
nsresult rv = GetSelectionController(getter_AddRefs(selectionController)); GetSelectionController();
NS_ENSURE_SUCCESS(rv, -1); if (NS_WARN_IF(!selectionController)) {
NS_ENSURE_TRUE(selectionController, -1); return -1;
}
int32_t minOffset = INT32_MAX; int32_t minOffset = INT32_MAX;
static const SelectionType kIMESelectionTypes[] = { static const SelectionType kIMESelectionTypes[] = {

View file

@ -17,6 +17,7 @@
#include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr #include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "nsGkAtoms.h" #include "nsGkAtoms.h"
#include "nsIDocument.h" // for nsIDocument
#include "nsIEditor.h" // for nsIEditor::EDirection, etc. #include "nsIEditor.h" // for nsIEditor::EDirection, etc.
#include "nsIEditorIMESupport.h" // for NS_DECL_NSIEDITORIMESUPPORT, etc. #include "nsIEditorIMESupport.h" // for NS_DECL_NSIEDITORIMESUPPORT, etc.
#include "nsIObserver.h" // for NS_DECL_NSIOBSERVER, etc. #include "nsIObserver.h" // for NS_DECL_NSIOBSERVER, etc.
@ -32,7 +33,6 @@
class nsIAtom; class nsIAtom;
class nsIContent; class nsIContent;
class nsIDOMDocument;
class nsIDOMEvent; class nsIDOMEvent;
class nsIDOMEventListener; class nsIDOMEventListener;
class nsIDOMEventTarget; class nsIDOMEventTarget;
@ -135,6 +135,57 @@ namespace widget {
struct IMEState; struct IMEState;
} // namespace widget } // 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 kMOZEditorBogusNodeAttrAtom nsGkAtoms::mozeditorbogusnode
#define kMOZEditorBogusNodeValue NS_LITERAL_STRING("TRUE") #define kMOZEditorBogusNodeValue NS_LITERAL_STRING("TRUE")
@ -178,6 +229,7 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor) NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor)
bool IsInitialized() const { return !!mDocumentWeak; }
already_AddRefed<nsIDOMDocument> GetDOMDocument(); already_AddRefed<nsIDOMDocument> GetDOMDocument();
already_AddRefed<nsIDocument> GetDocument(); already_AddRefed<nsIDocument> GetDocument();
already_AddRefed<nsIPresShell> GetPresShell(); already_AddRefed<nsIPresShell> GetPresShell();
@ -848,7 +900,7 @@ public:
bool HasIndependentSelection() const 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: protected:
enum Tristate enum Tristate
{ {
@ -975,12 +1035,8 @@ protected:
// The form field as an event receiver. // The form field as an event receiver.
nsCOMPtr<dom::EventTarget> mEventTarget; nsCOMPtr<dom::EventTarget> mEventTarget;
nsCOMPtr<nsIDOMEventListener> mEventListener; nsCOMPtr<nsIDOMEventListener> mEventListener;
// Weak reference to the nsISelectionController.
nsWeakPtr mSelConWeak;
// Weak reference to placeholder for begin/end batch purposes. // Weak reference to placeholder for begin/end batch purposes.
WeakPtr<PlaceholderTransaction> mPlaceholderTransactionWeak; WeakPtr<PlaceholderTransaction> mPlaceholderTransactionWeak;
// Weak reference to the nsIDOMDocument.
nsWeakPtr mDocWeak;
// Name of placeholder transaction. // Name of placeholder transaction.
nsIAtom* mPlaceholderName; nsIAtom* mPlaceholderName;
// Saved selection state for placeholder transaction batching. // Saved selection state for placeholder transaction batching.

View file

@ -165,7 +165,7 @@ HTMLEditor::~HTMLEditor()
// free any default style propItems // free any default style propItems
RemoveAllDefaultProperties(); RemoveAllDefaultProperties();
if (mLinkHandler && mDocWeak) { if (mLinkHandler && IsInitialized()) {
nsCOMPtr<nsIPresShell> ps = GetPresShell(); nsCOMPtr<nsIPresShell> ps = GetPresShell();
if (ps && ps->GetPresContext()) { if (ps && ps->GetPresContext()) {
@ -335,7 +335,7 @@ HTMLEditor::PreDestroy(bool aDestroyingFrames)
return NS_OK; return NS_OK;
} }
nsCOMPtr<nsINode> document = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
if (document) { if (document) {
document->RemoveMutationObserver(this); document->RemoveMutationObserver(this);
} }
@ -365,7 +365,7 @@ HTMLEditor::UpdateRootElement()
} else { } else {
// If there is no HTML body element, // If there is no HTML body element,
// we should use the document root element instead. // we should use the document root element instead.
nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDOMDocument> doc = GetDOMDocument();
if (doc) { if (doc) {
doc->GetDocumentElement(getter_AddRefs(rootElement)); doc->GetDocumentElement(getter_AddRefs(rootElement));
} }
@ -430,8 +430,9 @@ HTMLEditor::CreateEventListeners()
nsresult nsresult
HTMLEditor::InstallEventListeners() HTMLEditor::InstallEventListeners()
{ {
NS_ENSURE_TRUE(mDocWeak && mEventListener, if (NS_WARN_IF(!IsInitialized()) || NS_WARN_IF(!mEventListener)) {
NS_ERROR_NOT_INITIALIZED); return NS_ERROR_NOT_INITIALIZED;
}
// NOTE: HTMLEditor doesn't need to initialize mEventTarget here because // NOTE: HTMLEditor doesn't need to initialize mEventTarget here because
// the target must be document node and it must be referenced as weak pointer. // the target must be document node and it must be referenced as weak pointer.
@ -444,7 +445,7 @@ HTMLEditor::InstallEventListeners()
void void
HTMLEditor::RemoveEventListeners() HTMLEditor::RemoveEventListeners()
{ {
if (!mDocWeak) { if (!IsInitialized()) {
return; return;
} }
@ -506,7 +507,8 @@ HTMLEditor::InitRules()
NS_IMETHODIMP NS_IMETHODIMP
HTMLEditor::BeginningOfDocument() HTMLEditor::BeginningOfDocument()
{ {
if (!mDocWeak) { // XXX Why doesn't this check if the document is alive?
if (!IsInitialized()) {
return NS_ERROR_NOT_INITIALIZED; 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 // Do not use AutoRules -- rules code won't let us insert in <head>. Use
// the head node as a parent and delete/insert directly. // the head node as a parent and delete/insert directly.
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); if (NS_WARN_IF(!document)) {
return NS_ERROR_NOT_INITIALIZED;
}
RefPtr<nsContentList> nodeList = RefPtr<nsContentList> nodeList =
doc->GetElementsByTagName(NS_LITERAL_STRING("head")); document->GetElementsByTagName(NS_LITERAL_STRING("head"));
NS_ENSURE_TRUE(nodeList, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(nodeList, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIContent> headNode = nodeList->Item(0); nsCOMPtr<nsIContent> headNode = nodeList->Item(0);
@ -2705,7 +2709,7 @@ HTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement)
nsresult nsresult
HTMLEditor::SetHTMLBackgroundColor(const nsAString& aColor) 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 // Find a selected or enclosing table element to set background on
nsCOMPtr<nsIDOMElement> element; 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 // 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 // Set the background color attribute on the body tag
nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot()); 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. // 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(); nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); 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(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(); nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); 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 NS_ENSURE_TRUE(sheet, NS_OK); // Don't fail if sheet not found
// Ensure the style sheet is owned by our document. // Ensure the style sheet is owned by our document.
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
sheet->SetAssociatedDocument(doc, StyleSheet::NotOwnedByDocument); sheet->SetAssociatedDocument(document, StyleSheet::NotOwnedByDocument);
if (sheet->IsServo()) { if (sheet->IsServo()) {
// XXXheycam ServoStyleSheets don't support being enabled/disabled yet. // 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. // Ensure the style sheet is owned by our document.
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
sheet->SetAssociatedDocument(doc, StyleSheet::NotOwnedByDocument); sheet->SetAssociatedDocument(document, StyleSheet::NotOwnedByDocument);
if (sheet->IsServo()) { if (sheet->IsServo()) {
// XXXheycam ServoStyleSheets don't support being enabled/disabled yet. // XXXheycam ServoStyleSheets don't support being enabled/disabled yet.
@ -3374,13 +3382,12 @@ HTMLEditor::GetIsSelectionEditable(bool* aIsSelectionEditable)
static nsresult static nsresult
SetSelectionAroundHeadChildren(Selection* aSelection, SetSelectionAroundHeadChildren(Selection* aSelection,
nsIWeakReference* aDocWeak) nsCOMPtr<nsIDocument>& aDocument)
{ {
// Set selection around <head> node MOZ_ASSERT(aDocument);
nsCOMPtr<nsIDocument> doc = do_QueryReferent(aDocWeak);
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
dom::Element* headNode = doc->GetHeadElement(); // Set selection around <head> node
dom::Element* headNode = aDocument->GetHeadElement();
NS_ENSURE_STATE(headNode); NS_ENSURE_STATE(headNode);
// Collapse selection to before first child of the head, // Collapse selection to before first child of the head,
@ -3401,7 +3408,11 @@ HTMLEditor::GetHeadContentsAsHTML(nsAString& aOutputString)
// Save current selection // Save current selection
AutoSelectionRestorer selectionRestorer(selection, this); 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); NS_ENSURE_SUCCESS(rv, rv);
rv = OutputToString(NS_LITERAL_STRING("text/html"), rv = OutputToString(NS_LITERAL_STRING("text/html"),
@ -4275,10 +4286,11 @@ HTMLEditor::IsVisTextNode(nsIContent* aNode,
uint32_t length = aNode->TextLength(); uint32_t length = aNode->TextLength();
if (aSafeToAskFrames) { if (aSafeToAskFrames) {
nsCOMPtr<nsISelectionController> selCon; nsCOMPtr<nsISelectionController> selectionController =
nsresult rv = GetSelectionController(getter_AddRefs(selCon)); GetSelectionController();
NS_ENSURE_SUCCESS(rv, rv); if (NS_WARN_IF(!selectionController)) {
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE); return NS_ERROR_FAILURE;
}
bool isVisible = false; bool isVisible = false;
// ask the selection controller for information about whether any // ask the selection controller for information about whether any
// of the data in the node is really rendered. This is really // 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 // 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 // in bed with frames anyway. (this is a fix for bug 22227, and a
// partial fix for bug 46209) // 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); NS_ENSURE_SUCCESS(rv, rv);
if (isVisible) { if (isVisible) {
*outIsEmptyNode = false; *outIsEmptyNode = false;
@ -4802,7 +4815,9 @@ HTMLEditor::GetElementOrigin(nsIDOMElement* aElement,
aX = 0; aX = 0;
aY = 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(); nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
@ -4944,27 +4959,28 @@ HTMLEditor::GetReturnInParagraphCreatesNewParagraph(bool* aCreatesNewParagraph)
already_AddRefed<nsIContent> already_AddRefed<nsIContent>
HTMLEditor::GetFocusedContent() HTMLEditor::GetFocusedContent()
{ {
NS_ENSURE_TRUE(mDocWeak, nullptr);
nsFocusManager* fm = nsFocusManager::GetFocusManager(); nsFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, nullptr); NS_ENSURE_TRUE(fm, nullptr);
nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent(); nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
bool inDesignMode = doc->HasFlag(NODE_IS_EDITABLE); if (NS_WARN_IF(!document)) {
return nullptr;
}
bool inDesignMode = document->HasFlag(NODE_IS_EDITABLE);
if (!focusedContent) { if (!focusedContent) {
// in designMode, nobody gets focus in most cases. // in designMode, nobody gets focus in most cases.
if (inDesignMode && OurWindowHasFocus()) { if (inDesignMode && OurWindowHasFocus()) {
nsCOMPtr<nsIContent> docRoot = doc->GetRootElement(); nsCOMPtr<nsIContent> rootContent = document->GetRootElement();
return docRoot.forget(); return rootContent.forget();
} }
return nullptr; return nullptr;
} }
if (inDesignMode) { if (inDesignMode) {
return OurWindowHasFocus() && return OurWindowHasFocus() &&
nsContentUtils::ContentIsDescendantOf(focusedContent, doc) ? nsContentUtils::ContentIsDescendantOf(focusedContent, document) ?
focusedContent.forget() : nullptr; focusedContent.forget() : nullptr;
} }
@ -4988,28 +5004,32 @@ HTMLEditor::GetFocusedContentForIME()
return nullptr; return nullptr;
} }
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
NS_ENSURE_TRUE(doc, nullptr); if (NS_WARN_IF(!document)) {
return doc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent.forget(); return nullptr;
}
return document->HasFlag(NODE_IS_EDITABLE) ? nullptr :
focusedContent.forget();
} }
bool bool
HTMLEditor::IsActiveInDOMWindow() HTMLEditor::IsActiveInDOMWindow()
{ {
NS_ENSURE_TRUE(mDocWeak, false);
nsFocusManager* fm = nsFocusManager::GetFocusManager(); nsFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, false); NS_ENSURE_TRUE(fm, false);
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
bool inDesignMode = doc->HasFlag(NODE_IS_EDITABLE); 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 we're in designMode, we're always active in the DOM window.
if (inDesignMode) { if (inDesignMode) {
return true; return true;
} }
nsPIDOMWindowOuter* ourWindow = doc->GetWindow(); nsPIDOMWindowOuter* ourWindow = document->GetWindow();
nsCOMPtr<nsPIDOMWindowOuter> win; nsCOMPtr<nsPIDOMWindowOuter> win;
nsIContent* content = nsIContent* content =
nsFocusManager::GetFocusedDescendant(ourWindow, false, nsFocusManager::GetFocusedDescendant(ourWindow, false,
@ -5032,12 +5052,12 @@ HTMLEditor::IsActiveInDOMWindow()
Element* Element*
HTMLEditor::GetActiveEditingHost() HTMLEditor::GetActiveEditingHost()
{ {
NS_ENSURE_TRUE(mDocWeak, nullptr); nsCOMPtr<nsIDocument> document = GetDocument();
if (NS_WARN_IF(!document)) {
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); return nullptr;
NS_ENSURE_TRUE(doc, nullptr); }
if (doc->HasFlag(NODE_IS_EDITABLE)) { if (document->HasFlag(NODE_IS_EDITABLE)) {
return doc->GetBodyElement(); return document->GetBodyElement();
} }
// We're HTML editor for contenteditable // We're HTML editor for contenteditable
@ -5066,8 +5086,8 @@ HTMLEditor::GetDOMEventTarget()
// Don't use getDocument here, because we have no way of knowing // Don't use getDocument here, because we have no way of knowing
// whether Init() was ever called. So we need to get the document // whether Init() was ever called. So we need to get the document
// ourselves, if it exists. // ourselves, if it exists.
NS_PRECONDITION(mDocWeak, "This editor has not been initialized yet"); MOZ_ASSERT(IsInitialized(), "The HTMLEditor has not been initialized yet");
nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryReferent(mDocWeak); nsCOMPtr<mozilla::dom::EventTarget> target = GetDocument();
return target.forget(); return target.forget();
} }
@ -5121,12 +5141,16 @@ HTMLEditor::NotifyRootChanged()
nsresult nsresult
HTMLEditor::GetBodyElement(nsIDOMHTMLElement** aBody) HTMLEditor::GetBodyElement(nsIDOMHTMLElement** aBody)
{ {
NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak"); MOZ_ASSERT(IsInitialized(), "The HTMLEditor hasn't been initialized yet");
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
if (!htmlDoc) { if (NS_WARN_IF(!document)) {
return NS_ERROR_NOT_INITIALIZED; return NS_ERROR_NOT_INITIALIZED;
} }
return htmlDoc->GetBody(aBody); nsCOMPtr<nsIDOMHTMLDocument> domHTMLDocument = do_QueryInterface(document);
if (!domHTMLDocument) {
return NS_ERROR_NOT_INITIALIZED;
}
return domHTMLDocument->GetBody(aBody);
} }
already_AddRefed<nsINode> already_AddRefed<nsINode>
@ -5146,14 +5170,13 @@ HTMLEditor::GetFocusedNode()
return node.forget(); return node.forget();
} }
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
return doc.forget(); return document.forget();
} }
bool bool
HTMLEditor::OurWindowHasFocus() HTMLEditor::OurWindowHasFocus()
{ {
NS_ENSURE_TRUE(mDocWeak, false);
nsIFocusManager* fm = nsFocusManager::GetFocusManager(); nsIFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, false); NS_ENSURE_TRUE(fm, false);
nsCOMPtr<mozIDOMWindowProxy> focusedWindow; nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
@ -5161,8 +5184,11 @@ HTMLEditor::OurWindowHasFocus()
if (!focusedWindow) { if (!focusedWindow) {
return false; return false;
} }
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDocument> document = GetDocument();
nsPIDOMWindowOuter* ourWindow = doc->GetWindow(); if (NS_WARN_IF(!document)) {
return false;
}
nsPIDOMWindowOuter* ourWindow = document->GetWindow();
return ourWindow == focusedWindow; return ourWindow == focusedWindow;
} }
@ -5180,12 +5206,14 @@ HTMLEditor::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent)
return true; return true;
} }
NS_ENSURE_TRUE(mDocWeak, false);
nsCOMPtr<nsIDOMEventTarget> target = aGUIEvent->GetDOMEventTarget(); nsCOMPtr<nsIDOMEventTarget> target = aGUIEvent->GetDOMEventTarget();
NS_ENSURE_TRUE(target, false); 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 (document->HasFlag(NODE_IS_EDITABLE)) {
// If this editor is in designMode and the event target is the document, // If this editor is in designMode and the event target is the document,
// the event is for this editor. // the event is for this editor.

View file

@ -2594,7 +2594,6 @@ HTMLEditor::GetCellIndexes(nsIDOMElement* aCell,
aCell = cell; aCell = cell;
} }
NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsIPresShell> ps = GetPresShell(); nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);

View file

@ -1237,7 +1237,7 @@ TextEditor::GetAndInitDocEncoder(const nsAString& aFormatType,
nsCOMPtr<nsIDocumentEncoder> docEncoder (do_CreateInstance(formatType.get(), &rv)); nsCOMPtr<nsIDocumentEncoder> docEncoder (do_CreateInstance(formatType.get(), &rv));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryReferent(mDocWeak); nsCOMPtr<nsIDOMDocument> domDoc = GetDOMDocument();
NS_ASSERTION(domDoc, "Need a document"); NS_ASSERTION(domDoc, "Need a document");
rv = docEncoder->Init(domDoc, aFormatType, aFlags); rv = docEncoder->Init(domDoc, aFormatType, aFlags);

View file

@ -37,6 +37,11 @@ interface nsIWeakReference : nsISupports
%{C++ %{C++
virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0; virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
/**
* Returns true if the referring object is alive. Otherwise, false.
*/
virtual bool IsAlive() const = 0;
%} %}
}; };

View file

@ -37,6 +37,7 @@ public:
// nsIWeakReference... // nsIWeakReference...
NS_DECL_NSIWEAKREFERENCE NS_DECL_NSIWEAKREFERENCE
virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override; virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
bool IsAlive() const override { return mReferent != nullptr; }
private: private:
MOZ_WEAKREF_DECL_OWNINGTHREAD MOZ_WEAKREF_DECL_OWNINGTHREAD