diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 482e39e72..6fd0460e6 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -17,6 +17,7 @@ #include "mozilla/CORSMode.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" +#include "mozilla/HTMLEditor.h" #include "mozilla/InternalMutationEvent.h" #include "mozilla/Likely.h" #include "mozilla/MemoryReporting.h" diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp index 7aa739eb9..c50f8ccc6 100644 --- a/editor/libeditor/EditorBase.cpp +++ b/editor/libeditor/EditorBase.cpp @@ -142,6 +142,7 @@ EditorBase::EditorBase() , mDispatchInputEvent(true) , mIsInEditAction(false) , mHidingCaret(false) + , mIsHTMLEditorClass(false) { } diff --git a/editor/libeditor/EditorBase.h b/editor/libeditor/EditorBase.h index 8c4d6eadf..82ee6bb12 100644 --- a/editor/libeditor/EditorBase.h +++ b/editor/libeditor/EditorBase.h @@ -115,6 +115,7 @@ class DeleteNodeTransaction; class DeleteTextTransaction; class EditAggregateTransaction; class ErrorResult; +class HTMLEditor; class InsertNodeTransaction; class InsertTextTransaction; class JoinNodeTransaction; @@ -122,6 +123,7 @@ class PlaceholderTransaction; class RemoveStyleSheetTransaction; class SplitNodeTransaction; class TextComposition; +class TextEditor; struct EditorDOMPoint; namespace dom { @@ -1118,14 +1120,32 @@ protected: bool mIsInEditAction; // Whether caret is hidden forcibly. bool mHidingCaret; + // Whether we are an HTML editor class. + bool mIsHTMLEditorClass; friend bool NSCanUnload(nsISupports* serviceMgr); friend class AutoRules; friend class AutoSelectionRestorer; friend class AutoTransactionsConserveSelection; friend class RangeUpdater; + friend class nsIEditor; }; } // namespace mozilla +// nsIEditor helper functions. +// Here because of code context. +mozilla::EditorBase* +nsIEditor::AsEditorBase() +{ + return static_cast(this); +} + +const mozilla::EditorBase* +nsIEditor::AsEditorBase() const +{ + return static_cast(this); +} + + #endif // #ifndef mozilla_EditorBase_h diff --git a/editor/libeditor/HTMLEditRules.cpp b/editor/libeditor/HTMLEditRules.cpp index f174e873e..54dfaf7a9 100644 --- a/editor/libeditor/HTMLEditRules.cpp +++ b/editor/libeditor/HTMLEditRules.cpp @@ -241,9 +241,16 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLEditRules, TextEditRules, NS_IMETHODIMP HTMLEditRules::Init(TextEditor* aTextEditor) { + if (NS_WARN_IF(!aTextEditor)) { + return NS_ERROR_INVALID_ARG; + } + InitFields(); - mHTMLEditor = static_cast(aTextEditor); + mHTMLEditor = aTextEditor->AsHTMLEditor(); + if (NS_WARN_IF(!mHTMLEditor)) { + return NS_ERROR_INVALID_ARG; + } // call through to base class Init nsresult rv = TextEditRules::Init(aTextEditor); diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index 831feb12b..38c2c33be 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -132,6 +132,7 @@ HTMLEditor::HTMLEditor() , mPositionedObjectBorderTop(0) , mGridSize(0) { + mIsHTMLEditorClass = true; } HTMLEditor::~HTMLEditor() @@ -501,7 +502,7 @@ HTMLEditor::InitRules() // instantiate the rules for the html editor mRules = new HTMLEditRules(); } - return mRules->Init(static_cast(this)); + return mRules->Init(this); } NS_IMETHODIMP diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index 83f7cfdcd..469bbeacf 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -1121,4 +1121,20 @@ private: } // namespace mozilla +// nsIEditor helper functions. +// Here because of code context. +mozilla::HTMLEditor* +nsIEditor::AsHTMLEditor() +{ + return static_cast(this)->mIsHTMLEditorClass ? + static_cast(this) : nullptr; +} + +const mozilla::HTMLEditor* +nsIEditor::AsHTMLEditor() const +{ + return static_cast(this)->mIsHTMLEditorClass ? + static_cast(this) : nullptr; +} + #endif // #ifndef mozilla_HTMLEditor_h diff --git a/editor/libeditor/HTMLEditorEventListener.cpp b/editor/libeditor/HTMLEditorEventListener.cpp index aa767519c..3699e11ac 100644 --- a/editor/libeditor/HTMLEditorEventListener.cpp +++ b/editor/libeditor/HTMLEditorEventListener.cpp @@ -30,24 +30,18 @@ namespace mozilla { using namespace dom; -#ifdef DEBUG nsresult HTMLEditorEventListener::Connect(EditorBase* aEditorBase) { - nsCOMPtr htmlEditor = do_QueryObject(aEditorBase); - nsCOMPtr htmlInlineTableEditor = - do_QueryObject(aEditorBase); - NS_PRECONDITION(htmlEditor && htmlInlineTableEditor, - "Set HTMLEditor or its sub class"); - return EditorEventListener::Connect(aEditorBase); -} -#endif - -HTMLEditor* -HTMLEditorEventListener::GetHTMLEditor() -{ - // mEditor must be HTMLEditor or its subclass. - return static_cast(mEditorBase); + if (NS_WARN_IF(!aEditorBase)) { + return NS_ERROR_INVALID_ARG; + } + // Guarantee that mEditorBase is always HTMLEditor. + HTMLEditor* htmlEditor = aEditorBase->AsHTMLEditor(); + if (NS_WARN_IF(!htmlEditor)) { + return NS_ERROR_INVALID_ARG; + } + return EditorEventListener::Connect(htmlEditor); } nsresult @@ -59,7 +53,8 @@ HTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent) // FYI: We need to notify HTML editor of mouseup even if it's consumed // because HTML editor always needs to release grabbing resizer. - HTMLEditor* htmlEditor = GetHTMLEditor(); + HTMLEditor* htmlEditor = mEditorBase->AsHTMLEditor(); + MOZ_ASSERT(htmlEditor); nsCOMPtr target; nsresult rv = aMouseEvent->AsEvent()->GetTarget(getter_AddRefs(target)); @@ -85,7 +80,9 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent) WidgetMouseEvent* mousedownEvent = aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent(); - HTMLEditor* htmlEditor = GetHTMLEditor(); + HTMLEditor* htmlEditor = mEditorBase->AsHTMLEditor(); + MOZ_ASSERT(htmlEditor); + // Contenteditable should disregard mousedowns outside it. // IsAcceptableInputEvent() checks it for a mouse event. if (!htmlEditor->IsAcceptableInputEvent(mousedownEvent)) { @@ -221,13 +218,19 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent) nsresult HTMLEditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent) { + if (NS_WARN_IF(DetachedFromEditor())) { + return NS_OK; + } + nsCOMPtr target; nsresult rv = aMouseEvent->AsEvent()->GetTarget(getter_AddRefs(target)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(target, NS_ERROR_NULL_POINTER); nsCOMPtr element = do_QueryInterface(target); - GetHTMLEditor()->DoInlineTableEditingAction(element); + HTMLEditor* htmlEditor = mEditorBase->AsHTMLEditor(); + MOZ_ASSERT(htmlEditor); + htmlEditor->DoInlineTableEditingAction(element); return EditorEventListener::MouseClick(aMouseEvent); } diff --git a/editor/libeditor/HTMLEditorEventListener.h b/editor/libeditor/HTMLEditorEventListener.h index b97b675b5..69bbf705d 100644 --- a/editor/libeditor/HTMLEditorEventListener.h +++ b/editor/libeditor/HTMLEditorEventListener.h @@ -25,17 +25,13 @@ public: { } -#ifdef DEBUG - // WARNING: You must be use HTMLEditor or its sub class for this class. + // Connect() fails if aEditorBase isn't an HTMLEditor instance. virtual nsresult Connect(EditorBase* aEditorBase) override; -#endif protected: virtual nsresult MouseDown(nsIDOMMouseEvent* aMouseEvent) override; virtual nsresult MouseUp(nsIDOMMouseEvent* aMouseEvent) override; virtual nsresult MouseClick(nsIDOMMouseEvent* aMouseEvent) override; - - inline HTMLEditor* GetHTMLEditor(); }; } // namespace mozilla diff --git a/editor/libeditor/TextEditor.cpp b/editor/libeditor/TextEditor.cpp index e9c6a50c6..baedda6bc 100644 --- a/editor/libeditor/TextEditor.cpp +++ b/editor/libeditor/TextEditor.cpp @@ -10,6 +10,7 @@ #include "gfxFontUtils.h" #include "mozilla/Assertions.h" #include "mozilla/EditorUtils.h" // AutoEditBatch, AutoRules +#include "mozilla/HTMLEditor.h" #include "mozilla/mozalloc.h" #include "mozilla/Preferences.h" #include "mozilla/TextEditRules.h" diff --git a/editor/libeditor/TextEditor.h b/editor/libeditor/TextEditor.h index f3a15280b..ccdbc1d07 100644 --- a/editor/libeditor/TextEditor.h +++ b/editor/libeditor/TextEditor.h @@ -241,4 +241,18 @@ protected: } // namespace mozilla +// nsIEditor helper functions. +// Here because of code context. +mozilla::TextEditor* +nsIEditor::AsTextEditor() +{ + return static_cast(this); +} + +const mozilla::TextEditor* +nsIEditor::AsTextEditor() const +{ + return static_cast(this); +} + #endif // #ifndef mozilla_TextEditor_h diff --git a/editor/nsIEditor.idl b/editor/nsIEditor.idl index 0f2177d18..3b8748289 100644 --- a/editor/nsIEditor.idl +++ b/editor/nsIEditor.idl @@ -31,6 +31,14 @@ struct IMEState; native IMEState(mozilla::widget::IMEState); +%{C++ +namespace mozilla { +class EditorBase; +class HTMLEditor; +class TextEditor; +} // namespace mozilla +%} + [scriptable, uuid(094be624-f0bf-400f-89e2-6a84baab9474)] interface nsIEditor : nsISupports { @@ -589,4 +597,34 @@ interface nsIEditor : nsISupports * whether this editor has active IME transaction */ readonly attribute boolean composing; + +%{C++ + /** + * AsEditorBase() returns a pointer to EditorBase class. + * + * In order to avoid circular dependency issues, this method is defined + * in mozilla/EditorBase.h. Consumers need to #include that header. + */ + inline mozilla::EditorBase* AsEditorBase(); + inline const mozilla::EditorBase* AsEditorBase() const; + + /** + * AsTextEditor() returns a pointer to TextEditor class. + * + * In order to avoid circular dependency issues, this method is defined + * in mozilla/TextEditor.h. Consumers need to #include that header. + */ + inline mozilla::TextEditor* AsTextEditor(); + inline const mozilla::TextEditor* AsTextEditor() const; + + /** + * AsHTMLEditor() returns a pointer to HTMLEditor class. + * + * In order to avoid circular dependency issues, this method is defined + * in mozilla/HTMLEditor.h. Consumers need to #include that header. + */ + inline mozilla::HTMLEditor* AsHTMLEditor(); + inline const mozilla::HTMLEditor* AsHTMLEditor() const; +%} + };