1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef mozilla_EditorBase_h
7 #define mozilla_EditorBase_h
8 
9 #include "mozilla/intl/BidiEmbeddingLevel.h"
10 #include "mozilla/Assertions.h"          // for MOZ_ASSERT, etc.
11 #include "mozilla/EditAction.h"          // for EditAction and EditSubAction
12 #include "mozilla/EditorDOMPoint.h"      // for EditorDOMPoint
13 #include "mozilla/EventForwards.h"       // for InputEventTargetRanges
14 #include "mozilla/Maybe.h"               // for Maybe
15 #include "mozilla/OwningNonNull.h"       // for OwningNonNull
16 #include "mozilla/TypeInState.h"         // for PropItem, StyleCache
17 #include "mozilla/RangeBoundary.h"       // for RawRangeBoundary, RangeBoundary
18 #include "mozilla/SelectionState.h"      // for RangeUpdater, etc.
19 #include "mozilla/StyleSheet.h"          // for StyleSheet
20 #include "mozilla/TransactionManager.h"  // for TransactionManager
21 #include "mozilla/WeakPtr.h"             // for WeakPtr
22 #include "mozilla/dom/DataTransfer.h"    // for dom::DataTransfer
23 #include "mozilla/dom/HTMLBRElement.h"   // for dom::HTMLBRElement
24 #include "mozilla/dom/Selection.h"
25 #include "mozilla/dom/Text.h"
26 #include "nsAtom.h"    // for nsAtom, nsStaticAtom
27 #include "nsCOMPtr.h"  // for already_AddRefed, nsCOMPtr
28 #include "nsCycleCollectionParticipant.h"
29 #include "nsGkAtoms.h"
30 #include "nsIContentInlines.h"       // for nsINode::IsEditable()
31 #include "nsIEditor.h"               // for nsIEditor, etc.
32 #include "nsISelectionController.h"  // for nsISelectionController constants
33 #include "nsISelectionListener.h"    // for nsISelectionListener
34 #include "nsISupportsImpl.h"         // for EditorBase::Release, etc.
35 #include "nsIWeakReferenceUtils.h"   // for nsWeakPtr
36 #include "nsLiteralString.h"         // for NS_LITERAL_STRING
37 #include "nsPIDOMWindow.h"           // for nsPIDOMWindowInner, etc.
38 #include "nsString.h"                // for nsCString
39 #include "nsTArray.h"                // for nsTArray and nsAutoTArray
40 #include "nsWeakReference.h"         // for nsSupportsWeakReference
41 #include "nscore.h"                  // for nsresult, nsAString, etc.
42 
43 #include <tuple>  // for std::tuple
44 
45 class mozInlineSpellChecker;
46 class nsAtom;
47 class nsCaret;
48 class nsIContent;
49 class nsIDocumentEncoder;
50 class nsIDocumentStateListener;
51 class nsIEditActionListener;
52 class nsINode;
53 class nsIPrincipal;
54 class nsISupports;
55 class nsITransferable;
56 class nsITransaction;
57 class nsITransactionListener;
58 class nsIWidget;
59 class nsRange;
60 
61 namespace mozilla {
62 class AlignStateAtSelection;
63 class AutoRangeArray;
64 class AutoTopLevelEditSubActionNotifier;
65 class AutoTransactionsConserveSelection;
66 class AutoUpdateViewBatch;
67 class ChangeAttributeTransaction;
68 class CompositionTransaction;
69 class CSSEditUtils;
70 class DeleteNodeTransaction;
71 class DeleteRangeTransaction;
72 class DeleteTextTransaction;
73 class EditActionResult;
74 class EditAggregateTransaction;
75 class EditorEventListener;
76 class EditTransactionBase;
77 class ErrorResult;
78 class HTMLEditor;
79 class HTMLEditUtils;
80 class IMEContentObserver;
81 class InsertNodeTransaction;
82 class InsertTextTransaction;
83 class JoinNodesTransaction;
84 class ListElementSelectionState;
85 class ListItemElementSelectionState;
86 class ParagraphStateAtSelection;
87 class PlaceholderTransaction;
88 class PresShell;
89 class ReplaceTextTransaction;
90 class SplitNodeResult;
91 class SplitNodeTransaction;
92 class TextComposition;
93 class TextEditor;
94 class TextInputListener;
95 class TextServicesDocument;
96 class TypeInState;
97 class WhiteSpaceVisibilityKeeper;
98 
99 enum class SplitNodeDirection;  // Declrared in HTMLEditor.h
100 
101 template <typename NodeType>
102 class CreateNodeResultBase;
103 typedef CreateNodeResultBase<dom::Element> CreateElementResult;
104 
105 namespace dom {
106 class AbstractRange;
107 class DataTransfer;
108 class Document;
109 class DragEvent;
110 class Element;
111 class EventTarget;
112 class HTMLBRElement;
113 }  // namespace dom
114 
115 namespace widget {
116 struct IMEState;
117 }  // namespace widget
118 
119 /**
120  * Implementation of an editor object.  it will be the controller/focal point
121  * for the main editor services. i.e. the GUIManager, publishing, transaction
122  * manager, event interfaces. the idea for the event interfaces is to have them
123  * delegate the actual commands to the editor independent of the XPFE
124  * implementation.
125  */
126 class EditorBase : public nsIEditor,
127                    public nsISelectionListener,
128                    public nsSupportsWeakReference {
129  public:
130   /****************************************************************************
131    * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
132    *       classes under libeditor except EditorEventListener and
133    *       HTMLEditorEventListener because each public method which may fire
134    *       eEditorInput event will need to instantiate new stack class for
135    *       managing input type value of eEditorInput and cache some objects
136    *       for smarter handling.  In other words, when you add new root
137    *       method to edit the DOM tree, you can make your new method public.
138    ****************************************************************************/
139 
140   typedef dom::Document Document;
141   typedef dom::Element Element;
142   typedef dom::Selection Selection;
143   typedef dom::Text Text;
144 
145   enum class EditorType { Text, HTML };
146 
147   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
148   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor)
149 
150   // nsIEditor methods
151   NS_DECL_NSIEDITOR
152 
153   // nsISelectionListener method
154   NS_DECL_NSISELECTIONLISTENER
155 
156   /**
157    * The default constructor. This should suffice. the setting of the
158    * interfaces is done after the construction of the editor class.
159    */
160   EditorBase();
161 
IsInitialized()162   bool IsInitialized() const { return !!mDocument; }
Destroyed()163   bool Destroyed() const { return mDidPreDestroy; }
164 
GetDocument()165   Document* GetDocument() const { return mDocument; }
166   nsPIDOMWindowOuter* GetWindow() const;
167   nsPIDOMWindowInner* GetInnerWindow() const;
168 
169   /**
170    * MayHaveMutationEventListeners() returns true when the window may have
171    * mutation event listeners.
172    *
173    * @param aMutationEventType  One or multiple of NS_EVENT_BITS_MUTATION_*.
174    * @return                    true if the editor is an HTMLEditor instance,
175    *                            and at least one of NS_EVENT_BITS_MUTATION_* is
176    *                            set to the window or in debug build.
177    */
178   bool MayHaveMutationEventListeners(
179       uint32_t aMutationEventType = 0xFFFFFFFF) const {
180     if (IsTextEditor()) {
181       // DOM mutation event listeners cannot catch the changes of
182       // <input type="text"> nor <textarea>.
183       return false;
184     }
185 #ifdef DEBUG
186     // On debug build, this should always return true for testing complicated
187     // path without mutation event listeners because when mutation event
188     // listeners do not touch the DOM, editor needs to run as there is no
189     // mutation event listeners.
190     return true;
191 #else   // #ifdef DEBUG
192     nsPIDOMWindowInner* window = GetInnerWindow();
193     return window ? window->HasMutationListeners(aMutationEventType) : false;
194 #endif  // #ifdef DEBUG #else
195   }
196 
197   /**
198    * MayHaveBeforeInputEventListenersForTelemetry() returns true when the
199    * window may have or have had one or more `beforeinput` event listeners.
200    * Note that this may return false even if there is a `beforeinput`.
201    * See nsPIDOMWindowInner::HasBeforeInputEventListenersForTelemetry()'s
202    * comment for the detail.
203    */
MayHaveBeforeInputEventListenersForTelemetry()204   bool MayHaveBeforeInputEventListenersForTelemetry() const {
205     if (const nsPIDOMWindowInner* window = GetInnerWindow()) {
206       return window->HasBeforeInputEventListenersForTelemetry();
207     }
208     return false;
209   }
210 
211   /**
212    * MutationObserverHasObservedNodeForTelemetry() returns true when a node in
213    * the window may have been observed by the web apps with a mutation observer
214    * (i.e., `MutationObserver.observe()` called by chrome script and addon's
215    * script does not make this returns true).
216    * Note that this may return false even if there is a node observed by
217    * a MutationObserver.  See
218    * nsPIDOMWindowInner::MutationObserverHasObservedNodeForTelemetry()'s comment
219    * for the detail.
220    */
MutationObserverHasObservedNodeForTelemetry()221   bool MutationObserverHasObservedNodeForTelemetry() const {
222     if (const nsPIDOMWindowInner* window = GetInnerWindow()) {
223       return window->MutationObserverHasObservedNodeForTelemetry();
224     }
225     return false;
226   }
227 
228   PresShell* GetPresShell() const;
229   nsPresContext* GetPresContext() const;
230   already_AddRefed<nsCaret> GetCaret() const;
231 
232   already_AddRefed<nsIWidget> GetWidget();
233 
234   nsISelectionController* GetSelectionController() const;
235 
236   nsresult GetSelection(SelectionType aSelectionType,
237                         Selection** aSelection) const;
238 
239   Selection* GetSelection(
240       SelectionType aSelectionType = SelectionType::eNormal) const {
241     if (aSelectionType == SelectionType::eNormal &&
242         IsEditActionDataAvailable()) {
243       return &SelectionRef();
244     }
245     nsISelectionController* sc = GetSelectionController();
246     if (!sc) {
247       return nullptr;
248     }
249     Selection* selection = sc->GetSelection(ToRawSelectionType(aSelectionType));
250     return selection;
251   }
252 
253   /**
254    * Fast non-refcounting editor root element accessor
255    */
GetRoot()256   Element* GetRoot() const { return mRootElement; }
257 
258   /**
259    * Likewise, but gets the text control element instead of the root for
260    * plaintext editors.
261    */
262   Element* GetExposedRoot() const;
263 
264   /**
265    * Set or unset TextInputListener.  If setting non-nullptr when the editor
266    * already has a TextInputListener, this will crash in debug build.
267    */
268   void SetTextInputListener(TextInputListener* aTextInputListener);
269 
270   /**
271    * Set or unset IMEContentObserver.  If setting non-nullptr when the editor
272    * already has an IMEContentObserver, this will crash in debug build.
273    */
274   void SetIMEContentObserver(IMEContentObserver* aIMEContentObserver);
275 
276   /**
277    * Returns current composition.
278    */
279   TextComposition* GetComposition() const;
280 
281   /**
282    * Get preferred IME status of current widget.
283    */
284   virtual nsresult GetPreferredIMEState(widget::IMEState* aState);
285 
286   /**
287    * Returns true if there is composition string and not fixed.
288    */
289   bool IsIMEComposing() const;
290 
291   /**
292    * Commit composition if there is.
293    * Note that when there is a composition, this requests to commit composition
294    * to native IME.  Therefore, when there is composition, this can do anything.
295    * For example, the editor instance, the widget or the process itself may
296    * be destroyed.
297    */
298   nsresult CommitComposition();
299 
300   /**
301    * ToggleTextDirection() toggles text-direction of the root element.
302    *
303    * @param aPrincipal          Set subject principal if it may be called by
304    *                            JS.  If set to nullptr, will be treated as
305    *                            called by system.
306    */
307   MOZ_CAN_RUN_SCRIPT nsresult
308   ToggleTextDirectionAsAction(nsIPrincipal* aPrincipal = nullptr);
309 
310   /**
311    * SwitchTextDirectionTo() sets the text-direction of the root element to
312    * LTR or RTL.
313    */
314   enum class TextDirection {
315     eLTR,
316     eRTL,
317   };
318   MOZ_CAN_RUN_SCRIPT void SwitchTextDirectionTo(TextDirection aTextDirection);
319 
320   /**
321    * Finalizes selection and caret for the editor.
322    */
323   nsresult FinalizeSelection();
324 
325   /**
326    * Returns true if selection is in an editable element and both the range
327    * start and the range end are editable.  E.g., even if the selection range
328    * includes non-editable elements, returns true when one of common ancestors
329    * of the range start and the range end is editable.  Otherwise, false.
330    */
331   bool IsSelectionEditable();
332 
333   /**
334    * Returns number of undo or redo items.
335    */
NumberOfUndoItems()336   size_t NumberOfUndoItems() const {
337     return mTransactionManager ? mTransactionManager->NumberOfUndoItems() : 0;
338   }
NumberOfRedoItems()339   size_t NumberOfRedoItems() const {
340     return mTransactionManager ? mTransactionManager->NumberOfRedoItems() : 0;
341   }
342 
343   /**
344    * Returns number of maximum undo/redo transactions.
345    */
NumberOfMaximumTransactions()346   int32_t NumberOfMaximumTransactions() const {
347     return mTransactionManager
348                ? mTransactionManager->NumberOfMaximumTransactions()
349                : 0;
350   }
351 
352   /**
353    * Returns true if this editor can store transactions for undo/redo.
354    */
IsUndoRedoEnabled()355   bool IsUndoRedoEnabled() const {
356     return mTransactionManager &&
357            mTransactionManager->NumberOfMaximumTransactions();
358   }
359 
360   /**
361    * Return true if it's possible to undo/redo right now.
362    */
CanUndo()363   bool CanUndo() const {
364     return IsUndoRedoEnabled() && NumberOfUndoItems() > 0;
365   }
CanRedo()366   bool CanRedo() const {
367     return IsUndoRedoEnabled() && NumberOfRedoItems() > 0;
368   }
369 
370   /**
371    * Enables or disables undo/redo feature.  Returns true if it succeeded,
372    * otherwise, e.g., we're undoing or redoing, returns false.
373    */
374   bool EnableUndoRedo(int32_t aMaxTransactionCount = -1) {
375     if (!mTransactionManager) {
376       mTransactionManager = new TransactionManager();
377     }
378     return mTransactionManager->EnableUndoRedo(aMaxTransactionCount);
379   }
DisableUndoRedo()380   bool DisableUndoRedo() {
381     if (!mTransactionManager) {
382       return true;
383     }
384     return mTransactionManager->DisableUndoRedo();
385   }
ClearUndoRedo()386   bool ClearUndoRedo() {
387     if (!mTransactionManager) {
388       return true;
389     }
390     return mTransactionManager->ClearUndoRedo();
391   }
392 
393   /**
394    * See Document::AreClipboardCommandsUnconditionallyEnabled.
395    */
396   bool AreClipboardCommandsUnconditionallyEnabled() const;
397 
398   /**
399    * IsCutCommandEnabled() returns whether cut command can be enabled or
400    * disabled.  This always returns true if we're in non-chrome HTML/XHTML
401    * document.  Otherwise, same as the result of `IsCopyToClipboardAllowed()`.
402    */
403   MOZ_CAN_RUN_SCRIPT bool IsCutCommandEnabled() const;
404 
405   /**
406    * IsCopyCommandEnabled() returns copy command can be enabled or disabled.
407    * This always returns true if we're in non-chrome HTML/XHTML document.
408    * Otherwise, same as the result of `IsCopyToClipboardAllowed()`.
409    */
410   MOZ_CAN_RUN_SCRIPT bool IsCopyCommandEnabled() const;
411 
412   /**
413    * IsCopyToClipboardAllowed() returns true if the selected content can
414    * be copied into the clipboard.  This returns true when:
415    * - `Selection` is not collapsed and we're not a password editor.
416    * - `Selection` is not collapsed and we're a password editor but selection
417    *   range is in unmasked range.
418    */
IsCopyToClipboardAllowed()419   bool IsCopyToClipboardAllowed() const {
420     AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
421     if (NS_WARN_IF(!editActionData.CanHandle())) {
422       return false;
423     }
424     return IsCopyToClipboardAllowedInternal();
425   }
426 
427   /**
428    * HandleDropEvent() is called from EditorEventListener::Drop that is handler
429    * of drop event.
430    */
431   MOZ_CAN_RUN_SCRIPT nsresult HandleDropEvent(dom::DragEvent* aDropEvent);
432 
433   MOZ_CAN_RUN_SCRIPT virtual nsresult HandleKeyPressEvent(
434       WidgetKeyboardEvent* aKeyboardEvent);
435 
436   virtual dom::EventTarget* GetDOMEventTarget() const = 0;
437 
438   /**
439    * OnCompositionStart() is called when editor receives eCompositionStart
440    * event which should be handled in this editor.
441    */
442   nsresult OnCompositionStart(WidgetCompositionEvent& aCompositionStartEvent);
443 
444   /**
445    * OnCompositionChange() is called when editor receives an eCompositioChange
446    * event which should be handled in this editor.
447    *
448    * @param aCompositionChangeEvent     eCompositionChange event which should
449    *                                    be handled in this editor.
450    */
451   MOZ_CAN_RUN_SCRIPT nsresult
452   OnCompositionChange(WidgetCompositionEvent& aCompositionChangeEvent);
453 
454   /**
455    * OnCompositionEnd() is called when editor receives an eCompositionChange
456    * event and it's followed by eCompositionEnd event and after
457    * OnCompositionChange() is called.
458    */
459   MOZ_CAN_RUN_SCRIPT void OnCompositionEnd(
460       WidgetCompositionEvent& aCompositionEndEvent);
461 
462   /**
463    * Similar to the setter for wrapWidth, but just sets the editor
464    * internal state without actually changing the content being edited
465    * to wrap at that column.  This should only be used by callers who
466    * are sure that their content is already set up correctly.
467    */
SetWrapColumn(int32_t aWrapColumn)468   void SetWrapColumn(int32_t aWrapColumn) { mWrapColumn = aWrapColumn; }
469 
470   /**
471    * Accessor methods to flags.
472    */
Flags()473   uint32_t Flags() const { return mFlags; }
474 
AddFlags(uint32_t aFlags)475   MOZ_CAN_RUN_SCRIPT nsresult AddFlags(uint32_t aFlags) {
476     const uint32_t kOldFlags = Flags();
477     const uint32_t kNewFlags = (kOldFlags | aFlags);
478     if (kNewFlags == kOldFlags) {
479       return NS_OK;
480     }
481     return SetFlags(kNewFlags);  // virtual call and may be expensive.
482   }
RemoveFlags(uint32_t aFlags)483   MOZ_CAN_RUN_SCRIPT nsresult RemoveFlags(uint32_t aFlags) {
484     const uint32_t kOldFlags = Flags();
485     const uint32_t kNewFlags = (kOldFlags & ~aFlags);
486     if (kNewFlags == kOldFlags) {
487       return NS_OK;
488     }
489     return SetFlags(kNewFlags);  // virtual call and may be expensive.
490   }
AddAndRemoveFlags(uint32_t aAddingFlags,uint32_t aRemovingFlags)491   MOZ_CAN_RUN_SCRIPT nsresult AddAndRemoveFlags(uint32_t aAddingFlags,
492                                                 uint32_t aRemovingFlags) {
493     MOZ_ASSERT(!(aAddingFlags & aRemovingFlags),
494                "Same flags are specified both adding and removing");
495     const uint32_t kOldFlags = Flags();
496     const uint32_t kNewFlags = ((kOldFlags | aAddingFlags) & ~aRemovingFlags);
497     if (kNewFlags == kOldFlags) {
498       return NS_OK;
499     }
500     return SetFlags(kNewFlags);  // virtual call and may be expensive.
501   }
502 
IsInPlaintextMode()503   bool IsInPlaintextMode() const {
504     const bool isPlaintextMode =
505         (mFlags & nsIEditor::eEditorPlaintextMask) != 0;
506     MOZ_ASSERT_IF(IsTextEditor(), isPlaintextMode);
507     return isPlaintextMode;
508   }
509 
IsSingleLineEditor()510   bool IsSingleLineEditor() const {
511     const bool isSingleLineEditor =
512         (mFlags & nsIEditor::eEditorSingleLineMask) != 0;
513     MOZ_ASSERT_IF(isSingleLineEditor, IsTextEditor());
514     return isSingleLineEditor;
515   }
516 
IsPasswordEditor()517   bool IsPasswordEditor() const {
518     const bool isPasswordEditor =
519         (mFlags & nsIEditor::eEditorPasswordMask) != 0;
520     MOZ_ASSERT_IF(isPasswordEditor, IsTextEditor());
521     return isPasswordEditor;
522   }
523 
524   // FYI: Both IsRightToLeft() and IsLeftToRight() may return false if
525   //      the editor inherits the content node's direction.
IsRightToLeft()526   bool IsRightToLeft() const {
527     return (mFlags & nsIEditor::eEditorRightToLeft) != 0;
528   }
IsLeftToRight()529   bool IsLeftToRight() const {
530     return (mFlags & nsIEditor::eEditorLeftToRight) != 0;
531   }
532 
IsReadonly()533   bool IsReadonly() const {
534     return (mFlags & nsIEditor::eEditorReadonlyMask) != 0;
535   }
536 
IsMailEditor()537   bool IsMailEditor() const {
538     return (mFlags & nsIEditor::eEditorMailMask) != 0;
539   }
540 
IsWrapHackEnabled()541   bool IsWrapHackEnabled() const {
542     return (mFlags & nsIEditor::eEditorEnableWrapHackMask) != 0;
543   }
544 
IsInteractionAllowed()545   bool IsInteractionAllowed() const {
546     const bool isInteractionAllowed =
547         (mFlags & nsIEditor::eEditorAllowInteraction) != 0;
548     MOZ_ASSERT_IF(isInteractionAllowed, IsHTMLEditor());
549     return isInteractionAllowed;
550   }
551 
ShouldSkipSpellCheck()552   bool ShouldSkipSpellCheck() const {
553     return (mFlags & nsIEditor::eEditorSkipSpellCheck) != 0;
554   }
555 
HasIndependentSelection()556   bool HasIndependentSelection() const {
557     MOZ_ASSERT_IF(mSelectionController, IsTextEditor());
558     return !!mSelectionController;
559   }
560 
IsModifiable()561   bool IsModifiable() const { return !IsReadonly(); }
562 
563   /**
564    * IsInEditSubAction() return true while the instance is handling an edit
565    * sub-action.  Otherwise, false.
566    */
IsInEditSubAction()567   bool IsInEditSubAction() const { return mIsInEditSubAction; }
568 
569   /**
570    * IsEmpty() checks whether the editor is empty.  If editor has only padding
571    * <br> element for empty editor, returns true.  If editor's root element has
572    * non-empty text nodes or other nodes like <br>, returns false.
573    */
574   virtual bool IsEmpty() const = 0;
575 
576   /**
577    * SuppressDispatchingInputEvent() suppresses or unsuppresses dispatching
578    * "input" event.
579    */
SuppressDispatchingInputEvent(bool aSuppress)580   void SuppressDispatchingInputEvent(bool aSuppress) {
581     mDispatchInputEvent = !aSuppress;
582   }
583 
584   /**
585    * IsSuppressingDispatchingInputEvent() returns true if the editor stops
586    * dispatching input event.  Otherwise, false.
587    */
IsSuppressingDispatchingInputEvent()588   bool IsSuppressingDispatchingInputEvent() const {
589     return !mDispatchInputEvent;
590   }
591 
592   /**
593    * Returns true if markNodeDirty() has any effect.  Returns false if
594    * markNodeDirty() is a no-op.
595    */
OutputsMozDirty()596   bool OutputsMozDirty() const {
597     // Return true for Composer (!IsInteractionAllowed()) or mail
598     // (IsMailEditor()), but false for webpages.
599     return !IsInteractionAllowed() || IsMailEditor();
600   }
601 
602   /**
603    * Get the focused content, if we're focused.  Returns null otherwise.
604    */
605   virtual nsIContent* GetFocusedContent() const;
606 
607   /**
608    * Whether the aGUIEvent should be handled by this editor or not.  When this
609    * returns false, The aGUIEvent shouldn't be handled on this editor,
610    * i.e., The aGUIEvent should be handled by another inner editor or ancestor
611    * elements.
612    */
613   virtual bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) const;
614 
615   /**
616    * FindSelectionRoot() returns a selection root of this editor when aNode
617    * gets focus.  aNode must be a content node or a document node.  When the
618    * target isn't a part of this editor, returns nullptr.  If this is for
619    * designMode, you should set the document node to aNode except that an
620    * element in the document has focus.
621    */
622   virtual Element* FindSelectionRoot(nsINode* aNode) const;
623 
624   /**
625    * This method has to be called by EditorEventListener::Focus.
626    * All actions that have to be done when the editor is focused needs to be
627    * added here.
628    */
629   MOZ_CAN_RUN_SCRIPT void OnFocus(nsINode& aFocusEventTargetNode);
630 
631   /** Resyncs spellchecking state (enabled/disabled).  This should be called
632    * when anything that affects spellchecking state changes, such as the
633    * spellcheck attribute value.
634    */
635   void SyncRealTimeSpell();
636 
637   /**
638    * This method re-initializes the selection and caret state that are for
639    * current editor state. When editor session is destroyed, it always reset
640    * selection state even if this has no focus.  So if destroying editor,
641    * we have to call this method for focused editor to set selection state.
642    */
643   MOZ_CAN_RUN_SCRIPT void ReinitializeSelection(Element& aElement);
644 
645   /**
646    * Do "cut".
647    *
648    * @param aPrincipal          If you know current context is subject
649    *                            principal or system principal, set it.
650    *                            When nullptr, this checks it automatically.
651    */
652   MOZ_CAN_RUN_SCRIPT nsresult CutAsAction(nsIPrincipal* aPrincipal = nullptr);
653 
654   /**
655    * CanPaste() returns true if user can paste something at current selection.
656    */
657   virtual bool CanPaste(int32_t aClipboardType) const = 0;
658 
659   /**
660    * Do "undo" or "redo".
661    *
662    * @param aCount              How many count of transactions should be
663    *                            handled.
664    * @param aPrincipal          Set subject principal if it may be called by
665    *                            JS.  If set to nullptr, will be treated as
666    *                            called by system.
667    */
668   MOZ_CAN_RUN_SCRIPT nsresult UndoAsAction(uint32_t aCount,
669                                            nsIPrincipal* aPrincipal = nullptr);
670   MOZ_CAN_RUN_SCRIPT nsresult RedoAsAction(uint32_t aCount,
671                                            nsIPrincipal* aPrincipal = nullptr);
672 
673   /**
674    * InsertTextAsAction() inserts aStringToInsert at selection.
675    * Although this method is implementation of nsIEditor.insertText(),
676    * this treats the input is an edit action.  If you'd like to insert text
677    * as part of edit action, you probably should use InsertTextAsSubAction().
678    *
679    * @param aStringToInsert     The string to insert.
680    * @param aPrincipal          Set subject principal if it may be called by
681    *                            JS.  If set to nullptr, will be treated as
682    *                            called by system.
683    */
684   MOZ_CAN_RUN_SCRIPT nsresult InsertTextAsAction(
685       const nsAString& aStringToInsert, nsIPrincipal* aPrincipal = nullptr);
686 
687   /**
688    * InsertLineBreakAsAction() is called when user inputs a line break with
689    * Enter or something.  If the instance is `HTMLEditor`, this is called
690    * when Shift + Enter or "insertlinebreak" command.
691    *
692    * @param aPrincipal          Set subject principal if it may be called by
693    *                            JS.  If set to nullptr, will be treated as
694    *                            called by system.
695    */
696   MOZ_CAN_RUN_SCRIPT virtual nsresult InsertLineBreakAsAction(
697       nsIPrincipal* aPrincipal = nullptr) = 0;
698 
699   /**
700    * CanDeleteSelection() returns true if `Selection` is not collapsed and
701    * it's allowed to be removed.
702    */
CanDeleteSelection()703   bool CanDeleteSelection() const {
704     AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
705     if (NS_WARN_IF(!editActionData.CanHandle())) {
706       return false;
707     }
708     return IsModifiable() && !SelectionRef().IsCollapsed();
709   }
710 
711   /**
712    * DeleteSelectionAsAction() removes selection content or content around
713    * caret with transactions.  This should be used for handling it as an
714    * edit action.  If you'd like to remove selection for preparing to insert
715    * something, you probably should use DeleteSelectionAsSubAction().
716    *
717    * @param aDirectionAndAmount How much range should be removed.
718    * @param aStripWrappers      Whether the parent blocks should be removed
719    *                            when they become empty.
720    * @param aPrincipal          Set subject principal if it may be called by
721    *                            JS.  If set to nullptr, will be treated as
722    *                            called by system.
723    */
724   MOZ_CAN_RUN_SCRIPT nsresult
725   DeleteSelectionAsAction(nsIEditor::EDirection aDirectionAndAmount,
726                           nsIEditor::EStripWrappers aStripWrappers,
727                           nsIPrincipal* aPrincipal = nullptr);
728 
729   enum class AllowBeforeInputEventCancelable {
730     No,
731     Yes,
732   };
733 
734   /**
735    * Replace text in aReplaceRange or all text in this editor with aString and
736    * treat the change as inserting the string.
737    *
738    * @param aString             The string to set.
739    * @param aReplaceRange       The range to be replaced.
740    *                            If nullptr, all contents will be replaced.
741    *                            NOTE: Currently, nullptr is not allowed if
742    *                                  the editor is an HTMLEditor.
743    * @param aAllowBeforeInputEventCancelable
744    *                            Whether `beforeinput` event which will be
745    *                            dispatched for this can be cancelable or not.
746    * @param aPrincipal          Set subject principal if it may be called by
747    *                            JS.  If set to nullptr, will be treated as
748    *                            called by system.
749    */
750   MOZ_CAN_RUN_SCRIPT nsresult ReplaceTextAsAction(
751       const nsAString& aString, nsRange* aReplaceRange,
752       AllowBeforeInputEventCancelable aAllowBeforeInputEventCancelable,
753       nsIPrincipal* aPrincipal = nullptr);
754 
755   /**
756    * Can we paste |aTransferable| or, if |aTransferable| is null, will a call
757    * to pasteTransferable later possibly succeed if given an instance of
758    * nsITransferable then? True if the doc is modifiable, and, if
759    * |aTransfeable| is non-null, we have pasteable data in |aTransfeable|.
760    */
761   virtual bool CanPasteTransferable(nsITransferable* aTransferable) = 0;
762 
763   /**
764    * PasteAsAction() pastes clipboard content to Selection.  This method
765    * may dispatch ePaste event first.  If its defaultPrevent() is called,
766    * this does nothing but returns NS_OK.
767    *
768    * @param aClipboardType      nsIClipboard::kGlobalClipboard or
769    *                            nsIClipboard::kSelectionClipboard.
770    * @param aDispatchPasteEvent true if this should dispatch ePaste event
771    *                            before pasting.  Otherwise, false.
772    * @param aPrincipal          Set subject principal if it may be called by
773    *                            JS.  If set to nullptr, will be treated as
774    *                            called by system.
775    */
776   MOZ_CAN_RUN_SCRIPT virtual nsresult PasteAsAction(
777       int32_t aClipboardType, bool aDispatchPasteEvent,
778       nsIPrincipal* aPrincipal = nullptr) = 0;
779 
780   /**
781    * Paste aTransferable at Selection.
782    *
783    * @param aTransferable       Must not be nullptr.
784    * @param aPrincipal          Set subject principal if it may be called by
785    *                            JS.  If set to nullptr, will be treated as
786    *                            called by system.
787    */
788   MOZ_CAN_RUN_SCRIPT virtual nsresult PasteTransferableAsAction(
789       nsITransferable* aTransferable, nsIPrincipal* aPrincipal = nullptr) = 0;
790 
791   /**
792    * PasteAsQuotationAsAction() pastes content in clipboard as quotation.
793    * If the editor is TextEditor or in plaintext mode, will paste the content
794    * with appending ">" to start of each line.
795    * if the editor is HTMLEditor and is not in plaintext mode, will patste it
796    * into newly created blockquote element.
797    *
798    * @param aClipboardType      nsIClipboard::kGlobalClipboard or
799    *                            nsIClipboard::kSelectionClipboard.
800    * @param aDispatchPasteEvent true if this should dispatch ePaste event
801    *                            before pasting.  Otherwise, false.
802    * @param aPrincipal          Set subject principal if it may be called by
803    *                            JS.  If set to nullptr, will be treated as
804    *                            called by system.
805    */
806   MOZ_CAN_RUN_SCRIPT virtual nsresult PasteAsQuotationAsAction(
807       int32_t aClipboardType, bool aDispatchPasteEvent,
808       nsIPrincipal* aPrincipal = nullptr) = 0;
809 
810  protected:  // May be used by friends.
811   class AutoEditActionDataSetter;
812 
813   /**
814    * TopLevelEditSubActionData stores temporary data while we're handling
815    * top-level edit sub-action.
816    */
817   struct MOZ_STACK_CLASS TopLevelEditSubActionData final {
818     friend class AutoEditActionDataSetter;
819 
820     // If we have created a new block element, set to it.
821     RefPtr<Element> mNewBlockElement;
822 
823     // Set selected range before edit.  Then, RangeUpdater keep modifying
824     // the range while we're changing the DOM tree.
825     RefPtr<RangeItem> mSelectedRange;
826 
827     // Computing changed range while we're handling sub actions.
828     RefPtr<nsRange> mChangedRange;
829 
830     // XXX In strict speaking, mCachedInlineStyles isn't enough to cache inline
831     //     styles because inline style can be specified with "style" attribute
832     //     and/or CSS in <style> elements or CSS files.  So, we need to look
833     //     for better implementation about this.
834     // FYI: Initialization cost of AutoStyleCacheArray is expensive and it is
835     //      not used by TextEditor so that we should construct it only when
836     //      we're an HTMLEditor.
837     Maybe<AutoStyleCacheArray> mCachedInlineStyles;
838 
839     // If we tried to delete selection, set to true.
840     bool mDidDeleteSelection;
841 
842     // If we have explicitly set selection inter line, set to true.
843     // `AfterEdit()` or something shouldn't overwrite it in such case.
844     bool mDidExplicitlySetInterLine;
845 
846     // If we have deleted non-collapsed range set to true, there are only 2
847     // cases for now:
848     //   - non-collapsed range was selected.
849     //   - selection was collapsed in a text node and a Unicode character
850     //     was removed.
851     bool mDidDeleteNonCollapsedRange;
852 
853     // If we have deleted parent empty blocks, set to true.
854     bool mDidDeleteEmptyParentBlocks;
855 
856     // If we're a contenteditable editor, we temporarily increase edit count
857     // of the document between `BeforeEdit()` and `AfterEdit()`.  I.e., if
858     // we increased the count in `BeforeEdit()`, we need to decrease it in
859     // `AfterEdit()`, however, the document may be changed to designMode or
860     // non-editable.  Therefore, we need to store with this whether we need
861     // to restore it.
862     bool mRestoreContentEditableCount;
863 
864     // If we explicitly normalized whitespaces around the changed range,
865     // set to true.
866     bool mDidNormalizeWhitespaces;
867 
868     // Set to true by default.  If somebody inserts an HTML fragment
869     // intentionally, any empty elements shouldn't be cleaned up later.  In the
870     // case this is set to false.
871     // TODO: We should not do this by default.  If it's necessary, each edit
872     //       action handler do it by itself instead.  Then, we can avoid such
873     //       unnecessary DOM tree scan.
874     bool mNeedsToCleanUpEmptyElements;
875 
876     /**
877      * The following methods modifies some data of this struct and
878      * `EditSubActionData` struct.  Currently, these are required only
879      * by `HTMLEditor`.  Therefore, for cutting the runtime cost of
880      * `TextEditor`, these methods should be called only by `HTMLEditor`.
881      * But it's fine to use these methods in `TextEditor` if necessary.
882      * If so, you need to call `DidDeleteText()` and `DidInsertText()`
883      * from `SetTextNodeWithoutTransaction()`.
884      */
885     void DidCreateElement(EditorBase& aEditorBase, Element& aNewElement);
886     void DidInsertContent(EditorBase& aEditorBase, nsIContent& aNewContent);
887     void WillDeleteContent(EditorBase& aEditorBase,
888                            nsIContent& aRemovingContent);
889     void DidSplitContent(EditorBase& aEditorBase, nsIContent& aSplitContent,
890                          nsIContent& aNewContent,
891                          SplitNodeDirection aSplitNodeDirection);
892     void DidJoinContents(EditorBase& aEditorBase,
893                          const EditorRawDOMPoint& aJoinedPoint);
894     void DidInsertText(EditorBase& aEditorBase,
895                        const EditorRawDOMPoint& aInsertionBegin,
896                        const EditorRawDOMPoint& aInsertionEnd);
897     void DidDeleteText(EditorBase& aEditorBase,
898                        const EditorRawDOMPoint& aStartInTextNode);
899     void WillDeleteRange(EditorBase& aEditorBase,
900                          const EditorRawDOMPoint& aStart,
901                          const EditorRawDOMPoint& aEnd);
902 
903    private:
Clearfinal904     void Clear() {
905       mDidExplicitlySetInterLine = false;
906       // We don't need to clear other members which are referred only when the
907       // editor is an HTML editor anymore.  Note that if `mSelectedRange` is
908       // non-nullptr, that means that we're in `HTMLEditor`.
909       if (!mSelectedRange) {
910         return;
911       }
912       mNewBlockElement = nullptr;
913       mSelectedRange->Clear();
914       mChangedRange->Reset();
915       if (mCachedInlineStyles.isSome()) {
916         mCachedInlineStyles->Clear();
917       }
918       mDidDeleteSelection = false;
919       mDidDeleteNonCollapsedRange = false;
920       mDidDeleteEmptyParentBlocks = false;
921       mRestoreContentEditableCount = false;
922       mDidNormalizeWhitespaces = false;
923       mNeedsToCleanUpEmptyElements = true;
924     }
925 
926     /**
927      * Extend mChangedRange to include `aNode`.
928      */
929     nsresult AddNodeToChangedRange(const HTMLEditor& aHTMLEditor,
930                                    nsINode& aNode);
931 
932     /**
933      * Extend mChangedRange to include `aPoint`.
934      */
935     nsresult AddPointToChangedRange(const HTMLEditor& aHTMLEditor,
936                                     const EditorRawDOMPoint& aPoint);
937 
938     /**
939      * Extend mChangedRange to include `aStart` and `aEnd`.
940      */
941     nsresult AddRangeToChangedRange(const HTMLEditor& aHTMLEditor,
942                                     const EditorRawDOMPoint& aStart,
943                                     const EditorRawDOMPoint& aEnd);
944 
945     TopLevelEditSubActionData() = default;
946     TopLevelEditSubActionData(const TopLevelEditSubActionData& aOther) = delete;
947   };
948 
949   struct MOZ_STACK_CLASS EditSubActionData final {
950     // While this is set to false, TopLevelEditSubActionData::mChangedRange
951     // shouldn't be modified since in some cases, modifying it in the setter
952     // itself may be faster.  Note that we should affect this only for current
953     // edit sub action since mutation event listener may edit different range.
954     bool mAdjustChangedRangeFromListener;
955 
956    private:
Clearfinal957     void Clear() { mAdjustChangedRangeFromListener = true; }
958 
959     friend EditorBase;
960   };
961 
962  protected:  // AutoEditActionDataSetter, this shouldn't be accessed by friends.
963   /**
964    * SettingDataTransfer enum class is used to specify whether DataTransfer
965    * should be initialized with or without format.  For example, when user
966    * uses Accel + Shift + V to paste text without format, DataTransfer should
967    * have only plain/text data to make web apps treat it without format.
968    */
969   enum class SettingDataTransfer {
970     eWithFormat,
971     eWithoutFormat,
972   };
973 
974   /**
975    * AutoEditActionDataSetter grabs some necessary objects for handling any
976    * edit actions and store the edit action what we're handling.  When this is
977    * created, its pointer is set to the mEditActionData, and this guarantees
978    * the lifetime of grabbing objects until it's destroyed.
979    */
980   class MOZ_STACK_CLASS AutoEditActionDataSetter final {
981    public:
982     // NOTE: aPrincipal will be used when we implement "beforeinput" event.
983     //       It's set only when maybe we shouldn't dispatch it because of
984     //       called by JS.  I.e., if this is nullptr, we can always dispatch
985     //       it.
986     AutoEditActionDataSetter(const EditorBase& aEditorBase,
987                              EditAction aEditAction,
988                              nsIPrincipal* aPrincipal = nullptr);
989     ~AutoEditActionDataSetter();
990 
UpdateEditAction(EditAction aEditAction)991     void UpdateEditAction(EditAction aEditAction) {
992       MOZ_ASSERT(!mHasTriedToDispatchBeforeInputEvent,
993                  "It's too late to update EditAction since this may have "
994                  "already dispatched a beforeinput event");
995       mEditAction = aEditAction;
996     }
997 
998     /**
999      * CanHandle() or CanHandleAndHandleBeforeInput() must be called
1000      * immediately after creating the instance.  If caller does not need to
1001      * handle "beforeinput" event or caller needs to set additional information
1002      * the events later, use the former.  Otherwise, use the latter.  If caller
1003      * uses the former, it's required to call MaybeDispatchBeforeInputEvent() by
1004      * itself.
1005      *
1006      */
CanHandle()1007     [[nodiscard]] bool CanHandle() const {
1008 #ifdef DEBUG
1009       mHasCanHandleChecked = true;
1010 #endif  // #ifdefn DEBUG
1011       // Don't allow to run new edit action when an edit action caused
1012       // destroying the editor while it's being handled.
1013       if (mEditAction != EditAction::eInitializing &&
1014           mEditorWasDestroyedDuringHandlingEditAction) {
1015         NS_WARNING("Editor was destroyed during an edit action being handled");
1016         return false;
1017       }
1018       return IsDataAvailable();
1019     }
1020     [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
CanHandleAndMaybeDispatchBeforeInputEvent()1021     CanHandleAndMaybeDispatchBeforeInputEvent() {
1022       if (NS_WARN_IF(!CanHandle())) {
1023         return NS_ERROR_NOT_INITIALIZED;
1024       }
1025       return MaybeDispatchBeforeInputEvent();
1026     }
1027 
IsDataAvailable()1028     [[nodiscard]] bool IsDataAvailable() const {
1029       return mSelection && mEditorBase.IsInitialized();
1030     }
1031 
1032     /**
1033      * MaybeDispatchBeforeInputEvent() considers whether this instance needs to
1034      * dispatch "beforeinput" event or not.  Then,
1035      * mHasTriedToDispatchBeforeInputEvent is set to true.
1036      *
1037      * @param aDeleteDirectionAndAmount
1038      *                  If `MayEditActionDeleteAroundCollapsedSelection(
1039      *                  mEditAction)` returns true, this must be set.
1040      *                  Otherwise, don't set explicitly.
1041      * @return          If this method actually dispatches "beforeinput" event
1042      *                  and it's canceled, returns
1043      *                  NS_ERROR_EDITOR_ACTION_CANCELED.
1044      */
1045     [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MaybeDispatchBeforeInputEvent(
1046         nsIEditor::EDirection aDeleteDirectionAndAmount = nsIEditor::eNone);
1047 
1048     /**
1049      * MarkAsBeforeInputHasBeenDispatched() should be called only when updating
1050      * the DOM occurs asynchronously from user input (e.g., inserting blob
1051      * object which is loaded asynchronously) and `beforeinput` has already
1052      * been dispatched (always should be so).
1053      */
MarkAsBeforeInputHasBeenDispatched()1054     void MarkAsBeforeInputHasBeenDispatched() {
1055       MOZ_ASSERT(!HasTriedToDispatchBeforeInputEvent());
1056       MOZ_ASSERT(mEditAction == EditAction::ePaste ||
1057                  mEditAction == EditAction::ePasteAsQuotation ||
1058                  mEditAction == EditAction::eDrop);
1059       mHasTriedToDispatchBeforeInputEvent = true;
1060     }
1061 
1062     /**
1063      * MarkAsHandled() is called before dispatching `input` event and notifying
1064      * editor observers.  After this is called, any nested edit action become
1065      * non illegal case.
1066      */
MarkAsHandled()1067     void MarkAsHandled() {
1068       MOZ_ASSERT(!mHandled);
1069       mHandled = true;
1070     }
1071 
1072     /**
1073      * ShouldAlreadyHaveHandledBeforeInputEventDispatching() returns true if the
1074      * edit action requires to handle "beforeinput" event but not yet dispatched
1075      * it nor considered as not dispatched it and can dispatch it when this is
1076      * called.
1077      */
ShouldAlreadyHaveHandledBeforeInputEventDispatching()1078     bool ShouldAlreadyHaveHandledBeforeInputEventDispatching() const {
1079       return !HasTriedToDispatchBeforeInputEvent() &&
1080              NeedsBeforeInputEventHandling(mEditAction) &&
1081              IsBeforeInputEventEnabled() /* &&
1082               // If we still need to dispatch a clipboard event, we should
1083               // dispatch it first, then, we need to dispatch beforeinput
1084               // event later.
1085               !NeedsToDispatchClipboardEvent()*/
1086           ;
1087     }
1088 
1089     /**
1090      * HasTriedToDispatchBeforeInputEvent() returns true if the instance's
1091      * MaybeDispatchBeforeInputEvent() has already been called.
1092      */
HasTriedToDispatchBeforeInputEvent()1093     bool HasTriedToDispatchBeforeInputEvent() const {
1094       return mHasTriedToDispatchBeforeInputEvent;
1095     }
1096 
IsCanceled()1097     bool IsCanceled() const { return mBeforeInputEventCanceled; }
1098 
1099     /**
1100      * Returns a `Selection` for normal selection.  The lifetime is guaranteed
1101      * during alive this instance in the stack.
1102      */
SelectionRef()1103     MOZ_KNOWN_LIVE Selection& SelectionRef() const {
1104       MOZ_ASSERT(!mSelection ||
1105                  (mSelection->GetType() == SelectionType::eNormal));
1106       return *mSelection;
1107     }
1108 
GetPrincipal()1109     nsIPrincipal* GetPrincipal() const { return mPrincipal; }
GetEditAction()1110     EditAction GetEditAction() const { return mEditAction; }
1111 
1112     template <typename PT, typename CT>
SetSpellCheckRestartPoint(const EditorDOMPointBase<PT,CT> & aPoint)1113     void SetSpellCheckRestartPoint(const EditorDOMPointBase<PT, CT>& aPoint) {
1114       MOZ_ASSERT(aPoint.IsSet());
1115       // We should store only container and offset because new content may
1116       // be inserted before referring child.
1117       // XXX Shouldn't we compare whether aPoint is before
1118       //     mSpellCheckRestartPoint if it's set.
1119       mSpellCheckRestartPoint =
1120           EditorDOMPoint(aPoint.GetContainer(), aPoint.Offset());
1121     }
ClearSpellCheckRestartPoint()1122     void ClearSpellCheckRestartPoint() { mSpellCheckRestartPoint.Clear(); }
GetSpellCheckRestartPoint()1123     const EditorDOMPoint& GetSpellCheckRestartPoint() const {
1124       return mSpellCheckRestartPoint;
1125     }
1126 
SetData(const nsAString & aData)1127     void SetData(const nsAString& aData) {
1128       MOZ_ASSERT(!mHasTriedToDispatchBeforeInputEvent,
1129                  "It's too late to set data since this may have already "
1130                  "dispatched a beforeinput event");
1131       mData = aData;
1132     }
GetData()1133     const nsString& GetData() const { return mData; }
1134 
1135     void SetColorData(const nsAString& aData);
1136 
1137     /**
1138      * InitializeDataTransfer(DataTransfer*) sets mDataTransfer to
1139      * aDataTransfer.  In this case, aDataTransfer should not be read/write
1140      * because it'll be set to InputEvent.dataTransfer and which should be
1141      * read-only.
1142      */
1143     void InitializeDataTransfer(dom::DataTransfer* aDataTransfer);
1144     /**
1145      * InitializeDataTransfer(nsITransferable*) creates new DataTransfer
1146      * instance, initializes it with aTransferable and sets mDataTransfer to
1147      * it.
1148      */
1149     void InitializeDataTransfer(nsITransferable* aTransferable);
1150     /**
1151      * InitializeDataTransfer(const nsAString&) creates new DataTransfer
1152      * instance, initializes it with aString and sets mDataTransfer to it.
1153      */
1154     void InitializeDataTransfer(const nsAString& aString);
1155     /**
1156      * InitializeDataTransferWithClipboard() creates new DataTransfer instance,
1157      * initializes it with clipboard and sets mDataTransfer to it.
1158      */
1159     void InitializeDataTransferWithClipboard(
1160         SettingDataTransfer aSettingDataTransfer, int32_t aClipboardType);
GetDataTransfer()1161     dom::DataTransfer* GetDataTransfer() const { return mDataTransfer; }
1162 
1163     /**
1164      * AppendTargetRange() appends aTargetRange to target ranges.  This should
1165      * be used only by edit action handlers which do not want to set target
1166      * ranges to selection ranges.
1167      */
1168     void AppendTargetRange(dom::StaticRange& aTargetRange);
1169 
1170     /**
1171      * Make dispatching `beforeinput` forcibly non-cancelable.
1172      */
MakeBeforeInputEventNonCancelable()1173     void MakeBeforeInputEventNonCancelable() {
1174       mMakeBeforeInputEventNonCancelable = true;
1175     }
1176 
1177     /**
1178      * NotifyOfDispatchingClipboardEvent() is called after dispatching
1179      * a clipboard event.
1180      */
NotifyOfDispatchingClipboardEvent()1181     void NotifyOfDispatchingClipboardEvent() {
1182       MOZ_ASSERT(NeedsToDispatchClipboardEvent());
1183       MOZ_ASSERT(!mHasTriedToDispatchClipboardEvent);
1184       mHasTriedToDispatchClipboardEvent = true;
1185     }
1186 
Abort()1187     void Abort() { mAborted = true; }
IsAborted()1188     bool IsAborted() const { return mAborted; }
1189 
OnEditorDestroy()1190     void OnEditorDestroy() {
1191       if (!mHandled && mHasTriedToDispatchBeforeInputEvent) {
1192         // Remember the editor was destroyed only when this edit action is being
1193         // handled because they are caused by mutation event listeners or
1194         // something other unexpected event listeners.  In the cases, new child
1195         // edit action shouldn't been aborted.
1196         mEditorWasDestroyedDuringHandlingEditAction = true;
1197       }
1198       if (mParentData) {
1199         mParentData->OnEditorDestroy();
1200       }
1201     }
HasEditorDestroyedDuringHandlingEditAction()1202     bool HasEditorDestroyedDuringHandlingEditAction() const {
1203       return mEditorWasDestroyedDuringHandlingEditAction;
1204     }
1205 
1206     void SetTopLevelEditSubAction(EditSubAction aEditSubAction,
1207                                   EDirection aDirection = eNone) {
1208       mTopLevelEditSubAction = aEditSubAction;
1209       TopLevelEditSubActionDataRef().Clear();
1210       switch (mTopLevelEditSubAction) {
1211         case EditSubAction::eInsertNode:
1212         case EditSubAction::eCreateNode:
1213         case EditSubAction::eSplitNode:
1214         case EditSubAction::eInsertText:
1215         case EditSubAction::eInsertTextComingFromIME:
1216         case EditSubAction::eSetTextProperty:
1217         case EditSubAction::eRemoveTextProperty:
1218         case EditSubAction::eRemoveAllTextProperties:
1219         case EditSubAction::eSetText:
1220         case EditSubAction::eInsertLineBreak:
1221         case EditSubAction::eInsertParagraphSeparator:
1222         case EditSubAction::eCreateOrChangeList:
1223         case EditSubAction::eIndent:
1224         case EditSubAction::eOutdent:
1225         case EditSubAction::eSetOrClearAlignment:
1226         case EditSubAction::eCreateOrRemoveBlock:
1227         case EditSubAction::eMergeBlockContents:
1228         case EditSubAction::eRemoveList:
1229         case EditSubAction::eCreateOrChangeDefinitionListItem:
1230         case EditSubAction::eInsertElement:
1231         case EditSubAction::eInsertQuotation:
1232         case EditSubAction::eInsertQuotedText:
1233         case EditSubAction::ePasteHTMLContent:
1234         case EditSubAction::eInsertHTMLSource:
1235         case EditSubAction::eSetPositionToAbsolute:
1236         case EditSubAction::eSetPositionToStatic:
1237         case EditSubAction::eDecreaseZIndex:
1238         case EditSubAction::eIncreaseZIndex:
1239           MOZ_ASSERT(aDirection == eNext);
1240           mDirectionOfTopLevelEditSubAction = eNext;
1241           break;
1242         case EditSubAction::eJoinNodes:
1243         case EditSubAction::eDeleteText:
1244           MOZ_ASSERT(aDirection == ePrevious);
1245           mDirectionOfTopLevelEditSubAction = ePrevious;
1246           break;
1247         case EditSubAction::eUndo:
1248         case EditSubAction::eRedo:
1249         case EditSubAction::eComputeTextToOutput:
1250         case EditSubAction::eCreatePaddingBRElementForEmptyEditor:
1251         case EditSubAction::eNone:
1252           MOZ_ASSERT(aDirection == eNone);
1253           mDirectionOfTopLevelEditSubAction = eNone;
1254           break;
1255         case EditSubAction::eReplaceHeadWithHTMLSource:
1256           // NOTE: Not used with AutoTopLevelEditSubActionNotifier.
1257           mDirectionOfTopLevelEditSubAction = eNone;
1258           break;
1259         case EditSubAction::eDeleteNode:
1260         case EditSubAction::eDeleteSelectedContent:
1261           // Unfortunately, eDeleteNode and eDeleteSelectedContent is used with
1262           // any direction.  We might have specific sub-action for each
1263           // direction, but there are some points referencing
1264           // eDeleteSelectedContent so that we should keep storing direction
1265           // as-is for now.
1266           mDirectionOfTopLevelEditSubAction = aDirection;
1267           break;
1268       }
1269     }
GetTopLevelEditSubAction()1270     EditSubAction GetTopLevelEditSubAction() const {
1271       MOZ_ASSERT(IsDataAvailable());
1272       return mTopLevelEditSubAction;
1273     }
GetDirectionOfTopLevelEditSubAction()1274     EDirection GetDirectionOfTopLevelEditSubAction() const {
1275       return mDirectionOfTopLevelEditSubAction;
1276     }
1277 
TopLevelEditSubActionDataRef()1278     const TopLevelEditSubActionData& TopLevelEditSubActionDataRef() const {
1279       return mParentData ? mParentData->TopLevelEditSubActionDataRef()
1280                          : mTopLevelEditSubActionData;
1281     }
TopLevelEditSubActionDataRef()1282     TopLevelEditSubActionData& TopLevelEditSubActionDataRef() {
1283       return mParentData ? mParentData->TopLevelEditSubActionDataRef()
1284                          : mTopLevelEditSubActionData;
1285     }
1286 
EditSubActionDataRef()1287     const EditSubActionData& EditSubActionDataRef() const {
1288       return mEditSubActionData;
1289     }
EditSubActionDataRef()1290     EditSubActionData& EditSubActionDataRef() { return mEditSubActionData; }
1291 
SavedSelectionRef()1292     SelectionState& SavedSelectionRef() {
1293       return mParentData ? mParentData->SavedSelectionRef() : mSavedSelection;
1294     }
SavedSelectionRef()1295     const SelectionState& SavedSelectionRef() const {
1296       return mParentData ? mParentData->SavedSelectionRef() : mSavedSelection;
1297     }
1298 
RangeUpdaterRef()1299     RangeUpdater& RangeUpdaterRef() {
1300       return mParentData ? mParentData->RangeUpdaterRef() : mRangeUpdater;
1301     }
RangeUpdaterRef()1302     const RangeUpdater& RangeUpdaterRef() const {
1303       return mParentData ? mParentData->RangeUpdaterRef() : mRangeUpdater;
1304     }
1305 
1306     void UpdateSelectionCache(Selection& aSelection);
1307 
1308    private:
1309     bool IsBeforeInputEventEnabled() const;
1310 
NeedsBeforeInputEventHandling(EditAction aEditAction)1311     static bool NeedsBeforeInputEventHandling(EditAction aEditAction) {
1312       MOZ_ASSERT(aEditAction != EditAction::eNone);
1313       switch (aEditAction) {
1314         case EditAction::eNone:
1315         // If we're not handling edit action, we don't need to handle
1316         // "beforeinput" event.
1317         case EditAction::eNotEditing:
1318         // If we're being initialized, we may need to create a padding <br>
1319         // element, but it shouldn't cause `beforeinput` event.
1320         case EditAction::eInitializing:
1321         // If raw level transaction API is used, the API user needs to handle
1322         // both "beforeinput" event and "input" event if it's necessary.
1323         case EditAction::eUnknown:
1324         // Hiding/showing password affects only layout so that we don't need
1325         // to handle beforeinput event for it.
1326         case EditAction::eHidePassword:
1327         // We don't need to dispatch "beforeinput" event before
1328         // "compositionstart".
1329         case EditAction::eStartComposition:
1330         // We don't need to let web apps know the mode change.
1331         case EditAction::eEnableOrDisableCSS:
1332         case EditAction::eEnableOrDisableAbsolutePositionEditor:
1333         case EditAction::eEnableOrDisableResizer:
1334         case EditAction::eEnableOrDisableInlineTableEditingUI:
1335         // We don't need to let contents in chrome's editor to know the size
1336         // change.
1337         case EditAction::eSetWrapWidth:
1338         // While resizing or moving element, we update only shadow, i.e.,
1339         // don't touch to the DOM in content.  Therefore, we don't need to
1340         // dispatch "beforeinput" event.
1341         case EditAction::eResizingElement:
1342         case EditAction::eMovingElement:
1343         // Perhaps, we don't need to dispatch "beforeinput" event for
1344         // padding `<br>` element for empty editor because it's internal
1345         // handling and it should be occurred by another change.
1346         case EditAction::eCreatePaddingBRElementForEmptyEditor:
1347           return false;
1348         default:
1349           return true;
1350       }
1351     }
1352 
NeedsToDispatchClipboardEvent()1353     bool NeedsToDispatchClipboardEvent() const {
1354       if (mHasTriedToDispatchClipboardEvent) {
1355         return false;
1356       }
1357       switch (mEditAction) {
1358         case EditAction::ePaste:
1359         case EditAction::ePasteAsQuotation:
1360         case EditAction::eCut:
1361         case EditAction::eCopy:
1362           return true;
1363         default:
1364           return false;
1365       }
1366     }
1367 
1368     EditorBase& mEditorBase;
1369     RefPtr<Selection> mSelection;
1370     nsTArray<OwningNonNull<Selection>> mRetiredSelections;
1371     nsCOMPtr<nsIPrincipal> mPrincipal;
1372     // EditAction may be nested, for example, a command may be executed
1373     // from mutation event listener which is run while editor changes
1374     // the DOM tree.  In such case, we need to handle edit action separately.
1375     AutoEditActionDataSetter* mParentData;
1376 
1377     // Cached selection for HTMLEditor::AutoSelectionRestorer.
1378     SelectionState mSavedSelection;
1379 
1380     // Utility class object for maintaining preserved ranges.
1381     RangeUpdater mRangeUpdater;
1382 
1383     // The data should be set to InputEvent.data.
1384     nsString mData;
1385 
1386     // The dataTransfer should be set to InputEvent.dataTransfer.
1387     RefPtr<dom::DataTransfer> mDataTransfer;
1388 
1389     // They are used for result of InputEvent.getTargetRanges() of beforeinput.
1390     OwningNonNullStaticRangeArray mTargetRanges;
1391 
1392     // Start point where spell checker should check from.  This is used only
1393     // by TextEditor.
1394     EditorDOMPoint mSpellCheckRestartPoint;
1395 
1396     // Different from mTopLevelEditSubAction, its data should be stored only
1397     // in the most ancestor AutoEditActionDataSetter instance since we don't
1398     // want to pay the copying cost and sync cost.
1399     TopLevelEditSubActionData mTopLevelEditSubActionData;
1400 
1401     // Different from mTopLevelEditSubActionData, this stores temporaly data
1402     // for current edit sub action.
1403     EditSubActionData mEditSubActionData;
1404 
1405     EditAction mEditAction;
1406 
1407     // Different from its data, you can refer "current" AutoEditActionDataSetter
1408     // instance's mTopLevelEditSubAction member since it's copied from the
1409     // parent instance at construction and it's always cleared before this
1410     // won't be overwritten and cleared before destruction.
1411     EditSubAction mTopLevelEditSubAction;
1412 
1413     EDirection mDirectionOfTopLevelEditSubAction;
1414 
1415     bool mAborted;
1416 
1417     // Set to true when this handles "beforeinput" event dispatching.  Note
1418     // that even if "beforeinput" event shouldn't be dispatched for this,
1419     // instance, this is set to true when it's considered.
1420     bool mHasTriedToDispatchBeforeInputEvent;
1421     // Set to true if "beforeinput" event was dispatched and it's canceled.
1422     bool mBeforeInputEventCanceled;
1423     // Set to true if `beforeinput` event must not be cancelable even if
1424     // its inputType is defined as cancelable by the standards.
1425     bool mMakeBeforeInputEventNonCancelable;
1426     // Set to true when the edit action handler tries to dispatch a clipboard
1427     // event.
1428     bool mHasTriedToDispatchClipboardEvent;
1429     // The editor instance may be destroyed once temporarily if `document.write`
1430     // etc runs.  In such case, we should mark this flag of being handled
1431     // edit action.
1432     bool mEditorWasDestroyedDuringHandlingEditAction;
1433     // This is set before dispatching `input` event and notifying editor
1434     // observers.
1435     bool mHandled;
1436 
1437 #ifdef DEBUG
1438     mutable bool mHasCanHandleChecked = false;
1439 #endif  // #ifdef DEBUG
1440 
1441     AutoEditActionDataSetter() = delete;
1442     AutoEditActionDataSetter(const AutoEditActionDataSetter& aOther) = delete;
1443   };
1444 
UpdateEditActionData(const nsAString & aData)1445   void UpdateEditActionData(const nsAString& aData) {
1446     mEditActionData->SetData(aData);
1447   }
1448 
NotifyOfDispatchingClipboardEvent()1449   void NotifyOfDispatchingClipboardEvent() {
1450     MOZ_ASSERT(mEditActionData);
1451     mEditActionData->NotifyOfDispatchingClipboardEvent();
1452   }
1453 
1454  protected:  // May be called by friends.
1455   /****************************************************************************
1456    * Some friend classes are allowed to call the following protected methods.
1457    * However, those methods won't prepare caches of some objects which are
1458    * necessary for them.  So, if you call them from friend classes, you need
1459    * to make sure that AutoEditActionDataSetter is created.
1460    ****************************************************************************/
1461 
IsEditActionCanceled()1462   bool IsEditActionCanceled() const {
1463     MOZ_ASSERT(mEditActionData);
1464     return mEditActionData->IsCanceled();
1465   }
1466 
ShouldAlreadyHaveHandledBeforeInputEventDispatching()1467   bool ShouldAlreadyHaveHandledBeforeInputEventDispatching() const {
1468     MOZ_ASSERT(mEditActionData);
1469     return mEditActionData
1470         ->ShouldAlreadyHaveHandledBeforeInputEventDispatching();
1471   }
1472 
MaybeDispatchBeforeInputEvent()1473   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MaybeDispatchBeforeInputEvent() {
1474     MOZ_ASSERT(mEditActionData);
1475     return mEditActionData->MaybeDispatchBeforeInputEvent();
1476   }
1477 
MarkAsBeforeInputHasBeenDispatched()1478   void MarkAsBeforeInputHasBeenDispatched() {
1479     MOZ_ASSERT(mEditActionData);
1480     return mEditActionData->MarkAsBeforeInputHasBeenDispatched();
1481   }
1482 
HasTriedToDispatchBeforeInputEvent()1483   bool HasTriedToDispatchBeforeInputEvent() const {
1484     return mEditActionData &&
1485            mEditActionData->HasTriedToDispatchBeforeInputEvent();
1486   }
1487 
IsEditActionDataAvailable()1488   bool IsEditActionDataAvailable() const {
1489     return mEditActionData && mEditActionData->IsDataAvailable();
1490   }
1491 
IsTopLevelEditSubActionDataAvailable()1492   bool IsTopLevelEditSubActionDataAvailable() const {
1493     return mEditActionData && !!GetTopLevelEditSubAction();
1494   }
1495 
IsEditActionAborted()1496   bool IsEditActionAborted() const {
1497     MOZ_ASSERT(mEditActionData);
1498     return mEditActionData->IsAborted();
1499   }
1500 
1501   /**
1502    * SelectionRef() returns cached normal Selection.  This is pretty faster than
1503    * EditorBase::GetSelection() if available.
1504    * Note that this never crash unless public methods ignore the result of
1505    * AutoEditActionDataSetter::CanHandle() and keep handling edit action but any
1506    * methods should stop handling edit action if it returns false.
1507    */
SelectionRef()1508   MOZ_KNOWN_LIVE Selection& SelectionRef() const {
1509     MOZ_ASSERT(mEditActionData);
1510     MOZ_ASSERT(mEditActionData->SelectionRef().GetType() ==
1511                SelectionType::eNormal);
1512     return mEditActionData->SelectionRef();
1513   }
1514 
GetEditActionPrincipal()1515   nsIPrincipal* GetEditActionPrincipal() const {
1516     MOZ_ASSERT(mEditActionData);
1517     return mEditActionData->GetPrincipal();
1518   }
1519 
1520   /**
1521    * GetEditAction() returns EditAction which is being handled.  If some
1522    * edit actions are nested, this returns the innermost edit action.
1523    */
GetEditAction()1524   EditAction GetEditAction() const {
1525     return mEditActionData ? mEditActionData->GetEditAction()
1526                            : EditAction::eNone;
1527   }
1528 
1529   /**
1530    * GetInputEventData() returns inserting or inserted text value with
1531    * current edit action.  The result is proper for InputEvent.data value.
1532    */
GetInputEventData()1533   const nsString& GetInputEventData() const {
1534     return mEditActionData ? mEditActionData->GetData() : VoidString();
1535   }
1536 
1537   /**
1538    * GetInputEventDataTransfer() returns inserting or inserted transferable
1539    * content with current edit action.  The result is proper for
1540    * InputEvent.dataTransfer value.
1541    */
GetInputEventDataTransfer()1542   dom::DataTransfer* GetInputEventDataTransfer() const {
1543     return mEditActionData ? mEditActionData->GetDataTransfer() : nullptr;
1544   }
1545 
1546   /**
1547    * GetTopLevelEditSubAction() returns the top level edit sub-action.
1548    * For example, if selected content is being replaced with inserted text,
1549    * while removing selected content, the top level edit sub-action may be
1550    * EditSubAction::eDeleteSelectedContent.  However, while inserting new
1551    * text, the top level edit sub-action may be EditSubAction::eInsertText.
1552    * So, this result means what we are doing right now unless you're looking
1553    * for a case which the method is called via mutation event listener or
1554    * selectionchange event listener which are fired while handling the edit
1555    * sub-action.
1556    */
GetTopLevelEditSubAction()1557   EditSubAction GetTopLevelEditSubAction() const {
1558     return mEditActionData ? mEditActionData->GetTopLevelEditSubAction()
1559                            : EditSubAction::eNone;
1560   }
1561 
1562   /**
1563    * GetDirectionOfTopLevelEditSubAction() returns direction which user
1564    * intended for doing the edit sub-action.
1565    */
GetDirectionOfTopLevelEditSubAction()1566   EDirection GetDirectionOfTopLevelEditSubAction() const {
1567     return mEditActionData
1568                ? mEditActionData->GetDirectionOfTopLevelEditSubAction()
1569                : eNone;
1570   }
1571 
1572   /**
1573    * SavedSelection() returns reference to saved selection which are
1574    * stored by HTMLEditor::AutoSelectionRestorer.
1575    */
SavedSelectionRef()1576   SelectionState& SavedSelectionRef() {
1577     MOZ_ASSERT(IsHTMLEditor());
1578     MOZ_ASSERT(IsEditActionDataAvailable());
1579     return mEditActionData->SavedSelectionRef();
1580   }
SavedSelectionRef()1581   const SelectionState& SavedSelectionRef() const {
1582     MOZ_ASSERT(IsHTMLEditor());
1583     MOZ_ASSERT(IsEditActionDataAvailable());
1584     return mEditActionData->SavedSelectionRef();
1585   }
1586 
RangeUpdaterRef()1587   RangeUpdater& RangeUpdaterRef() {
1588     MOZ_ASSERT(IsEditActionDataAvailable());
1589     return mEditActionData->RangeUpdaterRef();
1590   }
RangeUpdaterRef()1591   const RangeUpdater& RangeUpdaterRef() const {
1592     MOZ_ASSERT(IsEditActionDataAvailable());
1593     return mEditActionData->RangeUpdaterRef();
1594   }
1595 
1596   template <typename PT, typename CT>
SetSpellCheckRestartPoint(const EditorDOMPointBase<PT,CT> & aPoint)1597   void SetSpellCheckRestartPoint(const EditorDOMPointBase<PT, CT>& aPoint) {
1598     MOZ_ASSERT(IsEditActionDataAvailable());
1599     return mEditActionData->SetSpellCheckRestartPoint(aPoint);
1600   }
1601 
ClearSpellCheckRestartPoint()1602   void ClearSpellCheckRestartPoint() {
1603     MOZ_ASSERT(IsEditActionDataAvailable());
1604     return mEditActionData->ClearSpellCheckRestartPoint();
1605   }
1606 
GetSpellCheckRestartPoint()1607   const EditorDOMPoint& GetSpellCheckRestartPoint() const {
1608     MOZ_ASSERT(IsEditActionDataAvailable());
1609     return mEditActionData->GetSpellCheckRestartPoint();
1610   }
1611 
TopLevelEditSubActionDataRef()1612   const TopLevelEditSubActionData& TopLevelEditSubActionDataRef() const {
1613     MOZ_ASSERT(IsEditActionDataAvailable());
1614     return mEditActionData->TopLevelEditSubActionDataRef();
1615   }
TopLevelEditSubActionDataRef()1616   TopLevelEditSubActionData& TopLevelEditSubActionDataRef() {
1617     MOZ_ASSERT(IsEditActionDataAvailable());
1618     return mEditActionData->TopLevelEditSubActionDataRef();
1619   }
1620 
EditSubActionDataRef()1621   const EditSubActionData& EditSubActionDataRef() const {
1622     MOZ_ASSERT(IsEditActionDataAvailable());
1623     return mEditActionData->EditSubActionDataRef();
1624   }
EditSubActionDataRef()1625   EditSubActionData& EditSubActionDataRef() {
1626     MOZ_ASSERT(IsEditActionDataAvailable());
1627     return mEditActionData->EditSubActionDataRef();
1628   }
1629 
1630   /**
1631    * GetCompositionStartPoint() and GetCompositionEndPoint() returns start and
1632    * end point of composition string if there is.  Otherwise, returns non-set
1633    * DOM point.
1634    */
1635   EditorRawDOMPoint GetCompositionStartPoint() const;
1636   EditorRawDOMPoint GetCompositionEndPoint() const;
1637 
1638   /**
1639    * IsSelectionRangeContainerNotContent() returns true if one of container
1640    * of selection ranges is not a content node, i.e., a Document node.
1641    */
1642   bool IsSelectionRangeContainerNotContent() const;
1643 
1644   /**
1645    * OnInputText() is called when user inputs text with keyboard or something.
1646    *
1647    * @param aStringToInsert     The string to insert.
1648    */
1649   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1650   OnInputText(const nsAString& aStringToInsert);
1651 
1652   /**
1653    * InsertTextAsSubAction() inserts aStringToInsert at selection.  This
1654    * should be used for handling it as an edit sub-action.
1655    *
1656    * @param aStringToInsert     The string to insert.
1657    * @param aSelectionHandling  Specify whether selected content should be
1658    *                            deleted or ignored.
1659    */
1660   enum class SelectionHandling { Ignore, Delete };
1661   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertTextAsSubAction(
1662       const nsAString& aStringToInsert, SelectionHandling aSelectionHandling);
1663 
1664   /**
1665    * InsertTextWithTransaction() inserts aStringToInsert to aPointToInsert or
1666    * better insertion point around it.  If aPointToInsert isn't in a text node,
1667    * this method looks for the nearest point in a text node with
1668    * FindBetterInsertionPoint().  If there is no text node, this creates
1669    * new text node and put aStringToInsert to it.
1670    *
1671    * @param aDocument       The document of this editor.
1672    * @param aStringToInsert The string to insert.
1673    * @param aPointToInser   The point to insert aStringToInsert.
1674    *                        Must be valid DOM point.
1675    * @param aPointAfterInsertedString
1676    *                        The point after inserted aStringToInsert.
1677    *                        So, when this method actually inserts string,
1678    *                        this is set to a point in the text node.
1679    *                        Otherwise, this may be set to aPointToInsert.
1680    * @return                When this succeeds to insert the string or
1681    *                        does nothing during composition, returns NS_OK.
1682    *                        Otherwise, an error code.
1683    */
1684   MOZ_CAN_RUN_SCRIPT virtual nsresult InsertTextWithTransaction(
1685       Document& aDocument, const nsAString& aStringToInsert,
1686       const EditorRawDOMPoint& aPointToInsert,
1687       EditorRawDOMPoint* aPointAfterInsertedString = nullptr);
1688 
1689   /**
1690    * InsertTextIntoTextNodeWithTransaction() inserts aStringToInsert into
1691    * aOffset of aTextNode with transaction.
1692    *
1693    * @param aStringToInsert     String to be inserted.
1694    * @param aPointToInsert      The insertion point.
1695    * @param aSuppressIME        true if it's not a part of IME composition.
1696    *                            E.g., adjusting white-spaces during composition.
1697    *                            false, otherwise.
1698    */
1699   MOZ_CAN_RUN_SCRIPT nsresult InsertTextIntoTextNodeWithTransaction(
1700       const nsAString& aStringToInsert,
1701       const EditorDOMPointInText& aPointToInsert, bool aSuppressIME = false);
1702 
1703   /**
1704    * SetTextNodeWithoutTransaction() is optimized path to set new value to
1705    * the text node directly and without transaction.  This is used when
1706    * setting `<input>.value` and `<textarea>.value`.
1707    */
1708   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1709   SetTextNodeWithoutTransaction(const nsAString& aString, Text& aTextNode);
1710 
1711   /**
1712    * DeleteNodeWithTransaction() removes aContent from the DOM tree.
1713    *
1714    * @param aContent    The node which will be removed form the DOM tree.
1715    */
1716   virtual MOZ_CAN_RUN_SCRIPT nsresult
1717   DeleteNodeWithTransaction(nsIContent& aContent);
1718 
1719   /**
1720    * InsertNodeWithTransaction() inserts aContentToInsert before the child
1721    * specified by aPointToInsert.
1722    *
1723    * @param aContentToInsert    The node to be inserted.
1724    * @param aPointToInsert      The insertion point of aContentToInsert.
1725    *                            If this refers end of the container, the
1726    *                            transaction will append the node to the
1727    *                            container.  Otherwise, will insert the node
1728    *                            before child node referred by this.
1729    */
1730   MOZ_CAN_RUN_SCRIPT nsresult InsertNodeWithTransaction(
1731       nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert);
1732 
1733   /**
1734    * InsertPaddingBRElementForEmptyLastLineWithTransaction() creates a padding
1735    * <br> element with setting flags to NS_PADDING_FOR_EMPTY_LAST_LINE and
1736    * inserts it around aPointToInsert.
1737    *
1738    * @param aPointToInsert      The DOM point where should be <br> node inserted
1739    *                            before.
1740    */
1741   [[nodiscard]] MOZ_CAN_RUN_SCRIPT CreateElementResult
1742   InsertPaddingBRElementForEmptyLastLineWithTransaction(
1743       const EditorDOMPoint& aPointToInsert);
1744 
1745   /**
1746    * CloneAttributesWithTransaction() clones all attributes from
1747    * aSourceElement to aDestElement after removing all attributes in
1748    * aDestElement.
1749    */
1750   MOZ_CAN_RUN_SCRIPT void CloneAttributesWithTransaction(
1751       Element& aDestElement, Element& aSourceElement);
1752 
1753   /**
1754    * CloneAttributeWithTransaction() copies aAttribute of aSourceElement to
1755    * aDestElement.  If aSourceElement doesn't have aAttribute, this removes
1756    * aAttribute from aDestElement.
1757    *
1758    * @param aAttribute          Attribute name to be cloned.
1759    * @param aDestElement        Element node which will be set aAttribute or
1760    *                            whose aAttribute will be removed.
1761    * @param aSourceElement      Element node which provides the value of
1762    *                            aAttribute in aDestElement.
1763    */
1764   MOZ_CAN_RUN_SCRIPT nsresult CloneAttributeWithTransaction(
1765       nsAtom& aAttribute, Element& aDestElement, Element& aSourceElement);
1766 
1767   /**
1768    * RemoveAttributeWithTransaction() removes aAttribute from aElement.
1769    *
1770    * @param aElement        Element node which will lose aAttribute.
1771    * @param aAttribute      Attribute name to be removed from aElement.
1772    */
1773   MOZ_CAN_RUN_SCRIPT nsresult
1774   RemoveAttributeWithTransaction(Element& aElement, nsAtom& aAttribute);
1775 
1776   MOZ_CAN_RUN_SCRIPT virtual nsresult RemoveAttributeOrEquivalent(
1777       Element* aElement, nsAtom* aAttribute, bool aSuppressTransaction) = 0;
1778 
1779   /**
1780    * SetAttributeWithTransaction() sets aAttribute of aElement to aValue.
1781    *
1782    * @param aElement        Element node which will have aAttribute.
1783    * @param aAttribute      Attribute name to be set.
1784    * @param aValue          Attribute value be set to aAttribute.
1785    */
1786   MOZ_CAN_RUN_SCRIPT nsresult SetAttributeWithTransaction(
1787       Element& aElement, nsAtom& aAttribute, const nsAString& aValue);
1788 
1789   MOZ_CAN_RUN_SCRIPT virtual nsresult SetAttributeOrEquivalent(
1790       Element* aElement, nsAtom* aAttribute, const nsAString& aValue,
1791       bool aSuppressTransaction) = 0;
1792 
1793   /**
1794    * Method to replace certain CreateElementNS() calls.
1795    *
1796    * @param aTag        Tag you want.
1797    */
1798   already_AddRefed<Element> CreateHTMLContent(const nsAtom* aTag);
1799 
1800   /**
1801    * Creates text node which is marked as "maybe modified frequently" and
1802    * "maybe masked" if this is a password editor.
1803    */
1804   already_AddRefed<nsTextNode> CreateTextNode(const nsAString& aData);
1805 
1806   /**
1807    * DoInsertText(), DoDeleteText(), DoReplaceText() and DoSetText() are
1808    * wrapper of `CharacterData::InsertData()`, `CharacterData::DeleteData()`,
1809    * `CharacterData::ReplaceData()` and `CharacterData::SetData()`.
1810    */
1811   MOZ_CAN_RUN_SCRIPT void DoInsertText(dom::Text& aText, uint32_t aOffset,
1812                                        const nsAString& aStringToInsert,
1813                                        ErrorResult& aRv);
1814   MOZ_CAN_RUN_SCRIPT void DoDeleteText(dom::Text& aText, uint32_t aOffset,
1815                                        uint32_t aCount, ErrorResult& aRv);
1816   MOZ_CAN_RUN_SCRIPT void DoReplaceText(dom::Text& aText, uint32_t aOffset,
1817                                         uint32_t aCount,
1818                                         const nsAString& aStringToInsert,
1819                                         ErrorResult& aRv);
1820   MOZ_CAN_RUN_SCRIPT void DoSetText(dom::Text& aText,
1821                                     const nsAString& aStringToSet,
1822                                     ErrorResult& aRv);
1823 
1824   /**
1825    * DeleteTextWithTransaction() removes text in the range from aTextNode.
1826    *
1827    * @param aTextNode           The text node which should be modified.
1828    * @param aOffset             Start offset of removing text in aTextNode.
1829    * @param aLength             Length of removing text.
1830    */
1831   MOZ_CAN_RUN_SCRIPT nsresult DeleteTextWithTransaction(dom::Text& aTextNode,
1832                                                         uint32_t aOffset,
1833                                                         uint32_t aLength);
1834 
1835   /**
1836    * MarkElementDirty() sets a special dirty attribute on the element.
1837    * Usually this will be called immediately after creating a new node.
1838    *
1839    * @param aElement    The element for which to insert formatting.
1840    */
1841   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult MarkElementDirty(Element& aElement);
1842 
1843   MOZ_CAN_RUN_SCRIPT nsresult
1844   DoTransactionInternal(nsITransaction* aTransaction);
1845 
1846   /**
1847    * Returns true if aNode is our root node.
1848    */
1849   bool IsRoot(const nsINode* inNode) const;
1850   bool IsEditorRoot(const nsINode* aNode) const;
1851 
1852   /**
1853    * Returns true if aNode is a descendant of our root node.
1854    */
1855   bool IsDescendantOfRoot(const nsINode* inNode) const;
1856   bool IsDescendantOfEditorRoot(const nsINode* aNode) const;
1857 
1858   /**
1859    * Returns true when inserting text should be a part of current composition.
1860    */
1861   bool ShouldHandleIMEComposition() const;
1862 
1863   static EditorRawDOMPoint GetStartPoint(const Selection& aSelection);
1864   static EditorRawDOMPoint GetEndPoint(const Selection& aSelection);
1865 
1866   static nsresult GetEndChildNode(const Selection& aSelection,
1867                                   nsIContent** aEndNode);
1868 
1869   /**
1870    * CollapseSelectionToEnd() collapses the selection to the end of the editor.
1871    */
1872   MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult CollapseSelectionToEnd() const;
1873 
1874   /**
1875    * AllowsTransactionsToChangeSelection() returns true if editor allows any
1876    * transactions to change Selection.  Otherwise, transactions shouldn't
1877    * change Selection.
1878    */
AllowsTransactionsToChangeSelection()1879   inline bool AllowsTransactionsToChangeSelection() const {
1880     return mAllowsTransactionsToChangeSelection;
1881   }
1882 
1883   /**
1884    * MakeThisAllowTransactionsToChangeSelection() with true makes this editor
1885    * allow transactions to change Selection.  Otherwise, i.e., with false,
1886    * makes this editor not allow transactions to change Selection.
1887    */
MakeThisAllowTransactionsToChangeSelection(bool aAllow)1888   inline void MakeThisAllowTransactionsToChangeSelection(bool aAllow) {
1889     mAllowsTransactionsToChangeSelection = aAllow;
1890   }
1891 
1892   nsresult HandleInlineSpellCheck(
1893       const EditorDOMPoint& aPreviouslySelectedStart,
1894       const dom::AbstractRange* aRange = nullptr);
1895 
1896   /**
1897    * Likewise, but gets the editor's root instead, which is different for HTML
1898    * editors.
1899    */
1900   virtual Element* GetEditorRoot() const;
1901 
1902   /**
1903    * Whether the editor is active on the DOM window.  Note that when this
1904    * returns true but GetFocusedContent() returns null, it means that this
1905    * editor was focused when the DOM window was active.
1906    */
1907   virtual bool IsActiveInDOMWindow() const;
1908 
1909   /**
1910    * FindBetterInsertionPoint() tries to look for better insertion point which
1911    * is typically the nearest text node and offset in it.
1912    *
1913    * @param aPoint      Insertion point which the callers found.
1914    * @return            Better insertion point if there is.  If not returns
1915    *                    same point as aPoint.
1916    */
1917   EditorRawDOMPoint FindBetterInsertionPoint(
1918       const EditorRawDOMPoint& aPoint) const;
1919 
1920   /**
1921    * HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
1922    * with nsCaret::RemoveForceHide().  This does NOT set visibility of
1923    * nsCaret.  Therefore, this is stateless.
1924    */
1925   void HideCaret(bool aHide);
1926 
1927  protected:  // Edit sub-action handler
1928   /**
1929    * AutoCaretBidiLevelManager() computes bidi level of caret, deleting
1930    * character(s) from aPointAtCaret at construction.  Then, if you'll
1931    * need to extend the selection, you should calls `UpdateCaretBidiLevel()`,
1932    * then, this class may update caret bidi level for you if it's required.
1933    */
1934   class MOZ_RAII AutoCaretBidiLevelManager final {
1935    public:
1936     /**
1937      * @param aEditorBase         The editor.
1938      * @param aPointAtCaret       Collapsed `Selection` point.
1939      * @param aDirectionAndAmount The direction and amount to delete.
1940      */
1941     template <typename PT, typename CT>
1942     AutoCaretBidiLevelManager(const EditorBase& aEditorBase,
1943                               nsIEditor::EDirection aDirectionAndAmount,
1944                               const EditorDOMPointBase<PT, CT>& aPointAtCaret);
1945 
1946     /**
1947      * Failed() returns true if the constructor failed to handle the bidi
1948      * information.
1949      */
Failed()1950     bool Failed() const { return mFailed; }
1951 
1952     /**
1953      * Canceled() returns true if when the caller should stop deleting
1954      * characters since caret position is not visually adjacent the deleting
1955      * characters and user does not wand to delete them in that case.
1956      */
Canceled()1957     bool Canceled() const { return mCanceled; }
1958 
1959     /**
1960      * MaybeUpdateCaretBidiLevel() may update caret bidi level and schedule to
1961      * paint it if they are necessary.
1962      */
1963     void MaybeUpdateCaretBidiLevel(const EditorBase& aEditorBase) const;
1964 
1965    private:
1966     Maybe<mozilla::intl::BidiEmbeddingLevel> mNewCaretBidiLevel;
1967     bool mFailed = false;
1968     bool mCanceled = false;
1969   };
1970 
1971   /**
1972    * UndefineCaretBidiLevel() resets bidi level of the caret.
1973    */
1974   void UndefineCaretBidiLevel() const;
1975 
1976   /**
1977    * Flushing pending notifications if nsFrameSelection requires the latest
1978    * layout information to compute deletion range.  This may destroy the
1979    * editor instance itself.  When this returns false, don't keep doing
1980    * anything.
1981    */
1982   [[nodiscard]] MOZ_CAN_RUN_SCRIPT bool
1983   FlushPendingNotificationsIfToHandleDeletionWithFrameSelection(
1984       nsIEditor::EDirection aDirectionAndAmount) const;
1985 
1986   /**
1987    * DeleteSelectionAsSubAction() removes selection content or content around
1988    * caret with transactions.  This should be used for handling it as an
1989    * edit sub-action.
1990    *
1991    * @param aDirectionAndAmount How much range should be removed.
1992    * @param aStripWrappers      Whether the parent blocks should be removed
1993    *                            when they become empty.  If this instance is
1994    *                            a TextEditor, Must be nsIEditor::eNoStrip.
1995    */
1996   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
1997   DeleteSelectionAsSubAction(nsIEditor::EDirection aDirectionAndAmount,
1998                              nsIEditor::EStripWrappers aStripWrappers);
1999 
2000   /**
2001    * This method handles "delete selection" commands.
2002    * NOTE: Don't call this method recursively from the helper methods since
2003    *       when nobody handled it without canceling and returing an error,
2004    *       this falls it back to `DeleteSelectionWithTransaction()`.
2005    *
2006    * @param aDirectionAndAmount Direction of the deletion.
2007    * @param aStripWrappers      Must be nsIEditor::eNoStrip if this is a
2008    *                            TextEditor instance.  Otherwise,
2009    *                            nsIEditor::eStrip is also valid.
2010    */
2011   [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual EditActionResult
2012   HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
2013                         nsIEditor::EStripWrappers aStripWrappers) = 0;
2014 
2015   /**
2016    * ReplaceSelectionAsSubAction() replaces selection with aString.
2017    *
2018    * @param aString    The string to replace.
2019    */
2020   MOZ_CAN_RUN_SCRIPT nsresult
2021   ReplaceSelectionAsSubAction(const nsAString& aString);
2022 
2023   /**
2024    * HandleInsertText() handles inserting text at selection.
2025    *
2026    * @param aEditSubAction      Must be EditSubAction::eInsertText or
2027    *                            EditSubAction::eInsertTextComingFromIME.
2028    * @param aInsertionString    String to be inserted at selection.
2029    * @param aSelectionHandling  Specify whether selected content should be
2030    *                            deleted or ignored.
2031    */
2032   [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual EditActionResult HandleInsertText(
2033       EditSubAction aEditSubAction, const nsAString& aInsertionString,
2034       SelectionHandling aSelectionHandling) = 0;
2035 
2036   /**
2037    * InsertWithQuotationsAsSubAction() inserts aQuotedText with appending ">"
2038    * to start of every line.
2039    *
2040    * @param aQuotedText         String to insert.  This will be quoted by ">"
2041    *                            automatically.
2042    */
2043   [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult
2044   InsertWithQuotationsAsSubAction(const nsAString& aQuotedText) = 0;
2045 
2046   /**
2047    * PrepareInsertContent() is a helper method of InsertTextAt(),
2048    * HTMLEditor::HTMLWithContextInserter::Run().  They insert content coming
2049    * from clipboard or drag and drop.  Before that, they may need to remove
2050    * selected contents and adjust selection.  This does them instead.
2051    *
2052    * @param aPointToInsert      Point to insert.  Must be set.  Callers
2053    *                            shouldn't use this instance after calling this
2054    *                            method because this method may cause changing
2055    *                            the DOM tree and Selection.
2056    * @param aDoDeleteSelection  true if selected content should be removed.
2057    */
2058   MOZ_CAN_RUN_SCRIPT nsresult PrepareToInsertContent(
2059       const EditorDOMPoint& aPointToInsert, bool aDoDeleteSelection);
2060 
2061   /**
2062    * InsertTextAt() inserts aStringToInsert at aPointToInsert.
2063    *
2064    * @param aStringToInsert     The string which you want to insert.
2065    * @param aPointToInsert      The insertion point.
2066    * @param aDoDeleteSelection  true if you want this to delete selected
2067    *                            content.  Otherwise, false.
2068    */
2069   MOZ_CAN_RUN_SCRIPT nsresult InsertTextAt(const nsAString& aStringToInsert,
2070                                            const EditorDOMPoint& aPointToInsert,
2071                                            bool aDoDeleteSelection);
2072 
2073   /**
2074    * Return true if the data is safe to insert as the source and destination
2075    * principals match, or we are in a editor context where this doesn't matter.
2076    * Otherwise, the data must be sanitized first.
2077    */
2078   bool IsSafeToInsertData(nsIPrincipal* aSourcePrincipal) const;
2079 
2080  protected:  // Called by helper classes.
2081   /**
2082    * OnStartToHandleTopLevelEditSubAction() is called when
2083    * GetTopLevelEditSubAction() is EditSubAction::eNone and somebody starts to
2084    * handle aEditSubAction.
2085    *
2086    * @param aTopLevelEditSubAction              Top level edit sub action which
2087    *                                            will be handled soon.
2088    * @param aDirectionOfTopLevelEditSubAction   Direction of aEditSubAction.
2089    */
2090   MOZ_CAN_RUN_SCRIPT virtual void OnStartToHandleTopLevelEditSubAction(
2091       EditSubAction aTopLevelEditSubAction,
2092       nsIEditor::EDirection aDirectionOfTopLevelEditSubAction,
2093       ErrorResult& aRv);
2094 
2095   /**
2096    * OnEndHandlingTopLevelEditSubAction() is called after
2097    * SetTopLevelEditSubAction() is handled.
2098    */
2099   MOZ_CAN_RUN_SCRIPT virtual nsresult OnEndHandlingTopLevelEditSubAction();
2100 
2101   /**
2102    * OnStartToHandleEditSubAction() and OnEndHandlingEditSubAction() are called
2103    * when starting to handle an edit sub action and ending handling an edit
2104    * sub action.
2105    */
OnStartToHandleEditSubAction()2106   void OnStartToHandleEditSubAction() { EditSubActionDataRef().Clear(); }
OnEndHandlingEditSubAction()2107   void OnEndHandlingEditSubAction() { EditSubActionDataRef().Clear(); }
2108 
2109   /**
2110    * (Begin|End)PlaceholderTransaction() are called by AutoPlaceholderBatch.
2111    * This set of methods are similar to the (Begin|End)Transaction(), but do
2112    * not use the transaction managers batching feature.  Instead we use a
2113    * placeholder transaction to wrap up any further transaction while the
2114    * batch is open.  The advantage of this is that placeholder transactions
2115    * can later merge, if needed.  Merging is unavailable between transaction
2116    * manager batches.
2117    */
2118   MOZ_CAN_RUN_SCRIPT_BOUNDARY void BeginPlaceholderTransaction(
2119       nsStaticAtom& aTransactionName, const char* aRequesterFuncName);
2120   enum class ScrollSelectionIntoView { No, Yes };
2121   MOZ_CAN_RUN_SCRIPT_BOUNDARY void EndPlaceholderTransaction(
2122       ScrollSelectionIntoView aScrollSelectionIntoView,
2123       const char* aRequesterFuncName);
2124 
2125   void BeginUpdateViewBatch(const char* aRequesterFuncName);
2126   MOZ_CAN_RUN_SCRIPT void EndUpdateViewBatch(const char* aRequesterFuncName);
2127 
2128   /**
2129    * Used by HTMLEditor::AutoTransactionBatch, nsIEditor::BeginTransaction
2130    * and nsIEditor::EndTransation.  After calling BeginTransactionInternal(),
2131    * all transactions will be treated as an atomic transaction.  I.e., two or
2132    * more transactions are undid once.
2133    * XXX What's the difference with PlaceholderTransaction? Should we always
2134    *     use it instead?
2135    */
2136   MOZ_CAN_RUN_SCRIPT void BeginTransactionInternal(
2137       const char* aRequesterFuncName);
2138   MOZ_CAN_RUN_SCRIPT void EndTransactionInternal(
2139       const char* aRequesterFuncName);
2140 
2141  protected:  // Shouldn't be used by friend classes
2142   /**
2143    * The default destructor. This should suffice. Should this be pure virtual
2144    * for someone to derive from the EditorBase later? I don't believe so.
2145    */
2146   virtual ~EditorBase();
2147 
2148   /**
2149    * @param aDocument   The dom document interface being observed
2150    * @param aRootElement
2151    *                    This is the root of the editable section of this
2152    *                    document. If it is null then we get root from document
2153    *                    body.
2154    * @param aSelectionController
2155    *                    The selection controller of selections which will be
2156    *                    used in this editor.
2157    * @param aFlags      Some of nsIEditor::eEditor*Mask flags.
2158    */
2159   MOZ_CAN_RUN_SCRIPT nsresult
2160   InitInternal(Document& aDocument, Element* aRootElement,
2161                nsISelectionController& aSelectionController, uint32_t aFlags);
2162 
2163   /**
2164    * PostCreateInternal() should be called after InitInternal(), and is the time
2165    * that the editor tells its documentStateObservers that the document has been
2166    * created.
2167    */
2168   MOZ_CAN_RUN_SCRIPT nsresult PostCreateInternal();
2169 
2170   /**
2171    * PreDestroyInternal() is called before the editor goes away, and gives the
2172    * editor a chance to tell its documentStateObservers that the document is
2173    * going away.
2174    */
2175   MOZ_CAN_RUN_SCRIPT virtual void PreDestroyInternal();
2176 
GetEditorType()2177   MOZ_ALWAYS_INLINE EditorType GetEditorType() const {
2178     return mIsHTMLEditorClass ? EditorType::HTML : EditorType::Text;
2179   }
2180 
2181   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult EnsureEmptyTextFirstChild();
2182 
2183   /**
2184    * InitEditorContentAndSelection() may insert a padding `<br>` element for
2185    * if it's required in the anonymous `<div>` element or `<body>` element and
2186    * collapse selection at the end if there is no selection ranges.
2187    */
2188   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InitEditorContentAndSelection();
2189 
WrapWidth()2190   int32_t WrapWidth() const { return mWrapColumn; }
2191 
2192   /**
2193    * ToGenericNSResult() computes proper nsresult value for the editor users.
2194    * This should be used only when public methods return result of internal
2195    * methods.
2196    */
ToGenericNSResult(nsresult aRv)2197   static inline nsresult ToGenericNSResult(nsresult aRv) {
2198     switch (aRv) {
2199       // If the editor is destroyed while handling an edit action, editor needs
2200       // to stop handling it.  However, editor throw exception in this case
2201       // because Chrome does not throw exception even in this case.
2202       case NS_ERROR_EDITOR_DESTROYED:
2203         return NS_OK;
2204       // If editor meets unexpected DOM tree due to modified by mutation event
2205       // listener, editor needs to stop handling it.  However, editor shouldn't
2206       // return error for the users because Chrome does not throw exception in
2207       // this case.
2208       case NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE:
2209         return NS_OK;
2210       // If the editing action is canceled by event listeners, editor needs
2211       // to stop handling it.  However, editor shouldn't return error for
2212       // the callers but they should be able to distinguish whether it's
2213       // canceled or not.  Although it's DOM specific code, let's return
2214       // DOM_SUCCESS_DOM_NO_OPERATION here.
2215       case NS_ERROR_EDITOR_ACTION_CANCELED:
2216         return NS_SUCCESS_DOM_NO_OPERATION;
2217       // If there is no selection range or editable selection ranges, editor
2218       // needs to stop handling it.  However, editor shouldn't return error for
2219       // the callers to avoid throwing exception.  However, they may want to
2220       // check whether it works or not.  Therefore, we should return
2221       // NS_SUCCESS_DOM_NO_OPERATION instead.
2222       case NS_ERROR_EDITOR_NO_EDITABLE_RANGE:
2223         return NS_SUCCESS_DOM_NO_OPERATION;
2224       default:
2225         return aRv;
2226     }
2227   }
2228 
2229   /**
2230    * GetDocumentCharsetInternal() returns charset of the document.
2231    */
2232   nsresult GetDocumentCharsetInternal(nsACString& aCharset) const;
2233 
2234   /**
2235    * ComputeValueInternal() computes string value of this editor for given
2236    * format.  This may be too expensive if it's in hot path.
2237    *
2238    * @param aFormatType             MIME type like "text/plain".
2239    * @param aDocumentEncoderFlags   Flags of nsIDocumentEncoder.
2240    * @param aCharset                Encoding of the document.
2241    */
2242   nsresult ComputeValueInternal(const nsAString& aFormatType,
2243                                 uint32_t aDocumentEncoderFlags,
2244                                 nsAString& aOutputString) const;
2245 
2246   /**
2247    * GetAndInitDocEncoder() returns a document encoder instance for aFormatType
2248    * after initializing it.  The result may be cached for saving recreation
2249    * cost.
2250    *
2251    * @param aFormatType             MIME type like "text/plain".
2252    * @param aDocumentEncoderFlags   Flags of nsIDocumentEncoder.
2253    * @param aCharset                Encoding of the document.
2254    */
2255   already_AddRefed<nsIDocumentEncoder> GetAndInitDocEncoder(
2256       const nsAString& aFormatType, uint32_t aDocumentEncoderFlags,
2257       const nsACString& aCharset) const;
2258 
2259   /**
2260    * EnsurePaddingBRElementInMultilineEditor() creates a padding `<br>` element
2261    * at end of multiline text editor.
2262    */
2263   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2264   EnsurePaddingBRElementInMultilineEditor();
2265 
2266   /**
2267    * SelectAllInternal() should be used instead of SelectAll() in editor
2268    * because SelectAll() creates AutoEditActionSetter but we should avoid
2269    * to create it as far as possible.
2270    */
2271   MOZ_CAN_RUN_SCRIPT virtual nsresult SelectAllInternal();
2272 
2273   nsresult DetermineCurrentDirection();
2274 
2275   /**
2276    * DispatchInputEvent() dispatches an "input" event synchronously or
2277    * asynchronously if it's not safe to dispatch.
2278    */
2279   MOZ_CAN_RUN_SCRIPT void DispatchInputEvent();
2280 
2281   /**
2282    * Called after a transaction is done successfully.
2283    */
2284   MOZ_CAN_RUN_SCRIPT void DoAfterDoTransaction(nsITransaction* aTransaction);
2285 
2286   /**
2287    * Called after a transaction is undone successfully.
2288    */
2289 
2290   MOZ_CAN_RUN_SCRIPT void DoAfterUndoTransaction();
2291 
2292   /**
2293    * Called after a transaction is redone successfully.
2294    */
2295   MOZ_CAN_RUN_SCRIPT void DoAfterRedoTransaction();
2296 
2297   /**
2298    * Tell the doc state listeners that the doc state has changed.
2299    */
2300   enum TDocumentListenerNotification {
2301     eDocumentCreated,
2302     eDocumentToBeDestroyed,
2303     eDocumentStateChanged
2304   };
2305   MOZ_CAN_RUN_SCRIPT nsresult
2306   NotifyDocumentListeners(TDocumentListenerNotification aNotificationType);
2307 
2308   /**
2309    * Make the given selection span the entire document.
2310    */
2311   MOZ_CAN_RUN_SCRIPT virtual nsresult SelectEntireDocument() = 0;
2312 
2313   /**
2314    * Helper method for scrolling the selection into view after
2315    * an edit operation.
2316    *
2317    * Editor methods *should* call this method instead of the versions
2318    * in the various selection interfaces, since this makes sure that
2319    * the editor's sync/async settings for reflowing, painting, and scrolling
2320    * match.
2321    */
2322   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ScrollSelectionFocusIntoView();
2323 
2324   virtual nsresult InstallEventListeners();
2325   virtual void CreateEventListeners();
2326   virtual void RemoveEventListeners();
2327 
2328   /**
2329    * Called if and only if this editor is in readonly mode.
2330    */
2331   void HandleKeyPressEventInReadOnlyMode(
2332       WidgetKeyboardEvent& aKeyboardEvent) const;
2333 
2334   /**
2335    * Get the input event target. This might return null.
2336    */
2337   virtual already_AddRefed<Element> GetInputEventTargetElement() const = 0;
2338 
2339   /**
2340    * Return true if spellchecking should be enabled for this editor.
2341    */
2342   bool GetDesiredSpellCheckState();
2343 
CanEnableSpellCheck()2344   bool CanEnableSpellCheck() {
2345     // Check for password/readonly/disabled, which are not spellchecked
2346     // regardless of DOM. Also, check to see if spell check should be skipped
2347     // or not.
2348     return !IsPasswordEditor() && !IsReadonly() && !ShouldSkipSpellCheck();
2349   }
2350 
2351   /**
2352    * InitializeSelectionAncestorLimit() is called by InitializeSelection().
2353    * When this is called, each implementation has to call
2354    * Selection::SetAncestorLimiter() with aAnotherLimit.
2355    *
2356    * @param aAncestorLimit      New ancestor limit of Selection.  This always
2357    *                            has parent node.  So, it's always safe to
2358    *                            call SetAncestorLimit() with this node.
2359    */
2360   virtual void InitializeSelectionAncestorLimit(
2361       nsIContent& aAncestorLimit) const;
2362 
2363   /**
2364    * Initializes selection and caret for the editor.  If aEventTarget isn't
2365    * a host of the editor, i.e., the editor doesn't get focus, this does
2366    * nothing.
2367    */
2368   MOZ_CAN_RUN_SCRIPT nsresult InitializeSelection(nsINode& aFocusEventTarget);
2369 
2370   enum NotificationForEditorObservers {
2371     eNotifyEditorObserversOfEnd,
2372     eNotifyEditorObserversOfBefore,
2373     eNotifyEditorObserversOfCancel
2374   };
2375   MOZ_CAN_RUN_SCRIPT void NotifyEditorObservers(
2376       NotificationForEditorObservers aNotification);
2377 
2378   /**
2379    * HowToHandleCollapsedRange indicates how collapsed range should be treated.
2380    */
2381   enum class HowToHandleCollapsedRange {
2382     // Ignore collapsed range.
2383     Ignore,
2384     // Extend collapsed range for removing previous content.
2385     ExtendBackward,
2386     // Extend collapsed range for removing next content.
2387     ExtendForward,
2388   };
2389 
HowToHandleCollapsedRangeFor(nsIEditor::EDirection aDirectionAndAmount)2390   static HowToHandleCollapsedRange HowToHandleCollapsedRangeFor(
2391       nsIEditor::EDirection aDirectionAndAmount) {
2392     switch (aDirectionAndAmount) {
2393       case nsIEditor::eNone:
2394         return HowToHandleCollapsedRange::Ignore;
2395       case nsIEditor::ePrevious:
2396         return HowToHandleCollapsedRange::ExtendBackward;
2397       case nsIEditor::eNext:
2398         return HowToHandleCollapsedRange::ExtendForward;
2399       case nsIEditor::ePreviousWord:
2400       case nsIEditor::eNextWord:
2401       case nsIEditor::eToBeginningOfLine:
2402       case nsIEditor::eToEndOfLine:
2403         // If the amount is word or
2404         // line,`AutoRangeArray::ExtendAnchorFocusRangeFor()` must have already
2405         // been extended collapsed ranges before.
2406         return HowToHandleCollapsedRange::Ignore;
2407     }
2408     MOZ_ASSERT_UNREACHABLE("Invalid nsIEditor::EDirection value");
2409     return HowToHandleCollapsedRange::Ignore;
2410   }
2411 
2412   /**
2413    * InsertDroppedDataTransferAsAction() inserts all data items in aDataTransfer
2414    * at aDroppedAt unless the editor is destroyed.
2415    *
2416    * @param aEditActionData     The edit action data whose edit action must be
2417    *                            EditAction::eDrop.
2418    * @param aDataTransfer       The data transfer object which is dropped.
2419    * @param aDroppedAt          The DOM tree position whether aDataTransfer
2420    *                            is dropped.
2421    * @param aSourcePrincipal    Principal of the source of the drag.
2422    *                            May be nullptr if it comes from another app
2423    *                            or process.
2424    */
2425   [[nodiscard]] MOZ_CAN_RUN_SCRIPT virtual nsresult
2426   InsertDroppedDataTransferAsAction(AutoEditActionDataSetter& aEditActionData,
2427                                     dom::DataTransfer& aDataTransfer,
2428                                     const EditorDOMPoint& aDroppedAt,
2429                                     nsIPrincipal* aSourcePrincipal) = 0;
2430 
2431   /**
2432    * DeleteSelectionByDragAsAction() removes selection and dispatch "input"
2433    * event whose inputType is "deleteByDrag".
2434    */
2435   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2436   DeleteSelectionByDragAsAction(bool aDispatchInputEvent);
2437 
2438   /**
2439    * DeleteSelectionWithTransaction() removes selected content or content
2440    * around caret with transactions and remove empty inclusive ancestor
2441    * inline elements of collapsed selection after removing the contents.
2442    *
2443    * @param aDirectionAndAmount How much range should be removed.
2444    * @param aStripWrappers      Whether the parent blocks should be removed
2445    *                            when they become empty.
2446    *                            Note that this must be `nsIEditor::eNoStrip`
2447    *                            if this is a TextEditor because anyway it'll
2448    *                            be ignored.
2449    */
2450   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2451   DeleteSelectionWithTransaction(nsIEditor::EDirection aDirectionAndAmount,
2452                                  nsIEditor::EStripWrappers aStripWrappers);
2453 
2454   /**
2455    * DeleteRangesWithTransaction() removes content in aRangesToDelete or content
2456    * around collapsed ranges in aRangesToDelete with transactions and remove
2457    * empty inclusive ancestor inline elements of collapsed ranges after
2458    * removing the contents.
2459    *
2460    * @param aDirectionAndAmount How much range should be removed.
2461    * @param aStripWrappers      Whether the parent blocks should be removed
2462    *                            when they become empty.
2463    *                            Note that this must be `nsIEditor::eNoStrip`
2464    *                            if this is a TextEditor because anyway it'll
2465    *                            be ignored.
2466    * @param aRangesToDelete     The ranges to delete content.
2467    */
2468   [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
2469   DeleteRangesWithTransaction(nsIEditor::EDirection aDirectionAndAmount,
2470                               nsIEditor::EStripWrappers aStripWrappers,
2471                               const AutoRangeArray& aRangesToDelete);
2472 
2473   /**
2474    * Create an aggregate transaction for delete the content in aRangesToDelete.
2475    * The result may include DeleteNodeTransactions and/or DeleteTextTransactions
2476    * as its children.
2477    *
2478    * @param aHowToHandleCollapsedRange
2479    *                            How to handle collapsed ranges.
2480    * @param aRangesToDelete     The ranges to delete content.
2481    * @return                    If it can remove the content in ranges, returns
2482    *                            an aggregate transaction which has some
2483    *                            DeleteNodeTransactions and/or
2484    *                            DeleteTextTransactions as its children.
2485    */
2486   already_AddRefed<EditAggregateTransaction>
2487   CreateTransactionForDeleteSelection(
2488       HowToHandleCollapsedRange aHowToHandleCollapsedRange,
2489       const AutoRangeArray& aRangesToDelete);
2490 
2491   /**
2492    * Create a transaction for removing the nodes and/or text around
2493    * aRangeToDelete.
2494    *
2495    * @param aCollapsedRange     The range to be removed.  This must be
2496    *                            collapsed.
2497    * @param aHowToHandleCollapsedRange
2498    *                            How to handle aCollapsedRange.  Must
2499    *                            be HowToHandleCollapsedRange::ExtendBackward or
2500    *                            HowToHandleCollapsedRange::ExtendForward.
2501    * @return                    The transaction to remove content around the
2502    *                            range.  Its type is DeleteNodeTransaction or
2503    *                            DeleteTextTransaction.
2504    */
2505   already_AddRefed<EditTransactionBase> CreateTransactionForCollapsedRange(
2506       const nsRange& aCollapsedRange,
2507       HowToHandleCollapsedRange aHowToHandleCollapsedRange);
2508 
2509   /**
2510    * ComputeInsertedRange() returns actual range modified by inserting string
2511    * in a text node.  If mutation event listener changed the text data, this
2512    * returns a range which covers all over the text data.
2513    */
2514   std::tuple<EditorDOMPointInText, EditorDOMPointInText> ComputeInsertedRange(
2515       const EditorDOMPointInText& aInsertedPoint,
2516       const nsAString& aInsertedString) const;
2517 
2518   /**
2519    * EnsureComposition() should be called by composition event handlers.  This
2520    * tries to get the composition for the event and set it to mComposition.
2521    * However, this may fail because the composition may be committed before
2522    * the event comes to the editor.
2523    *
2524    * @return            true if there is a composition.  Otherwise, for example,
2525    *                    a composition event handler in web contents moved focus
2526    *                    for committing the composition, returns false.
2527    */
2528   bool EnsureComposition(WidgetCompositionEvent& aCompositionEvent);
2529 
2530   /**
2531    * See comment of IsCopyToClipboardAllowed() for the detail.
2532    */
IsCopyToClipboardAllowedInternal()2533   virtual bool IsCopyToClipboardAllowedInternal() const {
2534     MOZ_ASSERT(IsEditActionDataAvailable());
2535     return !SelectionRef().IsCollapsed();
2536   }
2537 
2538   /**
2539    * Helper for Is{Cut|Copy}CommandEnabled.
2540    * Look for a listener for the given command, including up the target chain.
2541    */
2542   MOZ_CAN_RUN_SCRIPT bool CheckForClipboardCommandListener(
2543       nsAtom* aCommand, EventMessage aEventMessage) const;
2544 
2545   /**
2546    * FireClipboardEvent() may dispatch a clipboard event.
2547    *
2548    * @param aEventMessage       The event message which may be set to the
2549    *                            dispatching event.
2550    * @param aClipboardType      Working with global clipboard or selection.
2551    * @param aActionTaken        [optional][out] If set to non-nullptr, will be
2552    *                            set to true if the action for the event is
2553    *                            handled or prevented default.
2554    * @return                    false if dispatching event is canceled.
2555    */
2556   bool FireClipboardEvent(EventMessage aEventMessage, int32_t aClipboardType,
2557                           bool* aActionTaken = nullptr);
2558 
2559  private:
2560   nsCOMPtr<nsISelectionController> mSelectionController;
2561   RefPtr<Document> mDocument;
2562 
2563   AutoEditActionDataSetter* mEditActionData;
2564 
2565   /**
2566    * SetTextDirectionTo() sets text-direction of the root element.
2567    * Should use SwitchTextDirectionTo() or ToggleTextDirection() instead.
2568    * This is a helper class of them.
2569    */
2570   nsresult SetTextDirectionTo(TextDirection aTextDirection);
2571 
2572  protected:  // helper classes which may be used by friends
2573   /**
2574    * Stack based helper class for batching a collection of transactions inside
2575    * a placeholder transaction.  Different from AutoTransactionBatch, this
2576    * notifies editor observers of before/end edit action handling, and
2577    * dispatches "input" event if it's necessary.
2578    */
2579   class MOZ_RAII AutoPlaceholderBatch final {
2580    public:
2581     /**
2582      * @param aRequesterFuncName function name which wants to end the batch.
2583      * This won't be stored nor exposed to selection listeners etc, used only
2584      * for logging. This MUST be alive when the destructor runs.
2585      */
AutoPlaceholderBatch(EditorBase & aEditorBase,ScrollSelectionIntoView aScrollSelectionIntoView,const char * aRequesterFuncName)2586     AutoPlaceholderBatch(EditorBase& aEditorBase,
2587                          ScrollSelectionIntoView aScrollSelectionIntoView,
2588                          const char* aRequesterFuncName)
2589         : mEditorBase(aEditorBase),
2590           mScrollSelectionIntoView(aScrollSelectionIntoView),
2591           mRequesterFuncName(aRequesterFuncName) {
2592       mEditorBase->BeginPlaceholderTransaction(*nsGkAtoms::_empty,
2593                                                mRequesterFuncName);
2594     }
2595 
AutoPlaceholderBatch(EditorBase & aEditorBase,nsStaticAtom & aTransactionName,ScrollSelectionIntoView aScrollSelectionIntoView,const char * aRequesterFuncName)2596     AutoPlaceholderBatch(EditorBase& aEditorBase,
2597                          nsStaticAtom& aTransactionName,
2598                          ScrollSelectionIntoView aScrollSelectionIntoView,
2599                          const char* aRequesterFuncName)
2600         : mEditorBase(aEditorBase),
2601           mScrollSelectionIntoView(aScrollSelectionIntoView),
2602           mRequesterFuncName(aRequesterFuncName) {
2603       mEditorBase->BeginPlaceholderTransaction(aTransactionName,
2604                                                mRequesterFuncName);
2605     }
2606 
~AutoPlaceholderBatch()2607     ~AutoPlaceholderBatch() {
2608       mEditorBase->EndPlaceholderTransaction(mScrollSelectionIntoView,
2609                                              mRequesterFuncName);
2610     }
2611 
2612    protected:
2613     const OwningNonNull<EditorBase> mEditorBase;
2614     const ScrollSelectionIntoView mScrollSelectionIntoView;
2615     const char* const mRequesterFuncName;
2616   };
2617 
2618   /**
2619    * AutoEditSubActionNotifier notifies editor of start to handle
2620    * top level edit sub-action and end handling top level edit sub-action.
2621    */
2622   class MOZ_RAII AutoEditSubActionNotifier final {
2623    public:
AutoEditSubActionNotifier(EditorBase & aEditorBase,EditSubAction aEditSubAction,nsIEditor::EDirection aDirection,ErrorResult & aRv)2624     MOZ_CAN_RUN_SCRIPT AutoEditSubActionNotifier(
2625         EditorBase& aEditorBase, EditSubAction aEditSubAction,
2626         nsIEditor::EDirection aDirection, ErrorResult& aRv)
2627         : mEditorBase(aEditorBase), mIsTopLevel(true) {
2628       // The top level edit sub action has already be set if this is nested call
2629       // XXX Looks like that this is not aware of unexpected nested edit action
2630       //     handling via selectionchange event listener or mutation event
2631       //     listener.
2632       if (!mEditorBase.GetTopLevelEditSubAction()) {
2633         MOZ_KnownLive(mEditorBase)
2634             .OnStartToHandleTopLevelEditSubAction(aEditSubAction, aDirection,
2635                                                   aRv);
2636       } else {
2637         mIsTopLevel = false;
2638       }
2639       mEditorBase.OnStartToHandleEditSubAction();
2640     }
2641 
~AutoEditSubActionNotifier()2642     MOZ_CAN_RUN_SCRIPT ~AutoEditSubActionNotifier() {
2643       mEditorBase.OnEndHandlingEditSubAction();
2644       if (mIsTopLevel) {
2645         MOZ_KnownLive(mEditorBase).OnEndHandlingTopLevelEditSubAction();
2646       }
2647     }
2648 
2649    protected:
2650     EditorBase& mEditorBase;
2651     bool mIsTopLevel;
2652   };
2653 
2654   /**
2655    * Stack based helper class for turning off active selection adjustment
2656    * by low level transactions
2657    */
2658   class MOZ_RAII AutoTransactionsConserveSelection final {
2659    public:
AutoTransactionsConserveSelection(EditorBase & aEditorBase)2660     explicit AutoTransactionsConserveSelection(EditorBase& aEditorBase)
2661         : mEditorBase(aEditorBase),
2662           mAllowedTransactionsToChangeSelection(
2663               aEditorBase.AllowsTransactionsToChangeSelection()) {
2664       mEditorBase.MakeThisAllowTransactionsToChangeSelection(false);
2665     }
2666 
~AutoTransactionsConserveSelection()2667     ~AutoTransactionsConserveSelection() {
2668       mEditorBase.MakeThisAllowTransactionsToChangeSelection(
2669           mAllowedTransactionsToChangeSelection);
2670     }
2671 
2672    protected:
2673     EditorBase& mEditorBase;
2674     bool mAllowedTransactionsToChangeSelection;
2675   };
2676 
2677   /***************************************************************************
2678    * stack based helper class for batching reflow and paint requests.
2679    */
2680   class MOZ_RAII AutoUpdateViewBatch final {
2681    public:
2682     /**
2683      * @param aRequesterFuncName function name which wants to end the batch.
2684      * This won't be stored nor exposed to selection listeners etc, used only
2685      * for logging. This MUST be alive when the destructor runs.
2686      */
AutoUpdateViewBatch(EditorBase & aEditorBase,const char * aRequesterFuncName)2687     MOZ_CAN_RUN_SCRIPT explicit AutoUpdateViewBatch(
2688         EditorBase& aEditorBase, const char* aRequesterFuncName)
2689         : mEditorBase(aEditorBase), mRequesterFuncName(aRequesterFuncName) {
2690       mEditorBase.BeginUpdateViewBatch(mRequesterFuncName);
2691     }
2692 
~AutoUpdateViewBatch()2693     MOZ_CAN_RUN_SCRIPT ~AutoUpdateViewBatch() {
2694       MOZ_KnownLive(mEditorBase).EndUpdateViewBatch(mRequesterFuncName);
2695     }
2696 
2697    protected:
2698     EditorBase& mEditorBase;
2699     const char* const mRequesterFuncName;
2700   };
2701 
2702  protected:
2703   enum Tristate { eTriUnset, eTriFalse, eTriTrue };
2704 
2705   // MIME type of the doc we are editing.
2706   nsString mContentMIMEType;
2707 
2708   RefPtr<mozInlineSpellChecker> mInlineSpellChecker;
2709   // Reference to text services document for mInlineSpellChecker.
2710   RefPtr<TextServicesDocument> mTextServicesDocument;
2711 
2712   RefPtr<TransactionManager> mTransactionManager;
2713   // Cached root node.
2714   RefPtr<Element> mRootElement;
2715 
2716   // The form field as an event receiver.
2717   nsCOMPtr<dom::EventTarget> mEventTarget;
2718   RefPtr<EditorEventListener> mEventListener;
2719   // Strong reference to placeholder for begin/end batch purposes.
2720   RefPtr<PlaceholderTransaction> mPlaceholderTransaction;
2721   // Name of placeholder transaction.
2722   nsStaticAtom* mPlaceholderName;
2723   // Saved selection state for placeholder transaction batching.
2724   mozilla::Maybe<SelectionState> mSelState;
2725   // IME composition this is not null between compositionstart and
2726   // compositionend.
2727   RefPtr<TextComposition> mComposition;
2728 
2729   RefPtr<TextInputListener> mTextInputListener;
2730 
2731   RefPtr<IMEContentObserver> mIMEContentObserver;
2732 
2733   // These members cache last encoder and its type for the performance in
2734   // TextEditor::ComputeTextValue() which is the implementation of
2735   // `<input>.value` and `<textarea>.value`.  See `GetAndInitDocEncoder()`.
2736   mutable nsCOMPtr<nsIDocumentEncoder> mCachedDocumentEncoder;
2737   mutable nsString mCachedDocumentEncoderType;
2738 
2739   // Listens to all low level actions on the doc.
2740   // Edit action listener is currently used by highlighter of the findbar and
2741   // the spellchecker.  So, we should reserve only 2 items.
2742   typedef AutoTArray<OwningNonNull<nsIEditActionListener>, 2>
2743       AutoActionListenerArray;
2744   AutoActionListenerArray mActionListeners;
2745   // Listen to overall doc state (dirty or not, just created, etc.).
2746   // Document state listener is currently used by FinderHighlighter and
2747   // BlueGriffon so that reserving only one is enough.
2748   typedef AutoTArray<OwningNonNull<nsIDocumentStateListener>, 1>
2749       AutoDocumentStateListenerArray;
2750   AutoDocumentStateListenerArray mDocStateListeners;
2751 
2752   // Number of modifications (for undo/redo stack).
2753   uint32_t mModCount;
2754   // Behavior flags. See nsIEditor.idl for the flags we use.
2755   uint32_t mFlags;
2756 
2757   int32_t mUpdateCount;
2758 
2759   // Nesting count for batching.
2760   int32_t mPlaceholderBatch;
2761 
2762   int32_t mWrapColumn;
2763   int32_t mNewlineHandling;
2764   int32_t mCaretStyle;
2765 
2766   // -1 = not initialized
2767   int8_t mDocDirtyState;
2768   // A Tristate value.
2769   uint8_t mSpellcheckCheckboxState;
2770 
2771   // If true, initialization was succeeded.
2772   bool mInitSucceeded;
2773   // If false, transactions should not change Selection even after modifying
2774   // the DOM tree.
2775   bool mAllowsTransactionsToChangeSelection;
2776   // Whether PreDestroy has been called.
2777   bool mDidPreDestroy;
2778   // Whether PostCreate has been called.
2779   bool mDidPostCreate;
2780   bool mDispatchInputEvent;
2781   // True while the instance is handling an edit sub-action.
2782   bool mIsInEditSubAction;
2783   // Whether caret is hidden forcibly.
2784   bool mHidingCaret;
2785   // Whether spellchecker dictionary is initialized after focused.
2786   bool mSpellCheckerDictionaryUpdated;
2787   // Whether we are an HTML editor class.
2788   bool mIsHTMLEditorClass;
2789 
2790   friend class AlignStateAtSelection;
2791   friend class AutoRangeArray;
2792   friend class CompositionTransaction;
2793   friend class CSSEditUtils;
2794   friend class DeleteNodeTransaction;
2795   friend class DeleteRangeTransaction;
2796   friend class DeleteTextTransaction;
2797   friend class HTMLEditUtils;
2798   friend class InsertNodeTransaction;
2799   friend class InsertTextTransaction;
2800   friend class JoinNodesTransaction;
2801   friend class ListElementSelectionState;
2802   friend class ListItemElementSelectionState;
2803   friend class ParagraphStateAtSelection;
2804   friend class ReplaceTextTransaction;
2805   friend class SplitNodeTransaction;
2806   friend class TypeInState;
2807   friend class WhiteSpaceVisibilityKeeper;
2808   friend class WSRunScanner;
2809   friend class nsIEditor;
2810 };
2811 
2812 }  // namespace mozilla
2813 
IsTextEditor()2814 bool nsIEditor::IsTextEditor() const {
2815   return !AsEditorBase()->mIsHTMLEditorClass;
2816 }
2817 
IsHTMLEditor()2818 bool nsIEditor::IsHTMLEditor() const {
2819   return AsEditorBase()->mIsHTMLEditorClass;
2820 }
2821 
AsEditorBase()2822 mozilla::EditorBase* nsIEditor::AsEditorBase() {
2823   return static_cast<mozilla::EditorBase*>(this);
2824 }
2825 
AsEditorBase()2826 const mozilla::EditorBase* nsIEditor::AsEditorBase() const {
2827   return static_cast<const mozilla::EditorBase*>(this);
2828 }
2829 
2830 #endif  // #ifndef mozilla_EditorBase_h
2831