Bug 1372829 - part2: mozilla::EditorBase should cache raw pointer of nsISelectionController and nsIDocument with nsWeakPtr r=froydnj,m_kato

mozilla::EditorBase stores nsISelectionController and nsIDocument with nsWeakPtr.  However, nsWeakPtr requires QI to retrieve actual pointer and it makes some damage to the performance.  If mozilla::WeakPter were available for them, it'd be great.  However, it's not available with nsISelectionController nor nsIDocument because it's possible to implement SupportsWeakPtr only with their subclasses but the subclasses shouldn't be referred by editor.  Therefore, this patch creates mozilla::CachedWeakPtr<class T> which stores both raw pointer (as cache) and nsWeakPtr and when its cache is requested, it checks if the object referred by nsWeakPtr is still alive.

Additionally, this patch hides the members from subclasses of EditorBase for reducing the maintenance cost.

MozReview-Commit-ID: FvtM7453Vv8

--HG--
extra : rebase_source : a524a8ea327c3993645fafa81db8aef65090f1e0
This commit is contained in:
Masayuki Nakano 2017-06-20 00:55:00 +09:00
Родитель 46f0810215
Коммит f337b95b60
7 изменённых файлов: 295 добавлений и 167 удалений

Просмотреть файл

@ -61,6 +61,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()
{

Просмотреть файл

@ -38,6 +38,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.
@ -70,7 +71,6 @@
#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
@ -150,7 +150,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();
@ -208,20 +209,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
@ -230,19 +232,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)
@ -259,13 +263,14 @@ EditorBase::Init(nsIDOMDocument* aDoc,
mIMETextNode = nullptr;
}
/* Show the caret */
selCon->SetCaretReadOnly(false);
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
// Show the caret.
selectionController->SetCaretReadOnly(false);
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
NS_POSTCONDITION(mDocWeak, "bad state");
MOZ_ASSERT(IsInitialized());
// Make sure that the editor will be destroyed properly
mDidPreDestroy = false;
@ -344,8 +349,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();
@ -366,7 +372,7 @@ EditorBase::InstallEventListeners()
void
EditorBase::RemoveEventListeners()
{
if (!mDocWeak || !mEventListener) {
if (!IsInitialized() || !mEventListener) {
return;
}
reinterpret_cast<EditorEventListener*>(mEventListener.get())->Disconnect();
@ -489,7 +495,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.
@ -555,17 +561,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
@ -578,11 +582,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>
@ -628,14 +633,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
@ -1043,7 +1048,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();
@ -1056,7 +1062,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;
}
@ -1093,7 +1100,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();
@ -1128,20 +1138,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;
}
@ -2007,12 +2019,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();
}
@ -2312,18 +2329,20 @@ EditorBase::CloneAttributes(Element* aDest,
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;
}
@ -4787,22 +4806,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.
@ -4852,9 +4876,11 @@ EditorBase::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget)
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);
@ -4864,7 +4890,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);
@ -4879,25 +4905,30 @@ 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);
}
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
selectionController->RepaintSelection(
nsISelectionController::SELECTION_NORMAL);
return NS_OK;
}
@ -5108,8 +5139,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,
@ -5219,10 +5253,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[] = {

Просмотреть файл

@ -16,6 +16,7 @@
#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.
@ -35,7 +36,6 @@ class nsIDOMEvent;
class nsIDOMEventListener;
class nsIDOMEventTarget;
class nsIDOMNode;
class nsIDocument;
class nsIDocumentStateListener;
class nsIEditActionListener;
class nsIEditorObserver;
@ -137,6 +137,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")
@ -183,6 +234,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();
@ -888,7 +940,7 @@ public:
bool HasIndependentSelection() const
{
return !!mSelConWeak;
return !!mSelectionControllerWeak;
}
bool IsModifiable() const
@ -986,6 +1038,14 @@ public:
*/
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
{
@ -1007,12 +1067,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.

Просмотреть файл

@ -164,7 +164,7 @@ HTMLEditor::~HTMLEditor()
// free any default style propItems
RemoveAllDefaultProperties();
if (mLinkHandler && mDocWeak) {
if (mLinkHandler && IsInitialized()) {
nsCOMPtr<nsIPresShell> ps = GetPresShell();
if (ps && ps->GetPresContext()) {
@ -327,7 +327,7 @@ HTMLEditor::PreDestroy(bool aDestroyingFrames)
return NS_OK;
}
nsCOMPtr<nsINode> document = do_QueryReferent(mDocWeak);
nsCOMPtr<nsIDocument> document = GetDocument();
if (document) {
document->RemoveMutationObserver(this);
}
@ -367,11 +367,14 @@ HTMLEditor::GetRootElement(nsIDOMElement** aRootElement)
} 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;
@ -440,8 +443,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.
@ -454,7 +458,7 @@ HTMLEditor::InstallEventListeners()
void
HTMLEditor::RemoveEventListeners()
{
if (!mDocWeak) {
if (!IsInitialized()) {
return;
}
@ -516,7 +520,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;
}
@ -1195,11 +1200,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);
@ -2713,7 +2720,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;
@ -2761,7 +2768,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());
@ -2840,7 +2847,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);
@ -2945,7 +2954,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);
@ -2964,8 +2975,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);
return sheet->SetDisabled(!aEnable);
}
@ -2981,8 +2992,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.
@ -3365,13 +3376,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,
@ -3392,7 +3402,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"),
@ -4248,10 +4262,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
@ -4259,7 +4274,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;
@ -4776,7 +4792,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);
@ -4918,28 +4936,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
@ -4962,28 +4981,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,
@ -5006,12 +5029,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
@ -5040,8 +5063,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();
}
@ -5101,12 +5124,16 @@ HTMLEditor::ResetRootElementAndEventTarget()
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>
@ -5126,14 +5153,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;
@ -5141,8 +5167,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;
}
@ -5160,12 +5189,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.

Просмотреть файл

@ -2590,7 +2590,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);

Просмотреть файл

@ -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;
%}
};

Просмотреть файл

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