--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -56,16 +56,17 @@ public:
}
// nsISupports
NS_DECL_ISUPPORTS
// nsIWeakReference
NS_DECL_NSIWEAKREFERENCE
virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+ virtual bool IsAlive() const override { return mNode != nullptr; }
void NoticeNodeDestruction()
{
mNode = nullptr;
}
private:
~nsNodeWeakReference();
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -33,16 +33,17 @@
#include "mozilla/FlushType.h" // for FlushType::Frames
#include "mozilla/IMEStateManager.h" // for IMEStateManager
#include "mozilla/Preferences.h" // for Preferences
#include "mozilla/dom/Selection.h" // for Selection, etc.
#include "mozilla/Services.h" // for GetObserverService
#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.
#include "nsAString.h" // for nsAString::Length, etc.
#include "nsCCUncollectableMarker.h" // for nsCCUncollectableMarker
#include "nsCaret.h" // for nsCaret
#include "nsCaseTreatment.h"
#include "nsCharTraits.h" // for NS_IS_HIGH_SURROGATE, etc.
@@ -65,17 +66,16 @@
#include "nsIDOMEvent.h" // for nsIDOMEvent
#include "nsIDOMEventListener.h" // for nsIDOMEventListener
#include "nsIDOMEventTarget.h" // for nsIDOMEventTarget
#include "nsIDOMHTMLElement.h" // for nsIDOMHTMLElement
#include "nsIDOMMozNamedAttrMap.h" // for nsIDOMMozNamedAttrMap
#include "nsIDOMMouseEvent.h" // for nsIDOMMouseEvent
#include "nsIDOMNode.h" // for nsIDOMNode, etc.
#include "nsIDOMNodeList.h" // for nsIDOMNodeList
-#include "nsIDocument.h" // for nsIDocument
#include "nsIDocumentStateListener.h" // for nsIDocumentStateListener
#include "nsIEditActionListener.h" // for nsIEditActionListener
#include "nsIEditorObserver.h" // for nsIEditorObserver
#include "nsIEditorSpellCheck.h" // for nsIEditorSpellCheck
#include "nsIFrame.h" // for nsIFrame
#include "nsIHTMLDocument.h" // for nsIHTMLDocument
#include "nsIInlineSpellChecker.h" // for nsIInlineSpellChecker, etc.
#include "nsNameSpaceManager.h" // for kNameSpaceID_None, etc.
@@ -145,17 +145,18 @@ EditorBase::EditorBase()
, mIsInEditAction(false)
, mHidingCaret(false)
, mSpellCheckerDictionaryUpdated(true)
{
}
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();
mComposition = nullptr;
}
// If this editor is still hiding the caret, we need to restore it.
HideCaret(false);
mTxnMgr = nullptr;
@@ -203,74 +204,78 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(EditorBase)
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
nsresult rv =
#endif
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);
- }
- NS_ASSERTION(selCon, "Selection controller should be available at this point");
+ selectionController = do_QueryInterface(presShell);
+ }
+ MOZ_ASSERT(selectionController,
+ "Selection controller should be available at this point");
//set up root element if we are passed one.
if (aRoot)
mRootElement = do_QueryInterface(aRoot);
mUpdateCount=0;
// If this is an editor for <input> or <textarea>, mIMETextNode is always
// recreated with same content. Therefore, we need to forget mIMETextNode,
// but we need to keep storing mIMETextOffset and mIMETextLength becuase
// they are necessary to restore IME selection and replacing composing string
// when this receives eCompositionChange event next time.
if (mIMETextNode && !mIMETextNode->IsInComposedDoc()) {
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
-
- NS_POSTCONDITION(mDocWeak, "bad state");
+ // Show the caret.
+ selectionController->SetCaretReadOnly(false);
+ selectionController->SetDisplaySelection(
+ nsISelectionController::SELECTION_ON);
+ // Show all the selection reflected to user.
+ selectionController->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);
+
+ MOZ_ASSERT(IsInitialized());
// Make sure that the editor will be destroyed properly
mDidPreDestroy = false;
// Make sure that the ediotr will be created properly
mDidPostCreate = false;
return NS_OK;
}
@@ -339,18 +344,19 @@ EditorBase::CreateEventListeners()
if (!mEventListener) {
mEventListener = new EditorEventListener();
}
}
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();
NS_ENSURE_TRUE(rootContent, NS_ERROR_NOT_AVAILABLE);
mEventTarget = do_QueryInterface(rootContent->GetParent());
NS_ENSURE_TRUE(mEventTarget, NS_ERROR_NOT_AVAILABLE);
EditorEventListener* listener =
@@ -361,17 +367,17 @@ EditorBase::InstallEventListeners()
mComposition->StartHandlingComposition(this);
}
return rv;
}
void
EditorBase::RemoveEventListeners()
{
- if (!mDocWeak || !mEventListener) {
+ if (!IsInitialized() || !mEventListener) {
return;
}
reinterpret_cast<EditorEventListener*>(mEventListener.get())->Disconnect();
if (mComposition) {
// Even if this is called, don't release mComposition because this is
// may be reused after reframing.
mComposition->EndHandlingComposition(this);
}
@@ -484,17 +490,17 @@ EditorBase::SetFlags(uint32_t aFlags)
{
if (mFlags == aFlags) {
return NS_OK;
}
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.
return NS_OK;
}
// The flag change may cause the spellchecker state change
if (CanEnableSpellCheck() != spellcheckerWasEnabled) {
@@ -550,44 +556,43 @@ EditorBase::GetIsDocumentEditable(bool*
*aIsDocumentEditable = doc && IsModifiable();
return NS_OK;
}
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
EditorBase::GetDocument(nsIDOMDocument** aDoc)
{
*aDoc = GetDOMDocument().take();
return *aDoc ? NS_OK : NS_ERROR_NOT_INITIALIZED;
}
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>
EditorBase::GetWidget()
{
nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, nullptr);
nsPresContext* pc = ps->GetPresContext();
@@ -623,24 +628,24 @@ EditorBase::GetSelectionController(nsISe
}
selCon.forget(aSel);
return NS_OK;
}
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);
- }
- return selCon.forget();
+ selectionController = do_QueryInterface(presShell);
+ }
+ return selectionController.forget();
}
NS_IMETHODIMP
EditorBase::DeleteSelection(EDirection aAction,
EStripWrappers aStripWrappers)
{
MOZ_ASSERT(aStripWrappers == eStrip || aStripWrappers == eNoStrip);
return DeleteSelectionImpl(aAction, aStripWrappers);
@@ -1038,30 +1043,32 @@ EditorBase::GetDocumentIsEmpty(bool* aDo
return NS_OK;
}
// XXX: The rule system should tell us which node to select all on (ie, the
// root, or the body)
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();
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
return SelectEntireDocument(selection);
}
NS_IMETHODIMP
EditorBase::BeginningOfDocument()
{
- if (!mDocWeak) {
+ // XXX Why doesn't this check if the document is alive?
+ if (!IsInitialized()) {
return NS_ERROR_NOT_INITIALIZED;
}
// get the selection
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
// get the root element
@@ -1088,17 +1095,20 @@ EditorBase::BeginningOfDocument()
int32_t offsetInParent = parent->IndexOf(firstNode);
return selection->Collapse(parent, offsetInParent);
}
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();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
// get the root element
nsINode* node = GetRoot();
NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
@@ -1123,30 +1133,32 @@ EditorBase::GetDocumentModified(bool* ou
*outDocModified = (modCount != 0);
return NS_OK;
}
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;
}
NS_IMETHODIMP
EditorBase::Cut()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
@@ -2002,22 +2014,27 @@ EditorBase::DumpContentTree()
#endif
return NS_OK;
}
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();
}
#endif
return NS_OK;
}
NS_IMETHODIMP
@@ -2307,28 +2324,30 @@ EditorBase::CloneAttributes(Element* aDe
true);
}
}
}
nsresult
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;
}
void
EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsIDOMNode>& aNode,
int32_t& aOffset)
{
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
@@ -4782,32 +4801,37 @@ EditorBase::InitializeSelection(nsIDOMEv
targetNode->HasFlag(NODE_IS_EDITABLE);
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_STATE(selection);
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.
// NOTE: If we set a root element to the ancestor limit, some selection
// methods don't work fine.
if (selectionRootContent->GetParent()) {
selection->SetAncestorLimiter(selectionRootContent);
} else {
@@ -4847,62 +4871,69 @@ EditorBase::InitializeSelection(nsIDOMEv
}
return NS_OK;
}
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);
selection->SetAncestorLimiter(nullptr);
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);
fm->UpdateCaretForCaretBrowsingMode();
if (!HasIndependentSelection()) {
// If this editor doesn't have an independent selection, i.e., it must
// mean that it is an HTML editor, the selection controller is shared with
// presShell. So, even this editor loses focus, other part of the document
// may still have focus.
nsCOMPtr<nsIDocument> doc = GetDocument();
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);
- }
-
- selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
+ selectionController->SetDisplaySelection(
+ nsISelectionController::SELECTION_DISABLED);
+ }
+
+ selectionController->RepaintSelection(
+ nsISelectionController::SELECTION_NORMAL);
return NS_OK;
}
Element*
EditorBase::GetRoot()
{
if (!mRootElement) {
// Let GetRootElement() do the work
@@ -5103,18 +5134,21 @@ EditorBase::IsActiveInDOMWindow()
nsCOMPtr<nsIDOMEventTarget> piTarget = GetDOMEventTarget();
if (!piTarget) {
return false;
}
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,
getter_AddRefs(win));
return SameCOMIdentity(content, piTarget);
}
bool
@@ -5214,20 +5248,21 @@ EditorBase::GetIsInEditAction(bool* aIsI
return NS_OK;
}
int32_t
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[] = {
SelectionType::eIMERawClause,
SelectionType::eIMESelectedRawClause,
SelectionType::eIMEConvertedClause,
SelectionType::eIMESelectedClause
};
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -11,16 +11,17 @@
#include "mozilla/SelectionState.h" // for RangeUpdater, etc.
#include "mozilla/StyleSheet.h" // for StyleSheet
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h" // for WeakPtr
#include "mozilla/dom/Text.h"
#include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr
#include "nsCycleCollectionParticipant.h"
#include "nsGkAtoms.h"
+#include "nsIDocument.h" // for nsIDocument
#include "nsIEditor.h" // for nsIEditor, etc.
#include "nsIObserver.h" // for NS_DECL_NSIOBSERVER, etc.
#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc.
#include "nsISelectionController.h" // for nsISelectionController constants
#include "nsISupportsImpl.h" // for EditorBase::Release, etc.
#include "nsIWeakReferenceUtils.h" // for nsWeakPtr
#include "nsLiteralString.h" // for NS_LITERAL_STRING
#include "nsString.h" // for nsCString
@@ -30,17 +31,16 @@
class nsIAtom;
class nsIContent;
class nsIDOMDocument;
class nsIDOMEvent;
class nsIDOMEventListener;
class nsIDOMEventTarget;
class nsIDOMNode;
-class nsIDocument;
class nsIDocumentStateListener;
class nsIEditActionListener;
class nsIEditorObserver;
class nsIInlineSpellChecker;
class nsINode;
class nsIPresShell;
class nsISupports;
class nsITransaction;
@@ -132,16 +132,67 @@ class EventTarget;
class Selection;
class Text;
} // namespace dom
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")
/**
* Implementation of an editor object. it will be the controller/focal point
* for the main editor services. i.e. the GUIManager, publishing, transaction
* manager, event interfaces. the idea for the event interfaces is to have them
* delegate the actual commands to the editor independent of the XPFE
@@ -178,16 +229,17 @@ protected:
* for someone to derive from the EditorBase later? I don't believe so.
*/
virtual ~EditorBase();
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();
already_AddRefed<nsIWidget> GetWidget();
enum NotificationForEditorObservers
{
eNotifyEditorObserversOfEnd,
eNotifyEditorObserversOfBefore,
@@ -883,17 +935,17 @@ public:
bool IsTabbable() const
{
return IsSingleLineEditor() || IsPasswordEditor() || IsFormWidget() ||
IsInteractionAllowed();
}
bool HasIndependentSelection() const
{
- return !!mSelConWeak;
+ return !!mSelectionControllerWeak;
}
bool IsModifiable() const
{
return !IsReadonly();
}
/**
@@ -981,16 +1033,24 @@ public:
/**
* HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
* with nsCaret::RemoveForceHide(). This does NOT set visibility of
* nsCaret. Therefore, this is stateless.
*/
void HideCaret(bool aHide);
+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
{
eTriUnset,
eTriFalse,
eTriTrue
};
@@ -1002,22 +1062,18 @@ protected:
RefPtr<nsTransactionManager> mTxnMgr;
// Cached root node.
nsCOMPtr<Element> mRootElement;
// Current IME text node.
RefPtr<Text> mIMETextNode;
// 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.
mozilla::UniquePtr<SelectionState> mSelState;
// IME composition this is not null between compositionstart and
// compositionend.
RefPtr<TextComposition> mComposition;
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -159,17 +159,17 @@ HTMLEditor::~HTMLEditor()
}
mTypeInState = nullptr;
mSelectionListenerP = nullptr;
// free any default style propItems
RemoveAllDefaultProperties();
- if (mLinkHandler && mDocWeak) {
+ if (mLinkHandler && IsInitialized()) {
nsCOMPtr<nsIPresShell> ps = GetPresShell();
if (ps && ps->GetPresContext()) {
ps->GetPresContext()->SetLinkHandler(mLinkHandler);
}
}
RemoveEventListeners();
@@ -322,17 +322,17 @@ HTMLEditor::Init(nsIDOMDocument* aDoc,
NS_IMETHODIMP
HTMLEditor::PreDestroy(bool aDestroyingFrames)
{
if (mDidPreDestroy) {
return NS_OK;
}
- nsCOMPtr<nsINode> document = do_QueryReferent(mDocWeak);
+ nsCOMPtr<nsIDocument> document = GetDocument();
if (document) {
document->RemoveMutationObserver(this);
}
while (!mStyleSheetURLs.IsEmpty()) {
RemoveOverrideStyleSheet(mStyleSheetURLs[0]);
}
@@ -362,21 +362,24 @@ HTMLEditor::GetRootElement(nsIDOMElement
nsresult rv = GetBodyElement(getter_AddRefs(bodyElement));
NS_ENSURE_SUCCESS(rv, rv);
if (bodyElement) {
rootElement = bodyElement;
} else {
// If there is no HTML body element,
// we should use the document root element instead.
- nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
- NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
-
- rv = doc->GetDocumentElement(getter_AddRefs(rootElement));
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIDOMDocument> domDocument = GetDOMDocument();
+ if (NS_WARN_IF(!domDocument)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ rv = domDocument->GetDocumentElement(getter_AddRefs(rootElement));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
// Document can have no elements
if (!rootElement) {
return NS_ERROR_NOT_AVAILABLE;
}
}
mRootElement = do_QueryInterface(rootElement);
rootElement.forget(aRootElement);
@@ -435,31 +438,32 @@ HTMLEditor::CreateEventListeners()
if (!mEventListener) {
mEventListener = new HTMLEditorEventListener();
}
}
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.
HTMLEditorEventListener* listener =
reinterpret_cast<HTMLEditorEventListener*>(mEventListener.get());
return listener->Connect(this);
}
void
HTMLEditor::RemoveEventListeners()
{
- if (!mDocWeak) {
+ if (!IsInitialized()) {
return;
}
nsCOMPtr<nsIDOMEventTarget> target = GetDOMEventTarget();
if (target) {
// Both mMouseMotionListenerP and mResizeEventListenerP can be
// registerd with other targets than the DOM event receiver that
@@ -511,17 +515,18 @@ HTMLEditor::InitRules()
mRules = new HTMLEditRules();
}
return mRules->Init(this);
}
NS_IMETHODIMP
HTMLEditor::BeginningOfDocument()
{
- if (!mDocWeak) {
+ // XXX Why doesn't this check if the document is alive?
+ if (!IsInitialized()) {
return NS_ERROR_NOT_INITIALIZED;
}
// Get the selection
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
// Get the root element.
@@ -1190,21 +1195,23 @@ HTMLEditor::ReplaceHeadContentsWithHTML(
AutoRules beginRulesSniffing(this, EditAction::ignore, nsIEditor::eNone);
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
ForceCompositionEnd();
// 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);
NS_ENSURE_TRUE(headNode, NS_ERROR_NULL_POINTER);
// First, make sure there are no return chars in the source. Bad things
// happen if you insert returns (instead of dom newlines, \n) into an editor
// document.
@@ -2708,17 +2715,17 @@ HTMLEditor::InsertLinkAroundSelection(ns
}
}
return NS_OK;
}
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;
int32_t selectedCount;
nsAutoString tagName;
nsresult rv = GetSelectedOrParentTableElement(tagName, &selectedCount,
getter_AddRefs(element));
NS_ENSURE_SUCCESS(rv, rv);
@@ -2756,17 +2763,17 @@ HTMLEditor::SetHTMLBackgroundColor(const
}
NS_IMETHODIMP
HTMLEditor::SetBodyAttribute(const nsAString& aAttribute,
const nsAString& aValue)
{
// 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());
NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
// Use the editor method that goes through the transaction system
return SetAttribute(bodyElement, aAttribute, aValue);
}
@@ -2835,17 +2842,19 @@ HTMLEditor::ReplaceStyleSheet(const nsAS
// Disable last sheet if not the same as new one
if (!mLastStyleSheetURL.IsEmpty() && !mLastStyleSheetURL.Equals(aURL)) {
return EnableStyleSheet(mLastStyleSheetURL, false);
}
return NS_OK;
}
// 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);
nsCOMPtr<nsIURI> uaURI;
nsresult rv = NS_NewURI(getter_AddRefs(uaURI), aURL);
NS_ENSURE_SUCCESS(rv, rv);
return ps->GetDocument()->CSSLoader()->
@@ -2940,17 +2949,19 @@ HTMLEditor::RemoveOverrideStyleSheet(con
RefPtr<StyleSheet> sheet = GetStyleSheetForURL(aURL);
// Make sure we remove the stylesheet from our internal list in all
// cases.
nsresult rv = RemoveStyleSheetFromList(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);
ps->RemoveOverrideStyleSheet(sheet);
ps->RestyleForCSSRuleChanges();
// Remove it from our internal list
return rv;
@@ -2959,35 +2970,35 @@ HTMLEditor::RemoveOverrideStyleSheet(con
NS_IMETHODIMP
HTMLEditor::EnableStyleSheet(const nsAString& aURL,
bool aEnable)
{
RefPtr<StyleSheet> sheet = GetStyleSheetForURL(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);
return sheet->SetDisabled(!aEnable);
}
bool
HTMLEditor::EnableExistingStyleSheet(const nsAString& aURL)
{
RefPtr<StyleSheet> sheet = GetStyleSheetForURL(aURL);
// Enable sheet if already loaded.
if (!sheet) {
return false;
}
// 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.
NS_ERROR("stylo: ServoStyleSheets can't be disabled yet");
return true;
}
sheet->AsGecko()->SetDisabled(false);
return true;
@@ -3360,23 +3371,22 @@ HTMLEditor::GetIsSelectionEditable(bool*
}
}
return NS_OK;
}
static nsresult
SetSelectionAroundHeadChildren(Selection* aSelection,
- nsIWeakReference* aDocWeak)
+ nsCOMPtr<nsIDocument>& aDocument)
{
+ MOZ_ASSERT(aDocument);
+
// Set selection around <head> node
- nsCOMPtr<nsIDocument> doc = do_QueryReferent(aDocWeak);
- NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
-
- dom::Element* headNode = doc->GetHeadElement();
+ dom::Element* headNode = aDocument->GetHeadElement();
NS_ENSURE_STATE(headNode);
// Collapse selection to before first child of the head,
nsresult rv = aSelection->Collapse(headNode, 0);
NS_ENSURE_SUCCESS(rv, rv);
// Then extend it to just after.
uint32_t childCount = headNode->GetChildCount();
@@ -3387,17 +3397,21 @@ NS_IMETHODIMP
HTMLEditor::GetHeadContentsAsHTML(nsAString& aOutputString)
{
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
// 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"),
nsIDocumentEncoder::OutputSelectionOnly,
aOutputString);
if (NS_FAILED(rv)) {
return rv;
}
@@ -4243,28 +4257,30 @@ HTMLEditor::IsVisTextNode(nsIContent* aN
MOZ_ASSERT(aNode);
MOZ_ASSERT(aNode->NodeType() == nsIDOMNode::TEXT_NODE);
MOZ_ASSERT(outIsEmptyNode);
*outIsEmptyNode = true;
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
// something that frames know about, but we aren't supposed to talk to frames.
// 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;
}
} else if (length) {
if (aNode->TextIsOnlyWhitespace()) {
WSRunObject wsRunObj(this, aNode, 0);
nsCOMPtr<nsINode> visNode;
@@ -4771,17 +4787,19 @@ HTMLEditor::CopyLastEditableChildStyles(
nsresult
HTMLEditor::GetElementOrigin(nsIDOMElement* aElement,
int32_t& aX,
int32_t& aY)
{
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);
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
nsIFrame *frame = content->GetPrimaryFrame();
NS_ENSURE_TRUE(frame, NS_OK);
nsIFrame *container = ps->GetAbsoluteContainingBlock(frame);
@@ -4913,38 +4931,39 @@ HTMLEditor::GetReturnInParagraphCreatesN
{
*aCreatesNewParagraph = mCRInParagraphCreatesParagraph;
return NS_OK;
}
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
// If the focused content isn't editable, or it has independent selection,
// we don't have focus.
if (!focusedContent->HasFlag(NODE_IS_EDITABLE) ||
focusedContent->HasIndependentSelection()) {
@@ -4957,38 +4976,42 @@ HTMLEditor::GetFocusedContent()
already_AddRefed<nsIContent>
HTMLEditor::GetFocusedContentForIME()
{
nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
if (!focusedContent) {
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,
getter_AddRefs(win));
if (!content) {
return false;
}
@@ -5001,22 +5024,22 @@ HTMLEditor::IsActiveInDOMWindow()
return false;
}
return true;
}
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
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, nullptr);
nsCOMPtr<nsIDOMNode> focusNode;
nsresult rv = selection->GetFocusNode(getter_AddRefs(focusNode));
NS_ENSURE_SUCCESS(rv, nullptr);
@@ -5035,18 +5058,18 @@ HTMLEditor::GetActiveEditingHost()
}
already_AddRefed<EventTarget>
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();
}
bool
HTMLEditor::ShouldReplaceRootElement()
{
if (!mRootElement) {
// If we don't know what is our root element, we should find our root.
@@ -5096,22 +5119,26 @@ HTMLEditor::ResetRootElementAndEventTarg
}
SyncRealTimeSpell();
}
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;
}
- return htmlDoc->GetBody(aBody);
+ nsCOMPtr<nsIDOMHTMLDocument> domHTMLDocument = do_QueryInterface(document);
+ if (!domHTMLDocument) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ return domHTMLDocument->GetBody(aBody);
}
already_AddRefed<nsINode>
HTMLEditor::GetFocusedNode()
{
nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
if (!focusedContent) {
return nullptr;
@@ -5121,33 +5148,35 @@ HTMLEditor::GetFocusedNode()
NS_ASSERTION(fm, "Focus manager is null");
nsCOMPtr<nsIDOMElement> focusedElement;
fm->GetFocusedElement(getter_AddRefs(focusedElement));
if (focusedElement) {
nsCOMPtr<nsINode> node = do_QueryInterface(focusedElement);
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;
fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
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;
}
bool
HTMLEditor::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent)
{
if (!EditorBase::IsAcceptableInputEvent(aGUIEvent)) {
return false;
@@ -5155,22 +5184,24 @@ HTMLEditor::IsAcceptableInputEvent(Widge
// While there is composition, all composition events in its top level window
// are always fired on the composing editor. Therefore, if this editor has
// composition, the composition events should be handled in this editor.
if (mComposition && aGUIEvent->AsCompositionEvent()) {
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.
nsCOMPtr<nsIDocument> targetDocument = do_QueryInterface(target);
if (targetDocument) {
return targetDocument == document;
}
// Otherwise, check whether the event target is in this document or not.
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -2585,17 +2585,16 @@ HTMLEditor::GetCellIndexes(nsIDOMElement
nsresult rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr,
getter_AddRefs(cell));
if (NS_FAILED(rv) || !cell) {
return NS_ERROR_FAILURE;
}
aCell = cell;
}
- NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsIContent> nodeAsContent( do_QueryInterface(aCell) );
NS_ENSURE_TRUE(nodeAsContent, NS_ERROR_FAILURE);
// frames are not ref counted, so don't use an nsCOMPtr
nsIFrame *layoutObject = nodeAsContent->GetPrimaryFrame();
NS_ENSURE_TRUE(layoutObject, NS_ERROR_FAILURE);
--- a/xpcom/base/nsIWeakReference.idl
+++ b/xpcom/base/nsIWeakReference.idl
@@ -32,16 +32,21 @@ interface nsIWeakReference : nsISupports
* an owning reference to the desired interface. It is designed to look and act exactly
* like (a proxied) |QueryInterface|. Don't hold on to the produced interface permanently;
* that would defeat the purpose of using a non-owning |nsIWeakReference| in the first place.
*/
void QueryReferent( in nsIIDRef uuid, [iid_is(uuid), retval] out nsQIResult result );
%{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;
%}
};
/**
* |nsISupportsWeakReference| is a factory interface which produces appropriate
* instances of |nsIWeakReference|. Weak references in this scheme can only be
* produced for objects that implement this interface.
--- a/xpcom/base/nsWeakReference.cpp
+++ b/xpcom/base/nsWeakReference.cpp
@@ -32,16 +32,17 @@ class nsWeakReference final : public nsI
{
public:
// nsISupports...
NS_DECL_ISUPPORTS
// nsIWeakReference...
NS_DECL_NSIWEAKREFERENCE
size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+ bool IsAlive() const override { return mReferent != nullptr; }
private:
MOZ_WEAKREF_DECL_OWNINGTHREAD
friend class nsSupportsWeakReference;
explicit nsWeakReference(nsSupportsWeakReference* aReferent)
: mReferent(aReferent)